Outlining, Dragging, and Pasting a Region (C++ 4.0 and later)

Take the following steps to add code that lets you outline an area with a mouse, drag a copy of the selected area, and paste the copy into another part of the bitmap:

1. Start with the project that you created in Loading and Displaying an Image.

2. Add another LEAD control with an ID of IDC_LEAD2, set its Visible property to FALSE, and give it a variable name of m_Lead2. (You can follow the same instructions as when adding the first LEAD control.)

3. Go to the Project WorkSpace and click the FileView tab.

4. Edit TUTORDLG.H and insert the following lines in the definition of CTutorDlg after DECLARE_MESSAGE_MAP():

BOOL ReadyToDrag;    //The state after marking the region but before dragging
BOOL Dragging;        //The state when the mouse is used for dragging the floater
float StartX;            //Starting X position in screen pixels
float StartY;        //Starting Y position in screen pixels
float FloaterX;        //Floater X position in screen pixels
float FloaterY;        //Floater Y position in screen pixels
float ZoomFactorX;  //Used for translating positioning information
float ZoomFactorY;  //Used for translating positioning information

5. Go to the Project Workspace and click the ResourceView tab.

6. Double-click Dialog and double-click IDD_TUTOR_DIALOG to bring up the application's dialog box.

7. image\btncmd.gif Add two new buttons to use for selecting and pasting the region. To do this, select the button control on the Controls toolbar. Then, click and drag to position the button on the dialog box.

8. Double-click each button and change its values as follows:

ID

Caption

IDC_SELRGN

Select Region

IDC_PASTEFLOATER

Paste Floater

9. Start the Class Wizard and add code for the IDC_SELRGN button. To do so, press Ctrl-W to go to the MFC Class Wizard; then do the following:

a. Click the Message Maps tab.

b. In the Class Name combo box, select CTutorDlg.

c. In the Object IDs list box, select IDC_SELRGN.

d. In the Messages list box, select BN_CLICKED.

e. Click the Add function button. Choose OK for the default function name (OnSelRgn).

f. Click the Edit Code button to start entering the code.

10. Enter new code as follows:

void CTutorDlg::OnSelrgn() 
{
   // TODO: Add your control notification handler code here
   m_Lead1.SetRgnMarkingMode(RGNMARK_FREEHAND);
   MessageBox("Draw a freehand region");

}

11. Start the Class Wizard and add code for the IDC_PASTEFLOATER button. To do so, press Ctrl-W to go to the MFC Class Wizard; then do the following:

a. Click the Message Maps tab.

b. In the Class Name combo box, select CTutorDlg.

c. In the Object IDs list box, select IDC_PASTEFLOATER.

d. In the Messages list box, select BN_CLICKED.

e. Click the Add function button. Choose OK for the default function name (OnPastefloater).

f. Click the Edit Code button to start entering the code.

12. Enter new code as follows:

void CTutorDlg::OnPastefloater() 
{
   // Variable for the Combine operation.
   long MyOp;

   // Variables for the client area coordinates.
   float LCRgnX, LCRgnY , LCRgnWidth, LCRgnHeight;

   // Variables for the bitmap coordinates.
   float LBRgnX, LBRgnY , LBRgnWidth, LBRgnHeight;

   // Do nothing if there is no floater.
   if (m_Lead1.GetFloater() == 0) return;

   // Set the scale mode to pixels so that we do not have to 
   // translate mouse coordinates
   m_Lead1.SetScaleMode(3);

   // Get the floater into another bitmap
   m_Lead2.SetScaleMode(m_Lead1.GetScaleMode());
   m_Lead2.SetBitmap(m_Lead1.GetFloater());

   // Get the floater's client coordinates into local variables.
   LCRgnX = m_Lead1.GetFloaterDstLeft();
   LCRgnY = m_Lead1.GetFloaterDstTop();
   LCRgnWidth = m_Lead1.GetFloaterDstWidth();
   LCRgnHeight = m_Lead1.GetFloaterDstHeight();

   // Delete the floater.
   m_Lead1.SetFloaterVisible(FALSE);
   m_Lead1.SetFloater(0);

   // Translate the client coordinates to bitmap coordinates.
   LBRgnX = ((LCRgnX - m_Lead1.GetDstLeft()) / ZoomFactorX) + m_Lead1.GetSrcLeft();
   LBRgnY = ((LCRgnY - m_Lead1.GetDstTop()) / ZoomFactorY) + m_Lead1.GetSrcTop();
   LBRgnWidth = LCRgnWidth / ZoomFactorX;
   LBRgnHeight = LCRgnHeight / ZoomFactorY;

   // Reposition the region to use as a mask for the Combine method.
   m_Lead1.OffsetRgn(LBRgnX - m_Lead1.GetRgnLeft(), LBRgnY - m_Lead1.GetRgnTop());

   // Use the Combine method to paste the Lead2 bitmap into the Lead1 bitmap.
   MyOp = CB_OP_ADD + CB_DST_0; // Operation flags for a simple paste.
   m_Lead1.Combine(LBRgnX, LBRgnY, LBRgnWidth, LBRgnHeight, 
               m_Lead2.GetBitmap(), 0.0f, 0.0f, MyOp);

   // Repaint the part of the client area that has changed.
   m_Lead1.RepaintRect(LCRgnX, LCRgnY, LCRgnWidth, LCRgnHeight, FALSE);

   // Free the region.
   m_Lead1.FreeRgn();

}

