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

Generated on 29 Aug 2015 for Hugintrunk by  doxygen 1.4.7