⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 floatcanvas.py

📁 Wxpython Implemented on Windows CE, Source code
💻 PY
📖 第 1 页 / 共 5 页
字号:
from __future__ import division

try:
    from Numeric import array,asarray,Float,cos, sin, pi,sum,minimum,maximum,Int32,zeros, ones, concatenate, sqrt, argmin, power, absolute, matrixmultiply, transpose, sometrue, arange, hypot
except ImportError:
    try:
        from numarray import array, asarray, Float, cos, sin, pi, sum, minimum, maximum, Int32, zeros, concatenate, matrixmultiply, transpose, sometrue, arange, hypot
    except ImportError:
        raise ImportError("I could not import either Numeric or numarray")

from time import clock, sleep

import Resources # A file with icons, etc for FloatCanvas

import wx

import types
import os        

## A global variable to hold the Pixels per inch that wxWindows thinks is in use
## This is used for scaling fonts.
## This can't be computed on module __init__, because a wx.App might not have initialized yet.
global ScreenPPI

## a custom Exceptions:

class FloatCanvasError(Exception):
    pass

## Create all the mouse events
# I don't see a need for these two, but maybe some day!
#EVT_FC_ENTER_WINDOW = wx.NewEventType()
#EVT_FC_LEAVE_WINDOW = wx.NewEventType()
EVT_FC_LEFT_DOWN = wx.NewEventType() 
EVT_FC_LEFT_UP  = wx.NewEventType()
EVT_FC_LEFT_DCLICK = wx.NewEventType() 
EVT_FC_MIDDLE_DOWN = wx.NewEventType() 
EVT_FC_MIDDLE_UP = wx.NewEventType() 
EVT_FC_MIDDLE_DCLICK = wx.NewEventType() 
EVT_FC_RIGHT_DOWN = wx.NewEventType() 
EVT_FC_RIGHT_UP = wx.NewEventType() 
EVT_FC_RIGHT_DCLICK = wx.NewEventType() 
EVT_FC_MOTION = wx.NewEventType() 
EVT_FC_MOUSEWHEEL = wx.NewEventType() 
## these two are for the hit-test stuff, I never make them real Events
EVT_FC_ENTER_OBJECT = wx.NewEventType()
EVT_FC_LEAVE_OBJECT = wx.NewEventType()

##Create all mouse event binding functions
#def EVT_ENTER_WINDOW( window, function ):
#    window.Connect( -1, -1, EVT_FC_ENTER_WINDOW, function ) 
#def EVT_LEAVE_WINDOW( window, function ):
#    window.Connect( -1, -1,EVT_FC_LEAVE_WINDOW , function ) 
def EVT_LEFT_DOWN( window, function ):  
    window.Connect( -1, -1,EVT_FC_LEFT_DOWN , function )
def EVT_LEFT_UP( window, function ):
    window.Connect( -1, -1,EVT_FC_LEFT_UP , function )
def EVT_LEFT_DCLICK  ( window, function ):
    window.Connect( -1, -1,EVT_FC_LEFT_DCLICK , function )
def EVT_MIDDLE_DOWN  ( window, function ):
    window.Connect( -1, -1,EVT_FC_MIDDLE_DOWN , function )
def EVT_MIDDLE_UP  ( window, function ):
    window.Connect( -1, -1,EVT_FC_MIDDLE_UP , function )
def EVT_MIDDLE_DCLICK  ( window, function ):
    window.Connect( -1, -1,EVT_FC_MIDDLE_DCLICK , function )
def EVT_RIGHT_DOWN  ( window, function ):
    window.Connect( -1, -1,EVT_FC_RIGHT_DOWN , function )
def EVT_RIGHT_UP( window, function ):
    window.Connect( -1, -1,EVT_FC_RIGHT_UP , function )
def EVT_RIGHT_DCLICK( window, function ):
    window.Connect( -1, -1,EVT_FC_RIGHT_DCLICK , function )
def EVT_MOTION( window, function ):
    window.Connect( -1, -1,EVT_FC_MOTION , function )
def EVT_MOUSEWHEEL( window, function ):
    window.Connect( -1, -1,EVT_FC_MOUSEWHEEL , function )

class _MouseEvent(wx.PyCommandEvent):

    """

    This event class takes a regular wxWindows mouse event as a parameter,
    and wraps it so that there is access to all the original methods. This
    is similar to subclassing, but you can't subclass a wxWindows event

    The goal is to be able to it just like a regular mouse event.

    It adds the method:

    GetCoords() , which returns and (x,y) tuple in world coordinates.

    Another difference is that it is a CommandEvent, which propagates up
    the window hierarchy until it is handled.

    """

    def __init__(self, EventType, NativeEvent, WinID, Coords = None):
        wx.PyCommandEvent.__init__(self)

        self.SetEventType( EventType )
        self._NativeEvent = NativeEvent
        self.Coords = Coords
    
