mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2025-08-17 08:00:20 +02:00
Add the FloatCanvas demo modules
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxPython/Phoenix/trunk@73860 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
304
samples/floatcanvas/Animation.py
Executable file
304
samples/floatcanvas/Animation.py
Executable file
@@ -0,0 +1,304 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A test of some simple animation
|
||||
|
||||
this is very old-style code: don't imitate it!
|
||||
|
||||
"""
|
||||
|
||||
from time import clock
|
||||
import wx
|
||||
from numpy import *
|
||||
|
||||
## import local version:
|
||||
import sys
|
||||
|
||||
#ver = 'local'
|
||||
ver = 'installed'
|
||||
|
||||
if ver == 'installed': ## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas
|
||||
from wx.lib.floatcanvas import FloatCanvas
|
||||
print "using installed version:", wx.lib.floatcanvas.__version__
|
||||
elif ver == 'local':
|
||||
## import a local version
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from floatcanvas import NavCanvas
|
||||
from floatcanvas import FloatCanvas
|
||||
|
||||
ID_DRAW_BUTTON = 100
|
||||
ID_QUIT_BUTTON = 101
|
||||
ID_CLEAR_BUTTON = 103
|
||||
ID_ZOOM_IN_BUTTON = 104
|
||||
ID_ZOOM_OUT_BUTTON = 105
|
||||
ID_ZOOM_TO_FIT_BUTTON = 110
|
||||
ID_MOVE_MODE_BUTTON = 111
|
||||
ID_TEST_BUTTON = 112
|
||||
|
||||
ID_ABOUT_MENU = 200
|
||||
ID_EXIT_MENU = 201
|
||||
ID_ZOOM_IN_MENU = 202
|
||||
ID_ZOOM_OUT_MENU = 203
|
||||
ID_ZOOM_TO_FIT_MENU = 204
|
||||
ID_DRAWTEST_MENU = 205
|
||||
ID_DRAWMAP_MENU = 206
|
||||
ID_CLEAR_MENU = 207
|
||||
|
||||
|
||||
ID_TEST = 500
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
def __init__(self,parent, id,title,position,size):
|
||||
wx.Frame.__init__(self,parent, id,title,position, size)
|
||||
|
||||
## Set up the MenuBar
|
||||
|
||||
MenuBar = wx.MenuBar()
|
||||
|
||||
file_menu = wx.Menu()
|
||||
file_menu.Append(ID_EXIT_MENU, "E&xit","Terminate the program")
|
||||
wx.EVT_MENU(self, ID_EXIT_MENU, self.OnQuit)
|
||||
MenuBar.Append(file_menu, "&File")
|
||||
|
||||
draw_menu = wx.Menu()
|
||||
draw_menu.Append(ID_DRAWTEST_MENU, "&Draw Test","Run a test of drawing random components")
|
||||
wx.EVT_MENU(self, ID_DRAWTEST_MENU,self.DrawTest)
|
||||
draw_menu.Append(ID_DRAWMAP_MENU, "Draw &Movie","Run a test of drawing a map")
|
||||
wx.EVT_MENU(self, ID_DRAWMAP_MENU,self.RunMovie)
|
||||
draw_menu.Append(ID_CLEAR_MENU, "&Clear","Clear the Canvas")
|
||||
wx.EVT_MENU(self, ID_CLEAR_MENU,self.Clear)
|
||||
MenuBar.Append(draw_menu, "&Draw")
|
||||
|
||||
|
||||
view_menu = wx.Menu()
|
||||
view_menu.Append(ID_ZOOM_TO_FIT_MENU, "Zoom to &Fit","Zoom to fit the window")
|
||||
wx.EVT_MENU(self, ID_ZOOM_TO_FIT_MENU,self.ZoomToFit)
|
||||
MenuBar.Append(view_menu, "&View")
|
||||
|
||||
help_menu = wx.Menu()
|
||||
help_menu.Append(ID_ABOUT_MENU, "&About",
|
||||
"More information About this program")
|
||||
wx.EVT_MENU(self, ID_ABOUT_MENU, self.OnAbout)
|
||||
MenuBar.Append(help_menu, "&Help")
|
||||
|
||||
self.SetMenuBar(MenuBar)
|
||||
|
||||
self.CreateStatusBar()
|
||||
self.SetStatusText("")
|
||||
|
||||
wx.EVT_CLOSE(self, self.OnCloseWindow)
|
||||
|
||||
# Other event handlers:
|
||||
wx.EVT_RIGHT_DOWN(self, self.RightButtonEvent)
|
||||
|
||||
# Add the Canvas
|
||||
self.Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
Debug = False,
|
||||
BackgroundColor = "WHITE").Canvas
|
||||
self.Canvas.NumBetweenBlits = 1000
|
||||
self.Show(True)
|
||||
|
||||
self.DrawTest(None)
|
||||
return None
|
||||
|
||||
def RightButtonEvent(self,event):
|
||||
print "Right Button has been clicked in DrawFrame"
|
||||
print "coords are: %i, %i"%(event.GetX(),event.GetY())
|
||||
event.Skip()
|
||||
|
||||
def OnAbout(self, event):
|
||||
dlg = wx.MessageDialog(self, "This is a small program to demonstrate\n"
|
||||
"the use of the FloatCanvas\n",
|
||||
"About Me", wx.OK | wx.ICON_INFORMATION)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def ZoomToFit(self,event):
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
def Clear(self,event = None):
|
||||
self.Canvas.ClearAll()
|
||||
self.Canvas.Draw()
|
||||
|
||||
def OnQuit(self,event):
|
||||
self.Close(True)
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
def DrawTest(self,event = None):
|
||||
import random
|
||||
import numpy.random as RandomArray
|
||||
|
||||
Range = (-10,10)
|
||||
|
||||
colors = ["AQUAMARINE", "BLACK", "BLUE", "BLUE VIOLET", "BROWN",
|
||||
"CADET BLUE", "CORAL", "CORNFLOWER BLUE", "CYAN", "DARK GREY",
|
||||
"DARK GREEN", "DARK OLIVE GREEN", "DARK ORCHID", "DARK SLATE BLUE",
|
||||
"DARK SLATE GREY", "DARK TURQUOISE", "DIM GREY",
|
||||
"FIREBRICK", "FOREST GREEN", "GOLD", "GOLDENROD", "GREY",
|
||||
"GREEN", "GREEN YELLOW", "INDIAN RED", "KHAKI", "LIGHT BLUE",
|
||||
"LIGHT GREY", "LIGHT STEEL BLUE", "LIME GREEN", "MAGENTA",
|
||||
"MAROON", "MEDIUM AQUAMARINE", "MEDIUM BLUE", "MEDIUM FOREST GREEN",
|
||||
"MEDIUM GOLDENROD", "MEDIUM ORCHID", "MEDIUM SEA GREEN",
|
||||
"MEDIUM SLATE BLUE", "MEDIUM SPRING GREEN", "MEDIUM TURQUOISE",
|
||||
"MEDIUM VIOLET RED", "MIDNIGHT BLUE", "NAVY", "ORANGE", "ORANGE RED",
|
||||
"ORCHID", "PALE GREEN", "PINK", "PLUM", "PURPLE", "RED",
|
||||
"SALMON", "SEA GREEN", "SIENNA", "SKY BLUE", "SLATE BLUE",
|
||||
"SPRING GREEN", "STEEL BLUE", "TAN", "THISTLE", "TURQUOISE",
|
||||
"VIOLET", "VIOLET RED", "WHEAT", "WHITE", "YELLOW", "YELLOW GREEN"]
|
||||
Canvas = self.Canvas
|
||||
|
||||
# Some Polygons in the background:
|
||||
# for i in range(500):
|
||||
# points = RandomArray.uniform(-100,100,(10,2))
|
||||
for i in range(500):
|
||||
# for i in range(1):
|
||||
points = RandomArray.uniform(-100,100,(10,2))
|
||||
lw = random.randint(1,6)
|
||||
cf = random.randint(0,len(colors)-1)
|
||||
cl = random.randint(0,len(colors)-1)
|
||||
self.Canvas.AddPolygon(points,
|
||||
LineWidth = lw,
|
||||
LineColor = colors[cl],
|
||||
FillColor = colors[cf],
|
||||
FillStyle = 'Solid',
|
||||
InForeground = False)
|
||||
|
||||
## Pointset
|
||||
print "Adding Points to Foreground"
|
||||
for i in range(1):
|
||||
points = RandomArray.uniform(-100,100,(1000,2))
|
||||
D = 2
|
||||
self.LEs = self.Canvas.AddPointSet(points, Color = "Black", Diameter = D, InForeground = True)
|
||||
|
||||
self.Canvas.AddRectangle((-200,-200), (400,400))
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def RunMovie(self,event = None):
|
||||
import numpy.random as RandomArray
|
||||
start = clock()
|
||||
#shift = RandomArray.randint(0,0,(2,))
|
||||
for i in range(100):
|
||||
points = self.LEs.Points
|
||||
shift = RandomArray.randint(-5,6,(2,))
|
||||
points += shift
|
||||
self.LEs.SetPoints(points)
|
||||
self.Canvas.Draw()
|
||||
wx.GetApp().Yield(True)
|
||||
print "running the movie took %f seconds"%(clock() - start)
|
||||
|
||||
class DemoApp(wx.App):
|
||||
"""
|
||||
How the demo works:
|
||||
|
||||
Under the Draw menu, there are three options:
|
||||
|
||||
*Draw Test: will put up a picture of a bunch of randomly generated
|
||||
objects, of each kind supported.
|
||||
|
||||
*Draw Map: will draw a map of the world. Be patient, it is a big map,
|
||||
with a lot of data, and will take a while to load and draw (about 10 sec
|
||||
on my 450Mhz PIII). Redraws take about 2 sec. This demonstrates how the
|
||||
performance is not very good for large drawings.
|
||||
|
||||
*Clear: Clears the Canvas.
|
||||
|
||||
Once you have a picture drawn, you can zoom in and out and move about
|
||||
the picture. There is a tool bar with three tools that can be
|
||||
selected.
|
||||
|
||||
The magnifying glass with the plus is the zoom in tool. Once selected,
|
||||
if you click the image, it will zoom in, centered on where you
|
||||
clicked. If you click and drag the mouse, you will get a rubber band
|
||||
box, and the image will zoom to fit that box when you release it.
|
||||
|
||||
The magnifying glass with the minus is the zoom out tool. Once selected,
|
||||
if you click the image, it will zoom out, centered on where you
|
||||
clicked. (note that this takes a while when you are looking at the map,
|
||||
as it has a LOT of lines to be drawn. The image is double buffered, so
|
||||
you don't see the drawing in progress)
|
||||
|
||||
The hand is the move tool. Once selected, if you click and drag on the
|
||||
image, it will move so that the part you clicked on ends up where you
|
||||
release the mouse. Nothing is changed while you are dragging. The
|
||||
drawing is too slow for that.
|
||||
|
||||
I'd like the cursor to change as you change tools, but the stock
|
||||
wx.Cursors didn't include anything I liked, so I stuck with the
|
||||
pointer. Pleae let me know if you have any nice cursor images for me to
|
||||
use.
|
||||
|
||||
|
||||
Any bugs, comments, feedback, questions, and especially code are welcome:
|
||||
|
||||
-Chris Barker
|
||||
|
||||
ChrisHBarker@home.net
|
||||
http://members.home.net/barkerlohmann
|
||||
|
||||
"""
|
||||
|
||||
def OnInit(self):
|
||||
wx.InitAllImageHandlers()
|
||||
frame = DrawFrame(None, -1, "Simple Drawing Window",wx.DefaultPosition, (700,700) )
|
||||
|
||||
self.SetTopWindow(frame)
|
||||
|
||||
return True
|
||||
|
||||
def Read_MapGen(filename,stats = False):
|
||||
"""
|
||||
This function reads a MapGen Format file, and
|
||||
returns a list of NumPy arrays with the line segments in them.
|
||||
|
||||
Each NumPy array in the list is an NX2 array of Python Floats.
|
||||
|
||||
The demo should have come with a file, "world.dat" that is the
|
||||
shorelines of the whole worls, in MapGen format.
|
||||
|
||||
"""
|
||||
import string
|
||||
from numpy import array
|
||||
file = open(filename,'rt')
|
||||
data = file.readlines()
|
||||
data = map(string.strip,data)
|
||||
|
||||
Shorelines = []
|
||||
segment = []
|
||||
for line in data:
|
||||
if line == "# -b": #New segment begining
|
||||
if segment: Shorelines.append(array(segment))
|
||||
segment = []
|
||||
else:
|
||||
segment.append(map(float,string.split(line)))
|
||||
if segment: Shorelines.append(array(segment))
|
||||
|
||||
if stats:
|
||||
NumSegments = len(Shorelines)
|
||||
NumPoints = False
|
||||
for segment in Shorelines:
|
||||
NumPoints = NumPoints + len(segment)
|
||||
AvgPoints = NumPoints / NumSegments
|
||||
print "Number of Segments: ", NumSegments
|
||||
print "Average Number of Points per segment: ",AvgPoints
|
||||
|
||||
return Shorelines
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
app = DemoApp(0)
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
133
samples/floatcanvas/BB_HitTest.py
Executable file
133
samples/floatcanvas/BB_HitTest.py
Executable file
@@ -0,0 +1,133 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
Test of an alternaive hit test methoid that used the bounding boxes of teh objects instead.
|
||||
|
||||
Poorly tested!
|
||||
|
||||
Edited from code contributed by Benjamin Jessup on the mailing list
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
FC = FloatCanvas
|
||||
|
||||
def BB_HitTest(self, event, HitEvent):
|
||||
""" Hit Test Function for BoundingBox Based HitMap System"""
|
||||
if self.HitDict and self.HitDict[HitEvent]:
|
||||
# loop though the objects associated with this event
|
||||
objects = [] #Create object list for holding multiple objects
|
||||
object_index_list = [] #Create list for holding the indexes
|
||||
xy_p = event.GetPosition()
|
||||
xy = self.PixelToWorld( xy_p ) #Convert to the correct coords
|
||||
for key2 in self.HitDict[HitEvent].keys():
|
||||
#Get Mouse Event Position
|
||||
bb = self.HitDict[HitEvent][key2].BoundingBox
|
||||
if bb.PointInside(xy):
|
||||
Object = self.HitDict[HitEvent][key2]
|
||||
objects.append(Object)
|
||||
try:
|
||||
#First try the foreground index and add the length of the background index
|
||||
#to account for the two 'layers' that already exist in the code
|
||||
index = self._ForeDrawList.index(Object) + len(self._DrawList)
|
||||
except ValueError:
|
||||
index = self._DrawList.index(Object) #Now check background if not found in foreground
|
||||
object_index_list.append(index) #append the index found
|
||||
else:
|
||||
Object = self.HitDict[HitEvent][key2]
|
||||
if len(objects) > 0: #If no objects then do nothing
|
||||
#Get the highest index object
|
||||
highest_object = objects[object_index_list.index(max(object_index_list))]
|
||||
highest_object.HitCoords = xy
|
||||
highest_object.HitCoordsPixel = xy_p
|
||||
highest_object.CallBackFuncs[HitEvent](highest_object)
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
return False
|
||||
|
||||
FC.FloatCanvas.HitTest = BB_HitTest
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
Point = (45,40)
|
||||
Text = Canvas.AddScaledText("A String",
|
||||
Point,
|
||||
20,
|
||||
Color = "Black",
|
||||
BackgroundColor = None,
|
||||
Family = wx.ROMAN,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'bl',
|
||||
InForeground = False)
|
||||
Text.MinFontSize = 4 # the default is 1
|
||||
Text.DisappearWhenSmall = False #the default is True
|
||||
|
||||
Rect1 = Canvas.AddRectangle((50, 20), (40,15), FillColor="Red", LineStyle = None)
|
||||
Rect1.Bind(FC.EVT_FC_LEFT_DOWN, self.OnLeft)
|
||||
Rect1.Name = "red"
|
||||
|
||||
Rect2 = Canvas.AddRectangle((70, 30), (40,15), FillColor="Blue", LineStyle = None)
|
||||
Rect2.Bind(FC.EVT_FC_LEFT_DOWN, self.OnLeft)
|
||||
Rect2.Name = 'blue'
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnLeft(self, object):
|
||||
print "Rect %s got hit"%object.Name
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
353
samples/floatcanvas/BNAEditor.py
Executable file
353
samples/floatcanvas/BNAEditor.py
Executable file
@@ -0,0 +1,353 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
BNA-Editor: a simple app for editing polygons in BNA files
|
||||
|
||||
BNA is a simple text format for storing polygons in lat-long coordinates.
|
||||
|
||||
"""
|
||||
import os, sys
|
||||
import sets
|
||||
|
||||
import numpy as N
|
||||
|
||||
#### import local version:
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
import wx
|
||||
import sys
|
||||
|
||||
if len(sys.argv) > 1:
|
||||
StartFileName = sys.argv[1]
|
||||
else:
|
||||
StartFileName = None
|
||||
|
||||
### These utilities are required to load and save BNA data.
|
||||
class BNAData:
|
||||
"""
|
||||
Class to store the full set of data in a BNA file
|
||||
|
||||
"""
|
||||
def __init__(self, Filename = None):
|
||||
self.Filename = Filename
|
||||
self.PointsData = None
|
||||
self.Filename = None
|
||||
self.Names = None
|
||||
self.Types = None
|
||||
if Filename is not None:
|
||||
self.Load(Filename)
|
||||
|
||||
def __getitem__(self,index):
|
||||
return (self.PointsData[index], self.Names[index])
|
||||
|
||||
def __len__(self):
|
||||
return len(self.PointsData)
|
||||
|
||||
def Save(self, filename = None):
|
||||
if not filename:
|
||||
filename = self.filename
|
||||
file = open(filename, 'w')
|
||||
for i, points in enumerate(self.PointsData):
|
||||
file.write('"%s","%s", %i\n'%(self.Names[i],self.Types[i],len(points) ) )
|
||||
for p in points:
|
||||
file.write("%.12f,%.12f\n"%(tuple(p)))
|
||||
|
||||
def Load(self, filename):
|
||||
#print "Loading:", filename
|
||||
file = open(filename,'rU')
|
||||
|
||||
self.Filename = filename
|
||||
self.PointsData = []
|
||||
self.Names = []
|
||||
self.Types = []
|
||||
while 1:
|
||||
line = file.readline()
|
||||
if not line:
|
||||
break
|
||||
line = line.strip()
|
||||
Name, line = line.split('","')
|
||||
Name = Name[1:]
|
||||
Type,line = line.split('",')
|
||||
num_points = int(line)
|
||||
self.Types.append(Type)
|
||||
self.Names.append(Name)
|
||||
polygon = N.zeros((num_points,2),N.float)
|
||||
for i in range(num_points):
|
||||
polygon[i,:] = map(float, file.readline().split(','))
|
||||
self.PointsData.append(polygon)
|
||||
|
||||
file.close()
|
||||
return None
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
"""
|
||||
A frame used for the BNA Editor
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,parent, id,title,position,size):
|
||||
wx.Frame.__init__(self,parent, id,title,position, size)
|
||||
|
||||
## Set up the MenuBar
|
||||
MenuBar = wx.MenuBar()
|
||||
|
||||
FileMenu = wx.Menu()
|
||||
|
||||
OpenMenu = FileMenu.Append(wx.ID_ANY, "&Open","Open BNA")
|
||||
self.Bind(wx.EVT_MENU, self.OpenBNA, OpenMenu)
|
||||
|
||||
SaveMenu = FileMenu.Append(wx.ID_ANY, "&Save","Save BNA")
|
||||
self.Bind(wx.EVT_MENU, self.SaveBNA, SaveMenu)
|
||||
|
||||
CloseMenu = FileMenu.Append(wx.ID_ANY, "&Close","Close Application")
|
||||
self.Bind(wx.EVT_MENU, self.OnQuit, CloseMenu)
|
||||
|
||||
MenuBar.Append(FileMenu, "&File")
|
||||
|
||||
view_menu = wx.Menu()
|
||||
ZoomMenu = view_menu.Append(wx.ID_ANY, "Zoom to &Fit","Zoom to fit the window")
|
||||
self.Bind(wx.EVT_MENU, self.ZoomToFit, ZoomMenu)
|
||||
MenuBar.Append(view_menu, "&View")
|
||||
|
||||
help_menu = wx.Menu()
|
||||
AboutMenu = help_menu.Append(wx.ID_ANY, "&About",
|
||||
"More information About this program")
|
||||
self.Bind(wx.EVT_MENU, self.OnAbout, AboutMenu)
|
||||
MenuBar.Append(help_menu, "&Help")
|
||||
|
||||
self.SetMenuBar(MenuBar)
|
||||
|
||||
self.CreateStatusBar()
|
||||
# Add the Canvas
|
||||
self.Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE"
|
||||
).Canvas
|
||||
|
||||
wx.EVT_CLOSE(self, self.OnCloseWindow)
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
FloatCanvas.EVT_LEFT_UP(self.Canvas, self.OnLeftUp )
|
||||
FloatCanvas.EVT_LEFT_DOWN(self.Canvas, self.OnLeftDown)
|
||||
|
||||
try:
|
||||
self.FileDialog = wx.FileDialog(self, "Pick a BNA file",".","","*", wx.OPEN)
|
||||
except wx._core.PyAssertionError:
|
||||
self.FileDialog = None
|
||||
|
||||
self.ResetSelections()
|
||||
return None
|
||||
|
||||
def ResetSelections(self):
|
||||
self.SelectedPoly = None
|
||||
self.SelectedPolyOrig = None
|
||||
self.SelectedPoints = None
|
||||
self.PointSelected = False
|
||||
self.SelectedPointNeighbors = None
|
||||
|
||||
def OnLeftDown(self,event):
|
||||
if self.SelectedPoly:
|
||||
self.DeSelectPoly()
|
||||
self.Canvas.Draw()
|
||||
|
||||
def OnAbout(self, event):
|
||||
dlg = wx.MessageDialog(self, "This is a small program to demonstrate\n"
|
||||
"the use of the FloatCanvas\n",
|
||||
"About Me", wx.OK | wx.ICON_INFORMATION)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def ZoomToFit(self,event):
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
def OpenBNA(self, event):
|
||||
if self.FileDialog is None:
|
||||
self.FileDialog = wx.FileDialog(self, "Pick a BNA file",style= wx.OPEN)
|
||||
dlg = self.FileDialog
|
||||
dlg.SetMessage("Pick a BNA file")
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
filename = dlg.GetPath()
|
||||
self.LoadBNA(filename)
|
||||
|
||||
def SaveBNA(self, event):
|
||||
for i in self.ChangedPolys:
|
||||
self.BNAFile.PointsData[i] = self.AllPolys[i].Points
|
||||
dlg = wx.FileDialog(self,
|
||||
message="Pick a BNA file",
|
||||
style=wx.SAVE)
|
||||
if dlg.ShowModal() == wx.ID_OK:
|
||||
filename = dlg.GetPath()
|
||||
self.BNAFile.Save(filename)
|
||||
|
||||
def Clear(self,event = None):
|
||||
self.Canvas.ClearAll()
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
def OnQuit(self,event):
|
||||
self.Close(True)
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
And moves a point if there is one
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.4f, %.4f"%tuple(event.Coords))
|
||||
|
||||
if self.PointSelected:
|
||||
PolyPoints = self.SelectedPoly.Points
|
||||
Index = self.SelectedPoints.Index
|
||||
dc = wx.ClientDC(self.Canvas)
|
||||
PixelCoords = event.GetPosition()
|
||||
dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
|
||||
dc.SetLogicalFunction(wx.XOR)
|
||||
if self.SelectedPointNeighbors is None:
|
||||
self.SelectedPointNeighbors = N.zeros((3,2), N.float)
|
||||
#fixme: This feels very inelegant!
|
||||
if Index == 0:
|
||||
self.SelectedPointNeighbors[0] = self.SelectedPoly.Points[-1]
|
||||
self.SelectedPointNeighbors[1:3] = self.SelectedPoly.Points[:2]
|
||||
elif Index == len(self.SelectedPoly.Points)-1:
|
||||
self.SelectedPointNeighbors[0:2] = self.SelectedPoly.Points[-2:]
|
||||
self.SelectedPointNeighbors[2] = self.SelectedPoly.Points[0]
|
||||
else:
|
||||
self.SelectedPointNeighbors = self.SelectedPoly.Points[Index-1:Index+2]
|
||||
self.SelectedPointNeighbors = self.Canvas.WorldToPixel(self.SelectedPointNeighbors)
|
||||
else:
|
||||
dc.DrawLines(self.SelectedPointNeighbors)
|
||||
self.SelectedPointNeighbors[1] = PixelCoords
|
||||
dc.DrawLines(self.SelectedPointNeighbors)
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
if self.PointSelected:
|
||||
self.SelectedPoly.Points[self.SelectedPoints.Index] = event.GetCoords()
|
||||
self.SelectedPoly.SetPoints(self.SelectedPoly.Points, copy = False)
|
||||
self.SelectedPoints.SetPoints(self.SelectedPoly.Points, copy = False)
|
||||
self.PointSelected = False
|
||||
self.SelectedPointNeighbors = None
|
||||
self.SelectedPoly.HasChanged = True
|
||||
self.Canvas.Draw()
|
||||
|
||||
def DeSelectPoly(self):
|
||||
Canvas = self.Canvas
|
||||
if self.SelectedPoly.HasChanged:
|
||||
self.ChangedPolys.add(self.SelectedPolyOrig.BNAIndex)
|
||||
self.SelectedPolyOrig.SetPoints(self.SelectedPoly.Points, copy = False)
|
||||
self.Canvas.Draw(Force = True)
|
||||
Canvas.RemoveObject(self.SelectedPoly)
|
||||
Canvas.RemoveObject(self.SelectedPoints)
|
||||
self.ResetSelections()
|
||||
|
||||
def SelectPoly(self, Object):
|
||||
Canvas = self.Canvas
|
||||
if Object is self.SelectedPolyOrig:
|
||||
pass
|
||||
else:
|
||||
if self.SelectedPoly is not None:
|
||||
self.DeSelectPoly()
|
||||
self.SelectedPolyOrig = Object
|
||||
self.SelectedPoly = Canvas.AddPolygon(Object.Points,
|
||||
LineWidth = 1,
|
||||
LineColor = "Red",
|
||||
FillColor = None,
|
||||
InForeground = True)
|
||||
self.SelectedPoly.HasChanged = False
|
||||
# Draw points on the Vertices of the Selected Poly:
|
||||
self.SelectedPoints = Canvas.AddPointSet(Object.Points,
|
||||
Diameter = 4,
|
||||
Color = "Red",
|
||||
InForeground = True)
|
||||
self.SelectedPoints.HitLineWidth = 8 # make it a bit easier to hit
|
||||
self.SelectedPoints.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.SelectPointHit)
|
||||
Canvas.Draw()
|
||||
|
||||
def SelectPointHit(self, PointSet):
|
||||
PointSet.Index = PointSet.FindClosestPoint(PointSet.HitCoords)
|
||||
self.PointSelected = True
|
||||
|
||||
def LoadBNA(self, filename):
|
||||
self.ResetSelections()
|
||||
self.Canvas.ClearAll()
|
||||
self.Canvas.SetProjectionFun('FlatEarth')
|
||||
try:
|
||||
AllPolys = []
|
||||
self.BNAFile = BNAData(filename)
|
||||
print "loaded BNAFile:", self.BNAFile.Filename
|
||||
for i, shoreline in enumerate(self.BNAFile.PointsData):
|
||||
Poly = self.Canvas.AddPolygon(shoreline,
|
||||
LineWidth = 1,
|
||||
LineColor = "Black",
|
||||
FillColor = "Brown",
|
||||
FillStyle = 'Solid')
|
||||
Poly.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.SelectPoly)
|
||||
Poly.BNAIndex = i
|
||||
AllPolys.append(Poly)
|
||||
self.Canvas.ZoomToBB()
|
||||
self.ChangedPolys = sets.Set()
|
||||
self.AllPolys = AllPolys
|
||||
except:
|
||||
#raise
|
||||
dlg = wx.MessageDialog(None,
|
||||
'There was something wrong with the selected bna file',
|
||||
'File Loading Error',
|
||||
wx.OK | wx.ICON_ERROR)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
|
||||
class BNAEditor(wx.App):
|
||||
"""
|
||||
Once you have a picture drawn, you can zoom in and out and move about
|
||||
the picture. There is a tool bar with three tools that can be
|
||||
selected.
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.App.__init__(self, *args, **kwargs)
|
||||
|
||||
def OnInit(self):
|
||||
frame = DrawFrame(None, -1, "BNA Editor",wx.DefaultPosition,(700,700))
|
||||
|
||||
self.SetTopWindow(frame)
|
||||
frame.Show()
|
||||
|
||||
if StartFileName:
|
||||
frame.LoadBNA(StartFileName)
|
||||
else:
|
||||
##frame.LoadBNA("Tests/Small.bna")
|
||||
frame.LoadBNA("Tiny.bna")
|
||||
return True
|
||||
|
||||
|
||||
app = BNAEditor(False)# put in True if you want output to go to it's own window.
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
149
samples/floatcanvas/BarPlot.py
Executable file
149
samples/floatcanvas/BarPlot.py
Executable file
@@ -0,0 +1,149 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import wx
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
import numpy as N
|
||||
from numpy import random as random
|
||||
|
||||
NumChannels = 200
|
||||
MaxValue = 2000
|
||||
#MaxValue = 2**24
|
||||
|
||||
|
||||
def YScaleFun(center):
|
||||
"""
|
||||
Function that returns a scaling vector to scale y data to same range as x data
|
||||
|
||||
This is used by FloatCanvas as a "projection function", so that you can have
|
||||
a different scale for X and Y. With the default projection, X and Y are the same scale.
|
||||
|
||||
"""
|
||||
|
||||
# center gets ignored in this case
|
||||
return N.array((1, float(NumChannels)/MaxValue), N.float)
|
||||
|
||||
def ScaleWorldToPixel(self, Lengths):
|
||||
"""
|
||||
This is a new version of a function that will get passed to the
|
||||
drawing functions of the objects, to Change a length from world to
|
||||
pixel coordinates.
|
||||
|
||||
This version uses the "ceil" function, so that fractional pixel get
|
||||
rounded up, rather than down.
|
||||
|
||||
Lengths should be a NX2 array of (x,y) coordinates, or
|
||||
a 2-tuple, or sequence of 2-tuples.
|
||||
"""
|
||||
return N.ceil(( (N.asarray(Lengths, N.float)*self.TransformVector) )).astype('i')
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
FloatCanvas.FloatCanvas.ScaleWorldToPixel = ScaleWorldToPixel
|
||||
NC = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
ProjectionFun = YScaleFun,
|
||||
)
|
||||
|
||||
self.Canvas = Canvas = NC.Canvas
|
||||
#self.Canvas.ScaleWorldToPixel = ScaleWorldToPixel
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
self.Values = random.randint(0, MaxValue, (NumChannels,))
|
||||
|
||||
self.Bars = []
|
||||
self.BarWidth = 0.75
|
||||
# add an X axis
|
||||
Canvas.AddLine(((0,0), (NumChannels, 0 )),)
|
||||
for x in N.linspace(1, NumChannels, 11):
|
||||
Canvas.AddText("%i"%x, (x-1+self.BarWidth/2,0), Position="tc")
|
||||
|
||||
for i, Value in enumerate(self.Values):
|
||||
bar = Canvas.AddRectangle(XY=(i, 0),
|
||||
WH=(self.BarWidth, Value),
|
||||
LineColor = None,
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 1,
|
||||
FillColor = "Red",
|
||||
FillStyle = "Solid",
|
||||
)
|
||||
self.Bars.append(bar)
|
||||
|
||||
# Add a couple a button the Toolbar
|
||||
|
||||
tb = NC.ToolBar
|
||||
tb.AddSeparator()
|
||||
|
||||
ResetButton = wx.Button(tb, label="Reset")
|
||||
tb.AddControl(ResetButton)
|
||||
ResetButton.Bind(wx.EVT_BUTTON, self.ResetData)
|
||||
|
||||
# PlayButton = wx.Button(tb, wx.ID_ANY, "Run")
|
||||
# tb.AddControl(PlayButton)
|
||||
# PlayButton.Bind(wx.EVT_BUTTON, self.RunTest)
|
||||
tb.Realize()
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
Canvas.Draw(True)
|
||||
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
channel, value = event.Coords
|
||||
if 0 < channel < NumChannels :
|
||||
channel = "%i,"%(channel+1)
|
||||
else:
|
||||
channel = ""
|
||||
|
||||
if value >=0:
|
||||
value = "%3g"%value
|
||||
else:
|
||||
value = ""
|
||||
self.SetStatusText("Channel: %s Value: %s"%(channel, value))
|
||||
|
||||
def ResetData(self, event):
|
||||
self.Values = random.randint(0, MaxValue, (NumChannels,))
|
||||
for i, bar in enumerate(self.Bars):
|
||||
bar.SetShape(bar.XY, (self.BarWidth, self.Values[i]))
|
||||
self.Canvas.Draw(Force=True)
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
212
samples/floatcanvas/BouncingBall.py
Executable file
212
samples/floatcanvas/BouncingBall.py
Executable file
@@ -0,0 +1,212 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A test of some simple animation
|
||||
|
||||
this is very old-style code: don't imitate it!
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
import numpy as np
|
||||
|
||||
## import local version:
|
||||
import sys
|
||||
|
||||
#ver = 'local'
|
||||
ver = 'installed'
|
||||
|
||||
if ver == 'installed': ## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas
|
||||
from wx.lib.floatcanvas import FloatCanvas
|
||||
print "using installed version:", wx.lib.floatcanvas.__version__
|
||||
elif ver == 'local':
|
||||
## import a local version
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from floatcanvas import NavCanvas
|
||||
from floatcanvas import FloatCanvas
|
||||
|
||||
FC = FloatCanvas
|
||||
|
||||
class MovingObjectMixin: # Borrowed from MovingElements.py
|
||||
"""
|
||||
Methods required for a Moving object
|
||||
|
||||
"""
|
||||
|
||||
def GetOutlinePoints(self):
|
||||
BB = self.BoundingBox
|
||||
OutlinePoints = np.array( ( (BB[0,0], BB[0,1]),
|
||||
(BB[0,0], BB[1,1]),
|
||||
(BB[1,0], BB[1,1]),
|
||||
(BB[1,0], BB[0,1]),
|
||||
)
|
||||
)
|
||||
|
||||
return OutlinePoints
|
||||
|
||||
|
||||
class Ball(MovingObjectMixin, FloatCanvas.Circle):
|
||||
def __init__(self, XY, Velocity, Radius=2.0, **kwargs):
|
||||
self.Velocity = np.asarray(Velocity, np.float).reshape((2,))
|
||||
self.Radius = Radius
|
||||
self.Moving = False
|
||||
FloatCanvas.Circle.__init__(self, XY, Diameter=Radius*2, FillColor="red", **kwargs)
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
## Set up the MenuBar
|
||||
|
||||
MenuBar = wx.MenuBar()
|
||||
|
||||
file_menu = wx.Menu()
|
||||
item = file_menu.Append(wx.ID_ANY, "E&xit","Terminate the program")
|
||||
self.Bind(wx.EVT_MENU, self.OnQuit, item)
|
||||
MenuBar.Append(file_menu, "&File")
|
||||
|
||||
|
||||
self.SetMenuBar(MenuBar)
|
||||
|
||||
self.CreateStatusBar()
|
||||
self.SetStatusText("")
|
||||
|
||||
wx.EVT_CLOSE(self, self.OnCloseWindow)
|
||||
|
||||
# Add the buttons
|
||||
ResetButton = wx.Button(self, label="Reset")
|
||||
ResetButton.Bind(wx.EVT_BUTTON, self.OnReset)
|
||||
|
||||
StartButton = wx.Button(self, label="Start")
|
||||
StartButton.Bind(wx.EVT_BUTTON, self.OnStart)
|
||||
|
||||
StopButton = wx.Button(self, label="Stop")
|
||||
StopButton.Bind(wx.EVT_BUTTON, self.OnStop)
|
||||
|
||||
butSizer = wx.BoxSizer(wx.HORIZONTAL)
|
||||
butSizer.Add(StartButton, 0, wx.RIGHT, 5 )
|
||||
butSizer.Add(ResetButton, 0, wx.RIGHT, 5)
|
||||
butSizer.Add(StopButton, 0, )
|
||||
# Add the Canvas
|
||||
NC = NavCanvas.NavCanvas(self, -1, (500,500),
|
||||
Debug = False,
|
||||
BackgroundColor = "BLUE")
|
||||
|
||||
self.Canvas = NC.Canvas
|
||||
self.Initialize(None)
|
||||
|
||||
# lay it out:
|
||||
S = wx.BoxSizer(wx.VERTICAL)
|
||||
S.Add(butSizer, 0, wx.ALIGN_CENTER | wx.ALL, 5)
|
||||
S.Add(NC, 1, wx.EXPAND)
|
||||
self.SetSizer(S)
|
||||
|
||||
self.timer = wx.Timer(self)
|
||||
self.Bind(wx.EVT_TIMER, self.MoveBall, self.timer)
|
||||
|
||||
self.Show(True)
|
||||
|
||||
def OnQuit(self,event):
|
||||
self.Close(True)
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
def Initialize(self, event=None):
|
||||
Canvas = self.Canvas
|
||||
|
||||
#Add the floor
|
||||
Canvas.AddLine(( (0, 0), (100, 0) ), LineWidth=4, LineColor="Black")
|
||||
# add the wall:
|
||||
Canvas.AddRectangle( (0,0), (10,50), FillColor='green')
|
||||
|
||||
# add the ball:
|
||||
self.Ball = Ball( (5, 52), (2, 0), InForeground=True )
|
||||
Canvas.AddObject( self.Ball )
|
||||
# to capture the mouse to move the ball
|
||||
self.Ball.Bind(FC.EVT_FC_LEFT_DOWN, self.BallHit)
|
||||
Canvas.Bind(FC.EVT_MOTION, self.OnMove )
|
||||
Canvas.Bind(FC.EVT_LEFT_UP, self.OnLeftUp )
|
||||
|
||||
wx.CallAfter(Canvas.ZoomToBB)
|
||||
|
||||
def BallHit(self, object):
|
||||
print "the ball was clicked"
|
||||
self.Ball.Moving = True
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
and moves the object it is clicked on
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.4f, %.4f"%tuple(event.Coords))
|
||||
if self.Ball.Moving:
|
||||
self.Ball.SetPoint(event.Coords)
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
self.Ball.Moving = False
|
||||
|
||||
def OnReset(self, event=None):
|
||||
self.Ball.SetPoint( (5, 52) )
|
||||
self.Ball.Velocity = np.array((1.5, 0.0))
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
def OnStart(self, event=None):
|
||||
self.timer.Start(20)
|
||||
|
||||
def OnStop(self, event=None):
|
||||
self.timer.Stop()
|
||||
|
||||
def MoveBall(self, event=None):
|
||||
ball = self.Ball
|
||||
|
||||
dt = .1
|
||||
g = 9.806
|
||||
m = 1
|
||||
A = np.pi*(ball.Radius/100)**2 # radius in cm
|
||||
Cd = 0.47
|
||||
rho = 1.3
|
||||
|
||||
if not ball.Moving: # don't do this if the user is moving it
|
||||
vel = ball.Velocity
|
||||
pos = ball.XY
|
||||
|
||||
# apply drag
|
||||
vel -= np.sign(vel) * ((0.5 * Cd * rho * A * vel**2) / m * dt)
|
||||
# apply gravity
|
||||
vel[1] -= g * dt
|
||||
# move the ball
|
||||
pos += dt * vel
|
||||
# check if it's on the wall
|
||||
if pos[1] <= 52. and pos[0] <= 10.:
|
||||
#reverse velocity
|
||||
vel[1] *= -1.0
|
||||
pos[1] = 52.
|
||||
# check if it's hit the floor
|
||||
elif pos[1] <= ball.Radius:
|
||||
#reverse velocity
|
||||
vel[1] *= -1.0
|
||||
pos[1] = ball.Radius
|
||||
|
||||
self.Ball.SetPoint( pos )
|
||||
self.Canvas.Draw(True)
|
||||
wx.GetApp().Yield(onlyIfNeeded=True)
|
||||
|
||||
class DemoApp(wx.App):
|
||||
def OnInit(self):
|
||||
frame = DrawFrame(None, -1, "Simple Drawing Window",wx.DefaultPosition, (700,700) )
|
||||
|
||||
self.SetTopWindow(frame)
|
||||
|
||||
return True
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
app = DemoApp(0)
|
||||
app.MainLoop()
|
||||
|
||||
|
126
samples/floatcanvas/Chart.py
Executable file
126
samples/floatcanvas/Chart.py
Executable file
@@ -0,0 +1,126 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "White",
|
||||
).Canvas
|
||||
# Canvas = FloatCanvas.FloatCanvas(self,-1,
|
||||
# size = (500,500),
|
||||
# ProjectionFun = None,
|
||||
# Debug = 0,
|
||||
# BackgroundColor = "White",
|
||||
# )
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
FloatCanvas.EVT_LEFT_DOWN(self.Canvas, self.OnLeft)
|
||||
|
||||
|
||||
# Some default sizes:
|
||||
self.LineHeight = 1
|
||||
self.TextWidth = 8
|
||||
self.SpaceWidth = 1
|
||||
self.Labels = ["SW Tasks", "Set RX Rf"] + ["A Row Label"]*16
|
||||
self.NumRows = len(self.Labels)
|
||||
|
||||
self.BuildChartBackground()
|
||||
self.AddLabels()
|
||||
self.Show()
|
||||
Canvas.MinScale=28
|
||||
Canvas.MaxScale=28
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def BuildChartBackground(self):
|
||||
Canvas = self.Canvas
|
||||
top = 0
|
||||
bottom = -(self.LineHeight * self.NumRows)
|
||||
width = self.SpaceWidth * 16 + self.TextWidth
|
||||
# put in the rows:
|
||||
for i in range(1, self.NumRows+1, 2):
|
||||
Canvas.AddRectangle((0-self.TextWidth, -i*self.LineHeight),
|
||||
(width, self.LineHeight),
|
||||
LineColor = None,
|
||||
FillColor = "LightGrey",
|
||||
FillStyle = "Solid",)
|
||||
|
||||
# put a dashed line in every 1 unit:
|
||||
for i in range(16):
|
||||
Canvas.AddLine(((i*self.SpaceWidth,bottom),(i*self.SpaceWidth,top)),
|
||||
LineColor = "Black",
|
||||
LineStyle = "Dot",
|
||||
# or "Dot", "ShortDash", "LongDash","ShortDash", "DotDash"
|
||||
LineWidth = 1,)
|
||||
def AddLabels(self):
|
||||
Canvas = self.Canvas
|
||||
|
||||
for i, label in enumerate(self.Labels):
|
||||
Canvas.AddScaledText(label,
|
||||
( -self.TextWidth, -(i+0.2)*self.LineHeight ),
|
||||
Size = 0.6 * self.LineHeight,
|
||||
Color = "Black",
|
||||
BackgroundColor = None,
|
||||
Family = wx.MODERN,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'tl',
|
||||
)
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
def OnLeft(self, event):
|
||||
"""
|
||||
Prints various info about the state of the canvas to stdout
|
||||
|
||||
"""
|
||||
print "Scale is:", self.Canvas.Scale
|
||||
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
119
samples/floatcanvas/ClickableBoxes.py
Executable file
119
samples/floatcanvas/ClickableBoxes.py
Executable file
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
This is a little demo of how to make clickable (and changeable) objects with
|
||||
FloatCanvas
|
||||
|
||||
Also an example of constant size, rather than the usual zooming and panning
|
||||
|
||||
Developed as an answer to a question on the wxPYhton mailing lilst:
|
||||
"get panel id while dragging across several panels'
|
||||
April 5, 2012
|
||||
|
||||
"""
|
||||
|
||||
import random
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import FloatCanvas as FC
|
||||
|
||||
|
||||
colors = [ (255, 0 , 0 ),
|
||||
(0 , 255, 0 ),
|
||||
(0 , 0, 255),
|
||||
(255, 255, 0 ),
|
||||
(255, 0, 255),
|
||||
(0 , 255, 255),
|
||||
]
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
# Add the Canvas
|
||||
Canvas = FC.FloatCanvas(self,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "Black",
|
||||
)
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
self.Canvas.Bind(wx.EVT_SIZE, self.OnSize)
|
||||
|
||||
# build the squares:
|
||||
w = 10
|
||||
dx = 14
|
||||
for i in range(9):
|
||||
for j in range(9):
|
||||
Rect = Canvas.AddRectangle((i*dx, j*dx), (w, w), FillColor="White", LineStyle = None)
|
||||
Outline = Canvas.AddRectangle((i*dx, j*dx), (w, w),
|
||||
FillColor=None,
|
||||
LineWidth=4,
|
||||
LineColor='Red',
|
||||
LineStyle=None)
|
||||
Rect.indexes = (i,j)
|
||||
Rect.outline = Outline
|
||||
Rect.Bind(FC.EVT_FC_LEFT_DOWN, self.SquareHitLeft)
|
||||
Rect.Bind(FC.EVT_FC_ENTER_OBJECT, self.SquareEnter)
|
||||
Rect.Bind(FC.EVT_FC_LEAVE_OBJECT, self.SquareLeave)
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def SquareHitLeft(self, square):
|
||||
print "square hit:", square.indexes
|
||||
# set a random color
|
||||
c = random.sample(colors, 1)[0]
|
||||
square.SetFillColor( c )
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
def SquareEnter(self, square):
|
||||
print "entering square:", square.indexes
|
||||
square.outline.SetLineStyle("Solid")
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
def SquareLeave(self, square):
|
||||
print "leaving square:", square.indexes
|
||||
square.outline.SetLineStyle(None)
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
|
||||
def OnSize(self, event):
|
||||
"""
|
||||
re-zooms the canvas to fit the window
|
||||
|
||||
"""
|
||||
print "in OnSize"
|
||||
self.Canvas.ZoomToBB()
|
||||
event.Skip()
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
72
samples/floatcanvas/DrawBot.py
Executable file
72
samples/floatcanvas/DrawBot.py
Executable file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
DrawBot.py
|
||||
|
||||
This a a demo of how one can use the FloatCanvas to do a drawing similar to one of the "DrawBot" demos:
|
||||
|
||||
|
||||
http://just.letterror.com/ltrwiki/DrawBot
|
||||
|
||||
I think it's easier with FloatCavnas, and you get zoomign and scrolling to boot!
|
||||
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
from math import *
|
||||
|
||||
try: # see if there is a local FloatCanvas to use
|
||||
import sys
|
||||
sys.path.append("../")
|
||||
from floatcanvas import NavCanvas, FloatCanvas
|
||||
print "Using local FloatCanvas"
|
||||
except ImportError: # Use the wxPython lib one
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
print "Using installed FloatCanvas"
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,parent, id,title,position,size):
|
||||
wx.Frame.__init__(self,parent, id,title,position, size)
|
||||
|
||||
# Add the Canvas
|
||||
self.Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "White",
|
||||
).Canvas
|
||||
|
||||
|
||||
self.Show(True)
|
||||
self.MakePic()
|
||||
|
||||
return None
|
||||
|
||||
def MakePic(self):
|
||||
Canvas = self.Canvas
|
||||
phi = (sqrt(5) + 1)/2 - 1
|
||||
oradius = 10.0
|
||||
for i in xrange(720):
|
||||
radius = 1.5 * oradius * sin(i * pi/720)
|
||||
Color = (255*(i / 720.), 255*( i / 720.), 255 * 0.25)
|
||||
x = oradius + 0.25*i*cos(phi*i*2*pi)
|
||||
y = oradius + 0.25*i*sin(phi*i*2*pi)
|
||||
Canvas.AddCircle((x,y),
|
||||
radius,
|
||||
LineColor = "Black",
|
||||
LineWidth = 2,
|
||||
FillColor = Color,
|
||||
)
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
app = wx.PySimpleApp()
|
||||
DrawFrame(None, -1, "FloatCanvas Demo App", wx.DefaultPosition, (700,700) )
|
||||
app.MainLoop()
|
||||
|
117
samples/floatcanvas/DrawRect.py
Executable file
117
samples/floatcanvas/DrawRect.py
Executable file
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A simple demo that shows how to use FloatCanvas to draw rectangles on the screen
|
||||
|
||||
Note: this is now broken -- the events are not getting to the Rubber Band Box object.
|
||||
It should be re-factored to use GUIMode
|
||||
"""
|
||||
|
||||
|
||||
import wx
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas, Resources, Utilities, GUIMode
|
||||
#from floatcanvas.Utilities import GUI
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
from wx.lib.floatcanvas.Utilities import GUI
|
||||
|
||||
import numpy as N
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,parent, id,title,position,size):
|
||||
wx.Frame.__init__(self,parent, id,title,position, size)
|
||||
|
||||
self.CreateStatusBar()
|
||||
# Add the Canvas
|
||||
NC = NavCanvas.NavCanvas(self,
|
||||
size= (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
)
|
||||
|
||||
self.Canvas = NC.Canvas
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
# Add some buttons to the Toolbar
|
||||
tb = NC.ToolBar
|
||||
tb.AddSeparator()
|
||||
|
||||
ClearButton = wx.Button(tb, wx.ID_ANY, "Clear")
|
||||
tb.AddControl(ClearButton)
|
||||
ClearButton.Bind(wx.EVT_BUTTON, self.Clear)
|
||||
|
||||
DrawButton = wx.Button(tb, wx.ID_ANY, "StopDrawing")
|
||||
tb.AddControl(DrawButton)
|
||||
DrawButton.Bind(wx.EVT_BUTTON, self.SetDraw)
|
||||
self.DrawButton = DrawButton
|
||||
|
||||
tb.Realize()
|
||||
|
||||
# Initialize a few values
|
||||
self.Rects = []
|
||||
|
||||
self.RBBoxMode = GUI.RubberBandBox(self.NewRect)
|
||||
self.Canvas.SetMode(self.RBBoxMode)
|
||||
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
self.Show(True)
|
||||
return None
|
||||
|
||||
def Clear(self, event=None):
|
||||
self.Rects = []
|
||||
self.Canvas.ClearAll()
|
||||
self.Canvas.Draw()
|
||||
|
||||
def SetDraw(self, event=None):
|
||||
label = self.DrawButton.GetLabel()
|
||||
if label == "Draw":
|
||||
self.DrawButton.SetLabel("StopDrawing")
|
||||
self.Canvas.SetMode(self.RBBoxMode)
|
||||
elif label == "StopDrawing":
|
||||
self.DrawButton.SetLabel("Draw")
|
||||
self.Canvas.SetMode(GUIMode.GUIMouse())
|
||||
else: # huh?
|
||||
pass
|
||||
|
||||
def NewRect(self, rect):
|
||||
self.Rects.append(self.Canvas.AddRectangle(*rect, LineWidth=4))
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.4f, %.4f"%tuple(event.Coords))
|
||||
event.Skip()
|
||||
|
||||
app = wx.PySimpleApp()
|
||||
DrawFrame(None, -1, "FloatCanvas Rectangle Drawer", wx.DefaultPosition, (700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
84
samples/floatcanvas/GridDemo.py
Executable file
84
samples/floatcanvas/GridDemo.py
Executable file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A simple demo to show how to do grids
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
|
||||
try:
|
||||
# See if there is a local copy
|
||||
import sys
|
||||
sys.path.append("../")
|
||||
from floatcanvas import NavCanvas, FloatCanvas
|
||||
except ImportError:
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
|
||||
Point = (45,40)
|
||||
Box = Canvas.AddCircle(Point,
|
||||
Diameter = 10,
|
||||
FillColor = "Black",
|
||||
LineColor = "Red",
|
||||
LineWidth = 6)
|
||||
|
||||
# Crosses:
|
||||
Grid = FloatCanvas.DotGrid( Spacing=(1, .5), Size=2, Color="Cyan", Cross=True, CrossThickness=2)
|
||||
#Dots:
|
||||
#Grid = FloatCanvas.DotGrid( (0.5, 1), Size=3, Color="Red")
|
||||
|
||||
Canvas.GridUnder = Grid
|
||||
#Canvas.GridOver = Grid
|
||||
|
||||
FloatCanvas.EVT_MOTION(Canvas, self.OnMove )
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
|
||||
|
||||
app = wx.App(False) # true to get its own output window.
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
121
samples/floatcanvas/GroupDeleteDemo.py
Normal file
121
samples/floatcanvas/GroupDeleteDemo.py
Normal file
@@ -0,0 +1,121 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A small demo of how to use Groups of Objects
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
NC = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
)
|
||||
Canvas = NC.Canvas
|
||||
self.Canvas = Canvas
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
Point = (45,40)
|
||||
|
||||
## create a few Objects:
|
||||
C = FloatCanvas.Circle((0, 0), 10, FillColor="Red")
|
||||
R = FloatCanvas.Rectangle((5, 5),(15, 8), FillColor="Blue")
|
||||
E = FloatCanvas.Ellipse((1.5, 1.5), (12, 8), FillColor="Purple")
|
||||
C2 = FloatCanvas.Circle((0, 5), 10, FillColor="cyan")
|
||||
T = FloatCanvas.Text("Group A", (5.5, 5.5), Position="cc", Size = 16, Weight=wx.BOLD, Family=wx.SWISS)
|
||||
|
||||
self.GroupA = FloatCanvas.Group((R,C,E))
|
||||
self.GroupA.AddObjects((C2,T))
|
||||
Canvas.AddObject(self.GroupA)
|
||||
|
||||
|
||||
## create another Groups of objects
|
||||
|
||||
R = FloatCanvas.Rectangle((15, 15),(10, 18), FillColor="orange")
|
||||
E = FloatCanvas.Ellipse((22, 28), (12, 8), FillColor="yellow")
|
||||
C = FloatCanvas.Circle((25, 20), 15, FillColor="Green")
|
||||
C2 = FloatCanvas.Circle((12, 22), 10, FillColor="cyan")
|
||||
T = FloatCanvas.Text("Group B", (19, 24), Position="cc", Size = 16, Weight=wx.BOLD, Family=wx.SWISS)
|
||||
|
||||
self.GroupB = FloatCanvas.Group((R,E,C,C2,T))
|
||||
Canvas.AddObject(self.GroupB)
|
||||
|
||||
self.Groups = {"A":self.GroupA, "B":self.GroupB}
|
||||
|
||||
# Add a couple of tools to the Canvas Toolbar
|
||||
|
||||
tb = NC.ToolBar
|
||||
# tb.AddSeparator()
|
||||
|
||||
for Group in self.Groups.keys():
|
||||
Button = wx.Button(tb, wx.ID_ANY, "Remove %s"%Group)
|
||||
tb.AddControl(Button)
|
||||
Button.Bind(wx.EVT_BUTTON, lambda evt, group=Group: self.RemoveGroup(evt, group))
|
||||
Button = wx.Button(tb, wx.ID_ANY, "Replace%s"%Group)
|
||||
tb.AddControl(Button)
|
||||
Button.Bind(wx.EVT_BUTTON, lambda evt, group=Group: self.ReplaceGroup(evt, group))
|
||||
tb.Realize()
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates of the mouse position
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
def RemoveGroup(self, evt, group=""):
|
||||
print "removing group:", group
|
||||
G = self.Groups[group]
|
||||
self.Canvas.RemoveObject(G)
|
||||
self.Canvas.Draw(Force=True)
|
||||
|
||||
def ReplaceGroup(self, evt, group=""):
|
||||
print "replacing group:", group
|
||||
G = self.Groups[group]
|
||||
self.Canvas.AddObject(G)
|
||||
self.Canvas.Draw(Force=True)
|
||||
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
111
samples/floatcanvas/GroupDemo.py
Normal file
111
samples/floatcanvas/GroupDemo.py
Normal file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A small demo of how to use Groups of Objects
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
NC = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
)
|
||||
Canvas = NC.Canvas
|
||||
self.Canvas = Canvas
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
Point = (45,40)
|
||||
|
||||
## create a few Objects:
|
||||
C = FloatCanvas.Circle((0, 0), 10, FillColor="Red")
|
||||
R = FloatCanvas.Rectangle((5, 5),(15, 8), FillColor="Blue")
|
||||
E = FloatCanvas.Ellipse((1.5, 1.5), (12, 8), FillColor="Purple")
|
||||
C2 = FloatCanvas.Circle((0, 5), 10, FillColor="cyan")
|
||||
T = FloatCanvas.Text("Group A", (5.5, 5.5), Position="cc", Size = 16, Weight=wx.BOLD, Family=wx.SWISS)
|
||||
|
||||
self.GroupA = FloatCanvas.Group((R,C,E))
|
||||
self.GroupA.AddObjects((C2,T))
|
||||
Canvas.AddObject(self.GroupA)
|
||||
|
||||
|
||||
## create another Groups of objects
|
||||
|
||||
R = FloatCanvas.Rectangle((15, 15),(10, 18), FillColor="orange")
|
||||
E = FloatCanvas.Ellipse((22, 28), (12, 8), FillColor="yellow")
|
||||
C = FloatCanvas.Circle((25, 20), 15, FillColor="Green")
|
||||
C2 = FloatCanvas.Circle((12, 22), 10, FillColor="cyan")
|
||||
T = FloatCanvas.Text("Group B", (19, 24), Position="cc", Size = 16, Weight=wx.BOLD, Family=wx.SWISS)
|
||||
|
||||
self.GroupB = FloatCanvas.Group((R,E,C,C2,T))
|
||||
Canvas.AddObject(self.GroupB)
|
||||
|
||||
self.Groups = {"A":self.GroupA, "B":self.GroupB}
|
||||
|
||||
# Add a couple of tools to the Canvas Toolbar
|
||||
|
||||
tb = NC.ToolBar
|
||||
# tb.AddSeparator()
|
||||
|
||||
for Group in self.Groups.keys():
|
||||
Button = wx.Button(tb, wx.ID_ANY, "Hide/Show%s"%Group)
|
||||
tb.AddControl(Button)
|
||||
print Group
|
||||
Button.Bind(wx.EVT_BUTTON, lambda evt, group=Group: self.HideGroup(evt, group))
|
||||
tb.Realize()
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates of the mouse position
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
def HideGroup(self, evt, group=""):
|
||||
G = self.Groups[group]
|
||||
G.Visible = not G.Visible
|
||||
self.Canvas.Draw(Force=True)
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
102
samples/floatcanvas/Hexagons.py
Executable file
102
samples/floatcanvas/Hexagons.py
Executable file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A simple demo to display a lot of hexagons
|
||||
|
||||
This was an example someone had on the wxPython-users list
|
||||
|
||||
"""
|
||||
import wx
|
||||
import wx.lib.colourdb
|
||||
|
||||
## import local version:
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
NumHexagons = 1000
|
||||
|
||||
import numpy as N
|
||||
from numpy.random import uniform
|
||||
|
||||
import random
|
||||
import time
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
# Add the Canvas
|
||||
self.Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 1,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
self.MakeHexagons()
|
||||
|
||||
self.Show(True)
|
||||
print "Drawing the Hexagons"
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
return None
|
||||
|
||||
def MakeHexagons(self):
|
||||
print "Building %i Hexagons"%NumHexagons
|
||||
# get a list of colors for random colors
|
||||
|
||||
wx.lib.colourdb.updateColourDB()
|
||||
self.colors = wx.lib.colourdb.getColourList()
|
||||
print "Max colors:", len(self.colors)
|
||||
Canvas = self.Canvas
|
||||
D = 1.0
|
||||
h = D *N.sqrt(3)/2
|
||||
Hex = N.array(((D , 0),
|
||||
(D/2 , -h),
|
||||
(-D/2, -h),
|
||||
(-D , 0),
|
||||
(-D/2, h),
|
||||
(D/2 , h),
|
||||
))
|
||||
Centers = uniform(-100, 100, (NumHexagons, 2))
|
||||
for center in Centers:
|
||||
# scale the hexagon
|
||||
Points = Hex * uniform(5,20)
|
||||
#print Points
|
||||
# shift the hexagon
|
||||
Points = Points + center
|
||||
#print Points
|
||||
cf = random.randint(0,len(self.colors)-1)
|
||||
#cf = 55
|
||||
H = Canvas.AddPolygon(Points, LineColor = None, FillColor = self.colors[cf])
|
||||
#print "BrushList is: %i long"%len(H.BrushList)
|
||||
H.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.HexHit)
|
||||
print "BrushList is: %i long"%len(H.BrushList)
|
||||
|
||||
def HexHit(self, Hex):
|
||||
print "A %s Hex was hit, obj ID: %i"%(Hex.FillColor, id(Hex))
|
||||
|
||||
|
||||
|
||||
app = wx.App(False)
|
||||
DrawFrame(None, -1, "FloatCanvas Demo App", wx.DefaultPosition, (700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
77
samples/floatcanvas/Map.py
Executable file
77
samples/floatcanvas/Map.py
Executable file
@@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
|
||||
TestFileName = "../data/TestMap.png"
|
||||
|
||||
|
||||
import wx
|
||||
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
NC = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "White",
|
||||
)
|
||||
self.Canvas = NC.Canvas
|
||||
|
||||
self.LoadMap(TestFileName)
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
self.Show()
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
def LoadMap(self, filename):
|
||||
Image = wx.Image(filename)
|
||||
self.Canvas.AddScaledBitmap(Image, (0,0), Height = Image.GetSize()[1], Position = "tl")
|
||||
|
||||
self.Canvas.AddPoint((0,0), Diameter=3)
|
||||
self.Canvas.AddText("(0,0)", (0,0), Position="cl")
|
||||
p = (Image.GetSize()[0],-Image.GetSize()[1])
|
||||
self.Canvas.AddPoint(p, Diameter=3)
|
||||
self.Canvas.AddText("(%i,%i)"%p, p, Position="cl")
|
||||
|
||||
self.Canvas.MinScale = 0.15
|
||||
self.Canvas.MaxScale = 1.0
|
||||
|
||||
def Binding(self, event):
|
||||
print "Writing a png file:"
|
||||
self.Canvas.SaveAsImage("junk.png")
|
||||
print "Writing a jpeg file:"
|
||||
self.Canvas.SaveAsImage("junk.jpg",wx.BITMAP_TYPE_JPEG)
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
And moves a point if there is one selected
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
83
samples/floatcanvas/MicroDemo.py
Executable file
83
samples/floatcanvas/MicroDemo.py
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
Point = (45,40)
|
||||
Text = Canvas.AddScaledText("A String",
|
||||
Point,
|
||||
20,
|
||||
Color = "Black",
|
||||
BackgroundColor = None,
|
||||
Family = wx.ROMAN,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'bl',
|
||||
InForeground = False)
|
||||
Text.MinFontSize = 4 # the default is 1
|
||||
Text.DisappearWhenSmall = False #the default is True
|
||||
|
||||
Rect = Canvas.AddRectangle((50, 20), (40,10), FillColor="Red", LineStyle = None)
|
||||
Rect.MinSize = 4 # default is 1
|
||||
Rect.DisappearWhenSmall = False # defualt is True
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
381
samples/floatcanvas/MiniDemo.py
Executable file
381
samples/floatcanvas/MiniDemo.py
Executable file
@@ -0,0 +1,381 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import wx
|
||||
|
||||
## import local version:
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
import wx.lib.colourdb
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
## Set up the MenuBar
|
||||
|
||||
MenuBar = wx.MenuBar()
|
||||
|
||||
file_menu = wx.Menu()
|
||||
item = file_menu.Append(wx.ID_ANY, "&Close","Close this frame")
|
||||
self.Bind(wx.EVT_MENU, self.OnQuit, item)
|
||||
MenuBar.Append(file_menu, "&File")
|
||||
|
||||
draw_menu = wx.Menu()
|
||||
|
||||
item = draw_menu.Append(wx.ID_ANY, "&Draw Test","Run a test of drawing random components")
|
||||
self.Bind(wx.EVT_MENU,self.DrawTest, item)
|
||||
|
||||
item = draw_menu.Append(wx.ID_ANY, "&Move Test","Run a test of moving stuff in the background")
|
||||
self.Bind(wx.EVT_MENU, self.MoveTest, item)
|
||||
|
||||
item = draw_menu.Append(wx.ID_ANY, "&Clear","Clear the Canvas")
|
||||
self.Bind(wx.EVT_MENU,self.Clear, item)
|
||||
|
||||
MenuBar.Append(draw_menu, "&Draw")
|
||||
|
||||
view_menu = wx.Menu()
|
||||
item = view_menu.Append(wx.ID_ANY, "Zoom to &Fit","Zoom to fit the window")
|
||||
self.Bind(wx.EVT_MENU,self.ZoomToFit, item)
|
||||
MenuBar.Append(view_menu, "&View")
|
||||
|
||||
help_menu = wx.Menu()
|
||||
item = help_menu.Append(wx.ID_ANY, "&About",
|
||||
"More information About this program")
|
||||
self.Bind(wx.EVT_MENU, self.OnAbout, item)
|
||||
MenuBar.Append(help_menu, "&Help")
|
||||
|
||||
self.SetMenuBar(MenuBar)
|
||||
|
||||
self.CreateStatusBar()
|
||||
self.SetStatusText("")
|
||||
|
||||
wx.EVT_CLOSE(self, self.OnCloseWindow)
|
||||
|
||||
# Add the Canvas
|
||||
self.Canvas = NavCanvas.NavCanvas(self,
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
|
||||
self.Show(True)
|
||||
|
||||
|
||||
# get a list of colors for random colors
|
||||
wx.lib.colourdb.updateColourDB()
|
||||
self.colors = wx.lib.colourdb.getColourList()
|
||||
|
||||
self.LineStyles = FloatCanvas.DrawObject.LineStyleList.keys()
|
||||
|
||||
return None
|
||||
|
||||
def OnAbout(self, event):
|
||||
dlg = wx.MessageDialog(self, "This is a small program to demonstrate\n"
|
||||
"the use of the FloatCanvas\n",
|
||||
"About Me", wx.OK | wx.ICON_INFORMATION)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def ZoomToFit(self,event):
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
def Clear(self,event = None):
|
||||
self.Canvas.ClearAll()
|
||||
self.Canvas.Draw()
|
||||
|
||||
def OnQuit(self,event):
|
||||
self.Close(True)
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
def DrawTest(self,event):
|
||||
wx.GetApp().Yield()
|
||||
import random
|
||||
import numpy.random as RandomArray
|
||||
Range = (-10,10)
|
||||
|
||||
Canvas = self.Canvas
|
||||
Canvas.ClearAll()
|
||||
|
||||
# Set some zoom limits:
|
||||
self.Canvas.MinScale = 15.0
|
||||
self.Canvas.MaxScale = 500.0
|
||||
|
||||
#### Draw a few Random Objects ####
|
||||
|
||||
# Rectangles
|
||||
for i in range(5):
|
||||
xy = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1]))
|
||||
lw = random.randint(1,5)
|
||||
cf = random.randint(0,len(self.colors)-1)
|
||||
h = random.randint(1,5)
|
||||
w = random.randint(1,5)
|
||||
Canvas.AddRectangle(xy, (h,w),
|
||||
LineWidth = lw,
|
||||
FillColor = self.colors[cf])
|
||||
|
||||
# Ellipses
|
||||
for i in range(5):
|
||||
xy = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1]))
|
||||
lw = random.randint(1,5)
|
||||
cf = random.randint(0,len(self.colors)-1)
|
||||
h = random.randint(1,5)
|
||||
w = random.randint(1,5)
|
||||
Canvas.AddEllipse(xy, (h,w),
|
||||
LineWidth = lw,
|
||||
FillColor = self.colors[cf])
|
||||
|
||||
# Circles
|
||||
for i in range(5):
|
||||
point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1]))
|
||||
D = random.randint(1,5)
|
||||
lw = random.randint(1,5)
|
||||
cf = random.randint(0,len(self.colors)-1)
|
||||
cl = random.randint(0,len(self.colors)-1)
|
||||
Canvas.AddCircle(point, D,
|
||||
LineWidth = lw,
|
||||
LineColor = self.colors[cl],
|
||||
FillColor = self.colors[cf])
|
||||
Canvas.AddText("Circle # %i"%(i),
|
||||
point,
|
||||
Size = 12,
|
||||
Position = "cc")
|
||||
|
||||
# Lines
|
||||
for i in range(5):
|
||||
points = []
|
||||
for j in range(random.randint(2,10)):
|
||||
point = (random.randint(Range[0],Range[1]),random.randint(Range[0],Range[1]))
|
||||
points.append(point)
|
||||
lw = random.randint(1,10)
|
||||
cf = random.randint(0,len(self.colors)-1)
|
||||
cl = random.randint(0,len(self.colors)-1)
|
||||
Canvas.AddLine(points, LineWidth = lw, LineColor = self.colors[cl])
|
||||
|
||||
# Polygons
|
||||
for i in range(3):
|
||||
points = []
|
||||
for j in range(random.randint(2,6)):
|
||||
point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1]))
|
||||
points.append(point)
|
||||
lw = random.randint(1,6)
|
||||
cf = random.randint(0,len(self.colors)-1)
|
||||
cl = random.randint(0,len(self.colors)-1)
|
||||
Canvas.AddPolygon(points,
|
||||
LineWidth = lw,
|
||||
LineColor = self.colors[cl],
|
||||
FillColor = self.colors[cf],
|
||||
FillStyle = 'Solid')
|
||||
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
def MoveTest(self,event=None):
|
||||
print "Running: TestHitTestForeground"
|
||||
wx.GetApp().Yield()
|
||||
|
||||
self.UnBindAllMouseEvents()
|
||||
Canvas = self.Canvas
|
||||
|
||||
Canvas.ClearAll()
|
||||
# Clear the zoom limits:
|
||||
self.Canvas.MinScale = None
|
||||
self.Canvas.MaxScale = None
|
||||
|
||||
Canvas.SetProjectionFun(None)
|
||||
|
||||
#Add a Hitable rectangle
|
||||
w,h = 60, 20
|
||||
|
||||
dx = 80
|
||||
dy = 40
|
||||
x,y = 20, 20
|
||||
|
||||
color = "Red"
|
||||
R = Canvas.AddRectangle((x,y), (w,h),
|
||||
LineWidth = 2,
|
||||
FillColor = color
|
||||
)
|
||||
|
||||
R.Name = color + "Rectangle"
|
||||
Canvas.AddText(R.Name, (x, y+h), Position = "tl")
|
||||
|
||||
## A set of Rectangles that move together
|
||||
|
||||
## NOTE: In a real app, it might be better to create a new
|
||||
## custom FloatCanvas DrawObject
|
||||
|
||||
self.MovingRects = []
|
||||
x += dx
|
||||
color = "LightBlue"
|
||||
R = Canvas.AddRectangle((x,y), (w/2, h/2),
|
||||
LineWidth = 2,
|
||||
FillColor = color)
|
||||
|
||||
R.HitFill = True
|
||||
R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectMoveLeft)
|
||||
L = Canvas.AddText("Left", (x + w/4, y + h/4),
|
||||
Position = "cc")
|
||||
self.MovingRects.extend( (R,L) )
|
||||
|
||||
x += w/2
|
||||
R = Canvas.AddRectangle((x, y), (w/2, h/2),
|
||||
LineWidth = 2,
|
||||
FillColor = color)
|
||||
|
||||
R.HitFill = True
|
||||
R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectMoveRight)
|
||||
L = Canvas.AddText("Right", (x + w/4, y + h/4),
|
||||
Position = "cc")
|
||||
self.MovingRects.extend( (R,L) )
|
||||
|
||||
x -= w/2
|
||||
y += h/2
|
||||
R = Canvas.AddRectangle((x, y), (w/2, h/2),
|
||||
LineWidth = 2,
|
||||
FillColor = color)
|
||||
R.HitFill = True
|
||||
R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectMoveUp)
|
||||
L = Canvas.AddText("Up", (x + w/4, y + h/4),
|
||||
Position = "cc")
|
||||
self.MovingRects.extend( (R,L) )
|
||||
|
||||
|
||||
x += w/2
|
||||
R = Canvas.AddRectangle((x, y), (w/2, h/2),
|
||||
LineWidth = 2,
|
||||
FillColor = color)
|
||||
R.HitFill = True
|
||||
R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectMoveDown)
|
||||
L = Canvas.AddText("Down", (x + w/4, y + h/4),
|
||||
Position = "cc")
|
||||
self.MovingRects.extend( (R,L) )
|
||||
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
def RectMoveLeft(self,Object):
|
||||
self.MoveRects("left")
|
||||
|
||||
def RectMoveRight(self,Object):
|
||||
self.MoveRects("right")
|
||||
|
||||
def RectMoveUp(self,Object):
|
||||
self.MoveRects("up")
|
||||
|
||||
def RectMoveDown(self,Object):
|
||||
self.MoveRects("down")
|
||||
|
||||
def MoveRects(self, Dir):
|
||||
for Object in self.MovingRects:
|
||||
X,Y = Object.XY
|
||||
if Dir == "left": X -= 10
|
||||
elif Dir == "right": X += 10
|
||||
elif Dir == "up": Y += 10
|
||||
elif Dir == "down": Y -= 10
|
||||
Object.SetPoint((X,Y))
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
def UnBindAllMouseEvents(self):
|
||||
## Here is how you catch FloatCanvas mouse events
|
||||
FloatCanvas.EVT_LEFT_DOWN(self.Canvas, None )
|
||||
FloatCanvas.EVT_LEFT_UP(self.Canvas, None )
|
||||
FloatCanvas.EVT_LEFT_DCLICK(self.Canvas, None)
|
||||
|
||||
FloatCanvas.EVT_MIDDLE_DOWN(self.Canvas, None )
|
||||
FloatCanvas.EVT_MIDDLE_UP(self.Canvas, None )
|
||||
FloatCanvas.EVT_MIDDLE_DCLICK(self.Canvas, None )
|
||||
|
||||
FloatCanvas.EVT_RIGHT_DOWN(self.Canvas, None )
|
||||
FloatCanvas.EVT_RIGHT_UP(self.Canvas, None )
|
||||
FloatCanvas.EVT_RIGHT_DCLICK(self.Canvas, None )
|
||||
|
||||
FloatCanvas.EVT_MOUSEWHEEL(self.Canvas, None )
|
||||
|
||||
self.EventsAreBound = False
|
||||
|
||||
class DemoApp(wx.App):
|
||||
"""
|
||||
How the demo works:
|
||||
|
||||
Under the Draw menu, there are three options:
|
||||
|
||||
*Draw Test: will put up a picture of a bunch of randomly generated
|
||||
objects, of each kind supported.
|
||||
|
||||
*Draw Map: will draw a map of the world. Be patient, it is a big map,
|
||||
with a lot of data, and will take a while to load and draw (about 10 sec
|
||||
on my 450Mhz PIII). Redraws take about 2 sec. This demonstrates how the
|
||||
performance is not very good for large drawings.
|
||||
|
||||
*Clear: Clears the Canvas.
|
||||
|
||||
Once you have a picture drawn, you can zoom in and out and move about
|
||||
the picture. There is a tool bar with three tools that can be
|
||||
selected.
|
||||
|
||||
The magnifying glass with the plus is the zoom in tool. Once selected,
|
||||
if you click the image, it will zoom in, centered on where you
|
||||
clicked. If you click and drag the mouse, you will get a rubber band
|
||||
box, and the image will zoom to fit that box when you release it.
|
||||
|
||||
The magnifying glass with the minus is the zoom out tool. Once selected,
|
||||
if you click the image, it will zoom out, centered on where you
|
||||
clicked. (note that this takes a while when you are looking at the map,
|
||||
as it has a LOT of lines to be drawn. The image is double buffered, so
|
||||
you don't see the drawing in progress)
|
||||
|
||||
The hand is the move tool. Once selected, if you click and drag on the
|
||||
image, it will move so that the part you clicked on ends up where you
|
||||
release the mouse. Nothing is changed while you are dragging. The
|
||||
drawing is too slow for that.
|
||||
|
||||
I'd like the cursor to change as you change tools, but the stock
|
||||
wx.Cursors didn't include anything I liked, so I stuck with the
|
||||
pointer. Please let me know if you have any nice cursor images for me to
|
||||
use.
|
||||
|
||||
|
||||
Any bugs, comments, feedback, questions, and especially code are welcome:
|
||||
|
||||
-Chris Barker
|
||||
|
||||
Chris.Barker@noaa.gov
|
||||
|
||||
"""
|
||||
|
||||
def OnInit(self):
|
||||
frame = DrawFrame(None, wx.ID_ANY,
|
||||
title = "FloatCanvas Demo App",
|
||||
size = (700,700) )
|
||||
|
||||
self.SetTopWindow(frame)
|
||||
|
||||
return True
|
||||
|
||||
app = DemoApp(False)
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
48
samples/floatcanvas/MouseTest.py
Executable file
48
samples/floatcanvas/MouseTest.py
Executable file
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Small demo of catching Mouse events using just FloatCanvas, rather than
|
||||
NavCanvas
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
app = wx.App(0)
|
||||
|
||||
try:
|
||||
# See if there is a local copy
|
||||
import sys
|
||||
sys.path.append("../")
|
||||
from floatcanvas import NavCanvas, FloatCanvas, GUIMode
|
||||
except ImportError:
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas, GUIMode
|
||||
|
||||
class TestFrame(wx.Frame):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
self.canvas =FloatCanvas.FloatCanvas(self, BackgroundColor = "DARK SLATE BLUE")
|
||||
|
||||
# Layout
|
||||
MainSizer = wx.BoxSizer(wx.VERTICAL)
|
||||
MainSizer.Add(self.canvas, 4, wx.EXPAND)
|
||||
self.SetSizer(MainSizer)
|
||||
|
||||
self.canvas.Bind(FloatCanvas.EVT_LEFT_DOWN, self.OnLeftDown)
|
||||
|
||||
self.canvas.AddRectangle((10,10), (100, 20), FillColor="red")
|
||||
|
||||
self.canvas.SetMode(GUIMode.GUIMouse(self.canvas))
|
||||
|
||||
wx.CallAfter(self.canvas.ZoomToBB)
|
||||
|
||||
def OnLeftDown(self, event):
|
||||
print 'Left Button clicked at:', event.Coords
|
||||
|
||||
frame = TestFrame(None, title="Mouse Event Tester")
|
||||
#self.SetTopWindow(frame)
|
||||
frame.Show(True)
|
||||
app.MainLoop()
|
||||
|
281
samples/floatcanvas/MovingElements.py
Executable file
281
samples/floatcanvas/MovingElements.py
Executable file
@@ -0,0 +1,281 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
This is a small demo, showing how to make an object that can be moved around.
|
||||
|
||||
It also contains a simple prototype for a "Connector" object
|
||||
-- a line connecting two other objects
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
#ver = 'local'
|
||||
ver = 'installed'
|
||||
|
||||
if ver == 'installed': ## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, Resources
|
||||
from wx.lib.floatcanvas import FloatCanvas as FC
|
||||
print "using installed version:", wx.lib.floatcanvas.__version__
|
||||
elif ver == 'local':
|
||||
## import a local version
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from floatcanvas import NavCanvas, Resources
|
||||
from floatcanvas import FloatCanvas as FC
|
||||
from floatcanvas.Utilities import BBox
|
||||
|
||||
import numpy as N
|
||||
|
||||
## here we create some new mixins:
|
||||
|
||||
class MovingObjectMixin:
|
||||
"""
|
||||
Methods required for a Moving object
|
||||
|
||||
"""
|
||||
|
||||
def GetOutlinePoints(self):
|
||||
BB = self.BoundingBox
|
||||
OutlinePoints = N.array( ( (BB[0,0], BB[0,1]),
|
||||
(BB[0,0], BB[1,1]),
|
||||
(BB[1,0], BB[1,1]),
|
||||
(BB[1,0], BB[0,1]),
|
||||
)
|
||||
)
|
||||
|
||||
return OutlinePoints
|
||||
|
||||
|
||||
class ConnectorObjectMixin:
|
||||
"""
|
||||
Mixin class for DrawObjects that can be connected with lines
|
||||
|
||||
NOte that this versionony works for Objects that have an "XY" attribute:
|
||||
that is, one that is derived from XHObjectMixin.
|
||||
|
||||
"""
|
||||
|
||||
def GetConnectPoint(self):
|
||||
return self.XY
|
||||
|
||||
class MovingBitmap(FC.ScaledBitmap, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
ScaledBitmap Object that can be moved
|
||||
"""
|
||||
## All we need to do is is inherit from:
|
||||
## ScaledBitmap, MovingObjectMixin and ConnectorObjectMixin
|
||||
pass
|
||||
|
||||
class MovingCircle(FC.Circle, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
ScaledBitmap Object that can be moved
|
||||
"""
|
||||
## All we need to do is is inherit from:
|
||||
## ScaledBitmap, MovingObjectMixin and ConnectorObjectMixin
|
||||
pass
|
||||
|
||||
class MovingArc(FC.Arc, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
ScaledBitmap Object that can be moved
|
||||
"""
|
||||
## All we need to do is is inherit from:
|
||||
## ScaledBitmap, MovingObjectMixin and ConnectorObjectMixin
|
||||
pass
|
||||
|
||||
class ConnectorLine(FC.LineOnlyMixin, FC.DrawObject,):
|
||||
"""
|
||||
|
||||
A Line that connects two objects -- it uses the objects to get its coordinates
|
||||
|
||||
"""
|
||||
##fixme: this should be added to the Main FloatCanvas Objects some day.
|
||||
def __init__(self,
|
||||
Object1,
|
||||
Object2,
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 1,
|
||||
InForeground = False):
|
||||
FC.DrawObject.__init__(self, InForeground)
|
||||
|
||||
self.Object1 = Object1
|
||||
self.Object2 = Object2
|
||||
self.LineColor = LineColor
|
||||
self.LineStyle = LineStyle
|
||||
self.LineWidth = LineWidth
|
||||
|
||||
self.CalcBoundingBox()
|
||||
self.SetPen(LineColor,LineStyle,LineWidth)
|
||||
|
||||
self.HitLineWidth = max(LineWidth,self.MinHitLineWidth)
|
||||
|
||||
def CalcBoundingBox(self):
|
||||
self.BoundingBox = BBox.fromPoints((self.Object1.GetConnectPoint(),
|
||||
self.Object2.GetConnectPoint()) )
|
||||
if self._Canvas:
|
||||
self._Canvas.BoundingBoxDirty = True
|
||||
|
||||
|
||||
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
|
||||
Points = N.array( (self.Object1.GetConnectPoint(),
|
||||
self.Object2.GetConnectPoint()) )
|
||||
Points = WorldToPixel(Points)
|
||||
dc.SetPen(self.Pen)
|
||||
dc.DrawLines(Points)
|
||||
if HTdc and self.HitAble:
|
||||
HTdc.SetPen(self.HitPen)
|
||||
HTdc.DrawLines(Points)
|
||||
|
||||
|
||||
class TriangleShape1(FC.Polygon, MovingObjectMixin):
|
||||
|
||||
def __init__(self, XY, L):
|
||||
|
||||
"""
|
||||
An equilateral triangle object
|
||||
XY is the middle of the triangle
|
||||
L is the length of one side of the Triangle
|
||||
"""
|
||||
|
||||
XY = N.asarray(XY)
|
||||
XY.shape = (2,)
|
||||
|
||||
Points = self.CompPoints(XY, L)
|
||||
|
||||
FC.Polygon.__init__(self, Points,
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 2,
|
||||
FillColor = "Red",
|
||||
FillStyle = "Solid")
|
||||
## Override the default OutlinePoints
|
||||
def GetOutlinePoints(self):
|
||||
return self.Points
|
||||
|
||||
def CompPoints(self, XY, L):
|
||||
c = L/ N.sqrt(3)
|
||||
|
||||
Points = N.array(((0, c),
|
||||
( L/2.0, -c/2.0),
|
||||
(-L/2.0, -c/2.0)),
|
||||
N.float_)
|
||||
|
||||
Points += XY
|
||||
return Points
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A simple frame used for the Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
Canvas.Bind(FC.EVT_MOTION, self.OnMove )
|
||||
Canvas.Bind(FC.EVT_LEFT_UP, self.OnLeftUp )
|
||||
|
||||
Points = N.array(((0,0),
|
||||
(1,0),
|
||||
(0.5, 1)),
|
||||
N.float)
|
||||
|
||||
data = (( (0,0), 1),
|
||||
( (3,3), 2),
|
||||
( (-2,3), 2.5 ),
|
||||
)
|
||||
|
||||
for p, L in data:
|
||||
Tri = TriangleShape1(p, 1)
|
||||
Canvas.AddObject(Tri)
|
||||
Tri.Bind(FC.EVT_FC_LEFT_DOWN, self.ObjectHit)
|
||||
|
||||
Circle = MovingCircle( (1, 3), 2, FillColor="Blue")
|
||||
Canvas.AddObject(Circle)
|
||||
Circle.Bind(FC.EVT_FC_LEFT_DOWN, self.ObjectHit)
|
||||
|
||||
Bitmaps = []
|
||||
## create the bitmaps first
|
||||
for Point in ((1,1), (-4,3)):
|
||||
Bitmaps.append(MovingBitmap(Resources.getMondrianImage(),
|
||||
Point,
|
||||
Height=1,
|
||||
Position='cc')
|
||||
)
|
||||
Line = ConnectorLine(Bitmaps[0], Bitmaps[1], LineWidth=3, LineColor="Red")
|
||||
Canvas.AddObject(Line)
|
||||
|
||||
|
||||
|
||||
## then add them to the Canvas, so they are on top of the line
|
||||
for bmp in Bitmaps:
|
||||
Canvas.AddObject(bmp)
|
||||
bmp.Bind(FC.EVT_FC_LEFT_DOWN, self.ObjectHit)
|
||||
|
||||
A = MovingArc((-5, 0),(-2, 2),(-5, 2), LineColor="Red", LineWidth=2)
|
||||
self.Canvas.AddObject(A)
|
||||
A.Bind(FC.EVT_FC_LEFT_DOWN, self.ObjectHit)
|
||||
|
||||
self.Show(True)
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
self.MoveObject = None
|
||||
self.Moving = False
|
||||
|
||||
return None
|
||||
|
||||
def ObjectHit(self, object):
|
||||
if not self.Moving:
|
||||
self.Moving = True
|
||||
self.StartPoint = object.HitCoordsPixel
|
||||
self.StartObject = self.Canvas.WorldToPixel(object.GetOutlinePoints())
|
||||
self.MoveObject = None
|
||||
self.MovingObject = object
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
and moves the object it is clicked on
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.4f, %.4f"%tuple(event.Coords))
|
||||
|
||||
if self.Moving:
|
||||
dxy = event.GetPosition() - self.StartPoint
|
||||
# Draw the Moving Object:
|
||||
dc = wx.ClientDC(self.Canvas)
|
||||
dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
|
||||
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||
dc.SetLogicalFunction(wx.XOR)
|
||||
if self.MoveObject is not None:
|
||||
dc.DrawPolygon(self.MoveObject)
|
||||
self.MoveObject = self.StartObject + dxy
|
||||
dc.DrawPolygon(self.MoveObject)
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
if self.Moving:
|
||||
self.Moving = False
|
||||
if self.MoveObject is not None:
|
||||
dxy = event.GetPosition() - self.StartPoint
|
||||
dxy = self.Canvas.ScalePixelToWorld(dxy)
|
||||
self.MovingObject.Move(dxy)
|
||||
self.MoveTri = None
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
app = wx.PySimpleApp(0)
|
||||
DrawFrame(None, -1, "FloatCanvas Moving Object App", wx.DefaultPosition, (700,700) )
|
||||
app.MainLoop()
|
238
samples/floatcanvas/MovingPlot.py
Executable file
238
samples/floatcanvas/MovingPlot.py
Executable file
@@ -0,0 +1,238 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
A small test app that uses FloatCanvas to draw a plot, and have an
|
||||
efficient moving line on it.
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
import numpy as N
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
## Set up the MenuBar
|
||||
|
||||
MenuBar = wx.MenuBar()
|
||||
|
||||
file_menu = wx.Menu()
|
||||
item = file_menu.Append(wx.ID_ANY, "E&xit","Terminate the program")
|
||||
self.Bind(wx.EVT_MENU, self.OnQuit, item)
|
||||
MenuBar.Append(file_menu, "&File")
|
||||
|
||||
draw_menu = wx.Menu()
|
||||
item = draw_menu.Append(wx.ID_ANY, "&Run","Run the test")
|
||||
self.Bind(wx.EVT_MENU, self.RunTest, item)
|
||||
item = draw_menu.Append(wx.ID_ANY, "&Stop","Stop the test")
|
||||
self.Bind(wx.EVT_MENU, self.Stop, item)
|
||||
MenuBar.Append(draw_menu, "&Plot")
|
||||
|
||||
|
||||
help_menu = wx.Menu()
|
||||
item = help_menu.Append(wx.ID_ANY, "&About",
|
||||
"More information About this program")
|
||||
self.Bind(wx.EVT_MENU, self.OnAbout, item)
|
||||
MenuBar.Append(help_menu, "&Help")
|
||||
|
||||
self.SetMenuBar(MenuBar)
|
||||
|
||||
|
||||
self.CreateStatusBar()
|
||||
self.SetStatusText("")
|
||||
|
||||
wx.EVT_CLOSE(self, self.OnCloseWindow)
|
||||
|
||||
# Add the Canvas
|
||||
NC = NavCanvas.NavCanvas(self ,wx.ID_ANY ,(500,300),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "WHITE"
|
||||
)
|
||||
self.Canvas = NC.Canvas
|
||||
|
||||
self.Canvas.NumBetweenBlits = 1000
|
||||
|
||||
# Add a couple of tools to the Canvas Toolbar
|
||||
|
||||
tb = NC.ToolBar
|
||||
tb.AddSeparator()
|
||||
|
||||
StopButton = wx.Button(tb, wx.ID_ANY, "Stop")
|
||||
tb.AddControl(StopButton)
|
||||
StopButton.Bind(wx.EVT_BUTTON, self.Stop)
|
||||
|
||||
PlayButton = wx.Button(tb, wx.ID_ANY, "Run")
|
||||
tb.AddControl(PlayButton)
|
||||
PlayButton.Bind(wx.EVT_BUTTON, self.RunTest)
|
||||
|
||||
tb.Realize()
|
||||
|
||||
self.Show(True)
|
||||
|
||||
self.timer = None
|
||||
|
||||
self.DrawAxis()
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def OnAbout(self, event):
|
||||
dlg = wx.MessageDialog(self, "This is a small program to demonstrate\n"
|
||||
"the use of the FloatCanvas\n"
|
||||
"for simple plotting",
|
||||
"About Me", wx.OK | wx.ICON_INFORMATION)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def ZoomToFit(self,event):
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
def OnQuit(self,event):
|
||||
self.Close(True)
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
def DrawAxis(self):
|
||||
Canvas = self.Canvas
|
||||
|
||||
# Draw the Axis
|
||||
|
||||
# Note: the AddRectangle Parameters all have sensible
|
||||
# defaults. I've put them all here explicitly, so you can see
|
||||
# what the options are.
|
||||
|
||||
self.Canvas.AddRectangle((0, -1.1),
|
||||
(2*N.pi, 2.2),
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 1,
|
||||
FillColor = None,
|
||||
FillStyle = "Solid",
|
||||
InForeground = 0)
|
||||
for tic in N.arange(7):
|
||||
self.Canvas.AddText("%1.1f"%tic,
|
||||
(tic,-1.1),
|
||||
Position = 'tc')
|
||||
|
||||
for tic in N.arange(-1, 1.1, 0.5):
|
||||
self.Canvas.AddText("%1.1f"%tic,
|
||||
(0,tic),
|
||||
Position = 'cr')
|
||||
|
||||
# Add a phantom rectangle to get the bounding box right
|
||||
# (the bounding box doesn't get unscaled text right)
|
||||
self.Canvas.AddRectangle((-0.7, -1.5), (7, 3), LineColor = None)
|
||||
|
||||
Canvas.ZoomToBB()
|
||||
Canvas.Draw()
|
||||
|
||||
def Stop(self,event):
|
||||
if self.timer:
|
||||
self.timer.Stop()
|
||||
|
||||
|
||||
def OnTimer(self,event):
|
||||
self.count += .1
|
||||
self.data1[:,1] = N.sin(self.time+self.count) #fake move
|
||||
|
||||
self.line.SetPoints(self.data1)
|
||||
|
||||
self.Canvas.Draw()
|
||||
|
||||
def RunTest(self,event = None):
|
||||
self.n = 100
|
||||
self.dT = 0.05
|
||||
|
||||
self.time = 2.0*N.pi*N.arange(100)/100.0
|
||||
|
||||
self.data1 = 1.0*N.ones((100,2))
|
||||
self.data1[:,0] = self.time
|
||||
self.data1[:,1] = N.sin(self.time)
|
||||
Canvas = self.Canvas
|
||||
self.Canvas.ClearAll()
|
||||
self.DrawAxis()
|
||||
self.line = Canvas.AddLine(self.data1,
|
||||
LineColor = "Red",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 2,
|
||||
InForeground = 1)
|
||||
self.Canvas.Draw()
|
||||
|
||||
self.timerID = wx.NewId()
|
||||
self.timer = wx.Timer(self,self.timerID)
|
||||
|
||||
wx.EVT_TIMER(self,self.timerID,self.OnTimer)
|
||||
|
||||
self.count = 0
|
||||
self.timer.Start(int(self.dT*1000))
|
||||
|
||||
class DemoApp(wx.App):
|
||||
"""
|
||||
How the demo works:
|
||||
|
||||
Either under the Draw menu, or on the toolbar, you can push Run and Stop
|
||||
|
||||
"Run" start an oscilloscope like display of a moving sine curve
|
||||
"Stop" stops it.
|
||||
|
||||
While the plot os running (or not) you can zoom in and out and move
|
||||
about the picture. There is a tool bar with three tools that can be
|
||||
selected.
|
||||
|
||||
The magnifying glass with the plus is the zoom in tool. Once selected,
|
||||
if you click the image, it will zoom in, centered on where you
|
||||
clicked. If you click and drag the mouse, you will get a rubber band
|
||||
box, and the image will zoom to fit that box when you release it.
|
||||
|
||||
The magnifying glass with the minus is the zoom out tool. Once selected,
|
||||
if you click the image, it will zoom out, centered on where you
|
||||
clicked.
|
||||
|
||||
The hand is the move tool. Once selected, if you click and drag on
|
||||
the image, it will move so that the part you clicked on ends up
|
||||
where you release the mouse. Nothing is changed while you are
|
||||
dragging, but you can see the outline of the former picture.
|
||||
|
||||
I'd like the cursor to change as you change tools, but the stock
|
||||
wx.Cursors didn't include anything I liked, so I stuck with the
|
||||
pointer. Please let me know if you have any nice cursor images for me to
|
||||
use.
|
||||
|
||||
|
||||
Any bugs, comments, feedback, questions, and especially code are welcome:
|
||||
|
||||
-Chris Barker
|
||||
|
||||
Chris.Barker@noaa.gov
|
||||
|
||||
"""
|
||||
|
||||
def OnInit(self):
|
||||
wx.InitAllImageHandlers()
|
||||
frame = DrawFrame(None, wx.ID_ANY,
|
||||
title = "Plotting Test",
|
||||
size = (700,400) )
|
||||
|
||||
self.SetTopWindow(frame)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
app = DemoApp(0)
|
||||
app.MainLoop()
|
||||
|
||||
|
189
samples/floatcanvas/MovingTriangle.py
Executable file
189
samples/floatcanvas/MovingTriangle.py
Executable file
@@ -0,0 +1,189 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
This is a small demo, showing how to make an object that can be moved around.
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
#ver = 'local'
|
||||
ver = 'installed'
|
||||
|
||||
if ver == 'installed': ## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, Resources
|
||||
from wx.lib.floatcanvas import FloatCanvas as FC
|
||||
print "using installed version:", wx.lib.floatcanvas.__version__
|
||||
elif ver == 'local':
|
||||
## import a local version
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from floatcanvas import NavCanvas, Resources
|
||||
from floatcanvas import FloatCanvas as FC
|
||||
|
||||
import numpy as N
|
||||
|
||||
## here we create a new DrawObject:
|
||||
## code borrowed and adapted from Werner Bruhin
|
||||
|
||||
class ShapeMixin:
|
||||
"""
|
||||
just here for added features later
|
||||
"""
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
class TriangleShape1(FC.Polygon, ShapeMixin):
|
||||
|
||||
def __init__(self, XY, L):
|
||||
|
||||
"""
|
||||
An equilateral triangle object
|
||||
|
||||
XY is the middle of the triangle
|
||||
|
||||
L is the length of one side of the Triangle
|
||||
"""
|
||||
|
||||
XY = N.asarray(XY)
|
||||
XY.shape = (2,)
|
||||
|
||||
Points = self.CompPoints(XY, L)
|
||||
|
||||
FC.Polygon.__init__(self, Points,
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 2,
|
||||
FillColor = "Red",
|
||||
FillStyle = "Solid")
|
||||
ShapeMixin.__init__(self)
|
||||
|
||||
def CompPoints(self, XY, L):
|
||||
c = L/ N.sqrt(3)
|
||||
|
||||
Points = N.array(((0, c),
|
||||
( L/2.0, -c/2.0),
|
||||
(-L/2.0, -c/2.0)),
|
||||
N.float_)
|
||||
|
||||
Points += XY
|
||||
return Points
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,parent, id,title,position,size):
|
||||
wx.Frame.__init__(self,parent, id,title,position, size)
|
||||
|
||||
self.CreateStatusBar()
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
Canvas.Bind(FC.EVT_MOTION, self.OnMove )
|
||||
Canvas.Bind(FC.EVT_LEFT_UP, self.OnLeftUp )
|
||||
|
||||
Canvas.AddRectangle((-5,-5),
|
||||
(10,10),
|
||||
LineColor = "Red",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 2,
|
||||
FillColor = "CYAN",
|
||||
FillStyle = "Solid")
|
||||
|
||||
Points = N.array(((0,0),
|
||||
(1,0),
|
||||
(0.5, 1)),
|
||||
N.float_)
|
||||
|
||||
data = (( (0,0), 1),
|
||||
( (3,3), 2),
|
||||
( (-2,3), 2.5 ),
|
||||
)
|
||||
|
||||
for p, L in data:
|
||||
Tri = TriangleShape1(p, 1)
|
||||
Canvas.AddObject(Tri)
|
||||
Tri.Bind(FC.EVT_FC_LEFT_DOWN, self.TriHit)
|
||||
|
||||
|
||||
self.MoveTri = None
|
||||
|
||||
self.Show(True)
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
self.Moving = False
|
||||
|
||||
return None
|
||||
|
||||
def TriHit(self, object):
|
||||
print "In TriHit"
|
||||
if not self.Moving:
|
||||
self.Moving = True
|
||||
self.StartPoint = object.HitCoordsPixel
|
||||
self.StartTri = self.Canvas.WorldToPixel(object.Points)
|
||||
self.MoveTri = None
|
||||
self.MovingTri = object
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
And moves the triangle it it is clicked on
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.4f, %.4f"%tuple(event.Coords))
|
||||
|
||||
if self.Moving:
|
||||
dxy = event.GetPosition() - self.StartPoint
|
||||
# Draw the Moving Triangle:
|
||||
dc = wx.ClientDC(self.Canvas)
|
||||
dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
|
||||
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||
dc.SetLogicalFunction(wx.XOR)
|
||||
if self.MoveTri is not None:
|
||||
dc.DrawPolygon(self.MoveTri)
|
||||
self.MoveTri = self.StartTri + dxy
|
||||
dc.DrawPolygon(self.MoveTri)
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
if self.Moving:
|
||||
self.Moving = False
|
||||
if self.MoveTri is not None:
|
||||
dxy = event.GetPosition() - self.StartPoint
|
||||
dxy = self.Canvas.ScalePixelToWorld(dxy)
|
||||
self.MovingTri.Move(dxy) ## The Move function has jsut been added
|
||||
## to the FloatCanvas PointsObject
|
||||
## It does the next three lines for you.
|
||||
#self.Tri.Points += dxy
|
||||
#self.Tri.BoundingBox += dxy
|
||||
#self.Canvas.BoundingBoxDirty = True
|
||||
self.MoveTri = None
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
app = wx.PySimpleApp(0)
|
||||
DrawFrame(None, -1, "FloatCanvas TextBox Test App", wx.DefaultPosition, (700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
samples/floatcanvas/NOAA.png
Normal file
BIN
samples/floatcanvas/NOAA.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.4 KiB |
93
samples/floatcanvas/NoToolbar.py
Executable file
93
samples/floatcanvas/NoToolbar.py
Executable file
@@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A simple example of how to use FloatCanvas by itself, without the NavCanvas toolbar
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = FloatCanvas.FloatCanvas(self,
|
||||
size = (500,500),
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
)
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
Point = (45,40)
|
||||
Box = Canvas.AddScaledTextBox("A Two Line\nString",
|
||||
Point,
|
||||
2,
|
||||
Color = "Black",
|
||||
BackgroundColor = None,
|
||||
LineColor = "Red",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 1,
|
||||
Width = None,
|
||||
PadSize = 5,
|
||||
Family = wx.ROMAN,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'br',
|
||||
Alignment = "left",
|
||||
InForeground = False)
|
||||
|
||||
Box.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.Binding)
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
def Binding(self, event):
|
||||
print "Writing a png file:"
|
||||
self.Canvas.SaveAsImage("junk.png")
|
||||
print "Writing a jpeg file:"
|
||||
self.Canvas.SaveAsImage("junk.jpg",wx.BITMAP_TYPE_JPEG)
|
||||
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
43
samples/floatcanvas/NonGUI.py
Executable file
43
samples/floatcanvas/NonGUI.py
Executable file
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
Demo of a FloatCanvas App that will create an image, without
|
||||
actually showing anything on screen. It seems to work, but you do need
|
||||
to have an X-server running on *nix for this to work.
|
||||
|
||||
Note: you need to specify the size in the FloatCanvas Constructor.
|
||||
|
||||
hmm -- I wonder if you'd even need the frame?
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
app = wx.PySimpleApp()
|
||||
|
||||
f = wx.Frame(None)
|
||||
Canvas = FloatCanvas.FloatCanvas(f,
|
||||
BackgroundColor = "Cyan",
|
||||
size=(500,500)
|
||||
)
|
||||
|
||||
|
||||
Canvas.AddRectangle((0,0), (16,20))
|
||||
Canvas.AddRectangle((1,1), (6,8.5))
|
||||
Canvas.AddRectangle((9,1), (6,8.5))
|
||||
Canvas.AddRectangle((9,10.5), (6,8.5))
|
||||
Canvas.AddRectangle((1,10.5), (6,8.5))
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
|
||||
print "Saving the image:", "junk.png"
|
||||
Canvas.SaveAsImage("junk.png")
|
||||
|
142
samples/floatcanvas/OverlayDemo.py
Executable file
142
samples/floatcanvas/OverlayDemo.py
Executable file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A simple demo to show how to "Overlays": i.e. drawing something
|
||||
on top of eveything else on the Canvas, relative to window coords,
|
||||
rather than screen coords.
|
||||
|
||||
This method uses the "GridOver" object in the FloatCanvas
|
||||
- it was orginally dsigend for girds, graticule,s etc. that
|
||||
are always drawn regardless of zoom, pan, etc, but it works
|
||||
for overlays too.
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
|
||||
try:
|
||||
# See if there is a local copy
|
||||
import sys
|
||||
sys.path.append("../")
|
||||
from floatcanvas import NavCanvas, FloatCanvas
|
||||
except ImportError:
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
class TextOverlay(FloatCanvas.Text):
|
||||
"""
|
||||
An example of an Overlay object:
|
||||
|
||||
all it needs is a new _Draw method.
|
||||
|
||||
NOTE: you may want to get fancier with this,
|
||||
deriving from ScaledTextBox
|
||||
|
||||
"""
|
||||
def __init__(self,
|
||||
String,
|
||||
xy,
|
||||
Size = 24,
|
||||
Color = "Black",
|
||||
BackgroundColor = None,
|
||||
Family = wx.MODERN,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Font = None):
|
||||
FloatCanvas.Text.__init__(self,
|
||||
String,
|
||||
xy,
|
||||
Size = Size,
|
||||
Color = Color,
|
||||
BackgroundColor = BackgroundColor,
|
||||
Family = Family,
|
||||
Style = Style,
|
||||
Weight = Weight,
|
||||
Underlined = Underlined,
|
||||
Font = Font)
|
||||
|
||||
def _Draw(self, dc, Canvas):
|
||||
"""
|
||||
_Draw method for Overlay
|
||||
note: this is a differeent signarture than the DrawObject Draw
|
||||
"""
|
||||
dc.SetFont(self.Font)
|
||||
dc.SetTextForeground(self.Color)
|
||||
if self.BackgroundColor:
|
||||
dc.SetBackgroundMode(wx.SOLID)
|
||||
dc.SetTextBackground(self.BackgroundColor)
|
||||
else:
|
||||
dc.SetBackgroundMode(wx.TRANSPARENT)
|
||||
## maybe inpliment this...
|
||||
#if self.TextWidth is None or self.TextHeight is None:
|
||||
# (self.TextWidth, self.TextHeight) = dc.GetTextExtent(self.String)
|
||||
#XY = self.ShiftFun(XY[0], XY[1], self.TextWidth, self.TextHeight)
|
||||
dc.DrawTextPoint(self.String, self.XY)
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
|
||||
Point = (45,40)
|
||||
Box = Canvas.AddCircle(Point,
|
||||
Diameter = 10,
|
||||
FillColor = "Cyan",
|
||||
LineColor = "Red",
|
||||
LineWidth = 6)
|
||||
|
||||
Canvas.GridOver = TextOverlay("Some Text",
|
||||
(20,20),
|
||||
Size = 48,
|
||||
Color = "Black",
|
||||
BackgroundColor = 'Pink',
|
||||
)
|
||||
|
||||
FloatCanvas.EVT_MOTION(Canvas, self.OnMove )
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
|
||||
|
||||
app = wx.App(False) # true to get its own output window.
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
91
samples/floatcanvas/PieChart.py
Executable file
91
samples/floatcanvas/PieChart.py
Executable file
@@ -0,0 +1,91 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
from wx.lib.floatcanvas.SpecialObjects import PieChart
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
#from floatcanvas.SpecialObjects import PieChart
|
||||
|
||||
|
||||
import numpy as N
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
Values = (10,10,10)
|
||||
Colors = ('Red', 'Blue', 'Green')
|
||||
Pie1 = PieChart(N.array((0, 0)), 10, Values, Colors, Scaled=False)
|
||||
Canvas.AddObject(Pie1)
|
||||
|
||||
Values = (10, 5, 5)
|
||||
Pie2 = PieChart(N.array((40, 0)), 10, Values, Colors)
|
||||
Canvas.AddObject(Pie2)
|
||||
|
||||
# test default colors
|
||||
Values = (10, 15, 12, 24, 6, 10, 13, 11, 9, 13, 15, 12)
|
||||
Pie3 = PieChart(N.array((20, 20)), 10, Values, LineColor="Black")
|
||||
Canvas.AddObject(Pie3)
|
||||
|
||||
# missng slice!
|
||||
Values = (10, 15, 12, 24)
|
||||
Colors = ('Red', 'Blue', 'Green', None)
|
||||
Pie4 = PieChart(N.array((0, -15)), 10, Values, Colors, LineColor="Black")
|
||||
Canvas.AddObject(Pie4)
|
||||
|
||||
|
||||
# Test the styles
|
||||
Values = (10, 12, 14)
|
||||
Styles = ("Solid", "CrossDiagHatch","CrossHatch")
|
||||
Colors = ('Red', 'Blue', 'Green')
|
||||
Pie4 = PieChart(N.array((20, -20)), 10, Values, Colors, Styles)
|
||||
Canvas.AddObject(Pie2)
|
||||
|
||||
Pie1.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.Pie1Hit)
|
||||
Pie2.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.Pie2Hit)
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def Pie1Hit(self, obj):
|
||||
print "Pie1 hit!"
|
||||
|
||||
def Pie2Hit(self, obj):
|
||||
print "Pie2 hit!"
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
"""
|
||||
self.SetStatusText("%.2g, %.2g"%tuple(event.Coords))
|
||||
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
150
samples/floatcanvas/PixelBitmap.py
Executable file
150
samples/floatcanvas/PixelBitmap.py
Executable file
@@ -0,0 +1,150 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A simple demo to show how to drw a bitmap on top of the Canvas at given pixel coords.
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
import numpy as np
|
||||
|
||||
try:
|
||||
# See if there is a local copy
|
||||
import sys
|
||||
sys.path.append("../")
|
||||
from floatcanvas import NavCanvas, FloatCanvas
|
||||
except ImportError:
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
FC = FloatCanvas
|
||||
|
||||
class PixelBitmap:
|
||||
"""
|
||||
An unscaled bitmap that can be put on top of the canvas using:
|
||||
|
||||
Canvas.GridOver = MyPixelBitmap
|
||||
|
||||
It will always be drawn on top of everything else, and be positioned
|
||||
according to pixel coordinates on teh screen, regardless of zoom and
|
||||
pan position.
|
||||
|
||||
"""
|
||||
def __init__(self, Bitmap, XY, Position = 'tl'):
|
||||
"""
|
||||
PixelBitmap (Bitmap, XY, Position='tl')
|
||||
|
||||
Bitmap is a wx.Bitmap or wx.Image
|
||||
|
||||
XY is the (x,y) location to place the bitmap, in pixel coordinates
|
||||
|
||||
Position indicates from where in the window the position is relative to:
|
||||
'tl' indicated the position from the top left the the window (the detault)
|
||||
'br' the bottom right
|
||||
'cr the center right, etc.
|
||||
|
||||
"""
|
||||
if type(Bitmap) == wx._gdi.Bitmap:
|
||||
self.Bitmap = Bitmap
|
||||
elif type(Bitmap) == wx._core.Image:
|
||||
self.Bitmap = wx.BitmapFromImage(Bitmap)
|
||||
else:
|
||||
raise FC.FloatCanvasError("PixelBitmap takes only a wx.Bitmap or a wx.Image as input")
|
||||
|
||||
self.XY = np.asarray(XY, dtype=np.int).reshape((2,))
|
||||
self.Position = Position
|
||||
|
||||
(self.Width, self.Height) = self.Bitmap.GetWidth(), self.Bitmap.GetHeight()
|
||||
self.ShiftFun = FC.TextObjectMixin.ShiftFunDict[Position]
|
||||
|
||||
def _Draw(self, dc, Canvas):
|
||||
w, h = Canvas.Size
|
||||
XY = self.XY
|
||||
if self.Position[0] == 'b':
|
||||
XY = (XY[0], h - XY[1] - self.Height)
|
||||
elif self.Position[0] == 'c':
|
||||
XY = (XY[0], XY[1] + (h - self.Height)/2)
|
||||
|
||||
if self.Position[1] == 'r':
|
||||
XY = (w - XY[0] - self.Width, XY[1])
|
||||
elif self.Position[1] == 'c':
|
||||
XY = (XY[0] + (w - self.Width)/2, XY[1])
|
||||
|
||||
dc.DrawBitmapPoint(self.Bitmap, XY, True)
|
||||
|
||||
class GridGroup:
|
||||
def __init__(self, grids=[]):
|
||||
self.Grids = grids
|
||||
|
||||
def _Draw(self, *args):
|
||||
for grid in self.Grids:
|
||||
grid._Draw(*args)
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
|
||||
Point = (45,40)
|
||||
Box = Canvas.AddCircle(Point,
|
||||
Diameter = 10,
|
||||
FillColor = "Black",
|
||||
LineColor = "Red",
|
||||
LineWidth = 6)
|
||||
bmp = wx.Bitmap('NOAA.png')
|
||||
grids = GridGroup([PixelBitmap(bmp, (10, 10), Position='tl'),
|
||||
PixelBitmap(bmp, (10, 10), Position='br'),
|
||||
PixelBitmap(bmp, (10, 10), Position='tr'),
|
||||
PixelBitmap(bmp, (10, 10), Position='bl'),
|
||||
PixelBitmap(bmp, (10, 10), Position='cl'),
|
||||
PixelBitmap(bmp, (10, 10), Position='cr'),
|
||||
PixelBitmap(bmp, (10, 10), Position='cc'),
|
||||
PixelBitmap(bmp, (10, 10), Position='tc'),
|
||||
PixelBitmap(bmp, (10, 10), Position='bc'),
|
||||
])
|
||||
Canvas.GridOver = grids
|
||||
|
||||
FloatCanvas.EVT_MOTION(Canvas, self.OnMove )
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
|
||||
|
||||
app = wx.App(False) # true to get its own output window.
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
81
samples/floatcanvas/PointsHitDemo.py
Executable file
81
samples/floatcanvas/PointsHitDemo.py
Executable file
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
Pts = ((45,40), (20, 15), (10, 40), (30,30))
|
||||
|
||||
Points = Canvas.AddPointSet(Pts, Diameter=3, Color="Red")
|
||||
Points.HitLineWidth = 10
|
||||
|
||||
Points.Bind(FloatCanvas.EVT_FC_ENTER_OBJECT, self.OnOverPoints)
|
||||
Points.Bind(FloatCanvas.EVT_FC_LEAVE_OBJECT, self.OnLeavePoints)
|
||||
Points.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.OnLeftDown)
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnOverPoints(self, obj):
|
||||
print "Mouse over point: ", obj.FindClosestPoint(obj.HitCoords)
|
||||
|
||||
def OnLeavePoints(self, obj):
|
||||
print "Mouse left point: ", obj.FindClosestPoint(obj.HitCoords)
|
||||
|
||||
def OnLeftDown(self, obj):
|
||||
print "Mouse left down on point: ", obj.FindClosestPoint(obj.HitCoords)
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
255
samples/floatcanvas/PolyEditor.py
Executable file
255
samples/floatcanvas/PolyEditor.py
Executable file
@@ -0,0 +1,255 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
PolyEditor: a simple app for editing polygons
|
||||
|
||||
Used as a demo for FloatCanvas
|
||||
"""
|
||||
import numpy as N
|
||||
import random
|
||||
import numpy.random as RandomArray
|
||||
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
# import a local copy:
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
import wx
|
||||
|
||||
ID_ABOUT_MENU = wx.ID_ABOUT
|
||||
ID_ZOOM_TO_FIT_MENU = wx.NewId()
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,parent, id,title,position,size):
|
||||
wx.Frame.__init__(self,parent, id,title,position, size)
|
||||
|
||||
## Set up the MenuBar
|
||||
MenuBar = wx.MenuBar()
|
||||
|
||||
FileMenu = wx.Menu()
|
||||
FileMenu.Append(wx.NewId(), "&Close","Close Application")
|
||||
wx.EVT_MENU(self, FileMenu.FindItem("Close"), self.OnQuit)
|
||||
|
||||
MenuBar.Append(FileMenu, "&File")
|
||||
|
||||
view_menu = wx.Menu()
|
||||
view_menu.Append(wx.NewId(), "Zoom to &Fit","Zoom to fit the window")
|
||||
wx.EVT_MENU(self, view_menu.FindItem("Zoom to &Fit"), self.ZoomToFit)
|
||||
MenuBar.Append(view_menu, "&View")
|
||||
|
||||
help_menu = wx.Menu()
|
||||
help_menu.Append(ID_ABOUT_MENU, "&About",
|
||||
"More information About this program")
|
||||
wx.EVT_MENU(self, ID_ABOUT_MENU, self.OnAbout)
|
||||
MenuBar.Append(help_menu, "&Help")
|
||||
|
||||
self.SetMenuBar(MenuBar)
|
||||
|
||||
self.CreateStatusBar()
|
||||
# Add the Canvas
|
||||
self.Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE"
|
||||
).Canvas
|
||||
|
||||
wx.EVT_CLOSE(self, self.OnCloseWindow)
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
FloatCanvas.EVT_LEFT_UP(self.Canvas, self.OnLeftUp )
|
||||
FloatCanvas.EVT_LEFT_DOWN(self.Canvas, self.OnLeftClick )
|
||||
|
||||
self.ResetSelections()
|
||||
|
||||
return None
|
||||
|
||||
def ResetSelections(self):
|
||||
self.SelectedPoly = None
|
||||
self.SelectedPolyOrig = None
|
||||
self.SelectedPoints = None
|
||||
self.PointSelected = False
|
||||
self.SelectedPointNeighbors = None
|
||||
|
||||
def OnAbout(self, event):
|
||||
dlg = wx.MessageDialog(self, "This is a small program to demonstrate\n"
|
||||
"the use of the FloatCanvas\n",
|
||||
"About Me", wx.OK | wx.ICON_INFORMATION)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def ZoomToFit(self,event):
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
def Clear(self,event = None):
|
||||
self.Canvas.ClearAll()
|
||||
self.Canvas.SetProjectionFun(None)
|
||||
self.Canvas.Draw()
|
||||
|
||||
def OnQuit(self,event):
|
||||
self.Close(True)
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
And moves a point if there is one selected
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
if self.PointSelected:
|
||||
PolyPoints = self.SelectedPoly.Points
|
||||
Index = self.SelectedPoints.Index
|
||||
dc = wx.ClientDC(self.Canvas)
|
||||
PixelCoords = event.GetPosition()
|
||||
dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
|
||||
dc.SetLogicalFunction(wx.XOR)
|
||||
if self.SelectedPointNeighbors is None:
|
||||
self.SelectedPointNeighbors = N.zeros((3,2), N.float_)
|
||||
#fixme: This feels very inelegant!
|
||||
if Index == 0:
|
||||
self.SelectedPointNeighbors[0] = self.SelectedPoly.Points[-1]
|
||||
self.SelectedPointNeighbors[1:3] = self.SelectedPoly.Points[:2]
|
||||
elif Index == len(self.SelectedPoly.Points)-1:
|
||||
self.SelectedPointNeighbors[0:2] = self.SelectedPoly.Points[-2:]
|
||||
self.SelectedPointNeighbors[2] = self.SelectedPoly.Points[0]
|
||||
else:
|
||||
self.SelectedPointNeighbors = self.SelectedPoly.Points[Index-1:Index+2]
|
||||
self.SelectedPointNeighbors = self.Canvas.WorldToPixel(self.SelectedPointNeighbors)
|
||||
else:
|
||||
dc.DrawLines(self.SelectedPointNeighbors)
|
||||
self.SelectedPointNeighbors[1] = PixelCoords
|
||||
dc.DrawLines(self.SelectedPointNeighbors)
|
||||
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
## if a point was selected, it's not anymore
|
||||
if self.PointSelected:
|
||||
self.SelectedPoly.Points[self.SelectedPoints.Index] = event.GetCoords()
|
||||
self.SelectedPoly.SetPoints(self.SelectedPoly.Points, copy = False)
|
||||
self.SelectedPoints.SetPoints(self.SelectedPoly.Points, copy = False)
|
||||
self.PointSelected = False
|
||||
self.SelectedPointNeighbors = None
|
||||
self.Canvas.Draw()
|
||||
|
||||
def OnLeftClick(self,event):
|
||||
## If a click happens outside the polygon, it's no longer selected
|
||||
self.DeSelectPoly()
|
||||
self.Canvas.Draw()
|
||||
|
||||
def Setup(self, event = None):
|
||||
"Seting up with some random polygons"
|
||||
wx.GetApp().Yield()
|
||||
self.ResetSelections()
|
||||
self.Canvas.ClearAll()
|
||||
|
||||
Range = (-10,10)
|
||||
|
||||
# Create a couple of random Polygons
|
||||
for i, color in enumerate(("LightBlue", "Green", "Purple","Yellow")):
|
||||
points = RandomArray.uniform(Range[0],Range[1],(6,2))
|
||||
Poly = self.Canvas.AddPolygon(points,
|
||||
LineWidth = 2,
|
||||
LineColor = "Black",
|
||||
FillColor = color,
|
||||
FillStyle = 'Solid')
|
||||
|
||||
Poly.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.SelectPoly)
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
|
||||
def SelectPoly(self, Object):
|
||||
Canvas = self.Canvas
|
||||
if Object is self.SelectedPolyOrig:
|
||||
pass
|
||||
else:
|
||||
if self.SelectedPoly:
|
||||
self.DeSelectPoly()
|
||||
self.SelectedPolyOrig = Object
|
||||
self.SelectedPoly = Canvas.AddPolygon(Object.Points,
|
||||
LineWidth = 2,
|
||||
LineColor = "Red",
|
||||
FillColor = "Red",
|
||||
FillStyle = "CrossHatch",
|
||||
InForeground = True)
|
||||
# Draw points on the Vertices of the Selected Poly:
|
||||
self.SelectedPoints = Canvas.AddPointSet(Object.Points,
|
||||
Diameter = 6,
|
||||
Color = "Red",
|
||||
InForeground = True)
|
||||
self.SelectedPoints.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.SelectPointHit)
|
||||
Canvas.Draw()
|
||||
|
||||
def DeSelectPoly(self):
|
||||
Canvas = self.Canvas
|
||||
if self.SelectedPolyOrig is not None:
|
||||
self.SelectedPolyOrig.SetPoints(self.SelectedPoly.Points, copy = False)
|
||||
self.Canvas.Draw(Force = True)
|
||||
Canvas.RemoveObject(self.SelectedPoly)
|
||||
Canvas.RemoveObject(self.SelectedPoints)
|
||||
self.ResetSelections()
|
||||
|
||||
def SelectPointHit(self, PointSet):
|
||||
PointSet.Index = PointSet.FindClosestPoint(PointSet.HitCoords)
|
||||
print "point #%i hit"%PointSet.Index
|
||||
#Index = PointSet.Index
|
||||
self.PointSelected = True
|
||||
|
||||
class PolyEditor(wx.App):
|
||||
"""
|
||||
|
||||
A simple example of making editable shapes with FloatCanvas
|
||||
|
||||
"""
|
||||
|
||||
def OnInit(self):
|
||||
wx.InitAllImageHandlers()
|
||||
frame = DrawFrame(None,
|
||||
-1,
|
||||
"FloatCanvas Demo App",
|
||||
wx.DefaultPosition,
|
||||
(700,700),
|
||||
)
|
||||
|
||||
self.SetTopWindow(frame)
|
||||
frame.Show()
|
||||
|
||||
frame.Setup()
|
||||
return True
|
||||
|
||||
PolyEditor(0).MainLoop()# put in True if you want output to go to it's own window.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
379
samples/floatcanvas/ProcessDiagram.py
Normal file
379
samples/floatcanvas/ProcessDiagram.py
Normal file
@@ -0,0 +1,379 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
This is a demo, showing how to work with a "tree" structure
|
||||
|
||||
It demonstrates moving objects around, etc, etc.
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
#ver = 'local'
|
||||
ver = 'installed'
|
||||
|
||||
if ver == 'installed': ## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, Resources
|
||||
from wx.lib.floatcanvas import FloatCanvas as FC
|
||||
from wx.lib.floatcanvas.Utilities import BBox
|
||||
print "using installed version:", wx.lib.floatcanvas.__version__
|
||||
elif ver == 'local':
|
||||
## import a local version
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from floatcanvas import NavCanvas, Resources
|
||||
from floatcanvas import FloatCanvas as FC
|
||||
from floatcanvas.Utilities import BBox
|
||||
|
||||
import numpy as N
|
||||
|
||||
## here we create some new mixins:
|
||||
## fixme: These really belong in floatcanvas package -- but I kind of want to clean it up some first
|
||||
|
||||
class MovingObjectMixin:
|
||||
"""
|
||||
Methods required for a Moving object
|
||||
|
||||
"""
|
||||
def GetOutlinePoints(self):
|
||||
"""
|
||||
Returns a set of points with which to draw the outline when moving the
|
||||
object.
|
||||
|
||||
Points are a NX2 array of (x,y) points in World coordinates.
|
||||
|
||||
|
||||
"""
|
||||
BB = self.BoundingBox
|
||||
OutlinePoints = N.array( ( (BB[0,0], BB[0,1]),
|
||||
(BB[0,0], BB[1,1]),
|
||||
(BB[1,0], BB[1,1]),
|
||||
(BB[1,0], BB[0,1]),
|
||||
)
|
||||
)
|
||||
|
||||
return OutlinePoints
|
||||
|
||||
class ConnectorObjectMixin:
|
||||
"""
|
||||
Mixin class for DrawObjects that can be connected with lines
|
||||
|
||||
Note that this version only works for Objects that have an "XY" attribute:
|
||||
that is, one that is derived from XHObjectMixin.
|
||||
|
||||
"""
|
||||
|
||||
def GetConnectPoint(self):
|
||||
return self.XY
|
||||
|
||||
class MovingBitmap(FC.ScaledBitmap, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
ScaledBitmap Object that can be moved
|
||||
"""
|
||||
## All we need to do is is inherit from:
|
||||
## ScaledBitmap, MovingObjectMixin and ConnectorObjectMixin
|
||||
pass
|
||||
|
||||
class MovingCircle(FC.Circle, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
ScaledBitmap Object that can be moved
|
||||
"""
|
||||
## All we need to do is is inherit from:
|
||||
## Circle MovingObjectMixin and ConnectorObjectMixin
|
||||
pass
|
||||
|
||||
|
||||
class MovingGroup(FC.Group, MovingObjectMixin, ConnectorObjectMixin):
|
||||
|
||||
def GetConnectPoint(self):
|
||||
return self.BoundingBox.Center
|
||||
|
||||
class NodeObject(FC.Group, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
A version of the moving group for nodes -- an ellipse with text on it.
|
||||
"""
|
||||
def __init__(self,
|
||||
Label,
|
||||
XY,
|
||||
WH,
|
||||
BackgroundColor = "Yellow",
|
||||
TextColor = "Black",
|
||||
InForeground = False,
|
||||
IsVisible = True):
|
||||
XY = N.asarray(XY, N.float).reshape(2,)
|
||||
WH = N.asarray(WH, N.float).reshape(2,)
|
||||
Label = FC.ScaledText(Label,
|
||||
XY,
|
||||
Size = WH[1] / 2.0,
|
||||
Color = TextColor,
|
||||
Position = 'cc',
|
||||
)
|
||||
self.Ellipse = FC.Ellipse( (XY - WH/2.0),
|
||||
WH,
|
||||
FillColor = BackgroundColor,
|
||||
LineStyle = None,
|
||||
)
|
||||
FC.Group.__init__(self, [self.Ellipse, Label], InForeground, IsVisible)
|
||||
|
||||
def GetConnectPoint(self):
|
||||
return self.BoundingBox.Center
|
||||
|
||||
|
||||
class MovingText(FC.ScaledText, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
ScaledBitmap Object that can be moved
|
||||
"""
|
||||
## All we need to do is is inherit from:
|
||||
## ScaledBitmap, MovingObjectMixin and ConnectorObjectMixin
|
||||
pass
|
||||
|
||||
class MovingTextBox(FC.ScaledTextBox, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
ScaledBitmap Object that can be moved
|
||||
"""
|
||||
## All we need to do is is inherit from:
|
||||
## ScaledBitmap, MovingObjectMixin and ConnectorObjectMixin
|
||||
pass
|
||||
|
||||
class ConnectorLine(FC.LineOnlyMixin, FC.DrawObject,):
|
||||
"""
|
||||
|
||||
A Line that connects two objects -- it uses the objects to get its coordinates
|
||||
The objects must have a GetConnectPoint() method.
|
||||
|
||||
"""
|
||||
##fixme: this should be added to the Main FloatCanvas Objects some day.
|
||||
def __init__(self,
|
||||
Object1,
|
||||
Object2,
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 1,
|
||||
InForeground = False):
|
||||
FC.DrawObject.__init__(self, InForeground)
|
||||
|
||||
self.Object1 = Object1
|
||||
self.Object2 = Object2
|
||||
self.LineColor = LineColor
|
||||
self.LineStyle = LineStyle
|
||||
self.LineWidth = LineWidth
|
||||
|
||||
self.CalcBoundingBox()
|
||||
self.SetPen(LineColor,LineStyle,LineWidth)
|
||||
|
||||
self.HitLineWidth = max(LineWidth,self.MinHitLineWidth)
|
||||
|
||||
def CalcBoundingBox(self):
|
||||
self.BoundingBox = BBox.fromPoints((self.Object1.GetConnectPoint(),
|
||||
self.Object2.GetConnectPoint()) )
|
||||
if self._Canvas:
|
||||
self._Canvas.BoundingBoxDirty = True
|
||||
|
||||
|
||||
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
|
||||
Points = N.array( (self.Object1.GetConnectPoint(),
|
||||
self.Object2.GetConnectPoint()) )
|
||||
Points = WorldToPixel(Points)
|
||||
dc.SetPen(self.Pen)
|
||||
dc.DrawLines(Points)
|
||||
if HTdc and self.HitAble:
|
||||
HTdc.SetPen(self.HitPen)
|
||||
HTdc.DrawLines(Points)
|
||||
|
||||
|
||||
class TriangleShape1(FC.Polygon, MovingObjectMixin):
|
||||
|
||||
def __init__(self, XY, L):
|
||||
|
||||
"""
|
||||
An equilateral triangle object
|
||||
XY is the middle of the triangle
|
||||
L is the length of one side of the Triangle
|
||||
"""
|
||||
|
||||
XY = N.asarray(XY)
|
||||
XY.shape = (2,)
|
||||
|
||||
Points = self.CompPoints(XY, L)
|
||||
|
||||
FC.Polygon.__init__(self, Points,
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 2,
|
||||
FillColor = "Red",
|
||||
FillStyle = "Solid")
|
||||
## Override the default OutlinePoints
|
||||
def GetOutlinePoints(self):
|
||||
return self.Points
|
||||
|
||||
def CompPoints(self, XY, L):
|
||||
c = L/ N.sqrt(3)
|
||||
|
||||
Points = N.array(((0, c),
|
||||
( L/2.0, -c/2.0),
|
||||
(-L/2.0, -c/2.0)),
|
||||
N.float_)
|
||||
|
||||
Points += XY
|
||||
return Points
|
||||
|
||||
### Tree Utilities
|
||||
### And some hard coded data...
|
||||
|
||||
class TreeNode:
|
||||
dx = 15
|
||||
dy = 4
|
||||
def __init__(self, name, Children = []):
|
||||
self.Name = name
|
||||
#self.parent = None -- Is this needed?
|
||||
self.Children = Children
|
||||
self.Point = None # The coords of the node.
|
||||
|
||||
def __str__(self):
|
||||
return "TreeNode: %s"%self.Name
|
||||
__repr__ = __str__
|
||||
|
||||
|
||||
## Build Tree:
|
||||
leaves = [TreeNode(name) for name in ["Assistant VP 1","Assistant VP 2","Assistant VP 3"] ]
|
||||
VP1 = TreeNode("VP1", Children = leaves)
|
||||
VP2 = TreeNode("VP2")
|
||||
|
||||
CEO = TreeNode("CEO", [VP1, VP2])
|
||||
Father = TreeNode("Father", [TreeNode("Daughter"), TreeNode("Son")])
|
||||
elements = TreeNode("Root", [CEO, Father])
|
||||
|
||||
def LayoutTree(root, x, y, level):
|
||||
NumNodes = len(root.Children)
|
||||
root.Point = (x,y)
|
||||
x += root.dx
|
||||
y += (root.dy * level * (NumNodes-1) / 2.0)
|
||||
for node in root.Children:
|
||||
LayoutTree(node, x, y, level-1)
|
||||
y -= root.dy * level
|
||||
|
||||
def TraverseTree(root, func):
|
||||
func(root)
|
||||
for child in (root.Children):
|
||||
TraverseTree(child, func)
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A simple frame used for the Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "White",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
|
||||
Canvas.Bind(FC.EVT_MOTION, self.OnMove )
|
||||
Canvas.Bind(FC.EVT_LEFT_UP, self.OnLeftUp )
|
||||
|
||||
self.elements = elements
|
||||
LayoutTree(self.elements, 0, 0, 3)
|
||||
self.AddTree(self.elements)
|
||||
|
||||
|
||||
self.Show(True)
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
self.MoveObject = None
|
||||
self.Moving = False
|
||||
|
||||
return None
|
||||
|
||||
def AddTree(self, root):
|
||||
Nodes = []
|
||||
Connectors = []
|
||||
EllipseW = 15
|
||||
EllipseH = 4
|
||||
def CreateObject(node):
|
||||
if node.Children:
|
||||
object = NodeObject(node.Name,
|
||||
node.Point,
|
||||
(15, 4),
|
||||
BackgroundColor = "Yellow",
|
||||
TextColor = "Black",
|
||||
)
|
||||
else:
|
||||
object = MovingTextBox(node.Name,
|
||||
node.Point,
|
||||
2.0,
|
||||
BackgroundColor = "White",
|
||||
Color = "Black",
|
||||
Position = "cl",
|
||||
PadSize = 1
|
||||
)
|
||||
node.DrawObject = object
|
||||
Nodes.append(object)
|
||||
def AddConnectors(node):
|
||||
for child in node.Children:
|
||||
Connector = ConnectorLine(node.DrawObject, child.DrawObject, LineWidth=3, LineColor="Red")
|
||||
Connectors.append(Connector)
|
||||
## create the Objects
|
||||
TraverseTree(root, CreateObject)
|
||||
## create the Connectors
|
||||
TraverseTree(root, AddConnectors)
|
||||
## Add the conenctos to the Canvas first, so they are undernieth the nodes
|
||||
self.Canvas.AddObjects(Connectors)
|
||||
## now add the nodes
|
||||
self.Canvas.AddObjects(Nodes)
|
||||
# Now bind the Nodes -- DrawObjects must be Added to a Canvas before they can be bound.
|
||||
for node in Nodes:
|
||||
#pass
|
||||
node.Bind(FC.EVT_FC_LEFT_DOWN, self.ObjectHit)
|
||||
|
||||
|
||||
|
||||
def ObjectHit(self, object):
|
||||
if not self.Moving:
|
||||
self.Moving = True
|
||||
self.StartPoint = object.HitCoordsPixel
|
||||
self.StartObject = self.Canvas.WorldToPixel(object.GetOutlinePoints())
|
||||
self.MoveObject = None
|
||||
self.MovingObject = object
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
and moves the object it is clicked on
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.4f, %.4f"%tuple(event.Coords))
|
||||
|
||||
if self.Moving:
|
||||
dxy = event.GetPosition() - self.StartPoint
|
||||
# Draw the Moving Object:
|
||||
dc = wx.ClientDC(self.Canvas)
|
||||
dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
|
||||
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||
dc.SetLogicalFunction(wx.XOR)
|
||||
if self.MoveObject is not None:
|
||||
dc.DrawPolygon(self.MoveObject)
|
||||
self.MoveObject = self.StartObject + dxy
|
||||
dc.DrawPolygon(self.MoveObject)
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
if self.Moving:
|
||||
self.Moving = False
|
||||
if self.MoveObject is not None:
|
||||
dxy = event.GetPosition() - self.StartPoint
|
||||
dxy = self.Canvas.ScalePixelToWorld(dxy)
|
||||
self.MovingObject.Move(dxy)
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
app = wx.PySimpleApp(0)
|
||||
DrawFrame(None, -1, "FloatCanvas Tree Demo App", wx.DefaultPosition, (700,700) )
|
||||
app.MainLoop()
|
100
samples/floatcanvas/ScaleDemo.py
Normal file
100
samples/floatcanvas/ScaleDemo.py
Normal file
@@ -0,0 +1,100 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
This demonstrates how to use FloatCanvas with a coordinate system where
|
||||
X and Y have different scales. In the example, a user had:
|
||||
|
||||
X data in the range: 50e-6 to 2000e-6
|
||||
Y data in the range: 0 to 50000
|
||||
|
||||
-chb
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
|
||||
import numpy as N
|
||||
|
||||
def YScaleFun(center):
|
||||
"""
|
||||
function that returns a scaling vector to scale y data to same range as x data
|
||||
|
||||
"""
|
||||
# center gets ignored in this case
|
||||
return N.array((5e7, 1), N.float)
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = YScaleFun,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
Point = N.array((50e-6, 0))
|
||||
Size = N.array(( (2000e-6 - 5e-6), 50000))
|
||||
Box = Canvas.AddRectangle(Point,
|
||||
Size,
|
||||
FillColor = "blue"
|
||||
)
|
||||
|
||||
Canvas.AddText("%s"%(Point,), Point, Position="cr")
|
||||
Canvas.AddPoint(Point, Diameter=3, Color = "red")
|
||||
|
||||
|
||||
Point = Point + Size
|
||||
Canvas.AddText("%s"%(Point,), Point, Position="cl")
|
||||
Canvas.AddPoint(Point, Diameter=3, Color = "red")
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
"""
|
||||
self.SetStatusText("%.2g, %.2g"%tuple(event.Coords))
|
||||
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
83
samples/floatcanvas/ScaledBitmap2Demo.py
Executable file
83
samples/floatcanvas/ScaledBitmap2Demo.py
Executable file
@@ -0,0 +1,83 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
This demo shows how to use a ScaledBitmap2 (which is like a scaled bitmap,
|
||||
but uses memory more efficiently for large images and high zoom levels.)
|
||||
|
||||
|
||||
"""
|
||||
|
||||
## Set a path to an Image file here:
|
||||
ImageFile = "white_tank.jpg"
|
||||
|
||||
|
||||
import wx
|
||||
import random
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,
|
||||
ProjectionFun = None,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
Canvas.MaxScale=20 # sets the maximum zoom level
|
||||
self.Canvas = Canvas
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
|
||||
# create the image:
|
||||
image = wx.Image(ImageFile)
|
||||
self.width, self.height = image.GetSize()
|
||||
img = FloatCanvas.ScaledBitmap2( image,
|
||||
(0,0),
|
||||
Height=image.GetHeight(),
|
||||
Position = 'tl',
|
||||
)
|
||||
Canvas.AddObject(img)
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.SetStatusText("%i, %i"%tuple(event.Coords))
|
||||
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
72
samples/floatcanvas/SplitterWindow.py
Normal file
72
samples/floatcanvas/SplitterWindow.py
Normal file
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
class MyFrame(wx.Frame):
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
#Adding the SplitterWindow
|
||||
splitter = wx.SplitterWindow(self, style=wx.SP_LIVE_UPDATE|wx.SP_3D, size = (800,400))
|
||||
|
||||
# add the left Panel
|
||||
panel1 = wx.Panel(splitter)
|
||||
panel1.SetBackgroundColour(wx.RED)
|
||||
|
||||
# add the Canvas
|
||||
panel2 = NavCanvas.NavCanvas(splitter,
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
)
|
||||
Canvas = panel2.Canvas
|
||||
|
||||
# put something on the Canvas
|
||||
Point = (15,10)
|
||||
Canvas.AddScaledTextBox("A Two Line\nString",
|
||||
Point,
|
||||
2,
|
||||
Color = "Black",
|
||||
BackgroundColor = None,
|
||||
LineColor = "Red",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 1,
|
||||
Width = None,
|
||||
PadSize = 5,
|
||||
Family = wx.ROMAN,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'br',
|
||||
Alignment = "left",
|
||||
InForeground = False)
|
||||
|
||||
wx.CallAfter(Canvas.ZoomToBB)
|
||||
|
||||
# set up the Splitter
|
||||
sash_Position = 300
|
||||
splitter.SplitVertically(panel1, panel2, sash_Position)
|
||||
splitter.SetSashSize(10)
|
||||
min_Pan_size = 40
|
||||
splitter.SetMinimumPaneSize(min_Pan_size)
|
||||
|
||||
self.Fit()
|
||||
|
||||
|
||||
class MyApp(wx.App):
|
||||
def OnInit(self):
|
||||
frame = MyFrame(None, title='splitter test')
|
||||
frame.Show(True)
|
||||
self.SetTopWindow(frame)
|
||||
return True
|
||||
|
||||
app = MyApp(0)
|
||||
app.MainLoop()
|
67
samples/floatcanvas/SubClassNavCanvas.py
Executable file
67
samples/floatcanvas/SubClassNavCanvas.py
Executable file
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
A simple example of sub-classing the Navcanvas
|
||||
|
||||
-- an alternative to simply putting a NavCanvas on your yoru oen panle or whatever
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the Demo
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
self.CreateStatusBar()
|
||||
|
||||
panel = NavPanel(self)
|
||||
|
||||
self.Show()
|
||||
|
||||
class NavPanel(NavCanvas.NavCanvas):
|
||||
"""
|
||||
a subclass of NavCAnvas -- with some specific drawing code
|
||||
"""
|
||||
def __init__(self, parent):
|
||||
NavCanvas.NavCanvas.__init__(self,
|
||||
parent,
|
||||
ProjectionFun = None,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
)
|
||||
|
||||
self.parent_frame = parent
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
# create the image:
|
||||
self.Canvas.AddPolygon( ( (2,3),
|
||||
(5,6),
|
||||
(7,1), ),
|
||||
FillColor = "red",
|
||||
)
|
||||
|
||||
|
||||
wx.CallAfter(self.Canvas.ZoomToBB) # so it will get called after everything is created and sized
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
"""
|
||||
self.parent_frame.SetStatusText("%f, %f"%tuple(event.Coords))
|
||||
pass
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
185
samples/floatcanvas/TestSpline.py
Executable file
185
samples/floatcanvas/TestSpline.py
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
|
||||
"""
|
||||
This is a very small app using the FloatCanvas
|
||||
|
||||
It tests the Spline object, including how you can put points together to
|
||||
create an object with curves and square corners.
|
||||
|
||||
|
||||
"""
|
||||
import wx
|
||||
|
||||
#### import local version:
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas
|
||||
#from floatcanvas import FloatCanvas as FC
|
||||
|
||||
from wx.lib.floatcanvas import FloatCanvas as FC
|
||||
from wx.lib.floatcanvas import NavCanvas
|
||||
|
||||
class Spline(FC.Line):
|
||||
def __init__(self, *args, **kwargs):
|
||||
FC.Line.__init__(self, *args, **kwargs)
|
||||
|
||||
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
|
||||
Points = WorldToPixel(self.Points)
|
||||
dc.SetPen(self.Pen)
|
||||
dc.DrawSpline(Points)
|
||||
if HTdc and self.HitAble:
|
||||
HTdc.SetPen(self.HitPen)
|
||||
HTdc.DrawSpline(Points)
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas
|
||||
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
## Set up the MenuBar
|
||||
MenuBar = wx.MenuBar()
|
||||
|
||||
file_menu = wx.Menu()
|
||||
item = file_menu.Append(-1, "&Close","Close this frame")
|
||||
self.Bind(wx.EVT_MENU, self.OnQuit, item)
|
||||
MenuBar.Append(file_menu, "&File")
|
||||
|
||||
help_menu = wx.Menu()
|
||||
item = help_menu.Append(-1, "&About",
|
||||
"More information About this program")
|
||||
self.Bind(wx.EVT_MENU, self.OnAbout, item)
|
||||
MenuBar.Append(help_menu, "&Help")
|
||||
|
||||
self.SetMenuBar(MenuBar)
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
self.Canvas = NavCanvas.NavCanvas(self,
|
||||
BackgroundColor = "White",
|
||||
).Canvas
|
||||
|
||||
self.Canvas.Bind(FC.EVT_MOTION, self.OnMove)
|
||||
|
||||
wx.EVT_CLOSE(self, self.OnCloseWindow)
|
||||
|
||||
self.DrawTest()
|
||||
self.Show()
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
def OnAbout(self, event):
|
||||
print "OnAbout called"
|
||||
|
||||
dlg = wx.MessageDialog(self, "This is a small program to demonstrate\n"
|
||||
"the use of the FloatCanvas\n",
|
||||
"About Me", wx.OK | wx.ICON_INFORMATION)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
def OnQuit(self,event):
|
||||
self.Close(True)
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
def DrawTest(self,event=None):
|
||||
wx.GetApp().Yield()
|
||||
|
||||
Canvas = self.Canvas
|
||||
|
||||
Points = [(0, 0),
|
||||
(200,0),
|
||||
(200,0),
|
||||
(200,0),
|
||||
(200,15),
|
||||
(185,15),
|
||||
(119,15),
|
||||
(104,15),
|
||||
(104,30),
|
||||
(104,265),
|
||||
(104,280),
|
||||
(119,280),
|
||||
(185,280),
|
||||
(200,280),
|
||||
(200,295),
|
||||
(200,295),
|
||||
(200,295),
|
||||
(0, 295),
|
||||
(0, 295),
|
||||
(0, 295),
|
||||
(0, 280),
|
||||
(15, 280),
|
||||
(81, 280),
|
||||
(96, 280),
|
||||
(96, 265),
|
||||
(96, 30),
|
||||
(96, 15),
|
||||
(81, 15),
|
||||
(15, 15),
|
||||
(0, 15),
|
||||
(0, 0),
|
||||
]
|
||||
|
||||
Canvas.ClearAll()
|
||||
|
||||
MyLine = FC.Spline(Points,
|
||||
LineWidth = 3,
|
||||
LineColor = "Blue")
|
||||
|
||||
Canvas.AddObject(MyLine)
|
||||
Canvas.AddPointSet(Points,
|
||||
Color = "Red",
|
||||
Diameter = 4,
|
||||
)
|
||||
|
||||
## A regular old spline:
|
||||
Points = [(-30, 260),
|
||||
(-10, 130),
|
||||
(70, 185),
|
||||
(160,60),
|
||||
]
|
||||
|
||||
Canvas.AddSpline(Points,
|
||||
LineWidth = 5,
|
||||
LineColor = "Purple")
|
||||
|
||||
class DemoApp(wx.App):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.App.__init__(self, *args, **kwargs)
|
||||
|
||||
def OnInit(self):
|
||||
frame = DrawFrame(None, title="FloatCanvas Spline Demo", size = (700,700))
|
||||
|
||||
self.SetTopWindow(frame)
|
||||
return True
|
||||
|
||||
app = DemoApp(False)# put in True if you want output to go to it's own window.
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
302
samples/floatcanvas/TextBox.py
Executable file
302
samples/floatcanvas/TextBox.py
Executable file
@@ -0,0 +1,302 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
A test and demo of the features of the ScaledTextBox
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import the local version
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
import numpy as N
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,parent, id,title,position,size):
|
||||
wx.Frame.__init__(self,parent, id,title,position, size)
|
||||
|
||||
# Add the Canvas
|
||||
self.CreateStatusBar()
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
Point = (45,40)
|
||||
Box = Canvas.AddScaledTextBox("A Two Line\nString",
|
||||
Point,
|
||||
2,
|
||||
Color = "Black",
|
||||
BackgroundColor = None,
|
||||
LineColor = "Red",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 1,
|
||||
Width = None,
|
||||
PadSize = 5,
|
||||
Family = wx.ROMAN,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'br',
|
||||
Alignment = "left",
|
||||
InForeground = False)
|
||||
|
||||
# All defaults
|
||||
Box = Canvas.AddScaledTextBox("A Two Line\nString",
|
||||
Point,
|
||||
2)
|
||||
|
||||
Box = Canvas.AddScaledTextBox("A Two Line\nString",
|
||||
Point,
|
||||
2,
|
||||
BackgroundColor = "Yellow",
|
||||
LineColor = "Red",
|
||||
LineStyle = "Solid",
|
||||
PadSize = 5,
|
||||
Family = wx.TELETYPE,
|
||||
Position = 'bl')
|
||||
|
||||
Box = Canvas.AddScaledTextBox("A Two Line\nString",
|
||||
Point,
|
||||
2,
|
||||
BackgroundColor = "Yellow",
|
||||
LineColor = "Red",
|
||||
LineStyle = "Solid",
|
||||
PadSize = 5,
|
||||
Family = wx.TELETYPE,
|
||||
Position = 'tr')
|
||||
|
||||
|
||||
|
||||
|
||||
Box.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.binding2)
|
||||
|
||||
Canvas.AddPoint(Point, Diameter = 4)
|
||||
|
||||
Point = (45,15)
|
||||
Box = Canvas.AddScaledTextBox("A Two Line\nString",
|
||||
Point,
|
||||
2,
|
||||
Color = "Black",
|
||||
BackgroundColor = 'Red',
|
||||
LineColor = "Blue",
|
||||
LineStyle = "LongDash",
|
||||
LineWidth = 2,
|
||||
Width = None,
|
||||
PadSize = 5,
|
||||
Family = wx.TELETYPE,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'cr',
|
||||
Alignment = "left",
|
||||
InForeground = False)
|
||||
|
||||
Box = Canvas.AddScaledTextBox("A Two Line\nString",
|
||||
Point,
|
||||
1.5,
|
||||
Color = "Black",
|
||||
BackgroundColor = 'Red',
|
||||
LineColor = "Blue",
|
||||
LineStyle = "LongDash",
|
||||
LineWidth = 2,
|
||||
Width = None,
|
||||
PadSize = 5,
|
||||
Family = wx.TELETYPE,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'cl',
|
||||
Alignment = "left",
|
||||
InForeground = False)
|
||||
|
||||
Canvas.AddPoint(Point, Diameter = 4)
|
||||
|
||||
Point = (45,-10)
|
||||
Box = Canvas.AddScaledTextBox("A Two Line\nString",
|
||||
Point,
|
||||
2,
|
||||
Color = "Black",
|
||||
BackgroundColor = 'Red',
|
||||
LineColor = "Blue",
|
||||
LineStyle = "LongDash",
|
||||
LineWidth = 2,
|
||||
Width = None,
|
||||
PadSize = 3,
|
||||
Family = wx.TELETYPE,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'tc',
|
||||
Alignment = "left",
|
||||
InForeground = False)
|
||||
|
||||
Box = Canvas.AddScaledTextBox("A three\nLine\nString",
|
||||
Point,
|
||||
1.5,
|
||||
Color = "Black",
|
||||
BackgroundColor = 'Red',
|
||||
LineColor = "Blue",
|
||||
LineStyle = "LongDash",
|
||||
LineWidth = 2,
|
||||
Width = None,
|
||||
PadSize = 0.5,
|
||||
Family = wx.TELETYPE,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'bc',
|
||||
Alignment = "left",
|
||||
InForeground = False)
|
||||
|
||||
|
||||
Canvas.AddPoint(Point, Diameter = 4)
|
||||
|
||||
Box = Canvas.AddScaledTextBox("Some Auto Wrapped Text. There is enough to do.",
|
||||
(80,40),
|
||||
2,
|
||||
BackgroundColor = 'White',
|
||||
LineWidth = 2,
|
||||
Width = 20,
|
||||
PadSize = 0.5,
|
||||
Family = wx.TELETYPE,
|
||||
)
|
||||
|
||||
Box = Canvas.AddScaledTextBox("Some more auto wrapped text. Wrapped to a different width and right aligned.\n\nThis is another paragraph.",
|
||||
(80,20),
|
||||
2,
|
||||
BackgroundColor = 'White',
|
||||
LineWidth = 2,
|
||||
Width = 40,
|
||||
PadSize = 0.5,
|
||||
Family = wx.ROMAN,
|
||||
Alignment = "right"
|
||||
)
|
||||
Point = N.array((100, -20), N.float_)
|
||||
Box = Canvas.AddScaledTextBox("Here is even more auto wrapped text. This time the line spacing is set to 0.8. \n\nThe Padding is set to 0.",
|
||||
Point,
|
||||
Size = 3,
|
||||
BackgroundColor = 'White',
|
||||
LineWidth = 1,
|
||||
Width = 40,
|
||||
PadSize = 0.0,
|
||||
Family = wx.ROMAN,
|
||||
Position = "cc",
|
||||
LineSpacing = 0.8
|
||||
)
|
||||
Canvas.AddPoint(Point, "Red", 2)
|
||||
|
||||
Point = N.array((0, -40), N.float_)
|
||||
# Point = N.array((0, 0), N.float_)
|
||||
for Position in ["tl", "bl", "tr", "br"]:
|
||||
# for Position in ["br"]:
|
||||
Box = Canvas.AddScaledTextBox("Here is a\nfour liner\nanother line\nPosition=%s"%Position,
|
||||
Point,
|
||||
Size = 4,
|
||||
Color = "Red",
|
||||
BackgroundColor = None,#'LightBlue',
|
||||
LineWidth = 1,
|
||||
LineColor = "White",
|
||||
Width = None,
|
||||
PadSize = 2,
|
||||
Family = wx.ROMAN,
|
||||
Position = Position,
|
||||
LineSpacing = 0.8
|
||||
)
|
||||
Canvas.AddPoint(Point, "Red", 4)
|
||||
|
||||
Point = N.array((-20, 60), N.float_)
|
||||
Box = Canvas.AddScaledTextBox("Here is some\ncentered\ntext",
|
||||
Point,
|
||||
Size = 4,
|
||||
Color = "Red",
|
||||
BackgroundColor = 'LightBlue',
|
||||
LineWidth = 1,
|
||||
LineColor = "White",
|
||||
Width = None,
|
||||
PadSize = 2,
|
||||
Family = wx.ROMAN,
|
||||
Position = "tl",
|
||||
Alignment = "center",
|
||||
LineSpacing = 0.8
|
||||
)
|
||||
|
||||
Point = N.array((-20, 20), N.float_)
|
||||
Box = Canvas.AddScaledTextBox("Here is some\nright aligned\ntext",
|
||||
Point,
|
||||
Size = 4,
|
||||
Color = "Red",
|
||||
BackgroundColor = 'LightBlue',
|
||||
LineColor = None,
|
||||
Width = None,
|
||||
PadSize = 2,
|
||||
Family = wx.ROMAN,
|
||||
Position = "tl",
|
||||
Alignment = "right",
|
||||
LineSpacing = 0.8
|
||||
)
|
||||
|
||||
Point = N.array((100, -60), N.float_)
|
||||
Box = Canvas.AddScaledTextBox("Here is some auto wrapped text. This time it is centered, rather than right aligned.\n\nThe Padding is set to 2.",
|
||||
Point,
|
||||
Size = 3,
|
||||
BackgroundColor = 'White',
|
||||
LineWidth = 1,
|
||||
Width = 40,
|
||||
PadSize = 2.0,
|
||||
Family = wx.ROMAN,
|
||||
Position = "cc",
|
||||
LineSpacing = 0.8,
|
||||
Alignment = 'center',
|
||||
)
|
||||
|
||||
|
||||
self.Show(True)
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
return None
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
|
||||
def binding(self, event):
|
||||
print "I'm the Rectangle"
|
||||
|
||||
def binding2(self, event):
|
||||
print "I'm the TextBox"
|
||||
|
||||
app = wx.PySimpleApp()
|
||||
DrawFrame(None, -1, "FloatCanvas Demo App", wx.DefaultPosition, (700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
228
samples/floatcanvas/TextBox2.py
Executable file
228
samples/floatcanvas/TextBox2.py
Executable file
@@ -0,0 +1,228 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
|
||||
"""
|
||||
A test and demo of the ScaledTextbox.
|
||||
|
||||
It also shows how one can use the Mouse to interact and change objects on a Canvas.
|
||||
|
||||
this really needs to be re-done with GUI-Modes.
|
||||
"""
|
||||
|
||||
|
||||
import wx
|
||||
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas, Resources
|
||||
|
||||
|
||||
import numpy as N
|
||||
|
||||
LongString = (
|
||||
"""This is a long string. It is a bunch of text. I am using it to test how the nifty wrapping text box works when you want to re-size.
|
||||
|
||||
This is another paragraph. I am trying to make it long enough to wrap a reasonable amount. Let's see how it works.
|
||||
|
||||
|
||||
This is a way to start a paragraph with indenting
|
||||
"""
|
||||
)
|
||||
|
||||
##LongString = (
|
||||
##""" This is a not so long string
|
||||
##Another line""")
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self,parent, id,title,position,size):
|
||||
wx.Frame.__init__(self,parent, id,title,position, size)
|
||||
|
||||
self.CreateStatusBar()
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
FloatCanvas.EVT_LEFT_UP(self.Canvas, self.OnLeftUp )
|
||||
FloatCanvas.EVT_LEFT_DOWN(self.Canvas, self.OnLeftDown)
|
||||
|
||||
Point = N.array((0,0), N.float)
|
||||
|
||||
|
||||
|
||||
Canvas.AddCircle(Point,
|
||||
|
||||
Diameter=40,
|
||||
|
||||
FillColor="Red",
|
||||
|
||||
LineStyle=None,
|
||||
|
||||
)
|
||||
|
||||
|
||||
Width = 300
|
||||
self.Box = Canvas.AddScaledTextBox(LongString,
|
||||
Point,
|
||||
10,
|
||||
Color = "Black",
|
||||
BackgroundColor = 'White',
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 2,
|
||||
Width = Width,
|
||||
PadSize = 10.0,
|
||||
Family = wx.ROMAN,
|
||||
#Family = wx.TELETYPE,
|
||||
Style = wx.NORMAL,
|
||||
Weight = wx.NORMAL,
|
||||
Underlined = False,
|
||||
Position = 'tl',
|
||||
LineSpacing = 0.8,
|
||||
Alignment = "left",
|
||||
#Alignment = "center",
|
||||
#Alignment = "right",
|
||||
InForeground = False)
|
||||
|
||||
|
||||
self.Handle1 = Canvas.AddBitmap(Resources.getMoveCursorBitmap(), Point, Position='cc')
|
||||
self.Handle2a = Canvas.AddBitmap(Resources.getMoveRLCursorBitmap(), Point, Position='cc')
|
||||
self.Handle2b = Canvas.AddBitmap(Resources.getMoveRLCursorBitmap(), Point, Position='cc')
|
||||
|
||||
self.SetHandles()
|
||||
|
||||
self.Handle1.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.Handle1Hit)
|
||||
self.Handle2a.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.Handle2Hit)
|
||||
self.Handle2b.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.Handle2Hit)
|
||||
|
||||
|
||||
self.Show(True)
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
self.Resizing = False
|
||||
self.ResizeRect = None
|
||||
self.Moving = False
|
||||
|
||||
return None
|
||||
|
||||
def Handle1Hit(self, object):
|
||||
if not self.Moving:
|
||||
self.Moving = True
|
||||
self.StartPoint = object.HitCoordsPixel
|
||||
|
||||
def Handle2Hit(self,event=None):
|
||||
if not self.Resizing:
|
||||
self.Resizing = True
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
|
||||
And moves a point if there is one
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.4f, %.4f"%tuple(event.Coords))
|
||||
|
||||
if self.Resizing:
|
||||
((xy),(wh)) = self.Box.GetBoxRect()
|
||||
(xp, yp) = self.Canvas.WorldToPixel(xy)
|
||||
(wp, hp) = self.Canvas.ScaleWorldToPixel(wh)
|
||||
hp = -hp
|
||||
Corner = event.GetPosition()
|
||||
if self.Box.Position[1] in 'lc':
|
||||
wp = max(20, Corner[0]-xp) # don't allow the box to get narrower than 20 pixels
|
||||
elif self.Box.Position[1] in 'r':
|
||||
DeltaX = Corner[0]-xp
|
||||
xp += DeltaX
|
||||
wp -= DeltaX
|
||||
# draw the RB box
|
||||
dc = wx.ClientDC(self.Canvas)
|
||||
dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
|
||||
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||
dc.SetLogicalFunction(wx.XOR)
|
||||
if self.ResizeRect:
|
||||
dc.DrawRectangle(*self.ResizeRect)
|
||||
self.ResizeRect = (xp,yp,wp,hp)
|
||||
dc.DrawRectangle(*self.ResizeRect)
|
||||
elif self.Moving:
|
||||
dxy = event.GetPosition() - self.StartPoint
|
||||
((xy),(wh)) = self.Box.GetBoxRect()
|
||||
xp, yp = self.Canvas.WorldToPixel(xy) + dxy
|
||||
(wp, hp) = self.Canvas.ScaleWorldToPixel(wh)
|
||||
hp = -hp
|
||||
# draw the RB box
|
||||
dc = wx.ClientDC(self.Canvas)
|
||||
dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
|
||||
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||
dc.SetLogicalFunction(wx.XOR)
|
||||
if self.ResizeRect:
|
||||
dc.DrawRectangle(*self.ResizeRect)
|
||||
self.ResizeRect = (xp,yp,wp,hp)
|
||||
dc.DrawRectangle(*self.ResizeRect)
|
||||
|
||||
def OnLeftDown(self, event):
|
||||
pass
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
if self.Resizing:
|
||||
self.Resizing = False
|
||||
if self.ResizeRect:
|
||||
Point = self.Canvas.PixelToWorld(self.ResizeRect[:2])
|
||||
W, H = self.Canvas.ScalePixelToWorld(self.ResizeRect[2:4])
|
||||
self.ResizeRect = None
|
||||
self.Box.ReWrap(W)
|
||||
self.SetHandles()
|
||||
elif self.Moving:
|
||||
self.Moving = False
|
||||
if self.ResizeRect:
|
||||
dxy = event.GetPosition() - self.StartPoint
|
||||
dxy = self.Canvas.ScalePixelToWorld(dxy)
|
||||
self.Box.Move(dxy)
|
||||
self.ResizeRect = None
|
||||
# self.Box.SetPoint(Point1)
|
||||
self.SetHandles()
|
||||
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
def SetHandles(self):
|
||||
((x,y),(w,h)) = self.Box.GetBoxRect()
|
||||
if self.Box.Position[1] in "lc":
|
||||
x += w
|
||||
y -= h/3
|
||||
self.Handle2a.SetPoint((x,y))
|
||||
y -= h/3
|
||||
self.Handle2b.SetPoint((x,y))
|
||||
self.Handle1.SetPoint(self.Box.XY)
|
||||
|
||||
|
||||
app = wx.PySimpleApp()
|
||||
DrawFrame(None, -1, "FloatCanvas TextBox Test App", wx.DefaultPosition, (700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
38
samples/floatcanvas/Tiny.bna
Normal file
38
samples/floatcanvas/Tiny.bna
Normal file
@@ -0,0 +1,38 @@
|
||||
"Another Name","Another Type", 19
|
||||
-81.531753540039,31.134635925293
|
||||
-81.531150817871,31.134529113769
|
||||
-81.530662536621,31.134353637695
|
||||
-81.530502319336,31.134126663208
|
||||
-81.530685424805,31.133970260620
|
||||
-81.531112670898,31.134040832519
|
||||
-81.532104492188,31.134008407593
|
||||
-81.532485961914,31.134220123291
|
||||
-81.533134460449,31.134204864502
|
||||
-81.534004211426,31.134277343750
|
||||
-81.534667968750,31.134349822998
|
||||
-81.534912109375,31.134525299072
|
||||
-81.534667968750,31.134855270386
|
||||
-81.534248352051,31.134975433350
|
||||
-81.533943176270,31.135166168213
|
||||
-81.533760070801,31.135200500488
|
||||
-81.532928466797,31.135110855102
|
||||
-81.532447814941,31.134794235229
|
||||
-81.532341003418,31.134586334229
|
||||
"A third 'name'","6", 7
|
||||
-81.522369384766,31.122062683106
|
||||
-81.522109985352,31.121908187866
|
||||
-81.522010803223,31.121685028076
|
||||
-81.522254943848,31.121658325195
|
||||
-81.522483825684,31.121797561646
|
||||
-81.522514343262,31.122062683106
|
||||
-81.522369384766,31.122062683106
|
||||
"8223","1", 9
|
||||
-81.523277282715,31.122261047363
|
||||
-81.522987365723,31.121982574463
|
||||
-81.523200988770,31.121547698975
|
||||
-81.523361206055,31.121408462524
|
||||
-81.523818969727,31.121549606323
|
||||
-81.524078369141,31.121662139893
|
||||
-81.524009704590,31.121944427490
|
||||
-81.523925781250,31.122068405151
|
||||
-81.523277282715,31.122261047363
|
371
samples/floatcanvas/Tree.py
Executable file
371
samples/floatcanvas/Tree.py
Executable file
@@ -0,0 +1,371 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
This is a demo, showing how to work with a "tree" structure
|
||||
|
||||
It demonstrates moving objects around, etc, etc.
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
#ver = 'local'
|
||||
2ver = 'installed'
|
||||
|
||||
if ver == 'installed': ## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, Resources
|
||||
from wx.lib.floatcanvas import FloatCanvas as FC
|
||||
from wx.lib.floatcanvas.Utilities import BBox
|
||||
print "using installed version:", wx.lib.floatcanvas.__version__
|
||||
elif ver == 'local':
|
||||
## import a local version
|
||||
import sys
|
||||
sys.path.append("..")
|
||||
from floatcanvas import NavCanvas, Resources
|
||||
from floatcanvas import FloatCanvas as FC
|
||||
from floatcanvas.Utilities import BBox
|
||||
|
||||
import numpy as N
|
||||
|
||||
## here we create some new mixins:
|
||||
## fixme: These really belong in floatcanvas package -- but I kind of want to clean it up some first
|
||||
|
||||
class MovingObjectMixin:
|
||||
"""
|
||||
Methods required for a Moving object
|
||||
|
||||
"""
|
||||
def GetOutlinePoints(self):
|
||||
"""
|
||||
Returns a set of points with which to draw the outline when moving the
|
||||
object.
|
||||
|
||||
Points are a NX2 array of (x,y) points in World coordinates.
|
||||
|
||||
|
||||
"""
|
||||
BB = self.BoundingBox
|
||||
OutlinePoints = N.array( ( (BB[0,0], BB[0,1]),
|
||||
(BB[0,0], BB[1,1]),
|
||||
(BB[1,0], BB[1,1]),
|
||||
(BB[1,0], BB[0,1]),
|
||||
)
|
||||
)
|
||||
|
||||
return OutlinePoints
|
||||
|
||||
class ConnectorObjectMixin:
|
||||
"""
|
||||
Mixin class for DrawObjects that can be connected with lines
|
||||
|
||||
Note that this version only works for Objects that have an "XY" attribute:
|
||||
that is, one that is derived from XHObjectMixin.
|
||||
|
||||
"""
|
||||
|
||||
def GetConnectPoint(self):
|
||||
return self.XY
|
||||
|
||||
class MovingBitmap(FC.ScaledBitmap, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
ScaledBitmap Object that can be moved
|
||||
"""
|
||||
## All we need to do is is inherit from:
|
||||
## ScaledBitmap, MovingObjectMixin and ConnectorObjectMixin
|
||||
pass
|
||||
|
||||
class MovingCircle(FC.Circle, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
ScaledBitmap Object that can be moved
|
||||
"""
|
||||
## All we need to do is is inherit from:
|
||||
## Circle MovingObjectMixin and ConnectorObjectMixin
|
||||
pass
|
||||
|
||||
|
||||
class MovingGroup(FC.Group, MovingObjectMixin, ConnectorObjectMixin):
|
||||
|
||||
def GetConnectPoint(self):
|
||||
return self.BoundingBox.Center
|
||||
|
||||
class NodeObject(FC.Group, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
A version of the moving group for nodes -- an ellipse with text on it.
|
||||
"""
|
||||
def __init__(self,
|
||||
Label,
|
||||
XY,
|
||||
WH,
|
||||
BackgroundColor = "Yellow",
|
||||
TextColor = "Black",
|
||||
InForeground = False,
|
||||
IsVisible = True):
|
||||
XY = N.asarray(XY, N.float).reshape(2,)
|
||||
WH = N.asarray(WH, N.float).reshape(2,)
|
||||
Label = FC.ScaledText(Label,
|
||||
XY,
|
||||
Size = WH[1] / 2.0,
|
||||
Color = TextColor,
|
||||
Position = 'cc',
|
||||
)
|
||||
self.Ellipse = FC.Ellipse( (XY - WH/2.0),
|
||||
WH,
|
||||
FillColor = BackgroundColor,
|
||||
LineStyle = None,
|
||||
)
|
||||
FC.Group.__init__(self, [self.Ellipse, Label], InForeground, IsVisible)
|
||||
|
||||
def GetConnectPoint(self):
|
||||
return self.BoundingBox.Center
|
||||
|
||||
|
||||
class MovingText(FC.ScaledText, MovingObjectMixin, ConnectorObjectMixin):
|
||||
"""
|
||||
ScaledBitmap Object that can be moved
|
||||
"""
|
||||
## All we need to do is is inherit from:
|
||||
## ScaledBitmap, MovingObjectMixin and ConnectorObjectMixin
|
||||
pass
|
||||
|
||||
class ConnectorLine(FC.LineOnlyMixin, FC.DrawObject,):
|
||||
"""
|
||||
|
||||
A Line that connects two objects -- it uses the objects to get its coordinates
|
||||
The objects must have a GetConnectPoint() method.
|
||||
|
||||
"""
|
||||
##fixme: this should be added to the Main FloatCanvas Objects some day.
|
||||
def __init__(self,
|
||||
Object1,
|
||||
Object2,
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 1,
|
||||
InForeground = False):
|
||||
FC.DrawObject.__init__(self, InForeground)
|
||||
|
||||
self.Object1 = Object1
|
||||
self.Object2 = Object2
|
||||
self.LineColor = LineColor
|
||||
self.LineStyle = LineStyle
|
||||
self.LineWidth = LineWidth
|
||||
|
||||
self.CalcBoundingBox()
|
||||
self.SetPen(LineColor,LineStyle,LineWidth)
|
||||
|
||||
self.HitLineWidth = max(LineWidth,self.MinHitLineWidth)
|
||||
|
||||
def CalcBoundingBox(self):
|
||||
self.BoundingBox = BBox.fromPoints((self.Object1.GetConnectPoint(),
|
||||
self.Object2.GetConnectPoint()) )
|
||||
if self._Canvas:
|
||||
self._Canvas.BoundingBoxDirty = True
|
||||
|
||||
|
||||
def _Draw(self, dc , WorldToPixel, ScaleWorldToPixel, HTdc=None):
|
||||
Points = N.array( (self.Object1.GetConnectPoint(),
|
||||
self.Object2.GetConnectPoint()) )
|
||||
Points = WorldToPixel(Points)
|
||||
dc.SetPen(self.Pen)
|
||||
dc.DrawLines(Points)
|
||||
if HTdc and self.HitAble:
|
||||
HTdc.SetPen(self.HitPen)
|
||||
HTdc.DrawLines(Points)
|
||||
|
||||
|
||||
class TriangleShape1(FC.Polygon, MovingObjectMixin):
|
||||
|
||||
def __init__(self, XY, L):
|
||||
|
||||
"""
|
||||
An equilateral triangle object
|
||||
XY is the middle of the triangle
|
||||
L is the length of one side of the Triangle
|
||||
"""
|
||||
|
||||
XY = N.asarray(XY)
|
||||
XY.shape = (2,)
|
||||
|
||||
Points = self.CompPoints(XY, L)
|
||||
|
||||
FC.Polygon.__init__(self, Points,
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 2,
|
||||
FillColor = "Red",
|
||||
FillStyle = "Solid")
|
||||
## Override the default OutlinePoints
|
||||
def GetOutlinePoints(self):
|
||||
return self.Points
|
||||
|
||||
def CompPoints(self, XY, L):
|
||||
c = L/ N.sqrt(3)
|
||||
|
||||
Points = N.array(((0, c),
|
||||
( L/2.0, -c/2.0),
|
||||
(-L/2.0, -c/2.0)),
|
||||
N.float_)
|
||||
|
||||
Points += XY
|
||||
return Points
|
||||
|
||||
### Tree Utilities
|
||||
### And some hard coded data...
|
||||
|
||||
class TreeNode:
|
||||
dx = 15
|
||||
dy = 4
|
||||
def __init__(self, name, Children = []):
|
||||
self.Name = name
|
||||
#self.parent = None -- Is this needed?
|
||||
self.Children = Children
|
||||
self.Point = None # The coords of the node.
|
||||
|
||||
def __str__(self):
|
||||
return "TreeNode: %s"%self.Name
|
||||
__repr__ = __str__
|
||||
|
||||
|
||||
## Build Tree:
|
||||
leaves = [TreeNode(name) for name in ["Assistant VP 1","Assistant VP 2","Assistant VP 3"] ]
|
||||
VP1 = TreeNode("VP1", Children = leaves)
|
||||
VP2 = TreeNode("VP2")
|
||||
|
||||
CEO = TreeNode("CEO", [VP1, VP2])
|
||||
Father = TreeNode("Father", [TreeNode("Daughter"), TreeNode("Son")])
|
||||
elements = TreeNode("Root", [CEO, Father])
|
||||
|
||||
def LayoutTree(root, x, y, level):
|
||||
NumNodes = len(root.Children)
|
||||
root.Point = (x,y)
|
||||
x += root.dx
|
||||
y += (root.dy * level * (NumNodes-1) / 2.0)
|
||||
for node in root.Children:
|
||||
LayoutTree(node, x, y, level-1)
|
||||
y -= root.dy * level
|
||||
|
||||
def TraverseTree(root, func):
|
||||
func(root)
|
||||
for child in (root.Children):
|
||||
TraverseTree(child, func)
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A simple frame used for the Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,(500,500),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "White",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
|
||||
Canvas.Bind(FC.EVT_MOTION, self.OnMove )
|
||||
Canvas.Bind(FC.EVT_LEFT_UP, self.OnLeftUp )
|
||||
|
||||
self.elements = elements
|
||||
LayoutTree(self.elements, 0, 0, 3)
|
||||
self.AddTree(self.elements)
|
||||
|
||||
|
||||
self.Show(True)
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
self.MoveObject = None
|
||||
self.Moving = False
|
||||
|
||||
return None
|
||||
|
||||
def AddTree(self, root):
|
||||
Nodes = []
|
||||
Connectors = []
|
||||
EllipseW = 15
|
||||
EllipseH = 4
|
||||
def CreateObject(node):
|
||||
if node.Children:
|
||||
object = NodeObject(node.Name,
|
||||
node.Point,
|
||||
(15, 4),
|
||||
BackgroundColor = "Yellow",
|
||||
TextColor = "Black",
|
||||
)
|
||||
else:
|
||||
object = MovingText(node.Name,
|
||||
node.Point,
|
||||
2.0,
|
||||
BackgroundColor = "Yellow",
|
||||
Color = "Red",
|
||||
Position = "cl",
|
||||
)
|
||||
node.DrawObject = object
|
||||
Nodes.append(object)
|
||||
def AddConnectors(node):
|
||||
for child in node.Children:
|
||||
Connector = ConnectorLine(node.DrawObject, child.DrawObject, LineWidth=3, LineColor="Red")
|
||||
Connectors.append(Connector)
|
||||
## create the Objects
|
||||
TraverseTree(root, CreateObject)
|
||||
## create the Connectors
|
||||
TraverseTree(root, AddConnectors)
|
||||
## Add the conenctos to the Canvas first, so they are undernieth the nodes
|
||||
self.Canvas.AddObjects(Connectors)
|
||||
## now add the nodes
|
||||
self.Canvas.AddObjects(Nodes)
|
||||
# Now bind the Nodes -- DrawObjects must be Added to a Canvas before they can be bound.
|
||||
for node in Nodes:
|
||||
#pass
|
||||
node.Bind(FC.EVT_FC_LEFT_DOWN, self.ObjectHit)
|
||||
|
||||
|
||||
|
||||
def ObjectHit(self, object):
|
||||
if not self.Moving:
|
||||
self.Moving = True
|
||||
self.StartPoint = object.HitCoordsPixel
|
||||
self.StartObject = self.Canvas.WorldToPixel(object.GetOutlinePoints())
|
||||
self.MoveObject = None
|
||||
self.MovingObject = object
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
and moves the object it is clicked on
|
||||
|
||||
"""
|
||||
self.SetStatusText("%.4f, %.4f"%tuple(event.Coords))
|
||||
|
||||
if self.Moving:
|
||||
dxy = event.GetPosition() - self.StartPoint
|
||||
# Draw the Moving Object:
|
||||
dc = wx.ClientDC(self.Canvas)
|
||||
dc.SetPen(wx.Pen('WHITE', 2, wx.SHORT_DASH))
|
||||
dc.SetBrush(wx.TRANSPARENT_BRUSH)
|
||||
dc.SetLogicalFunction(wx.XOR)
|
||||
if self.MoveObject is not None:
|
||||
dc.DrawPolygon(self.MoveObject)
|
||||
self.MoveObject = self.StartObject + dxy
|
||||
dc.DrawPolygon(self.MoveObject)
|
||||
|
||||
def OnLeftUp(self, event):
|
||||
if self.Moving:
|
||||
self.Moving = False
|
||||
if self.MoveObject is not None:
|
||||
dxy = event.GetPosition() - self.StartPoint
|
||||
dxy = self.Canvas.ScalePixelToWorld(dxy)
|
||||
self.MovingObject.Move(dxy)
|
||||
self.MoveTri = None
|
||||
self.Canvas.Draw(True)
|
||||
|
||||
app = wx.PySimpleApp(0)
|
||||
DrawFrame(None, -1, "FloatCanvas Tree Demo App", wx.DefaultPosition, (700,700) )
|
||||
app.MainLoop()
|
203
samples/floatcanvas/VectPlot.py
Executable file
203
samples/floatcanvas/VectPlot.py
Executable file
@@ -0,0 +1,203 @@
|
||||
#!/usr/bin/env python
|
||||
"""
|
||||
|
||||
A small test app that uses FloatCanvas to draw a vector plot.
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
import numpy as N
|
||||
import random
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("../")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
def __init__(self,parent, id,title,position,size):
|
||||
wx.Frame.__init__(self,parent, id,title,position, size)
|
||||
|
||||
## Set up the MenuBar
|
||||
|
||||
MenuBar = wx.MenuBar()
|
||||
|
||||
file_menu = wx.Menu()
|
||||
item = file_menu.Append(wx.ID_ANY, "E&xit","Terminate the program")
|
||||
self.Bind(wx.EVT_MENU, self.OnQuit, item)
|
||||
MenuBar.Append(file_menu, "&File")
|
||||
|
||||
draw_menu = wx.Menu()
|
||||
item = draw_menu.Append(wx.ID_ANY, "&Plot","Re-do Plot")
|
||||
self.Bind(wx.EVT_MENU, self.Plot, item)
|
||||
MenuBar.Append(draw_menu, "&Plot")
|
||||
|
||||
|
||||
help_menu = wx.Menu()
|
||||
item = help_menu.Append(wx.ID_ANY, "&About",
|
||||
"More information About this program")
|
||||
self.Bind(wx.EVT_MENU, self.OnAbout, item)
|
||||
MenuBar.Append(help_menu, "&Help")
|
||||
|
||||
self.SetMenuBar(MenuBar)
|
||||
|
||||
|
||||
self.CreateStatusBar()
|
||||
self.SetStatusText("")
|
||||
|
||||
wx.EVT_CLOSE(self, self.OnCloseWindow)
|
||||
|
||||
# Add the Canvas
|
||||
self.Canvas = NavCanvas.NavCanvas(self ,wx.ID_ANY ,(500,300),
|
||||
ProjectionFun = None,
|
||||
Debug = 0,
|
||||
BackgroundColor = "WHITE"
|
||||
).Canvas
|
||||
|
||||
self.Canvas.NumBetweenBlits = 1000
|
||||
|
||||
|
||||
self.Show(True)
|
||||
|
||||
self.Plot()
|
||||
return None
|
||||
|
||||
|
||||
def OnAbout(self, event):
|
||||
dlg = wx.MessageDialog(self, "This is a small program to demonstrate\n"
|
||||
"the use of the FloatCanvas\n"
|
||||
"for vector plotting",
|
||||
"About Me", wx.OK | wx.ICON_INFORMATION)
|
||||
dlg.ShowModal()
|
||||
dlg.Destroy()
|
||||
|
||||
def ZoomToFit(self,event):
|
||||
self.Canvas.ZoomToBB()
|
||||
|
||||
def OnQuit(self,event):
|
||||
self.Close(True)
|
||||
|
||||
def OnCloseWindow(self, event):
|
||||
self.Destroy()
|
||||
|
||||
|
||||
def DrawAxis(self):
|
||||
Canvas = self.Canvas
|
||||
|
||||
# Draw the Axis
|
||||
|
||||
# Note: the AddRectangle Parameters all have sensible
|
||||
# defaults. I've put them all here explicitly, so you can see
|
||||
# what the options are.
|
||||
|
||||
self.Canvas.AddRectangle((0, -1.1),
|
||||
(2*N.pi, 2.2),
|
||||
LineColor = "Black",
|
||||
LineStyle = "Solid",
|
||||
LineWidth = 1,
|
||||
FillColor = None,
|
||||
FillStyle = "Solid",
|
||||
InForeground = 0)
|
||||
for tic in N.arange(7):
|
||||
self.Canvas.AddText("%1.1f"%tic,
|
||||
(tic, -1.1),
|
||||
Position = 'tc')
|
||||
|
||||
for tic in N.arange(-1,1.1,0.5):
|
||||
self.Canvas.AddText("%1.1f"%tic,
|
||||
(0,tic),
|
||||
Position = 'cr')
|
||||
|
||||
# Add a phantom rectangle to get the bounding box right
|
||||
# (the bounding box doesn't get unscaled text right)
|
||||
self.Canvas.AddRectangle((-0.7, -1.5),
|
||||
(7, 3),
|
||||
LineColor = None)
|
||||
|
||||
#Canvas.ZoomToBB()
|
||||
#Canvas.Draw()
|
||||
|
||||
def Plot(self, event = None):
|
||||
x = N.arange(0, 2*N.pi, 0.1)
|
||||
x.shape = (-1,1)
|
||||
y = N.sin(x)
|
||||
data = N.concatenate((x, y),1)
|
||||
|
||||
Canvas = self.Canvas
|
||||
self.Canvas.ClearAll()
|
||||
self.DrawAxis()
|
||||
for p in data:
|
||||
Canvas.AddPoint(p,
|
||||
Diameter = 4,
|
||||
Color = "Red",
|
||||
InForeground = 1)
|
||||
theta = random.uniform(0, 360)
|
||||
Canvas.AddArrow(p,
|
||||
Length = 20,
|
||||
Direction = p[1]*360,
|
||||
LineColor = "Red",
|
||||
)
|
||||
self.Canvas.ZoomToBB()
|
||||
self.Canvas.Draw()
|
||||
self.Canvas.SaveAsImage("junk.png")
|
||||
|
||||
|
||||
class DemoApp(wx.App):
|
||||
"""
|
||||
How the demo works:
|
||||
|
||||
Either under the Draw menu, or on the toolbar, you can push Run and Stop
|
||||
|
||||
"Run" start an oscilloscope like display of a moving sine curve
|
||||
"Stop" stops it.
|
||||
|
||||
While the plot os running (or not) you can zoom in and out and move
|
||||
about the picture. There is a tool bar with three tools that can be
|
||||
selected.
|
||||
|
||||
The magnifying glass with the plus is the zoom in tool. Once selected,
|
||||
if you click the image, it will zoom in, centered on where you
|
||||
clicked. If you click and drag the mouse, you will get a rubber band
|
||||
box, and the image will zoom to fit that box when you release it.
|
||||
|
||||
The magnifying glass with the minus is the zoom out tool. Once selected,
|
||||
if you click the image, it will zoom out, centered on where you
|
||||
clicked.
|
||||
|
||||
The hand is the move tool. Once selected, if you click and drag on
|
||||
the image, it will move so that the part you clicked on ends up
|
||||
where you release the mouse. Nothing is changed while you are
|
||||
dragging, but you can see the outline of the former picture.
|
||||
|
||||
I'd like the cursor to change as you change tools, but the stock
|
||||
wx.Cursors didn't include anything I liked, so I stuck with the
|
||||
pointer. Please let me know if you have any nice cursor images for me to
|
||||
use.
|
||||
|
||||
|
||||
Any bugs, comments, feedback, questions, and especially code are welcome:
|
||||
|
||||
-Chris Barker
|
||||
|
||||
Chris.Barker@noaa.gov
|
||||
|
||||
"""
|
||||
|
||||
def OnInit(self):
|
||||
frame = DrawFrame(None, wx.ID_ANY, "Plotting Test",wx.DefaultPosition,wx.Size(700,400))
|
||||
|
||||
self.SetTopWindow(frame)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
||||
app = DemoApp(0)
|
||||
app.MainLoop()
|
||||
|
||||
|
95
samples/floatcanvas/YDownDemo.py
Executable file
95
samples/floatcanvas/YDownDemo.py
Executable file
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
This demonstrates how to use FloatCanvas with a coordinate system where
|
||||
Y is increased down, instead of up. This is a standard system for
|
||||
images, for instance.
|
||||
|
||||
Note that there are some problems with doing this for bitmaps and text: things that require positioning.
|
||||
|
||||
I'm sure it can be fixed, but I don't have a need for it, so I haven't taken the time yet.
|
||||
-chb
|
||||
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
## import the installed version
|
||||
from wx.lib.floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
## import a local version
|
||||
#import sys
|
||||
#sys.path.append("..")
|
||||
#from floatcanvas import NavCanvas, FloatCanvas
|
||||
|
||||
|
||||
import numpy as N
|
||||
|
||||
def YDownProjection(CenterPoint):
|
||||
return N.array((1,-1))
|
||||
|
||||
class DrawFrame(wx.Frame):
|
||||
|
||||
"""
|
||||
A frame used for the FloatCanvas Demo
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
wx.Frame.__init__(self, *args, **kwargs)
|
||||
|
||||
self.CreateStatusBar()
|
||||
|
||||
# Add the Canvas
|
||||
Canvas = NavCanvas.NavCanvas(self,-1,
|
||||
size = (500,500),
|
||||
ProjectionFun = YDownProjection,
|
||||
Debug = 0,
|
||||
BackgroundColor = "DARK SLATE BLUE",
|
||||
).Canvas
|
||||
|
||||
self.Canvas = Canvas
|
||||
|
||||
Point = (0,0)
|
||||
Box = Canvas.AddRectangle(Point,
|
||||
(80,100),
|
||||
FillColor = "blue"
|
||||
)
|
||||
|
||||
Canvas.AddText("%s"%(Point,), Point, Position="cr")
|
||||
Canvas.AddPoint(Point, Diameter=3, Color = "red")
|
||||
|
||||
|
||||
Point = (0,100)
|
||||
Canvas.AddText("%s"%(Point,), Point, Position="cr")
|
||||
Canvas.AddPoint(Point, Diameter=3, Color = "red")
|
||||
|
||||
FloatCanvas.EVT_MOTION(self.Canvas, self.OnMove )
|
||||
|
||||
|
||||
self.Show()
|
||||
Canvas.ZoomToBB()
|
||||
|
||||
def OnMove(self, event):
|
||||
"""
|
||||
Updates the status bar with the world coordinates
|
||||
"""
|
||||
self.SetStatusText("%.2f, %.2f"%tuple(event.Coords))
|
||||
|
||||
|
||||
app = wx.App(False)
|
||||
F = DrawFrame(None, title="FloatCanvas Demo App", size=(700,700) )
|
||||
app.MainLoop()
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
BIN
samples/floatcanvas/white_tank.jpg
Normal file
BIN
samples/floatcanvas/white_tank.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 162 KiB |
Reference in New Issue
Block a user