#!/usr/bin/env python

## NOTE: code from V. Stokes for the wxPython-users mailing list
##       modified by Chris Barker 2012.02.09
                      
'''
Purpose: to show how wx.Overlay() can be used to draw an object then erase it 
         (recover the bitmap before the object was drawn on it).

In this case, the overlay is used to draw a highlight around the rectangle on
screen that the mouse is currently in.

  This code snippet can be quite useful for the development of a more complex
  interactive drawing package.

 Notes:
  1. wx.ClientDC --- draws to window (frame) object, the interior (client part)
  2. wx.PaintDC  --- similiar to wx.ClientDC, but only used when processing a 
                     wx.PaintEvent
  3. Code is heavily commented for my own purposes.                   
  4. Code has been tested with Python 2.6.6, wxPython 2.8.12.1 on both a Windows
     Vista and 7 platform. No anomalies have been observed.
  5. TESTMODE = True, will "print" additional information for test purposes.   
  
  Creator: V. Stokes (vs@it.uu.se)
  Mods: Tim Roberts, Chris Barker
  Version: 2012.02.10.01, 2012.02.08.02
'''

import wx
import sys
print 'Python version: %s\n' %sys.version
print 'wxPython version: %s\n' %wx.version()

TESTMODE = False
TESTMODE = True

class TestPanel(wx.Panel):
    # # Define my own subclass for wx.Panel
    def __init__(self, parent):
        wx.Panel.__init__(self, parent, -1)        
        
        # wx.EVT_PAINT will occur when this window (panel) needs to be redrawn
        self.Bind(wx.EVT_PAINT, self.onPaint)
        # wx.EVT_MOTION will occur when the mouse is moved
        self.Bind(wx.EVT_MOTION, self.onMouseMove)       
        # To save previous cell (rectangle) that mouse was over        
        self.oldCell = None  
        # Define the location of two rectangles (cell grid)
        self.rect1 = wx.Rect(50,60,200,250) 
        self.rect2 = wx.Rect(250,60,200,250)
        # Create an instance of wx.Overlay (to handle Overlay processing)
        self.overlay = wx.Overlay()
        # Instantiate the device context for drawing when a non EVT_PAINT 
        #  event fires.
        #  Note! wx.PaintDC() MUST be instantiated inside the method
        #  that is bound to the EVT_PAINT event
        # self.dcC = wx.ClientDC(self)   
       
        if TESTMODE:
            self.onPaintCounter = 0 
            self.redrawOverlayCounter = 0

    def onPaint(self, evt): 
        '''
         Purpose: process the EVT_PAINT event
        '''
        dcP = wx.PaintDC(self)  # dc for EVT_PAINT
        if TESTMODE:
            self.onPaintCounter += 1
            print 'Enter OnPaint -- %3d' %self.onPaintCounter        
        ## Draw/redraw static objects when wx.EVT_PAINT event fires 
        # Put some polygons on a sky blue background
        dcP.SetBackground(wx.Brush("sky blue")) # set BG
        dcP.Clear()                   # blits BG to screen 
        
        dcP.SetPen(wx.Pen("red", 1))
        dcP.SetBrush(wx.CYAN_BRUSH)
        coords = ((40,40),(200,220),(210,120),(120,300))
        dcP.DrawPolygon(coords)
      
        dcP.SetPen(wx.Pen("white", 2))
        dcP.SetBrush(wx.RED_BRUSH)
        coords = ((10,50),(100,200),(210,30),(120,280))
        dcP.DrawPolygon(coords)

        # Draw my cell grid (edges only of two rectangles)
        dcP.SetPen(wx.Pen("black", 2))
        dcP.SetBrush(wx.TRANSPARENT_BRUSH)        
        dcP.DrawRectangleRect(self.rect1) 
        dcP.SetPen(wx.Pen("green", 2))
        dcP.DrawRectangleRect(self.rect2)
 
    def onMouseMove(self, evt): 
        '''
          Purpose: track the movement of the mouse and
                   process its movement into, between cells,
                   and exit from the cell grid
        '''        
        inCell = None  
        # Get mouse coordinates (referenced to this frame (panel))          
        pt = evt.GetPosition()                   
        if self.rect1.Inside(pt): 
            inCell = self.rect1
        if self.rect2.Inside(pt): 
            inCell = self.rect2                      
        if inCell == self.oldCell: 
            # State of cell grid has not changed: do nothing
            return
        else: 
            # In a new cell or moved out of cell grid           
            if TESTMODE:
                self.redrawOverlayCounter += 1
                print 'Redrawing the Overlay -- %3d' %self.redrawOverlayCounter        
            # The first time wx.DCOverlay is called or after a self.Overlay.Reset(),
            #  the current screen is mapped to the Overlay.
            dcC = wx.ClientDC(self) 
            odc = wx.DCOverlay(self.overlay, dcC)
            odc.Clear()
            #del odc        
            if not inCell: 
                # Moved out of cell grid
                self.oldCell = inCell # set to <None>                
                return              
                
            # Highlight the cell entered
            dcC.SetPen(wx.Pen("red", 4))
            dcC.SetBrush(wx.TRANSPARENT_BRUSH)
            dcC.DrawRectangleRect(inCell) 
            self.oldCell = inCell
            del odc      
        
class MyApp(wx.App):
    # Define my own subclass for wx.App
    def OnInit(self):       
        # The frame (container for the panel) is extremely simple 
        #  and thus a subclass of wx.Frame is not defined
        frame = wx.Frame(None, title="wx.Overlay Test", size=(600,450))
        # Create my own panel (subclass of frame)
        panel = TestPanel(frame)
        # Display what is in the frame -- when app.MainLoop() executes
        frame.Show(True)
        #self.SetTopWindow(frame)
        return True
#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
# Every wxPython program must have one application object and one or more 
#  frame objects!
if __name__ == '__main__':
    # Initialize 
    app = MyApp(False) # the False is important -- it sends stdout to the
                       # console, rather than a wx.Window
    app.MainLoop() 