Cropping Graphics Part 4 by Erick Tejkowsi
03-28-03




Today we'll look at last part of this tutorial (Part 4). These tutorials cover the basics of how to implement click-and-drag graphics selection and cropping, like you'll find in many popular applications (e.g.Photoshop, iPhoto, and the Finder). This week we'll add a lasso selection and offer live feedback.

The tutorial emulates a Cocoa project available from Apple. Go check out the original code and come back here ready for some REALbasic coding. NOTE: This demo is made with OS X in mind.

Augment the Interface
Launch REALbasic and open a copy of the last project. To the Window1 interface, add a checkbox labeled . Then, add another entry to PopupMenu2 property: Lasso. The result will look something like this (when tested with Debug-Run):

03-28-02_img1.jpg (25k)

If you're following along from the last tutorial, you may have to resize the window a bit to accommodate the new checkbox. Now, let's move on to the code.

Add the Code
Double-click the Window Editor of Window1 to open the Code Editor. Choose Edit-New Property to add a property to the window: polyPoints(0) as integer. This array will store a list of points that will make up the outline of the lasso selection.

Next, change the code in the MouseDrag event of Canvas1 to read:

  
  
  //Canvas1.MouseDrag
  dim g as graphics
  g=pictureSrc.graphics
  if lastx<>x OR lasty<>y then
    lastX = X
    lastY = Y
    
    g.foreColor=rgb(200,200,200)
    g.drawpicture scenery,0,0
    g.drawrect startX,startY,lastX-startX,lastY-startY
    g=me.graphics
    g.foreColor=rgb(200,200,200)
    //don't do for lasso type (3)
    'if popupMenu2.listindex<>3 then
    g.drawpicture scenery,0,0
    'end if
    
    //plain style
    select case popupMenu1.listindex
    case 0
      //red
      g.foreColor = rgb(255,0,0)
    case 1
      //green
      g.foreColor = rgb(0,255,0)
    case 2
      //blue
      g.foreColor = rgb(0,0,255)
    case 3
      //grey
      g.foreColor = rgb(200,200,200)
    end select
    
    select case popupMenu2.listindex
    case 0
      
      if startX
									
				<lastX and startY<lastY then g.drawrect startX,startY,lastX-startX,lastY-startY elseif startX>
				
									lastX and startY>lastY then
        g.drawrect lastX,lastY,startX-lastX,startY-lastY
      elseif startX>lastX then
        g.drawrect lastX,startY,startX-lastX,lastY-startY
      elseif startY>lastY then
        g.drawrect startX,lastY,lastX-startX,startY-lastY
      end if
    case 1
      //Finder style
      if startX
									
				<lastX and startY<lastY then g.drawrect startX,startY,lastX-startX,lastY-startY g.drawpicture pictureMask,startX+1,startY+1,lastX-startX-1,lastY-startY-1 elseif startX>
				
									lastX and startY>lastY then
        g.drawrect lastX,lastY,startX-lastX,startY-lastY
        g.drawpicture pictureMask,lastX+1,lastY+1,startX-lastX-1,startY-lastY-1
      elseif startX>lastX then
        g.drawrect lastX,startY,startX-lastX,lastY-startY
        g.drawpicture pictureMask,lastX+1,startY+1,startX-lastX-1,lastY-startY-1
      elseif startY>lastY then
        g.drawrect startX,lastY,lastX-startX,startY-lastY
        g.drawpicture pictureMask,startX+1,lastY+1,lastX-startX-1,startY-lastY-1
      end if
    case 2
      //iPhoto style
      if startX
									
				<lastX and startY<lastY then g.drawrect startX,startY,lastX-startX,lastY-startY g.drawpicture pictureMask,0,0,me.width,me.height g.drawpicture scenery,startX+1,startY+1,lastX-startX-1,lastY-startY-1,startX+1,startY+1,lastX-startX-1,lastY-startY-1 'g.drawpicture scenery,startX,startY,lastX-startX,lastY-startY,startX,startY,lastX-startX,lastY-startY elseif startX>
				
									lastX and startY>lastY then
        g.drawrect lastX,lastY,startX-lastX,startY-lastY
        g.drawpicture pictureMask,0,0,me.width,me.height
        g.drawpicture scenery,lastX+1,lastY+1,startX-lastX-1,startY-lastY-1,lastX+1,lastY+1,startX-lastX-1,startY-lastY-1
      elseif startX>lastX then
        g.drawrect lastX,startY,startX-lastX,lastY-startY
        g.drawpicture pictureMask,0,0,me.width,me.height
        g.drawpicture scenery,lastX+1,startY+1,startX-lastX-1,lastY-startY-1,lastX+1,startY+1,startX-lastX-1,lastY-startY-1
      elseif startY>lastY then
        g.drawrect startX,lastY,lastX-startX,startY-lastY
        g.drawpicture pictureMask,0,0,me.width,me.height
        g.drawpicture scenery,startX+1,lastY+1,lastX-startX-1,startY-lastY-1,startX+1,lastY+1,lastX-startX-1,startY-lastY-1
      end if
    case 3
      //lasso style
      polyPoints.append lastX
      polyPoints.append lastY
      
      pictureMask.graphics.drawpicture scenery,0,0
      pictureMask.mask.graphics.foreColor=rgb(255,255,255)
      pictureMask.mask.graphics.fillrect 0,0,me.width,me.height
      pictureMask.mask.graphics.foreColor=rgb(200,200,200)
      pictureMask.mask.graphics.fillpolygon polyPoints
      pictureMask.mask.graphics.foreColor=rgb(0,0,0)
      pictureMask.mask.graphics.drawpolygon polyPoints
      
      select case popupMenu1.listindex
      case 0
        //red
        pictureMask.graphics.foreColor = rgb(255,0,0)
      case 1
        //green
        pictureMask.graphics.foreColor = rgb(0,255,0)
      case 2
        //blue
        pictureMask.graphics.foreColor = rgb(0,0,255)
      case 3
        //grey
        pictureMask.graphics.foreColor = rgb(200,200,200)
      end select
      pictureMask.graphics.fillpolygon polyPoints
      
      g.drawpicture pictureMask,0,0,me.width,me.height
      g.foreColor=pictureMask.graphics.foreColor
      g.drawpolygon polyPoints
      
    end select 
    
  end if
  
  AutoDraw
  

