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     };
00361     if(needsUpdate)
00362     {
00363         // switch left/right or top/bottom if necessary
00364         if(newLeft>newRight)
00365         {
00366             int temp=newLeft;
00367             newLeft=newRight;
00368             newRight=temp;
00369         };
00370         if(newTop>newBottom)
00371         {
00372             int temp=newTop;
00373             newTop=newBottom;
00374             newBottom=temp;
00375         };
00376         m_cropRect.setUpperLeft(vigra::Point2D(newLeft, newTop));
00377         m_cropRect.setLowerRight(vigra::Point2D(newRight, newBottom));
00378     };
00379 };
00380 
00381 void MaskImageCtrl::OnMouseMove(wxMouseEvent& mouse)
00382 {
00383     if(m_previewOnly)
00384         return;
00385     wxPoint mpos;
00386     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00387                            &mpos.x, & mpos.y);
00388     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(mpos));
00389     bool doUpdate = false;
00390     switch(m_maskEditState)
00391     {
00392         case NEW_POLYGON_CREATING:
00393             doUpdate=true;
00394             m_editingMask.movePointTo(m_editingMask.getMaskPolygon().size()-1,currentPos);
00395             break;
00396         case POLYGON_SELECTING:
00397         case REGION_SELECTING:
00398         case POINTS_DELETING:
00399 #if defined SUPPORTS_WXINVERT
00400             DrawSelectionRectangle();
00401 #endif
00402             m_currentPos=mpos;
00403             DrawSelectionRectangle();
00404             break;
00405         case POINTS_MOVING:
00406             doUpdate=true;
00407             m_editingMask=m_imageMask[m_activeMask];
00408             {
00409                 hugin_utils::FDiff2D delta=currentPos-applyRotInv(invtransform(m_dragStartPos));
00410                 for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00411                     m_editingMask.movePointBy(*it,delta);
00412             };
00413             break;
00414         case POINTS_ADDING:
00415             doUpdate=true;
00416             for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00417                 m_editingMask.movePointTo(*it,currentPos);
00418             break;
00419         case CROP_SHOWING:
00420             switch(GetClickPos(vigra::Point2D(currentPos.x, currentPos.y)))
00421             {
00422                 case CLICK_INSIDE:
00423                     if(!m_cropCentered)
00424                     {
00425                         SetCursor(wxCURSOR_HAND);
00426                     }
00427                     else
00428                     {
00429                         SetCursor(wxNullCursor);
00430                     };
00431                     break;
00432                 case CLICK_LEFT:
00433                 case CLICK_RIGHT:
00434                     switch (m_imgRotation)
00435                     {
00436                         case ROT90:
00437                         case ROT270:
00438                             SetCursor(wxCURSOR_SIZENS);
00439                             break;
00440                         default:
00441                             SetCursor(wxCURSOR_SIZEWE);
00442                     };
00443                     break;
00444                 case CLICK_TOP:
00445                 case CLICK_BOTTOM:
00446                     switch (m_imgRotation)
00447                     {
00448                         case ROT90:
00449                         case ROT270:
00450                             SetCursor(wxCURSOR_SIZEWE);
00451                             break;
00452                         default:
00453                             SetCursor(wxCURSOR_SIZENS);
00454                     };
00455                     break;
00456                 case CLICK_CIRCLE:
00457                     SetCursor(wxCURSOR_SIZING);
00458                     break;
00459                 default:
00460                     SetCursor(wxNullCursor);
00461             };
00462             break;
00463         case CROP_MOVING:
00464         case CROP_LEFT_MOVING:
00465         case CROP_RIGHT_MOVING:
00466         case CROP_TOP_MOVING:
00467         case CROP_BOTTOM_MOVING:
00468         case CROP_CIRCLE_SCALING:
00469 #if defined SUPPORTS_WXINVERT
00470             DrawCrop();
00471 #else
00472             doUpdate=true;
00473 #endif
00474             UpdateCrop(currentPos);
00475             m_currentPos=mpos;
00476 #if defined SUPPORTS_WXINVERT
00477             DrawCrop();
00478 #endif
00479             m_editPanel->UpdateCropFromImage();
00480             break;
00481     };
00482     if(doUpdate)
00483         update();
00484 }
00485 
00486 void MaskImageCtrl::OnLeftMouseDown(wxMouseEvent& mouse)
00487 {
00488     if(m_previewOnly)
00489         return;
00490     DEBUG_DEBUG("LEFT MOUSE DOWN");
00491     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00492                            &m_dragStartPos.x, & m_dragStartPos.y);
00493     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(m_dragStartPos));
00494     m_currentPos=m_dragStartPos;
00495     if(!HasCapture())
00496         CaptureMouse();
00497     SetFocus();
00498     switch(m_maskEditState)
00499     {
00500         case NEW_POLYGON_STARTED:
00501             //starting polygon creating
00502             m_editingMask.addPoint(currentPos);
00503             m_selectedPoints.insert(m_editingMask.getMaskPolygon().size()-1);
00504             break;
00505         case NO_MASK:
00506             if(m_maskMode)
00507             {
00508                 m_maskEditState=POLYGON_SELECTING;
00509                 DrawSelectionRectangle();
00510             };
00511             break;
00512         case NO_SELECTION:
00513             if(mouse.CmdDown())
00514             {
00515                 // check if mouse clicks happens near one line of active polygon
00516                 unsigned int index=m_editingMask.FindPointNearPos(currentPos,5*maxSelectionDistance);
00517                 if(index<UINT_MAX)
00518                 {
00519                     m_selectedPoints.clear();
00520                     m_editingMask.insertPoint(index,currentPos);
00521                     m_selectedPoints.insert(index);
00522                     m_maskEditState=POINTS_ADDING;
00523                 };
00524             }
00525             else
00526             {
00527                 HuginBase::UIntSet points;
00528                 if(SelectPointsInsideMouseRect(points,false))
00529                 {
00530                     for(HuginBase::UIntSet::const_iterator it=points.begin();it!=points.end();++it)
00531                         m_selectedPoints.insert(*it);
00532                     m_maskEditState=POINTS_MOVING;
00533                 }
00534                 else
00535                 {
00536                     m_maskEditState=REGION_SELECTING;
00537                     DrawSelectionRectangle();
00538                 }
00539             };
00540             break;
00541         case POINTS_SELECTED:
00542             if(mouse.CmdDown())
00543             {
00544                 // check if mouse clicks happens near one line of active polygon
00545                 unsigned int index=m_editingMask.FindPointNearPos(currentPos, 5*maxSelectionDistance);
00546                 if(index<UINT_MAX)
00547                 {
00548                     m_selectedPoints.clear();
00549                     m_editingMask.insertPoint(index,currentPos);
00550                     m_selectedPoints.insert(index);
00551                     m_maskEditState=POINTS_ADDING;
00552                 };
00553             }
00554             else
00555             {
00556                 HuginBase::UIntSet points;
00557                 if(SelectPointsInsideMouseRect(points,true))
00558                 {
00559                     //selected point clicked, starting moving
00560                     m_maskEditState=POINTS_MOVING;
00561                 }
00562                 else
00563                 {
00564                     //unselected point clicked
00565                     if(SelectPointsInsideMouseRect(points,false))
00566                     {
00567                         //clicked near other point
00568                         if(!mouse.ShiftDown())
00569                             m_selectedPoints.clear();
00570                         for(HuginBase::UIntSet::const_iterator it=points.begin();it!=points.end();++it)
00571                             m_selectedPoints.insert(*it);
00572                         m_maskEditState=POINTS_MOVING;
00573                     }
00574                     else
00575                     {
00576                         m_maskEditState=REGION_SELECTING;
00577                         DrawSelectionRectangle();
00578                     };
00579                 }
00580             };
00581             break;
00582         case CROP_SHOWING:
00583             switch(GetClickPos(vigra::Point2D(currentPos.x,currentPos.y)))
00584             {
00585                 case CLICK_INSIDE:
00586                     if(!m_cropCentered)
00587                     {
00588                         m_maskEditState=CROP_MOVING;
00589                     };
00590                     break;
00591                 case CLICK_LEFT:
00592                     m_maskEditState=CROP_LEFT_MOVING;
00593                     break;
00594                 case CLICK_RIGHT:
00595                     m_maskEditState=CROP_RIGHT_MOVING;
00596                     break;
00597                 case CLICK_TOP:
00598                     m_maskEditState=CROP_TOP_MOVING;
00599                     break;
00600                 case CLICK_BOTTOM:
00601                     m_maskEditState=CROP_BOTTOM_MOVING;
00602                     break;
00603                 case CLICK_CIRCLE:
00604                     m_dragStartPos.x=(m_cropRect.left()+m_cropRect.right())/2;
00605                     m_dragStartPos.y=(m_cropRect.top()+m_cropRect.bottom())/2;
00606                     m_maskEditState=CROP_CIRCLE_SCALING;
00607                     break;
00608             };
00609             if(m_maskEditState!=CROP_SHOWING)
00610             {
00611                 if (m_cropMode == HuginBase::SrcPanoImage::NO_CROP && m_cropCircle)
00612                 {
00613 #if defined SUPPORTS_WXINVERT
00614                     DrawCrop();
00615                     m_cropMode = HuginBase::SrcPanoImage::CROP_CIRCLE;
00616                     DrawCrop();
00617 #else
00618                     m_cropMode=HuginBase::SrcPanoImage::CROP_CIRCLE;
00619                     update();
00620 #endif
00621                 };
00622             };
00623             break;
00624     };
00625 };
00626 
00627 void MaskImageCtrl::OnLeftMouseUp(wxMouseEvent& mouse)
00628 {
00629     if(m_previewOnly)
00630         return;
00631     DEBUG_DEBUG("LEFT MOUSE UP");
00632     wxPoint mpos;
00633     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00634                            &mpos.x, & mpos.y);
00635     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(mpos));
00636     bool doUpdate=false;
00637     switch(m_maskEditState)
00638     {
00639         case NEW_POLYGON_STARTED:
00640             doUpdate=true;
00641             m_editingMask.addPoint(currentPos);
00642             m_selectedPoints.insert(m_editingMask.getMaskPolygon().size()-1);
00643             m_maskEditState=NEW_POLYGON_CREATING;
00644             break;
00645         case NEW_POLYGON_CREATING:
00646             //next point of polygen selected
00647             doUpdate=true;
00648             m_editingMask.addPoint(currentPos);
00649             m_selectedPoints.insert(m_editingMask.getMaskPolygon().size()-1);
00650             break;
00651         case POINTS_MOVING:
00652             if(HasCapture())
00653                 ReleaseMouse();
00654             {
00655                 hugin_utils::FDiff2D delta=currentPos-applyRotInv(invtransform(m_dragStartPos));
00656                 if(hugin_utils::sqr(delta.x)+hugin_utils::sqr(delta.y)>hugin_utils::sqr(maxSelectionDistance))
00657                 {
00658                     for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00659                         m_imageMask[m_activeMask].movePointBy(*it,delta);
00660                     m_maskEditState=POINTS_SELECTED;
00661                     m_editPanel->UpdateMask();
00662                 }
00663                 else
00664                 {
00665                     m_editingMask=m_imageMask[m_activeMask];
00666                     m_maskEditState=POINTS_SELECTED;
00667                     doUpdate=true;
00668                 };
00669             };
00670             break;
00671         case POLYGON_SELECTING:
00672             if(HasCapture())
00673                 ReleaseMouse();
00674 #if defined SUPPORTS_WXINVERT
00675             DrawSelectionRectangle();
00676 #else
00677             doUpdate=true;
00678 #endif
00679             m_currentPos=mpos;
00680             m_maskEditState=NO_SELECTION;
00681             {
00682                 hugin_utils::FDiff2D p;
00683                 p.x=invtransform(m_dragStartPos.x+(m_currentPos.x-m_dragStartPos.x)/2);
00684                 p.y=invtransform(m_dragStartPos.y+(m_currentPos.y-m_dragStartPos.y)/2);
00685                 p=applyRotInv(p);
00686                 FindPolygon(p);
00687             };
00688             break;
00689         case REGION_SELECTING:
00690             {
00691                 if(HasCapture())
00692                     ReleaseMouse();
00693                 DrawSelectionRectangle();
00694                 m_currentPos=mpos;
00695                 bool selectedPoints=!m_selectedPoints.empty();
00696                 if(!mouse.ShiftDown())
00697                     m_selectedPoints.clear();
00698                 if(SelectPointsInsideMouseRect(m_selectedPoints,false))
00699                 {
00700                     //new points selected
00701                     if(m_selectedPoints.empty())
00702                         m_maskEditState=NO_SELECTION;
00703                     else
00704                         m_maskEditState=POINTS_SELECTED;
00705                 }
00706                 else
00707                 {
00708                     //there were no points selected
00709                     if(!selectedPoints)
00710                     {
00711                         //if there where no points selected before, we searching for an other polygon
00712                         hugin_utils::FDiff2D p;
00713                         p.x=invtransform(m_dragStartPos.x+(m_currentPos.x-m_dragStartPos.x)/2);
00714                         p.y=invtransform(m_dragStartPos.y+(m_currentPos.y-m_dragStartPos.y)/2);
00715                         p=applyRotInv(p);
00716                         FindPolygon(p);
00717                     };
00718                     m_maskEditState=NO_SELECTION;
00719                 };
00720                 doUpdate=true;
00721                 break;
00722             };
00723         case POINTS_ADDING:
00724             if(HasCapture())
00725                 ReleaseMouse();
00726             for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00727                 m_editingMask.movePointTo(*it,currentPos);
00728             m_imageMask[m_activeMask]=m_editingMask;
00729             m_editPanel->UpdateMask();
00730             m_maskEditState=POINTS_SELECTED;
00731             break;
00732         case CROP_MOVING:
00733         case CROP_LEFT_MOVING:
00734         case CROP_RIGHT_MOVING:
00735         case CROP_TOP_MOVING:
00736         case CROP_BOTTOM_MOVING:
00737         case CROP_CIRCLE_SCALING:
00738             if(HasCapture())
00739                 ReleaseMouse();
00740 #if defined SUPPORTS_WXINVERT
00741             DrawCrop();
00742 #else
00743             doUpdate=true;
00744 #endif
00745             UpdateCrop(currentPos);
00746 #if defined SUPPORTS_WXINVERT
00747             DrawCrop();
00748 #endif
00749             m_maskEditState=CROP_SHOWING;
00750             SetCursor(wxNullCursor);
00751             m_editPanel->UpdateCrop(true);
00752             break;
00753         default:
00754             if(HasCapture())
00755                 ReleaseMouse();
00756     };
00757     if(doUpdate)
00758         update();
00759 }
00760 
00761 void MaskImageCtrl::OnLeftMouseDblClick(wxMouseEvent &mouse)
00762 {
00763     if(m_previewOnly)
00764         return;
00765     wxPoint mpos;
00766     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00767                            &mpos.x, & mpos.y);
00768     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(mpos));
00769     switch(m_maskEditState)
00770     {
00771         case NEW_POLYGON_STARTED:
00772             {
00773                 m_maskEditState=NO_SELECTION;
00774                 HuginBase::MaskPolygon mask;
00775                 m_editingMask=mask;
00776                 m_selectedPoints.clear();
00777                 MainFrame::Get()->SetStatusText(wxT(""),0);
00778                 break;
00779             };
00780         case NEW_POLYGON_CREATING:
00781             {
00782                 //close newly generated polygon
00783                 m_maskEditState=NO_SELECTION;
00784                 //delete last point otherwise it would be added twice, because we added it
00785                 //already in release left mouse button
00786                 m_editingMask.removePoint(m_editingMask.getMaskPolygon().size()-1);
00787                 if(m_editingMask.getMaskPolygon().size()>2)
00788                 {
00789                     m_imageMask.push_back(m_editingMask);
00790                     m_activeMask=m_imageMask.size()-1;
00791                     m_editPanel->AddMask();
00792                 }
00793                 else
00794                 {
00795                     HuginBase::MaskPolygon mask;
00796                     m_editingMask=mask;
00797                     m_selectedPoints.clear();
00798                     update();
00799                 };
00800                 MainFrame::Get()->SetStatusText(wxT(""),0);
00801                 break;
00802             };
00803     };
00804 };
00805 
00806 void MaskImageCtrl::OnRightMouseDown(wxMouseEvent& mouse)
00807 {
00808     if(m_previewOnly)
00809         return;
00810     wxPoint mpos;
00811     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00812                            &m_dragStartPos.x, & m_dragStartPos.y);
00813     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(m_dragStartPos));
00814     m_currentPos=m_dragStartPos;
00815     if(!HasCapture())
00816         CaptureMouse();
00817     SetFocus();
00818     switch(m_maskEditState)
00819     {
00820         case NO_SELECTION:
00821         case POINTS_SELECTED:
00822             if(mouse.CmdDown())
00823             {
00824                 m_maskEditState=POINTS_DELETING;
00825                 DrawSelectionRectangle();
00826             }
00827             else
00828             {
00829                 if (m_editingMask.isInside(currentPos))
00830                 {
00831                     fill_set(m_selectedPoints,0,m_editingMask.getMaskPolygon().size()-1);
00832                     m_maskEditState=POINTS_MOVING;
00833                     update();
00834                 };
00835             };
00836             break;
00837     };
00838 };
00839 
00840 void MaskImageCtrl::OnRightMouseUp(wxMouseEvent& mouse)
00841 {
00842     if(m_previewOnly)
00843         return;
00844     wxPoint mpos;
00845     CalcUnscrolledPosition(mouse.GetPosition().x, mouse.GetPosition().y,
00846                            &mpos.x, & mpos.y);
00847     hugin_utils::FDiff2D currentPos=applyRotInv(invtransform(mpos));
00848     if(HasCapture())
00849         ReleaseMouse();
00850     switch(m_maskEditState)
00851     {
00852         case NEW_POLYGON_STARTED:
00853             {
00854                 m_maskEditState=NO_SELECTION;
00855                 HuginBase::MaskPolygon mask;
00856                 m_editingMask=mask;
00857                 m_selectedPoints.clear();
00858                 MainFrame::Get()->SetStatusText(wxT(""),0);
00859                 break;
00860             };
00861         case NEW_POLYGON_CREATING:
00862             {
00863                 //close newly generated polygon
00864                 m_maskEditState=NO_SELECTION;
00865                 m_editingMask.movePointTo(m_editingMask.getMaskPolygon().size()-1,currentPos);
00866                 if(m_editingMask.getMaskPolygon().size()>2)
00867                 {
00868                     m_imageMask.push_back(m_editingMask);
00869                     m_activeMask=m_imageMask.size()-1;
00870                     m_editPanel->AddMask();
00871                 }
00872                 else
00873                 {
00874                     HuginBase::MaskPolygon mask;
00875                     m_editingMask=mask;
00876                     m_selectedPoints.clear();
00877                     update();
00878                 };
00879                 MainFrame::Get()->SetStatusText(wxT(""),0);
00880                 break;
00881             };
00882         case POINTS_DELETING:
00883             {
00884                 DrawSelectionRectangle();
00885                 HuginBase::UIntSet points;
00886                 m_currentPos=mpos;
00887                 if(SelectPointsInsideMouseRect(points,false))
00888                 {
00889                     if(m_editingMask.getMaskPolygon().size()-points.size()>2)
00890                     {
00891                         // clear all selected points
00892                         for(HuginBase::UIntSet::const_reverse_iterator it=points.rbegin();it!=points.rend();++it)
00893                             m_editingMask.removePoint(*it);
00894                         // now update set of selected points
00895                         if(m_selectedPoints.size()>0)
00896                         {
00897                             std::vector<unsigned int> mappedSelectedPoints(m_imageMask[m_activeMask].getMaskPolygon().size());
00898                             for(unsigned int i=0;i<mappedSelectedPoints.size();i++)
00899                                 mappedSelectedPoints[i]=i;
00900                             HuginBase::UIntSet temp=m_selectedPoints;
00901                             m_selectedPoints.clear();
00902                             for(HuginBase::UIntSet::const_iterator it=points.begin();it!=points.end();++it)
00903                             {
00904                                 if((*it)<mappedSelectedPoints.size()-1)
00905                                     for(unsigned int i=(*it)+1;i<mappedSelectedPoints.size();i++)
00906                                         mappedSelectedPoints[i]--;
00907                             };
00908                             for(HuginBase::UIntSet::const_iterator it=temp.begin();it!=temp.end();++it)
00909                                 if(!set_contains(points,*it))
00910                                     m_selectedPoints.insert(mappedSelectedPoints[*it]);
00911                         };
00912                         //now update the saved mask
00913                         m_imageMask[m_activeMask]=m_editingMask;
00914                         m_editPanel->UpdateMask();
00915                     }
00916                     else
00917                         wxBell();
00918                 };
00919                 if(m_selectedPoints.size()==0)
00920                     m_maskEditState=NO_SELECTION;
00921                 else
00922                     m_maskEditState=POINTS_SELECTED;
00923                 break;
00924             };
00925         case POINTS_MOVING:
00926             {
00927                 hugin_utils::FDiff2D delta=currentPos-applyRotInv(invtransform(m_dragStartPos));
00928                 if(hugin_utils::sqr(delta.x)+hugin_utils::sqr(delta.y)>hugin_utils::sqr(maxSelectionDistance))
00929                 {
00930                     for(HuginBase::UIntSet::const_iterator it=m_selectedPoints.begin();it!=m_selectedPoints.end();++it)
00931                         m_imageMask[m_activeMask].movePointBy(*it,delta);
00932                     m_maskEditState=POINTS_SELECTED;
00933                     m_editPanel->UpdateMask();
00934                 }
00935                 else
00936                 {
00937                     m_editingMask=m_imageMask[m_activeMask];
00938                     m_maskEditState=POINTS_SELECTED;
00939                 };
00940                 break;
00941             };
00942     };
00943 };
00944 
00945 void MaskImageCtrl::OnKeyUp(wxKeyEvent &e)
00946 {
00947     int key=e.GetKeyCode();
00948     bool processed=false;
00949     if((key==WXK_DELETE) || (key==WXK_NUMPAD_DELETE))
00950     {
00951         if(m_activeMask<UINT_MAX)
00952         {
00953             switch(m_maskEditState)
00954             {
00955                 case POINTS_SELECTED:
00956                     if((m_selectedPoints.size()>0) && (m_editingMask.getMaskPolygon().size()-m_selectedPoints.size()>2))
00957                     {
00958                         for(HuginBase::UIntSet::const_reverse_iterator it=m_selectedPoints.rbegin();it!=m_selectedPoints.rend();++it)
00959                             m_editingMask.removePoint(*it);
00960                         m_imageMask[m_activeMask]=m_editingMask;
00961                         processed=true;
00962                         m_editPanel->UpdateMask();
00963                     }
00964                     else
00965                     {
00966                         if(m_editingMask.getMaskPolygon().size()==m_selectedPoints.size())
00967                         {
00968                             wxCommandEvent dummy;
00969                             processed=true;
00970                             m_editPanel->OnMaskDelete(dummy);
00971                         }
00972                         else
00973                             wxBell();
00974                     };
00975                     break;
00976                 case NO_SELECTION:
00977                     {
00978                         wxCommandEvent dummy;
00979                         processed=true;
00980                         m_editPanel->OnMaskDelete(dummy);
00981                     };
00982                     break;
00983             };
00984         };
00985     };
00986     if(!processed)
00987         e.Skip();
00988 };
00989 
00990 void MaskImageCtrl::OnCaptureLost(wxMouseCaptureLostEvent &e)
00991 {
00992     wxFocusEvent dummy;
00993     OnKillFocus(dummy);
00994 };
00995 
00996 void MaskImageCtrl::OnKillFocus(wxFocusEvent &e)
00997 {
00998     if(HasCapture())
00999         ReleaseMouse();
01000     switch(m_maskEditState)
01001     {
01002         case NEW_POLYGON_CREATING:
01003         case NEW_POLYGON_STARTED:
01004             {
01005                 wxBell();
01006                 m_maskEditState=NO_SELECTION;
01007                 HuginBase::MaskPolygon mask;
01008                 m_editingMask=mask;
01009                 m_selectedPoints.clear();
01010                 update();
01011                 break;
01012             };
01013     };
01014 };
01015 
01016 void MaskImageCtrl::startNewPolygon()
01017 {
01018     m_maskEditState=NEW_POLYGON_STARTED;
01019     HuginBase::MaskPolygon newMask;
01020     m_editingMask=newMask;
01021     m_selectedPoints.clear();
01022 };
01023 
01024 wxSize MaskImageCtrl::DoGetBestSize() const
01025 {
01026     return wxSize(m_imageSize.GetWidth(),m_imageSize.GetHeight());
01027 };
01028 
01029 void MaskImageCtrl::update()
01030 {
01031     wxClientDC dc(this);
01032     PrepareDC(dc);
01033     OnDraw(dc);
01034 };
01035 
01036 void MaskImageCtrl::DrawPolygon(wxDC &dc, HuginBase::MaskPolygon poly, bool isSelected, bool drawMarker)
01037 {
01038     unsigned int nrOfPoints=poly.getMaskPolygon().size();
01039     if (nrOfPoints<2)
01040         return;
01041     wxPoint *polygonPoints=new wxPoint[nrOfPoints];
01042     for(unsigned int j=0;j<nrOfPoints;j++)
01043     {
01044         polygonPoints[j]=transform(applyRot(poly.getMaskPolygon()[j]));
01045     };
01046     if(isSelected)
01047         dc.SetPen(wxPen(m_colour_point_unselected, 1, wxPENSTYLE_SOLID));
01048     else
01049         switch(poly.getMaskType())
01050         {
01051             case HuginBase::MaskPolygon::Mask_negative:
01052             case HuginBase::MaskPolygon::Mask_Stack_negative:
01053             case HuginBase::MaskPolygon::Mask_negative_lens:
01054                 dc.SetPen(wxPen(m_colour_polygon_negative, 1, wxPENSTYLE_SOLID));
01055                 break;
01056             case HuginBase::MaskPolygon::Mask_positive:
01057             case HuginBase::MaskPolygon::Mask_Stack_positive:
01058                 dc.SetPen(wxPen(m_colour_polygon_positive, 1, wxPENSTYLE_SOLID));
01059                  break;
01060         };
01061     dc.SetBrush(*wxTRANSPARENT_BRUSH);
01062     if(nrOfPoints>2)
01063         dc.DrawPolygon(nrOfPoints,polygonPoints);
01064     else
01065         dc.DrawLine(polygonPoints[0],polygonPoints[1]);
01066     if(drawMarker)
01067     {
01068         wxPen penSelected(m_colour_point_selected);
01069         wxPen penUnselected(m_colour_point_unselected);
01070         wxBrush brushSelected(m_colour_point_selected);
01071         wxBrush brushUnselected(m_colour_point_unselected);
01072         for(unsigned int j=0;j<nrOfPoints;j++)
01073         {
01074             if(set_contains(m_selectedPoints,j))
01075             {
01076                 dc.SetPen(penSelected);
01077                 dc.SetBrush(brushSelected);
01078             }
01079             else
01080             {
01081                 dc.SetPen(penUnselected);
01082                 dc.SetBrush(brushUnselected);
01083             };
01084             dc.DrawRectangle(polygonPoints[j].x-polygonPointSize,polygonPoints[j].y-polygonPointSize,
01085                             2*polygonPointSize,2*polygonPointSize);
01086         };
01087     };
01088     delete []polygonPoints;
01089 };
01090 
01091 void MaskImageCtrl::DrawCrop()
01092 {
01093     wxClientDC dc(this);
01094     PrepareDC(dc);
01095     DrawCrop(dc);
01096 };
01097 
01098 void MaskImageCtrl::DrawCrop(wxDC & dc)
01099 {
01100     // draw crop rectangle/circle
01101     if(!m_maskMode)
01102     {
01103         // draw all areas without fillings
01104         dc.SetBrush(*wxTRANSPARENT_BRUSH);
01105 #if defined SUPPORTS_WXINVERT
01106         dc.SetLogicalFunction (wxINVERT);
01107 #else
01108         dc.SetPen(wxPen(m_color_selection, 1, wxPENSTYLE_SOLID));
01109 #endif
01110         wxPoint middle=transform(applyRot((m_cropRect.lowerRight()+m_cropRect.upperLeft())/2));
01111 
01112         int c = 8; // size of midpoint cross
01113         dc.DrawLine( middle.x + c, middle.y + c, middle.x - c, middle.y - c);
01114         dc.DrawLine( middle.x - c, middle.y + c, middle.x + c, middle.y - c);
01115         dc.DrawRectangle(wxRect(transform(applyRot(hugin_utils::FDiff2D(m_cropRect.left(), m_cropRect.top()))),
01116                                 transform(applyRot(hugin_utils::FDiff2D(m_cropRect.right(), m_cropRect.bottom())))));
01117 
01118         // draw crop circle as well, if requested.
01119         if (m_cropMode==HuginBase::BaseSrcPanoImage::CROP_CIRCLE)
01120         {
01121             double radius=std::min<int>(m_cropRect.width(),m_cropRect.height())/2.0;
01122             dc.DrawCircle(middle.x, middle.y, scale(radius));
01123         }
01124     };
01125 };
01126 
01127 void MaskImageCtrl::OnDraw(wxDC & dc)
01128 {
01129     if(m_maskEditState!=NO_IMAGE)
01130     {
01131         int offset=scale(HuginBase::maskOffset);
01132         //draw border around image to allow drawing mask over boudaries of image
01133         //don't draw as one complete rectangle to prevent flickering
01134         dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
01135         dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
01136         dc.DrawRectangle(0,0,offset,m_bitmap.GetHeight()+2*offset);
01137         dc.DrawRectangle(0,0,m_bitmap.GetWidth()+2*offset,offset);
01138         dc.DrawRectangle(m_bitmap.GetWidth()+offset,0,m_bitmap.GetWidth()+2*offset,m_bitmap.GetHeight()+2*offset);
01139         dc.DrawRectangle(0,m_bitmap.GetHeight()+offset,m_bitmap.GetWidth()+2*offset,m_bitmap.GetHeight()+2*offset);
01140         dc.DrawBitmap(m_bitmap,offset,offset);
01141         if(m_fitToWindow)
01142         {
01143             //draw border when image is fit to window, otherwise the border (without image) is not updated
01144             wxSize clientSize=GetClientSize();
01145             if(m_bitmap.GetWidth()+2*offset<clientSize.GetWidth())
01146             {
01147                 dc.DrawRectangle(m_bitmap.GetWidth()+2*offset,0,clientSize.GetWidth()-m_bitmap.GetWidth()+2*offset,clientSize.GetHeight());
01148             };
01149             if(m_bitmap.GetHeight()+2*offset<clientSize.GetHeight())
01150             {
01151                 dc.DrawRectangle(0,m_bitmap.GetHeight()+2*offset,clientSize.GetWidth(),clientSize.GetHeight()-m_bitmap.GetHeight()+2*offset);
01152             };
01153         };
01154         if (m_maskMode && m_showActiveMasks && (m_cropMode != HuginBase::SrcPanoImage::NO_CROP || m_masksToDraw.size()>0))
01155         {
01156             //whole image, we need it several times
01157             wxRegion wholeImage(transform(applyRot(hugin_utils::FDiff2D(0,0))),
01158                                 transform(applyRot(hugin_utils::FDiff2D(m_realSize.GetWidth(),m_realSize.GetHeight()))));
01159             wxRegion region;
01160             if (m_cropMode != HuginBase::SrcPanoImage::NO_CROP)
01161             {
01162                 region.Union(wholeImage);
01163                 //now the crop
01164                 switch(m_cropMode)
01165                 {
01166                     case HuginBase::SrcPanoImage::CROP_RECTANGLE:
01167                         region.Subtract(wxRegion(transform(applyRot(m_cropRect.upperLeft())),
01168                             transform(applyRot(m_cropRect.lowerRight()))));
01169                         break;
01170                     case HuginBase::SrcPanoImage::CROP_CIRCLE:
01171                         unsigned int nrOfPoints=dc.GetSize().GetWidth()*2;
01172                         wxPoint* circlePoints=new wxPoint[nrOfPoints];
01173                         vigra::Point2D middle=(m_cropRect.lowerRight()+m_cropRect.upperLeft())/2;
01174                         double radius=std::min<int>(m_cropRect.width(),m_cropRect.height())/2;
01175                         double interval=2*PI/nrOfPoints;
01176                         for(unsigned int i=0;i<nrOfPoints;i++)
01177                         {
01178                             circlePoints[i]=transform(applyRot(hugin_utils::FDiff2D(middle.x+radius*cos(i*interval),middle.y+radius*sin(i*interval))));
01179                         };
01180                         region.Subtract(wxRegion(nrOfPoints,circlePoints));
01181                         delete []circlePoints;
01182                         break;
01183                 };
01184             };
01185             if(m_masksToDraw.size()>0)
01186             {
01187                 for(unsigned int i=0;i<m_masksToDraw.size();i++)
01188                 {
01189                     HuginBase::VectorPolygon poly=m_masksToDraw[i].getMaskPolygon();
01190                     wxPoint *polygonPoints=new wxPoint[poly.size()];
01191                     for(unsigned int j=0;j<poly.size();j++)
01192                     {
01193                         polygonPoints[j]=transform(applyRot(poly[j]));
01194                     };
01195                     wxRegion singleRegion(poly.size(),polygonPoints,wxWINDING_RULE);
01196                     if(m_masksToDraw[i].isInverted())
01197                     {
01198                         wxRegion newRegion(wholeImage);
01199                         newRegion.Subtract(singleRegion);
01200                         region.Union(newRegion);
01201                     }
01202                     else
01203                     {
01204                         region.Union(singleRegion);
01205                     };
01206                     delete []polygonPoints;
01207                 };
01208             };
01209 #ifndef __WXMAC__
01210             // on Windows and GTK we need to compensate to clipping region
01211             // by the scroll offset
01212             // this seems not to be necessary for wxMac
01213             int x;
01214             int y;
01215             GetViewStart(&x,&y);
01216             region.Offset(-x,-y);
01217 #endif
01218             dc.SetDeviceClippingRegion(region);
01219             dc.DrawBitmap(m_disabledBitmap,offset,offset);
01220             dc.DestroyClippingRegion();
01221         };
01222         DrawCrop(dc);
01223         if(m_maskMode && m_imageMask.size()>0)
01224         {
01225             //now draw all polygons
01226             HuginBase::MaskPolygonVector maskList=m_imageMask;
01227             bool drawSelected=(m_maskEditState!=POINTS_ADDING && m_maskEditState!=POINTS_MOVING);
01228             for(unsigned int i=0;i<maskList.size();i++)
01229             {
01230                 if(i!=m_activeMask)
01231                     DrawPolygon(dc,maskList[i],false,false);
01232                 else
01233                     if(drawSelected)
01234                         DrawPolygon(dc,maskList[i],true,true);
01235             };
01236         };
01237         //and now the actual polygon
01238         if(m_maskEditState==POINTS_ADDING || m_maskEditState==POINTS_MOVING || m_maskEditState==NEW_POLYGON_CREATING)
01239             DrawPolygon(dc,m_editingMask,true,true);
01240     }
01241     else
01242     {
01243         // clear the rectangle and exit
01244         dc.SetPen(wxPen(GetBackgroundColour(), 1, wxPENSTYLE_SOLID));
01245         dc.SetBrush(wxBrush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID));
01246         dc.Clear();
01247         return;
01248     };
01249 }
01250 
01251 void MaskImageCtrl::OnSize(wxSizeEvent &e)
01252 {
01253     DEBUG_TRACE("size: " << e.GetSize().GetWidth() << "x" << e.GetSize().GetHeight());
01254     // rescale m_bitmap if needed.
01255     if (m_imageFilename != "") {
01256         if (m_fitToWindow) {
01257             setScale(0);
01258         }
01259     }
01260 };
01261 
01262 void MaskImageCtrl::OnScroll(wxScrollWinEvent &e)
01263 {
01264     m_oldScrollPosX = GetScrollPos(wxHORIZONTAL);
01265     m_oldScrollPosY = GetScrollPos(wxVERTICAL);
01266     e.Skip();
01267 }
01268 
01269 void MaskImageCtrl::rescaleImage()
01270 {
01271     if (m_maskEditState == NO_IMAGE)
01272     {
01273         return;
01274     }
01275 #ifndef SUPPORTS_WXINVERT
01276     //determine average colour and set selection colour corresponding
01277     vigra::FindAverage<vigra::RGBValue<vigra::UInt8> > average;
01278     vigra::inspectImage(vigra::srcImageRange(*(m_img->get8BitImage())), average);
01279     vigra::RGBValue<vigra::UInt8> RGBaverage=average.average();
01280     if(RGBaverage[0]<180 && RGBaverage[1]<180 && RGBaverage[2]<180)
01281     {
01282         m_color_selection=*wxWHITE;
01283     }
01284     else
01285     {
01286         m_color_selection=*wxBLACK;
01287     };
01288 #endif
01289     wxImage img = imageCacheEntry2wxImage(m_img);
01290     if (img.GetWidth() == 0)
01291     {
01292         return;
01293     }
01294     m_imageSize = wxSize(img.GetWidth(), img.GetHeight());
01295     m_realSize = m_imageSize;
01296     m_imageSize.IncBy(2*HuginBase::maskOffset);
01297     if (m_fitToWindow)
01298         m_scaleFactor = calcAutoScaleFactor(m_imageSize);
01299 
01300     //scaling image to screen size
01301     if (getScaleFactor()!=1.0)
01302     {
01303         m_imageSize.SetWidth(scale(m_imageSize.GetWidth()));
01304         m_imageSize.SetHeight(scale(m_imageSize.GetHeight()));
01305         img=img.Scale(scale(m_realSize.GetWidth()), scale(m_realSize.GetHeight()));
01306     }
01307     else
01308     {
01309         //the conversion to disabled m_bitmap would work on the original cached image file
01310         //therefore we need to create a copy to work on it
01311         img=img.Copy();
01312     };
01313     //and now rotating
01314     switch(m_imgRotation)
01315     {
01316         case ROT90:
01317             img = img.Rotate90(true);
01318             break;
01319         case ROT180:
01320                 // this is slower than it needs to be...
01321             img = img.Rotate90(true);
01322             img = img.Rotate90(true);
01323             break;
01324         case ROT270:
01325             img = img.Rotate90(false);
01326             break;
01327         default:
01328             break;
01329     }
01330     // do color correction only if input image has icc profile or if we found a monitor profile
01331     if (!m_img->iccProfile->empty() || huginApp::Get()->HasMonitorProfile())
01332     {
01333         HuginBase::Color::CorrectImage(img, *(m_img->iccProfile), huginApp::Get()->GetMonitorProfile());
01334     };
01335     m_bitmap=wxBitmap(img);
01336 
01337     //create disabled m_bitmap for drawing active masks
01338 #if wxCHECK_VERSION(2,9,0)
01339     img = img.ConvertToDisabled(192);
01340 #else
01341     {
01342         int width = img.GetWidth();
01343         int height = img.GetHeight();
01344         for (int y = height-1; y >= 0; --y)
01345         {
01346             for (int x = width-1; x >= 0; --x)
01347             {
01348                 unsigned char* data = img.GetData() + (y*(width*3))+(x*3);
01349                 unsigned char* r = data;
01350                 unsigned char* g = data+1;
01351                 unsigned char* b = data+2;
01352                 *r=(unsigned char)wxMin(0.6*(*r)+77,255);
01353                 *b=(unsigned char)wxMin(0.6*(*b)+77,255);
01354                 *g=(unsigned char)wxMin(0.6*(*g)+77,255);
01355             }
01356         }
01357     }
01358 #endif
01359     m_disabledBitmap=wxBitmap(img);
01360     if (m_imgRotation == ROT90 || m_imgRotation == ROT270)
01361     {
01362         SetVirtualSize(m_imageSize.GetHeight(), m_imageSize.GetWidth());
01363     }
01364     else
01365     {
01366         SetVirtualSize(m_imageSize.GetWidth(), m_imageSize.GetHeight());
01367     };
01368     SetScrollRate(1,1);
01369     Refresh(true);
01370 };
01371 
01372 void MaskImageCtrl::DrawSelectionRectangle()
01373 {
01374     wxClientDC dc(this);
01375     PrepareDC(dc);
01376 #if defined SUPPORTS_WXINVERT
01377     dc.SetLogicalFunction(wxINVERT);
01378     dc.SetPen(wxPen(*wxWHITE, 1, wxPENSTYLE_DOT));
01379 #else
01380     OnDraw(dc);
01381     dc.SetPen(wxPen(m_color_selection, scale(1), wxPENSTYLE_DOT));
01382 #endif
01383     dc.SetBrush(*wxTRANSPARENT_BRUSH);
01384     dc.DrawRectangle(m_dragStartPos.x,m_dragStartPos.y,
01385         (m_currentPos.x-m_dragStartPos.x),(m_currentPos.y-m_dragStartPos.y));
01386 };
01387 
01388 void MaskImageCtrl::FindPolygon(hugin_utils::FDiff2D p)
01389 {
01390     unsigned int selectedPolygon=UINT_MAX;
01391     unsigned int i=0;
01392     while(selectedPolygon==UINT_MAX && i<m_imageMask.size())
01393     {
01394         if(m_imageMask[i].isInside(p))
01395             selectedPolygon=i;
01396         i++;
01397     };
01398     if(selectedPolygon<UINT_MAX)
01399         m_editPanel->SelectMask(selectedPolygon);
01400 };
01401 
01402 bool MaskImageCtrl::SelectPointsInsideMouseRect(HuginBase::UIntSet &points,const bool considerSelectedOnly)
01403 {
01404     bool found=false;
01405     hugin_utils::FDiff2D p1=applyRotInv(invtransform(m_dragStartPos));
01406     hugin_utils::FDiff2D p2=applyRotInv(invtransform(m_currentPos));
01407     double xmin=std::min(p1.x,p2.x)-maxSelectionDistance;
01408     double xmax=std::max(p1.x,p2.x)+maxSelectionDistance;
01409     double ymin=std::min(p1.y,p2.y)-maxSelectionDistance;
01410     double ymax=std::max(p1.y,p2.y)+maxSelectionDistance;
01411     const HuginBase::VectorPolygon poly=m_editingMask.getMaskPolygon();
01412     for(unsigned int i=0;i<poly.size();i++)
01413     {
01414         bool activePoints=true;
01415         if(considerSelectedOnly)
01416             activePoints=set_contains(m_selectedPoints,i);
01417         if(activePoints && xmin<=poly[i].x && poly[i].x<=xmax && ymin<=poly[i].y && poly[i].y<=ymax)
01418         {
01419             points.insert(i);
01420             found=true;
01421         };
01422     };
01423     return found;
01424 };
01425 
01426 void MaskImageCtrl::setScale(double factor)
01427 {
01428     if (factor == 0)
01429     {
01430         m_fitToWindow = true;
01431         factor = calcAutoScaleFactor(m_imageSize);
01432     }
01433     else
01434     {
01435         m_fitToWindow = false;
01436     }
01437     DEBUG_DEBUG("new scale factor:" << factor);
01438     // update if factor changed
01439     if (factor != m_scaleFactor)
01440     {
01441         m_scaleFactor = factor;
01442         // keep existing scale focussed.
01443         rescaleImage();
01444     }
01445 };
01446 
01447 double MaskImageCtrl::calcAutoScaleFactor(wxSize size)
01448 {
01449     int w = size.GetWidth();
01450     int h = size.GetHeight();
01451     if (m_imgRotation ==  ROT90 || m_imgRotation == ROT270)
01452     {
01453         int t = w;
01454         w = h;
01455         h = t;
01456     }
01457 
01458     wxSize csize = GetSize();
01459     DEBUG_DEBUG("csize: " << csize.GetWidth() << "x" << csize.GetHeight() << "image: " << w << "x" << h);
01460     double s1 = (double)csize.GetWidth()/w;
01461     double s2 = (double)csize.GetHeight()/h;
01462     DEBUG_DEBUG("s1: " << s1 << "  s2:" << s2);
01463     return s1 < s2 ? s1 : s2;
01464 };
01465 
01466 double MaskImageCtrl::getScaleFactor() const
01467 {
01468     return m_scaleFactor;
01469 };
01470 
01471 void MaskImageCtrl::setDrawingActiveMasks(bool newDrawActiveMasks)
01472 {
01473     m_showActiveMasks=newDrawActiveMasks;
01474     update();
01475 };
01476 
01477 IMPLEMENT_DYNAMIC_CLASS(MaskImageCtrl, wxScrolledWindow)
01478 
01479 MaskImageCtrlXmlHandler::MaskImageCtrlXmlHandler()
01480                 : wxXmlResourceHandler()
01481 {
01482     AddWindowStyles();
01483 };
01484 
01485 wxObject *MaskImageCtrlXmlHandler::DoCreateResource()
01486 {
01487     XRC_MAKE_INSTANCE(cp, MaskImageCtrl)
01488 
01489     cp->Create(m_parentAsWindow,
01490                    GetID(),
01491                    GetPosition(), GetSize(),
01492                    GetStyle(wxT("style")),
01493                    GetName());
01494 
01495     SetupWindow(cp);
01496 
01497     return cp;
01498 };
01499 
01500 bool MaskImageCtrlXmlHandler::CanHandle(wxXmlNode *node)
01501 {
01502     return IsOfClass(node, wxT("MaskImageCtrl"));
01503 };
01504 
01505 IMPLEMENT_DYNAMIC_CLASS(MaskImageCtrlXmlHandler, wxXmlResourceHandler)

Generated on 8 Feb 2016 for Hugintrunk by  doxygen 1.4.7