# I don't think this is used.
#    def SetCoords(self,Coords):
#        self.Coords = Coords
        
    def GetCoords(self):
        return self.Coords

    def __getattr__(self, name):
        #return eval(self.NativeEvent.__getattr__(name) )
        return getattr(self._NativeEvent, name)

def _cycleidxs(indexcount, maxvalue, step):

    """
    Utility function used by _colorGenerator

    """
    if indexcount == 0:
        yield ()
    else:
        for idx in xrange(0, maxvalue, step):
            for tail in _cycleidxs(indexcount - 1, maxvalue, step):
                yield (idx, ) + tail

def _colorGenerator():

    """

    Generates a seris of unique colors used to do hit-tests with the HIt
    Test bitmap

    """
    import sys
    if sys.platform == 'darwin':
        depth = 24
    else:
        b = wx.EmptyBitmap(1,1)
        depth = b.GetDepth()
    if depth == 16:
        step = 8
    elif depth >= 24:
        step = 1
    else:
        raise "ColorGenerator does not work with depth = %s" % depth
    return _cycleidxs(indexcount=3, maxvalue=256, step=step)


#### I don't know if the Set objects are useful, beyond the pointset
#### object. The problem is that when zoomed in, the BB is checked to see
#### whether to draw the object.  A Set object can defeat this. One day
#### I plan to write some custon C++ code to draw sets of objects

##class ObjectSetMixin:
##    """
##    A mix-in class for draw objects that are sets of objects

##    It contains methods for setting lists of pens and brushes

##    """
##    def SetPens(self,LineColors,LineStyles,LineWidths):
##        """
##        This method used when an object could have a list of pens, rather than just one
##        It is used for LineSet, and perhaps others in the future.

##        fixme: this should be in a mixin

##        fixme: this is really kludgy, there has got to be a better way!

##        """

##        length = 1
##        if type(LineColors) == types.ListType:
##            length = len(LineColors)
##        else:
##            LineColors = [LineColors]

##        if type(LineStyles) == types.ListType:
##            length = len(LineStyles)
##        else:
##            LineStyles = [LineStyles]

##        if type(LineWidths) == types.ListType:
##            length = len(LineWidths)
##        else:
##            LineWidths = [LineWidths]

##        if length > 1:
##            if len(LineColors) == 1:
##                LineColors = LineColors*length
##            if len(LineStyles) == 1:
##                LineStyles = LineStyles*length
##            if len(LineWidths) == 1:
##                LineWidths = LineWidths*length

##        self.Pens = []
##        for (LineColor,LineStyle,LineWidth) in zip(LineColors,LineStyles,LineWidths):
##            if LineColor is None or LineStyle is None:
##                self.Pens.append(wx.TRANSPARENT_PEN)
##                # what's this for?> self.LineStyle = 'Transparent'
##            if not self.PenList.has_key((LineColor,LineStyle,LineWidth)):
##                Pen = wx.Pen(LineColor,LineWidth,self.LineStyleList[LineStyle])
##                self.Pens.append(Pen)
##            else:
##                self.Pens.append(self.PenList[(LineColor,LineStyle,LineWidth)])
##        if length == 1:
##            self.Pens = self.Pens[0]