Then, navigate to the MouseUp event of Canvas1. Remove the code that you have there in favor of the new code. The code in the MouseDrag and MouseUp events closely matches earlier code with the addition of the lasso selection.

  
  
  dim g,gg as graphics
  
  
  g=pictureDest.graphics
  gg=canvas2.graphics
  
  g.clearrect 0,0,g.width,g.height 
  gg.forecolor=rgb(255,255,255)
  gg.fillrect 0,0,g.width,g.height 
  
  if popupMenu2.listindex<>3 then
    if startX
									
				<lastX and startY<lastY then g.drawpicture scenery,startX,startY,lastX-startX,lastY-startY,startX,startY,lastX-startX,lastY-startY gg.drawpicture scenery,startX,startY,lastX-startX,lastY-startY,startX,startY,lastX-startX,lastY-startY elseif startX>
				
									lastX and startY>lastY then
      g.drawpicture scenery,lastX,lastY,startX-lastX,startY-lastY,lastX,lastY,startX-lastX,startY-lastY
      gg.drawpicture scenery,lastX,lastY,startX-lastX,startY-lastY,lastX,lastY,startX-lastX,startY-lastY
    elseif startX>lastX then
      g.drawpicture scenery,lastX,startY,startX-lastX,lastY-startY,lastX,startY,startX-lastX,lastY-startY
      gg.drawpicture scenery,lastX,startY,startX-lastX,lastY-startY,lastX,startY,startX-lastX,lastY-startY
    elseif startY>lastY then
      g.drawpicture scenery,startX,lastY,lastX-startX,startY-lastY,startX,lastY,lastX-startX,startY-lastY
      gg.drawpicture scenery,startX,lastY,lastX-startX,startY-lastY,startX,lastY,lastX-startX,startY-lastY
    end if
  else
    //lasso style
    if startX
									
				<lastX and startY<lastY then g.drawpicture pictureMask,startX,startY,lastX-startX,lastY-startY,startX,startY,lastX-startX,lastY-startY gg.drawpicture pictureMask,startX,startY,lastX-startX,lastY-startY,startX,startY,lastX-startX,lastY-startY elseif startX>
				
									lastX and startY>lastY then
      g.drawpicture pictureMask,lastX,lastY,startX-lastX,startY-lastY,lastX,lastY,startX-lastX,startY-lastY
      gg.drawpicture pictureMask,lastX,lastY,startX-lastX,startY-lastY,lastX,lastY,startX-lastX,startY-lastY
    elseif startX>lastX then
      g.drawpicture pictureMask,lastX,startY,startX-lastX,lastY-startY,lastX,startY,startX-lastX,lastY-startY
      gg.drawpicture pictureMask,lastX,startY,startX-lastX,lastY-startY,lastX,startY,startX-lastX,lastY-startY
    elseif startY>lastY then
      g.drawpicture pictureMask,startX,lastY,lastX-startX,startY-lastY,startX,lastY,lastX-startX,startY-lastY
      gg.drawpicture pictureMask,startX,lastY,lastX-startX,startY-lastY,startX,lastY,lastX-startX,startY-lastY
    end if
    
    pictureDest = newpicture(canvas1.width,canvas1.height,32)
    pictureDest.graphics.drawpicture scenery,0,0
    pictureDest.mask.graphics.foreColor=rgb(255,255,255)
    pictureDest.mask.graphics.fillrect 0,0,me.width,me.height
    pictureDest.mask.graphics.foreColor=rgb(0,0,0)
    pictureDest.mask.graphics.fillpolygon polyPoints
    gg.drawpicture pictureDest,0,0,me.width,me.height
    DrawMask//refresh
  end if
  
  

