diff --git a/samples/floatcanvas/Animation.py b/samples/floatcanvas/Animation.py new file mode 100755 index 00000000..e5d0ae34 --- /dev/null +++ b/samples/floatcanvas/Animation.py @@ -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() + + + + + + + + + + diff --git a/samples/floatcanvas/BB_HitTest.py b/samples/floatcanvas/BB_HitTest.py new file mode 100755 index 00000000..29574317 --- /dev/null +++ b/samples/floatcanvas/BB_HitTest.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/BNAEditor.py b/samples/floatcanvas/BNAEditor.py new file mode 100755 index 00000000..f0693a5b --- /dev/null +++ b/samples/floatcanvas/BNAEditor.py @@ -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() + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/floatcanvas/BarPlot.py b/samples/floatcanvas/BarPlot.py new file mode 100755 index 00000000..ff8e4566 --- /dev/null +++ b/samples/floatcanvas/BarPlot.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/BouncingBall.py b/samples/floatcanvas/BouncingBall.py new file mode 100755 index 00000000..3efc35b8 --- /dev/null +++ b/samples/floatcanvas/BouncingBall.py @@ -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() + + diff --git a/samples/floatcanvas/Chart.py b/samples/floatcanvas/Chart.py new file mode 100755 index 00000000..bf079031 --- /dev/null +++ b/samples/floatcanvas/Chart.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/ClickableBoxes.py b/samples/floatcanvas/ClickableBoxes.py new file mode 100755 index 00000000..e16566e3 --- /dev/null +++ b/samples/floatcanvas/ClickableBoxes.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/DrawBot.py b/samples/floatcanvas/DrawBot.py new file mode 100755 index 00000000..9e13881e --- /dev/null +++ b/samples/floatcanvas/DrawBot.py @@ -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() + diff --git a/samples/floatcanvas/DrawRect.py b/samples/floatcanvas/DrawRect.py new file mode 100755 index 00000000..3fbcdb26 --- /dev/null +++ b/samples/floatcanvas/DrawRect.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/GridDemo.py b/samples/floatcanvas/GridDemo.py new file mode 100755 index 00000000..4143e3bf --- /dev/null +++ b/samples/floatcanvas/GridDemo.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/GroupDeleteDemo.py b/samples/floatcanvas/GroupDeleteDemo.py new file mode 100644 index 00000000..a09034f2 --- /dev/null +++ b/samples/floatcanvas/GroupDeleteDemo.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/GroupDemo.py b/samples/floatcanvas/GroupDemo.py new file mode 100644 index 00000000..a235dc78 --- /dev/null +++ b/samples/floatcanvas/GroupDemo.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/Hexagons.py b/samples/floatcanvas/Hexagons.py new file mode 100755 index 00000000..8c0e622c --- /dev/null +++ b/samples/floatcanvas/Hexagons.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/Map.py b/samples/floatcanvas/Map.py new file mode 100755 index 00000000..aa7b91b2 --- /dev/null +++ b/samples/floatcanvas/Map.py @@ -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() + + diff --git a/samples/floatcanvas/MicroDemo.py b/samples/floatcanvas/MicroDemo.py new file mode 100755 index 00000000..7f0bc367 --- /dev/null +++ b/samples/floatcanvas/MicroDemo.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/MiniDemo.py b/samples/floatcanvas/MiniDemo.py new file mode 100755 index 00000000..f8e4e79d --- /dev/null +++ b/samples/floatcanvas/MiniDemo.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/MouseTest.py b/samples/floatcanvas/MouseTest.py new file mode 100755 index 00000000..7e344df6 --- /dev/null +++ b/samples/floatcanvas/MouseTest.py @@ -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() + diff --git a/samples/floatcanvas/MovingElements.py b/samples/floatcanvas/MovingElements.py new file mode 100755 index 00000000..08f349e1 --- /dev/null +++ b/samples/floatcanvas/MovingElements.py @@ -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() diff --git a/samples/floatcanvas/MovingPlot.py b/samples/floatcanvas/MovingPlot.py new file mode 100755 index 00000000..bebc795e --- /dev/null +++ b/samples/floatcanvas/MovingPlot.py @@ -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() + + diff --git a/samples/floatcanvas/MovingTriangle.py b/samples/floatcanvas/MovingTriangle.py new file mode 100755 index 00000000..882bd3d2 --- /dev/null +++ b/samples/floatcanvas/MovingTriangle.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/NOAA.png b/samples/floatcanvas/NOAA.png new file mode 100644 index 00000000..f4d0e553 Binary files /dev/null and b/samples/floatcanvas/NOAA.png differ diff --git a/samples/floatcanvas/NoToolbar.py b/samples/floatcanvas/NoToolbar.py new file mode 100755 index 00000000..b8d35972 --- /dev/null +++ b/samples/floatcanvas/NoToolbar.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/NonGUI.py b/samples/floatcanvas/NonGUI.py new file mode 100755 index 00000000..de1c9b6a --- /dev/null +++ b/samples/floatcanvas/NonGUI.py @@ -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") + diff --git a/samples/floatcanvas/OverlayDemo.py b/samples/floatcanvas/OverlayDemo.py new file mode 100755 index 00000000..2c2e9ac0 --- /dev/null +++ b/samples/floatcanvas/OverlayDemo.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/PieChart.py b/samples/floatcanvas/PieChart.py new file mode 100755 index 00000000..b0a6d0c6 --- /dev/null +++ b/samples/floatcanvas/PieChart.py @@ -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() diff --git a/samples/floatcanvas/PixelBitmap.py b/samples/floatcanvas/PixelBitmap.py new file mode 100755 index 00000000..2c2d57c6 --- /dev/null +++ b/samples/floatcanvas/PixelBitmap.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/PointsHitDemo.py b/samples/floatcanvas/PointsHitDemo.py new file mode 100755 index 00000000..0a44925d --- /dev/null +++ b/samples/floatcanvas/PointsHitDemo.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/PolyEditor.py b/samples/floatcanvas/PolyEditor.py new file mode 100755 index 00000000..af545393 --- /dev/null +++ b/samples/floatcanvas/PolyEditor.py @@ -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. + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/floatcanvas/ProcessDiagram.py b/samples/floatcanvas/ProcessDiagram.py new file mode 100644 index 00000000..b6b1ca1f --- /dev/null +++ b/samples/floatcanvas/ProcessDiagram.py @@ -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() diff --git a/samples/floatcanvas/ScaleDemo.py b/samples/floatcanvas/ScaleDemo.py new file mode 100644 index 00000000..1ce05205 --- /dev/null +++ b/samples/floatcanvas/ScaleDemo.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/ScaledBitmap2Demo.py b/samples/floatcanvas/ScaledBitmap2Demo.py new file mode 100755 index 00000000..e7d068f5 --- /dev/null +++ b/samples/floatcanvas/ScaledBitmap2Demo.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/SplitterWindow.py b/samples/floatcanvas/SplitterWindow.py new file mode 100644 index 00000000..612125e9 --- /dev/null +++ b/samples/floatcanvas/SplitterWindow.py @@ -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() diff --git a/samples/floatcanvas/SubClassNavCanvas.py b/samples/floatcanvas/SubClassNavCanvas.py new file mode 100755 index 00000000..346ae4a2 --- /dev/null +++ b/samples/floatcanvas/SubClassNavCanvas.py @@ -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() diff --git a/samples/floatcanvas/TestSpline.py b/samples/floatcanvas/TestSpline.py new file mode 100755 index 00000000..6a06c825 --- /dev/null +++ b/samples/floatcanvas/TestSpline.py @@ -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() + + + + + + + + + + + + + + + + + diff --git a/samples/floatcanvas/TextBox.py b/samples/floatcanvas/TextBox.py new file mode 100755 index 00000000..429d1d34 --- /dev/null +++ b/samples/floatcanvas/TextBox.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/TextBox2.py b/samples/floatcanvas/TextBox2.py new file mode 100755 index 00000000..bbac53a2 --- /dev/null +++ b/samples/floatcanvas/TextBox2.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/Tiny.bna b/samples/floatcanvas/Tiny.bna new file mode 100644 index 00000000..72e30d3d --- /dev/null +++ b/samples/floatcanvas/Tiny.bna @@ -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 diff --git a/samples/floatcanvas/Tree.py b/samples/floatcanvas/Tree.py new file mode 100755 index 00000000..f7d35605 --- /dev/null +++ b/samples/floatcanvas/Tree.py @@ -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() diff --git a/samples/floatcanvas/VectPlot.py b/samples/floatcanvas/VectPlot.py new file mode 100755 index 00000000..25cab46f --- /dev/null +++ b/samples/floatcanvas/VectPlot.py @@ -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() + + diff --git a/samples/floatcanvas/YDownDemo.py b/samples/floatcanvas/YDownDemo.py new file mode 100755 index 00000000..76b7c891 --- /dev/null +++ b/samples/floatcanvas/YDownDemo.py @@ -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() + + + + + + + + + + + + + diff --git a/samples/floatcanvas/white_tank.jpg b/samples/floatcanvas/white_tank.jpg new file mode 100644 index 00000000..6e49f4c8 Binary files /dev/null and b/samples/floatcanvas/white_tank.jpg differ