13. To add the code for LEAD mouse events, do the following:

a. Press Ctrl-W to go to the MFC ClassWizard.

b. In the Class Name combo box, select CTutorDlg.

c. In the Object IDs list box, select IDC_LEAD1.

d. Continue with the remaining steps for each mouse event.

14. In the MFC ClassWizard, double-click the MouseDown event and add code as follows:

void CTutorDlg::OnMouseDownLead1(short Button, short Shift, long X, long Y) 
{
   // Declare local variables.
   float BitmapX, BitmapY;
   float NewX, NewY, NewWidth, NewHeight;

   // Do nothing if we are drawing a region.
   if (m_Lead1.GetRgnMarkingMode() != RGNMARK_NONE) return;

   //  Save the starting position, in case we need it.
   StartY = (float)Y;
   StartX = (float)X;

   // if we are ready to drag the selection, get a floater.
   if (ReadyToDrag == TRUE)
   {
      // Translate the current mouse coordinates.
      // These coordinates account for the zoom factor and offset.
      ZoomFactorX = m_Lead1.GetDstWidth() / m_Lead1.GetSrcWidth();
      ZoomFactorY = m_Lead1.GetDstHeight() / m_Lead1.GetSrcHeight();
      BitmapX = (X / ZoomFactorX) - (m_Lead1.GetDstLeft() / ZoomFactorX)
              + m_Lead1.GetSrcLeft();
      BitmapY = (Y / ZoomFactorY) - (m_Lead1.GetDstTop() / ZoomFactorY) 
               + m_Lead1.GetSrcTop();

      // Continue to create the floater if the mouse is pointing to 
      //  the region we marked.
      if (m_Lead1.IsPtInRgn(BitmapX, BitmapY))
      {
         // Hide the region frame.
         m_Lead1.SetRgnFrameType(RGNFRAME_NONE);

         // Create the floater bitmap, which will be the part of the main bitmap 
         // that is in the region's bounding rectangle.
         m_Lead1.SetFloater(m_Lead1.GetBitmap());

         // Translate the bitmap region coordinates to client area coordinates.
         NewY = ((m_Lead1.GetRgnTop() - m_Lead1.GetSrcTop()) * ZoomFactorY) 
               + m_Lead1.GetDstTop();
         NewX = ((m_Lead1.GetRgnLeft() - m_Lead1.GetSrcLeft()) * ZoomFactorX)
               + m_Lead1.GetDstLeft();
         NewWidth = m_Lead1.GetRgnWidth() * ZoomFactorX;
         NewHeight = m_Lead1.GetRgnHeight() * ZoomFactorY;

         // Set the initial display position of the floater.
         m_Lead1.SetFloaterDstRect(NewX, NewY, NewWidth, NewHeight);

         // Set form-level variables.
         FloaterY = m_Lead1.GetFloaterDstTop();
         FloaterX = m_Lead1.GetFloaterDstLeft();
         m_Lead1.SetFloaterVisible(TRUE);
         Dragging = TRUE;
         ReadyToDrag = FALSE;
      }
   }
}

15. In the MFC ClassWizard, double-click the MouseMove event and add code as follows:

void CTutorDlg::OnMouseMoveLead1(short Button, short Shift, long X, long Y) 
{
   // Variables for repositioning the floater.
   float NewX, NewY, NewWidth, NewHeight, XDelta, YDelta;

   // Do nothing if we are drawing a region.
   if (m_Lead1.GetRgnMarkingMode() != RGNMARK_NONE) return;

   // Reposition the floater if we are dragging it.
   if ((Dragging == TRUE) && (Button == 1) && (m_Lead1.GetFloater() != 0))
   {
      if (m_Lead1.IsPtInFloater((float)X, (float)Y))
      {
         // Update the position variables.
         XDelta = (float)X - StartX;
         YDelta = (float)Y - StartY;
         NewX = FloaterX + XDelta;
         NewY = FloaterY + YDelta;
         NewWidth = m_Lead1.GetFloaterDstWidth();
         NewHeight = m_Lead1.GetFloaterDstHeight();

         // Reposition the floater.
         m_Lead1.SetFloaterDstRect(NewX, NewY, NewWidth, NewHeight);

         // Save the form-level position variables.
         FloaterY = NewY;
         FloaterX = NewX;
         StartY = (float)Y;
         StartX = (float)X;
      }
   }
}

16. In the MFC ClassWizard, double-click the MouseUp event and add code as follows:

void CTutorDlg::OnMouseUpLead1(short Button, short Shift, long X, long Y) 
{
   //  If we were drawing a region, set up for the next operation.
   if (m_Lead1.GetRgnMarkingMode() != RGNMARK_NONE)
   {
      m_Lead1.SetRgnMarkingMode( RGNMARK_NONE);
      m_Lead1.SetRgnFrameType( RGNFRAME_STATIC);
      ReadyToDrag = TRUE;
      MessageBox("Now, drag the selection to another place.");
   }
}

17. Run your program to test it.