Finally, create a new method named AutoDraw by choosing Edit-New Method. Navigate to this new AutoDraw method and add the following code. This method takes care of continuously updating the display when the new checkbox is selected.

   
  dim g,gg as graphics
  
  if checkBox1.value then
    g=pictureDest.graphics
    gg=canvas2.graphics
    
    g.clearrect 0,0,g.width,g.height 
    gg.forecolor=rgb(255,255,255)
    gg.fillrect 0,0,g.width,g.height 
    
    if popupMenu2.listindex<>3 then
      if startX
									
				<lastX and startY<lastY then g.drawpicture scenery,startX,startY,lastX-startX,lastY-startY,startX,startY,lastX-startX,lastY-startY gg.drawpicture scenery,startX,startY,lastX-startX,lastY-startY,startX,startY,lastX-startX,lastY-startY elseif startX>
				
									lastX and startY>lastY then
        g.drawpicture scenery,lastX,lastY,startX-lastX,startY-lastY,lastX,lastY,startX-lastX,startY-lastY
        gg.drawpicture scenery,lastX,lastY,startX-lastX,startY-lastY,lastX,lastY,startX-lastX,startY-lastY
      elseif startX>lastX then
        g.drawpicture scenery,lastX,startY,startX-lastX,lastY-startY,lastX,startY,startX-lastX,lastY-startY
        gg.drawpicture scenery,lastX,startY,startX-lastX,lastY-startY,lastX,startY,startX-lastX,lastY-startY
      elseif startY>lastY then
        g.drawpicture scenery,startX,lastY,lastX-startX,startY-lastY,startX,lastY,lastX-startX,startY-lastY
        gg.drawpicture scenery,startX,lastY,lastX-startX,startY-lastY,startX,lastY,lastX-startX,startY-lastY
      end if
    else
      //lasso style
      if startX
									
				<lastX and startY<lastY then g.drawpicture pictureMask,startX,startY,lastX-startX,lastY-startY,startX,startY,lastX-startX,lastY-startY gg.drawpicture pictureMask,startX,startY,lastX-startX,lastY-startY,startX,startY,lastX-startX,lastY-startY elseif startX>
				
									lastX and startY>lastY then
        g.drawpicture pictureMask,lastX,lastY,startX-lastX,startY-lastY,lastX,lastY,startX-lastX,startY-lastY
        gg.drawpicture pictureMask,lastX,lastY,startX-lastX,startY-lastY,lastX,lastY,startX-lastX,startY-lastY
      elseif startX>lastX then
        g.drawpicture pictureMask,lastX,startY,startX-lastX,lastY-startY,lastX,startY,startX-lastX,lastY-startY
        gg.drawpicture pictureMask,lastX,startY,startX-lastX,lastY-startY,lastX,startY,startX-lastX,lastY-startY
      elseif startY>lastY then
        g.drawpicture pictureMask,startX,lastY,lastX-startX,startY-lastY,startX,lastY,lastX-startX,startY-lastY
        gg.drawpicture pictureMask,startX,lastY,lastX-startX,startY-lastY,startX,lastY,lastX-startX,startY-lastY
      end if
      
      pictureDest = newpicture(canvas1.width,canvas1.height,32)
      pictureDest.graphics.drawpicture scenery,0,0
      pictureDest.mask.graphics.foreColor=rgb(255,255,255)
      pictureDest.mask.graphics.fillrect 0,0,me.width,me.height
      pictureDest.mask.graphics.foreColor=rgb(0,0,0)
      pictureDest.mask.graphics.fillpolygon polyPoints
      gg.drawpicture pictureDest,0,0,me.width,me.height
      'DrawMask//refresh
    end if
  end if

Select Debug-Run to test your work. Click and drag in the image on the left side of the window to view a cropped version on the right side. Select the new Lasso selection feature to see it in action.

03-28-02_img2.jpg (21k)

Conclusion
You can download the completed project for this week here. That's it for this multi-part tutorial. Hopefully you learned a trick or two along the way. Next time we'll move on to a new topic. See you then!