class DrawObject:
    """
    This is the base class for all the objects that can be drawn.

    One must subclass from this (and an assortment of Mixins) to create
    a new DrawObject.

    """

    def __init__(self, InForeground  = False, IsVisible = True):
        self.InForeground = InForeground

        self._Canvas = None

        self.HitColor = None
        self.CallBackFuncs = {}

        ## these are the defaults
        self.HitAble = False
        self.HitLine = True
        self.HitFill = True
        self.MinHitLineWidth = 3
        self.HitLineWidth = 3 ## this gets re-set by the subclasses if necessary

        self.Brush = None
        self.Pen = None

        self.FillStyle = "Solid"
        
        self.Visible = IsVisible

    # I pre-define all these as class variables to provide an easier
    # interface, and perhaps speed things up by caching all the Pens
    # and Brushes, although that may not help, as I think wx now
    # does that on it's own. Send me a note if you know!

    BrushList = {
            ( None,"Transparent")  : wx.TRANSPARENT_BRUSH,
            ("Blue","Solid")       : wx.BLUE_BRUSH,
            ("Green","Solid")      : wx.GREEN_BRUSH,
            ("White","Solid")      : wx.WHITE_BRUSH,
            ("Black","Solid")      : wx.BLACK_BRUSH,
            ("Grey","Solid")       : wx.GREY_BRUSH,
            ("MediumGrey","Solid") : wx.MEDIUM_GREY_BRUSH,
            ("LightGrey","Solid")  : wx.LIGHT_GREY_BRUSH,
            ("Cyan","Solid")       : wx.CYAN_BRUSH,
            ("Red","Solid")        : wx.RED_BRUSH
                    }
    PenList = {
            (None,"Transparent",1)   : wx.TRANSPARENT_PEN,
            ("Green","Solid",1)      : wx.GREEN_PEN,
            ("White","Solid",1)      : wx.WHITE_PEN,
            ("Black","Solid",1)      : wx.BLACK_PEN,
            ("Grey","Solid",1)       : wx.GREY_PEN,
            ("MediumGrey","Solid",1) : wx.MEDIUM_GREY_PEN,
            ("LightGrey","Solid",1)  : wx.LIGHT_GREY_PEN,
            ("Cyan","Solid",1)       : wx.CYAN_PEN,
            ("Red","Solid",1)        : wx.RED_PEN
            }

    FillStyleList = {
            "Transparent"    : wx.TRANSPARENT,
            "Solid"          : wx.SOLID,
            "BiDiagonalHatch": wx.BDIAGONAL_HATCH,
            "CrossDiagHatch" : wx.CROSSDIAG_HATCH,
            "FDiagonal_Hatch": wx.FDIAGONAL_HATCH,
            "CrossHatch"     : wx.CROSS_HATCH,
            "HorizontalHatch": wx.HORIZONTAL_HATCH,
            "VerticalHatch"  : wx.VERTICAL_HATCH
            }

    LineStyleList = {
            "Solid"      : wx.SOLID,
            "Transparent": wx.TRANSPARENT,
            "Dot"        : wx.DOT,
            "LongDash"   : wx.LONG_DASH,
            "ShortDash"  : wx.SHORT_DASH,
            "DotDash"    : wx.DOT_DASH,
            }

    def Bind(self, Event, CallBackFun):
        self.CallBackFuncs[Event] = CallBackFun
        self.HitAble = True
        self._Canvas.UseHitTest = True
        if not self._Canvas._HTdc:
            self._Canvas.MakeNewHTdc()
        if not self.HitColor:
            if not self._Canvas.HitColorGenerator:
                self._Canvas.HitColorGenerator = _colorGenerator()
                self._Canvas.HitColorGenerator.next() # first call to prevent the background color from being used.
            self.HitColor = self._Canvas.HitColorGenerator.next()
            self.SetHitPen(self.HitColor,self.HitLineWidth)
            self.SetHitBrush(self.HitColor)
        # put the object in the hit dict, indexed by it's color
        if not self._Canvas.HitDict:
            self._Canvas.MakeHitDict()
        self._Canvas.HitDict[Event][self.HitColor] = (self) # put the object in the hit dict, indexed by it's color

    def UnBindAll(self):
        ## fixme: this only removes one from each list, there could be more.
        if self._Canvas.HitDict:
            for List in self._Canvas.HitDict.itervalues():
                try:
                   List.remove(self)
                except ValueError:
                    pass
        self.HitAble = False


    def SetBrush(self,FillColor,FillStyle):
        if FillColor is None or FillStyle is None:
            self.Brush = wx.TRANSPARENT_BRUSH
            ##fixme: should I really re-set the style?
            self.FillStyle = "Transparent"
        else:
            self.Brush = self.BrushList.setdefault( (FillColor,FillStyle),  wx.Brush(FillColor,self.FillStyleList[FillStyle] ) )

    def SetPen(self,LineColor,LineStyle,LineWidth):
        if (LineColor is None) or (LineStyle is None):
            self.Pen = wx.TRANSPARENT_PEN
            self.LineStyle = 'Transparent'
        else:
             self.Pen = self.PenList.setdefault( (LineColor,LineStyle,LineWidth),  wx.Pen(LineColor,LineWidth,self.LineStyleList[LineStyle]) )

    def SetHitBrush(self,HitColor):
        if not self.HitFill:
            self.HitBrush = wx.TRANSPARENT_BRUSH
        else:
            self.HitBrush = self.BrushList.setdefault( (HitColor,"solid"),  wx.Brush(HitColor,self.FillStyleList["Solid"] ) )

    def SetHitPen(self,HitColor,LineWidth):
        if not self.HitLine:
            self.HitPen = wx.TRANSPARENT_PEN
        else:
            self.HitPen = self.PenList.setdefault( (HitColor, "solid", self.HitLineWidth),  wx.Pen(HitColor, self.HitLineWidth, self.LineStyleList["Solid"]) )

    def PutInBackground(self):
        if self._Canvas and self.InForeground:
            self._Canvas._ForeDrawList.remove(self)
            self._Canvas._DrawList.append(self)
            self._Canvas._BackgroundDirty = True
            self.InForeground = False

    def PutInForeground(self):

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -