diff --git a/demo/AUI_DockingWindowMgr.py b/demo/AUI_DockingWindowMgr.py new file mode 100644 index 00000000..bade3525 --- /dev/null +++ b/demo/AUI_DockingWindowMgr.py @@ -0,0 +1,1150 @@ +import wx +import wx.grid +import wx.html +import wx.aui + +import cStringIO + +ID_CreateTree = wx.NewId() +ID_CreateGrid = wx.NewId() +ID_CreateText = wx.NewId() +ID_CreateHTML = wx.NewId() +ID_CreateSizeReport = wx.NewId() +ID_GridContent = wx.NewId() +ID_TextContent = wx.NewId() +ID_TreeContent = wx.NewId() +ID_HTMLContent = wx.NewId() +ID_SizeReportContent = wx.NewId() +ID_CreatePerspective = wx.NewId() +ID_CopyPerspective = wx.NewId() + +ID_TransparentHint = wx.NewId() +ID_VenetianBlindsHint = wx.NewId() +ID_RectangleHint = wx.NewId() +ID_NoHint = wx.NewId() +ID_HintFade = wx.NewId() +ID_AllowFloating = wx.NewId() +ID_NoVenetianFade = wx.NewId() +ID_TransparentDrag = wx.NewId() +ID_AllowActivePane = wx.NewId() +ID_NoGradient = wx.NewId() +ID_VerticalGradient = wx.NewId() +ID_HorizontalGradient = wx.NewId() + +ID_Settings = wx.NewId() +ID_About = wx.NewId() +ID_FirstPerspective = ID_CreatePerspective+1000 + + + +#---------------------------------------------------------------------- +def GetMondrianData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ +\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\ +ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\ +o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\ +\xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\ +\x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\ +\x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82' + + +def GetMondrianBitmap(): + return wx.BitmapFromImage(GetMondrianImage()) + + +def GetMondrianImage(): + stream = cStringIO.StringIO(GetMondrianData()) + return wx.ImageFromStream(stream) + + +def GetMondrianIcon(): + icon = wx.EmptyIcon() + icon.CopyFromBitmap(GetMondrianBitmap()) + return icon + + +class PyAUIFrame(wx.Frame): + + def __init__(self, parent, id=-1, title="", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE | + wx.SUNKEN_BORDER | + wx.CLIP_CHILDREN): + + wx.Frame.__init__(self, parent, id, title, pos, size, style) + + # tell FrameManager to manage this frame + self._mgr = wx.aui.AuiManager() + self._mgr.SetManagedWindow(self) + + self._perspectives = [] + self.n = 0 + self.x = 0 + + self.SetIcon(GetMondrianIcon()) + + # create menu + mb = wx.MenuBar() + + file_menu = wx.Menu() + file_menu.Append(wx.ID_EXIT, "Exit") + + view_menu = wx.Menu() + view_menu.Append(ID_CreateText, "Create Text Control") + view_menu.Append(ID_CreateHTML, "Create HTML Control") + view_menu.Append(ID_CreateTree, "Create Tree") + view_menu.Append(ID_CreateGrid, "Create Grid") + view_menu.Append(ID_CreateSizeReport, "Create Size Reporter") + view_menu.AppendSeparator() + view_menu.Append(ID_GridContent, "Use a Grid for the Content Pane") + view_menu.Append(ID_TextContent, "Use a Text Control for the Content Pane") + view_menu.Append(ID_HTMLContent, "Use an HTML Control for the Content Pane") + view_menu.Append(ID_TreeContent, "Use a Tree Control for the Content Pane") + view_menu.Append(ID_SizeReportContent, "Use a Size Reporter for the Content Pane") + + options_menu = wx.Menu() + options_menu.AppendRadioItem(ID_TransparentHint, "Transparent Hint") + options_menu.AppendRadioItem(ID_VenetianBlindsHint, "Venetian Blinds Hint") + options_menu.AppendRadioItem(ID_RectangleHint, "Rectangle Hint") + options_menu.AppendRadioItem(ID_NoHint, "No Hint") + options_menu.AppendSeparator(); + options_menu.AppendCheckItem(ID_HintFade, "Hint Fade-in") + options_menu.AppendCheckItem(ID_AllowFloating, "Allow Floating") + options_menu.AppendCheckItem(ID_NoVenetianFade, "Disable Venetian Blinds Hint Fade-in") + options_menu.AppendCheckItem(ID_TransparentDrag, "Transparent Drag") + options_menu.AppendCheckItem(ID_AllowActivePane, "Allow Active Pane") + options_menu.AppendSeparator(); + options_menu.AppendRadioItem(ID_NoGradient, "No Caption Gradient") + options_menu.AppendRadioItem(ID_VerticalGradient, "Vertical Caption Gradient") + options_menu.AppendRadioItem(ID_HorizontalGradient, "Horizontal Caption Gradient") + options_menu.AppendSeparator(); + options_menu.Append(ID_Settings, "Settings Pane") + + self._perspectives_menu = wx.Menu() + self._perspectives_menu.Append(ID_CreatePerspective, "Create Perspective") + self._perspectives_menu.Append(ID_CopyPerspective, "Copy Perspective Data To Clipboard") + self._perspectives_menu.AppendSeparator() + self._perspectives_menu.Append(ID_FirstPerspective+0, "Default Startup") + self._perspectives_menu.Append(ID_FirstPerspective+1, "All Panes") + self._perspectives_menu.Append(ID_FirstPerspective+2, "Vertical Toolbar") + + help_menu = wx.Menu() + help_menu.Append(ID_About, "About...") + + mb.Append(file_menu, "File") + mb.Append(view_menu, "View") + mb.Append(self._perspectives_menu, "Perspectives") + mb.Append(options_menu, "Options") + mb.Append(help_menu, "Help") + + self.SetMenuBar(mb) + + self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + self.statusbar.SetStatusWidths([-2, -3]) + self.statusbar.SetStatusText("Ready", 0) + self.statusbar.SetStatusText("Welcome To wxPython!", 1) + + # min size for the frame itself isn't completely done. + # see the end up FrameManager::Update() for the test + # code. For now, just hard code a frame minimum size + self.SetMinSize(wx.Size(400, 300)) + + # create some toolbars + tb1 = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + wx.TB_FLAT | wx.TB_NODIVIDER) + tb1.SetToolBitmapSize(wx.Size(48,48)) + tb1.AddLabelTool(101, "Test", wx.ArtProvider_GetBitmap(wx.ART_ERROR)) + tb1.AddSeparator() + tb1.AddLabelTool(102, "Test", wx.ArtProvider_GetBitmap(wx.ART_QUESTION)) + tb1.AddLabelTool(103, "Test", wx.ArtProvider_GetBitmap(wx.ART_INFORMATION)) + tb1.AddLabelTool(103, "Test", wx.ArtProvider_GetBitmap(wx.ART_WARNING)) + tb1.AddLabelTool(103, "Test", wx.ArtProvider_GetBitmap(wx.ART_MISSING_IMAGE)) + tb1.Realize() + + tb2 = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + wx.TB_FLAT | wx.TB_NODIVIDER) + tb2.SetToolBitmapSize(wx.Size(16,16)) + tb2_bmp1 = wx.ArtProvider_GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, wx.Size(16, 16)) + tb2.AddLabelTool(101, "Test", tb2_bmp1) + tb2.AddLabelTool(101, "Test", tb2_bmp1) + tb2.AddLabelTool(101, "Test", tb2_bmp1) + tb2.AddLabelTool(101, "Test", tb2_bmp1) + tb2.AddSeparator() + tb2.AddLabelTool(101, "Test", tb2_bmp1) + tb2.AddLabelTool(101, "Test", tb2_bmp1) + tb2.AddSeparator() + tb2.AddLabelTool(101, "Test", tb2_bmp1) + tb2.AddLabelTool(101, "Test", tb2_bmp1) + tb2.AddLabelTool(101, "Test", tb2_bmp1) + tb2.AddLabelTool(101, "Test", tb2_bmp1) + tb2.Realize() + + tb3 = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + wx.TB_FLAT | wx.TB_NODIVIDER) + tb3.SetToolBitmapSize(wx.Size(16,16)) + tb3_bmp1 = wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, wx.Size(16, 16)) + tb3.AddLabelTool(101, "Test", tb3_bmp1) + tb3.AddLabelTool(101, "Test", tb3_bmp1) + tb3.AddLabelTool(101, "Test", tb3_bmp1) + tb3.AddLabelTool(101, "Test", tb3_bmp1) + tb3.AddSeparator() + tb3.AddLabelTool(101, "Test", tb3_bmp1) + tb3.AddLabelTool(101, "Test", tb3_bmp1) + tb3.Realize() + + tb4 = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + wx.TB_FLAT | wx.TB_NODIVIDER | wx.TB_HORZ_TEXT) + tb4.SetToolBitmapSize(wx.Size(16,16)) + tb4_bmp1 = wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16)) + tb4.AddLabelTool(101, "Item 1", tb4_bmp1) + tb4.AddLabelTool(101, "Item 2", tb4_bmp1) + tb4.AddLabelTool(101, "Item 3", tb4_bmp1) + tb4.AddLabelTool(101, "Item 4", tb4_bmp1) + tb4.AddSeparator() + tb4.AddLabelTool(101, "Item 5", tb4_bmp1) + tb4.AddLabelTool(101, "Item 6", tb4_bmp1) + tb4.AddLabelTool(101, "Item 7", tb4_bmp1) + tb4.AddLabelTool(101, "Item 8", tb4_bmp1) + tb4.Realize() + + tb5 = wx.ToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + wx.TB_FLAT | wx.TB_NODIVIDER | wx.TB_VERTICAL) + tb5.SetToolBitmapSize(wx.Size(48, 48)) + tb5.AddLabelTool(101, "Test", wx.ArtProvider_GetBitmap(wx.ART_ERROR)) + tb5.AddSeparator() + tb5.AddLabelTool(102, "Test", wx.ArtProvider_GetBitmap(wx.ART_QUESTION)) + tb5.AddLabelTool(103, "Test", wx.ArtProvider_GetBitmap(wx.ART_INFORMATION)) + tb5.AddLabelTool(103, "Test", wx.ArtProvider_GetBitmap(wx.ART_WARNING)) + tb5.AddLabelTool(103, "Test", wx.ArtProvider_GetBitmap(wx.ART_MISSING_IMAGE)) + tb5.Realize() + + # add a bunch of panes + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo(). + Name("test1").Caption("Pane Caption").Top(). + CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo(). + Name("test2").Caption("Client Size Reporter"). + Bottom().Position(1).CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo(). + Name("test3").Caption("Client Size Reporter"). + Bottom().CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo(). + Name("test4").Caption("Pane Caption"). + Left().CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo(). + Name("test5").Caption("Pane Caption"). + Right().CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo(). + Name("test6").Caption("Client Size Reporter"). + Right().Row(1).CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo(). + Name("test7").Caption("Client Size Reporter"). + Left().Layer(1).CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(self.CreateTreeCtrl(), wx.aui.AuiPaneInfo(). + Name("test8").Caption("Tree Pane"). + Left().Layer(1).Position(1).CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo(). + Name("test9").Caption("Min Size 200x100"). + BestSize(wx.Size(200,100)).MinSize(wx.Size(200,100)). + Bottom().Layer(1).CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(self.CreateTextCtrl(), wx.aui.AuiPaneInfo(). + Name("test10").Caption("Text Pane"). + Bottom().Layer(1).Position(1).CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo(). + Name("test11").Caption("Fixed Pane"). + Bottom().Layer(1).Position(2).Fixed().CloseButton(True).MaximizeButton(True)) + + self._mgr.AddPane(SettingsPanel(self, self), wx.aui.AuiPaneInfo(). + Name("settings").Caption("Dock Manager Settings"). + Dockable(False).Float().Hide().CloseButton(True).MaximizeButton(True)) + + # create some center panes + + self._mgr.AddPane(self.CreateGrid(), wx.aui.AuiPaneInfo().Name("grid_content"). + CenterPane().Hide()) + + self._mgr.AddPane(self.CreateTreeCtrl(), wx.aui.AuiPaneInfo().Name("tree_content"). + CenterPane().Hide()) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo().Name("sizereport_content"). + CenterPane().Hide()) + + self._mgr.AddPane(self.CreateTextCtrl(), wx.aui.AuiPaneInfo().Name("text_content"). + CenterPane().Hide()) + + self._mgr.AddPane(self.CreateHTMLCtrl(), wx.aui.AuiPaneInfo().Name("html_content"). + CenterPane()) + + # add the toolbars to the manager + + self._mgr.AddPane(tb1, wx.aui.AuiPaneInfo(). + Name("tb1").Caption("Big Toolbar"). + ToolbarPane().Top(). + LeftDockable(False).RightDockable(False)) + + self._mgr.AddPane(tb2, wx.aui.AuiPaneInfo(). + Name("tb2").Caption("Toolbar 2"). + ToolbarPane().Top().Row(1). + LeftDockable(False).RightDockable(False)) + + self._mgr.AddPane(tb3, wx.aui.AuiPaneInfo(). + Name("tb3").Caption("Toolbar 3"). + ToolbarPane().Top().Row(1).Position(1). + LeftDockable(False).RightDockable(False)) + + self._mgr.AddPane(tb4, wx.aui.AuiPaneInfo(). + Name("tb4").Caption("Sample Bookmark Toolbar"). + ToolbarPane().Top().Row(2). + LeftDockable(False).RightDockable(False)) + + self._mgr.AddPane(tb5, wx.aui.AuiPaneInfo(). + Name("tbvert").Caption("Sample Vertical Toolbar"). + ToolbarPane().Left().GripperTop(). + TopDockable(False).BottomDockable(False)) + + self._mgr.AddPane(wx.Button(self, -1, "Test Button"), + wx.aui.AuiPaneInfo().Name("tb5"). + ToolbarPane().Top().Row(2).Position(1). + LeftDockable(False).RightDockable(False)) + + # make some default perspectives + + self._mgr.GetPane("tbvert").Hide() + + perspective_all = self._mgr.SavePerspective() + + all_panes = self._mgr.GetAllPanes() + + for ii in xrange(len(all_panes)): + if not all_panes[ii].IsToolbar(): + all_panes[ii].Hide() + + self._mgr.GetPane("tb1").Hide() + self._mgr.GetPane("tb5").Hide() + self._mgr.GetPane("test8").Show().Left().Layer(0).Row(0).Position(0) + self._mgr.GetPane("test10").Show().Bottom().Layer(0).Row(0).Position(0) + self._mgr.GetPane("html_content").Show() + + perspective_default = self._mgr.SavePerspective() + + for ii in xrange(len(all_panes)): + if not all_panes[ii].IsToolbar(): + all_panes[ii].Hide() + + self._mgr.GetPane("tb1").Hide() + self._mgr.GetPane("tb5").Hide() + self._mgr.GetPane("tbvert").Show() + self._mgr.GetPane("grid_content").Show() + self._mgr.GetPane("test8").Show().Left().Layer(0).Row(0).Position(0) + self._mgr.GetPane("test10").Show().Bottom().Layer(0).Row(0).Position(0) + self._mgr.GetPane("html_content").Show() + + perspective_vert = self._mgr.SavePerspective() + + self._perspectives.append(perspective_default) + self._perspectives.append(perspective_all) + self._perspectives.append(perspective_vert) + + self._mgr.GetPane("tbvert").Hide() + self._mgr.GetPane("grid_content").Hide() + + # "commit" all changes made to FrameManager + self._mgr.Update() + + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_CLOSE, self.OnClose) + + # Show How To Use The Closing Panes Event + self.Bind(wx.aui.EVT_AUI_PANE_CLOSE, self.OnPaneClose) + + self.Bind(wx.EVT_MENU, self.OnCreateTree, id=ID_CreateTree) + self.Bind(wx.EVT_MENU, self.OnCreateGrid, id=ID_CreateGrid) + self.Bind(wx.EVT_MENU, self.OnCreateText, id=ID_CreateText) + self.Bind(wx.EVT_MENU, self.OnCreateHTML, id=ID_CreateHTML) + self.Bind(wx.EVT_MENU, self.OnCreateSizeReport, id=ID_CreateSizeReport) + self.Bind(wx.EVT_MENU, self.OnCreatePerspective, id=ID_CreatePerspective) + self.Bind(wx.EVT_MENU, self.OnCopyPerspective, id=ID_CopyPerspective) + + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_AllowFloating) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_TransparentHint) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_VenetianBlindsHint) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_RectangleHint) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_NoHint) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_HintFade) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_NoVenetianFade) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_TransparentDrag) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_AllowActivePane) + + self.Bind(wx.EVT_MENU, self.OnGradient, id=ID_NoGradient) + self.Bind(wx.EVT_MENU, self.OnGradient, id=ID_VerticalGradient) + self.Bind(wx.EVT_MENU, self.OnGradient, id=ID_HorizontalGradient) + self.Bind(wx.EVT_MENU, self.OnSettings, id=ID_Settings) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_GridContent) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_TreeContent) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_TextContent) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_SizeReportContent) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_HTMLContent) + self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT) + self.Bind(wx.EVT_MENU, self.OnAbout, id=ID_About) + + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_TransparentHint) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_VenetianBlindsHint) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_RectangleHint) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NoHint) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_HintFade) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_AllowFloating) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NoVenetianFade) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_TransparentDrag) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_AllowActivePane) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NoGradient) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_VerticalGradient) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_HorizontalGradient) + + + self.Bind(wx.EVT_MENU_RANGE, self.OnRestorePerspective, id=ID_FirstPerspective, + id2=ID_FirstPerspective+1000) + + + def OnPaneClose(self, event): + + caption = event.GetPane().caption + + if caption in ["Tree Pane", "Dock Manager Settings", "Fixed Pane"]: + msg = "Are You Sure You Want To Close This Pane?" + dlg = wx.MessageDialog(self, msg, "AUI Question", + wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION) + + if dlg.ShowModal() in [wx.ID_NO, wx.ID_CANCEL]: + event.Veto() + dlg.Destroy() + + + def OnClose(self, event): + self._mgr.UnInit() + del self._mgr + self.Destroy() + + + def OnExit(self, event): + self.Close() + + def OnAbout(self, event): + + msg = "wx.aui Demo\n" + \ + "An advanced window management library for wxWidgets\n" + \ + "(c) Copyright 2005-2006, Kirix Corporation" + dlg = wx.MessageDialog(self, msg, "About wx.aui Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + + def GetDockArt(self): + + return self._mgr.GetArtProvider() + + + def DoUpdate(self): + + self._mgr.Update() + + + def OnEraseBackground(self, event): + + event.Skip() + + + def OnSize(self, event): + + event.Skip() + + + def OnSettings(self, event): + + # show the settings pane, and float it + floating_pane = self._mgr.GetPane("settings").Float().Show() + + if floating_pane.floating_pos == wx.DefaultPosition: + floating_pane.FloatingPosition(self.GetStartPosition()) + + self._mgr.Update() + + + def OnGradient(self, event): + + gradient = 0 + + if event.GetId() == ID_NoGradient: + gradient = wx.aui.AUI_GRADIENT_NONE + elif event.GetId() == ID_VerticalGradient: + gradient = wx.aui.AUI_GRADIENT_VERTICAL + elif event.GetId() == ID_HorizontalGradient: + gradient = wx.aui.AUI_GRADIENT_HORIZONTAL + + self._mgr.GetArtProvider().SetMetric(wx.aui.AUI_DOCKART_GRADIENT_TYPE, gradient) + self._mgr.Update() + + + def OnManagerFlag(self, event): + + flag = 0 + eid = event.GetId() + + if eid in [ ID_TransparentHint, ID_VenetianBlindsHint, ID_RectangleHint, ID_NoHint ]: + flags = self._mgr.GetFlags() + flags &= ~wx.aui.AUI_MGR_TRANSPARENT_HINT + flags &= ~wx.aui.AUI_MGR_VENETIAN_BLINDS_HINT + flags &= ~wx.aui.AUI_MGR_RECTANGLE_HINT + self._mgr.SetFlags(flags) + + if eid == ID_AllowFloating: + flag = wx.aui.AUI_MGR_ALLOW_FLOATING + elif eid == ID_TransparentDrag: + flag = wx.aui.AUI_MGR_TRANSPARENT_DRAG + elif eid == ID_HintFade: + flag = wx.aui.AUI_MGR_HINT_FADE + elif eid == ID_NoVenetianFade: + flag = wx.aui.AUI_MGR_NO_VENETIAN_BLINDS_FADE + elif eid == ID_AllowActivePane: + flag = wx.aui.AUI_MGR_ALLOW_ACTIVE_PANE + elif eid == ID_TransparentHint: + flag = wx.aui.AUI_MGR_TRANSPARENT_HINT + elif eid == ID_VenetianBlindsHint: + flag = wx.aui.AUI_MGR_VENETIAN_BLINDS_HINT + elif eid == ID_RectangleHint: + flag = wx.aui.AUI_MGR_RECTANGLE_HINT + + self._mgr.SetFlags(self._mgr.GetFlags() ^ flag) + + + def OnUpdateUI(self, event): + + flags = self._mgr.GetFlags() + eid = event.GetId() + + if eid == ID_NoGradient: + event.Check(self._mgr.GetArtProvider().GetMetric(wx.aui.AUI_DOCKART_GRADIENT_TYPE) == wx.aui.AUI_GRADIENT_NONE) + + elif eid == ID_VerticalGradient: + event.Check(self._mgr.GetArtProvider().GetMetric(wx.aui.AUI_DOCKART_GRADIENT_TYPE) == wx.aui.AUI_GRADIENT_VERTICAL) + + elif eid == ID_HorizontalGradient: + event.Check(self._mgr.GetArtProvider().GetMetric(wx.aui.AUI_DOCKART_GRADIENT_TYPE) == wx.aui.AUI_GRADIENT_HORIZONTAL) + + elif eid == ID_AllowFloating: + event.Check((flags & wx.aui.AUI_MGR_ALLOW_FLOATING) != 0) + + elif eid == ID_TransparentDrag: + event.Check((flags & wx.aui.AUI_MGR_TRANSPARENT_DRAG) != 0) + + elif eid == ID_TransparentHint: + event.Check((flags & wx.aui.AUI_MGR_TRANSPARENT_HINT) != 0) + + elif eid == ID_VenetianBlindsHint: + event.Check((flags & wx.aui.AUI_MGR_VENETIAN_BLINDS_HINT) != 0) + + elif eid == ID_RectangleHint: + event.Check((flags & wx.aui.AUI_MGR_RECTANGLE_HINT) != 0) + + elif eid == ID_NoHint: + event.Check(((wx.aui.AUI_MGR_TRANSPARENT_HINT | + wx.aui.AUI_MGR_VENETIAN_BLINDS_HINT | + wx.aui.AUI_MGR_RECTANGLE_HINT) & flags) == 0) + + elif eid == ID_HintFade: + event.Check((flags & wx.aui.AUI_MGR_HINT_FADE) != 0); + + elif eid == ID_NoVenetianFade: + event.Check((flags & wx.aui.AUI_MGR_NO_VENETIAN_BLINDS_FADE) != 0); + + + + + def OnCreatePerspective(self, event): + + dlg = wx.TextEntryDialog(self, "Enter a name for the new perspective:", "AUI Test") + + dlg.SetValue(("Perspective %d")%(len(self._perspectives)+1)) + if dlg.ShowModal() != wx.ID_OK: + return + + if len(self._perspectives) == 0: + self._perspectives_menu.AppendSeparator() + + self._perspectives_menu.Append(ID_FirstPerspective + len(self._perspectives), dlg.GetValue()) + self._perspectives.append(self._mgr.SavePerspective()) + + + def OnCopyPerspective(self, event): + + s = self._mgr.SavePerspective() + + if wx.TheClipboard.Open(): + + wx.TheClipboard.SetData(wx.TextDataObject(s)) + wx.TheClipboard.Close() + + def OnRestorePerspective(self, event): + + self._mgr.LoadPerspective(self._perspectives[event.GetId() - ID_FirstPerspective]) + + + def GetStartPosition(self): + + self.x = self.x + 20 + x = self.x + pt = self.ClientToScreen(wx.Point(0, 0)) + + return wx.Point(pt.x + x, pt.y + x) + + + def OnCreateTree(self, event): + self._mgr.AddPane(self.CreateTreeCtrl(), wx.aui.AuiPaneInfo(). + Caption("Tree Control"). + Float().FloatingPosition(self.GetStartPosition()). + FloatingSize(wx.Size(150, 300)).CloseButton(True).MaximizeButton(True)) + self._mgr.Update() + + + def OnCreateGrid(self, event): + self._mgr.AddPane(self.CreateGrid(), wx.aui.AuiPaneInfo(). + Caption("Grid"). + Float().FloatingPosition(self.GetStartPosition()). + FloatingSize(wx.Size(300, 200)).CloseButton(True).MaximizeButton(True)) + self._mgr.Update() + + + def OnCreateHTML(self, event): + self._mgr.AddPane(self.CreateHTMLCtrl(), wx.aui.AuiPaneInfo(). + Caption("HTML Content"). + Float().FloatingPosition(self.GetStartPosition()). + FloatingSize(wx.Size(300, 200)).CloseButton(True).MaximizeButton(True)) + self._mgr.Update() + + + def OnCreateText(self, event): + self._mgr.AddPane(self.CreateTextCtrl(), wx.aui.AuiPaneInfo(). + Caption("Text Control"). + Float().FloatingPosition(self.GetStartPosition()). + CloseButton(True).MaximizeButton(True)) + self._mgr.Update() + + + def OnCreateSizeReport(self, event): + self._mgr.AddPane(self.CreateSizeReportCtrl(), wx.aui.AuiPaneInfo(). + Caption("Client Size Reporter"). + Float().FloatingPosition(self.GetStartPosition()). + CloseButton(True).MaximizeButton(True)) + self._mgr.Update() + + + def OnChangeContentPane(self, event): + + self._mgr.GetPane("grid_content").Show(event.GetId() == ID_GridContent) + self._mgr.GetPane("text_content").Show(event.GetId() == ID_TextContent) + self._mgr.GetPane("tree_content").Show(event.GetId() == ID_TreeContent) + self._mgr.GetPane("sizereport_content").Show(event.GetId() == ID_SizeReportContent) + self._mgr.GetPane("html_content").Show(event.GetId() == ID_HTMLContent) + self._mgr.Update() + + + def CreateTextCtrl(self): + + text = ("This is text box %d")%(self.n + 1) + + return wx.TextCtrl(self,-1, text, wx.Point(0, 0), wx.Size(150, 90), + wx.NO_BORDER | wx.TE_MULTILINE) + + + + def CreateGrid(self): + + grid = wx.grid.Grid(self, -1, wx.Point(0, 0), wx.Size(150, 250), + wx.NO_BORDER | wx.WANTS_CHARS) + + grid.CreateGrid(50, 20) + + return grid + + + def CreateTreeCtrl(self): + + tree = wx.TreeCtrl(self, -1, wx.Point(0, 0), wx.Size(160, 250), + wx.TR_DEFAULT_STYLE | wx.NO_BORDER) + + root = tree.AddRoot("AUI Project") + items = [] + + imglist = wx.ImageList(16, 16, True, 2) + imglist.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, wx.Size(16,16))) + imglist.Add(wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16,16))) + tree.AssignImageList(imglist) + + items.append(tree.AppendItem(root, "Item 1", 0)) + items.append(tree.AppendItem(root, "Item 2", 0)) + items.append(tree.AppendItem(root, "Item 3", 0)) + items.append(tree.AppendItem(root, "Item 4", 0)) + items.append(tree.AppendItem(root, "Item 5", 0)) + + for ii in xrange(len(items)): + + id = items[ii] + tree.AppendItem(id, "Subitem 1", 1) + tree.AppendItem(id, "Subitem 2", 1) + tree.AppendItem(id, "Subitem 3", 1) + tree.AppendItem(id, "Subitem 4", 1) + tree.AppendItem(id, "Subitem 5", 1) + + tree.Expand(root) + + return tree + + + def CreateSizeReportCtrl(self, width=80, height=80): + + ctrl = SizeReportCtrl(self, -1, wx.DefaultPosition, + wx.Size(width, height), self._mgr) + return ctrl + + + def CreateHTMLCtrl(self): + ctrl = wx.html.HtmlWindow(self, -1, wx.DefaultPosition, wx.Size(400, 300)) + if "gtk2" in wx.PlatformInfo: + ctrl.SetStandardFonts() + ctrl.SetPage(self.GetIntroText()) + return ctrl + + + def GetIntroText(self): + return overview + + +# -- wx.SizeReportCtrl -- +# (a utility control that always reports it's client size) + +class SizeReportCtrl(wx.PyControl): + + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, + size=wx.DefaultSize, mgr=None): + + wx.PyControl.__init__(self, parent, id, pos, size, wx.NO_BORDER) + + self._mgr = mgr + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + + + def OnPaint(self, event): + + dc = wx.PaintDC(self) + + size = self.GetClientSize() + s = ("Size: %d x %d")%(size.x, size.y) + + dc.SetFont(wx.NORMAL_FONT) + w, height = dc.GetTextExtent(s) + height = height + 3 + dc.SetBrush(wx.WHITE_BRUSH) + dc.SetPen(wx.WHITE_PEN) + dc.DrawRectangle(0, 0, size.x, size.y) + dc.SetPen(wx.LIGHT_GREY_PEN) + dc.DrawLine(0, 0, size.x, size.y) + dc.DrawLine(0, size.y, size.x, 0) + dc.DrawText(s, (size.x-w)/2, ((size.y-(height*5))/2)) + + if self._mgr: + + pi = self._mgr.GetPane(self) + + s = ("Layer: %d")%pi.dock_layer + w, h = dc.GetTextExtent(s) + dc.DrawText(s, (size.x-w)/2, ((size.y-(height*5))/2)+(height*1)) + + s = ("Dock: %d Row: %d")%(pi.dock_direction, pi.dock_row) + w, h = dc.GetTextExtent(s) + dc.DrawText(s, (size.x-w)/2, ((size.y-(height*5))/2)+(height*2)) + + s = ("Position: %d")%pi.dock_pos + w, h = dc.GetTextExtent(s) + dc.DrawText(s, (size.x-w)/2, ((size.y-(height*5))/2)+(height*3)) + + s = ("Proportion: %d")%pi.dock_proportion + w, h = dc.GetTextExtent(s) + dc.DrawText(s, (size.x-w)/2, ((size.y-(height*5))/2)+(height*4)) + + + def OnEraseBackground(self, event): + # intentionally empty + pass + + + def OnSize(self, event): + + self.Refresh() + event.Skip() + + +ID_PaneBorderSize = wx.ID_HIGHEST + 1 +ID_SashSize = ID_PaneBorderSize + 1 +ID_CaptionSize = ID_PaneBorderSize + 2 +ID_BackgroundColor = ID_PaneBorderSize + 3 +ID_SashColor = ID_PaneBorderSize + 4 +ID_InactiveCaptionColor = ID_PaneBorderSize + 5 +ID_InactiveCaptionGradientColor = ID_PaneBorderSize + 6 +ID_InactiveCaptionTextColor = ID_PaneBorderSize + 7 +ID_ActiveCaptionColor = ID_PaneBorderSize + 8 +ID_ActiveCaptionGradientColor = ID_PaneBorderSize + 9 +ID_ActiveCaptionTextColor = ID_PaneBorderSize + 10 +ID_BorderColor = ID_PaneBorderSize + 11 +ID_GripperColor = ID_PaneBorderSize + 12 + +class SettingsPanel(wx.Panel): + + def __init__(self, parent, frame): + + wx.Panel.__init__(self, parent, wx.ID_ANY, wx.DefaultPosition, + wx.DefaultSize) + + self._frame = frame + + vert = wx.BoxSizer(wx.VERTICAL) + + s1 = wx.BoxSizer(wx.HORIZONTAL) + self._border_size = wx.SpinCtrl(self, ID_PaneBorderSize, "", wx.DefaultPosition, wx.Size(50,20)) + s1.Add((1, 1), 1, wx.EXPAND) + s1.Add(wx.StaticText(self, -1, "Pane Border Size:")) + s1.Add(self._border_size) + s1.Add((1, 1), 1, wx.EXPAND) + s1.SetItemMinSize(1, (180, 20)) + #vert.Add(s1, 0, wx.EXPAND | wxLEFT | wxBOTTOM, 5) + + s2 = wx.BoxSizer(wx.HORIZONTAL) + self._sash_size = wx.SpinCtrl(self, ID_SashSize, "", wx.DefaultPosition, wx.Size(50,20)) + s2.Add((1, 1), 1, wx.EXPAND) + s2.Add(wx.StaticText(self, -1, "Sash Size:")) + s2.Add(self._sash_size) + s2.Add((1, 1), 1, wx.EXPAND) + s2.SetItemMinSize(1, (180, 20)) + #vert.Add(s2, 0, wx.EXPAND | wxLEFT | wxBOTTOM, 5) + + s3 = wx.BoxSizer(wx.HORIZONTAL) + self._caption_size = wx.SpinCtrl(self, ID_CaptionSize, "", wx.DefaultPosition, wx.Size(50,20)) + s3.Add((1, 1), 1, wx.EXPAND) + s3.Add(wx.StaticText(self, -1, "Caption Size:")) + s3.Add(self._caption_size) + s3.Add((1, 1), 1, wx.EXPAND) + s3.SetItemMinSize(1, (180, 20)) + #vert.Add(s3, 0, wx.EXPAND | wxLEFT | wxBOTTOM, 5) + + #vert.Add(1, 1, 1, wx.EXPAND) + + b = self.CreateColorBitmap(wx.BLACK) + + s4 = wx.BoxSizer(wx.HORIZONTAL) + self._background_color = wx.BitmapButton(self, ID_BackgroundColor, b, wx.DefaultPosition, wx.Size(50,25)) + s4.Add((1, 1), 1, wx.EXPAND) + s4.Add(wx.StaticText(self, -1, "Background Color:")) + s4.Add(self._background_color) + s4.Add((1, 1), 1, wx.EXPAND) + s4.SetItemMinSize(1, (180, 20)) + + s5 = wx.BoxSizer(wx.HORIZONTAL) + self._sash_color = wx.BitmapButton(self, ID_SashColor, b, wx.DefaultPosition, wx.Size(50,25)) + s5.Add((1, 1), 1, wx.EXPAND) + s5.Add(wx.StaticText(self, -1, "Sash Color:")) + s5.Add(self._sash_color) + s5.Add((1, 1), 1, wx.EXPAND) + s5.SetItemMinSize(1, (180, 20)) + + s6 = wx.BoxSizer(wx.HORIZONTAL) + self._inactive_caption_color = wx.BitmapButton(self, ID_InactiveCaptionColor, b, + wx.DefaultPosition, wx.Size(50,25)) + s6.Add((1, 1), 1, wx.EXPAND) + s6.Add(wx.StaticText(self, -1, "Normal Caption:")) + s6.Add(self._inactive_caption_color) + s6.Add((1, 1), 1, wx.EXPAND) + s6.SetItemMinSize(1, (180, 20)) + + s7 = wx.BoxSizer(wx.HORIZONTAL) + self._inactive_caption_gradient_color = wx.BitmapButton(self, ID_InactiveCaptionGradientColor, + b, wx.DefaultPosition, wx.Size(50,25)) + s7.Add((1, 1), 1, wx.EXPAND) + s7.Add(wx.StaticText(self, -1, "Normal Caption Gradient:")) + s7.Add(self._inactive_caption_gradient_color) + s7.Add((1, 1), 1, wx.EXPAND) + s7.SetItemMinSize(1, (180, 20)) + + s8 = wx.BoxSizer(wx.HORIZONTAL) + self._inactive_caption_text_color = wx.BitmapButton(self, ID_InactiveCaptionTextColor, b, + wx.DefaultPosition, wx.Size(50,25)) + s8.Add((1, 1), 1, wx.EXPAND) + s8.Add(wx.StaticText(self, -1, "Normal Caption Text:")) + s8.Add(self._inactive_caption_text_color) + s8.Add((1, 1), 1, wx.EXPAND) + s8.SetItemMinSize(1, (180, 20)) + + s9 = wx.BoxSizer(wx.HORIZONTAL) + self._active_caption_color = wx.BitmapButton(self, ID_ActiveCaptionColor, b, + wx.DefaultPosition, wx.Size(50,25)) + s9.Add((1, 1), 1, wx.EXPAND) + s9.Add(wx.StaticText(self, -1, "Active Caption:")) + s9.Add(self._active_caption_color) + s9.Add((1, 1), 1, wx.EXPAND) + s9.SetItemMinSize(1, (180, 20)) + + s10 = wx.BoxSizer(wx.HORIZONTAL) + self._active_caption_gradient_color = wx.BitmapButton(self, ID_ActiveCaptionGradientColor, + b, wx.DefaultPosition, wx.Size(50,25)) + s10.Add((1, 1), 1, wx.EXPAND) + s10.Add(wx.StaticText(self, -1, "Active Caption Gradient:")) + s10.Add(self._active_caption_gradient_color) + s10.Add((1, 1), 1, wx.EXPAND) + s10.SetItemMinSize(1, (180, 20)) + + s11 = wx.BoxSizer(wx.HORIZONTAL) + self._active_caption_text_color = wx.BitmapButton(self, ID_ActiveCaptionTextColor, + b, wx.DefaultPosition, wx.Size(50,25)) + s11.Add((1, 1), 1, wx.EXPAND) + s11.Add(wx.StaticText(self, -1, "Active Caption Text:")) + s11.Add(self._active_caption_text_color) + s11.Add((1, 1), 1, wx.EXPAND) + s11.SetItemMinSize(1, (180, 20)) + + s12 = wx.BoxSizer(wx.HORIZONTAL) + self._border_color = wx.BitmapButton(self, ID_BorderColor, b, wx.DefaultPosition, + wx.Size(50,25)) + s12.Add((1, 1), 1, wx.EXPAND) + s12.Add(wx.StaticText(self, -1, "Border Color:")) + s12.Add(self._border_color) + s12.Add((1, 1), 1, wx.EXPAND) + s12.SetItemMinSize(1, (180, 20)) + + s13 = wx.BoxSizer(wx.HORIZONTAL) + self._gripper_color = wx.BitmapButton(self, ID_GripperColor, b, wx.DefaultPosition, + wx.Size(50,25)) + s13.Add((1, 1), 1, wx.EXPAND) + s13.Add(wx.StaticText(self, -1, "Gripper Color:")) + s13.Add(self._gripper_color) + s13.Add((1, 1), 1, wx.EXPAND) + s13.SetItemMinSize(1, (180, 20)) + + grid_sizer = wx.GridSizer(cols=2) + grid_sizer.SetHGap(5) + grid_sizer.Add(s1) + grid_sizer.Add(s4) + grid_sizer.Add(s2) + grid_sizer.Add(s5) + grid_sizer.Add(s3) + grid_sizer.Add(s13) + grid_sizer.Add((1, 1)) + grid_sizer.Add(s12) + grid_sizer.Add(s6) + grid_sizer.Add(s9) + grid_sizer.Add(s7) + grid_sizer.Add(s10) + grid_sizer.Add(s8) + grid_sizer.Add(s11) + + cont_sizer = wx.BoxSizer(wx.VERTICAL) + cont_sizer.Add(grid_sizer, 1, wx.EXPAND | wx.ALL, 5) + self.SetSizer(cont_sizer) + self.GetSizer().SetSizeHints(self) + + self._border_size.SetValue(frame.GetDockArt().GetMetric(wx.aui.AUI_DOCKART_PANE_BORDER_SIZE)) + self._sash_size.SetValue(frame.GetDockArt().GetMetric(wx.aui.AUI_DOCKART_SASH_SIZE)) + self._caption_size.SetValue(frame.GetDockArt().GetMetric(wx.aui.AUI_DOCKART_CAPTION_SIZE)) + + self.UpdateColors() + + self.Bind(wx.EVT_SPINCTRL, self.OnPaneBorderSize, id=ID_PaneBorderSize) + self.Bind(wx.EVT_SPINCTRL, self.OnSashSize, id=ID_SashSize) + self.Bind(wx.EVT_SPINCTRL, self.OnCaptionSize, id=ID_CaptionSize) + self.Bind(wx.EVT_BUTTON, self.OnSetColor, id=ID_BackgroundColor) + self.Bind(wx.EVT_BUTTON, self.OnSetColor, id=ID_SashColor) + self.Bind(wx.EVT_BUTTON, self.OnSetColor, id=ID_InactiveCaptionColor) + self.Bind(wx.EVT_BUTTON, self.OnSetColor, id=ID_InactiveCaptionGradientColor) + self.Bind(wx.EVT_BUTTON, self.OnSetColor, id=ID_InactiveCaptionTextColor) + self.Bind(wx.EVT_BUTTON, self.OnSetColor, id=ID_ActiveCaptionColor) + self.Bind(wx.EVT_BUTTON, self.OnSetColor, id=ID_ActiveCaptionGradientColor) + self.Bind(wx.EVT_BUTTON, self.OnSetColor, id=ID_ActiveCaptionTextColor) + self.Bind(wx.EVT_BUTTON, self.OnSetColor, id=ID_BorderColor) + self.Bind(wx.EVT_BUTTON, self.OnSetColor, id=ID_GripperColor) + + + def CreateColorBitmap(self, c): + image = wx.EmptyImage(25, 14) + + for x in xrange(25): + for y in xrange(14): + pixcol = c + if x == 0 or x == 24 or y == 0 or y == 13: + pixcol = wx.BLACK + + image.SetRGB(x, y, pixcol.Red(), pixcol.Green(), pixcol.Blue()) + + return image.ConvertToBitmap() + + + def UpdateColors(self): + + bk = self._frame.GetDockArt().GetColour(wx.aui.AUI_DOCKART_BACKGROUND_COLOUR) + self._background_color.SetBitmapLabel(self.CreateColorBitmap(bk)) + + cap = self._frame.GetDockArt().GetColour(wx.aui.AUI_DOCKART_INACTIVE_CAPTION_COLOUR) + self._inactive_caption_color.SetBitmapLabel(self.CreateColorBitmap(cap)) + + capgrad = self._frame.GetDockArt().GetColour(wx.aui.AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR) + self._inactive_caption_gradient_color.SetBitmapLabel(self.CreateColorBitmap(capgrad)) + + captxt = self._frame.GetDockArt().GetColour(wx.aui.AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR) + self._inactive_caption_text_color.SetBitmapLabel(self.CreateColorBitmap(captxt)) + + acap = self._frame.GetDockArt().GetColour(wx.aui.AUI_DOCKART_ACTIVE_CAPTION_COLOUR) + self._active_caption_color.SetBitmapLabel(self.CreateColorBitmap(acap)) + + acapgrad = self._frame.GetDockArt().GetColour(wx.aui.AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR) + self._active_caption_gradient_color.SetBitmapLabel(self.CreateColorBitmap(acapgrad)) + + acaptxt = self._frame.GetDockArt().GetColour(wx.aui.AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR) + self._active_caption_text_color.SetBitmapLabel(self.CreateColorBitmap(acaptxt)) + + sash = self._frame.GetDockArt().GetColour(wx.aui.AUI_DOCKART_SASH_COLOUR) + self._sash_color.SetBitmapLabel(self.CreateColorBitmap(sash)) + + border = self._frame.GetDockArt().GetColour(wx.aui.AUI_DOCKART_BORDER_COLOUR) + self._border_color.SetBitmapLabel(self.CreateColorBitmap(border)) + + gripper = self._frame.GetDockArt().GetColour(wx.aui.AUI_DOCKART_GRIPPER_COLOUR) + self._gripper_color.SetBitmapLabel(self.CreateColorBitmap(gripper)) + + + def OnPaneBorderSize(self, event): + + self._frame.GetDockArt().SetMetric(wx.aui.AUI_DOCKART_PANE_BORDER_SIZE, + event.GetInt()) + self._frame.DoUpdate() + + + def OnSashSize(self, event): + + self._frame.GetDockArt().SetMetric(wx.aui.AUI_DOCKART_SASH_SIZE, + event.GetInt()) + self._frame.DoUpdate() + + + def OnCaptionSize(self, event): + + self._frame.GetDockArt().SetMetric(wx.aui.AUI_DOCKART_CAPTION_SIZE, + event.GetInt()) + self._frame.DoUpdate() + + + def OnSetColor(self, event): + + dlg = wx.ColourDialog(self._frame) + + dlg.SetTitle("Color Picker") + + if dlg.ShowModal() != wx.ID_OK: + return + + var = 0 + if event.GetId() == ID_BackgroundColor: + var = wx.aui.AUI_DOCKART_BACKGROUND_COLOUR + elif event.GetId() == ID_SashColor: + var = wx.aui.AUI_DOCKART_SASH_COLOUR + elif event.GetId() == ID_InactiveCaptionColor: + var = wx.aui.AUI_DOCKART_INACTIVE_CAPTION_COLOUR + elif event.GetId() == ID_InactiveCaptionGradientColor: + var = wx.aui.AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR + elif event.GetId() == ID_InactiveCaptionTextColor: + var = wx.aui.AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR + elif event.GetId() == ID_ActiveCaptionColor: + var = wx.aui.AUI_DOCKART_ACTIVE_CAPTION_COLOUR + elif event.GetId() == ID_ActiveCaptionGradientColor: + var = wx.aui.AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR + elif event.GetId() == ID_ActiveCaptionTextColor: + var = wx.aui.AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR + elif event.GetId() == ID_BorderColor: + var = wx.aui.AUI_DOCKART_BORDER_COLOUR + elif event.GetId() == ID_GripperColor: + var = wx.aui.AUI_DOCKART_GRIPPER_COLOUR + else: + return + + self._frame.GetDockArt().SetColor(var, dlg.GetColourData().GetColour()) + self._frame.DoUpdate() + self.UpdateColors() + + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + b = wx.Button(self, -1, "Show the wx.aui Demo Frame", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + def OnButton(self, evt): + frame = PyAUIFrame(self, wx.ID_ANY, "wx.aui wxPython Demo", size=(750, 590)) + frame.Show() + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """\ + +

wx.aui, the Advanced User Interface module

+ +
Overview
+ +

wx.aui is an Advanced User Interface library for the wxWidgets toolkit +that allows developers to create high-quality, cross-platform user +interfaces quickly and easily.

+ +

Features

+ +

With wx.aui developers can create application frameworks with:

+ + + + +""" + + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/AUI_MDI.py b/demo/AUI_MDI.py new file mode 100644 index 00000000..50bbb6d3 --- /dev/null +++ b/demo/AUI_MDI.py @@ -0,0 +1,111 @@ + +import wx +import wx.aui + +#---------------------------------------------------------------------- + + +class ParentFrame(wx.aui.AuiMDIParentFrame): + def __init__(self, parent): + wx.aui.AuiMDIParentFrame.__init__(self, parent, -1, + title="AuiMDIParentFrame", + size=(640,480), + style=wx.DEFAULT_FRAME_STYLE) + self.count = 0 + mb = self.MakeMenuBar() + self.SetMenuBar(mb) + self.CreateStatusBar() + self.Bind(wx.EVT_CLOSE, self.OnDoClose) + + def MakeMenuBar(self): + mb = wx.MenuBar() + menu = wx.Menu() + item = menu.Append(-1, "New child window\tCtrl-N") + self.Bind(wx.EVT_MENU, self.OnNewChild, item) + item = menu.Append(-1, "Close parent") + self.Bind(wx.EVT_MENU, self.OnDoClose, item) + mb.Append(menu, "&File") + return mb + + def OnNewChild(self, evt): + self.count += 1 + child = ChildFrame(self, self.count) + child.Activate() + + def OnDoClose(self, evt): + # Close all ChildFrames first else Python crashes + for m in self.GetChildren(): + if isinstance(m, wx.aui.AuiMDIClientWindow): + for k in m.GetChildren(): + if isinstance(k, ChildFrame): + k.Close() + evt.Skip() + + +#---------------------------------------------------------------------- + +class ChildFrame(wx.aui.AuiMDIChildFrame): + def __init__(self, parent, count): + wx.aui.AuiMDIChildFrame.__init__(self, parent, -1, + title="Child: %d" % count) + mb = parent.MakeMenuBar() + menu = wx.Menu() + item = menu.Append(-1, "This is child %d's menu" % count) + mb.Append(menu, "&Child") + self.SetMenuBar(mb) + + p = wx.Panel(self) + wx.StaticText(p, -1, "This is child %d" % count, (10,10)) + p.SetBackgroundColour('light blue') + + sizer = wx.BoxSizer() + sizer.Add(p, 1, wx.EXPAND) + self.SetSizer(sizer) + + wx.CallAfter(self.Layout) + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show a AuiMDIParentFrame", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + pf = ParentFrame(self) + pf.Show() + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.aui.AuiMDI

+ +The wx.aui.AuiMDIParentFrame and wx.aui.AuiMDIChildFrame classes +implement the same API as wx.MDIParentFrame and wx.MDIChildFrame, but +implement the multiple document interface with a wx.aui.AuiNotebook. + + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/AUI_Notebook.py b/demo/AUI_Notebook.py new file mode 100644 index 00000000..2d0a8495 --- /dev/null +++ b/demo/AUI_Notebook.py @@ -0,0 +1,57 @@ + +import wx +import wx.aui + + +text = """\ +Hello! + +Welcome to this little demo of draggable tabs using the wx.aui module. + +To try it out, drag a tab from the top of the window all the way to the bottom. After releasing the mouse, the tab will dock at the hinted position. Then try it again with the remaining tabs in various other positions. Finally, try dragging a tab to an existing tab ctrl. You'll soon see that very complex tab layouts may be achieved. +""" + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + self.nb = wx.aui.AuiNotebook(self) + page = wx.TextCtrl(self.nb, -1, text, style=wx.TE_MULTILINE) + self.nb.AddPage(page, "Welcome") + + for num in range(1, 5): + page = wx.TextCtrl(self.nb, -1, "This is page %d" % num , + style=wx.TE_MULTILINE) + self.nb.AddPage(page, "Tab Number %d" % num) + + sizer = wx.BoxSizer() + sizer.Add(self.nb, 1, wx.EXPAND) + self.SetSizer(sizer) + wx.CallAfter(self.nb.SendSizeEvent) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Say something nice here

+ + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/About.py b/demo/About.py new file mode 100644 index 00000000..c9ea6ed1 --- /dev/null +++ b/demo/About.py @@ -0,0 +1,74 @@ +import sys + +import wx # This module uses the new wx namespace +import wx.html +import wx.lib.wxpTag + +#--------------------------------------------------------------------------- + +class MyAboutBox(wx.Dialog): + text = ''' + + +
+ + + +
+

wxPython %s

+ (%s)
+ Running on Python %s
+
+ +

wxPython is a Python extension module that +encapsulates the wxWindows GUI classes.

+ +

This demo shows off some of the capabilities +of wxPython. Select items from the menu or tree control, +sit back and enjoy. Be sure to take a peek at the source code for each +demo item so you can learn how to use the classes yourself.

+ +

wxPython is brought to you by Robin Dunn and
+Total Control Software, Copyright (c) 1997-2011.

+ +

+Please see license.txt for licensing information. +

+ +

+ + +

+
+ + +''' + def __init__(self, parent): + wx.Dialog.__init__(self, parent, -1, 'About the wxPython demo',) + html = wx.html.HtmlWindow(self, -1, size=(420, -1)) + if "gtk2" in wx.PlatformInfo: + html.SetStandardFonts() + py_version = sys.version.split()[0] + txt = self.text % (wx.VERSION_STRING, + ", ".join(wx.PlatformInfo[1:]), + py_version + ) + html.SetPage(txt) + btn = html.FindWindowById(wx.ID_OK) + ir = html.GetInternalRepresentation() + html.SetSize( (ir.GetWidth()+25, ir.GetHeight()+25) ) + self.SetClientSize(html.GetSize()) + self.CentreOnParent(wx.BOTH) + +#--------------------------------------------------------------------------- + + + +if __name__ == '__main__': + app = wx.PySimpleApp() + dlg = MyAboutBox(None) + dlg.ShowModal() + dlg.Destroy() + app.MainLoop() + diff --git a/demo/AboutBox.py b/demo/AboutBox.py new file mode 100644 index 00000000..fdec097b --- /dev/null +++ b/demo/AboutBox.py @@ -0,0 +1,73 @@ + +import wx +from wx.lib.wordwrap import wordwrap + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show a wx.AboutBox", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + # First we create and fill the info object + info = wx.AboutDialogInfo() + info.Name = "Hello World" + info.Version = "1.2.3" + info.Copyright = "(C) 2006 Programmers and Coders Everywhere" + info.Description = wordwrap( + "A \"hello world\" program is a software program that prints out " + "\"Hello world!\" on a display device. It is used in many introductory " + "tutorials for teaching a programming language." + + "\n\nSuch a program is typically one of the simplest programs possible " + "in a computer language. A \"hello world\" program can be a useful " + "sanity test to make sure that a language's compiler, development " + "environment, and run-time environment are correctly installed.", + 350, wx.ClientDC(self)) + info.WebSite = ("http://en.wikipedia.org/wiki/Hello_world", "Hello World home page") + info.Developers = [ "Joe Programmer", + "Jane Coder", + "Vippy the Mascot" ] + + info.License = wordwrap(licenseText, 500, wx.ClientDC(self)) + + # Then we call wx.AboutBox giving it that info object + wx.AboutBox(info) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.AboutBox

+ +This function shows the native standard about dialog containing the +information specified in info. If the current platform has a native +about dialog which is capable of showing all the fields in info, the +native dialog is used, otherwise the function falls back to the +generic wxWidgets version of the dialog. + + +""" + + +licenseText = "blah " * 250 + "\n\n" +"yadda " * 100 + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ActiveXWrapper_Acrobat.py b/demo/ActiveXWrapper_Acrobat.py new file mode 100644 index 00000000..e6cc8f02 --- /dev/null +++ b/demo/ActiveXWrapper_Acrobat.py @@ -0,0 +1,130 @@ +""" + +This demo shows how to embed an ActiveX control in a wxPython application, (Win32 only.) +

+The MakeActiveXClass function dynamically builds a new Class on the fly, that has the +same signature and semantics as wxWindow. This means that when you call the function +you get back a new class that you can use just like wxWindow, (set the size and position, +use in a sizer, etc.) except its contents will be the COM control. +

+This demo embeds the Adobe Acrobat Reader, and gives you some buttons for opening a PDF +file, changing pages, etc. that show how to call methods on the COM object. If you don't +have Acrobat Reader 4.0 installed it won't work. + +""" + +import wx + +if wx.Platform == '__WXMSW__': + from wx.lib.activexwrapper import MakeActiveXClass + import win32com.client.gencache + + try: + #acrobat = win32com.client.gencache.EnsureModule('{CA8A9783-280D-11CF-A24D-444553540000}', 0x0, 1, 3) + acrobat = win32com.client.gencache.EnsureModule('{05BFD3F1-6319-4F30-B752-C7A22889BCC4}', 0x0, 1, 0) + except: + raise ImportError("Can't load PDF.OCX, install Acrobat 4.0") + + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.pdf = None + + sizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + + # this function creates a new class that can be used as + # a wxWindow, but contains the given ActiveX control. + ActiveXWrapper = MakeActiveXClass(acrobat.AcroPDF) + + # create an instance of the new class + self.pdf = ActiveXWrapper( self, -1, style=wx.SUNKEN_BORDER) + + sizer.Add(self.pdf, 1, wx.EXPAND) + + btn = wx.Button(self, wx.NewId(), "Open PDF File") + wx.EVT_BUTTON(self, btn.GetId(), self.OnOpenButton) + btnSizer.Add(btn, 1, wx.EXPAND|wx.ALL, 5) + + btn = wx.Button(self, wx.NewId(), "<-- Previous Page") + wx.EVT_BUTTON(self, btn.GetId(), self.OnPrevPageButton) + btnSizer.Add(btn, 1, wx.EXPAND|wx.ALL, 5) + + btn = wx.Button(self, wx.NewId(), "Next Page -->") + wx.EVT_BUTTON(self, btn.GetId(), self.OnNextPageButton) + btnSizer.Add(btn, 1, wx.EXPAND|wx.ALL, 5) + + + btnSizer.Add((50, -1), 2, wx.EXPAND) + sizer.Add(btnSizer, 0, wx.EXPAND) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + wx.EVT_WINDOW_DESTROY(self, self.OnDestroy) + + + def OnDestroy(self, evt): + if self.pdf: + self.pdf.Cleanup() + self.pdf = None + + + + def OnOpenButton(self, event): + dlg = wx.FileDialog(self, wildcard="*.pdf") + if dlg.ShowModal() == wx.ID_OK: + wx.BeginBusyCursor() + self.pdf.LoadFile(dlg.GetPath()) + wx.EndBusyCursor() + + dlg.Destroy() + + + def OnPrevPageButton(self, event): + self.pdf.gotoPreviousPage() + + + def OnNextPageButton(self, event): + self.pdf.gotoNextPage() + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + if wxPlatform == '__WXMSW__': + win = TestPanel(nb, log) + return win + else: + dlg = wx.MessageDialog(frame, 'This demo only works on MSW.', + 'Sorry', wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +overview = __doc__ + +#---------------------------------------------------------------------- + + +if __name__ == '__main__': + import sys + class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "ActiveX test -- Acrobat", size=(640, 480), + style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE) + self.tp = TestPanel(self, sys.stdout) + + + app = wx.PySimpleApp() + frame = TestFrame() + frame.Show(True) + app.MainLoop() + + + diff --git a/demo/ActiveXWrapper_IE.py b/demo/ActiveXWrapper_IE.py new file mode 100644 index 00000000..fa1a9e4a --- /dev/null +++ b/demo/ActiveXWrapper_IE.py @@ -0,0 +1,186 @@ + +import wx + +from wx.lib.activexwrapper import MakeActiveXClass +import win32com.client.gencache +browserModule = win32com.client.gencache.EnsureModule( + "{EAB22AC0-30C1-11CF-A7EB-0000C05BAE0B}", 0, 1, 1) + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Window): + def __init__(self, parent, frame=None): + wx.Window.__init__(self, parent) + self.ie = None + self.current = "http://wxPython.org/" + self.frame = frame + if frame: + self.titleBase = frame.GetTitle() + + + sizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + + # Make a new class that derives from the WebBrowser class in the + # COM module imported above. This class also derives from wxWindow and + # implements the machinery needed to integrate the two worlds. + theClass = MakeActiveXClass(browserModule.WebBrowser, eventObj=self) + + # Create an instance of that class + self.ie = theClass(self, -1) + + + btn = wx.Button(self, wx.NewId(), "Open", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, wx.NewId(), "Home", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnHomeButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, wx.NewId(), "<--", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, wx.NewId(), "-->", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, wx.NewId(), "Stop", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnStopButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, wx.NewId(), "Search", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnSearchPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, wx.NewId(), "Refresh", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnRefreshPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + txt = wx.StaticText(self, -1, "Location:") + btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2) + + self.location = wx.ComboBox(self, wx.NewId(), "", style=wx.CB_DROPDOWN) + self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location) + self.location.Bind(wx.EVT_KEY_UP, self.OnLocationKey) + self.location.Bind(wx.EVT_CHAR, self.IgnoreReturn) + btnSizer.Add(self.location, 1, wx.EXPAND|wx.ALL, 2) + + sizer.Add(btnSizer, 0, wx.EXPAND) + sizer.Add(self.ie, 1, wx.EXPAND) + + self.ie.Navigate2(self.current) + self.location.Append(self.current) + + self.SetSizer(sizer) + + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) + + + + def OnDestroy(self, evt): + if self.ie: + self.ie.Cleanup() + self.ie = None + self.frame = None + + + def OnSize(self, evt): + self.Layout() + + + def OnLocationSelect(self, evt): + url = self.location.GetStringSelection() + self.ie.Navigate2(url) + + def OnLocationKey(self, evt): + if evt.KeyCode() == wx.WXK_RETURN: + URL = self.location.GetValue() + self.location.Append(URL) + self.ie.Navigate2(URL) + else: + evt.Skip() + + def IgnoreReturn(self, evt): + if evt.KeyCode() != wx.WXK_RETURN: + evt.Skip() + + def OnOpenButton(self, event): + dlg = wx.TextEntryDialog(self, "Open Location", + "Enter a full URL or local path", + self.current, wx.OK|wx.CANCEL) + dlg.CentreOnParent() + if dlg.ShowModal() == wx.ID_OK: + self.current = dlg.GetValue() + self.ie.Navigate2(self.current) + dlg.Destroy() + + def OnHomeButton(self, event): + self.ie.GoHome() + + def OnPrevPageButton(self, event): + self.ie.GoBack() + + def OnNextPageButton(self, event): + self.ie.GoForward() + + def OnStopButton(self, evt): + self.ie.Stop() + + def OnSearchPageButton(self, evt): + self.ie.GoSearch() + + def OnRefreshPageButton(self, evt): + self.ie.Refresh2(3) + + + + # The following event handlers are called by the web browser COM + # control since we passed self to MakeActiveXClass. It will look + # here for matching attributes and call them if they exist. See the + # module generated by makepy for details of method names, etc. + def OnNavigateComplete2(self, pDisp, URL): + self.current = URL + self.location.SetValue(URL) + + def OnTitleChange(self, text): + if self.frame: + self.frame.SetTitle(self.titleBase + ' -- ' + text) + + def OnStatusTextChange(self, text): + if self.frame: + self.frame.SetStatusText(text) + + +#---------------------------------------------------------------------- + + +if __name__ == '__main__': + class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "ActiveX test -- Internet Explorer", + size=(640, 480)) + self.CreateStatusBar() + self.tp = TestPanel(self, frame=self) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + def OnCloseWindow(self, evt): + self.tp.Destroy() + self.Destroy() + + app = wx.PySimpleApp() + frame = TestFrame() + frame.Show(True) + + import wx.py + shell = wx.py.shell.ShellFrame(frame, size=(640,480), + locals=dict(wx=wx, frame=frame, ie=frame.tp.ie)) + shell.Show() + frame.Raise() + app.MainLoop() + + + diff --git a/demo/ActiveX_FlashWindow.py b/demo/ActiveX_FlashWindow.py new file mode 100644 index 00000000..dfc3b103 --- /dev/null +++ b/demo/ActiveX_FlashWindow.py @@ -0,0 +1,105 @@ +import os +import wx + +if wx.Platform == '__WXMSW__': + from wx.lib.flashwin import FlashWindow + +from Main import opj + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, style=0) + self.pdf = None + + sizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + + self.flash = FlashWindow(self, style=wx.SUNKEN_BORDER) + self.flash.LoadMovie(0, 'file://' + os.path.abspath('data/Asteroid_blaster.swf')) + + sizer.Add(self.flash, proportion=1, flag=wx.EXPAND) + + btn = wx.Button(self, wx.NewId(), "Open Flash File") + self.Bind(wx.EVT_BUTTON, self.OnOpenFileButton, btn) + btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5) + + btn = wx.Button(self, wx.NewId(), "Open Flash URL") + self.Bind(wx.EVT_BUTTON, self.OnOpenURLButton, btn) + btnSizer.Add(btn, proportion=1, flag=wx.EXPAND|wx.ALL, border=5) + + btnSizer.Add((50,-1), proportion=2, flag=wx.EXPAND) + sizer.Add(btnSizer, proportion=0, flag=wx.EXPAND) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + + + def OnOpenFileButton(self, event): + dlg = wx.FileDialog(self, wildcard="*.swf") + + if dlg.ShowModal() == wx.ID_OK: + wx.BeginBusyCursor() + self.flash.LoadMovie(0, 'file://' + dlg.GetPath()) + wx.EndBusyCursor() + + dlg.Destroy() + + + def OnOpenURLButton(self, event): + dlg = wx.TextEntryDialog(self, "Enter a URL of a .swf file", "Enter URL") + + if dlg.ShowModal() == wx.ID_OK: + wx.BeginBusyCursor() + # setting the movie property works too + self.flash.movie = dlg.GetValue() + wx.EndBusyCursor() + + dlg.Destroy() + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + if wx.Platform == '__WXMSW__': + win = TestPanel(nb, log) + return win + else: + from wx.lib.msgpanel import MessagePanel + win = MessagePanel(nb, 'This demo only works on Microsoft Windows.', + 'Sorry', wx.ICON_WARNING) + return win + + +overview = """\ + +

wx.lib.flashwin.FlashWindow

+ +The wx.lib.pdfwin.FlashWindow class is yet another example of using +ActiveX controls from wxPython using the new wx.activex module. This +allows you to use an ActiveX control as if it is a wx.Window, you can +call its methods, set/get properties, and receive events from the +ActiveX control in a very intuitive way. + +

Using this class is simpler than ActiveXWrapper, doesn't rely on +the win32all extensions, and is more "wx\'ish", meaning that it uses +events and etc. as would be expected from any other wx window. + +

This demo embeds the Shockwave Flash control, and lets you play a game. + + +""" + +#---------------------------------------------------------------------- + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/ActiveX_IEHtmlWindow.py b/demo/ActiveX_IEHtmlWindow.py new file mode 100644 index 00000000..414128e0 --- /dev/null +++ b/demo/ActiveX_IEHtmlWindow.py @@ -0,0 +1,240 @@ +# 11/18/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Updated for wx namespace +# + +import wx + +if wx.Platform == '__WXMSW__': + import wx.lib.iewin as iewin + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log, frame=None): + wx.Panel.__init__( + self, parent, -1, + style=wx.TAB_TRAVERSAL|wx.CLIP_CHILDREN|wx.NO_FULL_REPAINT_ON_RESIZE + ) + + self.log = log + self.current = "http://wxPython.org/" + self.frame = frame + + if frame: + self.titleBase = frame.GetTitle() + + sizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + + self.ie = iewin.IEHtmlWindow(self) + + + btn = wx.Button(self, -1, "Open", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, -1, "Home", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnHomeButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, -1, "<--", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoBack, btn) + + btn = wx.Button(self, -1, "-->", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoForward, btn) + + btn = wx.Button(self, -1, "Stop", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnStopButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, -1, "Search", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnSearchPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, -1, "Refresh", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnRefreshPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + txt = wx.StaticText(self, -1, "Location:") + btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2) + + self.location = wx.ComboBox( + self, -1, "", style=wx.CB_DROPDOWN|wx.PROCESS_ENTER + ) + + self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location) + self.location.Bind(wx.EVT_KEY_UP, self.OnLocationKey) + self.location.Bind(wx.EVT_CHAR, self.IgnoreReturn) + btnSizer.Add(self.location, 1, wx.EXPAND|wx.ALL, 2) + + sizer.Add(btnSizer, 0, wx.EXPAND) + sizer.Add(self.ie, 1, wx.EXPAND) + + self.ie.LoadUrl(self.current) + self.location.Append(self.current) + + self.SetSizer(sizer) + # Since this is a wx.Window we have to call Layout ourselves + self.Bind(wx.EVT_SIZE, self.OnSize) + + + ## Hook up the event handlers for the IE window. Using + ## AddEventSink is how we tell the COM system to look in this + ## object for method names matching the COM Event names. They + ## are automatically looked for in the ActiveXCtrl class, (so + ## deriving a new class from IEHtmlWindow would also have been + ## a good appraoch) and now they will be looked for here too. + self.ie.AddEventSink(self) + + + + def ShutdownDemo(self): + # put the frame title back + if self.frame: + self.frame.SetTitle(self.titleBase) + + + def OnSize(self, evt): + self.Layout() + + def OnLocationSelect(self, evt): + url = self.location.GetStringSelection() + self.log.write('OnLocationSelect: %s\n' % url) + self.ie.Navigate(url) + + def OnLocationKey(self, evt): + if evt.GetKeyCode() == wx.WXK_RETURN: + URL = self.location.GetValue() + self.location.Append(URL) + self.ie.Navigate(URL) + else: + evt.Skip() + + + def IgnoreReturn(self, evt): + if evt.GetKeyCode() != wx.WXK_RETURN: + evt.Skip() + + def OnOpenButton(self, event): + dlg = wx.TextEntryDialog(self, "Open Location", + "Enter a full URL or local path", + self.current, wx.OK|wx.CANCEL) + dlg.CentreOnParent() + + if dlg.ShowModal() == wx.ID_OK: + self.current = dlg.GetValue() + self.ie.Navigate(self.current) + + dlg.Destroy() + + def OnHomeButton(self, event): + self.ie.GoHome() ## ET Phone Home! + + def OnPrevPageButton(self, event): + self.ie.GoBack() + + def OnNextPageButton(self, event): + self.ie.GoForward() + + def OnCheckCanGoBack(self, event): + event.Enable(self.ie.CanGoBack()) + + def OnCheckCanGoForward(self, event): + event.Enable(self.ie.CanGoForward()) + + def OnStopButton(self, evt): + self.ie.Stop() + + def OnSearchPageButton(self, evt): + self.ie.GoSearch() + + def OnRefreshPageButton(self, evt): + self.ie.Refresh(iewin.REFRESH_COMPLETELY) + + + # Here are some of the event methods for the IE COM events. See + # the MSDN docs for DWebBrowserEvents2 for details on what events + # are available, and what the parameters are. + + def BeforeNavigate2(self, this, pDisp, URL, Flags, TargetFrameName, + PostData, Headers, Cancel): + self.log.write('BeforeNavigate2: %s\n' % URL[0]) + if URL[0] == 'http://www.microsoft.com/': + if wx.MessageBox("Are you sure you want to visit Microsoft?", + style=wx.YES_NO|wx.ICON_QUESTION) == wx.NO: + # This is how you can cancel loading a page. The + # Cancel parameter is defined as an [in,out] type and + # so setting the value means it will be returned and + # checked in the COM control. + Cancel[0] = True + + + def NewWindow3(self, this, pDisp, Cancel, Flags, urlContext, URL): + self.log.write('NewWindow3: %s\n' % URL) + Cancel[0] = True # Veto the creation of a new window. + + #def ProgressChange(self, this, progress, progressMax): + # self.log.write('ProgressChange: %d of %d\n' % (progress, progressMax)) + + def DocumentComplete(self, this, pDisp, URL): + self.current = URL[0] + self.location.SetValue(self.current) + + def TitleChange(self, this, Text): + if self.frame: + self.frame.SetTitle(self.titleBase + ' -- ' + Text) + + def StatusTextChange(self, this, Text): + if self.frame: + self.frame.SetStatusText(Text) + + + +#---------------------------------------------------------------------- +# for the demo framework... + +def runTest(frame, nb, log): + if wx.Platform == '__WXMSW__': + win = TestPanel(nb, log, frame) + return win + else: + from wx.lib.msgpanel import MessagePanel + win = MessagePanel(nb, 'This demo only works on Microsoft Windows.', + 'Sorry', wx.ICON_WARNING) + return win + + + +overview = """\ + +

wx.lib.iewin.IEHtmlWindow

+ +The wx.lib.iewin.IEHtmlWindow class is one example of using ActiveX +controls from wxPython using the new wx.activex module. This allows +you to use an ActiveX control as if it is a wx.Window, you can call +its methods, set/get properties, and receive events from the ActiveX +control in a very intuitive way. + +

Using this class is simpler than ActiveXWrapper, doesn't rely on +the win32all extensions, and is more "wx\'ish", meaning that it uses +events and etc. as would be expected from any other wx window. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + +#---------------------------------------------------------------------- + diff --git a/demo/ActiveX_PDFWindow.py b/demo/ActiveX_PDFWindow.py new file mode 100644 index 00000000..cf009ed9 --- /dev/null +++ b/demo/ActiveX_PDFWindow.py @@ -0,0 +1,202 @@ +import sys +import wx + +if wx.Platform == '__WXMSW__': + from wx.lib.pdfwin import PDFWindow + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + + mainsizer = wx.BoxSizer(wx.HORIZONTAL) + leftsizer = wx.BoxSizer(wx.VERTICAL) + self.pdf = PDFWindow(self, style=wx.SUNKEN_BORDER) + leftsizer.Add(self.pdf, proportion=1, flag=wx.EXPAND) + + box = wx.StaticBox(self, wx.NewId(), "" ) + buttonsizer = wx.StaticBoxSizer(box, wx.HORIZONTAL ) + + b1 = wx.Button(self, wx.NewId(), "First") + buttonsizer.Add(b1, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5) + self.Bind(wx.EVT_BUTTON, self.OnFirstPageButton, b1) + + b2 = wx.Button(self, wx.NewId(), "Previous") + buttonsizer.Add(b2, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5) + self.Bind(wx.EVT_BUTTON, self.OnPreviousPageButton, b2) + + tx1 = wx.StaticText(self, wx.NewId(), " Go to page" ) + buttonsizer.Add(tx1, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5) + tc1 = wx.TextCtrl(self, wx.NewId(), "0", size=[30,-1]) + buttonsizer.Add( tc1, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5) + self.Bind(wx.EVT_TEXT, self.OnGotoPage, tc1) + + b3 = wx.Button(self, wx.NewId(), "Next") + buttonsizer.Add(b3, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5) + self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, b3) + + b4 = wx.Button(self, wx.NewId(), "Last") + buttonsizer.Add(b4, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5) + self.Bind(wx.EVT_BUTTON, self.OnLastPageButton, b4) + + tx2 = wx.StaticText(self, wx.NewId(), " Zoom") + buttonsizer.Add(tx2, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5) + + ch1 = wx.Choice(self, wx.NewId(), + choices=["Default", "Fit", "FitH", "FitV", + "25%", "50%", "75%", "100%", "125%", "200%", "400%"]) + ch1.SetSelection(0) + buttonsizer.Add(ch1, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=5) + self.Bind(wx.EVT_CHOICE, self.OnZoom, ch1) + + leftsizer.Add(buttonsizer, proportion=0) + mainsizer.Add(leftsizer, proportion=1, flag=wx.GROW|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, border=5) + + box = wx.StaticBox(self, wx.NewId(), "" ) + rightsizer = wx.StaticBoxSizer(box, wx.VERTICAL) + + b5 = wx.Button(self, wx.NewId(), "Load PDF") + rightsizer.Add(b5, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5) + self.Bind(wx.EVT_BUTTON, self.OnLoadButton, b5) + + b6 = wx.Button(self, wx.NewId(), "Print") + rightsizer.Add(b6, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5) + self.Bind(wx.EVT_BUTTON, self.OnPrintButton, b6) + + tx3 = wx.StaticText(self, wx.NewId(), "Page mode:") + rightsizer.Add(tx3, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5) + + ch2 = wx.Choice(self, wx.NewId(),size=[100,-1], + choices=["None", "Bookmarks", "Thumbs"]) + ch2.SetSelection(0) + rightsizer.Add(ch2, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5) + self.Bind(wx.EVT_CHOICE, self.OnPageMode, ch2) + + tx4 = wx.StaticText(self, wx.NewId(), "Layout mode:") + rightsizer.Add(tx4, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5) + + ch3 = wx.Choice(self, wx.NewId(),size=[100,-1], + choices=["DontCare", "SinglePage", + "OneColumn", "TwoColumnLeft", "TwoColumnRight" ]) + ch3.SetSelection(0) + rightsizer.Add(ch3, proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5) + self.Bind(wx.EVT_CHOICE, self.OnLayoutMode, ch3) + + cx1 = wx.CheckBox(self, wx.NewId(), "Toolbar") + cx1.SetValue( True ) + rightsizer.Add( cx1,proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5) + self.Bind(wx.EVT_CHECKBOX, self.OnToolbar, cx1) + + cx2 = wx.CheckBox(self, wx.NewId(), "Scrollbars") + cx2.SetValue( True ) + rightsizer.Add( cx2,proportion=0, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=5) + self.Bind(wx.EVT_CHECKBOX, self.OnScrollbars, cx2) + + mainsizer.Add( rightsizer, proportion=0, flag=wx.ALL, border=15) + self.SetSizer(mainsizer) + self.SetAutoLayout(True) + + def OnFirstPageButton(self, event): + self.pdf.gotoFirstPage() + + def OnPreviousPageButton(self, event): + self.pdf.gotoPreviousPage() + + def OnNextPageButton(self, event): + self.pdf.gotoNextPage() + + def OnLastPageButton(self, event): + self.pdf.gotoLastPage() + + def OnGotoPage(self, event): + npage = event.GetEventObject().GetValue() + try: + self.pdf.setCurrentPage(int(npage)) + except ValueError: + pass + + def OnZoom(self, event): + astring = event.GetEventObject().GetStringSelection() + if astring.startswith('Fit'): + self.pdf.setView(astring) + else: + try: + percent = float(astring.replace('%','')) + self.pdf.setZoom(percent) + except ValueError: + pass + + def OnLoadButton(self, event): + dlg = wx.FileDialog(self, wildcard="*.pdf") + if dlg.ShowModal() == wx.ID_OK: + wx.BeginBusyCursor() + self.pdf.LoadFile(dlg.GetPath()) + wx.EndBusyCursor() + dlg.Destroy() + + def OnPrintButton(self, event): + self.pdf.Print() + + def OnPageMode(self, event): + astring = event.GetEventObject().GetStringSelection() + self.pdf.setPageMode(astring.lower()) + + def OnLayoutMode(self, event): + astring = event.GetEventObject().GetStringSelection() + self.pdf.setLayoutMode(astring) + + def OnToolbar(self, event): + on = event.GetEventObject().GetValue() + self.pdf.setShowToolbar(on) + + def OnScrollbars(self, event): + on = event.GetEventObject().GetValue() + self.pdf.setShowScrollbars(on) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + if wx.Platform == '__WXMSW__': + win = TestPanel(nb, log) + return win + else: + from wx.lib.msgpanel import MessagePanel + win = MessagePanel(nb, 'This demo only works on Microsoft Windows.', + 'Sorry', wx.ICON_WARNING) + return win + + +overview = """\ + +

wx.lib.pdfwin.PDFWindow

+ +The wx.lib.pdfwin.PDFWindow class is another example of using ActiveX +controls from wxPython using the new wx.activex module. This allows +you to use an ActiveX control as if it is a wx.Window, you can call +its methods, set/get properties, and receive events from the ActiveX +control in a very intuitive way. + +

Using this class is simpler than ActiveXWrapper, doesn't rely on +the win32all extensions, and is more "wx\'ish", meaning that it uses +events and etc. as would be expected from any other wx window. + +

This demo embeds the Adobe Acrobat Reader, and gives you some +buttons for opening a PDF file, changing pages, etc. that show how to +call methods on the COM object. If you don't have Acrobat Reader 4.0 +(or greater) installed it won't work. + + +""" + +#---------------------------------------------------------------------- + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/AdjustChannels.py b/demo/AdjustChannels.py new file mode 100644 index 00000000..8d0a5bb9 --- /dev/null +++ b/demo/AdjustChannels.py @@ -0,0 +1,178 @@ + +import wx + +from Main import opj + +#---------------------------------------------------------------------- + +# AdjustChannels demo. The interesting part is ImageWindow.OnPaint + +class TestAdjustChannels(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + topsizer= wx.BoxSizer(wx.HORIZONTAL) # left controls, right image output + + # slider controls controls + ctrlsizer= wx.BoxSizer(wx.VERTICAL) + + label= wx.StaticText(self, -1, "Factor red in %") + label.SetForegroundColour("RED") + ctrlsizer.Add(label, 0, wx.ALL, 5) + sliderred= wx.Slider(self, wx.NewId(), 100, 0, 200, size=(150, -1), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS) + sliderred.SetForegroundColour("RED") + sliderred.SetTickFreq(50, 5) + ctrlsizer.Add(sliderred) + ctrlsizer.AddSpacer(15) + + label= wx.StaticText(self, -1, "Factor green in %") + label.SetForegroundColour("GREEN") + ctrlsizer.Add(label, 0, wx.ALL, 5) + slidergreen= wx.Slider(self, wx.NewId(), 100, 0, 200, size=(150, -1), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS) + slidergreen.SetForegroundColour("GREEN") + slidergreen.SetTickFreq(50, 5) + ctrlsizer.Add(slidergreen) + ctrlsizer.AddSpacer(15) + + label= wx.StaticText(self, -1, "Factor blue in %") + label.SetForegroundColour("BLUE") + ctrlsizer.Add(label, 0, wx.ALL, 5) + sliderblue= wx.Slider(self, wx.NewId(), 100, 0, 200, size=(150, -1), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS) + sliderblue.SetForegroundColour("BLUE") + sliderblue.SetTickFreq(50, 5) + ctrlsizer.Add(sliderblue) + ctrlsizer.AddSpacer(20) + + label= wx.StaticText(self, -1, "Factor alpha in %") + ctrlsizer.Add(label, 0, wx.ALL, 5) + slideralpha= wx.Slider(self, wx.NewId(), 100, 0, 200, size=(150, -1), style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS) + slideralpha.SetTickFreq(50, 1) + ctrlsizer.Add(slideralpha) + + topsizer.Add(ctrlsizer, 0, wx.ALL, 10) + + # image window + self.images= ImageWindow(self) + topsizer.Add(self.images, 1, wx.EXPAND) + + self.SetSizer(topsizer) + topsizer.Layout() + + # forward the slider change events to the image window + sliderred.Bind(wx.EVT_SCROLL, self.images.OnScrollRed) + slidergreen.Bind(wx.EVT_SCROLL, self.images.OnScrollGreen) + sliderblue.Bind(wx.EVT_SCROLL, self.images.OnScrollBlue) + slideralpha.Bind(wx.EVT_SCROLL, self.images.OnScrollAlpha) + + + +class ImageWindow(wx.Window): + def __init__(self, parent): + wx.Window.__init__(self, parent) + self.image1= wx.Image(opj('bitmaps/image.bmp'), wx.BITMAP_TYPE_BMP) + self.image2= wx.Image(opj('bitmaps/toucan.png'), wx.BITMAP_TYPE_PNG) + + # the factors -- 1.0 does not not modify the image + self.factorred= 1.0 + self.factorgreen= 1.0 + self.factorblue= 1.0 + self.factoralpha= 1.0 + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + self.Bind(wx.EVT_SIZE, self.OnSize) + + def OnScrollRed(self, event): + # position is a int value -- calculate the factor + self.factorred = event.GetPosition() / 100.0 + self.Refresh() + + def OnScrollGreen(self, event): + # position is a int value -- calculate the factor + self.factorgreen = event.GetPosition() / 100.0 + self.Refresh() + + def OnScrollBlue(self, event): + # position is a int value -- calculate the factor + self.factorblue = event.GetPosition() / 100.0 + self.Refresh() + + def OnScrollAlpha(self, event): + # position is a int value -- calculate the factor + self.factoralpha = event.GetPosition() / 100.0 + self.Refresh() + + def OnPaint(self, event): + dc= wx.PaintDC(self) + dc= wx.BufferedDC(dc) + + # paint a background to show the alpha manipulation + dc.SetBackground(wx.Brush("WHITE")) + dc.Clear() + dc.SetBrush(wx.Brush("GREY", wx.CROSSDIAG_HATCH)) + windowsize= self.GetSizeTuple() + dc.DrawRectangle(0, 0, windowsize[0], windowsize[1]) + + # apply correction to the image channels via wx.Image.AdjustChannels + image= self.image1.AdjustChannels(self.factorred, self.factorgreen, self.factorblue, self.factoralpha) + bitmap= wx.BitmapFromImage(image) + dc.DrawBitmap(bitmap, 10, 10, True) + + image= self.image2.AdjustChannels(self.factorred, self.factorgreen, self.factorblue, self.factoralpha) + bitmap= wx.BitmapFromImage(image) + dc.DrawBitmap(bitmap, 10, 110, True) + + def OnSize(self, event): + self.Refresh() + + def OnEraseBackground(self, event): + pass + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestAdjustChannels(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """ +

Adjust Channels

+ +

+The wx.Image member function 'AdjustChannels' is a fast way to manipulate the four +channels (red, green, blue, alpha) of a wx.Image. It can be used for colour or +gamma correction of a image. It is also possible to add or enhance the transparency +of a image via this function (eg. for fade-in/fade-out effects). +

+ +

+The function expects four float values (one for each channel) and multiplies every +byte in the channel with the given factor (written in C++). That means a 1.0 will not alter the channel +and eg. 1.2 will 'enhance' the channel by 20%. +

+ +
+Examples:
+
+# make a image 10% brighter - first three parameters are the factors for red, green and blue
+image= image.AdjustChannels(1.1, 1.1, 1.1, 1.0)
+
+# add 20% transparency to a image - the last parameter is the factor for the alpha channel
+image= image.AdjustChannels(1.0, 1.0, 1.0, 0.8)
+
+ + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/AlphaDrawing.py b/demo/AlphaDrawing.py new file mode 100644 index 00000000..6fb15a97 --- /dev/null +++ b/demo/AlphaDrawing.py @@ -0,0 +1,76 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + txt = """\ +If this build of wxPython includes the new wx.GCDC class (which +provides the wx.DC API on top of the new wx.GraphicsContext class) +then these squares should be transparent. +""" + wx.StaticText(self, -1, txt, (20, 20)) + + + def OnPaint(self, evt): + pdc = wx.PaintDC(self) + try: + dc = wx.GCDC(pdc) + except: + dc = pdc + rect = wx.Rect(0,0, 100, 100) + for RGB, pos in [((178, 34, 34), ( 50, 90)), + (( 35, 142, 35), (110, 150)), + (( 0, 0, 139), (170, 90)) + ]: + r, g, b = RGB + penclr = wx.Colour(r, g, b, wx.ALPHA_OPAQUE) + brushclr = wx.Colour(r, g, b, 128) # half transparent + dc.SetPen(wx.Pen(penclr)) + dc.SetBrush(wx.Brush(brushclr)) + rect.SetPosition(pos) + dc.DrawRoundedRectangleRect(rect, 8) + + # some additional testing stuff + #dc.SetPen(wx.Pen(wx.Colour(0,0,255, 196))) + #dc.SetBrush(wx.Brush(wx.Colour(0,0,255, 64))) + #dc.DrawCircle(50, 275, 25) + #dc.DrawEllipse(100, 275, 75, 50) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Alpha Drawing

+ +The wx.GCDC class is a class that implemented the wx.DC API using the +new wx.GraphicsContext class, and so it supports anti-aliased drawing +using pens and brushes, that can optionally also be drawn using an +alpha transparency. (On the Mac all the DC classes are using this new +implementation.) This is accomplished by enabling the wx.Colour class +to have a fourth component for the alpha value, where 0 is fully +transparent, and 255 is fully opaque. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/AnalogClock.py b/demo/AnalogClock.py new file mode 100644 index 00000000..018c4a8f --- /dev/null +++ b/demo/AnalogClock.py @@ -0,0 +1,142 @@ +# AnalogClock demo +# E. A. Tacao +# http://j.domaindlx.com/elements28/wxpython/ +# 12 Fev 2006, 22:00 GMT-03:00 +# Distributed under the wxWidgets license. + +import wx +import wx.lib.analogclock as ac + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent) + + # A mostly default clock + c1 = ac.AnalogClock(self, size=(200,200)) + + if True: # for a simpler test case just set this to False and + # only the one clock will be created + + # A plain clock, with square hour and round minute marks, no + # shadow, static border + c2 = ac.AnalogClock(self, style=wx.STATIC_BORDER, + hoursStyle=ac.TICKS_SQUARE, + minutesStyle=ac.TICKS_CIRCLE, + clockStyle=ac.SHOW_HOURS_TICKS| \ + ac.SHOW_MINUTES_TICKS| + ac.SHOW_HOURS_HAND| \ + ac.SHOW_MINUTES_HAND| \ + ac.SHOW_SECONDS_HAND) + c2.SetTickSize(12, target=ac.HOUR) + + # No minute tick marks + c3 = ac.AnalogClock(self, hoursStyle=ac.TICKS_CIRCLE, + clockStyle=ac.SHOW_HOURS_TICKS| \ + ac.SHOW_HOURS_HAND| \ + ac.SHOW_MINUTES_HAND| \ + ac.SHOW_SECONDS_HAND| \ + ac.SHOW_SHADOWS) + c3.SetTickSize(12) + + # A clock with hex numbers no seconds hand and different colours. + c4 = ac.AnalogClock(self, hoursStyle=ac.TICKS_HEX, + clockStyle=ac.SHOW_HOURS_TICKS| \ + ac.SHOW_HOURS_HAND| \ + ac.SHOW_MINUTES_HAND| \ + ac.SHOW_SHADOWS) + colour = wx.Colour(0, 255, 255) + c4.SetForegroundColour(colour) + colour = wx.Colour(0, 132, 132) + c4.SetShadowColour(colour) + c4.SetTickFont(wx.Font(10, wx.FONTFAMILY_MODERN, wx.NORMAL, wx.BOLD)) + c4.SetBackgroundColour(wx.BLACK) + c4.SetFaceBorderColour(wx.BLACK) + c4.SetFaceFillColour(wx.BLACK) + + # A clock with binary numbers shown only at the quarter tick marks, + # no minutes ticks and different colours. + c5 = ac.AnalogClock(self, style = wx.RAISED_BORDER, + hoursStyle=ac.TICKS_BINARY, + clockStyle=ac.SHOW_QUARTERS_TICKS| \ + ac.SHOW_HOURS_HAND| \ + ac.SHOW_MINUTES_HAND| \ + ac.SHOW_SECONDS_HAND| \ + ac.SHOW_SHADOWS) + colour = wx.Colour(0, 128, 0) + c5.SetHandFillColour(colour, target=ac.SECOND) + c5.SetHandBorderColour(colour, target=ac.SECOND) + c5.SetBackgroundColour(colour) + colour = wx.Colour(128, 0, 64) + c5.SetTickFillColour(colour) + c5.SetFaceBorderColour(colour) + c5.SetFaceBorderWidth(1) + colour = wx.Colour(0, 198, 0) + c5.SetFaceFillColour(colour) + c5.SetShadowColour(wx.WHITE) + + # A clock with a sunken border, roman numerals shown only at the + # quarter tick marks with a roman font, circular minutes ticks, + # no seconds hand, no shadows, tick overlapping and different colours. + c6 = ac.AnalogClock(self, style = wx.SUNKEN_BORDER, + hoursStyle=ac.TICKS_ROMAN, + minutesStyle=ac.TICKS_CIRCLE, + clockStyle=ac.SHOW_QUARTERS_TICKS| \ + ac.SHOW_MINUTES_TICKS| \ + ac.SHOW_HOURS_HAND| \ + ac.SHOW_MINUTES_HAND| \ + ac.OVERLAP_TICKS) + colour = wx.Colour(128, 0, 0) + c6.SetHandFillColour(colour) + colour = wx.Colour(179, 0, 89) + c6.SetHandBorderColour(colour) + c6.SetTickFillColour(colour) + c6.SetTickBorderColour(colour) + colour = wx.Colour(225, 255, 255) + c6.SetFaceBorderColour(colour) + c6.SetBackgroundColour(colour) + colour = wx.Colour(249, 255, 255) + c6.SetFaceFillColour(colour) + colour = wx.Colour(255, 213, 213) + c6.SetShadowColour(colour) + c6.SetTickFont(wx.Font(10, wx.FONTFAMILY_ROMAN, wx.NORMAL, wx.BOLD)) + + # layout the clocks in a grid + gs = wx.GridSizer(2, 3, 4, 4) + gs.Add(c1, 0, wx.EXPAND) + gs.Add(c2, 0, wx.EXPAND) + gs.Add(c3, 0, wx.EXPAND) + gs.Add(c4, 0, wx.EXPAND) + gs.Add(c5, 0, wx.EXPAND) + gs.Add(c6, 0, wx.EXPAND) + + # put it in another sizer for a border + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(gs, 1, wx.EXPAND|wx.ALL, 10) + + self.SetSizerAndFit(sizer) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

+""" + ac.__doc__.replace("<", "").replace(">", "") + """
+
""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/AnimateCtrl.py b/demo/AnimateCtrl.py new file mode 100644 index 00000000..d4a2db95 --- /dev/null +++ b/demo/AnimateCtrl.py @@ -0,0 +1,60 @@ + +import wx +import wx.animate +from Main import opj + +GIFNames = [ + 'bitmaps/AG00178_.gif', + 'bitmaps/BD13656_.gif', + 'bitmaps/AG00185_.gif', + 'bitmaps/AG00039_.gif', + 'bitmaps/AG00183_.gif', + 'bitmaps/AG00028_.gif', + ] + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + sizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5) + for name in GIFNames: + ani = wx.animate.Animation(opj(name)) + ctrl = wx.animate.AnimationCtrl(self, -1, ani) + ctrl.SetUseWindowBackgroundColour() + ctrl.Play() + sizer.AddF(ctrl, wx.SizerFlags().Border(wx.ALL, 10)) + + border = wx.BoxSizer() + border.AddF(sizer, wx.SizerFlags(1).Expand().Border(wx.ALL, 20)) + self.SetSizer(border) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.animate.AnimationCtrl

+ +wx.animate.AnimationCtrl is like a wx.StaticBitmap but is able to +display an animation by extracing frames from a multi-image GIF file. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ArtProvider.py b/demo/ArtProvider.py new file mode 100644 index 00000000..774fdf1b --- /dev/null +++ b/demo/ArtProvider.py @@ -0,0 +1,884 @@ + +import cStringIO +import wx + +#---------------------------------------------------------------------- + +ArtClients = [ "wx.ART_TOOLBAR", + "wx.ART_MENU", + "wx.ART_FRAME_ICON", + "wx.ART_CMN_DIALOG", + "wx.ART_HELP_BROWSER", + "wx.ART_MESSAGE_BOX", + "wx.ART_OTHER", + ] + +ArtIDs = [ "wx.ART_ADD_BOOKMARK", + "wx.ART_DEL_BOOKMARK", + "wx.ART_HELP_SIDE_PANEL", + "wx.ART_HELP_SETTINGS", + "wx.ART_HELP_BOOK", + "wx.ART_HELP_FOLDER", + "wx.ART_HELP_PAGE", + "wx.ART_GO_BACK", + "wx.ART_GO_FORWARD", + "wx.ART_GO_UP", + "wx.ART_GO_DOWN", + "wx.ART_GO_TO_PARENT", + "wx.ART_GO_HOME", + "wx.ART_FILE_OPEN", + "wx.ART_FILE_SAVE", + "wx.ART_FILE_SAVE_AS", + "wx.ART_PRINT", + "wx.ART_HELP", + "wx.ART_TIP", + "wx.ART_REPORT_VIEW", + "wx.ART_LIST_VIEW", + "wx.ART_NEW_DIR", + "wx.ART_HARDDISK", + "wx.ART_FLOPPY", + "wx.ART_CDROM", + "wx.ART_REMOVABLE", + "wx.ART_FOLDER", + "wx.ART_FOLDER_OPEN", + "wx.ART_GO_DIR_UP", + "wx.ART_EXECUTABLE_FILE", + "wx.ART_NORMAL_FILE", + "wx.ART_TICK_MARK", + "wx.ART_CROSS_MARK", + "wx.ART_ERROR", + "wx.ART_QUESTION", + "wx.ART_WARNING", + "wx.ART_INFORMATION", + "wx.ART_MISSING_IMAGE", + "wx.ART_COPY", + "wx.ART_CUT", + "wx.ART_PASTE", + "wx.ART_DELETE", + "wx.ART_NEW", + "wx.ART_UNDO", + "wx.ART_REDO", + "wx.ART_CLOSE", + "wx.ART_QUIT", + "wx.ART_FIND", + "wx.ART_FIND_AND_REPLACE", + ] + + +#---------------------------------------------------------------------- + +class MyArtProvider(wx.ArtProvider): + def __init__(self, log): + wx.ArtProvider.__init__(self) + self.log = log + + def CreateBitmap(self, artid, client, size): + # You can do anything here you want, such as using the same + # image for any size, any client, etc., or using specific + # images for specific sizes, whatever... + + # See end of file for the image data + + bmp = wx.NullBitmap + # use this one for all 48x48 images + if size.width == 48: + bmp = makeBitmap(smile48_png) + + # but be more specific for these + elif size.width == 16 and artid == wx.ART_ADD_BOOKMARK: + bmp = makeBitmap(smile16_png) + elif size.width == 32 and artid == wx.ART_ADD_BOOKMARK: + bmp = makeBitmap(smile32_png) + + # and just ignore the size for these + elif artid == wx.ART_GO_BACK: + bmp = makeBitmap(left_png) + elif artid == wx.ART_GO_FORWARD: + bmp = makeBitmap(right_png) + elif artid == wx.ART_GO_UP: + bmp = makeBitmap(up_png) + elif artid == wx.ART_GO_DOWN: + bmp = makeBitmap(down_png) + elif artid == wx.ART_GO_TO_PARENT: + bmp = makeBitmap(back_png) + + elif artid == wx.ART_CROSS_MARK: + bmp = makeBitmap(cross_png) + elif artid == wx.ART_TICK_MARK: + bmp = makeBitmap(tick_png) + + if bmp.Ok(): + self.log.write("MyArtProvider: providing %s:%s at %s\n" %(artid, client, size)) + return bmp + + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + sizer = wx.BoxSizer(wx.VERTICAL) + + title = wx.StaticText(self, -1, "ArtProvider") + title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)) + sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL) + sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + fgs = wx.FlexGridSizer(cols=3, hgap=10, vgap=10) + + combo = wx.ComboBox(self, -1, "", choices = ArtClients, + style = wx.CB_DROPDOWN|wx.CB_READONLY) + fgs.Add(combo, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + self.Bind(wx.EVT_COMBOBOX, self.OnSelectClient, combo) + combo.Select(0) + + combo = wx.ComboBox(self, -1, "", choices = ArtIDs, + style = wx.CB_DROPDOWN|wx.CB_READONLY) + fgs.Add(combo, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + self.Bind(wx.EVT_COMBOBOX, self.OnSelectID, combo) + combo.Select(0) + + cb = wx.CheckBox(self, -1, "Use custom provider") + fgs.Add(cb, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + self.Bind(wx.EVT_CHECKBOX, self.OnUseCustom, cb) + + fgs.Add((10, 10), 0, wx.ALIGN_CENTRE|wx.ALL, 5) + fgs.Add((10, 10), 0, wx.ALIGN_CENTRE|wx.ALL, 5) + fgs.Add((10, 10), 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + box = wx.BoxSizer(wx.VERTICAL) + bmp = wx.EmptyBitmap(16,16) + self.bmp16 = wx.StaticBitmap(self, -1, bmp) + box.Add(self.bmp16, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + text = wx.StaticText(self, -1, "16x16") + box.Add(text, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + fgs.Add(box, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + box = wx.BoxSizer(wx.VERTICAL) + bmp = wx.EmptyBitmap(32,32) + self.bmp32 = wx.StaticBitmap(self, -1, bmp) + box.Add(self.bmp32, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + text = wx.StaticText(self, -1, "32x32") + box.Add(text, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + fgs.Add(box, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + box = wx.BoxSizer(wx.VERTICAL) + bmp = wx.EmptyBitmap(48,48) + self.bmp48 = wx.StaticBitmap(self, -1, bmp) + box.Add(self.bmp48, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + text = wx.StaticText(self, -1, "48x48") + box.Add(text, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + fgs.Add(box, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + sizer.Add(fgs, 0, wx.ALL, 5) + self.SetSizer(sizer) + + self.client = eval(ArtClients[0]) + self.artid = eval(ArtIDs[0]) + self.getArt() + + + def OnSelectClient(self, evt): + self.log.write("OnSelectClient\n") + self.client = eval(evt.GetString()) + self.getArt() + + + def OnSelectID(self, evt): + self.log.write("OnSelectID\n") + self.artid = eval(evt.GetString()) + self.getArt() + + + def OnUseCustom(self, evt): + if evt.IsChecked(): + self.log.write("Images will now be provided by MyArtProvider\n") + wx.ArtProvider.Push( MyArtProvider(self.log) ) + else: + self.log.write("MyArtProvider deactivated\n") + wx.ArtProvider.Pop() + self.getArt() + + + def getArt(self): + self.log.write("Getting art for %s:%s\n" % (self.client, self.artid)) + + bmp = wx.ArtProvider.GetBitmap(self.artid, self.client, (16,16)) + + if not bmp.Ok(): + bmp = wx.EmptyBitmap(16,16) + self.clearBmp(bmp) + + self.bmp16.SetBitmap(bmp) + + bmp = wx.ArtProvider.GetBitmap(self.artid, self.client, (32,32)) + + if not bmp.Ok(): + bmp = wx.EmptyBitmap(32,32) + self.clearBmp(bmp) + + self.bmp32.SetBitmap(bmp) + + bmp = wx.ArtProvider.GetBitmap(self.artid, self.client, (48,48)) + + if not bmp.Ok(): + bmp = wx.EmptyBitmap(48,48) + self.clearBmp(bmp) + + self.bmp48.SetBitmap(bmp) + + + def clearBmp(self, bmp): + dc = wx.MemoryDC() + dc.SelectObject(bmp) + dc.SetBackground(wx.Brush("white")) + dc.Clear() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """ +

wx.ArtProvider

+ +wx.ArtProvider class can be used to customize the look of wxWindows +applications. When wxWindows internal classes need to display an icon +or a bitmap (e.g. in the standard file dialog), it does not use a +hard-coded resource but asks wx.ArtProvider for it instead. This way +the users can plug in their own wx.ArtProvider class and easily replace +standard art with his/her own version. It is easy thing to do: all +that is needed is to derive a class from wx.ArtProvider, override it's +CreateBitmap method and register the provider with +wx.ArtProvider.PushProvider. +

+ +This class can also be used to get the platform native icons as +provided by wx.ArtProvider.GetBitmap or wx.ArtProvider.GetIcon methods. + + +""" + + +#---------------------------------------------------------------------- +# Image data + + +def makeBitmap(data): + stream = cStringIO.StringIO(data) + return wx.BitmapFromImage(wx.ImageFromStream(stream)) + + +back_png = \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ +\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x07YID\ +ATx\x9c\xa5\x97Ml\x9dG\x15\x86\x9fsf\xbe\xef^\xfb:\xaeS\xd7\xa9\x1d;!IK)\xfd\ +A\x05\x95BQ\xc5\xdf\x02\xb1(\x12\x0b\x10\x8b\x8a\x05]Vl\xd8\xb2`\xcb\x92\xee\ +Q\x85\xd8U\xaa\xba\x03\tD+@j\x91J\x11\x8aT\xd14\xfd\xa7\xf9q\x9a\xc6\x8e\xe3\ +\xd8\xb1\xefwg\xcea1s\xaf\x13;\xaa*1\xd2h4su\xe7=\xe7\xcc{\xdes>\x99\x9b\x9b\ +\x03\xe0\xf9\x17\xff\xe2[\xb6B;u\'\x86`\x19\x9299Ar\xc8\x19\xb29\xd9 \xe5\ +\xb2O\x069\x97\xb3\x03{\x1b\xff\xa7\x9c\xa5zf\xe6,\x1e\xda\xe0\xe1\xe5U\xe6g\ +\xb6\x91\xb9\xb99~\xf7\xc2i\x1f\xcc-3\xdd\x8f\xe5r\x83Q\x86\x94\xa0K\x05p\ +\xbc\x1f\xe5\xba\xff?\xcf{\xb1\xe3;_x\x17\xf9\xd3\xcb\xaf\xbb\xce>\xc2\xcctd\ +\x94*x\xca\\\xdb\xd8\xe2Fg\x98\x0b\x96\x95l\xc2\xc8 \xbb\xe0Y\xc8&\xd5+!eadB\ +JBv\xa9`R\xef\x12FYH\x19\xcc\x84.\xcb\xc4\xb0\xa5\xd9k\xc4-[f\xb1_\xc0\xdda\ +\xed\xca*k\xabg\xd9\xda\xfc\x84\xeb;\x01\x97\x1eh\x03\x12A"N\x03D\\"\xe6\x81\ +LK\xf6H\xb6H\xf6@\xb6@\xf2H\xb2\xc0(+\xd9#\xbb]$y\x00\x14\xd5\x00\x08\x00\ +\x17\xaf\xcd\x12\t\x83b\x9d\xc3\xd6\xf5\xab|\xf4\xf6+|ti\xc8\xb9+\rW\xae\xb7\ +\x88*\x1a\x14\x15E\x82"Z\xa7(\xaa\rh\x00\tH]\x11\x05Q\\\x14<\xe0\x12HV"\xe8\ +\x08\xfd6\xd3k\x03\xee\xc2(\t\xd1\xc6\x841\xf8\xf8\xc2;\\^\x1f\xf2\xda\xd9\ +\x86\xc1\xf4!V\x16gh{-\xe6J\x08\x11\t\rA\x03\x1a"\xaa\r\x12\x02\xaa\x81 \x11\ +\x82\xa2\xd5\x10\x11-\x06\x11\xe8\xb7\xca(\x0b\xef\xad\n\xeb\x9b\x86Y\xa6UgD\ +\x03@4wF\x19,\x8f\xb8\xb1u\x85w/6\xf4z\x03N\x1e\x9bc\xa7\x13.\xad\x8d\xd8\ +\xed\x04QG\xd5\x11\x8d\x88\n\xa8 \x02\xaa\x02\x9a\x01\x07\x11\x10\xc1\xa5\ +\x84\xd8\x81\xa9>\x9cZR\xbev\xbf\xf3\xea\x1b\xc6ng\xb4\xd1\xd8\xee"\xee\x82\ +\x9a\x15V\xa6,\x98\x05\xae\xef\xf69<7 [\xe0\xfc\xe5!\xdb\xbb`D\x9c\x80\x110\ +\x1a2\x01\xf32\x93+)+\xc9\xea\xbb[ \xe5\xc8(\x17\x0e\\\xdbV\xfe\xf3a\xa6\x1b\ +\x19\xcb\x0bNTc\xaa5\xc6#\x9a\x97Ts\x03B\x8b\xc6\xcc\xf4T\x8f\xcd\x1b\x86y@\ +\xb4A5V\xcf[\xd0\x88H\x99\xd40#\x91\xe1\xf6\xc7|\xf0\xfa\xb3\xe44\xac$\x13\ +\x16\x1f|\x9a\xc3+\x8fc9s\xe1\n\xdc5\x0b\x17.\x1bM(\x112\x87\x98\xcdk\x8a\ +\x00\x94\xb7\r!\xe2#\x10\x95\xcf\x04\x8e\x04\xba\xe1&\xabg\x9e\'w[\x13\xef\ +\xe6V\x9e@W\x1eC\xc4p\x87\x18 \x06\xa3\x89\x8a{\xc9\xbahUt0\n\x80\xc6B\xb2\ +\x00\xaa\xf6\x99\xc0]\xea\xbe\xa6\xd7x\x08\x86\x88\xa1bD\x15\x82B\x10\xa7\t\ +\x19K\x1d9Iy\x82\x94\xc0\x11\xa0\xe4\xbajD\x15D\xed3\x82G\x1ce\xff\x10\xbc\ +\x82\x1bA\xa5\xcc`4\x01R\xee0\x13\xa2Y\xc9\x02\x1c\x8c0y\x82\x9a\xce\x07\xc0\ +\xddAt?x\xb8\xbd\x01\xe2\x15\xdcPQT\xa0Q\xa7\t`y\x88\xe5q\x16T\xfd\xf7q\x04B\ + \x84\xe6\x00x\xeevx\xff\xb5\xdf\xb0~\xfe\xd5\x03\xe0\xb73@e\x0c\xee\x04\xf5\ +\xca\x01\xa7\t\x86\xa5\x0e\xcf\x1dj\xe6E\xbbS5@cU\xb8\x83\xe0\xef\xfc\xe3\ +\xd7|\xf8\xfa\xb3\x9cy\xf9\x17\\=\xf7\xea-\xe0\x8a\xdd\xc6\x00\xaf\xe0F\x08N\ +T\'(\xc4h\xb8\x8d\xb0\xdc\xa1\xe6%\x02E\x8e\x03\xa2-\x12""\xe1\x00\xf8\x857~\ +\x8f{fg\xe3\x03\xce\xbc\xf4s\xd6\xcf\xfd\xbd\x80\x8b\xa1d\x04?`@P+\xde\xab\ +\x13\x024\xc1\xe97\x8e\xe7\x0e\xcfCt\\zG&\xe4ZdT\x02\xaa\xb7\x07\x1f\x8f\x9d\ +\x8d\xf79\xfb\xd23\\;\xf7r\x01\x17\xdf\x1f\x00d\x1c\xfa\xeayPh\x1b\xa7\x89\ +\x0e\xdea\xd6\xa1\xee^\x940A\xf6H\x13c\xcd\xfd\xc2\xf6\x94\x86\xdc\xb1\xf4(s\ +\xcb\x8f\xdfry;}\x84\x95G\x9eA0`\x84\xe5m\xdco}\x86\x10t\xe2y\xac\xde7\x01z\ +\x11\xdc\n\x07&: \x02x\xa0m\xa4V;@\x84\xde\xccQ\x16\x1fx\x8a\xd4\xedp\xf5\ +\xfc+\x93\xcb\xd3p\x83\xde\xf4<\xf3\x9f\xfb&*\xc6\xf6\xe5\xd3\xe4\xd1\x8d\ +\xc9\xef\xb1\x99f\xee\xae{\n\xb8:M\xa8\x86D\xa1\x89`\xb9\xc3\xb2U\x1d\xc8\ +\xa0\x02f\x01Cji\x15\x10&l\xef\xcd\x9e@4\xe2\x96\x80r\xc1\xbb\xaf\xfc\x8a\ +\xb4\xb3J\x7fz\x9e\xff\x9e\xfe\xed-\xde7\xfdY\x06\xb3\x0b\x05<\x8e\xa3P\xc0\ +\xdb\x08X5 \xd7,P\x11\xdcJ\x9dV\t\x88\x08.LR\xed\xd0\xdd_e\xfa\xf0}l\xaf\xbd\ +9\x01\xd9\xdd\xfc\x88\xb7\xfe\xfaKD\xc3\xc4\xb0\xf1\xb8\xfb\xc47\x98=\xbcD\ +\x13\xbd\x86_*\t\xa1\x89\xe0\x96\xf0\x9c\xf6t\xa04\x94\x01#\x82j\x997\xe5y38\ +\xca\xd1\x87~\xc6~\xb9\x05?\x00\xde\xf4\x0e\xf1\xc5\xc7~J\xaf\r\x05<\xde\x04\ +\xde\x08m\x03\xee\t\xcb\xc3\x92\x86\xa3\xda4\x8er S\xbb\x9b}"\xa3b,\xdd\xffc\ +\x16N}\x1f\r\xed\x01\xc6\xef\xbd\xfd\x14\xf7=\xfa\x14\xcb\xa7\x1e\x9d\x80\ +\xc7\xeau\x08B\x1b\xa1\x8d\x8a\xdb\x10\xb7\xaeHqJ\x85\x03\x9e\x15s\x10\n\x07\ +\xbc\xa8\xf9$\xcf{3\x0b|\xe9\xc9\xe7X\xff\xf0\xcf\x9c;\xfd\x1c\x1b\x97N\x93j\ +\xf5\x8b\xcd\x14\xf3+_\xe1\x81\xaf?\xcd=\x0f}\x8f\xb6mn\x01\x8f*5\xfcJ\xbf\ +\xe7\x95\x037e\x81\nXR\x92\x95~\xaf\xdf+\x06LD\xa6V\xb5\xb6?\xe0\xd8\x03?d\ +\xf9\xde\xef\xb2}\xf5,\xdb\xebo\xa3df\xef<\xce\x91\x95\x87\x99\x1e\xcc\x1c\ +\xf0\xbc\t\xc2\xa1\x81\x12\x832\xd5S\xdahX\x1e\xe1y\xb8\x97\x05"\xd0\x8d"\ +\xd9\x84\x8dm\xe1\xd4Q\xe5\xd2zfk;\xdfTR\xf7\xb4\xbd\x99\x1a0=\xf82K\xc7\x1f\ +\xd9K\xb51\xe1\xf6\x81\xdfqH9\xbe\xd8pi-\xd36B\xd3\x08\xe27G \x15ju)\x90\x0c\ +.\xac\t\'\x16\x9d\'\x1e\x84s\x9f@7\xa2\xd6sAE\t\xea\x84 {\xda^E&\xdc\xcc\xf6\ +\x1a\xf6~O8~w\x83 \xacof\x8e-\x08MTR\xea\xb0<\xac\x1c\xc8P\xaaw\xc0\xdd\x19v\ +\xc6kof\x8e\x1c\x866Z\x05\xda\xabj\xb7\x14\x96O\x01\x8f\r\x88\x08\xabW2[\xbb\ +#\xa6{pbQ\xf9\xdb?/\xb2\xb9\xb9\x8d[":\xb5\x1f\x00\xdc\x85A\xdf\x18\xa5\x8c\ +\xbb\xb1\xb6Q:\xd8\x18\xac\x94Q-k[C\x1d\xa3\xd3\x8b\x8eEh\xa3 ^"iU\xc4\xd4\ +\x95&8m\x14\x16\xef\x14\x96\xe6\x95l\xc6\x0b\x7f\xf8\x17f\x1d\xb8\x11\x8f\ +\xcd]\xe5\xcc\xea\x11\xccJ#\xa9!0\x88\xd0\x84L\x1b\x85\x18tR\xc3\x83\x16\x1e\ +\xc4\x89!U\xdf\xe3\xb8\xd7s\x9a e\x8dB\xaf1\x1a\x15\xa2\n\xbbC\xe1\xf4[[\xbc\ +\xf8\xc7\x7f\xf3\xde\x07\xab\xb8\x97\xce(\x9e\xbck\x8d\x85\x99M\xce_\xbdc\ +\x12\x85\x11\xb1\xf6\xed%2f`\xa9#\xe5\x8e\x9c\x129\x15\x02y\x1eb\xb5\xa8\x94\ +\x0e\xa7+\nge?>/kWz\x00\xebp7<\x0f9yr\x19\xfd\xc9\x8f\x9e\x94o}\xfe=\xee]\ +\xf8\x04%\x17A\x1aW\xc7}_\xb5\xd9J+\xfd\xa9\xc3\r\xb7\\V\xb7\xc9\xea\x9e\x8b\ +b\xba!\x18G\x97\xe6\xf9\xc1\xb7\x97\xf9\x1f\x92tznH\x8fy\x14\x00\x00\x00\x00\ +IEND\xaeB`\x82' + +down_png = \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ +\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x042ID\ +ATx\x9c\xa5\xd5Ko\x1bU\x14\xc0\xf1\xff\x8c\xe7\xe1g\xe2\xa6\x84\xa8\xa8\x82\ +\xd0\x88E\xabJ\x08\t\x8a*\xb1@\x02v\xec@l`\x87\xf8\x1e\x91\xf8\x06 \x90\xd8\ +\xb3\xe2S\xb0aS\x1ej\x8bhIe\xd2\xa8i\xa8\x13\xc7\x8f\xda\xe3\x99\xb93\xf7\ +\xcee1\x1e\xc7\xae\xed\xc4c\x16Wc\xddk\xfbw\xce\xf1\xf1\xb9\xc6\x0fw\xb5\xfe\ +h\x1b\x02\t\x91\x02\xa1 N&^+\x88\x12\x08%\x08\x99\xeeE\xa3\xf3l\t\x05~\x9c>\ +\xc3\xd1^(\'>7:\x7fqOH0\x13\r\x00\xa6\x91\xae\x82\x01F\xba5~\xca\x04\x94\x86\ +db\xa9\xd1\x92I\x1a|\x16t<\x91\x84\x18%\x15\xc4g\x81\x87Y\xa2\x12\x94R\x98J\ +\x8f\x0e\'\xb2\x11\nNzC\xfex\xb0\x8f\x17\xeb\xf4|"\xfb\xec\xfdB\x82\x17\x9fe\ +\xfcb\x05\xc6\x99gU\x12\n!\x13\xc2\x11\x8e\x14X*\x99\xc5#\x05a\x9c\xf0\xfdw\ +\xdf\xb0qe\x9bO>\xfb\x9c\xcb\x9b\x9b+\xe3\xa1L\xe8{\x01a\xa40\xdc**Iq\xad",\ +\xa5g\xf1HA\xb1R\xe3\xda\xcdw\xf8\xe5\xa7o9\xd8\xfb\x93\xdb\x1f\x7f\xc1\xdb\ +\xb7\xde\xc5)\x96s\xe1\xfda\xc0\xc0\x1b\x12)0\xdd\x1aI\xa2\xc78\xb1O\xe1\xc3\ +\xafvw\xafT\xa7q\x7f\xf4%\xf5\x8d-\xee\xfcz\x87\xb0w\xc2\xc1\xdf\xf7y\xf8\ +\xcf!Vu\x13wm\x8381\xce\xc5\xbd0\xe6\xb4\xd3a0\xf0\x90X\x18v\x19,w\nG\n\n\ +\x1f|\xb9\xbb\xbbU\x99\xc5#\tv\xa9\xc2\xa3\xc3\x16\x9d\xe6\x13\xb0\\\x82a\ +\x9f\xc7\xfb\rN\xfa!v\xf5\x12\x96[\x99\xc1\x07\xa1\xa4\xd5\xeepzz\x8a\x88\ +\x15\xda.\xa5\xb8S\xc2\x88\xa7\xf1\xb4\x07\xf4|\\(\x90\xda\xe0\xad\xdb\xef\ +\xf3\xf8\xaf\xdfP\x1a\x0c\xb7\x86L4O\x1e\xfc\xceq\xf3\x19Wo\xdc\xe2\xea\xceu\ +\x12\xd3!\x94\x9aV\xe79\'\xad\x14\xc6.\x81S\x1e\xe1e\x1cb\x84\x12S\xb8\x96\ +\x11\x96L\xe6\xe3Y\xc3m_\xbb\xc6\xfa\xab7\xe86\x0f\xc1.aXEp\xca\x88(f\xff\ +\xc1]\x8e\xdb]6^\xd9\xc1\xf3C\xfaC\x1f]pa\x84fx\xc5\xd2\x84A8\x83#E:\x07\x16\ +\xe1\x91\x02\xa3\xe0\xb2\xf3\xe6{`\x97\xc78N\x05\xc3)\x83]b\xe8y<=h\xd0\xeb\ +\x0f\xe6\xe2U\x1b,bT0\x98\xc1Q\x023N\x16\xe3Y\xb7o\xbfq\x9d\xf2KW_\xc0\'\xa0\ +\xe2\xfa\xec\xde\x08\xaf8\x90\x88!z\x0e\x8e\x8c\xd2At\xd1\x90q+kl\xbe~s>^\ +\xaa/\xc4\xab\x0eTL\x89\xef\xf5\xe7\xe2Z\nL\x99\x9c\x8fg\xdd\xfd\xca\xceu\n\ +\xe5z.|\xa3\x08\x81?D\x8a`.N\xec\xa7\x01,3\xe1\xca\xeb\x97\xa9\xbd\xfcZ.\xbc\ +h&\xf4\x9f\xf7\x16\xe2H1}\x17\x9c7\xe1\xe2\xc4\xe4\xd2\x95m\x0c\xa7\xb2\x14^\ +s@\x84>\xde\xa0\xbf\x10GE\x98?~z\xc9Xv\xb6;k\x9b\xd8\xeb[K\xe1eKs\xda\xe9\ +\xa2\xe3p!\xae\xa5\xc0\x84\xe5/\x16Up(\xd6\xb7.\xc4\xab\x0eh\x15\xd1>m\x9f\ +\x8b\x93\x05\x90\xe7J-\x94\xd60\xdc\xea\xb9x\xd5\x86V\xbbG\x14z\xe7\xe2\xc8\ +\x08\x0b\x96\xc7C\t\xca\xb01\x9c\n\xdar\x17\xe2\x16\x8a\xa3\xe6\xf1\x858jT\ +\x81e\xf1\xecL\x17\xec\x85x\xcd\x81^\xdf\xa3\xd7\xe9\\\x88\x9f\xf5@\x0e\\)\ +\x85\x11\x0b\\S\xcd\xc5\x8b\x05\xcd\xc1\xd3&*\n.\xc4\x89\xfcQ\x05r\xe0HA\xa2\ +\x04:\xf2g\xf0\x8a\rB\x08\x0e\x8f\x8e\x96\xc2\xc7M\x98\x07\xcf\xee\xf3\xa1\ +\xd7\xc7BN\xe15\x07\xf6\x8fZ\x04\x83\xeeR\xf88\x80\xbc8R\x10\x0e\x07xC\x7f\n\ +\'\x914\xf6\x1f/\x8dO\xf5@\x1e<\xbbX\x9a\xc7-\xdc\x82\x1e\xff\x14\xadn\x9f\ +\xe3\xe6\xbfK\xe3\xe3\n\xac\x82#\x05\xedv\x0b\xdf\x0f\xa8:\xb0\xeeh\xee\xed\ +\x1d\xa0\xa2pi\xfc\xeco\xb8\x02\x8e\x12D\x81O\xe3\xe91\x1bEx>\x0c\xd9k4r\xe1\ +\xe3\n\xac\x82gCf\xefQ\x83@D\xdcm\x1ck\x08l>\xc0\x11\x85/\xaf\x18\xef?\\\x148\xe6J\ +\x80\xd5\x03\x1cQ\x84\xe2^\r\xde\xc9-\x99\xf1\xf1\x80\x13\x0581\xe3\xd1\x8cs\ +$\x8b\x07\xb8\x93\x9cP\xec\xcb\xc3\x13mi\xa5B\xa2\x1d\xda+R\x0c!\nav\x06D\ +\x84\xb8\xbd7\x86#\x8a\xd0\xd8\x17\xc33q4:9{\x1dE\xac,\xe2\x15\xa0P&\x1a\xc1\ +g|\xcbn\xb3\x89\xcd\xb31\x1c\xa3\x08\x95=\x1a\xdeN\x85\x9dV\x87\x9d\xbd\x0e\ +\x89v\x98\xa0\x887S>\x80\x97Bh\xc5)\x9d\xb8u\x00GrB=\x05\x9ej\xc7n3\xa6\xba]\ +\xa7\xdeN\xc9\xc4\x83\x99\x12\x14\xca\x87\xe2\x9e3\xec\xd6\xeb\x13q\xd7\x9f\ +\x82g\xe1\xad4\xa7\xb2\xb5Mu\xb3F\xb3\xddA\xc22^\xa1\xfcL\xbc\x18:6\xb7\x9b\ +\xe4ig"\x8eN\x08\xb5\x9d\x8cg\xda\xb2\xb1\xbd\xc7ze\x83\xcd\xcd-\xd2\\\xe3\ +\x82\x08J\xa7zx\xf9\xa9x\x14\x82R\x8a\xc6\xee\xee\xa1\xf8`\x1b\x8e\xe2\xb5V\ +\xc6\xea\xc3\xc7\xdc_{@\xa3^G[o\x08M\x81\x87\x9ee\xfd\xc9\x0eZ\xa5\x87\xe2\ +\x98\xde\x1aP\xe2X\xab\xd4X\\^\xe1\xd1\xfa\x1aI\x92\xe0\xc2h\x1c\x9a\x02\x8f\ +B\xd8\xad\xb7i\xee5\x9e\x8a;Q\xdd)\x88Sa\xe9\xde*k+\xcbd*?\x08M\x89G\x01\xa4\ +i\x82\xd3\xd9SqD\xe1\xfd\xf2\xa7s\xa1\xdf\x9d\x82\xda^\xcc\xfd\x07\x15\xaa\ +\x9b\x9b$\xa9\xc2\x06\xc5\xa9\xf1\xfeu\x1c\'\xdc\xb8u\xa7\xb7\x00\'\xe3H\x8e\ +\xf7\xf3\x1f\xce\x15\x83\xf1}\xde\xc9\x84Z\xa3E\xad\xd1\xa6\x9d\n\xe2\xcdL\ +\x85\x97B(\x06\x8e\xbb+\x15\x16\x96\xee\x1e\x8acTw\r87~\xc8\x18/\xe4\xc4\xc9\ +9\xfc\xf2\x1ce%\xb4SM\xa2=L\x10=\x17\x1e\x050[\xf4\xb8|\xee\x0c\x1b\x955v\ +\xb6\x1a\x13q\'j\x98\x11\x1d\xf6bq^HX(Q\x8c"B\x1f\x02\x1c\xe5\xc0=\x03\xef\ +\x96\xef\xbcY\xe0\xeb/>\xc5w2\x11\'O\xba\t\xc9\xf3\xbc\xcf\x95\x80\x88\xa1\ +\x93\xa4\xec4c\x1a\xed6\xceh\xa2\xc0M\xc4\xfb\x83\xfa\xe6\xfc{\x9c\xfd\xf8\ +\xfd\x898\xa2\xf0\xd5s\xe0\xfb3\x19\x95\xb4\xa9\xd5vX^}\xc4\xbd\xf5*\x8df\ +\x8c\xef\xcc\x01\xbc\x14\xc2\\9\xe0\x87\xab\x97(\x15\xc2\x038\xa2\xf0\xf5\ +\x11\xd2\xa8~c\x95v\xa8V\xab\xdc\xbc\xb5\xc0\xf5\x9b\x8b,\xadV\x89\x93\x8cb\ +\x0f\xef\xff\xbe\xfa\xe8\x14W.}y\x00w\xa2\x08s\xd3M\x9d\xa7\xc5G\x8fW+9\xdbO\ +Zl?^c\xb1\\\xe4\xc2\xd9\x0f\xb9\xf2\xf9\'\\xw\x96R\xe83[\xf0\xf8\xe9\xfb\xcb\ +\xfc\xf7\xef\rj\x1b\x8d\x01\x8e(\x823?^\xbb\x96\xc9\xd1\xf1\xfd\x87\x8cJ\xda\ +<\xae<\xe4\xf6\xe2\x1dV*5\\P`\xfed\x99s\xf3\x11\xfe\x1boq\xf3\xef\xbfp\x92\r\ +\xf3\x81T\x86\x1f\x0c/\x8a\x8fn\xb5\\r\x96\x97n\xb3\xbc\xf0\x0f\xbf\xcf\x9d\ +\xe4\xbb\xab\xdfr\xf1\xb3\x0f\x98?\xfd6[\x8f\xee\xf7\xda+\xbc\xf3\xbf9\xa7\ +\xed\xcb\xc5\'\xadvDQ\x08}\xf2N\x0b\'\xe9\xf8\x1a\xd8\xff\xb9\xf4*p\'\n\x95\ +\xa9\xc1\x93\x0f\xce\x81\xd7\x85\x0f\xdb\xef;\x07\x8e\x13w\xa2\xf0\x8f\x13G\ +\x14\xff\x03\xe8\x84\x1b+\xdf\xf26\x9e\x00\x00\x00\x00IEND\xaeB`\x82' + +right_png = \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ +\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x04\nI\ +DATx\x9c\xc5\x96Ko\x1bU\x14\xc7\x7f\xf3\xb4=&\xd4mQ_H\xd0"\xdaD,\xda\x8aR\nB\ +\xa8\xb0a\x83\xc4\x82\r{>\x01_\x00\xa9;>\x04\x0b\xb6,\xd9\xb0fQ@\x08\x81BU\ +\x92\xaa\xa1\xa5\x0f\xbbQ\x12\'c{\xecy\xdf\x07\x8b\xf1\xb86u\x9c\xa4I\x95\ +\xd5\x9ds\xe6\xce\xfd\x9d9\xf7\x9c\xff\xbdF\xa3\xd1\xe0\xbb\xdf;:S \x15\xe4\ +\n\xa4\x06!Ah\x10C\x7f\xaa \x97O\xe7\x08]\xd8\xb9*\xe6\xc4\xa2\xb0\xb3\xe1\ +\xfbT\x0emY<\xc7\xa2\x18K;\x93\x90\x08\xb0\xbf\xf9\xa9\xa3/\x9dx\xea,\'\x8c\ +\xdbQ\xf9q9\xaa\xb1\xc5\x04\x0cr\xa8X\xa0u\x11|\x0e\x18\x80\x1a\xda\xd90\xd0\ +\\M\xc2\xa5\x94\x98R\xef\x1f^.\x98JH\xe4\xa4\x1d\xe5\x85/\x1d\xfa\xc6\xe1\ +\x88\x14S\xaa\xc3\x83k\x99\x15\x198,8y\x84]nA\xb9\xf8\x1fK\xf7\xb1\xaa\x1e\ +\xa7N\x9dBH\xe3\x85\xc2\x11)\xb6T\x93\x7f\xde\\\xf7\xf9\xfe\xdb\xaf9s\xe1\n\ +\xd7\xae\x7f\xc2\xf9\xf9\x0b\x98N\xe5\x85\xc0\x8b\x00\xf4d\xda\xaf]\xbd\xc2\ +\xcd\x9bW\xb9\xfb\xf3\x0f\xdc\xbf\xf5\x0b\x8d\xb3\x17Yx\xf7#\xe6\xdf\xbaHm\ +\xee(\x992\x0e\x0c\xaeE\x86-\xd4\xe4\x9eKm\xf2\xe9\xe7_\xd0\xbc\x7f\x87\xb8\ +\xd7\xc6o\xad\xf0\xebz\x8b\xc5\xdf\xcer\xf2\xcdK\xbc\xbep\x89\xa3\'N#\rg\xdf\ +pD\x8au\xfd\xcb\x1b7\x8eT\'\x0b\xce{i\x8e\x9e\xac\xd0\xfa\xf7.\xd8\x15\x8c\ +\xca\x1cBi\x02\xbfM\xeb\xf1CV76I\xa5\tN\ri:\xcf\rG\xa6\xd8#q\xf8_\xb5\xbf\ +\xf7\xc1\x87\xdc\xb9\xfd\x17\xdd\xf6*85\x0c\xbb\n\xae\x872\x1d\xfa]\x9f\xfe\ +\xd2"n\xb3\x85\xf7\xca\xab\xd4\x8e\x9d\xc1\xacx\xa4\xd2\xdc\x13\x1cQ\xb6\xe1\ +\x94V\xb3\xdd\x1a\x97?\xfe\x0c\xcbk\x8c\xe0\xb8u\x0c\xd7\x03\xc7\x03\xd7#\ +\x97\x9a^0`cm\x95\xcd\xf6&a\x94\x90\xe4z\xd7p-RL\xa1\xb6\xef\xf3\xb3o\x9c\ +\xe7\xe4\xfc;S\xe1\x86\xe3A\xad\x81\xe1zh\xabJ\xaeM2\xa1\x90\x18\xb8\xa6\xc6\ +6\x14\x86\x88g\xc2\xc9\xa3a\x11n\xd3\xe7\xb9\xb6\x98\xbf\xfc>\xbe\xdf%\x13b*\ +|\xc2\xe7z\xd4\x1d\xf0\x1c\x9b\x97\x9d:H\x9b\xa0\xd7\xa3\xd7MI\x92g\xe1\xa36\ +\x9c%2\xf5\xc6q\xce,\xbc\xcd\xa3\x95%\xb4S\xdb\x05\x1c\x1a\x15\xf0\x1c\x83\ +\xbaS\xe5\xdc\xf1*\xc8c\xf8\xdd.\xcd\'kl\xb5\xd7\xc8\xcbm\x91\x19F\xa3\xd1\ +\xe0\xab\x1f;z\x96\xc8\xf4\xa3\x8c\xbfo\xfdI\x14\xc5\xbb\x84S\xd8v1\x96\xef\ +\x1cC1\x08\x07,\xdfk\xb2\xf2\xcf\n\x9d\xcd\rl\xd8Y\xe1\x94\xe5b\xd7\x8f\x82\ +\xae<7\xbc\xee@\xa3b\xf2\xda\x919N\xcf\x9dC\xc4\x01\x8b\x1bO\x8a\x00v\x92\ +\xd7\xad\xde\x800\xcd\xf7\x05\xaf\x9a\x92\x87\xeb\x01\xb7\xef>`iy\x99\xb0\ +\xe7\x83\xc8\x8a\x00f\xc1\xc3L\xb1\xde\xdeD\x19\xce\x9e\xe1U[\x93$\x19\x0f\ +\x1e\xb5Y^\xb9\xc7\xdaj\x93<)\xdb2+\x84\x08f\x1f,[\x9d\x80$\xc9\xf6\x04wME\'\ +\x08\xb9\xf7\xf0\t\xad\xc7\x8f\x18\xf4\xb6@\x0e\xab\x7f\x0c\xae\xc50\x80\xed\ +\xe0Q&\xe9\x06\x01z(D;\xc1\x919\xcd\xad\xb1j\x8f\x82Q\xb5O\x83\x93E\xc3\x0cl\ +s\xaa\xf9\xdd\x1e\xb9d&\xbcf)\x928\xa1\xb5\xb9E\xbb\xbdA\x18\xf4&\xfa|\x16\ +\x9c2\x03\xd3\xe0\x838%\x8c\x92m\xe16\x92\xb0\x1f\xf2\xd8\xef\x10t}\xf2$|Fdv\ +\x82\x8f\x02\x98v\xa4\x06\x83\x08e\xb9\x13\xf0\x9a\r\x15r\xfc\xce\x80A\xafK\ +\x1c\xf6\xa7\xca\xebn\xe1\x1350\x0e\xefG)Y\xaeFp\xcf\xd2X*\'\xee\x87\xf8a\ +\x80L\xe3m\xb5}/\xf0Q\x06\xc6\xe1q\xae\x88\xe2\x14\x9c\x1a\xb85\x1c\x9d\x93&\ +\tQ\xdc\x1f}tP\xf0\xa7m8v\x99H2\x89\xb6*`9\x18YB&\xd3\x1d\x8f\xd4\xe7\x85\ +\x8f20~\x93\xc9q\xd0\xa6\x84\x0f\xae\xeb\xd2\x7f\xcb\xe5\xb2\n\x85\xcb\xcaf\x0f\xc8\xb6\r9\x8e\xa9\ +\\.\xadbqZ\xbe\xef\xeb\xf3\xff&}\xc7\xf3.\xe9\xea\xd5\xf3\x8c\x8d\xfd\xc3\ +\xdd\xbb\'i\xb5~\xa0\xd9\xfc\x9e;w\x8e12r\x1f\xcf;\x85\xe7]T?c\xb8\xae\x0b\ +\xc0\x89\x13\xdf(\x93\xf9\x9f\xf9\xf9\xf38N\x004\x81w@\x04t\x80g\x84a\x8d\ +\x99\x99\x80F\xe3$\xd5\xea\xb2\x01\xec(\xf0\xbcK\xcad\xa0T\xba\x8d\xe3\xe4\ +\x81D\x17\xec5k\x03-\x1c\xc7\xa0T\xdaE&\xb3\x84\xe7]\xd8)\xfa\xbe\xaftz\xaf\ +\x82\xa0&\xe9\xb9\xa4\x07\x9a\x9d\x9d\x15 \xa9 \xa9 @\xa9TJ\xd2\xa0\xa4\x01\ +\x05\x01J\x1fD\xbe\xef\xcb(\x16\xa752\xb2\xc5\x8d\x1b7\x01\x0bx\x82a\x9c\x03\ +@*\x00\x9b\xe4\xf3OY]]E\x1a\x04E\xb0e0\xf7c\xc4Z\xa3\x80Y\xa9\xdccrr\x18\xd8\ +\x00\x9e\x01\x7f\xf6Y\xd4\x016X__\xef{\xdb\x86\xce \x93\x13I*\x95E\x0c\xc71\ +\xd5l^\xc7q\x92@\x9b\xa9\xa9\x97,,\x04\x1f\x8d\x83\xf5\xae\xa1]8\x8a`s\x88\ +\xb0m\x918\xd4\xe8\xc5\x18t\x1d\x7f\xcb\xc2B\x08l\x02\xcb@\xbd\x0f\x16h\x8b\ +\xaf\x0e\xc6!\x1c\x800\x0e\x80\x99\xcd\x0eS\xaf\xff\x0b\xbc\x02\xea\xe4\xf3\ +\x8f\x80\x87\xdd\xce\xfa\x04\x13Bd\xb2\xf6\xf2-\xb4\x92\xd4W\r\xb2\x87R\xd8\ +\xe3\xe3gY\\\xfc\x85\xb1\xb1\x18 j5H$D\xb3\xd7\x98m`\x0b"\x83\xe3G\x93\xe8\ +\xf90\xb4v\xb3\xf8\xe05\xe3g&z1\x1a\n\x82\x81nL;Q)\x1eW,\x16\x93m[J\xc4m\x1d\ +\x1b\xdd+m\x1c\x91j\xa7\x15<\xfeN\xe9\xfd1\xf9Ke\x19\xae\xeb\xe2y\x17\x14E?S\ +*\xd9}\x92\x05\xe66\xc4,&\x8e\x0eQ\xfe-\x05\xed$\x84\xbb\x98\xbeY\xc3J~\xcb\ +\xaf\xbfW\x8c\xbeQ\xfeZ\x99\xcc\x12\xf3\xf3\xe08=\xf5&\xbc\xdf\x03o\xf6C;I\ +\xd8\x8c1s\xebo\x1a\xff\x1d\xa0\xfa\xd7\xda\xa7Q\x06\xa8V\x97\r\xcb\x9abt\ +\x14\xe6\xe6`e\x05\xc2\x8eE\xd81Yy\xfa\x8e\xb9\x9f^0z\xee!\xd6\xee\xd3\x1fa\ +\x00>_O\xdf\xf7U,^S.\xb7O\x8e\x8d\x1c\x1b\xe5\x0e\x0f\xa98}E\xfe\x1fK_\xac\ +\xf3\x07\xc0b=\xfa\xc1x\xb5\x84\x00\x00\x00\x00IEND\xaeB`\x82' + +smile32_png = \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ +\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\t\xc0I\ +DATx\x9c\xc5\x97il\\\xd5\x15\xc7\x7fo\xde\xbc7\xfbx6\xdb\x93L\xe2\x988\x9b\ +\x81\x10H\xd8\n\xa8-\x90PJ\xcb\xee\x90\xb0\x94B(\x08\xa9\xad\xa0\x85\x82J\ +\xa5\xaa\x1f\xa0\xa2\xa8,\x95\xba( \x81\x08!\x0b!\x86\x8a\xadI\x03\x05Z\xc2\ +\x1ah\x16\x12c\xc7`;\x1e\xc7\x9e}<3\xef\xbd\x99\xb7\xdc~\xb0\xb3\xe1\x80\xaa\ +~\xe9\x95\xae\xf4\xf4t\xef\xfd\xff\xee\xb9\xe7\x9c{\x8f\x14\x89D\xf8\x7f6\ +\xf7\x7f3h\xcd3\xcf\x8at:\x8d\xaeiH\x92D\xa1P\xa4\xd1h\xa0\xe9\x1a\xd9l\x16\ +\xaf\xd7\xcb\t\xed\xed\xa8\xaa\x8am\xdb\x04C!R\xa9\x14\x91H\x84\xe5]WI_\xb7\ +\xb6\xf4U\x16X\xfb\xecz\xd1\xdf\xdf\x8fe\x9aD\xa2Q\x12\x89\x04\xa6i\xd2\xbf\ +\x7f?\xbb\xf7\xec\xc1\xeb\xf5\x92lM\xb2{\xcfn>\xf9\xf8\x13\x96]\xb4\x8c\x13;\ +;\t75!\xcb2\xd9L\x86\\.\x8f\xdb\xedf\xee\xbc\xb9\xfc\xfcgw\x1c\x17\xe4\xb8\ +\x16x\xe4\xd1?\x88\xbe\xbe>\x96,^B"\x11G\xd3t,\xcb\xc2\xa8\x1b\xf8|>T\x8f\ +\x87P(Dkk+\xc1`\x00\x80\x83\x07\x0f2o\xee\\|>\x1f#\xe94\xd3S)\xe6\xcd\x9fO\ +\xb5Z\xe5\xa3\x0f?\xe2\xea\xaek\xc4\xb9\xe7\x9e;\x05\xe4\x18\x80u\xeb7\x8a\ +\xdd\xbbv\x91\xcdd\x08\x04\x83\x94\xc7\xcb(\x8aB\xbe\x90\'\x16\x8d100@*\x95\ +\xe2\x9co\x9c\x83n\xe8\x94\xcbe>\xeb\xed\xc50\x0c\x06\x07\x06Yz\xe1\x85L\x9b\ +6\r\xdb\xb6\xd9\xdf\xd7G\xad\xa6\xe18\x0e\xc5R\x91\xe1\xe1a\x06\x07\x07\xb9\ +\xf2\xaa.\xb1r\xe5JV\\\xd3%M\x01x\xe5\x95W\xe8\xee\xeef\xe1\xc2\x85\x94\x8aE\ +\xa2\xb1\x18~\xbf\x9f\xcf\xfb\xfbY\xb6\xec"\x92\xc9V*\x95\n\xd1h\x94x<\xcec\ +\x8f=FOO\x0f\x99L\x06\xaf\xd7\xcb\xce]\xbb\xb0,\x8bH4J\xa5R\xa5\xbb\xbb\x9bb\ +\xa9\xc8\x9c\x8e\x0e2\x99,\x8a\xa2\xa0\xeb:{\xf7\xee="\x1a\x89D\x88D"<\xb7i\ +\xb3ho\xef\x10\x1e\xaf_\xdcu\xd7="\xdc\x14\x15\xe7_\xb0T\x84\x9b\xa2Br\xb9\ +\xc5\x82\x05\'\x89\xef_z\xb9\x98={\xae\x981c\x96\xb8\xeb\xae{\x84?\x10\x12H\ +\xb2@\x92\x85\xe4r\x8b\xef\\|\x89X\xb8p\x91hk;A\x9cz\xeab\x91hn\x15H\xb2\xf0\ +\x07B\xe2\xf4\xd3\xcf\x14\x92\xcb-\xce8\xe3,\xd1\xb5|\x85\xd8\xb2u\x9b\x88D"\ +G,\xd0\xb3o\x1f\x8dF\x03\xbf\xd7\xcb\xa7\xef\xbeC\x9bdS\xfdl\x1fm\x8a\x0b\ +\x11\x8f\xe2\xd3*\x94v\xef\xc4_\xab\xe1\xb7\x1d\xde{\xa1\x9b\xd9.\x17x}\xe4M\ +\x93\x8am3\xf0\xe9^\x86GF0\x1c\x1b\xa1\xebx\x05\xc4\x90@\xd3\xe9\xed\xed\xc5\ ++\xcb\xe4\xb29Z\x93I\xca\xe5\xf2\xb1Q\xb0a\xe3&\xa1e\xb2\x046>\xcdl*\x04B!\ +\xacX+\xdbX\xcc\xe6\xfa)\xb42\xca\xaa\xe6/\x98\xa3\xd4\x10\xba\x81(\x14A\xd3\ +\x11\xe9\x0c\xf9L\x8e\xf2h\x81}\xca,^\x9b~6\xfd\xb2\x97\xcer?g\xa5\xdf!\\/\ +\x93G\xd0\x87M\xc4\xad0\xe7\xd2K\x98y\xf3\r\\\xff\x83\xeb\x8f\xf5\x81\x95+\ +\x96K\xef\xdd\xb4JL\xa3\x8a\x14\x0c E\xa3lu/&y\xe3O\xd9\xf9\x84\x865>H\xcf\ +\x80\xc2\xf3\xe7\x17\x898uDS\x18gx\x04a\xda\x04\x1a&=\xbe\x0e\x12\x8f\xaea\ +\xc7F0k\xa3\x8cU\x0e0\x16Hr\xe7\xee\xa7\t\xe3\x90@\xa2b9\x94_\xfb;\xd3N>\xe9\ +\xb0\x0b\xb8\x0e}ly\xe0A\x91\xd8\xb9\x1d\xc9\xed\xc6\x15\x0c!\xb9=\xbc\xeb\ +\xcc\xe2\xb6\'4\x1cK\x03 m\xa8\xechx\x91\x12\t\xa4D\x1c)\x1eC\xf2{q\xc5#t\'\ +\xcf\xe7\xce\x8d`\x9b\x06\x00\x02\x89\xde\xd0tz\x02\xcd\xc7\x84\xb8i\x18\x1c\ +\xe8\xfe+\x9b7l\x12\x87\x01^x\xbe[$\xb6nAih`9\x08K\x80\xc7K\x8b\xab\x80=>\ +\x88\xa3eq\xf4,\xaa\x18\'\x10\x0bL\x00\xf8\xfdH>/\xf8}\x00\xa4j\x038\x954N\ +\xa3\x84c\x14q\xac\x1a\xe1\xea\x18Q\xbd0%\xcf\x8c\xf5\xeeg\xfc\xdd\x0f\x8e\ +\xe4\x01W\xb1D =\x88p\t$\x1b\xb0\x04X\x82\xe5\x89Q\xfeU\xf8\x80>#\x82\xaah\\\ +\xb8\xc8\xcbi\x0b\xe7A~t\xca\xa2]\xe3\x1f\xb0o\x8f\xc5\xfb\xb1ET]n|\xc5^\xbe\ +}\xe0\rf:\x16\xd5/\x8dm8.\xd2\xdb\xdef\xf3\xe6\x17\x85\x1b@\x1d\x1cB\xaeV\ +\xc0\xe7A\x98\x0e\x92)\x106\xb4\xc8&\xeb\x97\n\x86|\x02Ob&\xb1\x96\x18~\xe1\ +\xe0L\x91\x87\x80S\xe7\xb7\xe9\x978\xb0\xe7y\n.\x19\xc7\xd6\xf186\xe3\xc7\ +\x19\x8b\xec\xe1`\xdf\x10\x1d\xe9\xf4\x84\x05\x94\\\x0e\xc9\xb4@U\xc0\x14\ +\xe0\x00\x15\x1d\x112p\xe9\x1a\xed\x01?\x92\xab\x01\xb9Q\x1c@\xe4r\x08MC\xe8\ +\x06h\xfa1k\'\xed\x06A[PEP9\x9e\xf8$\x80a\xb9idr\x93\x00c#XB \x8f\x1b\xa0\ +\xd6\xb1\xc7J\xb8$\x15\xf2\x05\x84\xcf;1I\xd3\x0e\xcf\x17\x9a\x86\xc8\xe5\ +\x11\xf9\x02B3p\xf2%\x84^\x07\xbd\x8e\x85\xc0\x02\xcc\xc9n\x1fG\x1c\xd9\x83-\ +\xfb1\xb2\xa5\xc90\xac\x94\xb1\xea6\xaai\xc1\xd88R\x8bLv\xd8M\x8bW\xc7\x19\ +\x1eA\xd2\x8d\t\x87;\x04\xa0\x1b\x88|a"\x0f\xe4K\xa0\x19\x88B\x05\xa17\xb0\ +\x01\x0b\x81\x89\x00\xc0\xc1M\x81\x16`\x18\x1b0\xd50\xb6\xac`\xca^*\xe9\xe2\ +\x04\x80\xddp\xb0\x1c\x81\xd1\xb0\xf1Z\x06\xaf\x0e\\\xc0j\xee\xe4\xba\xec\ +\x0b\\\xb7\xe8\x8d\t\xa1Io\x9f\xb0\x86\x8e\xd0\x0cD\xbe4\xd1\x0b\x15\xd0\xeb\ +\x18\x08L\xc0\x9a\xdc\xb9\x8e`\xb5\xfbe\xf4x\x8a\xc5c\xf7\x92P\xdf\xc4\x94=\ +\xd8j\x18I\xf6#$e\x02\xa0\xde\x9c\xc4\xb0l\x84-\x90\xab\x06#R3\x9a\x12d}\xe1\ +\n\x96|\xf6!\xf3\xdb\xb2\x90/\x1dcI\xe7\xe8\x9d\x17\xc61\xf5\x06\x06\x1c\x86\ +0\x81\xb7\xb8\x9d\x9c\xa7\x13\xbf\xa8RqM\'"{\xb0\xd5\xd0\xc41\xa8\x01\x02\ +\xd3&\xef\x02+\x1cA\xb7\x04.\xcb\xa1n;\x84\x19\xc3\xed3\xc9\x97\x9a\xb9\xd3z\ +\x88K3/qk\xcbjd\xe9\xc8\x89\n\xbd~x\xe7\xa6\xde\xa0>y\xf6:0F\x0bkx\x88\x81\ +\xe07\xa9\xd5\x82$[FH\x16\xdf\xc5RC\xd8\xb2\x8a\xa34!\x84\x89\xaf9<\t0k\x06\ +\x86\xac ;:\x02X\xc0[\xb8\x95\xbb\xf1x\x0cf\xcd\xfa\x82\x97\xd3\x97\xb0\xe5\ +\xe02f\xd4\x078\xd1\xda\xc5\x12e;\x91\xc6(\xed\xf5\x0cu\x04=\x9c\xc4\x10\x1d\ +\xec\xe1lz\xbdgR\xf2\xa4@\x92\x08\xfbJ4\x85\x8b\xa8\x8a\x8e\xdb\x93\xc7\x90C\ +8J\x13\xa6\xec!\xe0\xb1\xf1\xb7\xa7&\x00\xc4\xcc\x14F \x84S\xaa\xd1\x00b|N\ +\xdc\x9f\xa5\xaa\x86\x98?g\x1fw\xff\xf8\x01^\xddv9;\xfe}&\xaf\x16\xaf\xe2U\ +\xae\xc6\x96\xdc\xb8\x03\r\x00l[\xc1%\xdbH.\x87d\xf3(\xdf=g\r\x0b;w\xf2\xc4\ +\x9a\x9f`\xd4\xbd\xa4\xa4\xedXj\x88\x86\x1a\xc2V\xc3\x085\xc4\xf4y\x01V\xdc\ +\xbaJr\x03\\u\xcbM\xd2\xa6s\x96\nkh\x04\x81\x04\xd8,\x93\x9ed\x9dq\x1f\xdb\ +\xdf?\x0f\x10\xdc\xf6\xc3?r\xfb\xcd\x8fQ,\xc6)\x14\x13\x0c\x0e\xb7c\x9a\n\ +\x00\x01\x7f\x8d\xb6\x19\x03\x84\x82\xe3$\xe2YF3\xd3x\xf8O\xf71^\t\xa2*\x16\ +\xb1\xe2\x0645\x8c\xa3\x84\xb1d\x0f\x8a\xc7\xcf\x8c\xf3N\x86\xb7\x8f\xba\r]\ +\x97]\x8c\xf1\xe1\'\x98\xb9<&p\xca\x81\xa7\xd9\x92\\\x05\xaa\xcc\xaeOO\xe3W\ +\xf7?\xcc\xcd\xd7=\xce\x89\x0bv3}Z\x9a\x93O\xdc9%\xbf\xd4\xb4\x00o\xfc\xf3"\ +\x9e\xd9\xb8\x8aHS\x89\xf1j\x84\x94\xb4\x85\xba\x00\xc7\xe5\xc1T\xc38j\x88T\ +\xab\x9b\xd8\xe29\xc0\x97^\xc5\xeb/\xbdF\xe8\xeb\x9eCq@\x06*t\xf0Lj-\x86\xe3\ +\'\x16)ppl:\x1d\xed\xfb\xb9\xec\xe2\xcd\xcc\x99\xddK"\x9e\x01 \x93M\xb2c\xd7\ +\x19\xbc\xfe\xe6\xc5\x0c\xa5\xdb\xe9h\xefc\xff\xc0\\Z\x03\xbd\xcc5~\x8d\xa3z\ +h\xa8a\x1a\xbe\x042\x06\xe7\xafZ\xc2-\xf7\xffr\xea\x9bP]~9\xc6\xde\x1e\xf4\ +\x8fw\xe2\x06\xfc\xf4\xb3"\xdd\xc5\xdf\xda\xffL\xdf\xd0\xa9\x9c\xbap\x07~\ +\x9f\xc6\xd3\x1b~D\xb9\xdaD"\x9a\x03\xa0<\x1e\xa1)\\\xa2m\xc6\x00\xa6\xa5\ +\xb0\xff\x8by\xcc\x0e\xbd\xcet\xfd\xf1\xc3\xe2\x96\x1aB\x92\x15\xe6w*DN\xeb<\ +\xac9\xa5.x\xeew\x8f\x88\xdco\x1e\xc4\x1c\x1dC\x99$4\xf1\xf1R`5\xe3\xb1N*\ +\xb5&Z\x9b\xc7hI\x1c\xa4m\xe6 \x00C\x07N\xe0\xf3\xc1\xd9\xd4\xf4 !_\x89P\xf1\ +\x1ft\xf8\xd7b*\xe1\xc3\xe2\x96\x1a\xa0-^\xe7\xac{\xaf\xa4\xeb\xdak\xa4\xaf\ +\x04\x00Xw\xc7/\xc4\xe8\xea\xa7h\x8ceP\x8e\xfa\xdf \xc0`\xe2Z\x06\x03\xdfc\ +\xac:\x1b\x07\x19\x00\xb7\xabA\xab\xaf\x87&\xed-\xe2\xce\xdb4\xd4 \x8e\xeb\ +\xc8\xce-\x97\xcc\xccf\x87\xd3\xef\xb8\x8c\x95\xb7\xdcpL]\xf0\x95\x95\xd1\ +\xc6\x07\x7f/F\xff\xf2$\xa5O\xf7"\xec)W\n0\x91n\x1bj\x08K\xf6`\xa9!L\xd9CC\ +\x9d\x8cu5\x8c\xa5\x06q\x99e\xe6\xceS\xe9\xbc\xe5\nV\xac\xbaqJu\xf4\x95\x00\ +\x00\xcf\xaf]\'\xc6_\xdb\xc6\xe8+[)\x1d8\x80\xe3\x1c\x05"Ox\xb59\x99^\x0fe8[\ +\x9d\x085YQ\x88\x055\xe6_0\x9f\x96\xa5\xe7q\xf5\xf2\xab\x8f[\x9a}-\xc0\xa1\ +\xb6\xe9\xa95\xa2\xb4\xf5\r2\xdb\xdf\xa7:\x96\xa3VkP\xb7\x04\xb6\xdb\x87\xad\ +\x04AV\x10J\x08\xb7\xea\xc2\xe7s\x13\x9b\x91$\xf5\xadE\xc4\x96,8\xe6\xbc\xff\ +g\x80Cm\xf3\xe6\x17\x85S.S\x1f\x1a\xa6\xba\xef3L}"\x13:\xc2A\x89F\x89\x9e~\n\ +J\xef\xa6\xaf\xf4\x07\xf7\xefyF\xd5\xf2g\xa9\x15\ +\x06\x11\xc1,Am\x14+\xd1\x81\xe1\xac\xc1L\xde\x88\x11\xdf\xc07\xb7\x7fK\xac\ +\x94<\xb1RN|\xe0\xf9\xdd*w\xf9u.\x9d\xd8CX\x1b\'a{\xd8\x16d\xdc\x85\tJ \x8d\ +\x18V\xeafd\xf6~\xcc\xf4\xed+BdE\x08\x1cx~\xb7:q\xf8o\x99\xbc\xfc;\x1c\xd3\'\ +\xe3\xce\x03O\xbb\xe0X`\x9bW\xe7\xd6<\xa8\xf96\xa1\xfb\x87\xc4\xaf\xffA\xc3$\ +V\xc4\x84.\x1d\x7f\x8eK\x83G\x89Y\xc1\'\xe0\xdb\x9a\xe6\x81g\xdc\xcf\x12\x98\ +-\xd6\xa8\xd5\xdf\xc0\x9f\xd9\xd4\xb0\xec\x86\x9dx\xc7?\x7f_\xf5\xbd\xf7\x02\ +\x9a\x9c\x07o[\xf3\x7f\xde6\xa1-\x0b\xd9\x14\xc4\x9d\xab=\x9b\x9a\x1f\xb7\r\ +\x0fr\x078\xb0\xe7\x17\xeas%p\xee\xc3\x17\xf1je,\xe3\xea\x1fw\x16l?\xee\xfc\ +\xfe5qg\xfe\xbd\xee_ *\x1emH~C\x04\xf6\xef}VM\x8c_\xfe\xcc\xb8m~\xdal~_\xb3M\ +p,EX9\xd7\x08\x84\xc6\x08\xa8(\xc4\xf3\xfc\x86\x00(\x7f\xb6\xa1\xf5\r\x11\ +\x98\x9d:G>_n\x08@!7\xc4\xf3\xfb~y\xcd~\xd0P\x14:=0N\xad\x1ea\xe8P\xaeA\xbe\ +\x0cRB\xa9\n\xd3ypcW\xe7\xda\xb6\x8dm\xdb\xe8\x9aF\x10\x86\x9c\x1f\xf18>Pa\ +\xf0\xca4_i\x99\xbcf\x0c\xd7L\xe0\xc5\xfd\xff\xa1\x9e\xfe\xc5\xbfp\xe0p\x04\ +\x80e\x82\xa1\xfd\xcf\xf3{z\xae\xa7\xb7\xb7\x97m\x7f\xb0\x8d\xb7\xdey\x8bCo\ +\xbeM\xdf\x87\xa7\xd0\xb4:\xb7\xf6\x9e\xe4\xd7/\xeeR\xdf\xb8\xff\xdb\xcb\xde\ +\x13\xae\xc9\x84\x9e\xfd\xa7\xef\xaa\x96\xdaO\xd9\xbc\xee\x12=\xeb\xe2$b:\ +\x86\xa1\x834P\x18\x94\xaa|\xa6W\xea\x92\xd1\xf1B\x08R\xae\xcb\xd6\xeen\xfeh\xe3M\x18\x9a\x8ea\x1a\xe4\xa6\ +\xa68\xf2\xe6\x9bK\xc1\xbf\xb8\x06\xfcj\x05\x15\xf8L\x8e]\x01\xa50M\x93+\x95\ +"g\x86.\x12\x04\x01\xb1X\x82\xf6\xf6N\x92\xc9\x0cn\xc2\xa5;\xe5\x12\x85\xc1<\ +\xf8\x05[\x97R\x92\xd2u\xba;:\xb0m\x87\xa6l\x0bm\xad\x1d\x98\xa6\xc5\\\xa1\ +\xc0\x91\x93\'\x99\xacV\x90RbY\x16A\xdd\xe7\xec\xb1\xbe%\x11XT\x03~\xa5\x8c\ +\nCf\'\'H\xc4\xe3\x08\xa5\xd1\x1c\xe9\xdc\xb5\xf5\x0e\xe2\xc9\x0c1\xc3\xc4\ +\xb4l\x94\n)\xcd\xcd\xe2\x196\xc5P\x91\xf9\xf8\x03B\x12\x112^\xf1\xf8\xd2\ +\xedw\xd3{\xa7A(utM\x92\x9b\x9dfrf\n+\xac\xd1\x92J#\x95"\x16\x8b\xa3P\xcc\ +\x8e\x8f\xb3c\xc7\x0e\xf5\xe8\xa3\x8f\xfe\xaf\x11iQ\x02\x91\xef\xa3K\x81\xa5\ +i\xb8\x89\x04U?\xc2p\xb2\xac5tz\xd6v\xa1\x87ut)\x90*\xc2\xbc\xa1\x9b\x81\x91\ +\x11N\x8f\\fu\xa9\xc2\xe0\xe8%R\xf1\x04\xa9\xd5\x1d\xac\xbd~#=\x9d\x9d8""\ +\xf0\xabH)\t\xda\xb3\xcc\xd5\xd630:\xc6D\xbdF\x97\xa3\x93t\x13h\xa6I\x04\x0c\ +\r\r-\xaa\x81\xc5\x9d8\x08\x88\x82\x00\xbfRf$_`Z\t\x0c)\xd9\xb4~#\xa1W\xa5^)\ +P\xc9O\x13\xd6\xab\xe0\xd7\xd9r\xd3\x17\xb8\xed\xe6[\x98\xae\xd7\x19\x99\x99\ +f\xacP\xa0s\xfdM\xdcy\xcbVb\xa6N\xe8W\x89\xc2:^%O\xe0UH\xdb\x06[\xbao`\xba\ +\x1epdd\x9c\xa9j\x15\xcb4\x91J\xe1\xd5j\x8d\x13\x88\xc2\x90Z\xb5\xc2\xdc\\\ +\x8e\xa0^\xe5\xe2\xa5A6\xae\xef\x99\x0f\x83JQ\xafU\xf1}\x8fz\xbdB\x18\x05DQ\ +\x84\x1bO20t\x91G\xbe\xfe\x15\xdc\x98\xc5\xf1\x93\x1f0W\xcc\xcf\xef\x13\x86\ +\x85&@j\x12\x15\x85h\x9a$\x93L\xd2\xde\xdcFan\x1a\xd7q\xf0\xc3\x10/\x08>\xb5\ +\xd7\\3\x01?\x8c\xa8\xd7j8v\x8c\x94&\x88\xbc:\x02\x85\x14\xf3\xf1[\xd7-\x14\ +\x02\xa5\xe9\xd4\xbd\x80\xc1\x8b\x83\xec\xd8\xf5o\xacJX|\xe7\xeb\xf7\xf2\xbd\ +\x07\xefg\xf8\xf2\x00O\xef\xfcW\xaa\xb5\n\x9a\xa1a;1\x0c\xcb\xc4t\x1c\x84\ +\x9cwt\x85\xa2\xbb\xbd\x8d\x98m3[.\x11\x08\xd0\xf4\xc5\xb7\xa9E\th\x96E\xe0\ +\x05\xd8\x8eC\xd6qp\r\x8d\xbe\x8f\x8eb[6\xae\x9b\xc6\x89\'HfZ\x88\xb9\xab\ +\x98\xadz\xec\xf9\xcd\x8b\xdc\xb7\xf9F^z\xf2\xafX\xd7\xd5\xc9\xb7\xff\xf4\ +\x9b\x1c\xfc\xc7\xbf!\xa6G\xbcz\xe8%\x94n\x10\xe9\x06\xba\xe3b\xdb\t\x9c\xb8\ +K\xc9\xf3\xe8;\xfe\x01m-\xcdxB\xa1t\r\xa5\xeb\xf3\xa1\xb8Q\x02F,\x06J\xcd\ +\xc7v"\xbe\xd0\xd2\xcc\x85\x0b\x03|p\xb2\x0faX\xa4\xb2m\xb8\xd9V\x8cx\x86\ +\xd7\xdf=DO{\x13\x7f\xff\xf0\x9f\xd0\x94r!\xf0Q\x85<\xdd\xed-\xfc\xc3c\x0fs\ +\xf4\xc3~^{\xfb0N2K<\xb5\x9ax\xa6\x99\xc8\xb0x\xff\xa3>\xdaR\x0em-\xcd\xcc\ +\x14\x0bxa\x880\x8cE\xc1\xc3\x12\xa2\x90\x93L\xe2y>RH\x0c\xc3 )%[\xdb[8}\xf2\ +\x18\xfd\'\xfbi\xce\xaefMK\x1b\xa3\x93cL\xccL\xd2\xeev\xa0+\x05\xb5\n\x9f\ +\xdaJ\xbd\x1aQ\x14\xf1\xde\x07\xefs\xfdu\x1b0\x0c\x83\xf1\x99\x19fg\'ivmn\ +\xdd\xba\x05\x84`fnv>\x1d\x89\xc7\xd0\x97`B\x8b\xce0l\x07a\x9aD*$\x1eOP*\x14\ +I\xd86w\\\xd7E\xd1\xf7\x89\x00Y\xce\xb1&n3\x9eH\xf0\xf6\xd9\x0b\xfc\xc5S\xbb\ +\xf8\xde7\xeee\xdd\x9aV\xaa\x9eO\xdf\xf9K\xfc\xdd\xae\x17\x11(\xb6\xf6t#j\ +\xd3\x10\xeat\xad\xb2\xb9\xa3g\x0b\x9a\xd4(\x97\xcb\xcc\xe4r\x8cNN\xa2[6\xd2\ +\xb2\xe9\xec\xecl\x9c\xc0\x03\xdb\xb7\x8b\xa7~\xf635~\xfe<\x86\x13C+/\x1c\ +\xe2\x85 \x1d\x8b\xa1\x1b\x06\xbaa\xa0\xe9:\xa5 `*_\xe0\x95c\'x\xa5\xef\x14m\ +\x99$\xd5\xba\xc7\x95\xb9"\xa6\xaeQ\x0b\x15]\x9d\x9dt\xb4\xb6b\xda\x16\xb6ec\ +\xd9\x16\xbe\x1f\xe0\xf9>G\xfb\xfa(U\xabd\xd7\xac\xa5\xb3\xb3\x93\xc7\x1e{l\ +\xd1\xb4zI\xd9hv\xcd\x1a\xccl\x96\xd9\xa9I\x84n@\x14"\xa4\xbc\xda\x17r\x9e\ +\xee\xd6V&K\xdd\xbc\x7f\xe2\x04\xba\x80\\\xa9\x8c@\xa0P(-\xc6\x83\xf7\xdd\ +\xcb\xf5m\xad(\x14\x9eWG\xd3t,a#\xa4\xe0\xf4\xc0Y\x06\x87/\xe3\xc4\xe3\x98n\ +\x82\xeb\xae\xbbn)\xd0\x96~\xa0yf\xc7\x0eux\xdf^\xaaS\xd3\x18BbY\xe6\xfcIkA\ +\x03\x1fk\xc1\x0fC\x86\xa6\xa6\x98,\x95\x98+\x97I\xc4b\xb465\xd1\xd5\xdcD{\ +\xf3jL\xd3@\x01a\x14\xe28q\xdc\x94\xcb\xc8\xe5\xcb\xec\x7f\xe9U\xca\xf5:M\ +\x1dkY\xb7\xb1\x87\x9d;w.\xe9P\xb3\xac\xdb\xe9\x9f\xfe\xe4\'\xea\xd0\x9e\xdd\ +\xa8r\x95t2\x89m\x99\xf3\xe0u\x1d\xdd41\x0c\x830\x8a\x08\x95B\xd3u,\xcb\xc24\ +M\x0c\xcbBHP(L\xcb$\x8a"\xbc\xc0\xc7\xb2\x1dj\xb5*\x87\xdf?\xca\xe5+\xe3\xa4\ +V\xb7`\xa53<\xf4\xd0C<\xfe\xf8\xe3K"\xb0\xac3q\xd7\r7p\xeb=\xf7p\xec\xb7\xaf\ +3\x91\x9b!f\x98\xb8\xaeK<\x11Gj\x1a\xb50D3\x0c\xcc\x05\x8d\x08!\x88\x94\xc2\ +\xab\xd7\x91\xba$\x0c|\x84\x8a0-\x13\x82\x90\xbe\xbe~>\x1c8\x8b\x1fF\xacji\ +\xc5H\xa7\xe9\xed\xed]2x\xb8\x86\xfa\xc0\xc1\x03\x07\xd4\xe0\xa9S\xbc\xf9\ +\xc2\x0b\x14FGqL\x93\xe6\xa6&\xd2\xe9\x0cB\x93W\xcdI\xd3\xd0\x16HH)\x91R\x00\ +\x11(\xc5L.G\xff\x993\x8c\xcf\xcd\xa1\x9b&\xa9\xd66\x0c7\xc9]w}\x99\'\x9f|rY\ +wC\xd7\\\xe0\xd8\xf1\xf3\x9f\xab\xc3\x07\x0f2|\xea\x14\xa6\xd4\x16\xec? \x99\ +L\x92M\xa7q\x1c\x07\xc30PBP\xad\xd5\xa8T\xca\xe4\xf3s\\\xc9\xcdP*\x14\t4\r7\ +\x9d\xc6iiEZ6\xbd\xbd\xbd<\xf1\xc4\x13\xcb\xbe\xd8j\xa8B\xf3\xfc\xfe\xfdjx\ +\xe0\x1c\xaf\xec\xdc\x89\x0c|.\x0c\x0e2\xedy\xb4$\x93$]\x17MJ\xbc \xa0\xe6yx\ +\xbe\x87\xeb8\x9c\x19\x1d\xe3\xb6u\xeb\x18\x1e\x1e&\xb3i\x137\xddr\x0b\xdb\ +\xb6m[\x96\xd9\xac\x18\x81\x8f\xdb=\xb7\xdd\xa6:\xae\\\xe1G\x99\x0c\x87-\x8b\ +]\xc5"\xd3\xc3\xc3T,\x8b \x08\xd04\x8dD\xb9\xcc\xb6\xaf}\x8d\xf5o\xbd\xc5\ +\xed\xad\xad<44\xc4\xcdw\xdd\xc5\xab\x87\x0e5TbZ\x912\xab\x93JQT\x8a\xec\xd0\ +\x10\xdf\x12\x82\xbfv]\xc6\xcbe\xb4L\x06\'\x95\xc27M\x92\x1b6\xf0h\xb1\xc8\ +\xc3--\xac\x8a\xc7\t\x95b\xd3\x96-\r\xcb^\x91\x1a\xd9\x8d\x9b61\xecy\xd4\x86\ +\x86\x90A@\xe2\xd2%\xc2Z\r16\xc6\xadMM\xbc^(\x90\xae\xd7\xf1\x84\xa0R.3U\xab\ +\x91jo\xa7\xad\xa3\xa3a\xd9+\xa2\x81\xb6\xceN\xc6fg\x99\xeb\xea"\xd6\xd6F{S\ +\x13\xc9\xd5\xab\x19*\x958\x92\xcb\xa1\x0c\x83T"\xc1\x86X\x8cX{;\x17\x85\xa0\ +\\,\x92\xcdf\x1b\x96\xbdb\x85\xee\xcbccT\xebu\x82J\x85\x1f\x9d?\xcfd\x18\xf2\ +\xe7?\xfc!\xed]]\xfc\xee\x8d78\xd6\xd7\xc7\x91\xe1a\xbe\xb4y3^\xb1H87\xb7\ +\xa4ls\xb1\xb6"\x04b\xb1\x181\xc7\xe1e\xc3`(\x97\xe3\xadL\x86\x07\xbf\xfaU\ +\xbe|\xf7\xdd<\xf0\xc0\x03b\xf7\xee\xdd\xaaX(\xf0\xf0\xe1\xc3<25\xc5P\x14\ +\xd1\x12\x8baYV\xc3\xb2W$\n\x1dL\x85.\x91\xa7\x07\ +\xe2\xa8\x04W\xdb\xfcx#\x164c\xd1\x17?T\x84R\xd1a\xaa\\\x1c\x88\xef\xe4\x81\ +\xbc%u}c\x93\xd4\x16\xfa\xe2\xa1\x0f\x91\x0f\xc7\'C\x82\x82\xed\x8b\xa3e\xb6\ +\x04y\xf0\x964l5\xb6p\x8a\xa5\x81x\xe8\xc1\x91\xb2\xc7\xb1\'\xcb}\xf1l\t\x8c\ +\xcd\xd5L4[\x02\xa9\xc9\x85G>\x94|\x87\x17OLR\xb0\xea@\x1c\x95\xe0\xeeM@\xfd\ +\xeay3nc\xc7\xa2\\xg\xec\xf4\xd1\x88\xa3\x93\xa5\x03\xf1\x9d\x7f`\x10\xdeN4"\ +5C\xe1\x91\x0f\xc7J\x05\xa6_8q n\xb5\xcc\xa2`P\'\x13\')\xc6\x0b\x86\xc2\x0f\ +\x15\xb3\xcf\xe9\xd3SLDAO\x1c\x19\xe3*c\x07w2\x86\xbex\xe8\xdb\x9ex\xe4\xc3\ +\xa9\xc3E^9s\xaa\'\xbe\xdb\x92\xf5\xc1\x852\x98B\xd0\x13\x1fs\x0c\x0fk\x1b\ +\xcc\xcc-\xd1l\xc5]x\xe8\xc3D\xd1\xe1\xed\xb3\xcf\xe1;\xa6;\x1at\x82\xa7\x8c\ +\xed\xdbFI\xe3v\xe1\xa1\x07B\xb4\xb9\xbb\xfc\x90j\xb5\x8aM\x05\xab\x8b\xf3\ +\x9c=\xf3\x0c\x17^:N\x14z\x84>\x94\xb6\xe7\xbdvj\x82\xe7\x9f}\x9a\xdb3\xb7\ +\xf6\xe1Y?`\x0e\xc6\x13\rA\xc1\xee\xc3}4+\x95\x1a\xb7n\xdf\xa5R\xa9`S\x01*\ +\xa1\xd9\xa8\xf3\xd3\x8d\x9b|y\xf9*\xbf?\xa8\xe1\xbbv\xcffty\xef\xc2\xb9.\ +\x1c\xb5\xa7\x1f\xe8\x85\x17\xac\xa24\x96\xe1A\xc1\xd2n\xb5\x98\xbd\xb7\xc0\ +\xfd\xf9\x05R\x11w\xad\xa9M\x13\x16\xe7\x1f\xf0\xc5\xd7\x97\xf8\xfc\xf2/\xac\ +\xd6Ev\xf3\x01\xbc;}\x92\xa7\x8e\x1c\xde\x87gy\xc0\xd8\x9e8Z\x12z\x96\xc9\ +\xc0\xc15)\xcb\x955\xee\xdc\x9f\xa7\xb1\xf9h`zU\xa2\xc5\xb5kW\xb9\xf8\xd9W|{\ +\xe3>\xad\xc4\xf0\xf21\x9f\x0bo\xbd\xb9\x0fG\'8\xef\x7fS\xb1?\xd6\x8fv\xe1\ +\x05#9>\x19\xa0D\x9b\xda\xfa\x06I\xbb9\xb0\xb0\xf4\n5\'\x15\x9c?7\xcd\xa7\ +\x1f\xbc\x83\xd6\x86\x0f?\xfe\x04\xd9\xda\x04\x9d\xcd\xf1\xb4\xb5={8l\xcaz-&\ +nma\xd2\xc1U\xed\xa08\xb7*\xe1\xe7\xebW\xf8\xe8\xd7\xeb\xbc~\xfe\r|\x17\xa4\ +\xdemV00\x00\xa7\xd3\t\xa0\tK\x10\x8b\xc5hss\x13\x87\x87\x87\xf8\xfc\xfc,\x9b\xef\ +\xe9\xe9\xc1\xfc\xfc<|>\x1f\x03jT`\x7f\x7f\x9f\xf4\x86\xfb\xfd~,//\xb3\xc2;\ +\xf6\xf5$TU\x95nnn\x90J\xa5`0\x18055\x05\xaf\xd7\xcb\xca\xb25\x087\x1a\x8dXY\ +YA(\x14*\xcd\xa5(\x8a6\x92\xc9$\xb9\\.2\x1a\x8d\x04\x80\x00\xd0\xd0\xd0\x10\ +\xa5R)*\xf6\xfb:\x92\xc9$\x8d\x8d\x8d\x11\xe7\\\x8b+\x1e\xb2,\xd3\xe2\xe2"\ +\x9d\x9e\x9e\x96\xe5\xd1\x1e\x8e\x8f\x8f+&\xe9\xea\xea\xa2x<.\x14P\x0b.I\x92\ +\x10\xae(\xca\xbf\x1e\xb8\xbc\xbc\xc4\xd1\xd1QY\xf9^__\xf1\xfc\xfc\\\xb1\xec\ +\xaa\xaa\xd2\xc1\xc1\x81\xb0\xec\x9cs\xd8l6\x8c\x8c\x8c\xc0\xe9tV\\FM\xc0\ +\xc5\xc5\x05>>>\xca\x1c\xf2\xf9<\x1e\x1e\x1e*\xc2\x13\x89\x04\xa2\xd1\xa8\ +\x10>::\n\x8f\xc7\x83\xf1\xf1qa\x0fi\x02\xf2\xf9\xbc\xc8\x07www\x15\xe1\xa2}\ +\xce\x18\x83\xddn\xc7\xdc\xdc\x1c\\.W\xd5\x06\xae\xeb \xcaf\xb3\xda\x96\xdc\ +\xde\xde\xa6\xad\xad-!\x1c\x00\xacV+\xdcnwM8P\xe7A\x94N\xa7\xd9\xf5\xf55\x85\ +\xc3a\n\x06\x838??\xafX\xf6\x02|ii\t3335\xe1u\x0bxyy\xa1P(\x04\xce9\xb2\xd9\ +\xac\xd0\xcfj\xb5\xc2\xef\xf7k\xa7\x9cn\x02\x00\xe0\xf1\xf1Q8\xc79\xc7\xe0\ +\xe0 \x16\x16\x16\x1a\x82\x97\x08hkkk$\xae\x04^\xe8\xf6\xe9\xe9\xe9\x86\xe0%\ +\x02\xfa\xfa\xfa\xbe\r\xaf\xa7\xdb\x859\n\x0f&\x93\t\x8c\xd5\x9fC\x0fx\x89\ +\x00\xb3\xd9\x0cY\x96\xeb\n2\x18\x0c\xba\xc0\x81\xa2%\xe8\xee\xeeFgg\'r\xb9\ +\\\xd5\x00Y\x96\xe1\xf1x`\xb3\xd9099\xf9_p\xa0\xa8\x02\x92$\xa1\xb7\xb7\xb7&\ +\xdc\xeb\xf5\xc2\xe1p\xe8\x02\x07\x8a*011\xc1\xd6\xd7\xd7\xe9\xfd\xfd\x1dWWW\ +\xda\xed\xb5`\x1d\x1d\x1dp\xbb\xdd\xb0\xdb\xed\xc2\x0f\xcbw\xac\xecB\x12\x89\ +D(\x1a\x8d\xe2\xe4\xe4\x04\xb9\\\x0e\x8c1X,\x16\xf8|>\xac\xae\xae\xea\x06\ +\x16\n\x00\x80\xdd\xdd]\xba\xbd\xbdE&\x93A{{;\xfa\xfb\xfb1;;\xab;\\(\xe0\'\ +\xed\xf7\xfd\x9c~\xb5\xbf\x8a\xf3q\xb2q\x86\xa0|\x00\x00\x00\x00IEND\xaeB`\ +\x82' + + +cross_png = \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ +\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x03\ +\x9fIDATx\x9c\xc5\x97OH*_\x14\xc7\xbfW~\x82\x8c\x19Sh\xc2\x80\x8b\xfe\x10\ +\x04A\x90P.\x84(r\x13ER\x14\x11\x18A\x11\x14\xba0\n\x83B\xa1\x90\\\x88\xa5\ +\x05\xe5B\x11%7\x89\x14B\x08\xc2\xac\xda\xb6\x88V\xd12\xb0M\xb4jWx\xde\xe2a<\ +_3\xe3(\xef\xf7\xde\x81\xb3P\xef9\xdf\xcf\x9d+\xdfs\x87\xf1<\x8f\x7f\x19\x9a\ +\x7f\xaa\xfe7\x01\x82\xc1 \xcd\xcf\xcfS<\x1e\xa7_\xbfg\xf5\x8e \x9dNSKK\x0bf\ +ffX3\xc2\xc9d\x92r\xb9\x1c\x8a\xc5"\xde\xde\xde044\x84\xbd\xbd=,--1Y\x80t:M\ +\x8c1\xdc\xde\xde\xe2\xea\xea\n\x13\x13\x13\x98\x9a\x9aj\x18\xe2\xf0\xf0\x90\ +\xe2\xf18\xee\xef\xefA\xf4s\xe3Z\xad\x16\xa3\xa3\xa3\xb0\xdb\xed\xb0\xdb\xed\ +\x00\xcf\xf35y||L\xfd\xfd\xfd\xd4\xd3\xd3C\x1c\xc7\x11\x00\xe28\x8e\xbc^/\ +\x89\xa2H\xbf\xaf\x97\xcaR\xa9D>\x9f\x8f\xccf3\x01\x90L\x8e\xe3(\x18\x0cRM\ +\xe1\xc9\xc9\t\x19\x8dF\xd9\x025\x10\x85B\x81fggI\xa7\xd3\xc9\x8a\x03 \xa3\ +\xd1H\x89D\xa2\x16\xe0\xe2\xe2\x82:::\x14\xa9\x95 \xb2\xd9,\xd9l6\xd2h4\x8a\ +\xe2f\xb3\x99vvv\x88\xe7\xf9\xefG077\xa7Xl0\x18(\x14\n}\x038;;\xa3\x81\x81\ +\x01\xc5Z\x00\xd4\xd5\xd5E\x91H\xe4\xab\xfe\x1b@*\x95\x92=\x86jZ,\x16J&\x93\ +\xc4\xf3\x9f\xe4\x18\x07\xcf\xf3\xb8\xb9\ +\xb9\xa1\xb5\xb55U\xe2\xd5\x1d\x05\x02\x01U\xeb\xab\xa9\xd7\xeb)\x16\x8bI\ +\x03\xb8\xdd\xee\xba\x97\x88\xdf\x1f\xa7(\x8a\xe4\xf1x\xea\x0e\xa3j\xf6\xf6\ +\xf6R.\x97\x93\x06\x88F\xa3\xa4\xd7\xeb\x15\x1b\xf4\xf5\xf5Q4\x1a\xadiP,\x16\ +\xc9\xe9t*\xc23\xc6hdd\xe4\xeb\xfe \tpzzJ\xad\xad\xad\xb2M\x06\x07\x07)\x9b\ +\xcdJ6\x90:>\xc6\x181\xc6\x08\x00uwwK\xee\xbc\x9a\xff\x01\xc0\xf3\xf33\xde\ +\xdf\xdf!\x15\x16\x8b\x05n\xb7\x1b\x1b\x1b\x1b\x92\xf6\xba\xb8\xb8\xc8\xf2\ +\xf9<\xb5\xb5\xb5!\x93\xc9\xe0\xf3\xf3\x13ccc\xd0\xe9tx}}\x85\xc3\xe1\xc0\ +\xea\xea\xaa\xac5\xb3\xeae2\x91H\xa0T*\xa1R\xa9|\xc14:X\xce\xcf\xcf\x89\x88\ +\xb0\xbe\xbe\xaez\x16|]H.//\xe9\xe5\xe5\x05\x8f\x8f\x8f8::\x02\x00loo#\x1a\ +\x8d6\xf5F\xd40@5\xf2\xf9<\xdd\xdd\xdd\x01\x00\xacVk\xd3\xafdM\x03\xfc\xed\ +\xf8\x01\xe9\t\x94\x8c\xa7\xf9\xf9<\x00\x00\x00\x00IEND\xaeB`\x82' + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + diff --git a/demo/BitmapButton.py b/demo/BitmapButton.py new file mode 100644 index 00000000..0bd5ed03 --- /dev/null +++ b/demo/BitmapButton.py @@ -0,0 +1,86 @@ + +import wx +import images + +#import wx.lib.buttons +#wx.BitmapButton = wx.lib.buttons.GenBitmapButton + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1, + style=wx.NO_FULL_REPAINT_ON_RESIZE) + self.log = log + + if 0: # a test case for catching wx.PyAssertionError + + #wx.GetApp().SetAssertMode(wx.PYAPP_ASSERT_SUPPRESS) + #wx.GetApp().SetAssertMode(wx.PYAPP_ASSERT_EXCEPTION) + #wx.GetApp().SetAssertMode(wx.PYAPP_ASSERT_DIALOG) + #wx.GetApp().SetAssertMode(wx.PYAPP_ASSERT_EXCEPTION | wx.PYAPP_ASSERT_DIALOG) + + try: + bmp = wx.Bitmap("nosuchfile.bmp", wx.BITMAP_TYPE_BMP) + mask = wx.Mask(bmp, wx.BLUE) + except wx.PyAssertionError: + self.log.write("Caught wx.PyAssertionError! I will fix the problem.\n") + bmp = images.Test2.GetBitmap() + mask = wx.MaskColour(bmp, wx.BLUE) + else: + bmp = images.Test2.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + + bmp.SetMask(mask) + b = wx.BitmapButton(self, -1, bmp, (20, 20), + (bmp.GetWidth()+10, bmp.GetHeight()+10)) + b.SetToolTipString("This is a bitmap button.") + self.Bind(wx.EVT_BUTTON, self.OnClick, b) + + b = wx.BitmapButton(self, -1, bmp, (20, 120), + style = wx.NO_BORDER) + + # hide a little surprise in the button... + img = images.Robin.GetImage() + # we need to make it be the same size as the primary image, so + # grab a subsection of this new image + cropped = img.GetSubImage((20, 20, bmp.GetWidth(), bmp.GetHeight())) + b.SetBitmapSelected(cropped.ConvertToBitmap()) + + b.SetToolTipString("This is a bitmap button with \nwx.NO_BORDER style.") + self.Bind(wx.EVT_BUTTON, self.OnClick, b) + + + def OnClick(self, event): + self.log.write("Click! (%d)\n" % event.GetId()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """ +

BitmapButton

+ +

A BitmapButton control displays a bitmap. It can have a separate bitmap for each button state: normal, selected, disabled.

+ +

The bitmaps to be displayed should have a small number of colours, such as 16, +to avoid palette problems.

+ +

A bitmap can be derived from most image formats using the wx.Image class.

+ + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/BitmapComboBox.py b/demo/BitmapComboBox.py new file mode 100644 index 00000000..30d9f549 --- /dev/null +++ b/demo/BitmapComboBox.py @@ -0,0 +1,62 @@ + +import wx +import wx.combo + +import images + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + bcb1 = wx.combo.BitmapComboBox(self, pos=(25,25), size=(200,-1)) + bcb2 = wx.combo.BitmapComboBox(self, pos=(250,25), size=(200,-1)) + + for bcb in [bcb1, bcb2]: + for x in range(12): + name = 'LB%02d' % (x+1) + obj = getattr(images, name) + img = obj.GetImage() + img.Rescale(20,20) + bmp = img.ConvertToBitmap() + bcb.Append('images.%s' % name, bmp, name) + self.Bind(wx.EVT_COMBOBOX, self.OnCombo, bcb) + + + def OnCombo(self, evt): + bcb = evt.GetEventObject() + idx = evt.GetInt() + st = bcb.GetString(idx) + cd = bcb.GetClientData(idx) + self.log.write("EVT_COMBOBOX: Id %d, string '%s', clientData '%s'" % (idx, st, cd)) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.combo.BitmapComboBox

+ +A combobox that displays a bitmap in front of the list items. It +currently only allows using bitmaps of one size, and resizes itself so +that a bitmap can be shown next to the text field. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/BitmapFromBuffer.py b/demo/BitmapFromBuffer.py new file mode 100644 index 00000000..69f2c066 --- /dev/null +++ b/demo/BitmapFromBuffer.py @@ -0,0 +1,148 @@ + +import wx +import array + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.width, self.height = 120,120 + + self.MakeBitmapRGB(self.width, self.height) + self.MakeBitmapRGBA(self.width, self.height) + self.MakeBitmapRGBpA(self.width, self.height) + + def GetRGB(self, x, y, bpp): + # calculate some colour values for this sample based on x,y position + r = g = b = 0 + if y < self.height/3: r = 255 + if y >= self.height/3 and y <= 2*self.height/3: g = 255 + if y > 2*self.height/3: b = 255 + + if bpp == 4: + a = int(x * 255.0 / self.width) + return r, g, b, a + else: + return r, g, b + + + def MakeBitmapRGB(self, width, height): + # Make a bitmap using an array of RGB bytes + bpp = 3 # bytes per pixel + bytes = array.array('B', [0] * width*height*bpp) + + for y in xrange(height): + for x in xrange(width): + offset = y*width*bpp + x*bpp + r,g,b = self.GetRGB(x, y, bpp) + bytes[offset + 0] = r + bytes[offset + 1] = g + bytes[offset + 2] = b + + self.rgbBmp = wx.BitmapFromBuffer(width, height, bytes) + + + + def MakeBitmapRGBA(self, width, height): + # Make a bitmap using an array of RGBA bytes + bpp = 4 # bytes per pixel + bytes = array.array('B', [0] * width*height*bpp) + + for y in xrange(height): + for x in xrange(width): + offset = y*width*bpp + x*bpp + r,g,b,a = self.GetRGB(x, y, bpp) + bytes[offset + 0] = r + bytes[offset + 1] = g + bytes[offset + 2] = b + bytes[offset + 3] = a + + self.rgbaBmp = wx.BitmapFromBufferRGBA(width, height, bytes) + + + def MakeBitmapRGBpA(self, width, height): + # Make a bitmap using an array of RGB bytes plus a separate + # buffer for the alpha channel + bpp = 3 # bytes per pixel + bytes = array.array('B', [0] * width*height*bpp) + + for y in xrange(height): + for x in xrange(width): + offset = y*width*bpp + x*bpp + r,g,b = self.GetRGB(x, y, bpp) + bytes[offset + 0] = r + bytes[offset + 1] = g + bytes[offset + 2] = b + + # just use an alpha buffer with a constant alpha value for all + # pixels for this example, it could just as easily have + # varying alpha values like the other sample. + alpha = array.array('B', [128]*width*height) + self.rgbaBmp2 = wx.BitmapFromBuffer(width, height, bytes, alpha) + + + def DrawBitmapAndMessage(self, dc, bmp, msg, x_, y_): + x, y = x_, y_ + + # draw some text to help show the alpha + dc.SetFont(self.GetFont()) + while y < y_ + self.height + 2*dc.GetCharHeight(): + dc.DrawText(msg, x,y) + y += dc.GetCharHeight() + 5 + + # draw the bitmap over the text + dc.DrawBitmap(bmp, x+15,y_+15, True) + + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + self.DrawBitmapAndMessage(dc, self.rgbBmp, "No alpha channel in this image", 30,35) + self.DrawBitmapAndMessage(dc, self.rgbaBmp, "This image has some alpha", 325,35) + self.DrawBitmapAndMessage(dc, self.rgbaBmp2,"This one made with RGB+A", 180,220) + + + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

BitmapFromBuffer

+ +Two new wx.Bitmap factory functions allow you to create a wx.Bitmap +directly from a data buffer. The the buffer can be any Python object +that implements the buffer interface, or is convertable to a buffer, +such as a string or an array. The new functions are: + + + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Button.py b/demo/Button.py new file mode 100644 index 00000000..9493ae2d --- /dev/null +++ b/demo/Button.py @@ -0,0 +1,76 @@ + +import wx +import images + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1, + style=wx.NO_FULL_REPAINT_ON_RESIZE) + self.log = log + + b = wx.Button(self, 10, "Default Button", (20, 20)) + self.Bind(wx.EVT_BUTTON, self.OnClick, b) + b.SetDefault() + b.SetSize(b.GetBestSize()) + + b = wx.Button(self, 20, "HELLO AGAIN!", (20, 80)) + self.Bind(wx.EVT_BUTTON, self.OnClick, b) + b.SetToolTipString("This is a Hello button...") + + b = wx.Button(self, 40, "Flat Button?", (20,160), style=wx.NO_BORDER) + b.SetToolTipString("This button has a style flag of wx.NO_BORDER.\n" + "On some platforms that will give it a flattened look.") + self.Bind(wx.EVT_BUTTON, self.OnClick, b) + + b = wx.Button(self, 50, "wx.Button with icon", (20, 220)) + b.SetToolTipString("wx.Button can how have an icon on the left, right,\n" + "above or below the label.") + self.Bind(wx.EVT_BUTTON, self.OnClick, b) + + b.SetBitmap(images.Mondrian.Bitmap, + wx.LEFT # Left is the default, the image can be on the other sides too + #wx.RIGHT + #wx.TOP + #wx.BOTTOM + ) + b.SetBitmapMargins((2,2)) # default is 4 but that seems too big to me. + + # Setting the bitmap and margins changes the best size, so + # reset the initial size since we're not using a sizer in this + # example which would have taken care of this for us. + b.SetInitialSize() + + #b = wx.Button(self, 60, "Multi-line\nbutton", (20, 280)) + #b = wx.Button(self, 70, pos=(160, 280)) + #b.SetLabel("Another\nmulti-line") + + def OnClick(self, event): + self.log.write("Click! (%d)\n" % event.GetId()) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """ +

Button

+ +A button is a control that contains a text string or a bitmap and can be +placed on nearly any kind of window. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Cairo.py b/demo/Cairo.py new file mode 100644 index 00000000..b46c6b21 --- /dev/null +++ b/demo/Cairo.py @@ -0,0 +1,196 @@ + +import wx +import math + +try: + import wx.lib.wxcairo + import cairo + haveCairo = True +except ImportError: + haveCairo = False + +from Main import opj + +#---------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def OnPaint(self, evt): + if self.IsDoubleBuffered(): + dc = wx.PaintDC(self) + else: + dc = wx.BufferedPaintDC(self) + dc.SetBackground(wx.Brush('white')) + dc.Clear() + + self.Render(dc) + + + def Render(self, dc): + # Draw some stuff on the plain dc + sz = self.GetSize() + dc.SetPen(wx.Pen("navy", 1)) + x = y = 0 + while x < sz.width * 2 or y < sz.height * 2: + x += 20 + y += 20 + dc.DrawLine(x, 0, 0, y) + + # now draw something with cairo + ctx = wx.lib.wxcairo.ContextFromDC(dc) + ctx.set_line_width(15) + ctx.move_to(125, 25) + ctx.line_to(225, 225) + ctx.rel_line_to(-200, 0) + ctx.close_path() + ctx.set_source_rgba(0, 0, 0.5, 1) + ctx.stroke() + + # and something else... + ctx.arc(200, 200, 80, 0, math.pi*2) + ctx.set_source_rgba(0, 1, 1, 0.5) + ctx.fill_preserve() + ctx.set_source_rgb(1, 0.5, 0) + ctx.stroke() + + # here's a gradient pattern + ptn = cairo.RadialGradient(315, 70, 25, + 302, 70, 128) + ptn.add_color_stop_rgba(0, 1,1,1,1) + ptn.add_color_stop_rgba(1, 0,0,0,1) + ctx.set_source(ptn) + ctx.arc(328, 96, 75, 0, math.pi*2) + ctx.fill() + + # Draw some text + face = wx.lib.wxcairo.FontFaceFromFont( + wx.FFont(10, wx.SWISS, wx.FONTFLAG_BOLD)) + ctx.set_font_face(face) + ctx.set_font_size(60) + ctx.move_to(360, 180) + ctx.set_source_rgb(0, 0, 0) + ctx.show_text("Hello") + + # Text as a path, with fill and stroke + ctx.move_to(400, 220) + ctx.text_path("World") + ctx.set_source_rgb(0.39, 0.07, 0.78) + ctx.fill_preserve() + ctx.set_source_rgb(0,0,0) + ctx.set_line_width(2) + ctx.stroke() + + # Show iterating and modifying a (text) path + ctx.new_path() + ctx.move_to(0, 0) + ctx.set_source_rgb(0.3, 0.3, 0.3) + ctx.set_font_size(30) + text = "This path was warped..." + ctx.text_path(text) + tw, th = ctx.text_extents(text)[2:4] + self.warpPath(ctx, tw, th, 360,300) + ctx.fill() + + # Drawing a bitmap. Note that we can easily load a PNG file + # into a surface, but I wanted to show how to convert from a + # wx.Bitmap here instead. This is how to do it using just cairo: + #img = cairo.ImageSurface.create_from_png(opj('bitmaps/toucan.png')) + + # And this is how to convert a wx.Btmap to a cairo image + # surface. NOTE: currently on Mac there appears to be a + # problem using conversions of some types of images. They + # show up totally transparent when used. The conversion itself + # appears to be working okay, because converting back to + # wx.Bitmap or writing the image surface to a file produces + # the expected result. The other platforms are okay. + bmp = wx.Bitmap(opj('bitmaps/toucan.png')) + #bmp = wx.Bitmap(opj('bitmaps/splash.png')) + img = wx.lib.wxcairo.ImageSurfaceFromBitmap(bmp) + + ctx.set_source_surface(img, 70, 230) + ctx.paint() + + # this is how to convert an image surface to a wx.Bitmap + bmp2 = wx.lib.wxcairo.BitmapFromImageSurface(img) + dc.DrawBitmap(bmp2, 280, 300) + + + def warpPath(self, ctx, tw, th, dx, dy): + def f(x, y): + xn = x - tw/2 + yn = y+ xn ** 3 / ((tw/2)**3) * 70 + return xn+dx, yn+dy + + path = ctx.copy_path() + ctx.new_path() + for type, points in path: + if type == cairo.PATH_MOVE_TO: + x, y = f(*points) + ctx.move_to(x, y) + + elif type == cairo.PATH_LINE_TO: + x, y = f(*points) + ctx.line_to(x, y) + + elif type == cairo.PATH_CURVE_TO: + x1, y1, x2, y2, x3, y3 = points + x1, y1 = f(x1, y1) + x2, y2 = f(x2, y2) + x3, y3 = f(x3, y3) + ctx.curve_to(x1, y1, x2, y2, x3, y3) + + elif type == cairo.PATH_CLOSE_PATH: + ctx.close_path() + +#---------------------------------------------------------------------- + +if not haveCairo: + from wx.lib.msgpanel import MessagePanel + def runTest(frame, nb, log): + win = MessagePanel(nb, 'This demo requires the Pycairo package,\n' + 'or there is some other unmet dependency.', + 'Sorry', wx.ICON_WARNING) + return win +else: + + def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + +if haveCairo: + extra = "\n

wx.lib.wxcairo

\n%s" % ( + wx.lib.wxcairo.__doc__.replace('\n\n', '\n

')) +else: + extra = '\n

See the docstring in the wx.lib.wxcairo module for details about installing dependencies.' + + + +overview = """ +

Cairo Integration

+ +This sample shows how to draw on a DC using the cairo 2D graphics +library and the pycairo Python extension module that wraps the cairo +API. For more information about cairo please see +http://cairographics.org/. + +%s + + +""" % extra + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Cairo_Snippets.py b/demo/Cairo_Snippets.py new file mode 100644 index 00000000..d7764887 --- /dev/null +++ b/demo/Cairo_Snippets.py @@ -0,0 +1,132 @@ + +import wx + +try: + import wx.lib.wxcairo + import cairo + haveCairo = True +except ImportError: + haveCairo = False + +from math import pi as M_PI # used by many snippets +from snippets import snip_list, snippet_normalize +from Main import opj, DemoCodeEditor + +#---------------------------------------------------------------------- + +# TODO: Add the ability for the user to edit and render their own snippet + +class DisplayPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, style=wx.BORDER_SIMPLE) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.curr_snippet = '' + + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + + if self.curr_snippet: + width, height = self.GetClientSize() + cr = wx.lib.wxcairo.ContextFromDC(dc) + exec(self.curr_snippet, globals(), locals()) + + + def SetSnippet(self, text): + self.curr_snippet = text + self.Refresh() + + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + self.lb = wx.ListBox(self, choices=snip_list) + self.canvas = DisplayPanel(self) + self.editor = DemoCodeEditor(self, style=wx.BORDER_SIMPLE) + self.editor.SetEditable(False) + + self.Bind(wx.EVT_LISTBOX, self.OnListBoxSelect, self.lb) + + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(self.lb, 0, wx.EXPAND) + sizer.Add((15,1)) + vbox = wx.BoxSizer(wx.VERTICAL) + vbox.Add(self.canvas, 1, wx.EXPAND) + vbox.Add((1, 15)) + vbox.Add(self.editor, 1, wx.EXPAND) + sizer.Add(vbox, 1, wx.EXPAND) + border = wx.BoxSizer() + border.Add(sizer, 1, wx.EXPAND|wx.ALL, 30) + self.SetSizer(border) + + + def OnListBoxSelect(self, evt): + snippet_file = opj('snippets/%s.py' % evt.GetString()) + text = file(snippet_file).read() + self.canvas.SetSnippet(text) + self.editor.SetValue(text) + + +#---------------------------------------------------------------------- + +if not haveCairo: + from wx.lib.msgpanel import MessagePanel + def runTest(frame, nb, log): + win = MessagePanel(nb, 'This demo requires the Pycairo package,\n' + 'or there is some other unmet dependency.', + 'Sorry', wx.ICON_WARNING) + return win +else: + + def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + +if haveCairo: + extra = "\n

wx.lib.wxcairo

\n%s" % ( + wx.lib.wxcairo.__doc__.replace('\n\n', '\n

')) +else: + extra = '\n

See the docstring in the wx.lib.wxcairo module for details about installing dependencies.' + + +overview = """ +

Cairo Integration

+ +The wx.lib.wxcairo module provides a bit of glue that will allow you to +use the Pycairo package drawing directly on wx.DC's. + +

This sample draws the standard 'snippet' examples that come with +the Pycairo pacakge, and a few others. The C version of the samples +can be seen at http://cairographics.org/samples/ + +

In most snippets you'll see a call to a snippet_normalize() +function. This is part of the demo and not part of Cairo. It is +simply scaling the context such that the range of 0.0 to 1.0 is the +min(width, height) of the window in pixels. In other words, it allows +the rendering code to use a range or 0.0 to 1.0 and it will always fit +in the drawing area. (Try resizing the demo and reselecting a snippet +to see this.) + +

+def snippet_normalize(ctx, width, height):
+    size = min(width, height)
+    ctx.scale(size, size)
+    ctx.set_line_width(0.04)
+
+ +%s + +""" % extra + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Calendar.py b/demo/Calendar.py new file mode 100644 index 00000000..562844f4 --- /dev/null +++ b/demo/Calendar.py @@ -0,0 +1,660 @@ +#---------------------------------------------------------------------------- +# Name: Calendar.py +# Purpose: Calendar control display testing on panel for wxPython demo +# +# Author: Lorne White (email: lwhite1@planet.eon.net) +# +# Version 0.9 +# Date: Feb 26, 2001 +# Licence: wxWindows license +#---------------------------------------------------------------------------- +# 11/15/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Updated for wx namespace +# +# 11/26/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Ugh. AFter updating to the Bind() method, things lock up +# on various control clicks. Will have to debug. Only seems +# to happen on windows with calendar controls, though. +# +# 11/30/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Lockup issue clarification: it appears that the spinner is +# the culprit. +# + +import os + +import wx +import wx.lib.calendar + +import images + + +# highlighted days in month + +test_days ={ 0: [], + 1: [3, 7, 9, 21], + 2: [2, 10, 4, 9], + 3: [4, 20, 29], + 4: [1, 12, 22], + 5: [2, 10, 15], + 6: [4, 8, 17], + 7: [6, 7, 8], + 8: [5, 10, 20], + 9: [1, 2, 5, 29], + 10: [2, 4, 6, 22], + 11: [6, 9, 12, 28, 29], + 12: [8, 9, 10, 11, 20] } + +# test of full window calendar control functions + +def GetMonthList(): + + monthlist = [] + + for i in range(13): + name = wx.lib.calendar.Month[i] + + if name != None: + monthlist.append(name) + + return monthlist + +class TestPanel(wx.Panel): + def __init__(self, parent, log, frame): + wx.Panel.__init__(self, parent, -1) + + self.log = log + self.frame = frame + + self.calend = wx.lib.calendar.Calendar(self, -1, (100, 50), (200, 180)) + +# start_month = 2 # preselect the date for calendar +# start_year = 2001 + + start_month = self.calend.GetMonth() # get the current month & year + start_year = self.calend.GetYear() + + # month list from DateTime module + + monthlist = GetMonthList() + + self.date = wx.ComboBox(self, -1, "", + (100, 20), (90, -1), + monthlist, wx.CB_DROPDOWN) + + self.date.SetSelection(start_month-1) + self.Bind(wx.EVT_COMBOBOX, self.EvtComboBox, self.date) + + # set start month and year + + self.calend.SetMonth(start_month) + self.calend.SetYear(start_year) + + # set attributes of calendar + + self.calend.hide_title = True + self.calend.HideGrid() + self.calend.SetWeekColor('WHITE', 'BLACK') + + # display routine + + self.ResetDisplay() + + # mouse click event + self.Bind(wx.lib.calendar.EVT_CALENDAR, self.MouseClick, self.calend) + + # scroll bar for month selection + self.scroll = wx.ScrollBar(self, -1, (100, 240), (200, 20), wx.SB_HORIZONTAL) + self.scroll.SetScrollbar(start_month-1, 1, 12, 1, True) + self.Bind(wx.EVT_COMMAND_SCROLL, self.Scroll, self.scroll) + + # spin control for year selection + + self.dtext = wx.TextCtrl(self, -1, str(start_year), (200, 20), (60, -1)) + h = self.dtext.GetSize().height + + self.spin = wx.SpinButton(self, -1, (270, 20), (h*2, h)) + self.spin.SetRange(1980, 2010) + self.spin.SetValue(start_year) + self.Bind(wx.EVT_SPIN, self.OnSpin, self.spin) + + # button for calendar dialog test + self.but1 = wx.Button(self, -1, "Test Calendar Dialog", (380, 80)) + self.Bind(wx.EVT_BUTTON, self.TestDlg, self.but1) + + # button for calendar window test + self.but2 = wx.Button(self, -1, "Test Calendar Window", (380, 180)) + self.Bind(wx.EVT_BUTTON, self.TestFrame, self.but2) + + self.but3 = wx.Button(self, -1, "Test Calendar Print", (380, 280)) + self.Bind(wx.EVT_BUTTON, self.OnPreview, self.but3) + + # calendar dialog + + def TestDlg(self, event): # test the date dialog + dlg = wx.lib.calendar.CalenDlg(self) + dlg.Centre() + + if dlg.ShowModal() == wx.ID_OK: + result = dlg.result + day = result[1] + month = result[2] + year = result[3] + new_date = str(month) + '/'+ str(day) + '/'+ str(year) + self.log.WriteText('Date Selected: %s\n' % new_date) + else: + self.log.WriteText('No Date Selected') + + # calendar window test + + def TestFrame(self, event): + frame = CalendFrame(self, -1, "Test Calendar", self.log) + frame.Show(True) + return True + + # calendar print preview + + def OnPreview(self, event): + month = self.calend.GetMonth() + year = self.calend.GetYear() + + prt = PrintCalend(self.frame, month, year) + prt.Preview() + + # month and year control events + + def OnSpin(self, event): + year = event.GetPosition() + self.dtext.SetValue(str(year)) + self.calend.SetYear(year) + self.calend.Refresh() + + def EvtComboBox(self, event): + name = event.GetString() + self.log.WriteText('EvtComboBox: %s\n' % name) + monthval = self.date.FindString(name) + self.scroll.SetScrollbar(monthval, 1, 12, 1, True) + + self.calend.SetMonth(monthval+1) + self.ResetDisplay() + + def Scroll(self, event): + value = self.scroll.GetThumbPosition() + monthval = int(value)+1 + self.calend.SetMonth(monthval) + self.ResetDisplay() + self.log.WriteText('Month: %s\n' % value) + + name = wx.lib.calendar.Month[monthval] + self.date.SetValue(name) + + # log mouse events + + def MouseClick(self, evt): + text = '%s CLICK %02d/%02d/%d' % (evt.click, evt.day, evt.month, evt.year) # format date + self.log.WriteText('Date Selected: ' + text + '\n') + + + # set the highlighted days for the calendar + + def ResetDisplay(self): + month = self.calend.GetMonth() + + try: + set_days = test_days[month] + except: + set_days = [1, 5, 12] + + self.calend.AddSelect([4, 11], 'BLUE', 'WHITE') + self.calend.SetSelDay(set_days) + self.calend.Refresh() + + # increment and decrement toolbar controls + + def OnIncYear(self, event): + self.calend.IncYear() + self.ResetDisplay() + + def OnDecYear(self, event): + self.calend.DecYear() + self.ResetDisplay() + + def OnIncMonth(self, event): + self.calend.IncMonth() + self.ResetDisplay() + + def OnDecMonth(self, event): + self.calend.DecMonth() + self.ResetDisplay() + + def OnCurrent(self, event): + self.calend.SetCurrentDay() + self.ResetDisplay() + +# test of full window calendar control functions + +class CalendFrame(wx.Frame): + def __init__(self, parent, id, title, log): + wx.Frame.__init__(self, parent, id, title, size=(400, 400), + style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE) + + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + self.log = log + self.CreateStatusBar() + self.mainmenu = wx.MenuBar() + menu = wx.Menu() + + menu = self.MakeFileMenu() + self.mainmenu.Append(menu, '&File') + + self.MakeToolMenu() # toolbar + + self.SetMenuBar(self.mainmenu) + self.calend = wx.lib.calendar.Calendar(self, -1) + self.calend.SetCurrentDay() + self.calend.grid_color = 'BLUE' + self.calend.SetBusType() +# self.calend.ShowWeekEnd() + + self.ResetDisplay() + + self.Bind(wx.lib.calendar.EVT_CALENDAR, self.MouseClick, self.calend) + + def MouseClick(self, evt): + text = '%s CLICK %02d/%02d/%d' % (evt.click, evt.day, evt.month, evt.year) # format date + self.log.WriteText('Date Selected: ' + text + '\n') + + def OnCloseWindow(self, event): + self.Destroy() + + def ResetDisplay(self): + month = self.calend.GetMonth() + + try: + set_days = test_days[month] + except: + set_days = [1, 5, 12] + + self.calend.AddSelect([2, 16], 'GREEN', 'WHITE') + + self.calend.SetSelDay(set_days) + self.calend.Refresh() + + def OnIncYear(self, event): + self.calend.IncYear() + self.ResetDisplay() + + def OnDecYear(self, event): + self.calend.DecYear() + self.ResetDisplay() + + def OnIncMonth(self, event): + self.calend.IncMonth() + self.ResetDisplay() + + def OnDecMonth(self, event): + self.calend.DecMonth() + self.ResetDisplay() + + def OnCurrent(self, event): + self.calend.SetCurrentDay() + self.ResetDisplay() + + def MakeFileMenu(self): + menu = wx.Menu() + + mID = wx.NewId() + menu.Append(mID, 'Decrement', 'Next') + self.Bind(wx.EVT_MENU, self.OnDecMonth, id=mID) + + mID = wx.NewId() + menu.Append(mID, 'Increment', 'Dec') + self.Bind(wx.EVT_MENU, self.OnIncMonth, id=mID) + + menu.AppendSeparator() + + mID = wx.NewId() + menu.Append(mID, 'E&xit', 'Exit') + self.Bind(wx.EVT_MENU, self.OnCloseWindow, id=mID) + + return menu + + def MakeToolMenu(self): + tb = self.CreateToolBar(wx.TB_HORIZONTAL|wx.NO_BORDER) + + mID = wx.NewId() + SetToolPath(self, tb, mID, images.DbDec.GetBitmap(), 'Dec Year') + self.Bind(wx.EVT_TOOL, self.OnDecYear, id=mID) + + mID = wx.NewId() + SetToolPath(self, tb, mID, images.Dec.GetBitmap(), 'Dec Month') + self.Bind(wx.EVT_TOOL, self.OnDecMonth, id=mID) + + mID = wx.NewId() + SetToolPath(self, tb, mID, images.Pt.GetBitmap(), 'Current Month') + self.Bind(wx.EVT_TOOL, self.OnCurrent, id=mID) + + mID = wx.NewId() + SetToolPath(self, tb, mID, images.Inc.GetBitmap(), 'Inc Month') + self.Bind(wx.EVT_TOOL, self.OnIncMonth, id=mID) + + mID = wx.NewId() + SetToolPath(self, tb, mID, images.DbInc.GetBitmap(), 'Inc Year') + self.Bind(wx.EVT_TOOL, self.OnIncYear, id=mID) + + tb.Realize() + +#--------------------------------------------------------------------------- + +# example class for printing/previewing calendars + +class PrintCalend: + def __init__(self, parent, month, year): + self.frame = parent + self.month = month + self.year = year + + self.SetParms() + self.SetCal() + self.printData = wx.PrintData() + + def SetCal(self): + self.grid_color = 'BLUE' + self.back_color = 'WHITE' + self.sel_color = 'RED' + self.high_color = 'LIGHT BLUE' + self.font = wx.SWISS + self.bold = wx.NORMAL + + self.sel_key = None # last used by + self.sel_lst = [] # highlighted selected days + + self.size = None + self.hide_title = False + self.hide_grid = False + self.set_day = None + + def SetParms(self): + self.ymax = 1 + self.xmax = 1 + self.page = 1 + self.total_pg = 1 + + self.preview = None + self.scale = 1.0 + + self.pagew = 8.5 + self.pageh = 11.0 + + self.txt_marg = 0.1 + self.lf_marg = 0 + self.top_marg = 0 + + self.page = 0 + + def SetDates(self, month, year): + self.month = month + self.year = year + + def SetStyleDef(self, desc): + self.style = desc + + def SetCopies(self, copies): # number of copies of label + self.copies = copies + + def SetStart(self, start): # start position of label + self.start = start + + def Preview(self): + printout = SetPrintout(self) + printout2 = SetPrintout(self) + self.preview = wx.PrintPreview(printout, printout2, self.printData) + + if not self.preview.Ok(): + wx.MessageBox("There was a problem printing!", "Printing", wx.OK) + return + + self.preview.SetZoom(60) # initial zoom value + + frame = wx.PreviewFrame(self.preview, self.frame, "Print preview") + + frame.Initialize() + frame.SetPosition(self.frame.GetPosition()) + frame.SetSize(self.frame.GetSize()) + frame.Show(True) + + def Print(self): + pdd = wx.PrintDialogData() + pdd.SetPrintData(self.printData) + printer = wx.Printer(pdd) + printout = SetPrintout(self) + frame = wx.Frame(None, -1, "Test") + + if not printer.Print(frame, printout): + wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK) + else: + self.printData = printer.GetPrintDialogData().GetPrintData() + + printout.Destroy() + + def DoDrawing(self, DC): + size = DC.GetSize() + DC.BeginDrawing() + + cal = wx.lib.calendar.PrtCalDraw(self) + + if self.preview is None: + cal.SetPSize(size[0]/self.pagew, size[1]/self.pageh) + cal.SetPreview(False) + + else: + if self.preview == 1: + cal.SetPSize(size[0]/self.pagew, size[1]/self.pageh) + else: + cal.SetPSize(self.pwidth, self.pheight) + + cal.SetPreview(self.preview) + + cal.hide_title = self.hide_title # set the calendar parameters + cal.hide_grid = self.hide_grid + + cal.grid_color = self.grid_color + cal.high_color = self.high_color + cal.back_color = self.back_color + cal.outer_border = False + cal.font = self.font + cal.bold = self.bold + + cal_size = (3.0, 3.0) + cal.SetSize(cal_size) + + year, month = self.year, self.month + + x = 0.5 + for i in range(2): + y = 0.5 + + for j in range(3): + cal.SetCal(year, month) # current month + cal.SetPos(x, y) + + try: + set_days = test_days[month] + except: + set_days = [1, 5, 12] + + cal.AddSelect([2, 16], 'GREEN', 'WHITE') + + cal.DrawCal(DC, set_days) + + year, month = self.IncMonth(year, month) + y = y + 3.5 + + x = x + 4.0 # next column + + DC.EndDrawing() + + self.ymax = DC.MaxY() + self.xmax = DC.MaxX() + + def IncMonth(self, year, month): # next month + month = month + 1 + + if month > 12: + month = 1 + year = year + 1 + + return year, month + + def GetTotalPages(self): + self.pg_cnt = 1 + return self.pg_cnt + + def SetPage(self, page): + self.page = page + + def SetPageSize(self, width, height): + self.pwidth, self.pheight = width, height + + def SetTotalSize(self, width, height): + self.ptwidth, self.ptheight = width, height + + def SetPreview(self, preview, scale): + self.preview = preview + self.scale = scale + + def SetTotalSize(self, width, height): + self.ptwidth = width + self.ptheight = height + +def SetToolPath(self, tb, id, bmp, title): + tb.AddSimpleTool(id, bmp, title, title) + +class SetPrintout(wx.Printout): + def __init__(self, canvas): + wx.Printout.__init__(self) + self.canvas = canvas + self.end_pg = 1 + + def OnBeginDocument(self, start, end): + return super(SetPrintout, self).OnBeginDocument(start, end) + + def OnEndDocument(self): + super(SetPrintout, self).OnEndDocument() + + def HasPage(self, page): + if page <= self.end_pg: + return True + else: + return False + + def GetPageInfo(self): + self.end_pg = self.canvas.GetTotalPages() + str_pg = 1 + + try: + end_pg = self.end_pg + except: + end_pg = 1 + + return (str_pg, end_pg, str_pg, end_pg) + + def OnPreparePrinting(self): + super(SetPrintout, self).OnPreparePrinting() + + def OnBeginPrinting(self): + dc = self.GetDC() + + self.preview = self.IsPreview() + + if (self.preview): + self.pixelsPerInch = self.GetPPIScreen() + else: + self.pixelsPerInch = self.GetPPIPrinter() + + (w, h) = dc.GetSize() + scaleX = float(w) / 1000 + scaleY = float(h) / 1000 + self.printUserScale = min(scaleX, scaleY) + + super(SetPrintout, self).OnBeginPrinting() + + def GetSize(self): + self.psizew, self.psizeh = self.GetPPIPrinter() + return self.psizew, self.psizeh + + def GetTotalSize(self): + self.ptsizew, self.ptsizeh = self.GetPageSizePixels() + return self.ptsizew, self.ptsizeh + + def OnPrintPage(self, page): + dc = self.GetDC() + (w, h) = dc.GetSize() + scaleX = float(w) / 1000 + scaleY = float(h) / 1000 + self.printUserScale = min(scaleX, scaleY) + dc.SetUserScale(self.printUserScale, self.printUserScale) + + self.preview = self.IsPreview() + + self.canvas.SetPreview(self.preview, self.printUserScale) + self.canvas.SetPage(page) + + self.ptsizew, self.ptsizeh = self.GetPageSizePixels() + self.canvas.SetTotalSize(self.ptsizew, self.ptsizeh) + + self.psizew, self.psizeh = self.GetPPIPrinter() + self.canvas.SetPageSize(self.psizew, self.psizeh) + + self.canvas.DoDrawing(dc) + return True + +class MyApp(wx.App): + def OnInit(self): + frame = CalendFrame(None, -1, "Test Calendar", log) + frame.Show(True) + self.SetTopWindow(frame) + return True + +#--------------------------------------------------------------------------- + +def MessageDlg(self, message, type = 'Message'): + dlg = wx.MessageDialog(self, message, type, wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log, frame) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ +This control provides a Calendar control class for displaying and selecting dates. +In addition, the class is extended and can be used for printing/previewing. + +Additional features include weekend highlighting and business type Monday-Sunday +format. + +See example for various methods used to set display month, year, and highlighted +dates (different font and background colours). + +by Lorne White + +""" + + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/CalendarCtrl.py b/demo/CalendarCtrl.py new file mode 100644 index 00000000..f7902fec --- /dev/null +++ b/demo/CalendarCtrl.py @@ -0,0 +1,118 @@ + +import wx +import wx.calendar as wxcal + +#---------------------------------------------------------------------- + +description = """\ +This sample shows the wx.calendar.CalendarCtrl in a variety of styles +and modes. If this platform supports a native calendar widget then +that is what is shown to the left. However it may not support all of +the features and attributes of the older wx calendar, so we now have +the ability to explicitly use the generic widget via the +GenericCalendarCtrl class, and that is what is used for the two +calendars below. +""".replace('\n', ' ') + + +class TestPanel(wx.Panel): + def __init__(self, parent, ID, log): + wx.Panel.__init__(self, parent, ID) + self.log = log + + native = wxcal.CalendarCtrl(self, -1, wx.DateTime.Today(), + style=wxcal.CAL_SEQUENTIAL_MONTH_SELECTION) + + txt = wx.StaticText(self, -1, description) + txt.Wrap(300) + + cal = self.cal = wxcal.GenericCalendarCtrl(self, -1, wx.DateTime.Today(), + style = wxcal.CAL_SHOW_HOLIDAYS + | wxcal.CAL_SUNDAY_FIRST + | wxcal.CAL_SEQUENTIAL_MONTH_SELECTION + ) + + cal2 = wxcal.GenericCalendarCtrl(self, -1, wx.DateTime.Today()) + + + # Track a few holidays + self.holidays = [(1,1), (10,31), (12,25) ] # (these don't move around) + self.OnChangeMonth() + + + # bind some event handlers to each calendar + for c in native, cal, cal2: + c.Bind(wxcal.EVT_CALENDAR, self.OnCalSelected) + c.Bind(wxcal.EVT_CALENDAR_MONTH, self.OnChangeMonth) + c.Bind(wxcal.EVT_CALENDAR_SEL_CHANGED, self.OnCalSelChanged) + c.Bind(wxcal.EVT_CALENDAR_WEEKDAY_CLICKED, self.OnCalWeekdayClicked) + + # create some sizers for layout + fgs = wx.FlexGridSizer(cols=2, hgap=50, vgap=50) + fgs.Add(native) + fgs.Add(txt) + fgs.Add(cal) + fgs.Add(cal2) + box = wx.BoxSizer() + box.Add(fgs, 1, wx.EXPAND|wx.ALL, 25) + self.SetSizer(box) + + + def OnCalSelected(self, evt): + self.log.write('OnCalSelected: %s\n' % evt.GetDate()) + + def OnCalWeekdayClicked(self, evt): + self.log.write('OnCalWeekdayClicked: %s\n' % evt.GetWeekDay()) + + def OnCalSelChanged(self, evt): + cal = evt.GetEventObject() + self.log.write("OnCalSelChanged:\n\t%s: %s\n\t%s: %s" % + ("EventObject", cal.__class__, + "Date ", cal.GetDate(), + )) + + def OnChangeMonth(self, evt=None): + if evt is None: + cal = self.cal + else: + cal = evt.GetEventObject() + self.log.write('OnChangeMonth: %s\n' % cal.GetDate()) + cur_month = cal.GetDate().GetMonth() + 1 # convert wxDateTime 0-11 => 1-12 + for month, day in self.holidays: + if month == cur_month: + cal.SetHoliday(day) + + # August 14th is a special day, mark it with a blue square... + if cur_month == 8: + attr = wxcal.CalendarDateAttr(border=wxcal.CAL_BORDER_SQUARE, + colBorder="blue") + cal.SetAttr(14, attr) + else: + cal.ResetAttr(14) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, -1, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ + +

CalendarCtrl

+ +Yet another calendar control. This one is a wrapper around the C++ +version described in the docs. This one will probably be a bit more efficient +than the one in wxPython.lib.calendar, but I like a few things about it better, +so I think both will stay in wxPython. +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/CheckBox.py b/demo/CheckBox.py new file mode 100644 index 00000000..c54edafe --- /dev/null +++ b/demo/CheckBox.py @@ -0,0 +1,73 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestCheckBox(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + st = wx.StaticText(self, -1, "This example demonstrates the wx.CheckBox control.")#, (10, 10)) + + cb1 = wx.CheckBox(self, -1, "Apples")#, (65, 40), (150, 20), wx.NO_BORDER) + cb2 = wx.CheckBox(self, -1, "Oranges")#, (65, 60), (150, 20), wx.NO_BORDER) + cb2.SetValue(True) + cb3 = wx.CheckBox(self, -1, "Pears")#, (65, 80), (150, 20), wx.NO_BORDER) + + cb4 = wx.CheckBox(self, -1, "3-state checkbox", + style=wx.CHK_3STATE|wx.CHK_ALLOW_3RD_STATE_FOR_USER) + cb5 = wx.CheckBox(self, -1, "Align Right", style=wx.ALIGN_RIGHT) + + + self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, cb1) + self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, cb2) + self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, cb3) + self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, cb4) + self.Bind(wx.EVT_CHECKBOX, self.EvtCheckBox, cb5) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.AddMany( [ cb1, + cb2, + cb3, + (20,20), + cb4, + (20,20), + cb5 + ]) + + border = wx.BoxSizer(wx.VERTICAL) + border.Add(st, 0, wx.ALL, 15) + border.Add(sizer, 0, wx.LEFT, 50) + self.SetSizer(border) + + + def EvtCheckBox(self, event): + self.log.write('EvtCheckBox: %d\n' % event.IsChecked()) + cb = event.GetEventObject() + if cb.Is3State(): + self.log.write("\t3StateValue: %s\n" % cb.Get3StateValue()) + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestCheckBox(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ +A checkbox is a labelled box which is either on (checkmark is visible) or off +(no checkmark). + +""" + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/CheckListBox.py b/demo/CheckListBox.py new file mode 100644 index 00000000..ffd4b180 --- /dev/null +++ b/demo/CheckListBox.py @@ -0,0 +1,74 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', + 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', + 'twelve', 'thirteen', 'fourteen'] + + wx.StaticText(self, -1, "This example uses the wxCheckListBox control.", (45, 15)) + + lb = wx.CheckListBox(self, -1, (80, 50), wx.DefaultSize, sampleList) + self.Bind(wx.EVT_LISTBOX, self.EvtListBox, lb) + self.Bind(wx.EVT_CHECKLISTBOX, self.EvtCheckListBox, lb) + lb.SetSelection(0) + self.lb = lb + + lb.Bind(wx.EVT_RIGHT_DOWN, self.OnDoHitTest) + + pos = lb.GetPosition().x + lb.GetSize().width + 25 + btn = wx.Button(self, -1, "Test SetString", (pos, 50)) + self.Bind(wx.EVT_BUTTON, self.OnTestButton, btn) + + def EvtListBox(self, event): + self.log.WriteText('EvtListBox: %s\n' % event.GetString()) + + def EvtCheckListBox(self, event): + index = event.GetSelection() + label = self.lb.GetString(index) + status = 'un' + if self.lb.IsChecked(index): + status = '' + self.log.WriteText('Box %s is %schecked \n' % (label, status)) + self.lb.SetSelection(index) # so that (un)checking also selects (moves the highlight) + + + def OnTestButton(self, evt): + self.lb.SetString(4, "FUBAR") + + def OnDoHitTest(self, evt): + item = self.lb.HitTest(evt.GetPosition()) + self.log.write("HitTest: %d\n" % item) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ +A checklistbox is like a Listbox, but allows items to be checked or unchecked rather +than relying on extended selection (e.g. shift-select) to select multiple items in +the list. + +This class is currently implemented under Windows and GTK. + +This demo shows the basic CheckListBox and how to use the SetString method to change +labels dynamically. +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/CheckListCtrlMixin.py b/demo/CheckListCtrlMixin.py new file mode 100644 index 00000000..0742b146 --- /dev/null +++ b/demo/CheckListCtrlMixin.py @@ -0,0 +1,96 @@ +import sys +import wx +from wx.lib.mixins.listctrl import CheckListCtrlMixin + +from ListCtrl import musicdata + +#---------------------------------------------------------------------- + +class CheckListCtrl(wx.ListCtrl, CheckListCtrlMixin): + def __init__(self, parent, log): + wx.ListCtrl.__init__(self, parent, -1, style=wx.LC_REPORT) + CheckListCtrlMixin.__init__(self) + self.log = log + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated) + + + def OnItemActivated(self, evt): + self.ToggleItem(evt.m_itemIndex) + + + # this is called by the base class when an item is checked/unchecked + def OnCheckItem(self, index, flag): + data = self.GetItemData(index) + title = musicdata[data][1] + if flag: + what = "checked" + else: + what = "unchecked" + self.log.write('item "%s", at index %d was %s\n' % (title, index, what)) + + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + self.list = CheckListCtrl(self, log) + sizer = wx.BoxSizer() + sizer.Add(self.list, 1, wx.EXPAND) + self.SetSizer(sizer) + + self.list.InsertColumn(0, "Artist") + self.list.InsertColumn(1, "Title", wx.LIST_FORMAT_RIGHT) + self.list.InsertColumn(2, "Genre") + + for key, data in musicdata.iteritems(): + index = self.list.InsertStringItem(sys.maxint, data[0]) + self.list.SetStringItem(index, 1, data[1]) + self.list.SetStringItem(index, 2, data[2]) + self.list.SetItemData(index, key) + + self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(2, 100) + + self.list.CheckItem(4) + self.list.CheckItem(7) + + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list) + self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self.list) + + + def OnItemSelected(self, evt): + self.log.write('item selected: %s\n' % evt.m_itemIndex) + + def OnItemDeselected(self, evt): + self.log.write('item deselected: %s\n' % evt.m_itemIndex) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

+ +CheckListCtrlMixin is a simple mixin class that can add a checkbox to +the first column of a wx.ListCtrl. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Choice.py b/demo/Choice.py new file mode 100644 index 00000000..ef9db235 --- /dev/null +++ b/demo/Choice.py @@ -0,0 +1,54 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestChoice(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', + 'six', 'seven', 'eight'] + + wx.StaticText(self, -1, "This example uses the wxChoice control.", (15, 10)) + wx.StaticText(self, -1, "Select one:", (15, 50), (75, -1)) + self.ch = wx.Choice(self, -1, (100, 50), choices = sampleList) + self.Bind(wx.EVT_CHOICE, self.EvtChoice, self.ch) + + + def EvtChoice(self, event): + self.log.WriteText('EvtChoice: %s\n' % event.GetString()) + self.ch.Append("A new item") + + if event.GetString() == 'one': + self.log.WriteText('Well done!\n') + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestChoice(nb, log) + return win + +#--------------------------------------------------------------------------- + +overview = """ +A Choice control is used to select one of a list of strings. Unlike a listbox, +only the current selection is visible until the user pulls down the menu of +choices. + +This demo illustrates how to set up the Choice control and how to extract the +selected choice once it is selected. + +Note that the syntax of the constructor is different than the C++ implementation. +The number of choices and the choice array are consilidated into one python +list. +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Choicebook.py b/demo/Choicebook.py new file mode 100644 index 00000000..4b92842e --- /dev/null +++ b/demo/Choicebook.py @@ -0,0 +1,79 @@ + +import wx + +#---------------------------------------------------------------------------- + +pageTexts = [ "Yet", + "Another", + "Way", + "To", + "Select", + "Pages" + ] + + +class TestCB(wx.Choicebook): + def __init__(self, parent, id, log): + wx.Choicebook.__init__(self, parent, id) + self.log = log + + # Now make a bunch of panels for the choice book + count = 1 + for txt in pageTexts: + win = wx.Panel(self) + if count == 1: + st = wx.StaticText(win, -1, + "wx.Choicebook is yet another way to switch between 'page' windows", + (10, 10)) + else: + st = wx.StaticText(win, -1, "Page: %d" % count, (10,10)) + count += 1 + + self.AddPage(win, txt) + + self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGED, self.OnPageChanged) + self.Bind(wx.EVT_CHOICEBOOK_PAGE_CHANGING, self.OnPageChanging) + + + def OnPageChanged(self, event): + old = event.GetOldSelection() + new = event.GetSelection() + sel = self.GetSelection() + self.log.write('OnPageChanged, old:%d, new:%d, sel:%d\n' % (old, new, sel)) + event.Skip() + + def OnPageChanging(self, event): + old = event.GetOldSelection() + new = event.GetSelection() + sel = self.GetSelection() + self.log.write('OnPageChanging, old:%d, new:%d, sel:%d\n' % (old, new, sel)) + event.Skip() + +#---------------------------------------------------------------------------- + +def runTest(frame, nb, log): + testWin = TestCB(nb, -1, log) + return testWin + +#---------------------------------------------------------------------------- + + +overview = """\ + +

wx.Choicebook

+

+ +This class is a control similar to a notebook control, but uses a +wx.Choice to manage the selection of the pages. + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + diff --git a/demo/CollapsiblePane.py b/demo/CollapsiblePane.py new file mode 100644 index 00000000..2c35d712 --- /dev/null +++ b/demo/CollapsiblePane.py @@ -0,0 +1,125 @@ + +import wx + +#---------------------------------------------------------------------- + +label1 = "Click here to show pane" +label2 = "Click here to hide pane" + +btnlbl1 = "call Expand(True)" +btnlbl2 = "call Expand(False)" + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + title = wx.StaticText(self, label="wx.CollapsiblePane") + title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)) + title.SetForegroundColour("blue") + + self.cp = cp = wx.CollapsiblePane(self, label=label1, + style=wx.CP_DEFAULT_STYLE|wx.CP_NO_TLW_RESIZE) + self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged, cp) + self.MakePaneContent(cp.GetPane()) + + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(sizer) + sizer.Add(title, 0, wx.ALL, 25) + sizer.Add(cp, 0, wx.RIGHT|wx.LEFT|wx.EXPAND, 25) + + self.btn = btn = wx.Button(self, label=btnlbl1) + self.Bind(wx.EVT_BUTTON, self.OnToggle, btn) + sizer.Add(btn, 0, wx.ALL, 25) + + + def OnToggle(self, evt): + self.cp.Collapse(self.cp.IsExpanded()) + self.OnPaneChanged() + + + def OnPaneChanged(self, evt=None): + if evt: + self.log.write('wx.EVT_COLLAPSIBLEPANE_CHANGED: %s' % evt.Collapsed) + + # redo the layout + self.Layout() + + # and also change the labels + if self.cp.IsExpanded(): + self.cp.SetLabel(label2) + self.btn.SetLabel(btnlbl2) + else: + self.cp.SetLabel(label1) + self.btn.SetLabel(btnlbl1) + self.btn.SetInitialSize() + + + def MakePaneContent(self, pane): + '''Just make a few controls to put on the collapsible pane''' + nameLbl = wx.StaticText(pane, -1, "Name:") + name = wx.TextCtrl(pane, -1, ""); + + addrLbl = wx.StaticText(pane, -1, "Address:") + addr1 = wx.TextCtrl(pane, -1, ""); + addr2 = wx.TextCtrl(pane, -1, ""); + + cstLbl = wx.StaticText(pane, -1, "City, State, Zip:") + city = wx.TextCtrl(pane, -1, "", size=(150,-1)); + state = wx.TextCtrl(pane, -1, "", size=(50,-1)); + zip = wx.TextCtrl(pane, -1, "", size=(70,-1)); + + addrSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5) + addrSizer.AddGrowableCol(1) + addrSizer.Add(nameLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(name, 0, wx.EXPAND) + addrSizer.Add(addrLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(addr1, 0, wx.EXPAND) + addrSizer.Add((5,5)) + addrSizer.Add(addr2, 0, wx.EXPAND) + + addrSizer.Add(cstLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + + cstSizer = wx.BoxSizer(wx.HORIZONTAL) + cstSizer.Add(city, 1) + cstSizer.Add(state, 0, wx.LEFT|wx.RIGHT, 5) + cstSizer.Add(zip) + addrSizer.Add(cstSizer, 0, wx.EXPAND) + + border = wx.BoxSizer() + border.Add(addrSizer, 1, wx.EXPAND|wx.ALL, 5) + pane.SetSizer(border) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.CollapsiblePane

+ +A collapsable panel is a container with an embedded button-like +control which can be used by the user to collapse or expand the pane's +contents. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ColorPanel.py b/demo/ColorPanel.py new file mode 100644 index 00000000..29ef92c1 --- /dev/null +++ b/demo/ColorPanel.py @@ -0,0 +1,20 @@ +# +# Note: this module is not a demo per se, but is used by many of +# the demo modules for various purposes. +# + +import wx + +#--------------------------------------------------------------------------- + + +class ColoredPanel(wx.Window): + def __init__(self, parent, color): + wx.Window.__init__(self, parent, -1, style = wx.SIMPLE_BORDER) + self.SetBackgroundColour(color) + if wx.Platform == '__WXGTK__': + self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + + +#--------------------------------------------------------------------------- + diff --git a/demo/ColourDB.py b/demo/ColourDB.py new file mode 100644 index 00000000..4cce7599 --- /dev/null +++ b/demo/ColourDB.py @@ -0,0 +1,202 @@ + +import wx +import wx.lib.colourdb + +import images + + +#---------------------------------------------------------------------- + +class TestWindow(wx.ScrolledWindow): + def __init__(self, parent): + wx.ScrolledWindow.__init__(self, parent, -1) + + # Populate our color list + self.clrList = wx.lib.colourdb.getColourInfoList() + + # Just for style points, we'll use this as a background image. + self.bg_bmp = images.GridBG.GetBitmap() + + # This could also be done by getting the window's default font; + # either way, we need to have a font loaded for later on. + #self.SetBackgroundColour("WHITE") + self.font = wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL) + + # Create drawing area and set its font + dc = wx.ClientDC(self) + dc.SetFont(self.font) + + # Using GetFullTextExtent(), we calculate a basic 'building block' + # that will be used to draw a depiction of the color list. We're + # using 'Wy' as the model becuase 'W' is a wide character and 'y' + # has a descender. This constitutes a 'worst case' scenario, which means + # that no matter what we draw later, text-wise, we'll have room for it + w,h,d,e = dc.GetFullTextExtent("Wy") + + # Height plus descender + self.textHeight = h + d + + # Pad a little bit + self.lineHeight = self.textHeight + 5 + + # ... and this is the basic width. + self.cellWidth = w + + # jmg 11/8/03: why 24? + numCells = 24 + + # 'prep' our scroll bars. + self.SetScrollbars( + self.cellWidth, self.lineHeight, numCells, len(self.clrList) + 2 + ) + + # Bind event handlers + self.SetBackgroundStyle(wx.BG_STYLE_ERASE) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + + + # tile the background bitmap loaded in __init__() + def TileBackground(self, dc): + sz = self.GetClientSize() + w = self.bg_bmp.GetWidth() + h = self.bg_bmp.GetHeight() + + # adjust for scrolled position + spx, spy = self.GetScrollPixelsPerUnit() + vsx, vsy = self.GetViewStart() + dx, dy = (spx * vsx) % w, (spy * vsy) % h + + x = -dx + + while x < sz.width: + y = -dy + while y < sz.height: + dc.DrawBitmap(self.bg_bmp, x, y) + y = y + h + + x = x + w + + # Redraw the background over a 'damaged' area. + def OnEraseBackground(self, evt): + dc = evt.GetDC() + + if not dc: + dc = wx.ClientDC(self) + rect = self.GetUpdateRegion().GetBox() + dc.SetClippingRect(rect) + + self.TileBackground(dc) + + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + self.PrepareDC(dc) + self.Draw(dc, self.GetUpdateRegion(), self.GetViewStart()) + + + def Draw(self, dc, rgn=None, vs=None): + dc.SetTextForeground("BLACK") + dc.SetPen(wx.Pen("BLACK", 1, wx.SOLID)) + dc.SetFont(self.font) + colours = self.clrList + numColours = len(colours) + + if rgn: + # determine the subset of the color list that has been exposed + # and needs drawn. This is based on all the precalculation we + # did in __init__() + rect = rgn.GetBox() + pixStart = vs[1]*self.lineHeight + rect.y + pixStop = pixStart + rect.height + start = pixStart / self.lineHeight - 1 + stop = pixStop / self.lineHeight + else: + start = 0 + stop = numColours + + for line in range(max(0,start), min(stop,numColours)): + clr = colours[line][0] + y = (line+1) * self.lineHeight + 2 + + dc.DrawText(clr, self.cellWidth, y) + + brush = wx.Brush(clr, wx.SOLID) + dc.SetBrush(brush) + dc.DrawRectangle(10 * self.cellWidth, y, + 6 * self.cellWidth, self.textHeight) + + dc.DrawText(str(tuple(colours[line][1:])), + 18 * self.cellWidth, y) + + hexstr = "#%02X%02X%02X" % tuple(colours[line][1:]) + dc.DrawText(hexstr, 25 * self.cellWidth, y) + + +# On wxGTK there needs to be a panel under wx.ScrolledWindows if they are +# going to be in a wxNotebook. And, in this demo, we are. +class TestPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, -1) + self.win = TestWindow(self) + self.Bind(wx.EVT_SIZE, self.OnSize) + + + def OnSize(self, evt): + self.win.SetSize(evt.GetSize()) + + + +#---------------------------------------------------------------------- + + +def runTest(frame, nb, log): + # This loads a whole bunch of new color names and values + # into TheColourDatabase + # + # Note 11/24/03 - jg - I moved this into runTest() because + # there must be a wx.App existing before this function + # can be called - this is a change from 2.4 -> 2.5. + wx.lib.colourdb.updateColourDB() + + win = TestPanel(nb) + + return win + +#---------------------------------------------------------------------- + +overview = """ + + +ColourDB + +

wxWindows maintains a database of standard RGB colours for a predefined +set of named colours (such as "BLACK'', "LIGHT GREY''). The application +may add to this set if desired by using Append. There is only one instance +of this class: TheColourDatabase. + +

The colourdb library is a lightweight API that pre-defines +a multitude of colors for you to use 'out of the box', and this demo serves +to show you these colors (it also serves as a handy reference). + +

A secondary benefit of this demo is the use of the ScrolledWindow class +and the use of various *DC() classes, including background tiling and the use of +font data to generate a "building block" type of construct for repetitive use. + +

+Important note + +

+With implementation of V2.5 and later, it is required to have a wx.App already +initialized before wx.updateColourDB() can be called. +Trying to do otherwise will cause an exception to be raised. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ColourDialog.py b/demo/ColourDialog.py new file mode 100644 index 00000000..13422421 --- /dev/null +++ b/demo/ColourDialog.py @@ -0,0 +1,72 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a ColourDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + dlg = wx.ColourDialog(self) + + # Ensure the full colour dialog is displayed, + # not the abbreviated version. + dlg.GetColourData().SetChooseFull(True) + + if dlg.ShowModal() == wx.ID_OK: + + # If the user selected OK, then the dialog's wx.ColourData will + # contain valid information. Fetch the data ... + data = dlg.GetColourData() + + # ... then do something with it. The actual colour data will be + # returned as a three-tuple (r, g, b) in this particular case. + self.log.WriteText('You selected: %s\n' % str(data.GetColour().Get())) + + # Once the dialog is destroyed, Mr. wx.ColourData is no longer your + # friend. Don't use it again! + dlg.Destroy() + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = """\ +This class represents the colour chooser dialog. + +Use of this dialog is a multi-stage process. + +The actual information about how to display the dialog and the colors in the +dialog's 'registers' are contained in a wx.ColourData instance that is created by +the dialog at init time. Before displaying the dialog, you may alter these settings +to suit your needs. In the example, we set the dialog up to show the extended colour +data selection pane. Otherwise, only the more compact and less extensive colour +dialog is shown. You may also preset the colour as well as other items. + +If the user selects something and selects OK, then the wx.ColourData instance contains +the colour data that the user selected. Before destroying the dialog, retrieve the data. +Do not try to retain the wx.ColourData instance. It will probably not be valid +after the dialog is destroyed. + +Along with he wx.ColourDialog documentation, see also the wx.ColourData documentation +for details. +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ColourSelect.py b/demo/ColourSelect.py new file mode 100644 index 00000000..d255708d --- /dev/null +++ b/demo/ColourSelect.py @@ -0,0 +1,116 @@ +#---------------------------------------------------------------------------- +# Name: ColourSelect.py +# Purpose: Colour Selection control display testing on panel for wxPython demo +# +# Author: Lorne White (email: lorne.white@telusplanet.net) +# +# Version 0.6 +# Date: Nov 14, 2001 +# Licence: wxWindows license +# +# Change Log: Add Label parameter to accommodate updated library code +# +# Cliff Wells (logiplexsoftware@earthlink.net) 2002/03/11 +# - added code to demonstrate EVT_COLOURSELECT +# - use sizers +# - other minor "improvements" +#---------------------------------------------------------------------------- +# + +import wx +import wx.lib.colourselect as csel + +#---------------------------------------------------------------------------- + +class TestColourSelect(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + self.SetAutoLayout(True) + mainSizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(mainSizer) + t = wx.StaticText(self, -1, + "This example uses a colour selection control based on the wxButton\n" + "and wxColourDialog Classes. Click Button to get Colour Values") + mainSizer.Add(t, 0, wx.ALL, 3) + + b = wx.Button(self, -1, "Show All Colours") + self.Bind(wx.EVT_BUTTON, self.OnShowAll, id=b.GetId()) + mainSizer.Add(b, 0, wx.ALL, 3) + + buttonSizer = wx.FlexGridSizer(cols=2) # sizer to contain all the example buttons + + # show a button with all default values + self.colourDefaults = csel.ColourSelect(self, -1) + + self.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour, id=self.colourDefaults.GetId()) + + buttonSizer.AddMany([ + (wx.StaticText(self, -1, "Default Colour/Size"), 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL), + (self.colourDefaults, 0, wx.ALL, 3), + ]) + + # build several examples of buttons with different colours and sizes + buttonData = [ + ("Default Size", (255, 255, 0), wx.DefaultSize, ""), + ("Another Size", (255, 0, 255), (60, 20), ""), + ("Another Colour", (0, 255, 0), wx.DefaultSize, ""), + ("Larger Size", (0, 0, 255), (60, 60), ""), + ("With a Label", (127, 0, 255), wx.DefaultSize, "Colour..."), + ("Another Colour/Label", (255, 100, 130), (120, -1), "Choose Colour..."), + ] + + self.buttonRefs = [] # for saving references to buttons + + # build each button and save a reference to it + for name, color, size, label in buttonData: + b = csel.ColourSelect(self, -1, label, color, size = size) + + b.Bind(csel.EVT_COLOURSELECT, self.OnSelectColour) + self.buttonRefs.append((name, b)) # store reference to button + + buttonSizer.AddMany([ + (wx.StaticText(self, -1, name), 0, wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL), + (b, 0, wx.ALL, 3), + ]) + + mainSizer.Add(buttonSizer, 0, wx.ALL, 3) + self.Layout() + + def OnSelectColour(self, event): + self.log.WriteText("Colour selected: %s" % str(event.GetValue())) + + def OnShowAll(self, event): + # show the state of each button + result = [] + colour = self.colourDefaults.GetColour() # default control value + result.append("Default Colour/Size: " + str(colour)) + + for name, button in self.buttonRefs: + colour = button.GetColour() # get the colour selection button result + result.append(name + ": " + str(colour)) # create string list for easy viewing of results + + out_result = ', '.join(result) + self.log.WriteText("Colour Results: " + out_result + "\n") + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestColourSelect(nb, log) + return win + +#--------------------------------------------------------------------------- + + + + +overview = """\ +A coloured button that when clicked allows the user to select a colour from the wxColourDialog. +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ComboBox.py b/demo/ComboBox.py new file mode 100644 index 00000000..c4d6623c --- /dev/null +++ b/demo/ComboBox.py @@ -0,0 +1,110 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestComboBox(wx.Panel): + def OnSetFocus(self, evt): + print "OnSetFocus" + evt.Skip() + + def OnKillFocus(self, evt): + print "OnKillFocus" + evt.Skip() + + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', + #'this is a long item that needs a scrollbar...', + 'six', 'seven', 'eight'] + + wx.StaticText(self, -1, "This example uses the wx.ComboBox control.", (8, 10)) + wx.StaticText(self, -1, "Select one:", (15, 50), (75, 18)) + + # This combobox is created with a preset list of values. + cb = wx.ComboBox(self, 500, "default value", (90, 50), + (160, -1), sampleList, + wx.CB_DROPDOWN + #| wx.TE_PROCESS_ENTER + #| wx.CB_SORT + ) + + self.Bind(wx.EVT_COMBOBOX, self.EvtComboBox, cb) + self.Bind(wx.EVT_TEXT, self.EvtText, cb) + self.Bind(wx.EVT_TEXT_ENTER, self.EvtTextEnter, cb) + cb.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) + cb.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) + + # Once the combobox is set up, we can append some more data to it. + cb.Append("foo", "This is some client data for this item") + + # This combobox is created with no values initially. + cb = wx.ComboBox( + self, 501, "default value", (90, 80), (160, -1), [], wx.CB_DROPDOWN) + + # Here we dynamically add our values to the second combobox. + for item in sampleList: + cb.Append(item, item.upper()) + + self.Bind(wx.EVT_COMBOBOX, self.EvtComboBox, cb) + + # When the user selects something, we go here. + def EvtComboBox(self, evt): + cb = evt.GetEventObject() + data = cb.GetClientData(evt.GetSelection()) + self.log.WriteText('EvtComboBox: %s\nClientData: %s\n' % (evt.GetString(), data)) + + if evt.GetString() == 'one': + self.log.WriteText("You follow directions well!\n\n") + + # Capture events every time a user hits a key in the text entry field. + def EvtText(self, evt): + self.log.WriteText('EvtText: %s\n' % evt.GetString()) + evt.Skip() + + # Capture events when the user types something into the control then + # hits ENTER. + def EvtTextEnter(self, evt): + self.log.WriteText('EvtTextEnter: %s' % evt.GetString()) + evt.Skip() + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestComboBox(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ +A ComboBox is like a combination of an edit control and a listbox. It can be +displayed as static list with editable or read-only text field; or a drop-down +list with text field; or a drop-down list without a text field. + +This example shows both a preset ComboBox and one that is dynamically created +(that is, it is initially empty but then we 'grow' it out of program-supplied +data). The former is common for read-only controls. + +This example also shows the two form factors for the ComboBox. The first is more +common, and resembles a Choice control. The latter, although less common, shows +how all the values in the ComboBox can be visible, yet the functionality is the +same for both. + +Finally, this demo shows how event handling can differ. The first ComboBox is set +up to handle EVT_TEXT_ENTER events, in which text is typed in and then ENTER is +hit by the user. This allows the user to enter a line of text which can then be +processed by the program. EVT_TEXT can also be processed, but in that case the +event is generated every time that the user hits a key in the ComboBox entry field. + +""" + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ComboCtrl.py b/demo/ComboCtrl.py new file mode 100644 index 00000000..eb2de5a1 --- /dev/null +++ b/demo/ComboCtrl.py @@ -0,0 +1,480 @@ + +import wx +import wx.combo +import os + +#---------------------------------------------------------------------- + +class NullLog: + def write(*args): + pass + + +# This class is used to provide an interface between a ComboCtrl and a +# ListCtrl that is used as the popoup for the combo widget. In this +# case we use multiple inheritance to derive from both wx.ListCtrl and +# wx.ComboPopup, but it also works well when deriving from just +# ComboPopup and using a has-a relationship with the popup control, +# you just need to be sure to return the control itself from the +# GetControl method. + +class ListCtrlComboPopup(wx.ListCtrl, wx.combo.ComboPopup): + + def __init__(self, log=None): + if log: + self.log = log + else: + self.log = NullLog() + + + # Since we are using multiple inheritance, and don't know yet + # which window is to be the parent, we'll do 2-phase create of + # the ListCtrl instead, and call its Create method later in + # our Create method. (See Create below.) + self.PostCreate(wx.PreListCtrl()) + + # Also init the ComboPopup base class. + wx.combo.ComboPopup.__init__(self) + + + def AddItem(self, txt): + self.InsertStringItem(self.GetItemCount(), txt) + + def OnMotion(self, evt): + item, flags = self.HitTest(evt.GetPosition()) + if item >= 0: + self.Select(item) + self.curitem = item + + def OnLeftDown(self, evt): + self.value = self.curitem + self.Dismiss() + + + # The following methods are those that are overridable from the + # ComboPopup base class. Most of them are not required, but all + # are shown here for demonstration purposes. + + + # This is called immediately after construction finishes. You can + # use self.GetCombo if needed to get to the ComboCtrl instance. + def Init(self): + self.log.write("ListCtrlComboPopup.Init") + self.value = -1 + self.curitem = -1 + + + # Create the popup child control. Return true for success. + def Create(self, parent): + self.log.write("ListCtrlComboPopup.Create") + wx.ListCtrl.Create(self, parent, + style=wx.LC_LIST|wx.LC_SINGLE_SEL|wx.SIMPLE_BORDER) + #self.Bind(wx.EVT_MOTION, self.OnMotion) + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + return True + + + # Return the widget that is to be used for the popup + def GetControl(self): + #self.log.write("ListCtrlComboPopup.GetControl") + return self + + # Called just prior to displaying the popup, you can use it to + # 'select' the current item. + def SetStringValue(self, val): + self.log.write("ListCtrlComboPopup.SetStringValue") + idx = self.FindItem(-1, val) + if idx != wx.NOT_FOUND: + self.Select(idx) + + # Return a string representation of the current item. + def GetStringValue(self): + self.log.write("ListCtrlComboPopup.GetStringValue") + if self.value >= 0: + return self.GetItemText(self.value) + return "" + + # Called immediately after the popup is shown + def OnPopup(self): + self.log.write("ListCtrlComboPopup.OnPopup") + wx.combo.ComboPopup.OnPopup(self) + + # Called when popup is dismissed + def OnDismiss(self): + self.log.write("ListCtrlComboPopup.OnDismiss") + wx.combo.ComboPopup.OnDismiss(self) + + # This is called to custom paint in the combo control itself + # (ie. not the popup). Default implementation draws value as + # string. + def PaintComboControl(self, dc, rect): + self.log.write("ListCtrlComboPopup.PaintComboControl") + wx.combo.ComboPopup.PaintComboControl(self, dc, rect) + + # Receives key events from the parent ComboCtrl. Events not + # handled should be skipped, as usual. + def OnComboKeyEvent(self, event): + self.log.write("ListCtrlComboPopup.OnComboKeyEvent") + wx.combo.ComboPopup.OnComboKeyEvent(self, event) + + # Implement if you need to support special action when user + # double-clicks on the parent wxComboCtrl. + def OnComboDoubleClick(self): + self.log.write("ListCtrlComboPopup.OnComboDoubleClick") + wx.combo.ComboPopup.OnComboDoubleClick(self) + + # Return final size of popup. Called on every popup, just prior to OnPopup. + # minWidth = preferred minimum width for window + # prefHeight = preferred height. Only applies if > 0, + # maxHeight = max height for window, as limited by screen size + # and should only be rounded down, if necessary. + def GetAdjustedSize(self, minWidth, prefHeight, maxHeight): + self.log.write("ListCtrlComboPopup.GetAdjustedSize: %d, %d, %d" % (minWidth, prefHeight, maxHeight)) + return wx.combo.ComboPopup.GetAdjustedSize(self, minWidth, prefHeight, maxHeight) + + # Return true if you want delay the call to Create until the popup + # is shown for the first time. It is more efficient, but note that + # it is often more convenient to have the control created + # immediately. + # Default returns false. + def LazyCreate(self): + self.log.write("ListCtrlComboPopup.LazyCreate") + return wx.combo.ComboPopup.LazyCreate(self) + + + +#---------------------------------------------------------------------- +# This class is a popup containing a TreeCtrl. This time we'll use a +# has-a style (instead of is-a like above.) + +class TreeCtrlComboPopup(wx.combo.ComboPopup): + + # overridden ComboPopup methods + + def Init(self): + self.value = None + self.curitem = None + + + def Create(self, parent): + self.tree = wx.TreeCtrl(parent, style=wx.TR_HIDE_ROOT + |wx.TR_HAS_BUTTONS + |wx.TR_SINGLE + |wx.TR_LINES_AT_ROOT + |wx.SIMPLE_BORDER) + self.tree.Bind(wx.EVT_MOTION, self.OnMotion) + self.tree.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + + + def GetControl(self): + return self.tree + + + def GetStringValue(self): + if self.value: + return self.tree.GetItemText(self.value) + return "" + + + def OnPopup(self): + if self.value: + self.tree.EnsureVisible(self.value) + self.tree.SelectItem(self.value) + + + def SetStringValue(self, value): + # this assumes that item strings are unique... + root = self.tree.GetRootItem() + if not root: + return + found = self.FindItem(root, value) + if found: + self.value = found + self.tree.SelectItem(found) + + + def GetAdjustedSize(self, minWidth, prefHeight, maxHeight): + return wx.Size(minWidth, min(200, maxHeight)) + + + # helpers + + def FindItem(self, parentItem, text): + item, cookie = self.tree.GetFirstChild(parentItem) + while item: + if self.tree.GetItemText(item) == text: + return item + if self.tree.ItemHasChildren(item): + item = self.FindItem(item, text) + item, cookie = self.tree.GetNextChild(parentItem, cookie) + return wx.TreeItemId(); + + + def AddItem(self, value, parent=None): + if not parent: + root = self.tree.GetRootItem() + if not root: + root = self.tree.AddRoot("") + parent = root + + item = self.tree.AppendItem(parent, value) + return item + + + def OnMotion(self, evt): + # have the selection follow the mouse, like in a real combobox + item, flags = self.tree.HitTest(evt.GetPosition()) + if item and flags & wx.TREE_HITTEST_ONITEMLABEL: + self.tree.SelectItem(item) + self.curitem = item + evt.Skip() + + + def OnLeftDown(self, evt): + # do the combobox selection + item, flags = self.tree.HitTest(evt.GetPosition()) + if item and flags & wx.TREE_HITTEST_ONITEMLABEL: + self.curitem = item + self.value = item + self.Dismiss() + evt.Skip() + + +#---------------------------------------------------------------------- +# Here we subclass wx.combo.ComboCtrl to do some custom popup animation + +CUSTOM_COMBOBOX_ANIMATION_DURATION = 200 + +class ComboCtrlWithCustomPopupAnim(wx.combo.ComboCtrl): + def __init__(self, *args, **kw): + wx.combo.ComboCtrl.__init__(self, *args, **kw) + self.Bind(wx.EVT_TIMER, self.OnTimer) + self.aniTimer = wx.Timer(self) + + + def AnimateShow(self, rect, flags): + self.aniStart = wx.GetLocalTimeMillis() + self.aniRect = wx.Rect(*rect) + self.aniFlags = flags + + dc = wx.ScreenDC() + bmp = wx.EmptyBitmap(rect.width, rect.height) + mdc = wx.MemoryDC(bmp) + if "wxMac" in wx.PlatformInfo: + pass + else: + mdc.Blit(0, 0, rect.width, rect.height, dc, rect.x, rect.y) + del mdc + self.aniBackBitmap = bmp + + self.aniTimer.Start(10, wx.TIMER_CONTINUOUS) + self.OnTimer(None) + return False + + + def OnTimer(self, evt): + stopTimer = False + popup = self.GetPopupControl().GetControl() + rect = self.aniRect + dc = wx.ScreenDC() + + if self.IsPopupWindowState(self.Hidden): + stopTimer = True + else: + pos = wx.GetLocalTimeMillis() - self.aniStart + if pos < CUSTOM_COMBOBOX_ANIMATION_DURATION: + # Actual animation happens here + width = rect.width + height = rect.height + + center_x = rect.x + (width/2) + center_y = rect.y + (height/2) + + dc.SetPen( wx.BLACK_PEN ) + dc.SetBrush( wx.TRANSPARENT_BRUSH ) + + w = (((pos*256)/CUSTOM_COMBOBOX_ANIMATION_DURATION)*width)/256 + ratio = float(w) / float(width) + h = int(height * ratio) + + dc.DrawBitmap( self.aniBackBitmap, rect.x, rect.y ) + dc.DrawRectangle( center_x - w/2, center_y - h/2, w, h ) + else: + stopTimer = True + + if stopTimer: + dc.DrawBitmap( self.aniBackBitmap, rect.x, rect.y ) + popup.Move( (0, 0) ) + self.aniTimer.Stop() + self.DoShowPopup( rect, self.aniFlags ) + + +#---------------------------------------------------------------------- +# FileSelectorCombo displays a dialog instead of a popup control, it +# also uses a custom bitmap on the combo button. + +class FileSelectorCombo(wx.combo.ComboCtrl): + def __init__(self, *args, **kw): + wx.combo.ComboCtrl.__init__(self, *args, **kw) + + # make a custom bitmap showing "..." + bw, bh = 14, 16 + bmp = wx.EmptyBitmap(bw,bh) + dc = wx.MemoryDC(bmp) + + # clear to a specific background colour + bgcolor = wx.Colour(255,254,255) + dc.SetBackground(wx.Brush(bgcolor)) + dc.Clear() + + # draw the label onto the bitmap + label = "..." + font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + font.SetWeight(wx.FONTWEIGHT_BOLD) + dc.SetFont(font) + tw,th = dc.GetTextExtent(label) + dc.DrawText(label, (bw-tw)/2, (bw-tw)/2) + del dc + + # now apply a mask using the bgcolor + bmp.SetMaskColour(bgcolor) + + # and tell the ComboCtrl to use it + self.SetButtonBitmaps(bmp, True) + + self.Bind(wx.EVT_TEXT, self.onText) + + def onText(self, evt): + print 'EVT_TEXT:', self.GetValue() + evt.Skip() + + # Overridden from ComboCtrl, called when the combo button is clicked + def OnButtonClick(self): + path = "" + name = "" + if self.GetValue(): + path, name = os.path.split(self.GetValue()) + + dlg = wx.FileDialog(self, "Choose File", path, name, + "All files (*.*)|*.*", wx.FD_OPEN) + if dlg.ShowModal() == wx.ID_OK: + self.SetValue(dlg.GetPath()) + dlg.Destroy() + self.SetFocus() + + # Overridden from ComboCtrl to avoid assert since there is no ComboPopup + def DoSetPopupControl(self, popup): + pass + + +#---------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + fgs = wx.FlexGridSizer(cols=3, hgap=10, vgap=10) + + cc = self.MakeLCCombo(log=self.log) + fgs.Add(cc) + fgs.Add((10,10)) + fgs.Add(wx.StaticText(self, -1, "wx.ComboCtrl with a ListCtrl popup")) + + cc = self.MakeLCCombo(style=wx.CB_READONLY) + fgs.Add(cc) + fgs.Add((10,10)) + fgs.Add(wx.StaticText(self, -1, " Read-only")) + + cc = self.MakeLCCombo() + cc.SetButtonPosition(side=wx.LEFT) + fgs.Add(cc) + fgs.Add((10,10)) + fgs.Add(wx.StaticText(self, -1, " Button on the left")) + + cc = self.MakeLCCombo() + cc.SetPopupMaxHeight(250) + fgs.Add(cc) + fgs.Add((10,10)) + fgs.Add(wx.StaticText(self, -1, " Max height of popup set")) + + cc = wx.combo.ComboCtrl(self, size=(250,-1)) + tcp = TreeCtrlComboPopup() + cc.SetPopupControl(tcp) + fgs.Add(cc) + fgs.Add((10,10)) + fgs.Add(wx.StaticText(self, -1, "TreeCtrl popup")) + # add some items to the tree + for i in range(5): + item = tcp.AddItem('Item %d' % (i+1)) + for j in range(15): + tcp.AddItem('Subitem %d-%d' % (i+1, j+1), parent=item) + + cc = ComboCtrlWithCustomPopupAnim(self, size=(250, -1)) + popup = ListCtrlComboPopup() + cc.SetPopupMaxHeight(150) + cc.SetPopupControl(popup) + fgs.Add(cc) + fgs.Add((10,10)) + fgs.Add(wx.StaticText(self, -1, "Custom popup animation")) + for word in "How cool was that!? Way COOL!".split(): + popup.AddItem(word) + if "wxMac" in wx.PlatformInfo: + cc.SetValue("Sorry, animation not working yet on Mac") + + + cc = FileSelectorCombo(self, size=(250, -1)) + fgs.Add(cc) + fgs.Add((10,10)) + fgs.Add(wx.StaticText(self, -1, "Custom popup action, and custom button bitmap")) + + box = wx.BoxSizer() + box.Add(fgs, 1, wx.EXPAND|wx.ALL, 20) + self.SetSizer(box) + + + def MakeLCCombo(self, log=None, style=0): + # Create a ComboCtrl + cc = wx.combo.ComboCtrl(self, style=style, size=(250,-1)) + + # Create a Popup + popup = ListCtrlComboPopup(log) + + # Associate them with each other. This also triggers the + # creation of the ListCtrl. + cc.SetPopupControl(popup) + + # Add some items to the listctrl. + for x in range(75): + popup.AddItem("Item-%02d" % x) + + return cc + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.combo.ComboCtrl

+ +A combo control is a generic combobox that allows a totally custom +popup. In addition it has other customization features. For instance, +position and size of the dropdown button can be changed. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/ComboTreeBox.py b/demo/ComboTreeBox.py new file mode 100644 index 00000000..4a4e5b2f --- /dev/null +++ b/demo/ComboTreeBox.py @@ -0,0 +1,69 @@ +import wx +from wx.lib.combotreebox import ComboTreeBox + + +#--------------------------------------------------------------------------- + + +class TestComboTreeBox(wx.Panel): + def __init__(self, parent, log): + super(TestComboTreeBox, self).__init__(parent) + self.log = log + panelSizer = wx.FlexGridSizer(cols=2) + panelSizer.AddGrowableCol(1) + for style, labelText in [(0, 'Default style:'), + (wx.CB_READONLY, 'Read-only style:')]: + label = wx.StaticText(self, label=labelText) + panelSizer.Add(label, flag=wx.ALL|wx.ALIGN_CENTER_VERTICAL, + border=5) + comboBox = self._createComboTreeBox(style) + panelSizer.Add(comboBox, flag=wx.EXPAND|wx.ALL, border=5) + self.SetSizerAndFit(panelSizer) + + def _createComboTreeBox(self, style): + comboBox = ComboTreeBox(self, style=style) + self._bindEventHandlers(comboBox) + for i in range(5): + child = comboBox.Append('Item %d'%i) + for j in range(5): + grandChild = comboBox.Append('Item %d.%d'%(i,j), child) + for k in range(5): + comboBox.Append('Item %d.%d.%d'%(i,j, k), grandChild) + return comboBox + + def _bindEventHandlers(self, comboBox): + for eventType, handler in [(wx.EVT_COMBOBOX, self.OnItemSelected), + (wx.EVT_TEXT, self.OnItemEntered)]: + comboBox.Bind(eventType, handler) + + def OnItemSelected(self, event): + self.log.WriteText('You selected: %s\n'%event.GetString()) + event.Skip() + + def OnItemEntered(self, event): + self.log.WriteText('You entered: %s\n'%event.GetString()) + event.Skip() + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestComboTreeBox(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = wx.lib.combotreebox.__doc__ + + +#--------------------------------------------------------------------------- + + +if __name__ == '__main__': + import sys, os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/CommandLinkButton.py b/demo/CommandLinkButton.py new file mode 100644 index 00000000..5b0e1bf9 --- /dev/null +++ b/demo/CommandLinkButton.py @@ -0,0 +1,47 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + cmd = wx.CommandLinkButton(self, -1, + "wx.CommandLinkButton", + """\ +This type of button includes both a main label and a 'note' that is meant to +contain a description of what the button does or what it is used for. On +Windows 7 it is a new native widget type, on the other platforms it is +implemented generically.""", + pos=(25,25)) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.CommandLinkButton

+ +This type of button includes both a main label and a 'note' that is meant to +contain a description of what the button does or what it is used for. On +Windows 7 it is a new native widget type, on the other platforms it is +implemented generically. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ContextHelp.py b/demo/ContextHelp.py new file mode 100644 index 00000000..0367a5b8 --- /dev/null +++ b/demo/ContextHelp.py @@ -0,0 +1,111 @@ + +import wx + +#---------------------------------------------------------------------- +# We first have to set an application-wide help provider. Normally you +# would do this in your app's OnInit or in other startup code... + +provider = wx.SimpleHelpProvider() +wx.HelpProvider_Set(provider) + +# This panel is chock full of controls about which we can demonstrate the +# help system. +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + # This help text, set for the panel itself, will be used if context + # sensitive help cannot be found for any particular control. + self.SetHelpText("This is a wx.Panel.") + + sizer = wx.BoxSizer(wx.VERTICAL) + + # Init the context help button. + # And even include help text about the help button :-) + cBtn = wx.ContextHelpButton(self) + cBtn.SetHelpText("wx.ContextHelpButton") + + cBtnText = wx.StaticText(self, -1, + "This is a wx.ContextHelpButton. Clicking it puts the\n" + "app into context sensitive help mode." + ) + + # Yes, even static text can have help text associated with it :-) + cBtnText.SetHelpText("Some helpful text...") + + s = wx.BoxSizer(wx.HORIZONTAL) + s.Add(cBtn, 0, wx.ALL, 5) + s.Add(cBtnText, 0, wx.ALL, 5) + sizer.Add((20,20)) + sizer.Add(s) + + # A text control with help text. + text = wx.TextCtrl(self, -1, "Each sub-window can have its own help message", + size=(240, 60), style=wx.TE_MULTILINE) + text.SetHelpText("This is my very own help message. This is a really long long long long long long long long long long long long long long long long long long long long message!") + sizer.Add((20,20)) + sizer.Add(text) + + # Same thing, but this time to demonstrate how the help event can be + # intercepted. + text = wx.TextCtrl(self, -1, "You can also intercept the help event if you like. Watch the log window when you click here...", + size=(240, 60), style = wx.TE_MULTILINE) + text.SetHelpText("Yet another context help message.") + sizer.Add((20,20)) + sizer.Add(text) + text.Bind(wx.EVT_HELP, self.OnCtxHelp, text) + + text = wx.TextCtrl(self, -1, "This one displays the tip itself...", + size=(240, 60), style = wx.TE_MULTILINE) + sizer.Add((20,20)) + sizer.Add(text) + text.Bind(wx.EVT_HELP, self.OnCtxHelp2, text) + + + border = wx.BoxSizer(wx.VERTICAL) + border.Add(sizer, 0, wx.ALL, 25) + + self.SetAutoLayout(True) + self.SetSizer(border) + self.Layout() + + + # On the second text control above, we intercept the help event. This is where + # we process it. Anything could happen here. In this case we're just printing + # some stuff about it, then passing it on, at which point we see the help tip. + def OnCtxHelp(self, evt): + self.log.write("OnCtxHelp: %s" % evt) + evt.Skip() + + # On the third text control above, we intercept the help event. + # Here, we print a note about it, generate our own tip window, and, + # unlike last time, we don't pass it on to the underlying provider. + def OnCtxHelp2(self, evt): + self.log.write("OnCtxHelp2: %s\n" % evt) + tip = wx.TipWindow(self, "This is a wx.TipWindow") + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#---------------------------------------------------------------------- + + +overview = """ +This demo shows how to incorporate Context Sensitive +help into your application using the wx.SimpleHelpProvider class. + +""" + +#---------------------------------------------------------------------- + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Cursor.py b/demo/Cursor.py new file mode 100644 index 00000000..ade91686 --- /dev/null +++ b/demo/Cursor.py @@ -0,0 +1,139 @@ + +import wx +import images + +#---------------------------------------------------------------------- + +CUSTOMID = 1111 + +cursors = { + "wx.CURSOR_ARROW" : wx.CURSOR_ARROW, + "wx.CURSOR_RIGHT_ARROW" : wx.CURSOR_RIGHT_ARROW, + "wx.CURSOR_BULLSEYE" : wx.CURSOR_BULLSEYE, + "wx.CURSOR_CHAR" : wx.CURSOR_CHAR, + "wx.CURSOR_CROSS" : wx.CURSOR_CROSS, + "wx.CURSOR_HAND" : wx.CURSOR_HAND, + "wx.CURSOR_IBEAM" : wx.CURSOR_IBEAM, + "wx.CURSOR_LEFT_BUTTON" : wx.CURSOR_LEFT_BUTTON, + "wx.CURSOR_MAGNIFIER" : wx.CURSOR_MAGNIFIER, + "wx.CURSOR_MIDDLE_BUTTON" : wx.CURSOR_MIDDLE_BUTTON, + "wx.CURSOR_NO_ENTRY" : wx.CURSOR_NO_ENTRY, + "wx.CURSOR_PAINT_BRUSH" : wx.CURSOR_PAINT_BRUSH, + "wx.CURSOR_PENCIL" : wx.CURSOR_PENCIL, + "wx.CURSOR_POINT_LEFT" : wx.CURSOR_POINT_LEFT, + "wx.CURSOR_POINT_RIGHT" : wx.CURSOR_POINT_RIGHT, + "wx.CURSOR_QUESTION_ARROW" : wx.CURSOR_QUESTION_ARROW, + "wx.CURSOR_RIGHT_BUTTON" : wx.CURSOR_RIGHT_BUTTON, + "wx.CURSOR_SIZENESW" : wx.CURSOR_SIZENESW, + "wx.CURSOR_SIZENS" : wx.CURSOR_SIZENS, + "wx.CURSOR_SIZENWSE" : wx.CURSOR_SIZENWSE, + "wx.CURSOR_SIZEWE" : wx.CURSOR_SIZEWE, + "wx.CURSOR_SIZING" : wx.CURSOR_SIZING, + "wx.CURSOR_SPRAYCAN" : wx.CURSOR_SPRAYCAN, + "wx.CURSOR_WAIT" : wx.CURSOR_WAIT, + "wx.CURSOR_WATCH" : wx.CURSOR_WATCH, + "wx.CURSOR_BLANK" : wx.CURSOR_BLANK, + "wx.CURSOR_DEFAULT" : wx.CURSOR_DEFAULT, + "wx.CURSOR_COPY_ARROW" : wx.CURSOR_COPY_ARROW, + "wx.CURSOR_ARROWWAIT" : wx.CURSOR_ARROWWAIT, + + "zz [custom cursor]" : CUSTOMID, +} + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + # create a list of choices from the dictionary above + choices = cursors.keys() + choices.sort() + + # create the controls + self.cb = wx.ComboBox(self, -1, "wx.CURSOR_DEFAULT", choices=choices, + style=wx.CB_READONLY) + self.tx = wx.StaticText(self, -1, + "This sample allows you to see all the stock cursors \n" + "available to wxPython. Simply select a name from the \n" + "wx.Choice and then move the mouse into the window \n" + "below to see the cursor. NOTE: not all stock cursors \n" + "have a specific representaion on all platforms.") + + self.win = wx.Window(self, -1, size=(200,200), style=wx.SIMPLE_BORDER) + self.win.SetBackgroundColour("white") + + # bind an event or two + self.Bind(wx.EVT_COMBOBOX, self.OnChooseCursor, self.cb) + self.win.Bind(wx.EVT_LEFT_DOWN, self.OnDrawDot) + + + # Setup the layout + gbs = wx.GridBagSizer() + gbs.Add(self.cb, (2,1)) + gbs.Add(self.tx, (2,3)) + gbs.Add(self.win, (5,0), (1, 6), wx.ALIGN_CENTER) + self.SetSizer(gbs) + + + def OnChooseCursor(self, evt): + # clear the dots + self.win.Refresh() + + choice = self.cb.GetStringSelection() + self.log.write("Selecting the %s cursor\n" % choice) + + cnum = cursors[choice] + + if cnum == CUSTOMID: + image = images.Pointy.GetImage() + + # since this image didn't come from a .cur file, tell it where the hotspot is + image.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_X, 1) + image.SetOptionInt(wx.IMAGE_OPTION_CUR_HOTSPOT_Y, 1) + + # make the image into a cursor + cursor = wx.CursorFromImage(image) + + else: + # create one of the stock (built-in) cursors + cursor = wx.StockCursor(cnum) + + # set the cursor for the window + self.win.SetCursor(cursor) + + + def OnDrawDot(self, evt): + # Draw a dot so the user can see where the hotspot is + dc = wx.ClientDC(self.win) + dc.SetPen(wx.Pen("RED")) + dc.SetBrush(wx.Brush("RED")) + pos = evt.GetPosition() + dc.DrawCircle(pos.x, pos.y, 4) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.Cursor

+ +This demo shows the stock mouse cursors that are available to wxPython. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/CustomDragAndDrop.py b/demo/CustomDragAndDrop.py new file mode 100644 index 00000000..42fd4006 --- /dev/null +++ b/demo/CustomDragAndDrop.py @@ -0,0 +1,347 @@ + +import cPickle +import wx + +#---------------------------------------------------------------------- + + +class DoodlePad(wx.Window): + def __init__(self, parent, log): + wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER) + self.log = log + self.SetBackgroundColour(wx.WHITE) + self.lines = [] + self.x = self.y = 0 + self.SetMode("Draw") + + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) + self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) + self.Bind(wx.EVT_MOTION, self.OnMotion) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def SetMode(self, mode): + self.mode = mode + if self.mode == "Draw": + self.SetCursor(wx.StockCursor(wx.CURSOR_PENCIL)) + else: + self.SetCursor(wx.STANDARD_CURSOR) + + + def OnPaint(self, event): + dc = wx.PaintDC(self) + self.DrawSavedLines(dc) + + def DrawSavedLines(self, dc): + dc.BeginDrawing() + dc.SetPen(wx.Pen(wx.BLUE, 3)) + for line in self.lines: + for coords in line: + dc.DrawLine(*coords) + dc.EndDrawing() + + + def OnLeftDown(self, event): + if self.mode == "Drag": + self.StartDragOpperation() + elif self.mode == "Draw": + self.curLine = [] + self.x, self.y = event.GetPositionTuple() + self.CaptureMouse() + else: + wx.Bell() + self.log.write("unknown mode!\n") + + + def OnLeftUp(self, event): + if self.HasCapture(): + self.lines.append(self.curLine) + self.curLine = [] + self.ReleaseMouse() + + def OnRightUp(self, event): + self.lines = [] + self.Refresh() + + def OnMotion(self, event): + if self.HasCapture() and event.Dragging() and not self.mode == "Drag": + dc = wx.ClientDC(self) + dc.BeginDrawing() + dc.SetPen(wx.Pen(wx.BLUE, 3)) + coords = (self.x, self.y) + event.GetPositionTuple() + self.curLine.append(coords) + dc.DrawLine(*coords) + self.x, self.y = event.GetPositionTuple() + dc.EndDrawing() + + + def StartDragOpperation(self): + # pickle the lines list + linesdata = cPickle.dumps(self.lines, 1) + + # create our own data format and use it in a + # custom data object + ldata = wx.CustomDataObject("DoodleLines") + ldata.SetData(linesdata) + + # Also create a Bitmap version of the drawing + size = self.GetSize() + bmp = wx.EmptyBitmap(size.width, size.height) + dc = wx.MemoryDC() + dc.SelectObject(bmp) + dc.SetBackground(wx.WHITE_BRUSH) + dc.Clear() + self.DrawSavedLines(dc) + dc.SelectObject(wx.NullBitmap) + + # Now make a data object for the bitmap and also a composite + # data object holding both of the others. + bdata = wx.BitmapDataObject(bmp) + data = wx.DataObjectComposite() + data.Add(ldata) + data.Add(bdata) + + # And finally, create the drop source and begin the drag + # and drop opperation + dropSource = wx.DropSource(self) + dropSource.SetData(data) + self.log.WriteText("Begining DragDrop\n") + result = dropSource.DoDragDrop(wx.Drag_AllowMove) + self.log.WriteText("DragDrop completed: %d\n" % result) + + if result == wx.DragMove: + self.lines = [] + self.Refresh() + + +#---------------------------------------------------------------------- + + +class DoodleDropTarget(wx.DropTarget): + def __init__(self, window, log): + wx.DropTarget.__init__(self) + self.log = log + self.dv = window + + # specify the type of data we will accept + self.data = wx.CustomDataObject("DoodleLines") + self.SetDataObject(self.data) + + + # some virtual methods that track the progress of the drag + def OnEnter(self, x, y, d): + self.log.WriteText("OnEnter: %d, %d, %d\n" % (x, y, d)) + return d + + def OnLeave(self): + self.log.WriteText("OnLeave\n") + + def OnDrop(self, x, y): + self.log.WriteText("OnDrop: %d %d\n" % (x, y)) + return True + + def OnDragOver(self, x, y, d): + #self.log.WriteText("OnDragOver: %d, %d, %d\n" % (x, y, d)) + + # The value returned here tells the source what kind of visual + # feedback to give. For example, if wxDragCopy is returned then + # only the copy cursor will be shown, even if the source allows + # moves. You can use the passed in (x,y) to determine what kind + # of feedback to give. In this case we return the suggested value + # which is based on whether the Ctrl key is pressed. + return d + + + + # Called when OnDrop returns True. We need to get the data and + # do something with it. + def OnData(self, x, y, d): + self.log.WriteText("OnData: %d, %d, %d\n" % (x, y, d)) + + # copy the data from the drag source to our data object + if self.GetData(): + # convert it back to a list of lines and give it to the viewer + linesdata = self.data.GetData() + lines = cPickle.loads(linesdata) + self.dv.SetLines(lines) + + # what is returned signals the source what to do + # with the original data (move, copy, etc.) In this + # case we just return the suggested value given to us. + return d + + + +class DoodleViewer(wx.Window): + def __init__(self, parent, log): + wx.Window.__init__(self, parent, -1, style=wx.SUNKEN_BORDER) + self.log = log + self.SetBackgroundColour(wx.WHITE) + self.lines = [] + self.x = self.y = 0 + dt = DoodleDropTarget(self, log) + self.SetDropTarget(dt) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def SetLines(self, lines): + self.lines = lines + self.Refresh() + + def OnPaint(self, event): + dc = wx.PaintDC(self) + self.DrawSavedLines(dc) + + def DrawSavedLines(self, dc): + dc.BeginDrawing() + dc.SetPen(wx.Pen(wx.RED, 3)) + + for line in self.lines: + for coords in line: + dc.DrawLine(*coords) + dc.EndDrawing() + +#---------------------------------------------------------------------- + +class CustomDnDPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + + self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + + # Make the controls + text1 = wx.StaticText(self, -1, + "Draw a little picture in this window\n" + "then switch the mode below and drag the\n" + "picture to the lower window or to another\n" + "application that accepts Bitmaps as a\n" + "drop target.\n" + ) + + rb1 = wx.RadioButton(self, -1, "Draw", style=wx.RB_GROUP) + rb1.SetValue(True) + rb2 = wx.RadioButton(self, -1, "Drag") + rb2.SetValue(False) + + text2 = wx.StaticText(self, -1, + "The lower window is accepting a\n" + "custom data type that is a pickled\n" + "Python list of lines data.") + + self.pad = DoodlePad(self, log) + view = DoodleViewer(self, log) + + # put them in sizers + sizer = wx.BoxSizer(wx.HORIZONTAL) + box = wx.BoxSizer(wx.VERTICAL) + rbox = wx.BoxSizer(wx.HORIZONTAL) + + rbox.Add(rb1) + rbox.Add(rb2) + box.Add(text1, 0, wx.ALL, 10) + box.Add(rbox, 0, wx.ALIGN_CENTER) + box.Add((10,90)) + box.Add(text2, 0, wx.ALL, 10) + + sizer.Add(box) + + dndsizer = wx.BoxSizer(wx.VERTICAL) + dndsizer.Add(self.pad, 1, wx.EXPAND|wx.ALL, 5) + dndsizer.Add(view, 1, wx.EXPAND|wx.ALL, 5) + + sizer.Add(dndsizer, 1, wx.EXPAND) + + self.SetAutoLayout(True) + self.SetSizer(sizer) + + # Events + self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton, rb1) + self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton, rb2) + + + def OnRadioButton(self, evt): + rb = self.FindWindowById(evt.GetId()) + self.pad.SetMode(rb.GetLabel()) + + +#---------------------------------------------------------------------- +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + + self.SetAutoLayout(True) + sizer = wx.BoxSizer(wx.VERTICAL) + + msg = "Custom Drag-And-Drop" + text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE) + text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + text.SetLabel(msg) + w,h = text.GetTextExtent(msg) + text.SetSize(wx.Size(w,h+1)) + text.SetForegroundColour(wx.BLUE) + sizer.Add(text, 0, wx.EXPAND|wx.ALL, 5) + sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) + + sizer.Add(CustomDnDPanel(self, log), 1, wx.EXPAND) + + self.SetSizer(sizer) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + #win = TestPanel(nb, log) + win = CustomDnDPanel(nb, log) + return win + + +if __name__ == '__main__': + import sys + + class DummyLog: + def WriteText(self, text): + sys.stdout.write(text) + + class TestApp(wx.App): + def OnInit(self): + self.MakeFrame() + return True + + def MakeFrame(self, event=None): + frame = wx.Frame(None, -1, "Custom Drag and Drop", size=(550,400)) + menu = wx.Menu() + item = menu.Append(-1, "Window") + mb = wx.MenuBar() + mb.Append(menu, "New") + frame.SetMenuBar(mb) + frame.Bind(wx.EVT_MENU, self.MakeFrame, item) + panel = TestPanel(frame, DummyLog()) + frame.Show(True) + self.SetTopWindow(frame) + + #---------------------------------------------------------------------- + + app = TestApp(0) + app.MainLoop() + +#---------------------------------------------------------------------- + + +overview = """ +This demo shows Drag and Drop using a custom data type and a custom +data object. A type called "DoodleLines" is created and a Python +Pickle of a list is actually transfered in the drag and drop +opperation. + +A second data object is also created containing a bitmap of the image +and is made available to any drop target that accepts bitmaps, such as +MS Word. + +The two data objects are combined in a wx.DataObjectComposite and the +rest is handled by the framework. + +""" + diff --git a/demo/DVC_CustomRenderer.py b/demo/DVC_CustomRenderer.py new file mode 100644 index 00000000..4a65a2ec --- /dev/null +++ b/demo/DVC_CustomRenderer.py @@ -0,0 +1,180 @@ + +import wx +import wx.dataview as dv + +#---------------------------------------------------------------------- + +class MyCustomRenderer(dv.PyDataViewCustomRenderer): + def __init__(self, log, *args, **kw): + dv.PyDataViewCustomRenderer.__init__(self, *args, **kw) + self.log = log + self.value = None + + + def SetValue(self, value): + #self.log.write('SetValue: %s' % value) + self.value = value + return True + + def GetValue(self): + #self.log.write('GetValue') + return self.value + + def GetSize(self): + # Return the size needed to display the value. The renderer + # has a helper function we can use for measuring text that is + # aware of any custom attributes that may have been set for + # this item. + return self.GetTextExtent(self.value) + + + def Render(self, rect, dc, state): + if state != 0: + self.log.write('Render: %s, %d' % (rect, state)) + + if not state & dv.DATAVIEW_CELL_SELECTED: + # we'll draw a shaded background to see if the rect correctly + # fills the cell + dc.SetBrush(wx.Brush('light grey')) + dc.SetPen(wx.TRANSPARENT_PEN) + rect.Deflate(1, 1) + dc.DrawRoundedRectangleRect(rect, 2) + + # And then finish up with this helper function that draws the + # text for us, dealing with alignment, font and color + # attributes, etc + self.RenderText(self.value, + 4, # x-offset, to compensate for the rounded rectangles + rect, + dc, + state # wxDataViewCellRenderState flags + ) + + + # The HasEditorCtrl, CreateEditorCtrl and GetValueFromEditorCtrl + # methods need to be implemented if this renderer is going to + # support in-place editing of the cell value, otherwise they can + # be omitted. + + def HasEditorCtrl(self): + self.log.write('HasEditorCtrl') + return True + + + def CreateEditorCtrl(self, parent, labelRect, value): + self.log.write('CreateEditorCtrl: %s' % labelRect) + ctrl = wx.TextCtrl(parent, + value=value, + pos=labelRect.Position, + size=labelRect.Size) + + # select the text and put the caret at the end + ctrl.SetInsertionPointEnd() + ctrl.SelectAll() + + return ctrl + + + def GetValueFromEditorCtrl(self, editor): + self.log.write('GetValueFromEditorCtrl: %s' % editor) + value = editor.GetValue() + return value + + + # The LeftClick and Activate methods serve as notifications + # letting you know that the user has either clicked or + # double-clicked on an item. Implementing them in your renderer + # is optional. + + def LeftClick(self, pos, cellRect, model, item, col): + self.log.write('LeftClick') + return False + + + def Activate(self, cellRect, model, item, col): + self.log.write('Activate') + return False + + +#---------------------------------------------------------------------- + +# To help focus this sammple on the custom renderer, we'll reuse the +# model class from another sample. +from DVC_IndexListModel import TestModel + + + +class TestPanel(wx.Panel): + def __init__(self, parent, log, model=None, data=None): + self.log = log + wx.Panel.__init__(self, parent, -1) + + # Create a dataview control + self.dvc = dv.DataViewCtrl(self, + style=wx.BORDER_THEME + | dv.DV_ROW_LINES + #| dv.DV_HORIZ_RULES + | dv.DV_VERT_RULES + | dv.DV_MULTIPLE + ) + + # Create an instance of the model + if model is None: + self.model = TestModel(data, log) + else: + self.model = model + self.dvc.AssociateModel(self.model) + + # Now we create some columns. + c0 = self.dvc.AppendTextColumn("Id", 0, width=40) + c0.Alignment = wx.ALIGN_RIGHT + c0.MinWidth = 40 + + # We'll use our custom renderer for these columns + for title, col, width in [ ('Artist', 1, 170), + ('Title', 2, 260), + ('Genre', 3, 80)]: + renderer = MyCustomRenderer(self.log, mode=dv.DATAVIEW_CELL_EDITABLE) + #renderer.SetMode(dv.DATAVIEW_CELL_EDITABLE) + column = dv.DataViewColumn(title, renderer, col, width=width) + column.Alignment = wx.ALIGN_LEFT + self.dvc.AppendColumn(column) + + self.Sizer = wx.BoxSizer(wx.VERTICAL) + self.Sizer.Add(self.dvc, 1, wx.EXPAND) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + # Get the data from the ListCtrl sample to play with, converting it + # from a dictionary to a list of lists, including the dictionary key + # as the first element of each sublist. + import ListCtrl + musicdata = ListCtrl.musicdata.items() + musicdata.sort() + musicdata = [[str(k)] + list(v) for k,v in musicdata] + + win = TestPanel(nb, log, data=musicdata) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

DemoName

+ +Say something nice here + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DVC_DataViewModel.py b/demo/DVC_DataViewModel.py new file mode 100644 index 00000000..b832f512 --- /dev/null +++ b/demo/DVC_DataViewModel.py @@ -0,0 +1,353 @@ + +import wx +import wx.dataview as dv +import images + +import random + +#---------------------------------------------------------------------- + +def makeBlank(self): + # Just a little helper function to make an empty image for our + # model to use. + empty = wx.EmptyBitmap(16,16,32) + dc = wx.MemoryDC(empty) + dc.SetBackground(wx.Brush((0,0,0,0))) + dc.Clear() + del dc + return empty + +#---------------------------------------------------------------------- +# We'll use instaces of these classes to hold our music data. Items in the +# tree will get associated back to the coresponding Song or Genre object. + +class Song(object): + def __init__(self, id, artist, title, genre): + self.id = id + self.artist = artist + self.title = title + self.genre = genre + self.like = False + # get a random date value + d = random.choice(range(27))+1 + m = random.choice(range(12)) + y = random.choice(range(1980, 2005)) + self.date = wx.DateTimeFromDMY(d,m,y) + + def __repr__(self): + return 'Song: %s-%s' % (self.artist, self.title) + + +class Genre(object): + def __init__(self, name): + self.name = name + self.songs = [] + + def __repr__(self): + return 'Genre: ' + self.name + +#---------------------------------------------------------------------- + +# This model acts as a bridge between the DataViewCtrl and the music data, and +# organizes it hierarchically as a collection of Genres, each of which is a +# collection of songs. We derive the class from PyDataViewModel, which knows +# how to reflect the C++ virtual methods to the Python methods in the derived +# class. + +# This model provides these data columns: +# +# 0. Genre: string +# 1. Artist: string +# 2. Title: string +# 3. id: integer +# 4. Aquired: date +# 5. Liked: bool +# + +class MyTreeListModel(dv.PyDataViewModel): + def __init__(self, data, log): + dv.PyDataViewModel.__init__(self) + self.data = data + self.log = log + + # The objmapper is an instance of DataViewItemObjectMapper and is used + # to help associate Python objects with DataViewItem objects. Normally + # a dictionary is used so any Python object can be used as data nodes. + # If the data nodes are weak-referencable then the objmapper can use a + # WeakValueDictionary instead. Each PyDataViewModel automagically has + # an instance of DataViewItemObjectMapper preassigned. This + # self.objmapper is used by the self.ObjectToItem and + # self.ItemToObject methods used below. + self.objmapper.UseWeakRefs(True) + + + # Report how many columns this model provides data for. + def GetColumnCount(self): + return 6 + + # Map the data column numbers to the data type + def GetColumnType(self, col): + mapper = { 0 : 'string', + 1 : 'string', + 2 : 'string', + 3.: 'string', # the real value is an int, but the renderer should convert it okay + 4 : 'datetime', + 5 : 'bool', + } + return mapper[col] + + + def GetChildren(self, parent, children): + # The view calls this method to find the children of any node in the + # control. There is an implicit hidden root node, and the top level + # item(s) should be reported as children of this node. A List view + # simply provides all items as children of this hidden root. A Tree + # view adds additional items as children of the other items, as needed, + # to provide the tree hierachy. + ##self.log.write("GetChildren\n") + + # If the parent item is invalid then it represents the hidden root + # item, so we'll use the genre objects as its children and they will + # end up being the collection of visible roots in our tree. + if not parent: + for genre in self.data: + children.append(self.ObjectToItem(genre)) + return len(self.data) + + # Otherwise we'll fetch the python object associated with the parent + # item and make DV items for each of it's child objects. + node = self.ItemToObject(parent) + if isinstance(node, Genre): + for song in node.songs: + children.append(self.ObjectToItem(song)) + return len(node.songs) + return 0 + + + def IsContainer(self, item): + # Return True if the item has children, False otherwise. + ##self.log.write("IsContainer\n") + + # The hidden root is a container + if not item: + return True + # and in this model the genre objects are containers + node = self.ItemToObject(item) + if isinstance(node, Genre): + return True + # but everything else (the song objects) are not + return False + + + #def HasContainerColumns(self, item): + # self.log.write('HasContainerColumns\n') + # return True + + + def GetParent(self, item): + # Return the item which is this item's parent. + ##self.log.write("GetParent\n") + + if not item: + return dv.NullDataViewItem + + node = self.ItemToObject(item) + if isinstance(node, Genre): + return dv.NullDataViewItem + elif isinstance(node, Song): + for g in self.data: + if g.name == node.genre: + return self.ObjectToItem(g) + + + def GetValue(self, item, col): + # Return the value to be displayed for this item and column. For this + # example we'll just pull the values from the data objects we + # associated with the items in GetChildren. + + # Fetch the data object for this item. + node = self.ItemToObject(item) + + if isinstance(node, Genre): + # We'll only use the first column for the Genre objects, + # for the other columns lets just return empty values + mapper = { 0 : node.name, + 1 : "", + 2 : "", + 3 : "", + 4 : wx.DateTimeFromTimeT(0), # TODO: There should be some way to indicate a null value... + 5 : False, + } + return mapper[col] + + + elif isinstance(node, Song): + mapper = { 0 : node.genre, + 1 : node.artist, + 2 : node.title, + 3 : node.id, + 4 : node.date, + 5 : node.like, + } + return mapper[col] + + else: + raise RuntimeError("unknown node type") + + + + def GetAttr(self, item, col, attr): + ##self.log.write('GetAttr') + node = self.ItemToObject(item) + if isinstance(node, Genre): + attr.SetColour('blue') + attr.SetBold(True) + return True + return False + + + def SetValue(self, value, item, col): + self.log.write("SetValue: %s\n" % value) + + # We're not allowing edits in column zero (see below) so we just need + # to deal with Song objects and cols 1 - 5 + + node = self.ItemToObject(item) + if isinstance(node, Song): + if col == 1: + node.artist = value + elif col == 2: + node.title = value + elif col == 3: + node.id = value + elif col == 4: + node.date = value + elif col == 5: + node.like = value + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log, data=None, model=None): + self.log = log + wx.Panel.__init__(self, parent, -1) + + # Create a dataview control + self.dvc = dv.DataViewCtrl(self, + style=wx.BORDER_THEME + | dv.DV_ROW_LINES # nice alternating bg colors + #| dv.DV_HORIZ_RULES + | dv.DV_VERT_RULES + | dv.DV_MULTIPLE + ) + + # Create an instance of our model... + if model is None: + self.model = MyTreeListModel(data, log) + else: + self.model = model + + # Tel the DVC to use the model + self.dvc.AssociateModel(self.model) + + # Define the columns that we want in the view. Notice the + # parameter which tells the view which col in the data model to pull + # values from for each view column. + if 1: + self.tr = tr = dv.DataViewTextRenderer() + c0 = dv.DataViewColumn("Genre", # title + tr, # renderer + 0, # data model column + width=80) + self.dvc.AppendColumn(c0) + else: + self.dvc.AppendTextColumn("Genre", 0, width=80) + + c1 = self.dvc.AppendTextColumn("Artist", 1, width=170, mode=dv.DATAVIEW_CELL_EDITABLE) + c2 = self.dvc.AppendTextColumn("Title", 2, width=260, mode=dv.DATAVIEW_CELL_EDITABLE) + c3 = self.dvc.AppendDateColumn('Acquired', 4, width=100, mode=dv.DATAVIEW_CELL_ACTIVATABLE) + c4 = self.dvc.AppendToggleColumn('Like', 5, width=40, mode=dv.DATAVIEW_CELL_ACTIVATABLE) + + # Notice how we pull the data from col 3, but this is the 6th col + # added to the DVC. The order of the view columns is not dependent on + # the order of the model columns at all. + c5 = self.dvc.AppendTextColumn("id", 3, width=40, mode=dv.DATAVIEW_CELL_EDITABLE) + c5.Alignment = wx.ALIGN_RIGHT + + # Set some additional attributes for all the columns + for c in self.dvc.Columns: + c.Sortable = True + c.Reorderable = True + + + self.Sizer = wx.BoxSizer(wx.VERTICAL) + self.Sizer.Add(self.dvc, 1, wx.EXPAND) + + b1 = wx.Button(self, label="New View", name="newView") + self.Bind(wx.EVT_BUTTON, self.OnNewView, b1) + + self.Sizer.Add(b1, 0, wx.ALL, 5) + + + def OnNewView(self, evt): + f = wx.Frame(None, title="New view, shared model", size=(600,400)) + TestPanel(f, self.log, model=self.model) + b = f.FindWindowByName("newView") + b.Disable() + f.Show() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + # Reuse the music data in the ListCtrl sample, and put it in a + # hierarchical structure so we can show it as a tree + import ListCtrl + musicdata = ListCtrl.musicdata.items() + musicdata.sort() + + ## For testing Unicode + #musicdata = { + # 1 : (u'BE \u662f', u'Python \u662f\u6700\u597d\u7684\u7de8\u7a0b\u8a9e\u8a00\uff01', u"Rock \u662f"), + #} + #musicdata = musicdata.items() + + # our data structure will be a collection of Genres, each of which is a + # collection of Songs + data = dict() + for key, val in musicdata: + song = Song(str(key), val[0], val[1], val[2]) + genre = data.get(song.genre) + if genre is None: + genre = Genre(song.genre) + data[song.genre] = genre + genre.songs.append(song) + data = data.values() + + # Finally create the test window + win = TestPanel(nb, log, data=data) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

DataViewCtrl with custom DataViewModel

+ +This sample shows how to derive a class from PyDataViewModel, implement a set +of hierarchical data objects and use the DataViewControl to view and +manipulate them. + +

See the comments in the source for lots of details. + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DVC_IndexListModel.py b/demo/DVC_IndexListModel.py new file mode 100644 index 00000000..cedc022e --- /dev/null +++ b/demo/DVC_IndexListModel.py @@ -0,0 +1,253 @@ + +import wx +import wx.dataview as dv + +#---------------------------------------------------------------------- + +# This model class provides the data to the view when it is asked for. +# Since it is a list-only model (no hierachical data) then it is able +# to be referenced by row rather than by item object, so in this way +# it is easier to comprehend and use than other model types. In this +# example we also provide a Compare function to assist with sorting of +# items in our model. Notice that the data items in the data model +# object don't ever change position due to a sort or column +# reordering. The view manages all of that and maps view rows and +# columns to the model's rows and columns as needed. +# +# For this example our data is stored in a simple list of lists. In +# real life you can use whatever you want or need to hold your data. + +class TestModel(dv.PyDataViewIndexListModel): + def __init__(self, data, log): + dv.PyDataViewIndexListModel.__init__(self, len(data)) + self.data = data + self.log = log + + # All of our columns are strings. If the model or the renderers + # in the view are other types then that should be reflected here. + def GetColumnType(self, col): + return "string" + + # This method is called to provide the data object for a + # particular row,col + def GetValueByRow(self, row, col): + return self.data[row][col] + + # This method is called when the user edits a data item in the view. + def SetValueByRow(self, value, row, col): + self.log.write("SetValue: (%d,%d) %s\n" % (row, col, value)) + self.data[row][col] = value + + # Report how many columns this model provides data for. + def GetColumnCount(self): + return len(self.data[0]) + + # Report the number of rows in the model + def GetCount(self): + #self.log.write('GetCount') + return len(self.data) + + # Called to check if non-standard attributes should be used in the + # cell at (row, col) + def GetAttrByRow(self, row, col, attr): + ##self.log.write('GetAttrByRow: (%d, %d)' % (row, col)) + if col == 3: + attr.SetColour('blue') + attr.SetBold(True) + return True + return False + + + # This is called to assist with sorting the data in the view. The + # first two args are instances of the DataViewItem class, so we + # need to convert them to row numbers with the GetRow method. + # Then it's just a matter of fetching the right values from our + # data set and comparing them. The return value is -1, 0, or 1, + # just like Python's cmp() function. + def Compare(self, item1, item2, col, ascending): + if not ascending: # swap sort order? + item2, item1 = item1, item2 + row1 = self.GetRow(item1) + row2 = self.GetRow(item2) + if col == 0: + return cmp(int(self.data[row1][col]), int(self.data[row2][col])) + else: + return cmp(self.data[row1][col], self.data[row2][col]) + + + def DeleteRows(self, rows): + # make a copy since we'll be sorting(mutating) the list + rows = list(rows) + # use reverse order so the indexes don't change as we remove items + rows.sort(reverse=True) + + for row in rows: + # remove it from our data structure + del self.data[row] + # notify the view(s) using this model that it has been removed + self.RowDeleted(row) + + + def AddRow(self, value): + # update data structure + self.data.append(value) + # notify views + self.RowAppended() + + + +class TestPanel(wx.Panel): + def __init__(self, parent, log, model=None, data=None): + self.log = log + wx.Panel.__init__(self, parent, -1) + + # Create a dataview control + self.dvc = dv.DataViewCtrl(self, + style=wx.BORDER_THEME + | dv.DV_ROW_LINES # nice alternating bg colors + #| dv.DV_HORIZ_RULES + | dv.DV_VERT_RULES + | dv.DV_MULTIPLE + ) + + # Create an instance of our simple model... + if model is None: + self.model = TestModel(data, log) + else: + self.model = model + + # ...and associate it with the dataview control. Models can + # be shared between multiple DataViewCtrls, so this does not + # assign ownership like many things in wx do. There is some + # internal reference counting happening so you don't really + # need to hold a reference to it either, but we do for this + # example so we can fiddle with the model from the widget + # inspector or whatever. + self.dvc.AssociateModel(self.model) + + # Now we create some columns. The second parameter is the + # column number within the model that the DataViewColumn will + # fetch the data from. This means that you can have views + # using the same model that show different columns of data, or + # that they can be in a different order than in the model. + self.dvc.AppendTextColumn("Artist", 1, width=170, mode=dv.DATAVIEW_CELL_EDITABLE) + self.dvc.AppendTextColumn("Title", 2, width=260, mode=dv.DATAVIEW_CELL_EDITABLE) + self.dvc.AppendTextColumn("Genre", 3, width=80, mode=dv.DATAVIEW_CELL_EDITABLE) + + # There are Prepend methods too, and also convenience methods + # for other data types but we are only using strings in this + # example. You can also create a DataViewColumn object + # yourself and then just use AppendColumn or PrependColumn. + c0 = self.dvc.PrependTextColumn("Id", 0, width=40) + + # The DataViewColumn object is returned from the Append and + # Prepend methods, and we can modify some of it's properties + # like this. + c0.Alignment = wx.ALIGN_RIGHT + c0.Renderer.Alignment = wx.ALIGN_RIGHT + c0.MinWidth = 40 + + # Through the magic of Python we can also access the columns + # as a list via the Columns property. Here we'll mark them + # all as sortable and reorderable. + for c in self.dvc.Columns: + c.Sortable = True + c.Reorderable = True + + # Let's change our minds and not let the first col be moved. + c0.Reorderable = False + + # set the Sizer property (same as SetSizer) + self.Sizer = wx.BoxSizer(wx.VERTICAL) + self.Sizer.Add(self.dvc, 1, wx.EXPAND) + + # Add some buttons to help out with the tests + b1 = wx.Button(self, label="New View", name="newView") + self.Bind(wx.EVT_BUTTON, self.OnNewView, b1) + b2 = wx.Button(self, label="Add Row") + self.Bind(wx.EVT_BUTTON, self.OnAddRow, b2) + b3 = wx.Button(self, label="Delete Row(s)") + self.Bind(wx.EVT_BUTTON, self.OnDeleteRows, b3) + + btnbox = wx.BoxSizer(wx.HORIZONTAL) + btnbox.Add(b1, 0, wx.LEFT|wx.RIGHT, 5) + btnbox.Add(b2, 0, wx.LEFT|wx.RIGHT, 5) + btnbox.Add(b3, 0, wx.LEFT|wx.RIGHT, 5) + self.Sizer.Add(btnbox, 0, wx.TOP|wx.BOTTOM, 5) + + # Bind some events so we can see what the DVC sends us + self.Bind(dv.EVT_DATAVIEW_ITEM_EDITING_DONE, self.OnEditingDone, self.dvc) + self.Bind(dv.EVT_DATAVIEW_ITEM_VALUE_CHANGED, self.OnValueChanged, self.dvc) + + + def OnNewView(self, evt): + f = wx.Frame(None, title="New view, shared model", size=(600,400)) + TestPanel(f, self.log, self.model) + b = f.FindWindowByName("newView") + b.Disable() + f.Show() + + + def OnDeleteRows(self, evt): + # Remove the selected row(s) from the model. The model will take care + # of notifying the view (and any other observers) that the change has + # happened. + items = self.dvc.GetSelections() + rows = [self.model.GetRow(item) for item in items] + self.model.DeleteRows(rows) + + + def OnAddRow(self, evt): + # Add some bogus data to a new row in the model's data + id = len(self.model.data) + 1 + value = [str(id), + 'new artist %d' % id, + 'new title %d' % id, + 'genre %d' % id] + self.model.AddRow(value) + + + def OnEditingDone(self, evt): + self.log.write("OnEditingDone\n") + + def OnValueChanged(self, evt): + self.log.write("OnValueChanged\n") + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + # Get the data from the ListCtrl sample to play with, converting it + # from a dictionary to a list of lists, including the dictionary key + # as the first element of each sublist. + import ListCtrl + musicdata = ListCtrl.musicdata.items() + musicdata.sort() + musicdata = [[str(k)] + list(v) for k,v in musicdata] + + win = TestPanel(nb, log, data=musicdata) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

DataViewCtrl with DataViewIndexListModel

+ +This sample shows how to derive a class from PyDataViewIndexListModel and use +it to interface with a list of data items. (This model does not have any +hierarchical relationships in the data.) + +

See the comments in the source for lots of details. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DVC_ListCtrl.py b/demo/DVC_ListCtrl.py new file mode 100644 index 00000000..626bfbe5 --- /dev/null +++ b/demo/DVC_ListCtrl.py @@ -0,0 +1,68 @@ + +import wx +import wx.dataview as dv + +#---------------------------------------------------------------------- + +# Reuse the music data in the ListCtrl sample +import ListCtrl +musicdata = ListCtrl.musicdata.items() +musicdata.sort() +musicdata = [[str(k)] + list(v) for k,v in musicdata] + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + # create the listctrl + self.dvlc = dvlc = dv.DataViewListCtrl(self) + + # Give it some columns. + # The ID col we'll customize a bit: + dvlc.AppendTextColumn('id', width=40) + dvlc.AppendTextColumn('artist', width=170) + dvlc.AppendTextColumn('title', width=260) + dvlc.AppendTextColumn('genre', width=80) + + # Load the data. Each item (row) is added as a sequence of values + # whose order matches the columns + for itemvalues in musicdata: + dvlc.AppendItem(itemvalues) + + # Set the layout so the listctrl fills the panel + self.Sizer = wx.BoxSizer() + self.Sizer.Add(dvlc, 1, wx.EXPAND) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

DataViewListCtrl

+ +The DataViewListCtrl class is much like the traditional wx.ListCtrl in report +mode, in that it stores all items itself and all access to the data is through +the list ctrl's API. However it is derived from DataViewCtrl and uses a model +class internally, so it also has many of the benefits of the data view classes +available as well. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DVC_TreeCtrl.py b/demo/DVC_TreeCtrl.py new file mode 100644 index 00000000..aab6c4bc --- /dev/null +++ b/demo/DVC_TreeCtrl.py @@ -0,0 +1,75 @@ + +import wx +import wx.dataview as dv + + +#---------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent) + + # create the treectrl + self.dvtc = dvtc = dv.DataViewTreeCtrl(self) + + isz = (16,16) + il = wx.ImageList(*isz) + fldridx = il.AddIcon(wx.ArtProvider.GetIcon(wx.ART_FOLDER, wx.ART_OTHER, isz)) + fldropenidx = il.AddIcon(wx.ArtProvider.GetIcon(wx.ART_FOLDER_OPEN, wx.ART_OTHER, isz)) + fileidx = il.AddIcon(wx.ArtProvider.GetIcon(wx.ART_NORMAL_FILE, wx.ART_OTHER, isz)) + dvtc.SetImageList(il) + + self.root = dvtc.AppendContainer(dv.NullDataViewItem, + "The Root Item", + fldridx, fldropenidx) + for x in range(15): + child = dvtc.AppendContainer(self.root, "Item %d" % x, + fldridx, fldropenidx) + + for y in range(5): + last = dvtc.AppendContainer( + child, "item %d-%s" % (x, chr(ord("a")+y)), + fldridx, fldropenidx) + + for z in range(5): + item = dvtc.AppendItem( + last, "item %d-%s-%d" % (x, chr(ord("a")+y), z), + fileidx) + + # Set the layout so the treectrl fills the panel + self.Sizer = wx.BoxSizer() + self.Sizer.Add(dvtc, 1, wx.EXPAND) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

DataViewTreeCtrl

+ +The DataViewTreeCtrl class is much like the traditional wx.TreeCtrl, +in that it stores all items itself and all access to the data is +through the tree ctrl's API. However it is derived from DataViewCtrl +and uses a model class internally, so it also has many of the benefits +of the data view classes available as well. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DatePickerCtrl.py b/demo/DatePickerCtrl.py new file mode 100644 index 00000000..a738af18 --- /dev/null +++ b/demo/DatePickerCtrl.py @@ -0,0 +1,64 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(sizer) + + dpc = wx.DatePickerCtrl(self, size=(120,-1), + style = wx.DP_DROPDOWN + | wx.DP_SHOWCENTURY + | wx.DP_ALLOWNONE ) + self.Bind(wx.EVT_DATE_CHANGED, self.OnDateChanged, dpc) + sizer.Add(dpc, 0, wx.ALL, 50) + + # In some cases the widget used above will be a native date + # picker, so show the generic one too. + dpc = wx.GenericDatePickerCtrl(self, size=(120,-1), + style = wx.TAB_TRAVERSAL + | wx.DP_DROPDOWN + | wx.DP_SHOWCENTURY + | wx.DP_ALLOWNONE ) + self.Bind(wx.EVT_DATE_CHANGED, self.OnDateChanged, dpc) + sizer.Add(dpc, 0, wx.LEFT, 50) + + + def OnDateChanged(self, evt): + self.log.write("OnDateChanged: %s\n" % evt.GetDate()) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.DatePickerCtrl

+ +This control allows the user to select a date. Unlike +wx.calendar.CalendarCtrl, which is a relatively big control, +wx.DatePickerCtrl is implemented as a small window showing the +currently selected date. The control can be edited using the keyboard, +and can also display a popup window for more user-friendly date +selection, depending on the styles used and the platform. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DelayedResult.py b/demo/DelayedResult.py new file mode 100644 index 00000000..f5631880 --- /dev/null +++ b/demo/DelayedResult.py @@ -0,0 +1,224 @@ +""" +This demonstrates a simple use of delayedresult: get/compute +something that takes a long time, without hanging the GUI while this +is taking place. + +The top button runs a small GUI that uses wx.lib.delayedresult.startWorker +to wrap a long-running function into a separate thread. Just click +Get, and move the slider, and click Get and Abort a few times, and +observe that GUI responds. The key functions to look for in the code +are startWorker() and __handleResult(). + +The second button runs the same GUI, but without delayedresult. Click +Get: now the get/compute is taking place in main thread, so the GUI +does not respond to user actions until worker function returns, it's +not even possible to Abort. +""" + +import wx +import wx.lib.delayedresult as delayedresult + + +class FrameSimpleDelayedBase(wx.Frame): + def __init__(self, *args, **kwds): + wx.Frame.__init__(self, *args, **kwds) + pnl = wx.Panel(self) + self.checkboxUseDelayed = wx.CheckBox(pnl, -1, "Using delayedresult") + self.buttonGet = wx.Button(pnl, -1, "Get") + self.buttonAbort = wx.Button(pnl, -1, "Abort") + self.slider = wx.Slider(pnl, -1, 0, 0, 10, size=(100,-1), + style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS) + self.textCtrlResult = wx.TextCtrl(pnl, -1, "", style=wx.TE_READONLY) + + self.checkboxUseDelayed.SetValue(1) + self.checkboxUseDelayed.Enable(False) + self.buttonAbort.Enable(False) + + vsizer = wx.BoxSizer(wx.VERTICAL) + hsizer = wx.BoxSizer(wx.HORIZONTAL) + vsizer.Add(self.checkboxUseDelayed, 0, wx.ALL, 10) + hsizer.Add(self.buttonGet, 0, wx.ALL, 5) + hsizer.Add(self.buttonAbort, 0, wx.ALL, 5) + hsizer.Add(self.slider, 0, wx.ALL, 5) + hsizer.Add(self.textCtrlResult, 0, wx.ALL, 5) + vsizer.Add(hsizer, 0, wx.ALL, 5) + pnl.SetSizer(vsizer) + vsizer.SetSizeHints(self) + + self.Bind(wx.EVT_BUTTON, self.handleGet, self.buttonGet) + self.Bind(wx.EVT_BUTTON, self.handleAbort, self.buttonAbort) + + + + +class FrameSimpleDelayed(FrameSimpleDelayedBase): + """This demos simplistic use of delayedresult module.""" + + def __init__(self, *args, **kwargs): + FrameSimpleDelayedBase.__init__(self, *args, **kwargs) + self.jobID = 0 + self.abortEvent = delayedresult.AbortEvent() + self.Bind(wx.EVT_CLOSE, self.handleClose) + + def setLog(self, log): + self.log = log + + def handleClose(self, event): + """Only needed because in demo, closing the window does not kill the + app, so worker thread continues and sends result to dead frame; normally + your app would exit so this would not happen.""" + if self.buttonAbort.IsEnabled(): + self.log( "Exiting: Aborting job %s" % self.jobID ) + self.abortEvent.set() + self.Destroy() + + def handleGet(self, event): + """Compute result in separate thread, doesn't affect GUI response.""" + self.buttonGet.Enable(False) + self.buttonAbort.Enable(True) + self.abortEvent.clear() + self.jobID += 1 + + self.log( "Starting job %s in producer thread: GUI remains responsive" + % self.jobID ) + delayedresult.startWorker(self._resultConsumer, self._resultProducer, + wargs=(self.jobID,self.abortEvent), jobID=self.jobID) + + + def _resultProducer(self, jobID, abortEvent): + """Pretend to be a complex worker function or something that takes + long time to run due to network access etc. GUI will freeze if this + method is not called in separate thread.""" + import time + count = 0 + while not abortEvent() and count < 50: + time.sleep(0.1) + count += 1 + return jobID + + + def handleAbort(self, event): + """Abort the result computation.""" + self.log( "Aborting result for job %s" % self.jobID ) + self.buttonGet.Enable(True) + self.buttonAbort.Enable(False) + self.abortEvent.set() + + + def _resultConsumer(self, delayedResult): + jobID = delayedResult.getJobID() + assert jobID == self.jobID + try: + result = delayedResult.get() + except Exception, exc: + self.log( "Result for job %s raised exception: %s" % (jobID, exc) ) + return + + # output result + self.log( "Got result for job %s: %s" % (jobID, result) ) + self.textCtrlResult.SetValue(str(result)) + + # get ready for next job: + self.buttonGet.Enable(True) + self.buttonAbort.Enable(False) + + +class FrameSimpleDirect(FrameSimpleDelayedBase): + """This does not use delayedresult so the GUI will freeze while + the GET is taking place.""" + + def __init__(self, *args, **kwargs): + self.jobID = 1 + FrameSimpleDelayedBase.__init__(self, *args, **kwargs) + self.checkboxUseDelayed.SetValue(False) + + def setLog(self, log): + self.log = log + + def handleGet(self, event): + """Use delayedresult, this will compute result in separate + thread, and will affect GUI response because a thread is not + used.""" + self.buttonGet.Enable(False) + self.buttonAbort.Enable(True) + + self.log( "Doing job %s without delayedresult (same as GUI thread): GUI hangs (for a while)" % self.jobID ) + result = self._resultProducer(self.jobID) + self._resultConsumer( result ) + + def _resultProducer(self, jobID): + """Pretend to be a complex worker function or something that takes + long time to run due to network access etc. GUI will freeze if this + method is not called in separate thread.""" + import time + time.sleep(5) + return jobID + + def handleAbort(self, event): + """can never be called""" + pass + + def _resultConsumer(self, result): + # output result + self.log( "Got result for job %s: %s" % (self.jobID, result) ) + self.textCtrlResult.SetValue(str(result)) + + # get ready for next job: + self.buttonGet.Enable(True) + self.buttonAbort.Enable(False) + self.jobID += 1 + + +#--------------------------------------------------------------------------- +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + vsizer = wx.BoxSizer(wx.VERTICAL) + b = wx.Button(self, -1, "Long-running function in separate thread") + vsizer.Add(b, 0, wx.ALL, 5) + self.Bind(wx.EVT_BUTTON, self.OnButton1, b) + + b = wx.Button(self, -1, "Long-running function in GUI thread") + vsizer.Add(b, 0, wx.ALL, 5) + self.Bind(wx.EVT_BUTTON, self.OnButton2, b) + + bdr = wx.BoxSizer() + bdr.Add(vsizer, 0, wx.ALL, 50) + self.SetSizer(bdr) + self.Layout() + + def OnButton1(self, evt): + frame = FrameSimpleDelayed(self, title="Long-running function in separate thread") + frame.setLog(self.log.WriteText) + frame.Show() + + def OnButton2(self, evt): + frame = FrameSimpleDirect(self, title="Long-running function in GUI thread") + frame.setLog(self.log.WriteText) + frame.Show() + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = __doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/Dialog.py b/demo/Dialog.py new file mode 100644 index 00000000..611eea54 --- /dev/null +++ b/demo/Dialog.py @@ -0,0 +1,173 @@ + +import wx + +#--------------------------------------------------------------------------- +# Create and set a help provider. Normally you would do this in +# the app's OnInit as it must be done before any SetHelpText calls. +provider = wx.SimpleHelpProvider() +wx.HelpProvider.Set(provider) + +#--------------------------------------------------------------------------- + +class TestDialog(wx.Dialog): + def __init__( + self, parent, ID, title, size=wx.DefaultSize, pos=wx.DefaultPosition, + style=wx.DEFAULT_DIALOG_STYLE, + ): + + # Instead of calling wx.Dialog.__init__ we precreate the dialog + # so we can set an extra style that must be set before + # creation, and then we create the GUI object using the Create + # method. + pre = wx.PreDialog() + pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP) + pre.Create(parent, ID, title, pos, size, style) + + # This next step is the most important, it turns this Python + # object into the real wrapper of the dialog (instead of pre) + # as far as the wxPython extension is concerned. + self.PostCreate(pre) + + # Now continue with the normal construction of the dialog + # contents + sizer = wx.BoxSizer(wx.VERTICAL) + + label = wx.StaticText(self, -1, "This is a wx.Dialog") + label.SetHelpText("This is the help text for the label") + sizer.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + box = wx.BoxSizer(wx.HORIZONTAL) + + label = wx.StaticText(self, -1, "Field #1:") + label.SetHelpText("This is the help text for the label") + box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + text = wx.TextCtrl(self, -1, "", size=(80,-1)) + text.SetHelpText("Here's some help text for field #1") + box.Add(text, 1, wx.ALIGN_CENTRE|wx.ALL, 5) + + sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + box = wx.BoxSizer(wx.HORIZONTAL) + + label = wx.StaticText(self, -1, "Field #2:") + label.SetHelpText("This is the help text for the label") + box.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + text = wx.TextCtrl(self, -1, "", size=(80,-1)) + text.SetHelpText("Here's some help text for field #2") + box.Add(text, 1, wx.ALIGN_CENTRE|wx.ALL, 5) + + sizer.Add(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL) + sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5) + + btnsizer = wx.StdDialogButtonSizer() + + if wx.Platform != "__WXMSW__": + btn = wx.ContextHelpButton(self) + btnsizer.AddButton(btn) + + btn = wx.Button(self, wx.ID_OK) + btn.SetHelpText("The OK button completes the dialog") + btn.SetDefault() + btnsizer.AddButton(btn) + + btn = wx.Button(self, wx.ID_CANCEL) + btn.SetHelpText("The Cancel button cancels the dialog. (Cool, huh?)") + btnsizer.AddButton(btn) + btnsizer.Realize() + + sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + + self.SetSizer(sizer) + sizer.Fit(self) + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a custom Dialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + b = wx.Button(self, -1, "Show dialog with ShowWindowModal", (50, 140)) + self.Bind(wx.EVT_BUTTON, self.OnShowWindowModal, b) + self.Bind(wx.EVT_WINDOW_MODAL_DIALOG_CLOSED, self.OnWindowModalDialogClosed) + + + def OnButton(self, evt): + dlg = TestDialog(self, -1, "Sample Dialog", size=(350, 200), + style=wx.DEFAULT_DIALOG_STYLE, + ) + dlg.CenterOnScreen() + + # this does not return until the dialog is closed. + val = dlg.ShowModal() + + if val == wx.ID_OK: + self.log.WriteText("You pressed OK\n") + else: + self.log.WriteText("You pressed Cancel\n") + + dlg.Destroy() + + + def OnShowWindowModal(self, evt): + dlg = TestDialog(self, -1, "Sample Dialog", size=(350, 200), + style=wx.DEFAULT_DIALOG_STYLE) + dlg.ShowWindowModal() + + + def OnWindowModalDialogClosed(self, evt): + dialog = evt.GetDialog() + val = evt.GetReturnCode() + try: + btnTxt = { wx.ID_OK : "OK", + wx.ID_CANCEL: "Cancel" }[val] + except KeyError: + btnTxt = '' + + wx.MessageBox("You closed the window-modal dialog with the %s button" % btnTxt) + + dialog.Destroy() + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = """\ +wxPython offers quite a few general purpose dialogs for useful data input from +the user; they are all based on the wx.Dialog class, which you can also subclass +to create custom dialogs to suit your needs. + +The Dialog class, in addition to dialog-like behaviors, also supports the full +wxWindows layout featureset, which means that you can incorporate sizers or +layout constraints as needed to achieve the look and feel desired. It even supports +context-sensitive help, which is illustrated in this example. + +The example is very simple; in real world situations, a dialog that had input +fields such as this would no doubt be required to deliver those values back to +the calling function. The Dialog class supports data retrieval in this manner. +However, the data must be retrieved prior to the dialog being destroyed. +The example shown here is modal; non-modal dialogs are possible as well. + +See the documentation for the Dialog class for more details. + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DialogUnits.py b/demo/DialogUnits.py new file mode 100644 index 00000000..975eb175 --- /dev/null +++ b/demo/DialogUnits.py @@ -0,0 +1,127 @@ +#!/usr/bin/env python +#---------------------------------------------------------------------------- +# Name: DialogUnits.py +# Purpose: A minimal wxPython program that is a bit smarter than test1. +# +# Author: Robin Dunn +# +# Created: A long time ago, in a galaxy far, far away... +# RCS-ID: $Id$ +# Copyright: (c) 1998 by Total Control Software +# Licence: wxWindows license +#---------------------------------------------------------------------------- +# + +import wx + +#--------------------------------------------------------------------------- + +# Create a new frame class, derived from the wxPython Frame. +class MyFrame(wx.Frame): + + def __init__(self, parent, id, title): + # First, call the base class' __init__ method to create the frame + wx.Frame.__init__(self, parent, id, title, (100, 100), (160, 100)) + + # Associate some events with methods of this class + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_MOVE, self.OnMove) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + # Add a panel and some controls to display the size and position + panel = wx.Panel(self, -1) + + wx.StaticText(panel, -1, "Size:", + wx.DLG_PNT(panel, (4, 4)), wx.DefaultSize + ) + + wx.StaticText(panel, -1, "Pos:", + wx.DLG_PNT(panel, (4, 16)), wx.DefaultSize + ) + + self.sizeCtrl = wx.TextCtrl(panel, -1, "", + wx.DLG_PNT(panel, (24, 4)), + wx.DLG_SZE(panel, (36, -1)), + wx.TE_READONLY) + + self.posCtrl = wx.TextCtrl(panel, -1, "", + wx.DLG_PNT(panel, (24, 16)), + wx.DLG_SZE(panel, (36, -1)), + wx.TE_READONLY) + + #print wx.DLG_PNT(panel, (24, 4)), wx.DLG_SZE(panel, (36, -1)) + #print wx.DLG_PNT(panel, (24, 16)),wx.DLG_SZE(panel, (36, -1)) + + # This method is called automatically when the CLOSE event is + # sent to this window + def OnCloseWindow(self, event): + # tell the window to kill itself + self.Destroy() + + # This method is called by the System when the window is resized, + # because of the association above. + def OnSize(self, event): + size = event.GetSize() + self.sizeCtrl.SetValue("%s, %s" % (size.width, size.height)) + + # tell the event system to continue looking for an event handler, + # so the default handler will get called. + event.Skip() + + # This method is called by the System when the window is moved, + # because of the association above. + def OnMove(self, event): + pos = event.GetPosition() + self.posCtrl.SetValue("%s, %s" % (pos.x, pos.y)) + + + +#--------------------------------------------------------------------------- +# if running standalone + +if __name__ == "__main__": + # Every wxWindows application must have a class derived from wxApp + class MyApp(wx.App): + + # wxWindows calls this method to initialize the application + def OnInit(self): + + # Create an instance of our customized Frame class + frame = MyFrame(None, -1, "This is a test") + frame.Show(True) + + # Tell wxWindows that this is our main window + self.SetTopWindow(frame) + + # Return a success flag + return True + + + app = MyApp(0) # Create an instance of the application class + app.MainLoop() # Tell it to start processing events + + +#--------------------------------------------------------------------------- +# if running as part of the Demo Framework... + +def runTest(frame, nb, log): + win = MyFrame(frame, -1, "This is a test") + frame.otherWin = win + win.Show(True) + + +overview = """\ +A simple example that shows how to use Dialog Units. +""" + +#---------------------------------------------------------------------------- +# + + + + + + + + + diff --git a/demo/DirDialog.py b/demo/DirDialog.py new file mode 100644 index 00000000..eed1be3b --- /dev/null +++ b/demo/DirDialog.py @@ -0,0 +1,57 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a DirDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + # In this case we include a "New directory" button. + dlg = wx.DirDialog(self, "Choose a directory:", + style=wx.DD_DEFAULT_STYLE + #| wx.DD_DIR_MUST_EXIST + #| wx.DD_CHANGE_DIR + ) + + # If the user selects OK, then we process the dialog's data. + # This is done by getting the path data from the dialog - BEFORE + # we destroy it. + if dlg.ShowModal() == wx.ID_OK: + self.log.WriteText('You selected: %s\n' % dlg.GetPath()) + + # Only destroy a dialog after you're done with it. + dlg.Destroy() + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + + + +overview = """\ +This class represents the directory chooser dialog. It is used when all you +need from the user is the name of a directory. Data is retrieved via utility +methods; see the DirDialog documentation for specifics. +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DragAndDrop.py b/demo/DragAndDrop.py new file mode 100644 index 00000000..95b192db --- /dev/null +++ b/demo/DragAndDrop.py @@ -0,0 +1,273 @@ + +import wx + +#---------------------------------------------------------------------- + +ID_CopyBtn = wx.NewId() +ID_PasteBtn = wx.NewId() +ID_BitmapBtn = wx.NewId() + +#---------------------------------------------------------------------- + +class ClipTextPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + #self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add( + wx.StaticText( + self, -1, "Copy/Paste text to/from\n" + "this window and other apps" + ), + 0, wx.EXPAND|wx.ALL, 2 + ) + + self.text = wx.TextCtrl(self, -1, "", style=wx.TE_MULTILINE|wx.HSCROLL) + sizer.Add(self.text, 1, wx.EXPAND) + + hsz = wx.BoxSizer(wx.HORIZONTAL) + hsz.Add(wx.Button(self, ID_CopyBtn, " Copy "), 1, wx.EXPAND|wx.ALL, 2) + hsz.Add(wx.Button(self, ID_PasteBtn, " Paste "), 1, wx.EXPAND|wx.ALL, 2) + sizer.Add(hsz, 0, wx.EXPAND) + sizer.Add( + wx.Button(self, ID_BitmapBtn, " Copy Bitmap "), + 0, wx.EXPAND|wx.ALL, 2 + ) + + self.Bind(wx.EVT_BUTTON, self.OnCopy, id=ID_CopyBtn) + self.Bind(wx.EVT_BUTTON, self.OnPaste, id=ID_PasteBtn) + self.Bind(wx.EVT_BUTTON, self.OnCopyBitmap, id=ID_BitmapBtn) + + self.SetAutoLayout(True) + self.SetSizer(sizer) + + + def OnCopy(self, evt): + self.do = wx.TextDataObject() + self.do.SetText(self.text.GetValue()) + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(self.do) + wx.TheClipboard.Close() + else: + wx.MessageBox("Unable to open the clipboard", "Error") + + + def OnPaste(self, evt): + success = False + do = wx.TextDataObject() + if wx.TheClipboard.Open(): + success = wx.TheClipboard.GetData(do) + wx.TheClipboard.Close() + + if success: + self.text.SetValue(do.GetText()) + else: + wx.MessageBox( + "There is no data in the clipboard in the required format", + "Error" + ) + + def OnCopyBitmap(self, evt): + dlg = wx.FileDialog(self, "Choose a bitmap to copy", wildcard="*.bmp") + + if dlg.ShowModal() == wx.ID_OK: + bmp = wx.Bitmap(dlg.GetPath(), wx.BITMAP_TYPE_BMP) + bmpdo = wx.BitmapDataObject(bmp) + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(bmpdo) + wx.TheClipboard.Close() + + wx.MessageBox( + "The bitmap is now in the Clipboard. Switch to a graphics\n" + "editor and try pasting it in..." + ) + else: + wx.MessageBox( + "There is no data in the clipboard in the required format", + "Error" + ) + + dlg.Destroy() + +#---------------------------------------------------------------------- + +class OtherDropTarget(wx.PyDropTarget): + def __init__(self, window, log): + wx.PyDropTarget.__init__(self) + self.log = log + self.do = wx.FileDataObject() + self.SetDataObject(self.do) + + def OnEnter(self, x, y, d): + self.log.WriteText("OnEnter: %d, %d, %d\n" % (x, y, d)) + return wx.DragCopy + + #def OnDragOver(self, x, y, d): + # self.log.WriteText("OnDragOver: %d, %d, %d\n" % (x, y, d)) + # return wx.DragCopy + + def OnLeave(self): + self.log.WriteText("OnLeave\n") + + def OnDrop(self, x, y): + self.log.WriteText("OnDrop: %d %d\n" % (x, y)) + return True + + def OnData(self, x, y, d): + self.log.WriteText("OnData: %d, %d, %d\n" % (x, y, d)) + self.GetData() + self.log.WriteText("%s\n" % self.do.GetFilenames()) + return d + + +class MyFileDropTarget(wx.FileDropTarget): + def __init__(self, window, log): + wx.FileDropTarget.__init__(self) + self.window = window + self.log = log + + def OnDropFiles(self, x, y, filenames): + self.window.SetInsertionPointEnd() + self.window.WriteText("\n%d file(s) dropped at %d,%d:\n" % + (len(filenames), x, y)) + + for file in filenames: + self.window.WriteText(file + '\n') + + +class MyTextDropTarget(wx.TextDropTarget): + def __init__(self, window, log): + wx.TextDropTarget.__init__(self) + self.window = window + self.log = log + + def OnDropText(self, x, y, text): + self.window.WriteText("(%d, %d)\n%s\n" % (x, y, text)) + + def OnDragOver(self, x, y, d): + return wx.DragCopy + + +class FileDropPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + + #self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add( + wx.StaticText(self, -1, " \nDrag some files here:"), + 0, wx.EXPAND|wx.ALL, 2 + ) + + self.text = wx.TextCtrl( + self, -1, "", + style = wx.TE_MULTILINE|wx.HSCROLL|wx.TE_READONLY + ) + + dt = MyFileDropTarget(self, log) + self.text.SetDropTarget(dt) + sizer.Add(self.text, 1, wx.EXPAND) + + sizer.Add( + wx.StaticText(self, -1, " \nDrag some text here:"), + 0, wx.EXPAND|wx.ALL, 2 + ) + + self.text2 = wx.TextCtrl( + self, -1, "", + style = wx.TE_MULTILINE|wx.HSCROLL|wx.TE_READONLY + ) + + dt = MyTextDropTarget(self.text2, log) + self.text2.SetDropTarget(dt) + sizer.Add(self.text2, 1, wx.EXPAND) + + self.SetAutoLayout(True) + self.SetSizer(sizer) + + + def WriteText(self, text): + self.text.WriteText(text) + + def SetInsertionPointEnd(self): + self.text.SetInsertionPointEnd() + + +#---------------------------------------------------------------------- +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + + self.SetAutoLayout(True) + outsideSizer = wx.BoxSizer(wx.VERTICAL) + + msg = "Clipboard / Drag-And-Drop" + text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE) + text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + text.SetLabel(msg) + + w,h = text.GetTextExtent(msg) + text.SetSize(wx.Size(w,h+1)) + text.SetForegroundColour(wx.BLUE) + outsideSizer.Add(text, 0, wx.EXPAND|wx.ALL, 5) + outsideSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) + + inSizer = wx.BoxSizer(wx.HORIZONTAL) + inSizer.Add(ClipTextPanel(self, log), 1, wx.EXPAND) + inSizer.Add(FileDropPanel(self, log), 1, wx.EXPAND) + + outsideSizer.Add(inSizer, 1, wx.EXPAND) + self.SetSizer(outsideSizer) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ + + +This demo shows some examples of data transfer through clipboard or +drag and drop. In wxWindows, these two ways to transfer data (either +between different applications or inside one and the same) are very +similar which allows to implement both of them using almost the same +code - or, in other words, if you implement drag and drop support for +your application, you get clipboard support for free and vice versa. +

+At the heart of both clipboard and drag and drop operations lies the +wxDataObject class. The objects of this class (or, to be precise, +classes derived from it) represent the data which is being carried by +the mouse during drag and drop operation or copied to or pasted from +the clipboard. wxDataObject is a "smart" piece of data because it +knows which formats it supports (see GetFormatCount and GetAllFormats) +and knows how to render itself in any of them (see GetDataHere). It +can also receive its value from the outside in a format it supports if +it implements the SetData method. Please see the documentation of this +class for more details. +

+Both clipboard and drag and drop operations have two sides: the source +and target, the data provider and the data receiver. These which may +be in the same application and even the same window when, for example, +you drag some text from one position to another in a word +processor. Let us describe what each of them should do. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DragImage.py b/demo/DragImage.py new file mode 100644 index 00000000..6b065d9b --- /dev/null +++ b/demo/DragImage.py @@ -0,0 +1,327 @@ + +import wx +import images + +#---------------------------------------------------------------------- + +class DragShape: + def __init__(self, bmp): + self.bmp = bmp + self.pos = (0,0) + self.shown = True + self.text = None + self.fullscreen = False + + def HitTest(self, pt): + rect = self.GetRect() + return rect.InsideXY(pt.x, pt.y) + + def GetRect(self): + return wx.Rect(self.pos[0], self.pos[1], + self.bmp.GetWidth(), self.bmp.GetHeight()) + + def Draw(self, dc, op = wx.COPY): + if self.bmp.Ok(): + memDC = wx.MemoryDC() + memDC.SelectObject(self.bmp) + + dc.Blit(self.pos[0], self.pos[1], + self.bmp.GetWidth(), self.bmp.GetHeight(), + memDC, 0, 0, op, True) + + return True + else: + return False + + + +#---------------------------------------------------------------------- + +class DragCanvas(wx.ScrolledWindow): + def __init__(self, parent, ID): + wx.ScrolledWindow.__init__(self, parent, ID) + self.shapes = [] + self.dragImage = None + self.dragShape = None + self.hiliteShape = None + + self.SetCursor(wx.StockCursor(wx.CURSOR_ARROW)) + self.bg_bmp = images.Background.GetBitmap() + self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + + # Make a shape from an image and mask. This one will demo + # dragging outside the window + bmp = images.TestStar.GetBitmap() + #bmp = wx.Bitmap('bitmaps/toucan.png') + shape = DragShape(bmp) + shape.pos = (5, 5) + shape.fullscreen = True + self.shapes.append(shape) + + bmp = images.TheKid.GetBitmap() + shape = DragShape(bmp) + shape.pos = (200, 5) + self.shapes.append(shape) + + # Make a shape from some text + text = "Some Text" + bg_colour = wx.Colour(57, 115, 57) # matches the bg image + font = wx.Font(15, wx.ROMAN, wx.NORMAL, wx.BOLD) + textExtent = self.GetFullTextExtent(text, font) + + # create a bitmap the same size as our text + bmp = wx.EmptyBitmap(textExtent[0], textExtent[1]) + + # 'draw' the text onto the bitmap + dc = wx.MemoryDC() + dc.SelectObject(bmp) + dc.SetBackground(wx.Brush(bg_colour, wx.SOLID)) + dc.Clear() + dc.SetTextForeground(wx.RED) + dc.SetFont(font) + dc.DrawText(text, 0, 0) + dc.SelectObject(wx.NullBitmap) + mask = wx.Mask(bmp, bg_colour) + bmp.SetMask(mask) + shape = DragShape(bmp) + shape.pos = (5, 100) + shape.text = "Some dragging text" + self.shapes.append(shape) + + + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) + self.Bind(wx.EVT_MOTION, self.OnMotion) + self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow) + + + # We're not doing anything here, but you might have reason to. + # for example, if you were dragging something, you might elect to + # 'drop it' when the cursor left the window. + def OnLeaveWindow(self, evt): + pass + + + # tile the background bitmap + def TileBackground(self, dc): + sz = self.GetClientSize() + w = self.bg_bmp.GetWidth() + h = self.bg_bmp.GetHeight() + + x = 0 + + while x < sz.width: + y = 0 + + while y < sz.height: + dc.DrawBitmap(self.bg_bmp, x, y) + y = y + h + + x = x + w + + + # Go through our list of shapes and draw them in whatever place they are. + def DrawShapes(self, dc): + for shape in self.shapes: + if shape.shown: + shape.Draw(dc) + + # This is actually a sophisticated 'hit test', but in this + # case we're also determining which shape, if any, was 'hit'. + def FindShape(self, pt): + for shape in self.shapes: + if shape.HitTest(pt): + return shape + return None + + + # Clears the background, then redraws it. If the DC is passed, then + # we only do so in the area so designated. Otherwise, it's the whole thing. + def OnEraseBackground(self, evt): + dc = evt.GetDC() + if not dc: + dc = wx.ClientDC(self) + rect = self.GetUpdateRegion().GetBox() + dc.SetClippingRect(rect) + self.TileBackground(dc) + + # Fired whenever a paint event occurs + def OnPaint(self, evt): + dc = wx.PaintDC(self) + self.PrepareDC(dc) + self.DrawShapes(dc) + + # Left mouse button is down. + def OnLeftDown(self, evt): + # Did the mouse go down on one of our shapes? + shape = self.FindShape(evt.GetPosition()) + + # If a shape was 'hit', then set that as the shape we're going to + # drag around. Get our start position. Dragging has not yet started. + # That will happen once the mouse moves, OR the mouse is released. + if shape: + self.dragShape = shape + self.dragStartPos = evt.GetPosition() + + # Left mouse button up. + def OnLeftUp(self, evt): + if not self.dragImage or not self.dragShape: + self.dragImage = None + self.dragShape = None + return + + # Hide the image, end dragging, and nuke out the drag image. + self.dragImage.Hide() + self.dragImage.EndDrag() + self.dragImage = None + + if self.hiliteShape: + self.RefreshRect(self.hiliteShape.GetRect()) + self.hiliteShape = None + + # reposition and draw the shape + + # Note by jmg 11/28/03 + # Here's the original: + # + # self.dragShape.pos = self.dragShape.pos + evt.GetPosition() - self.dragStartPos + # + # So if there are any problems associated with this, use that as + # a starting place in your investigation. I've tried to simulate the + # wx.Point __add__ method here -- it won't work for tuples as we + # have now from the various methods + # + # There must be a better way to do this :-) + # + + self.dragShape.pos = ( + self.dragShape.pos[0] + evt.GetPosition()[0] - self.dragStartPos[0], + self.dragShape.pos[1] + evt.GetPosition()[1] - self.dragStartPos[1] + ) + + self.dragShape.shown = True + self.RefreshRect(self.dragShape.GetRect()) + self.dragShape = None + + + # The mouse is moving + def OnMotion(self, evt): + # Ignore mouse movement if we're not dragging. + if not self.dragShape or not evt.Dragging() or not evt.LeftIsDown(): + return + + # if we have a shape, but haven't started dragging yet + if self.dragShape and not self.dragImage: + + # only start the drag after having moved a couple pixels + tolerance = 2 + pt = evt.GetPosition() + dx = abs(pt.x - self.dragStartPos.x) + dy = abs(pt.y - self.dragStartPos.y) + if dx <= tolerance and dy <= tolerance: + return + + # refresh the area of the window where the shape was so it + # will get erased. + self.dragShape.shown = False + self.RefreshRect(self.dragShape.GetRect(), True) + self.Update() + + if self.dragShape.text: + self.dragImage = wx.DragString(self.dragShape.text, + wx.StockCursor(wx.CURSOR_HAND)) + else: + self.dragImage = wx.DragImage(self.dragShape.bmp, + wx.StockCursor(wx.CURSOR_HAND)) + + hotspot = self.dragStartPos - self.dragShape.pos + self.dragImage.BeginDrag(hotspot, self, self.dragShape.fullscreen) + + self.dragImage.Move(pt) + self.dragImage.Show() + + + # if we have shape and image then move it, posibly highlighting another shape. + elif self.dragShape and self.dragImage: + onShape = self.FindShape(evt.GetPosition()) + unhiliteOld = False + hiliteNew = False + + # figure out what to hilite and what to unhilite + if self.hiliteShape: + if onShape is None or self.hiliteShape is not onShape: + unhiliteOld = True + + if onShape and onShape is not self.hiliteShape and onShape.shown: + hiliteNew = True + + # if needed, hide the drag image so we can update the window + if unhiliteOld or hiliteNew: + self.dragImage.Hide() + + if unhiliteOld: + dc = wx.ClientDC(self) + self.hiliteShape.Draw(dc) + self.hiliteShape = None + + if hiliteNew: + dc = wx.ClientDC(self) + self.hiliteShape = onShape + self.hiliteShape.Draw(dc, wx.INVERT) + + # now move it and show it again if needed + self.dragImage.Move(evt.GetPosition()) + if unhiliteOld or hiliteNew: + self.dragImage.Show() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + + win = wx.Panel(nb, -1) + canvas = DragCanvas(win, -1) + + def onSize(evt, panel=win, canvas=canvas): + canvas.SetSize(panel.GetSize()) + + win.Bind(wx.EVT_SIZE, onSize) + return win + +#---------------------------------------------------------------------- + + + +overview = """\ +DragImage is used when you wish to drag an object on the screen, and a simple +cursor is not enough. + +On Windows, the WIN32 API is used to do achieve smooth dragging. On other +platforms, GenericDragImage is used. Applications may also prefer to use +GenericDragImage on Windows, too. + +wxPython note: wxPython uses GenericDragImage on all +platforms, but uses the DragImage name. + +To use this class, when you wish to start dragging an image, create a +DragImage object and store it somewhere you can access it as the +drag progresses. Call BeginDrag to start, and EndDrag to stop the drag. To move +the image, initially call Show and then Move. If you wish to update the screen +contents during the drag (for example, highlight an item as in the example), first +call Hide, update the screen, call Move, and then call Show. + +You can drag within one window, or you can use full-screen dragging either across +the whole screen, or just restricted to one area of the screen to save resources. +If you want the user to drag between two windows, then you will need to use +full-screen dragging. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DragScroller.py b/demo/DragScroller.py new file mode 100644 index 00000000..101555ef --- /dev/null +++ b/demo/DragScroller.py @@ -0,0 +1,57 @@ +import wx +import wx.lib.dragscroller + +#------------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = DragScrollerExample(nb, -1) + return win + +class DragScrollerExample(wx.ScrolledWindow): + def __init__(self, parent, id=-1): + wx.ScrolledWindow.__init__(self, parent, id) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) + self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) + + self.SetScrollbars(1, 1, 2000, 2000, 0, 0) + + self.scroller = wx.lib.dragscroller.DragScroller(self) + + def OnPaint(self, event): + dc = wx.PaintDC(self) + self.PrepareDC(dc) + + pen = wx.Pen(wx.BLACK, 5) + dc.SetPen(pen) + + for y in range(10): + for x in range(10): + dc.DrawCircle(x*400+20, y*400+20, 200) + + dc.DrawText('Right click and drag in the direction you want to scroll.', + 20, 20) + dc.DrawText('The distance from the start of the drag determines the speed.', + 20, 50) + + def OnRightDown(self, event): + self.scroller.Start(event.GetPosition()) + + def OnRightUp(self, event): + self.scroller.Stop() + + +#------------------------------------------------------------------------------- + +overview = """ +

DragScroller

+

+A helper class that adds scrolling to a wx.ScrolledWindow in the direction +of the drag. + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])]) diff --git a/demo/DrawXXXList.py b/demo/DrawXXXList.py new file mode 100644 index 00000000..5086b14c --- /dev/null +++ b/demo/DrawXXXList.py @@ -0,0 +1,453 @@ + +import random +import time + +import wx + +#---------------------------------------------------------------------- + +colours = [ + "BLACK", + "BLUE", + "BLUE VIOLET", + "BROWN", + "CYAN", + "DARK GREY", + "DARK GREEN", + "GOLD", + "GREY", + "GREEN", + "MAGENTA", + "NAVY", + "PINK", + "RED", + "SKY BLUE", + "VIOLET", + "YELLOW", + ] + +#---------------------------------------------------------------------- + +def makeRandomPoints(num, w, h): + pnts = [] + + for i in range(num): + x = random.randint(0, w) + y = random.randint(0, h) + pnts.append( (x,y) ) + + return pnts + + +def makeRandomLines(num, w, h): + pnts = [] + + for i in range(num): + x1 = random.randint(0, w) + y1 = random.randint(0, h) + x2 = random.randint(0, w) + y2 = random.randint(0, h) + pnts.append( (x1,y1, x2,y2) ) + + return pnts + + +def makeRandomRectangles(num, W, H): + rects = [] + + for i in range(num): + w = random.randint(10, W/2) + h = random.randint(10, H/2) + x = random.randint(0, W - w) + y = random.randint(0, H - h) + rects.append( (x, y, w, h) ) + + return rects + + +def makeRandomText(num): + Np = 8 # number of characters in text + text = [] + + for i in range(num): + word = [] + + for i in range(Np): + c = chr( random.randint(48, 122) ) + word.append( c ) + + text.append( "".join(word) ) + + return text + + +def makeRandomPolygons(num, W, H): + Np = 8 # number of points per polygon + polys = [] + + for i in range(num): + poly = [] + + for i in range(Np): + x = random.randint(0, W) + y = random.randint(0, H) + poly.append( (x,y) ) + + polys.append( poly ) + + return polys + + +def makeRandomPens(num, cache): + pens = [] + + for i in range(num): + c = random.choice(colours) + t = random.randint(1, 4) + + if not cache.has_key( (c, t) ): + cache[(c, t)] = wx.Pen(c, t) + + pens.append( cache[(c, t)] ) + + return pens + + +def makeRandomBrushes(num, cache): + brushes = [] + + for i in range(num): + c = random.choice(colours) + + if not cache.has_key(c): + cache[c] = wx.Brush(c) + + brushes.append( cache[c] ) + + return brushes + + +def makeRandomColors(num): + colors = [] + + for i in range(num): + c = random.choice(colours) + colors.append(wx.NamedColour(c)) + return colors + + + +pencache = {} +brushcache = {} +points = None +lines = None +rectangles = None +polygons = None +text = None +pens = None +brushes = None +colors1 = None +colors2 = None + + +def Init(w, h, n): + global pencache + global brushcache + global points + global lines + global rectangles + global polygons + global text + global pens + global brushes + global colors1 + global colors2 + + # make some lists of random shapes + points = makeRandomPoints(n, w, h) + + try: + import Numeric + Apoints = Numeric.array(points) + except: + pass + + lines = makeRandomLines(n, w, h) + rectangles = makeRandomRectangles(n, w, h) + polygons = makeRandomPolygons(n, w, h) + text = makeRandomText(n) + + # make some random pens and brushes + pens = makeRandomPens(n, pencache) + brushes = makeRandomBrushes(n, brushcache) + # make some random color lists + colors1 = makeRandomColors(n) + colors2 = makeRandomColors(n) + + + +def TestPoints(dc,log): + dc.BeginDrawing() + start = time.time() + dc.SetPen(wx.Pen("BLACK", 4)) + + dc.DrawPointList(points) + dc.DrawPointList(points, wx.Pen("RED", 2)) + dc.DrawPointList(points, pens) + + dc.EndDrawing() + log.write("DrawTime: %s seconds with DrawPointList\n" % (time.time() - start)) + + +def TestArrayPoints(dc,log): + try: + import Numeric + + dc.BeginDrawing() + start = time.time() + dc.SetPen(wx.Pen("BLACK", 1)) + + for i in range(1): + dc.DrawPointList(Apoints) + + #dc.DrawPointList(Apoints, wx.Pen("RED", 2)) + #dc.DrawPointList(Apoints, pens) + dc.EndDrawing() + log.write("DrawTime: %s seconds with DrawPointList an Numpy Array\n" % (time.time() - start)) + except ImportError: + log.write("Couldn't import Numeric") + pass + + +def TestLines(dc,log): + dc.BeginDrawing() + start = time.time() + + dc.SetPen(wx.Pen("BLACK", 2)) + dc.DrawLineList(lines) + dc.DrawLineList(lines, wx.Pen("RED", 2)) + dc.DrawLineList(lines, pens) + + dc.EndDrawing() + log.write("DrawTime: %s seconds with DrawLineList\n" % (time.time() - start)) + + +def TestRectangles(dc,log): + dc.BeginDrawing() + start = time.time() + + dc.SetPen( wx.Pen("BLACK",1) ) + dc.SetBrush( wx.Brush("RED") ) + + dc.DrawRectangleList(rectangles) + dc.DrawRectangleList(rectangles,pens) + dc.DrawRectangleList(rectangles,pens[0],brushes) + dc.DrawRectangleList(rectangles,pens,brushes[0]) + dc.DrawRectangleList(rectangles,None,brushes) +## for i in range(10): +## #dc.DrawRectangleList(rectangles,pens,brushes) +## dc.DrawRectangleList(rectangles) + + dc.EndDrawing() + log.write("DrawTime: %s seconds with DrawRectanglesList\n" % (time.time() - start)) + + +def TestEllipses(dc,log): + dc.BeginDrawing() + start = time.time() + + dc.SetPen( wx.Pen("BLACK",1) ) + dc.SetBrush( wx.Brush("RED") ) + + dc.DrawEllipseList(rectangles) + dc.DrawEllipseList(rectangles,pens) + dc.DrawEllipseList(rectangles,pens[0],brushes) + dc.DrawEllipseList(rectangles,pens,brushes[0]) + dc.DrawEllipseList(rectangles,None,brushes) + dc.DrawEllipseList(rectangles,pens,brushes) + + dc.EndDrawing() + log.write("DrawTime: %s seconds with DrawEllipsesList\n" % (time.time() - start)) + + +def TestRectanglesArray(dc,log): + try: + import Numeric + Apoints = Numeric.array(rectangles) + + dc.BeginDrawing() + start = time.time() + dc.SetPen(wx.Pen("BLACK", 1)) + dc.DrawRectangleList(rectangles) + dc.DrawRectangleList(rectangles,pens) + dc.DrawRectangleList(rectangles,pens[0],brushes) + dc.DrawRectangleList(rectangles,pens,brushes[0]) + dc.DrawRectangleList(rectangles,None,brushes) +## for i in range(10): +## #dc.DrawRectangleList(rectangles,pens,brushes) +## dc.DrawRectangleList(rectangles) + + dc.EndDrawing() + log.write("DrawTime: %s seconds with DrawRectangleList and Numpy Array\n" % (time.time() - start)) + except ImportError: + log.write("Couldn't import Numeric") + pass + + +def TestRectanglesLoop(dc,log): + dc.BeginDrawing() + + start = time.time() + dc.DrawRectangleList(rectangles,pens,brushes) + log.write("DrawTime: %s seconds with DrawRectanglesList\n" % (time.time() - start)) + + start = time.time() + + for i in range(len(rectangles)): + dc.SetPen( pens[i] ) + dc.SetBrush( brushes[i] ) + dc.DrawRectangle(rectangles[i][0],rectangles[i][1],rectangles[i][2],rectangles[i][3]) + + dc.EndDrawing() + log.write("DrawTime: %s seconds with Python loop\n" % (time.time() - start)) + + +def TestPolygons(dc,log): + dc.BeginDrawing() + + start = time.time() + dc.SetPen(wx.Pen("BLACK", 1)) + dc.DrawPolygonList(polygons) + dc.DrawPolygonList(polygons,pens) + dc.DrawPolygonList(polygons,pens[0],brushes) + dc.DrawPolygonList(polygons,pens,brushes[0]) + dc.DrawPolygonList(polygons,None,brushes) + log.write("DrawTime: %s seconds with DrawPolygonList\n" % (time.time() - start)) + + dc.EndDrawing() + + +def TestText(dc,log): + dc.BeginDrawing() + + start = time.time() + + # NOTE: you need to set BackgroundMode for the background colors to be used. + dc.SetBackgroundMode(wx.SOLID) + foreground = colors1 + background = colors2 + dc.DrawTextList(text, points, foreground, background) + + log.write("DrawTime: %s seconds with DrawTextList\n" % (time.time() - start)) + + dc.EndDrawing() + + + +class TestNB(wx.Notebook): + def __init__(self, parent, id, log): + style = wx.NB_BOTTOM + + if wx.Platform == "__WXMAC__": + style = 0 + + wx.Notebook.__init__(self, parent, id, style=style) + self.log = log + + # Initialize our various samples and add them to the notebook. + win = DrawPanel(self, TestEllipses, log) + self.AddPage(win, 'Ellipses') + + win = DrawPanel(self, TestText, log) + self.AddPage(win, 'Text') + + win = DrawPanel(self, TestPolygons, log) + self.AddPage(win, 'Polygons') + + win = DrawPanel(self, TestPoints, log) + self.AddPage(win, 'Points') + + win = DrawPanel(self, TestLines, log) + self.AddPage(win, 'Lines') + + win = DrawPanel(self, TestRectangles, log) + self.AddPage(win, 'Rectangles') + +# Class used for all the various sample pages; the mechanics are the same +# for each one with regards to the notebook. The only difference is +# the function we use to draw on it. +class DrawPanel(wx.Panel): + def __init__(self, parent, drawFun, log): + wx.Panel.__init__(self, parent, -1) + self.SetBackgroundColour(wx.WHITE) + + self.log = log + self.drawFun = drawFun + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + dc.Clear() + self.drawFun(dc,self.log) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + w = nb.GetClientSize().width + h = nb.GetClientSize().height + if w < 600: w = 600 + if h < 400: h = 400 + Init(w, h, 200) + win = TestNB(nb, -1, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ + +Some methods have been added to wx.DC to help with optimization of +drawing routines. Currently they are: + +

+    DrawPointList(sequence, pens=None)
+
+ Where sequence is a tuple, list, whatever of 2 element tuples + (x, y) and pens is either None, a single pen or a list of pens. + +
+    DrawLineList(sequence, pens=None)
+
+ Where sequence is a tuple, list, whatever of 4 element tuples + (x1,y1, x2,y2) and pens is either None, a single pen or a list + of pens. + +
+    DrawRectangleList(rectangles, pens=None, brushes=None)
+
+ + +
+    DrawEllipseList(ellipses, pens=None, brushes=None)
+
+ + +
+    DrawPolygonList(polygons, pens=None, brushes=None)
+
+ + +
+    DrawTextList(textList, coords, foregrounds = None, backgrounds = None)
+
+ +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/DynamicSashWindow.py b/demo/DynamicSashWindow.py new file mode 100644 index 00000000..fab2767f --- /dev/null +++ b/demo/DynamicSashWindow.py @@ -0,0 +1,166 @@ + +import wx +import wx.gizmos as gizmos +import wx.stc as stc + +#---------------------------------------------------------------------- +# This is an example of the complex view that manages its own scrollbars +# as described in the overview below. + +class TestView(stc.StyledTextCtrl): + def __init__(self, parent, ID, log): + stc.StyledTextCtrl.__init__(self, parent, ID, style=wx.NO_BORDER) + self.dyn_sash = parent + self.log = log + self.SetupScrollBars() + self.SetMarginWidth(1,0) + + self.StyleSetFont(stc.STC_STYLE_DEFAULT, + wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL)) + + self.Bind(gizmos.EVT_DYNAMIC_SASH_SPLIT, self.OnSplit) + self.Bind(gizmos.EVT_DYNAMIC_SASH_UNIFY, self.OnUnify) + #self.SetScrollWidth(500) + + def SetupScrollBars(self): + # hook the scrollbars provided by the wxDynamicSashWindow + # to this view + v_bar = self.dyn_sash.GetVScrollBar(self) + h_bar = self.dyn_sash.GetHScrollBar(self) + v_bar.Bind(wx.EVT_SCROLL, self.OnSBScroll) + h_bar.Bind(wx.EVT_SCROLL, self.OnSBScroll) + v_bar.Bind(wx.EVT_SET_FOCUS, self.OnSBFocus) + h_bar.Bind(wx.EVT_SET_FOCUS, self.OnSBFocus) + + # And set the wxStyledText to use these scrollbars instead + # of its built-in ones. + self.SetVScrollBar(v_bar) + self.SetHScrollBar(h_bar) + + + def __del__(self): + self.log.write("TestView.__del__\n") + + def OnSplit(self, evt): + self.log.write("TestView.OnSplit\n"); + newview = TestView(self.dyn_sash, -1, self.log) + newview.SetDocPointer(self.GetDocPointer()) # use the same document + self.SetupScrollBars() + + + def OnUnify(self, evt): + self.log.write("TestView.OnUnify\n"); + self.SetupScrollBars() + + + def OnSBScroll(self, evt): + # redirect the scroll events from the dyn_sash's scrollbars to the STC + self.GetEventHandler().ProcessEvent(evt) + + def OnSBFocus(self, evt): + # when the scrollbar gets the focus move it back to the STC + self.SetFocus() + + +sampleText="""\ +You can drag the little tabs above the vertical scrollbar, or to the +left of the horizontal scrollbar to split this view, and you can +continue splitting the new views as much as you like. Try it and see. + +In this case the views also share the same document so changes in one +are instantly seen in the others. This is a feature of the +StyledTextCtrl that is used for the view class in this sample. +""" + +#---------------------------------------------------------------------- +# This one is simpler, but doesn't do anything with the scrollbars +# except the default wxDynamicSashWindow behaviour + +class SimpleView(wx.Panel): + def __init__(self, parent, ID, log): + wx.Panel.__init__(self, parent, ID) + self.dyn_sash = parent + self.log = log + self.SetBackgroundColour("LIGHT BLUE") + self.Bind(gizmos.EVT_DYNAMIC_SASH_SPLIT, self.OnSplit) + + def OnSplit(self, evt): + v = SimpleView(self.dyn_sash, -1, self.log) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): +## if wx.Platform == "__WXMAC__": +## from wx.lib.msgpanel import MessagePanel +## win = MessagePanel(nb, 'This demo currently fails on the Mac. The problem is being looked into...', +## 'Sorry', wx.ICON_WARNING) +## return win + + if 1: + win = gizmos.DynamicSashWindow(nb, -1, style = wx.CLIP_CHILDREN + #| wxDS_MANAGE_SCROLLBARS + #| wxDS_DRAG_CORNER + ) + + win.SetFont(wx.Font(10, wx.MODERN, wx.NORMAL, wx.NORMAL)) + view = TestView(win, -1, log) + view.SetText(sampleText) + else: + win = wx.DynamicSashWindow(nb, -1) + view = SimpleView(win, -1, log) + return win + +#---------------------------------------------------------------------- + +overview = """\ + +

DynamicSashWindow

+

+wxDynamicSashWindow widgets manages the way other widgets are viewed. +When a wxDynamicSashWindow is first shown, it will contain one child +view, a viewport for that child, and a pair of scrollbars to allow the +user to navigate the child view area. Next to each scrollbar is a small +tab. By clicking on either tab and dragging to the appropriate spot, a +user can split the view area into two smaller views separated by a +draggable sash. Later, when the user wishes to reunify the two subviews, +the user simply drags the sash to the side of the window. +wxDynamicSashWindow will automatically reparent the appropriate child +view back up the window hierarchy, and the wxDynamicSashWindow will have +only one child view once again. +

+As an application developer, you will simply create a wxDynamicSashWindow +using either the Create() function or the more complex constructor +provided below, and then create a view window whose parent is the +wxDynamicSashWindow. The child should respond to +wxDynamicSashSplitEvents -- perhaps with an OnSplit() event handler -- by +constructing a new view window whose parent is also the +wxDynamicSashWindow. That's it! Now your users can dynamically split +and reunify the view you provided. +

+If you wish to handle the scrollbar events for your view, rather than +allowing wxDynamicSashWindow to do it for you, things are a bit more +complex. (You might want to handle scrollbar events yourself, if, +for instance, you wish to scroll a subwindow of the view you add to +your wxDynamicSashWindow object, rather than scrolling the whole view.) +In this case, you will need to construct your wxDynamicSashWindow without +the wxDS_MANAGE_SCROLLBARS style and you will need to use the +GetHScrollBar() and GetVScrollBar() methods to retrieve the scrollbar +controls and call SetEventHanler() on them to redirect the scrolling +events whenever your window is reparented by wxDyanmicSashWindow. +You will need to set the scrollbars' event handler at three times: +

+

+ +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/EditableListBox.py b/demo/EditableListBox.py new file mode 100644 index 00000000..55de3b69 --- /dev/null +++ b/demo/EditableListBox.py @@ -0,0 +1,97 @@ + +import wx +import wx.gizmos as gizmos + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + self.elb = gizmos.EditableListBox( + self, -1, "List of Stuff", (50,50), (250, 250) + ) + #style=wx.EL_ALLOW_NEW | wx.EL_ALLOW_EDIT | wx.EL_ALLOW_DELETE) + + self.elb.SetStrings(["This is a nifty ListBox widget", + "that is editable by the user.", + "", + "Use the buttons above to", + "manipulate items in the list", + "Or to add new ones.", + ]) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """\ + + +This class provides a composite control that lets the user easily enter and edit +a list of strings. + +

Styles supported:

+ +

+ +

Init: +

+ EditableListBox(wxWindow *parent, wxWindowID id=-1,
+                 const wxString& label,
+                 const wxPoint& pos = wxDefaultPosition,
+                 const wxSize& size = wxDefaultSize,
+                 long style = EL_ALLOW_NEW | EL_ALLOW_EDIT | EL_ALLOW_DELETE,
+                 const wxString& name = "editableListBox")
+
+ +

Methods: +

+ + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Editor.py b/demo/Editor.py new file mode 100644 index 00000000..114f2f00 --- /dev/null +++ b/demo/Editor.py @@ -0,0 +1,69 @@ + +import wx +import wx.lib.editor as editor + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = wx.Panel(nb, -1) + ed = editor.Editor(win, -1, style=wx.SUNKEN_BORDER) + box = wx.BoxSizer(wx.VERTICAL) + box.Add(ed, 1, wx.ALL|wx.GROW, 1) + win.SetSizer(box) + win.SetAutoLayout(True) + + ed.SetText(["", + "This is a simple text editor, the class name is", + "Editor. Type a few lines and try it out.", + "", + "It uses Windows-style key commands that can be overridden by subclassing.", + "Mouse select works. Here are the key commands:", + "", + "Cursor movement: Arrow keys or mouse", + "Beginning of line: Home", + "End of line: End", + "Beginning of buffer: Control-Home", + "End of the buffer: Control-End", + "Select text: Hold down Shift while moving the cursor", + "Copy: Control-Insert, Control-C", + "Cut: Shift-Delete, Control-X", + "Paste: Shift-Insert, Control-V", + ""]) + + return win + +#---------------------------------------------------------------------- + + +overview = """ +The Editor class implements a simple text editor using wxPython. You +can create a custom editor by subclassing Editor. Even though much of +the editor is implemented in Python, it runs surprisingly smoothly on +normal hardware with small files. + +How to use it +------------- +The demo code (demo/Editor.py) shows how to use Editor as a simple text +box. Use the SetText() and GetText() methods to set or get text from +the component; these both use a list of strings. + +The samples/FrogEdit directory has an example of a simple text editor +application that uses the Editor component. + +Subclassing +----------- +To add or change functionality, you can subclass this +component. One example of this might be to change the key +Alt key commands. In that case you would (for example) override the +SetAltFuncs() method. + +""" + + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/EventManager.py b/demo/EventManager.py new file mode 100644 index 00000000..7f794289 --- /dev/null +++ b/demo/EventManager.py @@ -0,0 +1,290 @@ +#--------------------------------------------------------------------------- +# Name: EventManager.py +# Purpose: A module to demonstrate wxPython.lib.evtmgr.EventManager. +# +# Author: Robb Shecter (robb@acm.org) +# +# Created: 16-December-2002 +# Copyright: (c) 2002 by Robb Shecter (robb@acm.org) +# Licence: wxWindows license +#--------------------------------------------------------------------------- + +import wx +import wx.lib.evtmgr as em + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + fsize = self.GetFont().GetPointSize() + f1 = wx.Font(fsize+0, wx.SWISS, wx.NORMAL, wx.NORMAL) + f2 = wx.Font(fsize+2, wx.SWISS, wx.NORMAL, wx.BOLD) + f3 = wx.Font(fsize+6, wx.SWISS, wx.NORMAL, wx.BOLD) + + title1 = wx.StaticText(self, -1, 'EventManager') + title1.SetFont(f3) + txt = """\ + This demo shows (1) basic uses and features of the EventManager, as well + as (2) how it helps with a real-world task: creating independent, object- + oriented components.""" + message0 = wx.StaticText(self, -1, txt) + message0.SetFont(f1) + + title2 = wx.StaticText(self, -1, 'Event Listeners') + title2.SetFont(f2) + + txt = """\ + These objects listen to motion events from the target window, using the ability + to register one event with multiple listeners. They also register for mouse events + on themselves to implement toggle-button functionality.""" + message1 = wx.StaticText(self, -1, txt) + message1.SetFont(f1) + + title3 = wx.StaticText(self, -1, 'Target Window') + title3.SetFont(f2) + + txt = """\ + A passive window that's used as an event generator. Move the mouse over it to + send events to the listeners above.""" + message2 = wx.StaticText(self, -1, txt) + message2.SetFont(f1) + + targetPanel = Tile(self, log, bgColor=wx.Colour(80,10,10), active=0) + buttonPanel = wx.Panel(self ,-1) + sizer = wx.BoxSizer(wx.HORIZONTAL) + target = targetPanel.tile + + sizer.Add((0,0), 1) + for factor in [0.2, 0.3, 0.4, 0.5, 0.6, 0.7]: + sizer.Add(Tile(buttonPanel, log, factor-0.05, target), 0, wx.ALIGN_CENTER) + sizer.Add((0,0),1) + sizer.Add(Tile(buttonPanel, log, factor, target), 0, wx.ALIGN_CENTER) + sizer.Add((0,0),1) + + buttonPanel.SetSizer(sizer) + sizer.Fit(buttonPanel) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(title1, 0, wx.ALIGN_CENTER | wx.TOP | wx.BOTTOM, 6) + sizer.Add(message0, 0, wx.ALIGN_CENTER | wx.ALL, 6) + sizer.Add(title2, 0, wx.ALIGN_CENTER | wx.LEFT | wx.TOP | wx.RIGHT, 16) + sizer.Add(message1, 0, wx.ALIGN_CENTER | wx.ALL, 6) + sizer.Add(buttonPanel, 0, wx.EXPAND | wx.ALL, 16) + sizer.Add(title3, 0, wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT, 16) + sizer.Add(message2, 0, wx.ALIGN_CENTER | wx.ALL, 6) + sizer.Add(targetPanel, 2, wx.EXPAND | wx.LEFT | wx.BOTTOM | wx.RIGHT, 16) + self.SetSizer(sizer) + + + +class Tile(wx.Window): + """ + This outer class is responsible for changing + its border color in response to certain mouse + events over its contained 'InnerTile'. + """ + normal = wx.Colour(150,150,150) + active = wx.Colour(250,245,245) + hover = wx.Colour(210,220,210) + + def __init__(self, parent, log, factor=1, thingToWatch=None, bgColor=None, active=1, size=(38,38), borderWidth=3): + wx.Window.__init__(self, parent, -1, size=size, style=wx.CLIP_CHILDREN) + self.tile = InnerTile(self, log, factor, thingToWatch, bgColor) + self.log = log + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(self.tile, 1, wx.EXPAND | wx.ALL, borderWidth) + self.SetSizer(sizer) + self.Layout() + em.eventManager.Register(self.doLayout, wx.EVT_SIZE, self) + self.SetBackgroundColour(Tile.normal) + if active: + # Register myself for mouse events over self.tile in order to + # create typical button/hyperlink visual effects. + em.eventManager.Register(self.setHover, wx.EVT_ENTER_WINDOW, self.tile) + em.eventManager.Register(self.setNormal, wx.EVT_LEAVE_WINDOW, self.tile) + em.eventManager.Register(self.setActive, wx.EVT_LEFT_DOWN, self.tile) + em.eventManager.Register(self.setHover, wx.EVT_LEFT_UP, self.tile) + + + def doLayout(self, event): + self.Layout() + + + def setHover(self, event): + self.SetBackgroundColour(Tile.hover) + self.Refresh() + + + def setActive(self, event): + self.SetBackgroundColour(Tile.active) + self.Refresh() + + + def setNormal(self, event): + self.SetBackgroundColour(Tile.normal) + self.Refresh() + + + +class InnerTile(wx.Window): + IDLE_COLOR = wx.Colour( 80, 10, 10) + START_COLOR = wx.Colour(200, 70, 50) + FINAL_COLOR = wx.Colour( 20, 80,240) + OFF_COLOR = wx.Colour(185,190,185) + # Some pre-computation. + DELTAS = map(lambda a,b: b-a, START_COLOR.Get(), FINAL_COLOR.Get()) + START_COLOR_TUPLE = START_COLOR.Get() + + """ + This inner panel changes its color in reaction to mouse + events over the 'thingToWatch'. + """ + def __init__(self, parent, log, factor, thingToWatch=None, bgColor=None): + wx.Window.__init__(self, parent, -1) + self.SetMinSize((20,20)) + self.log=log + if bgColor: + self.SetBackgroundColour(bgColor) + if thingToWatch: + self.factor = factor + self.thingToWatch = thingToWatch + self.state = 0 + self.toggleOnOff() + # Watch for the mouse click to enable/disable myself. + em.eventManager.Register(self.toggleOnOff, wx.EVT_LEFT_UP, self) + + + def toggleOnOff(self, event=None): + # Implement being on or off by registering and + # de-registering self.makeColor() from the event manager. + if self.state: + em.eventManager.DeregisterListener(self.makeColor) + else: + em.eventManager.Register(self.makeColor, wx.EVT_MOTION, self.thingToWatch) + self.state = 1 - self.state + self.resetColor() + + + def resetColor(self, event=None): + if self.state: + self.setColor(InnerTile.IDLE_COLOR) + else: + self.setColor(InnerTile.OFF_COLOR) + + + def setColor(self, color): + self.SetBackgroundColour(color) + self.Refresh() + + + def makeColor(self, mouseEvent): + self.makeColorFromTuple(mouseEvent.GetPositionTuple()) + + + def makeColorFromTuple(self, (x, y)): + MAX = 180.0 + scaled = min((x + y) * self.factor, MAX) # In range [0..MAX] + percent = scaled / MAX + r = InnerTile.START_COLOR_TUPLE[0] + (InnerTile.DELTAS[0] * percent) + g = InnerTile.START_COLOR_TUPLE[1] + (InnerTile.DELTAS[1] * percent) + b = InnerTile.START_COLOR_TUPLE[2] + (InnerTile.DELTAS[2] * percent) + self.setColor(wx.Colour(int(r), int(g), int(b))) + + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

EventManager

+ +

The goal of the EventManager is to make wxWindows events more +'Pythonic' (ie. object-oriented) and easier to work with, without +impacting performance. It offers these features: + +

+

+ +

Usage

+ +

The EventManager class has three public methods. First get a +reference to it: + +

+  from wxPython.lib.evtmgr import eventManager
+
+ +

...and then invoke any of the following methods. These methods are +'safe'; duplicate registrations or de-registrations will have no +effect. + +

Registering a listener: + +

+  eventManager.Register(listener, event, event-source)
+
+ + +

De-registering by window: + +

+  eventManager.DeregisterWindow(event-source)
+
+ + +

De-registering by listener: + +

+  eventManager.DeregisterListener(listener)
+
+ +

Simple Example: + +

+  from wxPython.lib.evtmgr import eventManager
+
+  aButton = wxButton(somePanel, -1, 'Click me')
+  eventManager.Register(self.someMethod, EVT_BUTTON, aButton)
+
+ +

See the demo code as well as the documentation in the source of +wxPython.lib.evtmgr for more details. + + +

+by Robb Shecter (robb@acm.org) + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ExpandoTextCtrl.py b/demo/ExpandoTextCtrl.py new file mode 100644 index 00000000..b9ba3091 --- /dev/null +++ b/demo/ExpandoTextCtrl.py @@ -0,0 +1,163 @@ + +import wx +from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED + +#---------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, title="Test ExpandoTextCtrl") + self.log = log + self.pnl = p = wx.Panel(self) + self.eom = ExpandoTextCtrl(p, size=(250,-1), + value="This control will expand as you type") + self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.eom) + + # create some buttons and sizers to use in testing some + # features and also the layout + vBtnSizer = wx.BoxSizer(wx.VERTICAL) + + btn = wx.Button(p, -1, "Set MaxHeight") + self.Bind(wx.EVT_BUTTON, self.OnSetMaxHeight, btn) + vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5) + + btn = wx.Button(p, -1, "Set Font") + self.Bind(wx.EVT_BUTTON, self.OnSetFont, btn) + vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5) + + btn = wx.Button(p, -1, "Write Text") + self.Bind(wx.EVT_BUTTON, self.OnWriteText, btn) + vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5) + + btn = wx.Button(p, -1, "Append Text") + self.Bind(wx.EVT_BUTTON, self.OnAppendText, btn) + vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5) + + btn = wx.Button(p, -1, "Set Value") + self.Bind(wx.EVT_BUTTON, self.OnSetValue, btn) + vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5) + + btn = wx.Button(p, -1, "Get Value") + self.Bind(wx.EVT_BUTTON, self.OnGetValue, btn) + vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5) + + for x in range(3): + btn = wx.Button(p, -1, " ") + vBtnSizer.Add(btn, 0, wx.ALL|wx.EXPAND, 5) + self.Bind(wx.EVT_BUTTON, self.OnOtherBtn, btn) + + hBtnSizer = wx.BoxSizer(wx.HORIZONTAL) + for x in range(3): + btn = wx.Button(p, -1, " ") + hBtnSizer.Add(btn, 0, wx.ALL, 5) + self.Bind(wx.EVT_BUTTON, self.OnOtherBtn, btn) + + sizer = wx.BoxSizer(wx.HORIZONTAL) + col1 = wx.BoxSizer(wx.VERTICAL) + col1.Add(self.eom, 0, wx.ALL, 10) + col1.Add(hBtnSizer) + sizer.Add(col1) + sizer.Add(vBtnSizer) + p.SetSizer(sizer) + + # Put the panel in a sizer for the frame so we can use self.Fit() + frameSizer = wx.BoxSizer() + frameSizer.Add(p, 1, wx.EXPAND) + self.SetSizer(frameSizer) + + self.Fit() + + + def OnRefit(self, evt): + # The Expando control will redo the layout of the + # sizer it belongs to, but sometimes this may not be + # enough, so it will send us this event so we can do any + # other layout adjustments needed. In this case we'll + # just resize the frame to fit the new needs of the sizer. + self.Fit() + + + def OnSetMaxHeight(self, evt): + mh = self.eom.GetMaxHeight() + dlg = wx.NumberEntryDialog(self, "", "Enter new max height:", + "MaxHeight", mh, -1, 1000) + if dlg.ShowModal() == wx.ID_OK: + self.eom.SetMaxHeight(dlg.GetValue()) + dlg.Destroy() + + + def OnSetFont(self, evt): + dlg = wx.FontDialog(self, wx.FontData()) + dlg.GetFontData().SetInitialFont(self.eom.GetFont()) + if dlg.ShowModal() == wx.ID_OK: + self.eom.SetFont(dlg.GetFontData().GetChosenFont()) + dlg.Destroy() + + + def OnWriteText(self, evt): + self.eom.WriteText("\nThis is a test... Only a test. If this had " + "been a real emergency you would have seen the " + "quick brown fox jump over the lazy dog.\n") + + def OnAppendText(self, evt): + self.eom.AppendText("\nAppended text.") + + def OnSetValue(self, evt): + self.eom.SetValue("A new value.") + + def OnGetValue(self, evt): + self.log.write("-----------------\n" + self.eom.GetValue()) + + def OnOtherBtn(self, evt): + # just for testing... + #print self.eom.numLines, + self.eom._adjustCtrl() + #print self.eom.numLines + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test ExpandoTextCtrl ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = TestFrame(self, self.log) + self.win.Show(True) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

ExpandoTextCtrl

+ +The ExpandoTextCtrl is a multi-line wx.TextCtrl that will +adjust its height on the fly as needed to accomodate the number of +lines needed to display the current content of the control. It is +assumed that the width of the control will be a fixed value and +that only the height will be adjusted automatically. If the +control is used in a sizer then the width should be set as part of +the initial or min size of the control. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/FancyText.py b/demo/FancyText.py new file mode 100644 index 00000000..b7c954c2 --- /dev/null +++ b/demo/FancyText.py @@ -0,0 +1,82 @@ + +import wx +import wx.lib.fancytext as fancytext + +#---------------------------------------------------------------------- + +test_str = ('' + 'some |23 textwith subscript' + ' some other text') + +test_str2 = 'big green text' + + +class TestPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, -1) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + + w, h = fancytext.GetExtent(test_str, dc) + fancytext.RenderToDC(test_str, dc, 20, 20) + + fancytext.RenderToDC(test_str2, dc, 20, 20 + h + 10) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb) + return win + +#---------------------------------------------------------------------- + + + +overview = \ +""" + + +

FancyText -- methods for rendering XML specified text

+ +

This module exports four main methods:: +

+    def GetExtent(str, dc=None, enclose=True)
+    def GetFullExtent(str, dc=None, enclose=True)
+    def RenderToBitmap(str, background=None, enclose=True)
+    def RenderToDC(str, dc, x, y, enclose=True)
+
+ +In all cases, 'str' is an XML string. Note that start and end tags +are only required if *enclose* is set to False. In this case the +text should be wrapped in FancyText tags. + +

In addition, the module exports one class:: +

+    class StaticFancyText(self, window, id, text, background, ...)
+
+This class works similar to StaticText except it interprets its text +as FancyText. + +

The text can supportsuperscripts and subscripts, text +in different sizes, colors, +styles, weights and +families. It also supports a limited set of symbols, +currently , , as well as greek letters in both +upper case (...) and lower case (...). + + +The End + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/FileBrowseButton.py b/demo/FileBrowseButton.py new file mode 100644 index 00000000..2af110a9 --- /dev/null +++ b/demo/FileBrowseButton.py @@ -0,0 +1,99 @@ + +""" Demonstrate filebrowsebutton module of the wxPython.lib Library. + +14.1.2001 Bernhard Reiter + Added demo for DirBrowseButton and improved overview text. +""" + +import wx +import wx.lib.filebrowsebutton as filebrowse + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, ID, log): + wx.Panel.__init__(self, parent, ID) + self.log = log + + self.fbb = filebrowse.FileBrowseButton( + self, -1, size=(450, -1), changeCallback = self.fbbCallback + ) + + self.fbbh = filebrowse.FileBrowseButtonWithHistory( + self, -1, size=(450, -1), changeCallback = self.fbbhCallback + ) + + self.dbb = filebrowse.DirBrowseButton( + self, -1, size=(450, -1), changeCallback = self.dbbCallback + ) + + self.fbbh.callCallback = False + self.fbbh.SetHistory(['You', 'can', 'put', 'some', 'filenames', 'here'], 4) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.fbb, 0, wx.ALL, 5) + sizer.Add(self.fbbh, 0, wx.ALL, 5) + sizer.Add(self.dbb, 0, wx.ALL, 5) + box = wx.BoxSizer() + box.Add(sizer, 0, wx.ALL, 20) + self.SetSizer(box) + + + def fbbCallback(self, evt): + self.log.write('FileBrowseButton: %s\n' % evt.GetString()) + + + def fbbhCallback(self, evt): + if hasattr(self, 'fbbh'): + value = evt.GetString() + if not value: + return + self.log.write('FileBrowseButtonWithHistory: %s\n' % value) + history = self.fbbh.GetHistory() + if value not in history: + history.append(value) + self.fbbh.SetHistory(history) + self.fbbh.GetHistoryControl().SetStringSelection(value) + + + def dbbCallback(self, evt): + self.log.write('DirBrowseButton: %s\n' % evt.GetString()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, -1, log) + return win + + +#---------------------------------------------------------------------- + +overview = """ +

class FileBrowseButton:

+
+%s
+
+ +

class FileBrowseButtonWithHistory(FileBrowseButton):

+
+%s
+
+ +

class DirBrowseButton(FileBrowseButton):

+
+%s
+
+ +< +""" % ( filebrowse.FileBrowseButton.__doc__, + filebrowse.FileBrowseButtonWithHistory.__doc__ , + filebrowse.DirBrowseButton.__doc__ + ) + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/FileDialog.py b/demo/FileDialog.py new file mode 100644 index 00000000..da832540 --- /dev/null +++ b/demo/FileDialog.py @@ -0,0 +1,143 @@ + +import os +import wx + +#--------------------------------------------------------------------------- + +# This is how you pre-establish a file filter so that the dialog +# only shows the extension(s) you want it to. +wildcard = "Python source (*.py)|*.py|" \ + "Compiled Python (*.pyc)|*.pyc|" \ + "SPAM files (*.spam)|*.spam|" \ + "Egg file (*.egg)|*.egg|" \ + "All files (*.*)|*.*" + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show an OPEN FileDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + b = wx.Button(self, -1, "Create and Show a SAVE FileDialog", (50,90)) + self.Bind(wx.EVT_BUTTON, self.OnButton2, b) + + + def OnButton(self, evt): + self.log.WriteText("CWD: %s\n" % os.getcwd()) + + # Create the dialog. In this case the current directory is forced as the starting + # directory for the dialog, and no default file name is forced. This can easilly + # be changed in your program. This is an 'open' dialog, and allows multitple + # file selections as well. + # + # Finally, if the directory is changed in the process of getting files, this + # dialog is set up to change the current working directory to the path chosen. + dlg = wx.FileDialog( + self, message="Choose a file", + defaultDir=os.getcwd(), + defaultFile="", + wildcard=wildcard, + style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR + ) + + # Show the dialog and retrieve the user response. If it is the OK response, + # process the data. + if dlg.ShowModal() == wx.ID_OK: + # This returns a Python list of files that were selected. + paths = dlg.GetPaths() + + self.log.WriteText('You selected %d files:' % len(paths)) + + for path in paths: + self.log.WriteText(' %s\n' % path) + + # Compare this with the debug above; did we change working dirs? + self.log.WriteText("CWD: %s\n" % os.getcwd()) + + # Destroy the dialog. Don't do this until you are done with it! + # BAD things can happen otherwise! + dlg.Destroy() + + + + def OnButton2(self, evt): + self.log.WriteText("CWD: %s\n" % os.getcwd()) + + # Create the dialog. In this case the current directory is forced as the starting + # directory for the dialog, and no default file name is forced. This can easilly + # be changed in your program. This is an 'save' dialog. + # + # Unlike the 'open dialog' example found elsewhere, this example does NOT + # force the current working directory to change if the user chooses a different + # directory than the one initially set. + dlg = wx.FileDialog( + self, message="Save file as ...", defaultDir=os.getcwd(), + defaultFile="", wildcard=wildcard, style=wx.SAVE + ) + + # This sets the default filter that the user will initially see. Otherwise, + # the first filter in the list will be used by default. + dlg.SetFilterIndex(2) + + # Show the dialog and retrieve the user response. If it is the OK response, + # process the data. + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + self.log.WriteText('You selected "%s"' % path) + + # Normally, at this point you would save your data using the file and path + # data that the user provided to you, but since we didn't actually start + # with any data to work with, that would be difficult. + # + # The code to do so would be similar to this, assuming 'data' contains + # the data you want to save: + # + # fp = file(path, 'w') # Create file anew + # fp.write(data) + # fp.close() + # + # You might want to add some error checking :-) + # + + # Note that the current working dir didn't change. This is good since + # that's the way we set it up. + self.log.WriteText("CWD: %s\n" % os.getcwd()) + + # Destroy the dialog. Don't do this until you are done with it! + # BAD things can happen otherwise! + dlg.Destroy() + + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ +This class provides the file selection dialog. It incorporates OS-native features +depending on the OS in use, and can be used both for open and save operations. +The files displayed can be filtered by setting up a wildcard filter, multiple files +can be selected (open only), and files can be forced in a read-only mode. + +There are two ways to get the results back from the dialog. GetFiles() returns only +the file names themselves, in a Python list. GetPaths() returns the full path and +filenames combined as a Python list. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/FileHistory.py b/demo/FileHistory.py new file mode 100644 index 00000000..b94b4567 --- /dev/null +++ b/demo/FileHistory.py @@ -0,0 +1,143 @@ + +import os +import wx + +#---------------------------------------------------------------------- + +text = """\ +Right-click on the panel above the line to get a menu. This menu will +be managed by a FileHistory object and so the files you select will +automatically be added to the end of the menu and will be selectable +the next time the menu is viewed. The filename selected, either via the +Open menu item, or from the history, will be displayed in the log +window below. +""" + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + box = wx.BoxSizer(wx.VERTICAL) + + # Make and layout the controls + fs = self.GetFont().GetPointSize() + bf = wx.Font(fs+4, wx.SWISS, wx.NORMAL, wx.BOLD) + nf = wx.Font(fs+2, wx.SWISS, wx.NORMAL, wx.NORMAL) + + t = wx.StaticText(self, -1, "FileHistory") + t.SetFont(bf) + box.Add(t, 0, wx.CENTER|wx.ALL, 5) + + box.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) + box.Add((10,20)) + + t = wx.StaticText(self, -1, text) + t.SetFont(nf) + box.Add(t, 0, wx.CENTER|wx.ALL, 5) + + self.SetSizer(box) + self.SetAutoLayout(True) + + # Make a menu + self.menu = m = wx.Menu() + + # Little know wx Fact #42: there are a number of pre-set IDs + # in the wx package, to be used for common controls such as those + # illustrated below. Neat, huh? + m.Append(wx.ID_NEW, "&New") + m.Append(wx.ID_OPEN, "&Open...") + m.Append(wx.ID_CLOSE, "&Close") + m.Append(wx.ID_SAVE, "&Save") + m.Append(wx.ID_SAVEAS, "Save &as...") + m.Enable(wx.ID_NEW, False) + m.Enable(wx.ID_CLOSE, False) + m.Enable(wx.ID_SAVE, False) + m.Enable(wx.ID_SAVEAS, False) + + # and a file history + self.filehistory = wx.FileHistory() + self.filehistory.UseMenu(self.menu) + + # and finally the event handler bindings + self.Bind(wx.EVT_RIGHT_UP, self.OnRightClick) + + self.Bind(wx.EVT_MENU, self.OnFileOpenDialog, id=wx.ID_OPEN) + + self.Bind( + wx.EVT_MENU_RANGE, self.OnFileHistory, id=wx.ID_FILE1, id2=wx.ID_FILE9 + ) + + self.Bind(wx.EVT_WINDOW_DESTROY, self.Cleanup) + + + def Cleanup(self, *args): + # A little extra cleanup is required for the FileHistory control + del self.filehistory + self.menu.Destroy() + + + def OnRightClick(self, evt): + self.PopupMenu(self.menu) + + + def OnFileOpenDialog(self, evt): + dlg = wx.FileDialog(self, + defaultDir = os.getcwd(), + wildcard = "All Files|*", + style = wx.OPEN | wx.CHANGE_DIR) + + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + self.log.write("You selected %s\n" % path) + + # add it to the history + self.filehistory.AddFileToHistory(path) + + dlg.Destroy() + + + def OnFileHistory(self, evt): + # get the file based on the menu ID + fileNum = evt.GetId() - wx.ID_FILE1 + path = self.filehistory.GetHistoryFile(fileNum) + self.log.write("You selected %s\n" % path) + + # add it back to the history so it will be moved up the list + self.filehistory.AddFileToHistory(path) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

FileHistory

+ +wxFileHistory encapsulates functionality to record the last few files +visited, and to allow the user to quickly load these files using the +list appended to a menu, such as the File menu. + +

Note that this inclusion is not automatic; as illustrated in this example, +you must add files (and remove them) as deemed necessary within the framework +of your program. + +

Note also the additional cleanup required for this class, namely trapping the +enclosing window's Destroy event and deleting the file history control and its +associated menu. + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/FindReplaceDialog.py b/demo/FindReplaceDialog.py new file mode 100644 index 00000000..b27a83ce --- /dev/null +++ b/demo/FindReplaceDialog.py @@ -0,0 +1,121 @@ +# 11/17/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Updated for wx namespace +# +# 11/28/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Changed the event binding slightly. + + +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + self.findData = wx.FindReplaceData() + + self.fbtn = wx.Button(self, -1, "Show Find Dialog", (25, 50)) + self.Bind(wx.EVT_BUTTON, self.OnShowFind, self.fbtn) + + self.frbtn = wx.Button(self, -1, "Show Find && Replace Dialog", (25, 90)) + self.Bind(wx.EVT_BUTTON, self.OnShowFindReplace, self.frbtn) + + def BindFindEvents(self, win): + win.Bind(wx.EVT_FIND, self.OnFind) + win.Bind(wx.EVT_FIND_NEXT, self.OnFind) + win.Bind(wx.EVT_FIND_REPLACE, self.OnFind) + win.Bind(wx.EVT_FIND_REPLACE_ALL, self.OnFind) + win.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose) + + def EnableButtons(self): + self.fbtn.Enable() + self.frbtn.Enable() + + def DisableButtons(self): + self.fbtn.Disable() + self.frbtn.Disable() + + def OnShowFind(self, evt): + self.DisableButtons() + dlg = wx.FindReplaceDialog(self, self.findData, "Find") + self.BindFindEvents(dlg) + dlg.Show(True) + + + def OnShowFindReplace(self, evt): + self.DisableButtons() + dlg = wx.FindReplaceDialog(self, self.findData, "Find & Replace", wx.FR_REPLACEDIALOG) + self.BindFindEvents(dlg) + dlg.Show(True) + + + def OnFind(self, evt): + #print repr(evt.GetFindString()), repr(self.findData.GetFindString()) + map = { + wx.wxEVT_COMMAND_FIND : "FIND", + wx.wxEVT_COMMAND_FIND_NEXT : "FIND_NEXT", + wx.wxEVT_COMMAND_FIND_REPLACE : "REPLACE", + wx.wxEVT_COMMAND_FIND_REPLACE_ALL : "REPLACE_ALL", + } + + et = evt.GetEventType() + + if et in map: + evtType = map[et] + else: + evtType = "**Unknown Event Type**" + + if et in [wx.wxEVT_COMMAND_FIND_REPLACE, wx.wxEVT_COMMAND_FIND_REPLACE_ALL]: + replaceTxt = "Replace text: %s" % evt.GetReplaceString() + else: + replaceTxt = "" + + self.log.write("%s -- Find text: %s %s Flags: %d \n" % + (evtType, evt.GetFindString(), replaceTxt, evt.GetFlags())) + + + def OnFindClose(self, evt): + self.log.write("FindReplaceDialog closing...\n") + evt.GetDialog().Destroy() + self.EnableButtons() + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + + + +overview = """\ +FindReplaceDialog is a standard modeless dialog which is used to allow the user +to search for some text (and possibly replace it with something else). The actual +searching is supposed to be done in the owner window which is the parent of this +dialog. Note that it means that unlike for the other standard dialogs this one +must have a parent window. Also note that there is no way to use this +dialog in a modal way; it is always, by design and implementation, modeless. + +FileReplaceDialog requires the use of FindReplaceData. This holds the +data for the dialog. It is used to initialize the dialog with the default values +and will keep the last values from the dialog when it is closed. It is also +updated each time a FindDialogEvent is generated so instead of using the +FindDialogEvent methods you can also directly query this object. Care must be +taken not to use this object after the dialog is destroyed. The data within +will be invalid after the parent dialog is destroyed. +""" + + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/FloatBar.py b/demo/FloatBar.py new file mode 100644 index 00000000..8f85d6e2 --- /dev/null +++ b/demo/FloatBar.py @@ -0,0 +1,145 @@ +# +# Please note that wx.lib.floatbar is not formally supported as +# part of wxPython. If it works, fine. If not, unfortunate. +# GTK users can use the wx.TB_DOCKABLE flag with a regular +# wx.ToolBar, but everyone else has to take their chances. +# + +import wx +import wx.lib.floatbar + +import images + + +class TestFloatBar(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__( + self, parent, -1, 'Test ToolBar', wx.DefaultPosition, (500, 300) + ) + + self.log = log + + win = wx.Window(self, -1) + win.SetBackgroundColour("WHITE") + wx.StaticText( + win, -1, "Drag the toolbar to float it,\n" + "Toggle the last tool to remove\nthe title.", (15,15) + ) + + tb = wx.lib.floatbar.FloatBar(self, -1) + self.SetToolBar(tb) + tb.SetFloatable(1) + tb.SetTitle("Floating!") + self.CreateStatusBar() + + tsize = (16,16) + new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, tsize) + open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize) + copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR, tsize) + paste_bmp= wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR, tsize) + + tb.AddSimpleTool(10, new_bmp, "New", "Long help for 'New'") + self.Bind(wx.EVT_TOOL, self.OnToolClick, id=10) + self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=10) + + tb.AddSimpleTool(20, open_bmp, "Open") + self.Bind(wx.EVT_TOOL, self.OnToolClick, id=20) + self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=20) + + tb.AddSeparator() + tb.AddSimpleTool(30, copy_bmp, "Copy") + self.Bind(wx.EVT_TOOL, self.OnToolClick, id=30) + self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=30) + + tb.AddSimpleTool(40, paste_bmp, "Paste") + self.Bind(wx.EVT_TOOL, self.OnToolClick, id=40) + self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=40) + + tb.AddSeparator() + + tb.AddCheckTool(60, images.Tog1.GetBitmap(), images.Tog2.GetBitmap()) + self.Bind(wx.EVT_TOOL, self.OnToolClick, id=60) + self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=60) + + tb.Realize() + + self.tb = tb + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + + def OnCloseWindow(self, event): + self.Destroy() + + def OnToolClick(self, event): + self.log.WriteText("tool %s clicked\n" % event.GetId()) + + if event.GetId() == 60: + print event.GetExtraLong(), event.IsChecked(), event.GetInt(), self.tb.GetToolState(60) + + if event.GetExtraLong(): + self.tb.SetTitle("") + else: + self.tb.SetTitle("Floating!") + + def OnToolRClick(self, event): + self.log.WriteText("tool %s right-clicked\n" % event.GetId()) + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show the FloatBar sample", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + if wx.Platform == "__WXMAC__": + dlg = wx.MessageDialog( + self, 'FloatBar does not work well on this platform.', + 'Sorry', wx.OK | wx.ICON_WARNING + ) + dlg.ShowModal() + dlg.Destroy() + else: + win = TestFloatBar(self, self.log) + win.Show(True) + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + +overview = """\ +FloatBar is a subclass of wx.ToolBar, implemented in Python, which +can be detached from its frame. + +Drag the toolbar with the mouse to make it float, and drag it back, or +close it to make the toolbar return to its original position. + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + + + + + + + + + + + diff --git a/demo/FloatCanvas.py b/demo/FloatCanvas.py new file mode 100644 index 00000000..86919bd0 --- /dev/null +++ b/demo/FloatCanvas.py @@ -0,0 +1,1960 @@ +#!/usr/bin/env python + +try: + import numpy as N + import numpy.random as RandomArray + haveNumpy = True + #print "Using numpy, version:", N.__version__ +except ImportError: + # numpy isn't there + haveNumpy = False + errorText = ( + "The FloatCanvas requires the numpy module, version 1.* \n\n" + "You can get info about it at:\n" + "http://numpy.scipy.org/\n\n" + ) + +#--------------------------------------------------------------------------- + + +def BuildDrawFrame(): # this gets called when needed, rather than on import + try: + from floatcanvas import NavCanvas, FloatCanvas, Resources + except ImportError: # if it's not there locally, try the wxPython lib. + from wx.lib.floatcanvas import NavCanvas, FloatCanvas, Resources + import wx.lib.colourdb + import time, random + + 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() + + file_menu = wx.Menu() + item = file_menu.Append(-1, "&Close","Close this frame") + self.Bind(wx.EVT_MENU, self.OnQuit, item) + + item = file_menu.Append(-1, "&SavePNG","Save the current image as a PNG") + self.Bind(wx.EVT_MENU, self.OnSavePNG, item) + MenuBar.Append(file_menu, "&File") + + draw_menu = wx.Menu() + + item = draw_menu.Append(-1, "&Clear","Clear the Canvas") + self.Bind(wx.EVT_MENU, self.Clear, item) + + item = draw_menu.Append(-1, "&Draw Test","Run a test of drawing random components") + self.Bind(wx.EVT_MENU, self.DrawTest, item) + + item = draw_menu.Append(-1, "&Line Test","Run a test of drawing random lines") + self.Bind(wx.EVT_MENU, self.LineTest, item) + + item = draw_menu.Append(-1, "Draw &Map","Run a test of drawing a map") + self.Bind(wx.EVT_MENU, self.DrawMap, item) + + item = draw_menu.Append(-1, "&Text Test","Run a test of text drawing") + self.Bind(wx.EVT_MENU, self.TestText, item) + + item = draw_menu.Append(-1, "&ScaledText Test","Run a test of text drawing") + self.Bind(wx.EVT_MENU, self.TestScaledText, item) + + item = draw_menu.Append(-1, "&ScaledTextBox Test","Run a test of the Scaled Text Box") + self.Bind(wx.EVT_MENU, self.TestScaledTextBox, item) + + item = draw_menu.Append(-1, "&Bitmap Test","Run a test of the Bitmap Object") + self.Bind(wx.EVT_MENU, self.TestBitmap, item) + + item = draw_menu.Append(-1, "&Hit Test","Run a test of the hit test code") + self.Bind(wx.EVT_MENU, self.TestHitTest, item) + + item = draw_menu.Append(-1, "Hit Test &Foreground","Run a test of the hit test code with a foreground Object") + self.Bind(wx.EVT_MENU, self.TestHitTestForeground, item) + + item = draw_menu.Append(-1, "&Animation","Run a test of Animation") + self.Bind(wx.EVT_MENU, self.TestAnimation, item) + + #item = draw_menu.Append(-1, "&Speed","Run a test of Drawing Speed") + #self.Bind(wx.EVT_MENU, self.SpeedTest, item) + + item = draw_menu.Append(-1, "Change &Properties","Run a test of Changing Object Properties") + self.Bind(wx.EVT_MENU, self.PropertiesChangeTest, item) + + item = draw_menu.Append(-1, "&Arrows","Run a test of Arrows") + self.Bind(wx.EVT_MENU, self.ArrowTest, item) + + item = draw_menu.Append(-1, "&ArrowLine Test","Run a test of drawing Arrow Lines") + self.Bind(wx.EVT_MENU, self.ArrowLineTest, item) + + item = draw_menu.Append(-1, "&Hide","Run a test of hiding and showing objects") + self.Bind(wx.EVT_MENU, self.HideTest, item) + + MenuBar.Append(draw_menu, "&Tests") + + view_menu = wx.Menu() + item = view_menu.Append(-1, "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(-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 + NC = NavCanvas.NavCanvas(self, + Debug = 0, + BackgroundColor = "DARK SLATE BLUE") + + self.Canvas = NC.Canvas # reference the contained FloatCanvas + + self.MsgWindow = wx.TextCtrl(self, wx.ID_ANY, + "Look Here for output from events\n", + style = (wx.TE_MULTILINE | + wx.TE_READONLY | + wx.SUNKEN_BORDER) + ) + + ##Create a sizer to manage the Canvas and message window + MainSizer = wx.BoxSizer(wx.VERTICAL) + MainSizer.Add(NC, 4, wx.EXPAND) + MainSizer.Add(self.MsgWindow, 1, wx.EXPAND | wx.ALL, 5) + + self.SetSizer(MainSizer) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + self.Canvas.Bind(FloatCanvas.EVT_MOTION, self.OnMove) + self.Canvas.Bind(FloatCanvas.EVT_MOUSEWHEEL, self.OnWheel) + + self.EventsAreBound = False + + ## getting all the colors for random objects + wx.lib.colourdb.updateColourDB() + self.colors = wx.lib.colourdb.getColourList() + + + return None + + def Log(self, text): + self.MsgWindow.AppendText(text) + if not text[-1] == "\n": + self.MsgWindow.AppendText("\n") + + + def BindAllMouseEvents(self): + if not self.EventsAreBound: + ## Here is how you catch FloatCanvas mouse events + self.Canvas.Bind(FloatCanvas.EVT_LEFT_DOWN, self.OnLeftDown) + self.Canvas.Bind(FloatCanvas.EVT_LEFT_UP, self.OnLeftUp) + self.Canvas.Bind(FloatCanvas.EVT_LEFT_DCLICK, self.OnLeftDouble) + + self.Canvas.Bind(FloatCanvas.EVT_MIDDLE_DOWN, self.OnMiddleDown) + self.Canvas.Bind(FloatCanvas.EVT_MIDDLE_UP, self.OnMiddleUp) + self.Canvas.Bind(FloatCanvas.EVT_MIDDLE_DCLICK, self.OnMiddleDouble) + + self.Canvas.Bind(FloatCanvas.EVT_RIGHT_DOWN, self.OnRightDown) + self.Canvas.Bind(FloatCanvas.EVT_RIGHT_UP, self.OnRightUp) + self.Canvas.Bind(FloatCanvas.EVT_RIGHT_DCLICK, self.OnRightDouble) + + self.EventsAreBound = True + + + def UnBindAllMouseEvents(self): + ## Here is how you unbind FloatCanvas mouse events + self.Canvas.Unbind(FloatCanvas.EVT_LEFT_DOWN) + self.Canvas.Unbind(FloatCanvas.EVT_LEFT_UP) + self.Canvas.Unbind(FloatCanvas.EVT_LEFT_DCLICK) + + self.Canvas.Unbind(FloatCanvas.EVT_MIDDLE_DOWN) + self.Canvas.Unbind(FloatCanvas.EVT_MIDDLE_UP) + self.Canvas.Unbind(FloatCanvas.EVT_MIDDLE_DCLICK) + + self.Canvas.Unbind(FloatCanvas.EVT_RIGHT_DOWN) + self.Canvas.Unbind(FloatCanvas.EVT_RIGHT_UP) + self.Canvas.Unbind(FloatCanvas.EVT_RIGHT_DCLICK) + + self.EventsAreBound = False + + + def PrintCoords(self,event): + self.Log("coords are: %s"%(event.Coords,)) + self.Log("pixel coords are: %s\n"%(event.GetPosition(),)) + + def OnSavePNG(self, event=None): + import os + dlg = wx.FileDialog( + self, message="Save file as ...", defaultDir=os.getcwd(), + defaultFile="", wildcard="*.png", style=wx.SAVE + ) + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + if not(path[-4:].lower() == ".png"): + path = path+".png" + self.Canvas.SaveAsImage(path) + + + def OnLeftDown(self, event): + self.Log("LeftDown") + self.PrintCoords(event) + + def OnLeftUp(self, event): + self.Log("LeftUp") + self.PrintCoords(event) + + def OnLeftDouble(self, event): + self.Log("LeftDouble") + self.PrintCoords(event) + + def OnMiddleDown(self, event): + self.Log("MiddleDown") + self.PrintCoords(event) + + def OnMiddleUp(self, event): + self.Log("MiddleUp") + self.PrintCoords(event) + + def OnMiddleDouble(self, event): + self.Log("MiddleDouble") + self.PrintCoords(event) + + def OnRightDown(self, event): + self.Log("RightDown") + self.PrintCoords(event) + + def OnRightUp(self, event): + self.Log("RightUp") + self.PrintCoords(event) + + def OnRightDouble(self, event): + self.Log("RightDouble") + self.PrintCoords(event) + + def OnWheel(self, event): + self.Log("Mouse Wheel") + self.PrintCoords(event) + Rot = event.GetWheelRotation() + Rot = Rot / abs(Rot) * 0.1 + if event.ControlDown(): # move left-right + self.Canvas.MoveImage( (Rot, 0), "Panel" ) + else: # move up-down + self.Canvas.MoveImage( (0, Rot), "Panel" ) + + def OnMove(self, event): + """ + Updates the status bar with the world coordinates + """ + self.SetStatusText("%.2f, %.2f"%tuple(event.Coords)) + 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.UnBindAllMouseEvents() + self.Canvas.InitAll() + self.Canvas.Draw() + + def OnQuit(self,event): + self.Close(True) + + def OnCloseWindow(self, event): + self.Destroy() + + def DrawTest(self,event=None): + """ + This demo draws a few of everything + + """ + + wx.GetApp().Yield(True) + + Range = (-10,10) + colors = self.colors + + self.BindAllMouseEvents() + Canvas = self.Canvas + + Canvas.InitAll() + # + ## these set the limits for how much you can zoom in and out + Canvas.MinScale = 14 + Canvas.MaxScale = 500 + + + ############# Random tests of everything ############## + + # Rectangles + for i in range(3): + xy = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + lw = random.randint(1,5) + cf = random.randint(0,len(colors)-1) + wh = (random.randint(1,5), random.randint(1,5)) + Canvas.AddRectangle(xy, wh, LineWidth = lw, FillColor = colors[cf]) + + # Ellipses + for i in range(3): + xy = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + lw = random.randint(1,5) + cf = random.randint(0,len(colors)-1) + h = random.randint(1,5) + w = random.randint(1,5) + Canvas.AddEllipse(xy, (h,w), LineWidth = lw,FillColor = colors[cf]) + + # Points + for i in range(5): + xy = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + D = random.randint(1,50) + cf = random.randint(0,len(colors)-1) + Canvas.AddPoint(xy, Color = colors[cf], Diameter = D) + + # SquarePoints + for i in range(500): + xy = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + S = random.randint(1, 50) + cf = random.randint(0,len(colors)-1) + Canvas.AddSquarePoint(xy, Color = colors[cf], Size = S) + + # Circles + for i in range(5): + xy = (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(colors)-1) + cl = random.randint(0,len(colors)-1) + Canvas.AddCircle(xy, D, LineWidth = lw, LineColor = colors[cl], FillColor = colors[cf]) + Canvas.AddText("Circle # %i"%(i), xy, Size = 12, BackgroundColor = None, 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(colors)-1) + cl = random.randint(0,len(colors)-1) + Canvas.AddLine(points, LineWidth = lw, LineColor = 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(colors)-1) + cl = random.randint(0,len(colors)-1) + Canvas.AddPolygon(points, + LineWidth = lw, + LineColor = colors[cl], + FillColor = colors[cf], + FillStyle = 'Solid') + + ## Pointset + for i in range(4): + points = [] + points = RandomArray.uniform(Range[0],Range[1],(100,2)) + cf = random.randint(0,len(colors)-1) + D = random.randint(1,4) + Canvas.AddPointSet(points, Color = colors[cf], Diameter = D) + + # Text + String = "Unscaled text" + for i in range(3): + ts = random.randint(10,40) + cf = random.randint(0,len(colors)-1) + xy = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + Canvas.AddText(String, xy, Size = ts, Color = colors[cf], Position = "cc") + + # Scaled Text + String = "Scaled text" + for i in range(3): + ts = random.random()*3 + 0.2 + cf = random.randint(0,len(colors)-1) + Point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + Canvas.AddScaledText(String, Point, Size = ts, Color = colors[cf], Position = "cc") + + # Arrows + N = 5 + Points = RandomArray.uniform(Range[0], Range[1], (N,2) ) + for i in range(N): + Canvas.AddArrow(Points[i], + random.uniform(20,100), + Direction = random.uniform(0,360), + LineWidth = random.uniform(1,5), + LineColor = colors[random.randint(0,len(colors)-1)], + ArrowHeadAngle = random.uniform(20,90)) + + # ArrowLines + 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(colors)-1) + cl = random.randint(0,len(colors)-1) + Canvas.AddArrowLine(points, LineWidth = lw, LineColor = colors[cl], ArrowHeadSize= 16) + + + Canvas.ZoomToBB() + + def TestAnimation(self,event=None): + """ + + In this test, a relatively complex background is drawn, and + a simple object placed in the foreground is moved over + it. This demonstrates how to use the InForeground attribute + to make an object in the foregorund draw fast, without + having to re-draw the whole background. + + """ + wx.GetApp().Yield(True) + Range = (-10,10) + self.Range = Range + + self.UnBindAllMouseEvents() + Canvas = self.Canvas + Canvas.InitAll() + + ## Random tests of everything: + colors = self.colors + # Rectangles + for i in range(3): + xy = (random.uniform(Range[0],Range[1]), random.uniform(Range[0],Range[1])) + lw = random.randint(1,5) + cf = random.randint(0,len(colors)-1) + wh = (random.randint(1,5), random.randint(1,5) ) + Canvas.AddRectangle(xy, wh, LineWidth = lw, FillColor = colors[cf]) + + # Ellipses + for i in range(3): + xy = (random.uniform(Range[0],Range[1]), random.uniform(Range[0],Range[1])) + lw = random.randint(1,5) + cf = random.randint(0,len(colors)-1) + wh = (random.randint(1,5), random.randint(1,5) ) + Canvas.AddEllipse(xy, wh, LineWidth = lw, FillColor = colors[cf]) + + # Circles + for i in range(5): + xy = (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(colors)-1) + cl = random.randint(0,len(colors)-1) + Canvas.AddCircle(xy, D, LineWidth = lw, LineColor = colors[cl], FillColor = colors[cf]) + Canvas.AddText("Circle # %i"%(i), xy, Size = 12, BackgroundColor = None, 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(colors)-1) + cl = random.randint(0,len(colors)-1) + Canvas.AddLine(points, LineWidth = lw, LineColor = 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(colors)-1) + cl = random.randint(0,len(colors)-1) + Canvas.AddPolygon(points, + LineWidth = lw, + LineColor = colors[cl], + FillColor = colors[cf], + FillStyle = 'Solid') + + # Scaled Text + String = "Scaled text" + for i in range(3): + ts = random.random()*3 + 0.2 + cf = random.randint(0,len(colors)-1) + xy = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + Canvas.AddScaledText(String, xy, Size = ts, Color = colors[cf], Position = "cc") + + + # Now the Foreground Object: + C = Canvas.AddCircle((0,0), 7, LineWidth = 2,LineColor = "Black",FillColor = "Red", InForeground = True) + T = Canvas.AddScaledText("Click to Move", (0,0), Size = 0.6, Position = 'cc', InForeground = True) + C.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.MoveMe) + C.Text = T + + self.Timer = wx.PyTimer(self.ShowFrame) + self.FrameDelay = 50 # milliseconds + + Canvas.ZoomToBB() + + def ShowFrame(self): + Object = self.MovingObject + Range = self.Range + if self.TimeStep < self.NumTimeSteps: + x,y = Object.XY + if x > Range[1] or x < Range[0]: + self.dx = -self.dx + if y > Range[1] or y < Range[0]: + self.dy = -self.dy + Object.Move( (self.dx,self.dy) ) + Object.Text.Move( (self.dx,self.dy)) + self.Canvas.Draw() + self.TimeStep += 1 + wx.GetApp().Yield(True) + else: + self.Timer.Stop() + + + def MoveMe(self, Object): + self.MovingObject = Object + Range = self.Range + self.dx = random.uniform(Range[0]/4,Range[1]/4) + self.dy = random.uniform(Range[0]/4,Range[1]/4) + #import time + #start = time.time() + self.NumTimeSteps = 200 + self.TimeStep = 1 + self.Timer.Start(self.FrameDelay) + #print "Did %i frames in %f seconds"%(N, (time.time() - start) ) + + def TestHitTest(self, event=None): + wx.GetApp().Yield(True) + + self.UnBindAllMouseEvents() + Canvas = self.Canvas + + Canvas.InitAll() + + #Add a Hit-able rectangle + w, h = 60, 20 + + dx = 80 + dy = 40 + x, y = 20, 20 + FontSize = 8 + + #Add one that is not HitAble + Canvas.AddRectangle((x,y), (w, h), LineWidth = 2) + Canvas.AddText("Not Hit-able", (x,y), Size = FontSize, Position = "bl") + + + x += dx + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2) + R.Name = "Line Rectangle" + R.HitFill = False + R.HitLineWidth = 5 # Makes it a little easier to hit + R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectGotHit) + Canvas.AddText("Left Click Line", (x,y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "Red" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + "Rectangle" + R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectGotHit) + Canvas.AddText("Left Click Fill", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x = 20 + y += dy + color = "LightBlue" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + " Rectangle" + R.Bind(FloatCanvas.EVT_FC_RIGHT_DOWN, self.RectGotHit) + Canvas.AddText("Right Click Fill", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "Grey" + R = Canvas.AddEllipse((x, y), (w, h),LineWidth = 2,FillColor = color) + R.Name = color +" Ellipse" + R.Bind(FloatCanvas.EVT_FC_RIGHT_DOWN, self.RectGotHit) + Canvas.AddText("Right Click Fill", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "Brown" + R = Canvas.AddCircle((x+dx/2, y+dy/2), dx/4, LineWidth = 2, FillColor = color) + R.Name = color + " Circle" + R.HitFill = True + R.Bind(FloatCanvas.EVT_FC_LEFT_DCLICK, self.RectGotHit) + Canvas.AddText("Left D-Click Fill", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x = 20 + y += dy + color = "Pink" + R = Canvas.AddCircle((x+dx/2, y+dy/2), dx/4, LineWidth = 2,FillColor = color) + R.Name = color + " Circle" + R.Bind(FloatCanvas.EVT_FC_LEFT_UP, self.RectGotHit) + Canvas.AddText("Left Up Fill", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "White" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + " Rectangle" + R.Bind(FloatCanvas.EVT_FC_MIDDLE_DOWN, self.RectGotHit) + Canvas.AddText("Middle Down", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "AQUAMARINE" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + " Rectangle" + R.Bind(FloatCanvas.EVT_FC_MIDDLE_UP, self.RectGotHit) + Canvas.AddText("Middle Up", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x = 20 + y += dy + color = "CORAL" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + " Rectangle" + R.Bind(FloatCanvas.EVT_FC_MIDDLE_DCLICK, self.RectGotHit) + Canvas.AddText("Middle DoubleClick", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "CYAN" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + " Rectangle" + R.Bind(FloatCanvas.EVT_FC_RIGHT_UP, self.RectGotHit) + Canvas.AddText("Right Up", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "LIME GREEN" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + " Rectangle" + R.Bind(FloatCanvas.EVT_FC_RIGHT_DCLICK, self.RectGotHit) + Canvas.AddText("Right Double Click", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x = 20 + y += dy + color = "MEDIUM GOLDENROD" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + R.Bind(FloatCanvas.EVT_FC_RIGHT_DOWN, self.RectGotHitRight) + R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectGotHitLeft) + Canvas.AddText("L and R Click", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "SALMON" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + " Rectangle" + R.Bind(FloatCanvas.EVT_FC_ENTER_OBJECT, self.RectMouseOver) + Canvas.AddText("Mouse Enter", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "MEDIUM VIOLET RED" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + R.Bind(FloatCanvas.EVT_FC_LEAVE_OBJECT, self.RectMouseLeave) + Canvas.AddText("Mouse Leave", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x = 20 + y += dy + color = "SKY BLUE" + R = Canvas.AddRectangle((x, y), (w, h), LineWidth = 2, FillColor = color) + R.Name = color + R.Bind(FloatCanvas.EVT_FC_ENTER_OBJECT, self.RectMouseOver) + R.Bind(FloatCanvas.EVT_FC_LEAVE_OBJECT, self.RectMouseLeave) + Canvas.AddText("Enter and Leave", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "WHEAT" + R = Canvas.AddRectangle((x, y), (w+12, h), LineColor = None, FillColor = color) + R.Name = color + R.Bind(FloatCanvas.EVT_FC_ENTER_OBJECT, self.RectMouseOver) + R.Bind(FloatCanvas.EVT_FC_LEAVE_OBJECT, self.RectMouseLeave) + Canvas.AddText("Mouse Enter&Leave", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "KHAKI" + R = Canvas.AddRectangle((x-12, y), (w+12, h), LineColor = None, FillColor = color) + R.Name = color + R.Bind(FloatCanvas.EVT_FC_ENTER_OBJECT, self.RectMouseOver) + R.Bind(FloatCanvas.EVT_FC_LEAVE_OBJECT, self.RectMouseLeave) + Canvas.AddText("Mouse Enter&Leave", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x = 20 + y += dy + L = Canvas.AddLine(( (x, y), (x+10, y+10), (x+w, y+h) ), LineWidth = 2, LineColor = "Red") + L.Name = "A Line" + L.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectGotHitLeft) + Canvas.AddText("Left Down", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(L.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "SEA GREEN" + Points = N.array(( (x, y), (x, y+2.*h/3), (x+w, y+h), (x+w, y+h/2.), (x + 2.*w/3, y+h/2.), (x + 2.*w/3,y) ), N.float_) + R = Canvas.AddPolygon(Points, LineWidth = 2, FillColor = color) + R.Name = color + " Polygon" + R.Bind(FloatCanvas.EVT_FC_RIGHT_DOWN, self.RectGotHitRight) + Canvas.AddText("RIGHT_DOWN", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x += dx + color = "Red" + Points = N.array(( (x, y), (x, y+2.*h/3), (x+w, y+h), (x+w, y+h/2.), (x + 2.*w/3, y+h/2.), (x + 2.*w/3,y) ), N.float_) + R = Canvas.AddPointSet(Points, Diameter = 4, Color = color) + R.Name = "PointSet" + R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.PointSetGotHit) + Canvas.AddText("LEFT_DOWN", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y+h), Size = FontSize, Position = "tl") + + x = 20 + y += dy + T = Canvas.AddText("Hit-able Text", (x, y), Size = 15, Color = "Red", Position = 'tl') + T.Name = "Hit-able Text" + T.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectGotHitLeft) + Canvas.AddText("Left Down", (x, y), Size = FontSize, Position = "bl") + + x += dx + T = Canvas.AddScaledText("Scaled Text", (x, y), Size = 1./2*h, Color = "Pink", Position = 'bl') + Canvas.AddPointSet( (x, y), Diameter = 3) + T.Name = "Scaled Text" + T.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectGotHitLeft) + Canvas.AddText("Left Down", (x, y), Size = FontSize, Position = "tl") + + x += dx + color = "Cyan" + Point = (x + w/2, y) + #Points = N.array(( (x, y), (x, y+2.*h/3), (x+w, y+h), (x+w, y+h/2.), (x + 2.*w/3, y+h/2.), (x + 2.*w/3,y) ), N.float_) + R = Canvas.AddSquarePoint(Point, Size = 8, Color = color) + R.Name = "SquarePoint" + R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectGotHit) + Canvas.AddText("LEFT_DOWN", (x, y), Size = FontSize, Position = "bl") + Canvas.AddText(R.Name, (x, y), Size = FontSize, Position = "tl") + + + self.Canvas.ZoomToBB() + + def TestHitTestForeground(self,event=None): + wx.GetApp().Yield(True) + + self.UnBindAllMouseEvents() + Canvas = self.Canvas + + Canvas.InitAll() + + #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, InForeground = False) + R.Name = color + "Rectangle" + R.HitFill = True + R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectGotHit) + Canvas.AddText("Left Click Fill", (x, y), Position = "bl") + 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 = [] + WH = (w/2, h/2) + x += dx + color = "LightBlue" + R = Canvas.AddRectangle((x, y), WH, LineWidth = 2, FillColor = color, InForeground = True) + R.HitFill = True + R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectMoveLeft) + L = Canvas.AddText("Left", (x + w/4, y + h/4), Position = "cc", InForeground = True) + self.MovingRects.extend( (R,L) ) + + x += w/2 + R = Canvas.AddRectangle((x, y), WH, LineWidth = 2, FillColor = color, InForeground = True) + R.HitFill = True + R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectMoveRight) + L = Canvas.AddText("Right", (x + w/4, y + h/4), Position = "cc", InForeground = True) + self.MovingRects.extend( (R,L) ) + + x -= w/2 + y += h/2 + R = Canvas.AddRectangle((x, y), WH, LineWidth = 2, FillColor = color, InForeground = True) + R.HitFill = True + R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectMoveUp) + L = Canvas.AddText("Up", (x + w/4, y + h/4), Position = "cc", InForeground = True) + self.MovingRects.extend( (R,L) ) + + + x += w/2 + R = Canvas.AddRectangle((x, y), WH, LineWidth = 2, FillColor = color, InForeground = True) + R.HitFill = True + R.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RectMoveDown) + L = Canvas.AddText("Down", (x + w/4, y + h/4), Position = "cc", InForeground = True) + 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() + + def PointSetGotHit(self, Object): + self.Log(Object.Name + "Got Hit\n") + + def RectGotHit(self, Object): + self.Log(Object.Name + "Got Hit\n") + + def RectGotHitRight(self, Object): + self.Log(Object.Name + "Got Hit With Right\n") + + def RectGotHitLeft(self, Object): + self.Log(Object.Name + "Got Hit with Left\n") + + def RectMouseOver(self, Object): + self.Log("Mouse entered:" + Object.Name) + + def RectMouseLeave(self, Object): + self.Log("Mouse left " + Object.Name) + + + def TestText(self, event= None): + wx.GetApp().Yield(True) + + self.BindAllMouseEvents() + Canvas = self.Canvas + Canvas.InitAll() + + + DefaultSize = 12 + Point = (3, 0) + + ## Add a non-visible rectangle, just to get a Bounding Box + ## Text objects have a zero-size bounding box, because it changes with zoom + Canvas.AddRectangle((-10,-10), + (20,20), + LineWidth = 1, + LineColor = None) + + # Text + String = "Some text" + self.Canvas.AddText("Top Left",Point,Size = DefaultSize,Color = "Yellow",BackgroundColor = "Blue", Position = "tl") + self.Canvas.AddText("Bottom Left",Point,Size = DefaultSize,Color = "Cyan",BackgroundColor = "Black",Position = "bl") + self.Canvas.AddText("Top Right",Point,Size = DefaultSize,Color = "Black",BackgroundColor = "Cyan",Position = "tr") + self.Canvas.AddText("Bottom Right",Point,Size = DefaultSize,Color = "Blue",BackgroundColor = "Yellow",Position = "br") + Canvas.AddPointSet((Point), Color = "White", Diameter = 2) + + Point = (3, 2) + + Canvas.AddPointSet((Point), Color = "White", Diameter = 2) + self.Canvas.AddText("Top Center",Point,Size = DefaultSize,Color = "Black",Position = "tc") + self.Canvas.AddText("Bottom Center",Point,Size = DefaultSize,Color = "White",Position = "bc") + + Point = (3, 4) + + Canvas.AddPointSet((Point), Color = "White", Diameter = 2) + self.Canvas.AddText("Center Right",Point,Size = DefaultSize,Color = "Black",Position = "cr") + self.Canvas.AddText("Center Left",Point,Size = DefaultSize,Color = "Black",Position = "cl") + + Point = (3, -2) + + Canvas.AddPointSet((Point), Color = "White", Diameter = 2) + self.Canvas.AddText("Center Center", + Point, Size = DefaultSize, + Color = "Black", + Position = "cc") + + self.Canvas.AddText("40 Pixels", (-10,8), Size = 40) + self.Canvas.AddText("20 Pixels", (-10,5), Size = 20) + self.Canvas.AddText("10 Pixels", (-10,3), Size = 10) + + self.Canvas.AddText("MODERN Font", (-10, 0), Family = wx.MODERN) + self.Canvas.AddText("DECORATIVE Font", (-10, -1), Family = wx.DECORATIVE) + self.Canvas.AddText("ROMAN Font", (-10, -2), Family = wx.ROMAN) + self.Canvas.AddText("SCRIPT Font", (-10, -3), Family = wx.SCRIPT) + self.Canvas.AddText("ROMAN BOLD Font", (-10, -4), Family = wx.ROMAN, Weight=wx.BOLD) + self.Canvas.AddText("ROMAN ITALIC BOLD Font", (-10, -5), Family = wx.ROMAN, Weight=wx.BOLD, Style=wx.ITALIC) + + # NOTE: this font exists on my Linux box..who knows were else you'll find it! + Font = wx.Font(20, wx.DEFAULT, wx.ITALIC, wx.NORMAL, False, "helvetica") + self.Canvas.AddText("Helvetica Italic", (-10, -6), Font = Font) + + self.Canvas.ZoomToBB() + + def TestScaledText(self, event= None): + wx.GetApp().Yield(True) + + self.BindAllMouseEvents() + Canvas = self.Canvas + Canvas.InitAll() + + Point = (0, 0) + + T = Canvas.AddScaledText("Top Left", + Point, + Size = 5, + Color = "Yellow", + BackgroundColor = "Blue", + Position = "tl") + T = Canvas.AddScaledText("Bottom Left",Point,Size = 5,Color = "Cyan",BackgroundColor = "Black",Position = "bl") + T = Canvas.AddScaledText("Top Right",Point,Size = 5,Color = "Black",BackgroundColor = "Cyan",Position = "tr") + T = Canvas.AddScaledText("Bottom Right",Point,Size = 5,Color = "Blue",BackgroundColor = "Yellow",Position = "br") + Canvas.AddPointSet((Point), Color = "Red", Diameter = 4) + + + Point = (0, 20) + + Canvas.AddScaledText("Top Center",Point,Size = 7,Color = "Black",Position = "tc") + Canvas.AddScaledText("Bottom Center",Point,Size = 7,Color = "White",Position = "bc") + Canvas.AddPointSet((Point), Color = "White", Diameter = 4) + + Point = (0, -20) + + Canvas.AddScaledText("Center Right",Point,Size = 9,Color = "Black",Position = "cr") + Canvas.AddScaledText("Center Left",Point,Size = 9,Color = "Black",Position = "cl") + Canvas.AddPointSet((Point), Color = "White", Diameter = 4) + + x = -200 + + self.Canvas.AddScaledText("MODERN Font", (x, 0), Size = 7, Family = wx.MODERN, Color = (0,0,0)) + self.Canvas.AddScaledText("DECORATIVE Font", (x, -10), Size = 7, Family = wx.DECORATIVE, Color = (0,0,1)) + self.Canvas.AddScaledText("ROMAN Font", (x, -20), Size = 7, Family = wx.ROMAN) + self.Canvas.AddScaledText("SCRIPT Font", (x, -30), Size = 7, Family = wx.SCRIPT) + self.Canvas.AddScaledText("ROMAN BOLD Font", (x, -40), Size = 7, Family = wx.ROMAN, Weight=wx.BOLD) + self.Canvas.AddScaledText("ROMAN ITALIC BOLD Font", (x, -50), Size = 7, Family = wx.ROMAN, Weight=wx.BOLD, Style=wx.ITALIC) + Canvas.AddPointSet((x,0), Color = "White", Diameter = 4) + + + # NOTE: this font exists on my OS-X.who knows were else you'll find it! + Point = (-100, 50) + Font = wx.Font(12, wx.DEFAULT, wx.ITALIC, wx.NORMAL, False, "helvetica") + T = self.Canvas.AddScaledText("Helvetica Italic", Point, Size = 20, Font = Font, Position = 'bc') + + Point = (-50, -50) + Font = wx.Font(12, wx.DEFAULT, wx.ITALIC, wx.NORMAL, False, "times") + T = self.Canvas.AddScaledText("Times Font", Point, Size = 8, Font = Font) + + self.Canvas.ZoomToBB() + + def TestScaledTextBox(self, event= None): + wx.GetApp().Yield(True) + + self.UnBindAllMouseEvents() + Canvas = self.Canvas + Canvas.InitAll() + + 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 String\nThis box is clickable", + 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.\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.Canvas.ZoomToBB() + + def binding2(self, event): + self.Log("I'm the TextBox") + + def TestBitmap(self, event= None): + wx.GetApp().Yield(True) + + self.UnBindAllMouseEvents() + Canvas = self.Canvas + Canvas.InitAll() + + Canvas.AddRectangle((10, 20), + (400, 100), + LineWidth = 3, + LineColor = "Blue", + FillColor = "Red") + + bmp = Resources.getMagPlusBitmap() + + Canvas.AddText("These are Unscaled Bitmaps:", (140, 90)) + + Point = (150, 50) + BitMap = Canvas.AddBitmap(bmp, Point, Position = "cc" ) + Canvas.AddPoint(Point, Diameter=4, Color="Green") + + Point = (200, 50) + BitMap = Canvas.AddBitmap(bmp, Point, Position = "br" ) + Canvas.AddPoint(Point, Diameter=4, Color="Green") + + Point = (200, 50) + BitMap = Canvas.AddBitmap(bmp, Point, Position = "bl" ) + Canvas.AddPoint(Point, Diameter=4, Color="Green") + + Point = (200, 50) + BitMap = Canvas.AddBitmap(bmp, Point, Position = "tr" ) + Canvas.AddPoint(Point, Diameter=4, Color="Green") + + Point = (200, 50) + BitMap = Canvas.AddBitmap(bmp, Point, Position = "tl" ) + Canvas.AddPoint(Point, Diameter=4, Color="Green") + + Point = (250, 50) + BitMap = Canvas.AddBitmap(bmp, Point, Position = "cr" ) + Canvas.AddPoint(Point, Diameter=4, Color="Green") + + Point = (250, 50) + BitMap = Canvas.AddBitmap(bmp, Point, Position = "cl" ) + Canvas.AddPoint(Point, Diameter=4, Color="Green") + + Point = (300, 50) + BitMap = Canvas.AddBitmap(bmp, Point, Position = "tc" ) + Canvas.AddPoint(Point, Diameter=4, Color="Green") + + Point = (300, 50) + BitMap = Canvas.AddBitmap(bmp, Point, Position = "bc" ) + Canvas.AddPoint(Point, Diameter=4, Color="Green") + + Canvas.AddScaledText("These are Scaled Bitmaps:", (220, -60), Size = 10, Position = "tr") + Point = (250, -100) + BitMap = Canvas.AddScaledBitmap(bmp, Point, Height = 50, Position = "bc" ) + BitMap = Canvas.AddScaledBitmap(bmp, Point, Height = 50, Position = "tc" ) + Canvas.AddPoint(Point, Diameter=4, Color="Green") + + Point = (300, -100) + BitMap = Canvas.AddScaledBitmap(Resources.getMondrianImage(), Point, Height = 50) + + self.Canvas.ZoomToBB() + + def DrawMap(self,event = None): + wx.GetApp().Yield(True) + import os, time + + self.Canvas.InitAll() + self.Canvas.SetProjectionFun("FlatEarth") + self.BindAllMouseEvents() + + ## Test of Actual Map Data + #start = time.clock() + self.Log("Loading Map from a File") + wx.GetApp().Yield(True) # so log text will get displayed now. + Shorelines = self.Read_MapGen(os.path.join("data",'world.dat'),stats = 0) + #print "It took %f seconds to load %i shorelines"%(time.clock() - start,len(Shorelines) ) + #start = time.clock() + for segment in Shorelines: + self.Canvas.AddLine(segment) + #print "It took %f seconds to add %i shorelines"%(time.clock() - start,len(Shorelines) ) + #start = time.clock() + self.Canvas.ZoomToBB() + #print "It took %f seconds to draw %i shorelines"%(time.clock() - start,len(Shorelines) ) + + + + def LineTest(self,event = None): + wx.GetApp().Yield(True) + import os, time +# import random + colors = self.colors + Range = (-10,10) + ## Test of drawing lots of lines + Canvas = self.Canvas + Canvas.InitAll() + #start = time.clock() + linepoints = [] + linecolors = [] + linewidths = [] + for i in range(2000): + points = (random.randint(Range[0],Range[1]), + random.randint(Range[0],Range[1]), + random.randint(Range[0],Range[1]), + random.randint(Range[0],Range[1])) + linepoints.append(points) + linewidths.append(random.randint(1,10) ) + linecolors.append(random.randint(0,len(colors)-1) ) + for (points,color,width) in zip(linepoints,linecolors,linewidths): + Canvas.AddLine((points[0:2],points[2:4]), LineWidth = width, LineColor = colors[color]) + #print "It took %f seconds to add %i lines"%(time.clock() - start,len(linepoints) ) + #start = time.clock() + Canvas.ZoomToBB() + #print "It took %f seconds to draw %i lines"%(time.clock() - start,len(linepoints) ) + + def ArrowLineTest(self,event = None): + wx.GetApp().Yield(True) + Canvas = self.Canvas + Canvas.InitAll() + # import os, time +## import random + Range = (-100,100) + colors = self.colors + + # 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,4) + cf = random.randint(0,len(colors)-1) + cl = random.randint(0,len(colors)-1) + al = random.randint(8,20) + aa = random.randint(20,90) + Canvas.AddArrowLine(points, + LineWidth = lw, + LineColor = colors[cl], + ArrowHeadSize = al, + ArrowHeadAngle = aa) + + Canvas.ZoomToBB() + + def SpeedTest(self,event=None): + wx.GetApp().Yield(True) + BigRange = (-1000,1000) + colors = self.colors + + self.UnBindAllMouseEvents() + Canvas = self.Canvas + + Canvas.InitAll() + + # Pointset + coords = [] + for i in range(1000): + Point = (random.uniform(BigRange[0],BigRange[1]),random.uniform(BigRange[0],BigRange[1])) + coords.append( (Point) ) + print "Drawing the Points" + start = time.clock() + for Point in coords: + Canvas.AddPoint(Point, Diameter = 4) + print "It took %s seconds to add the points"%(time.clock() - start) + Canvas.ZoomToBB() + + def PropertiesChangeTest(self,event=None): + wx.GetApp().Yield(True) + + Range = (-10,10) + colors = self.colors + + self.UnBindAllMouseEvents() + Canvas = self.Canvas + + Canvas.InitAll() + + self.ColorObjectsAll = [] + self.ColorObjectsLine = [] + self.ColorObjectsColor = [] + self.ColorObjectsText = [] + ##One of each object: + # Rectangle + Point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + lw = random.randint(1,5) + cf = random.randint(0,len(colors)-1) + wh = ( random.randint(1,5), random.randint(1,5) ) + self.Rectangle = Canvas.AddRectangle(Point, wh, LineWidth = lw, FillColor = colors[cf]) + self.ColorObjectsAll.append(self.Rectangle) + + # Ellipse + Point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + lw = random.randint(1,5) + cf = random.randint(0,len(colors)-1) + wh = ( random.randint(1,5), random.randint(1,5) ) + self.Ellipse = Canvas.AddEllipse(Point, wh, LineWidth = lw, FillColor = colors[cf]) + self.ColorObjectsAll.append(self.Ellipse) + + # Point + xy = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + D = random.randint(1,50) + lw = random.randint(1,5) + cf = random.randint(0,len(colors)-1) + cl = random.randint(0,len(colors)-1) + self.ColorObjectsColor.append(Canvas.AddPoint(xy, colors[cf], D)) + + # Circle + 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(colors)-1) + cl = random.randint(0,len(colors)-1) + self.Circle = Canvas.AddCircle(Point, D, LineWidth = lw, LineColor = colors[cl], FillColor = colors[cf]) + self.ColorObjectsAll.append(self.Circle) + + # Line + 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(colors)-1) + cl = random.randint(0,len(colors)-1) + self.ColorObjectsLine.append(Canvas.AddLine(points, LineWidth = lw, LineColor = colors[cl])) + + # Polygon +## 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) + points = RandomArray.uniform(Range[0],Range[1],(6,2)) + lw = random.randint(1,6) + cf = random.randint(0,len(colors)-1) + cl = random.randint(0,len(colors)-1) + self.ColorObjectsAll.append(Canvas.AddPolygon(points, + LineWidth = lw, + LineColor = colors[cl], + FillColor = colors[cf], + FillStyle = 'Solid')) + + ## Pointset + points = RandomArray.uniform(Range[0],Range[1],(100,2)) + cf = random.randint(0,len(colors)-1) + D = random.randint(1,4) + self.PointSet = Canvas.AddPointSet(points, Color = colors[cf], Diameter = D) + self.ColorObjectsColor.append(self.PointSet) + + ## Point + point = RandomArray.uniform(Range[0],Range[1],(2,)) + cf = random.randint(0,len(colors)-1) + D = random.randint(1,4) + self.Point = Canvas.AddPoint(point, Color = colors[cf], Diameter = D) + self.ColorObjectsColor.append(self.Point) + + # Text + String = "Unscaled text" + ts = random.randint(10,40) + cf = random.randint(0,len(colors)-1) + Point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + self.ColorObjectsText.append(Canvas.AddText(String, Point, Size = ts, Color = colors[cf], Position = "cc")) + + # Scaled Text + String = "Scaled text" + ts = random.random()*3 + 0.2 + cf = random.randint(0,len(colors)-1) + Point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + self.ColorObjectsText.append(Canvas.AddScaledText(String, Point, Size = ts, Color = colors[cf], Position = "cc")) + + # A "Button" + Button = Canvas.AddRectangle((-10, -12), (20, 3), LineStyle = None, FillColor = "Red") + Canvas.AddScaledText("Click Here To Change Properties", + (0, -10.5), + Size = 0.7, + Color = "Black", + Position = "cc") + + Button.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.ChangeProperties) + + Canvas.ZoomToBB() + + def ChangeProperties(self, Object = None): + colors = self.colors + Range = (-10,10) + + for Object in self.ColorObjectsAll: + pass + Object.SetFillColor(colors[random.randint(0,len(colors)-1)]) + Object.SetLineColor(colors[random.randint(0,len(colors)-1)]) + Object.SetLineWidth(random.randint(1,7)) + Object.SetLineStyle(FloatCanvas.DrawObject.LineStyleList.keys()[random.randint(0,5)]) + for Object in self.ColorObjectsLine: + Object.SetLineColor(colors[random.randint(0,len(colors)-1)]) + Object.SetLineWidth(random.randint(1,7)) + Object.SetLineStyle(FloatCanvas.DrawObject.LineStyleList.keys()[random.randint(0,5)]) + for Object in self.ColorObjectsColor: + Object.SetColor(colors[random.randint(0,len(colors)-1)]) + for Object in self.ColorObjectsText: + Object.SetColor(colors[random.randint(0,len(colors)-1)]) + Object.SetBackgroundColor(colors[random.randint(0,len(colors)-1)]) + self.Circle.SetDiameter(random.randint(1,10)) + self.PointSet.SetDiameter(random.randint(1,8)) + self.Point.SetDiameter(random.randint(1,8)) + for Object in (self.Rectangle, self.Ellipse): + Point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + wh = ( random.randint(1,5), random.randint(1,5) ) + Object.SetShape(Point, wh) + self.Canvas.Draw(Force = True) + + def ArrowTest(self,event=None): + wx.GetApp().Yield(True) + self.UnBindAllMouseEvents() + Canvas = self.Canvas + + Canvas.InitAll() + Canvas.MinScale = 15 + Canvas.MaxScale = 30 + + # put in a rectangle to get a bounding box + Canvas.AddRectangle((0,0), (20,20), LineColor = None) + + # Draw some Arrows + Canvas.AddArrow((10,10),Length = 40, Direction = 0) + Canvas.AddArrow((10,10),Length = 50, Direction = 45 ,LineWidth = 2, LineColor = "Black", ArrowHeadAngle = 20) + Canvas.AddArrow((10,10),Length = 60, Direction = 90 ,LineWidth = 3, LineColor = "Red", ArrowHeadAngle = 30) + Canvas.AddArrow((10,10),Length = 70, Direction = 135,LineWidth = 4, LineColor = "Red", ArrowHeadAngle = 40) + Canvas.AddArrow((10,10),Length = 80, Direction = 180,LineWidth = 5, LineColor = "Blue", ArrowHeadAngle = 50) + Canvas.AddArrow((10,10),Length = 90, Direction = 225,LineWidth = 4, LineColor = "Blue", ArrowHeadAngle = 60) + Canvas.AddArrow((10,10),Length = 100,Direction = 270,LineWidth = 3, LineColor = "Green", ArrowHeadAngle = 70) + Canvas.AddArrow((10,10),Length = 110,Direction = 315,LineWidth = 2, LineColor = "Green", ArrowHeadAngle = 90 ) + + Canvas.AddText("Clickable Arrow", (4,18), Position = "bc") + Arrow = Canvas.AddArrow((4,18), 80, Direction = 90 ,LineWidth = 3, LineColor = "Red", ArrowHeadAngle = 30) + Arrow.HitLineWidth = 6 + Arrow.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.ArrowClicked) + + Canvas.AddText("Changable Arrow: try clicking it", (16,4), Position = "tc") + self.RotArrow = Canvas.AddArrow((16,4), 80, Direction = 0 ,LineWidth = 3, LineColor = "Green", ArrowHeadAngle = 30) + self.RotArrow.HitLineWidth = 6 + self.RotArrow.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.RotateArrow) + + Canvas.ZoomToBB() + + def ArrowClicked(self,event): + self.Log("The Arrow was Clicked") + + def RotateArrow(self,event): + ##print "The Changeable Arrow was Clicked" + ## You can do them either one at a time, or both at once + ## Doing them both at once prevents the arrow points from being calculated twice + #self.RotArrow.SetDirection(self.RotArrow.Direction + random.uniform(-90,90)) + #self.RotArrow.SetLength(self.RotArrow.Length + random.randint(-20,20)) + self.RotArrow.SetLengthDirection(self.RotArrow.Length + random.randint(-20,20), + self.RotArrow.Direction + random.uniform(-90,90) ) + + self.Canvas.Draw(Force = True) + + def HideTest(self, event=None): + wx.GetApp().Yield(True) + + self.UnBindAllMouseEvents() + Canvas = self.Canvas + Canvas.InitAll() + + Range = (-10,10) + + # Create a couple random Polygons + points = [] + for j in range(6): + point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + points.append(point) + Poly = Canvas.AddPolygon(points, + LineWidth = 2, + LineColor = "Black", + FillColor = "LightBlue", + FillStyle = 'Solid') + + points = [] + for j in range(6): + point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + points.append(point) + Poly2 = Canvas.AddPolygon(points, + LineWidth = 2, + LineColor = "Black", + FillColor = "Purple", + FillStyle = 'Solid', + InForeground = True) + + HideButton = Canvas.AddScaledTextBox("Click To Hide\nBackground Polygon", + (-10, 0), + .5, + BackgroundColor="Red", + PadSize = 0.5, + Position = 'tr', + Alignment="center", + ) + HideButton.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.HidePoly) + HideButton.HidePoly = Poly + + HideButton2 = Canvas.AddScaledTextBox("Click To Hide\nForeground Polygon", + (-10, 5), + .5, + BackgroundColor="Red", + PadSize = 0.5, + Position = 'tr', + Alignment="center", + ) + # Put a reference to the Polygon in the Button object + HideButton2.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.HidePoly) + HideButton2.HidePoly = Poly2 + + + Canvas.ZoomToBB() + + def HidePoly(self, Button): + Poly = Button.HidePoly + + if Poly.Visible: + Poly.Visible = False + Button.SetText(Button.String.replace("Hide","Show")) + else: + Poly.Visible = True + Button.SetText(Button.String.replace("Show", "Hide")) + self.Canvas.Draw(True) + + + def TempTest(self, event= None): + """ + + This is the start of a poly editor test, but it's not complete + so you can only run it through a command line flag: + + python FloatCanvasDemo.py --temp + + """ + + wx.GetApp().Yield(True) + + self.UnBindAllMouseEvents() + Canvas = self.Canvas + Canvas.InitAll() + + Range = (-10,10) + + # Create a random Polygon + points = [] + for j in range(6): + point = (random.uniform(Range[0],Range[1]),random.uniform(Range[0],Range[1])) + points.append(point) + Poly = Canvas.AddPolygon(points, + LineWidth = 2, + LineColor = "Black", + FillColor = "LightBlue", + FillStyle = 'Solid') + + Poly.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.SelectPoly) + + self.SelectedPoly = None + self.SelectPoints = [] + self.SelectedPoint = None + + Canvas.ZoomToBB() + + def SelectPoly(self, Object): + Canvas = self.Canvas + if Object is self.SelectedPoly: + pass + else: + #fixme: Do something to unselect the old one + self.SelectedPoly = Object + Canvas.RemoveObjects(self.SelectPoints) + self.SelectPoints = [] + # Draw points on the Vertices of the Selected Poly: + for i, point in enumerate(Object.Points): + P = Canvas.AddPointSet(point, Diameter = 6, Color = "Red") + P.VerticeNum = i + P.Bind(FloatCanvas.EVT_FC_LEFT_DOWN, self.SelectPointHit) + self.SelectPoints.append(P) + #Canvas.ZoomToBB() + Canvas.Draw() + + def SelectPointHit(self, Point): + self.Log("Point Num: %i Hit"%Point.VerticeNum) + self.SelectedPoint = Point + + def Read_MapGen(self, filename, stats = 0,AllLines=0): + """ + 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 world, in MapGen format. + + """ + import string + file = open(filename,'rt') + data = file.readlines() + data = map(string.strip,data) + + Shorelines = [] + segment = [] + for line in data: + if line: + if line == "# -b": #New segment beginning + if segment: Shorelines.append(N.array(segment)) + segment = [] + else: + segment.append(map(float,string.split(line))) + if segment: Shorelines.append(N.array(segment)) + + if stats: + NumSegments = len(Shorelines) + NumPoints = 0 + for segment in Shorelines: + NumPoints = NumPoints + len(segment) + AvgPoints = NumPoints / NumSegments + print "Number of Segments: ", NumSegments + print "Average Number of Points per segment: ",AvgPoints + if AllLines: + Lines = [] + for segment in Shorelines: + Lines.append(segment[0]) + for point in segment[1:-1]: + Lines.append(point) + Lines.append(point) + Lines.append(segment[-1]) + return Lines + else: + return Shorelines + return DrawFrame + +#--------------------------------------------------------------------------- + +if __name__ == "__main__": + + # running stand alone, Use wxversion: +# import wxversion +# wxversion.select("2.6") +# wxversion.select("2.8") + import wx + + + # check options: + import sys, getopt + optlist, args = getopt.getopt(sys.argv[1:],'l',["all", + "text", + "map", + "stext", + "stextbox", + "bitmap", + "hit", + "hitf", + "animate", + "speed", + "temp", + "props", + "arrow", + "arrowline", + "hide"]) + + if not haveNumpy: + raise ImportError(errorText) + StartUpDemo = "all" # the default + if optlist: + StartUpDemo = optlist[0][0][2:] + + + 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 + wxCursors 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 __init__(self, *args, **kwargs): + wx.App.__init__(self, *args, **kwargs) + + def OnInit(self): + DrawFrame = BuildDrawFrame() + frame = DrawFrame(None, -1, "FloatCanvas Demo App",wx.DefaultPosition,(700,700)) + + self.SetTopWindow(frame) + frame.Show() + + ## check to see if the demo is set to start in a particular mode. + ## fixme: should this be in a dict instead? + if StartUpDemo == "text": + frame.TestText() + elif StartUpDemo == "stext": + frame.TestScaledText() + elif StartUpDemo == "stextbox": + frame.TestScaledTextBox() + elif StartUpDemo == "bitmap": + frame.TestBitmap() + elif StartUpDemo == "all": + frame.DrawTest() + elif StartUpDemo == "map": + frame.DrawMap() + elif StartUpDemo == "hit": + frame.TestHitTest() + elif StartUpDemo == "hitf": + frame.TestHitTestForeground() + elif StartUpDemo == "animate": + frame.TestAnimation() + elif StartUpDemo == "speed": + frame.SpeedTest() + elif StartUpDemo == "temp": + frame.TempTest() + elif StartUpDemo == "props": + frame.PropertiesChangeTest() + elif StartUpDemo == "arrow": + frame.ArrowTest() + elif StartUpDemo == "arrowline": + frame.ArrowLineTest() + elif StartUpDemo == "hide": + frame.HideTest() + + return True + + app = DemoApp(False)# put in True if you want output to go to it's own window. + app.MainLoop() + +else: + # It's not running stand-alone, set up for wxPython demo. + # don't neeed wxversion here. + import wx + if not haveNumpy: + ## TestPanel and runTest used for integration into wxPython Demo + class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + from wx.lib.floatcanvas.ScreenShot import getScreenShotBitmap + + note1 = wx.StaticText(self, -1, errorText) + note2 = wx.StaticText(self, -1, "This is what the FloatCanvas can look like:") + S = wx.BoxSizer(wx.VERTICAL) + S.Add((10, 10), 1) + S.Add(note1, 0, wx.ALIGN_CENTER) + S.Add(note2, 0, wx.ALIGN_CENTER | wx.BOTTOM, 4) + S.Add(wx.StaticBitmap(self,-1,getScreenShotBitmap()),0,wx.ALIGN_CENTER) + S.Add((10, 10), 1) + self.SetSizer(S) + self.Layout() + + else: + ## TestPanel and runTest used for integration into wxPython Demo + class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + note1 = wx.StaticText(self, -1, "The FloatCanvas Demo needs") + note2 = wx.StaticText(self, -1, "a separate frame") + b = wx.Button(self, -1, "Open Demo Frame Now") + b.Bind(wx.EVT_BUTTON, self.OnButton) + + S = wx.BoxSizer(wx.VERTICAL) + S.Add((10, 10), 1) + S.Add(note1, 0, wx.ALIGN_CENTER) + S.Add(note2, 0, wx.ALIGN_CENTER | wx.BOTTOM, 5) + S.Add(b, 0, wx.ALIGN_CENTER | wx.ALL, 5) + S.Add((10, 10), 1) + self.SetSizer(S) + self.Layout() + + def OnButton(self, evt): + DrawFrame = BuildDrawFrame() + frame = DrawFrame(None, -1, "FloatCanvas Drawing Window",wx.DefaultPosition,(500,500)) + + #win = wx.lib.plot.TestFrame(self, -1, "PlotCanvas Demo") + frame.Show() + frame.DrawTest() + + def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + # import to get the doc + from wx.lib import floatcanvas + overview = floatcanvas.__doc__ + + + + + + + + diff --git a/demo/FontDialog.py b/demo/FontDialog.py new file mode 100644 index 00000000..f5b9bcc9 --- /dev/null +++ b/demo/FontDialog.py @@ -0,0 +1,141 @@ + +import wx +from wx.lib import stattext + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + btn = wx.Button(self, -1, "Select Font") + self.Bind(wx.EVT_BUTTON, self.OnSelectFont, btn) + + self.sampleText = stattext.GenStaticText(self, -1, "Sample Text") + self.sampleText.SetBackgroundColour(wx.WHITE) + + self.curFont = self.sampleText.GetFont() + self.curClr = wx.BLACK + + fgs = wx.FlexGridSizer(cols=2, vgap=5, hgap=5) + fgs.AddGrowableCol(1) + fgs.AddGrowableRow(0) + + fgs.Add(btn) + fgs.Add(self.sampleText, 0, wx.ADJUST_MINSIZE|wx.GROW) + + fgs.Add((15,15)); fgs.Add((15,15)) # an empty row + + fgs.Add(wx.StaticText(self, -1, "PointSize:")) + self.ps = wx.StaticText(self, -1, "") + font = self.ps.GetFont() + font.SetWeight(wx.BOLD) + self.ps.SetFont(font) + fgs.Add(self.ps, 0, wx.ADJUST_MINSIZE) + + fgs.Add(wx.StaticText(self, -1, "Family:")) + self.family = wx.StaticText(self, -1, "") + self.family.SetFont(font) + fgs.Add(self.family, 0, wx.ADJUST_MINSIZE) + + fgs.Add(wx.StaticText(self, -1, "Style:")) + self.style = wx.StaticText(self, -1, "") + self.style.SetFont(font) + fgs.Add(self.style, 0, wx.ADJUST_MINSIZE) + + fgs.Add(wx.StaticText(self, -1, "Weight:")) + self.weight = wx.StaticText(self, -1, "") + self.weight.SetFont(font) + fgs.Add(self.weight, 0, wx.ADJUST_MINSIZE) + + fgs.Add(wx.StaticText(self, -1, "Face:")) + self.face = wx.StaticText(self, -1, "") + self.face.SetFont(font) + fgs.Add(self.face, 0, wx.ADJUST_MINSIZE) + + fgs.Add((15,15)); fgs.Add((15,15)) # an empty row + + fgs.Add(wx.StaticText(self, -1, "wx.NativeFontInfo:")) + self.nfi = wx.StaticText(self, -1, "") + self.nfi.SetFont(font) + fgs.Add(self.nfi, 0, wx.ADJUST_MINSIZE) + + # give it some border space + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(fgs, 0, wx.GROW|wx.ADJUST_MINSIZE|wx.ALL, 25) + + self.SetSizer(sizer) + self.UpdateUI() + + + def UpdateUI(self): + self.sampleText.SetFont(self.curFont) + self.sampleText.SetForegroundColour(self.curClr) + self.ps.SetLabel(str(self.curFont.GetPointSize())) + self.family.SetLabel(self.curFont.GetFamilyString()) + self.style.SetLabel(self.curFont.GetStyleString()) + self.weight.SetLabel(self.curFont.GetWeightString()) + self.face.SetLabel(self.curFont.GetFaceName()) + self.nfi.SetLabel(self.curFont.GetNativeFontInfo().ToString()) + self.Layout() + + + def OnSelectFont(self, evt): + data = wx.FontData() + data.EnableEffects(True) + data.SetColour(self.curClr) # set colour + data.SetInitialFont(self.curFont) + + dlg = wx.FontDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetFontData() + font = data.GetChosenFont() + colour = data.GetColour() + + self.log.WriteText('You selected: "%s", %d points, color %s\n' % + (font.GetFaceName(), font.GetPointSize(), + colour.Get())) + + self.curFont = font + self.curClr = colour + self.UpdateUI() + + # Don't destroy the dialog until you get everything you need from the + # dialog! + dlg.Destroy() + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ +This class allows you to use the system font selection dialog +from within your program. Generally speaking, this allows you +to select a font by its name, font size, and weight, and +on some systems such things as strikethrough and underline. + +As with other dialogs used in wxPython, it is important to +use the class' methods to extract the information you need +about the font before you destroy the dialog. Failure +to observe this almost always leads to a program failure of +some sort, often ugly. + +This demo serves two purposes; it shows how to use the dialog +to GET font information from the user, but also shows how +to APPLY that information once you get it. + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/FontEnumerator.py b/demo/FontEnumerator.py new file mode 100644 index 00000000..4356a5a8 --- /dev/null +++ b/demo/FontEnumerator.py @@ -0,0 +1,80 @@ + +import wx + +#---------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + + e = wx.FontEnumerator() + e.EnumerateFacenames() + list = e.GetFacenames() + + list.sort() + + s1 = wx.StaticText(self, -1, "Face names:") + + self.lb1 = wx.ListBox(self, -1, wx.DefaultPosition, (200, 250), + list, wx.LB_SINGLE) + + self.Bind(wx.EVT_LISTBOX, self.OnSelect, id=self.lb1.GetId()) + + self.txt = wx.StaticText(self, -1, "Sample text...", (285, 50)) + + row = wx.BoxSizer(wx.HORIZONTAL) + row.Add(s1, 0, wx.ALL, 5) + row.Add(self.lb1, 0, wx.ALL, 5) + row.Add(self.txt, 0, wx.ALL|wx.ADJUST_MINSIZE, 5) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(row, 0, wx.ALL, 30) + self.SetSizer(sizer) + self.Layout() + + self.lb1.SetSelection(0) + self.OnSelect(None) + wx.FutureCall(300, self.SetTextSize) + + + def SetTextSize(self): + self.txt.SetSize(self.txt.GetBestSize()) + + + def OnSelect(self, evt): + face = self.lb1.GetStringSelection() + font = wx.Font(28, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, face) + self.txt.SetLabel(face) + self.txt.SetFont(font) + if wx.Platform == "__WXMAC__": self.Refresh() + +## st = font.GetNativeFontInfo().ToString() +## ni2 = wx.NativeFontInfo() +## ni2.FromString(st) +## font2 = wx.FontFromNativeInfo(ni2) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +wxFontEnumerator enumerates either all available fonts on the system or only +the ones with given attributes - either only fixed-width (suited for use in +programs such as terminal emulators and the like) or the fonts available in +the given encoding. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Frame.py b/demo/Frame.py new file mode 100644 index 00000000..6a205094 --- /dev/null +++ b/demo/Frame.py @@ -0,0 +1,84 @@ + +import wx + +#--------------------------------------------------------------------------- + +class MyFrame(wx.Frame): + def __init__( + self, parent, ID, title, pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE + ): + + wx.Frame.__init__(self, parent, ID, title, pos, size, style) + panel = wx.Panel(self, -1) + + button = wx.Button(panel, 1003, "Close Me") + button.SetPosition((15, 15)) + self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + + def OnCloseMe(self, event): + self.Close(True) + + def OnCloseWindow(self, event): + self.Destroy() + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a Frame", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = MyFrame(self, -1, "This is a wx.Frame", size=(350, 200), + style = wx.DEFAULT_FRAME_STYLE) + win.Show(True) + + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = """\ +A Frame is a window whose size and position can (usually) be changed by +the user. It usually has thick borders and a title bar, and can optionally +contain a menu bar, toolbar and status bar. A frame can contain any window +that is not a Frame or Dialog. It is one of the most fundamental of the +wxWindows components. + +A Frame that has a status bar and toolbar created via the +CreateStatusBar / CreateToolBar functions manages +these windows, and adjusts the value returned by GetClientSize +to reflect the remaining size available to application windows. + +By itself, a Frame is not too useful, but with the addition of Panels and +other child objects, it encompasses the framework around which most user +interfaces are constructed. + +If you plan on using Sizers and auto-layout features, be aware that the Frame +class lacks the ability to handle these features unless it contains a Panel. +The Panel has all the necessary functionality to both control the size of +child components, and also communicate that information in a useful way to +the Frame itself. +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/GIFAnimationCtrl.py b/demo/GIFAnimationCtrl.py new file mode 100644 index 00000000..8f010385 --- /dev/null +++ b/demo/GIFAnimationCtrl.py @@ -0,0 +1,60 @@ + +import wx +from wx.animate import GIFAnimationCtrl + +from Main import opj + +GIFNames = [ + 'bitmaps/AG00178_.gif', + 'bitmaps/BD13656_.gif', + 'bitmaps/AG00185_.gif', + 'bitmaps/AG00039_.gif', + 'bitmaps/AG00183_.gif', + 'bitmaps/AG00028_.gif', + ] + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + sizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5) + for name in GIFNames: + ani = GIFAnimationCtrl(self, -1, opj(name)) + ani.GetPlayer().UseBackgroundColour(True) + ani.Play() + sizer.Add(ani, 0, wx.ALL, 10) + + border = wx.BoxSizer() + border.Add(sizer, 1, wx.EXPAND|wx.ALL, 20) + self.SetSizer(border) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.animate.GIFAnimationCtrl

+ +wx.animate.GIFAnimationCtrl is like a wx.StaticBitmap but is able to +display an animation by extracing frames from a multi-images GIF file. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/GLCanvas.py b/demo/GLCanvas.py new file mode 100644 index 00000000..26635db4 --- /dev/null +++ b/demo/GLCanvas.py @@ -0,0 +1,290 @@ + +import wx +import sys + +try: + from wx import glcanvas + haveGLCanvas = True +except ImportError: + haveGLCanvas = False + +try: + # The Python OpenGL package can be found at + # http://PyOpenGL.sourceforge.net/ + from OpenGL.GL import * + from OpenGL.GLUT import * + haveOpenGL = True +except ImportError: + haveOpenGL = False + +#---------------------------------------------------------------------- + + +buttonDefs = { + wx.NewId() : ('CubeCanvas', 'Cube'), + wx.NewId() : ('ConeCanvas', 'Cone'), + } + +class ButtonPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + box = wx.BoxSizer(wx.VERTICAL) + box.Add((20, 30)) + keys = buttonDefs.keys() + keys.sort() + for k in keys: + text = buttonDefs[k][1] + btn = wx.Button(self, k, text) + box.Add(btn, 0, wx.ALIGN_CENTER|wx.ALL, 15) + self.Bind(wx.EVT_BUTTON, self.OnButton, btn) + + #** Enable this to show putting a GLCanvas on the wx.Panel + if 1: + c = CubeCanvas(self) + c.SetMinSize((200, 200)) + box.Add(c, 0, wx.ALIGN_CENTER|wx.ALL, 15) + + self.SetAutoLayout(True) + self.SetSizer(box) + + + def OnButton(self, evt): + if not haveGLCanvas: + dlg = wx.MessageDialog(self, + 'The GLCanvas class has not been included with this build of wxPython!', + 'Sorry', wx.OK | wx.ICON_WARNING) + dlg.ShowModal() + dlg.Destroy() + + elif not haveOpenGL: + dlg = wx.MessageDialog(self, + 'The OpenGL package was not found. You can get it at\n' + 'http://PyOpenGL.sourceforge.net/', + 'Sorry', wx.OK | wx.ICON_WARNING) + dlg.ShowModal() + dlg.Destroy() + + else: + canvasClassName = buttonDefs[evt.GetId()][0] + canvasClass = eval(canvasClassName) + frame = wx.Frame(None, -1, canvasClassName, size=(400,400)) + canvas = canvasClass(frame) + frame.Show(True) + + +class MyCanvasBase(glcanvas.GLCanvas): + def __init__(self, parent): + glcanvas.GLCanvas.__init__(self, parent, -1) + self.init = False + self.context = glcanvas.GLContext(self) + + # initial mouse position + self.lastx = self.x = 30 + self.lasty = self.y = 30 + self.size = None + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_LEFT_DOWN, self.OnMouseDown) + self.Bind(wx.EVT_LEFT_UP, self.OnMouseUp) + self.Bind(wx.EVT_MOTION, self.OnMouseMotion) + + + def OnEraseBackground(self, event): + pass # Do nothing, to avoid flashing on MSW. + + + def OnSize(self, event): + wx.CallAfter(self.DoSetViewport) + event.Skip() + + def DoSetViewport(self): + size = self.size = self.GetClientSize() + self.SetCurrent(self.context) + glViewport(0, 0, size.width, size.height) + + + + def OnPaint(self, event): + dc = wx.PaintDC(self) + self.SetCurrent(self.context) + if not self.init: + self.InitGL() + self.init = True + self.OnDraw() + + + def OnMouseDown(self, evt): + self.CaptureMouse() + self.x, self.y = self.lastx, self.lasty = evt.GetPosition() + + + def OnMouseUp(self, evt): + self.ReleaseMouse() + + + def OnMouseMotion(self, evt): + if evt.Dragging() and evt.LeftIsDown(): + self.lastx, self.lasty = self.x, self.y + self.x, self.y = evt.GetPosition() + self.Refresh(False) + + + + +class CubeCanvas(MyCanvasBase): + def InitGL(self): + # set viewing projection + glMatrixMode(GL_PROJECTION) + glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0) + + # position viewer + glMatrixMode(GL_MODELVIEW) + glTranslatef(0.0, 0.0, -2.0) + + # position object + glRotatef(self.y, 1.0, 0.0, 0.0) + glRotatef(self.x, 0.0, 1.0, 0.0) + + glEnable(GL_DEPTH_TEST) + glEnable(GL_LIGHTING) + glEnable(GL_LIGHT0) + + + def OnDraw(self): + # clear color and depth buffers + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + + # draw six faces of a cube + glBegin(GL_QUADS) + glNormal3f( 0.0, 0.0, 1.0) + glVertex3f( 0.5, 0.5, 0.5) + glVertex3f(-0.5, 0.5, 0.5) + glVertex3f(-0.5,-0.5, 0.5) + glVertex3f( 0.5,-0.5, 0.5) + + glNormal3f( 0.0, 0.0,-1.0) + glVertex3f(-0.5,-0.5,-0.5) + glVertex3f(-0.5, 0.5,-0.5) + glVertex3f( 0.5, 0.5,-0.5) + glVertex3f( 0.5,-0.5,-0.5) + + glNormal3f( 0.0, 1.0, 0.0) + glVertex3f( 0.5, 0.5, 0.5) + glVertex3f( 0.5, 0.5,-0.5) + glVertex3f(-0.5, 0.5,-0.5) + glVertex3f(-0.5, 0.5, 0.5) + + glNormal3f( 0.0,-1.0, 0.0) + glVertex3f(-0.5,-0.5,-0.5) + glVertex3f( 0.5,-0.5,-0.5) + glVertex3f( 0.5,-0.5, 0.5) + glVertex3f(-0.5,-0.5, 0.5) + + glNormal3f( 1.0, 0.0, 0.0) + glVertex3f( 0.5, 0.5, 0.5) + glVertex3f( 0.5,-0.5, 0.5) + glVertex3f( 0.5,-0.5,-0.5) + glVertex3f( 0.5, 0.5,-0.5) + + glNormal3f(-1.0, 0.0, 0.0) + glVertex3f(-0.5,-0.5,-0.5) + glVertex3f(-0.5,-0.5, 0.5) + glVertex3f(-0.5, 0.5, 0.5) + glVertex3f(-0.5, 0.5,-0.5) + glEnd() + + if self.size is None: + self.size = self.GetClientSize() + w, h = self.size + w = max(w, 1.0) + h = max(h, 1.0) + xScale = 180.0 / w + yScale = 180.0 / h + glRotatef((self.y - self.lasty) * yScale, 1.0, 0.0, 0.0); + glRotatef((self.x - self.lastx) * xScale, 0.0, 1.0, 0.0); + + self.SwapBuffers() + + + + + +class ConeCanvas(MyCanvasBase): + def InitGL( self ): + glMatrixMode(GL_PROJECTION) + # camera frustrum setup + glFrustum(-0.5, 0.5, -0.5, 0.5, 1.0, 3.0) + glMaterial(GL_FRONT, GL_AMBIENT, [0.2, 0.2, 0.2, 1.0]) + glMaterial(GL_FRONT, GL_DIFFUSE, [0.8, 0.8, 0.8, 1.0]) + glMaterial(GL_FRONT, GL_SPECULAR, [1.0, 0.0, 1.0, 1.0]) + glMaterial(GL_FRONT, GL_SHININESS, 50.0) + glLight(GL_LIGHT0, GL_AMBIENT, [0.0, 1.0, 0.0, 1.0]) + glLight(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1.0]) + glLight(GL_LIGHT0, GL_SPECULAR, [1.0, 1.0, 1.0, 1.0]) + glLight(GL_LIGHT0, GL_POSITION, [1.0, 1.0, 1.0, 0.0]) + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [0.2, 0.2, 0.2, 1.0]) + glEnable(GL_LIGHTING) + glEnable(GL_LIGHT0) + glDepthFunc(GL_LESS) + glEnable(GL_DEPTH_TEST) + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + # position viewer + glMatrixMode(GL_MODELVIEW) + # position viewer + glTranslatef(0.0, 0.0, -2.0); + # + glutInit(sys.argv) + + + def OnDraw(self): + # clear color and depth buffers + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) + # use a fresh transformation matrix + glPushMatrix() + # position object + #glTranslate(0.0, 0.0, -2.0) + glRotate(30.0, 1.0, 0.0, 0.0) + glRotate(30.0, 0.0, 1.0, 0.0) + + glTranslate(0, -1, 0) + glRotate(250, 1, 0, 0) + glutSolidCone(0.5, 1, 30, 5) + glPopMatrix() + glRotatef((self.y - self.lasty), 0.0, 0.0, 1.0); + glRotatef((self.x - self.lastx), 1.0, 0.0, 0.0); + # push into visible buffer + self.SwapBuffers() + + + + +#---------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = ButtonPanel(nb, log) + return win + + + + + + +overview = """\ +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + + +#---------------------------------------------------------------------- + diff --git a/demo/Gauge.py b/demo/Gauge.py new file mode 100644 index 00000000..d53bcdbf --- /dev/null +++ b/demo/Gauge.py @@ -0,0 +1,60 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + self.count = 0 + + wx.StaticText(self, -1, "This example shows the wx.Gauge control.", (45, 15)) + + self.g1 = wx.Gauge(self, -1, 50, (110, 50), (250, 25)) + self.g2 = wx.Gauge(self, -1, 50, (110, 95), (250, 25)) + + self.Bind(wx.EVT_TIMER, self.TimerHandler) + self.timer = wx.Timer(self) + self.timer.Start(100) + + def __del__(self): + self.timer.Stop() + + def TimerHandler(self, event): + self.count = self.count + 1 + + if self.count >= 50: + self.count = 0 + + self.g1.SetValue(self.count) + self.g2.Pulse() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ +A Gauge is a horizontal or vertical bar which shows a quantity in a graphical +fashion. It is often used to indicate progress through lengthy tasks, such as +file copying or data analysis. + +When the Gauge is initialized, it's "complete" value is usually set; at any rate, +before using the Gauge, the maximum value of the control must be set. As the task +progresses, the Gauge is updated by the program via the SetValue method. + +This control is for use within a GUI; there is a seperate ProgressDialog class +to present the same sort of control as a dialog to the user. +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/GenericButtons.py b/demo/GenericButtons.py new file mode 100644 index 00000000..ff0ba020 --- /dev/null +++ b/demo/GenericButtons.py @@ -0,0 +1,184 @@ + +import wx +import wx.lib.buttons as buttons + +import images + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + ##self.SetBackgroundColour("sky blue") + + sizer = wx.FlexGridSizer(cols=3, hgap=20, vgap=20) + + # A regular button, selected as the default button + b = wx.Button(self, -1, "A real button") + b.SetDefault() + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + sizer.Add(b) + + # Same thing, but NOT set as the default button + b = wx.Button(self, -1, "non-default") + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + sizer.Add(b) + sizer.Add((10,10)) + + # Plain old text button based off GenButton() + b = buttons.GenButton(self, -1, 'Hello') + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + sizer.Add(b) + + # Plain old text button, disabled. + b = buttons.GenButton(self, -1, 'disabled') + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + b.Enable(False) + sizer.Add(b) + + # This time, we let the botton be as big as it can be. + # Also, this one is fancier, with custom colors and bezel size. + b = buttons.GenButton(self, -1, 'bigger') + self.Bind(wx.EVT_BUTTON, self.OnBiggerButton, b) + b.SetFont(wx.Font(20, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + b.SetBezelWidth(5) + b.SetMinSize(wx.DefaultSize) + b.SetBackgroundColour("Navy") + b.SetForegroundColour(wx.WHITE) + b.SetToolTipString("This is a BIG button...") + # let the sizer set best size + sizer.Add(b, flag=wx.ADJUST_MINSIZE) + + # An image button + bmp = images.Test2.GetBitmap() + b = buttons.GenBitmapButton(self, -1, bmp) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + sizer.Add(b) + + # An image button, disabled. + bmp = images.Test2.GetBitmap() + b = buttons.GenBitmapButton(self, -1, bmp) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + sizer.Add(b) + b.Enable(False) + + # An image button, using a mask to get rid of the + # undesireable part of the image + b = buttons.GenBitmapButton(self, -1, None) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + bmp = images.Bulb1.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + bmp.SetMask(mask) + b.SetBitmapLabel(bmp) + bmp = images.Bulb2.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + bmp.SetMask(mask) + b.SetBitmapSelected(bmp) + b.SetInitialSize() + sizer.Add(b) + + # A toggle button + b = buttons.GenToggleButton(self, -1, "Toggle Button") + self.Bind(wx.EVT_BUTTON, self.OnToggleButton, b) + sizer.Add(b) + + # An image toggle button + b = buttons.GenBitmapToggleButton(self, -1, None) + self.Bind(wx.EVT_BUTTON, self.OnToggleButton, b) + bmp = images.Bulb1.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + bmp.SetMask(mask) + b.SetBitmapLabel(bmp) + bmp = images.Bulb2.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + bmp.SetMask(mask) + b.SetBitmapSelected(bmp) + b.SetToggle(True) + b.SetInitialSize() + sizer.Add(b) + + # A bitmap button with text. + b = buttons.GenBitmapTextButton(self, -1, None, "Bitmapped Text", size = (200, 45)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + bmp = images.Bulb1.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + bmp.SetMask(mask) + b.SetBitmapLabel(bmp) + bmp = images.Bulb2.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + bmp.SetMask(mask) + b.SetBitmapSelected(bmp) + b.SetUseFocusIndicator(False) + b.SetInitialSize() + sizer.Add(b) + + + # a flat text button + b = buttons.GenButton(self, -1, 'Flat buttons too!', style=wx.BORDER_NONE) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + sizer.Add(b, flag=wx.ALIGN_CENTER_VERTICAL) + + # A flat image button + bmp = images.Test2.GetBitmap() + bmp.SetMaskColour("blue") + b = buttons.GenBitmapButton(self, -1, bmp, style=wx.BORDER_NONE) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + sizer.Add(b) + ##b.SetBackgroundColour("sky blue") + ##b.SetBackgroundColour("pink") + + vbox = wx.BoxSizer(wx.VERTICAL) + sizer.Add(vbox) + + b = buttons.ThemedGenButton(self, -1, 'Drawn with native renderer') + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + vbox.Add(b, 0, wx.ALL, 5) + + b = buttons.ThemedGenToggleButton(self, -1, 'native renderered toggle') + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + vbox.Add(b, 0, wx.ALL, 5) + + + + border = wx.BoxSizer(wx.VERTICAL) + border.Add(sizer, 0, wx.ALL, 25) + self.SetSizer(border) + + + def OnButton(self, event): + self.log.WriteText("Button Clicked: %d\n" % event.GetId()) + + + def OnBiggerButton(self, event): + self.log.WriteText("Bigger Button Clicked: %d\n" % event.GetId()) + b = event.GetEventObject() + txt = "big " + b.GetLabel() + b.SetLabel(txt) + self.GetSizer().Layout() + + + def OnToggleButton(self, event): + msg = (event.GetIsDown() and "on") or "off" + self.log.WriteText("Button %d Toggled: %s\n" % (event.GetId(), msg)) + + + +#---------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#---------------------------------------------------------------------- + + +overview = buttons.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/GenericDirCtrl.py b/demo/GenericDirCtrl.py new file mode 100644 index 00000000..409abb15 --- /dev/null +++ b/demo/GenericDirCtrl.py @@ -0,0 +1,69 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + txt1 = wx.StaticText(self, -1, "style=0") + dir1 = wx.GenericDirCtrl(self, -1, size=(200,225), style=0) + + txt2 = wx.StaticText(self, -1, "wx.DIRCTRL_DIR_ONLY") + dir2 = wx.GenericDirCtrl(self, -1, size=(200,225), style=wx.DIRCTRL_DIR_ONLY|wx.DIRCTRL_MULTIPLE) + + txt3 = wx.StaticText(self, -1, "wx.DIRCTRL_SHOW_FILTERS") + dir3 = wx.GenericDirCtrl(self, -1, size=(200,225), style=wx.DIRCTRL_SHOW_FILTERS, + filter="All files (*.*)|*.*|Python files (*.py)|*.py") + + sz = wx.FlexGridSizer(cols=3, hgap=5, vgap=5) + sz.Add((35, 35)) # some space above + sz.Add((35, 35)) + sz.Add((35, 35)) + + sz.Add(txt1) + sz.Add(txt2) + sz.Add(txt3) + + sz.Add(dir1, 0, wx.EXPAND) + sz.Add(dir2, 0, wx.EXPAND) + sz.Add(dir3, 0, wx.EXPAND) + + sz.Add((35,35)) # some space below + + sz.AddGrowableRow(2) + sz.AddGrowableCol(0) + sz.AddGrowableCol(1) + sz.AddGrowableCol(2) + + self.SetSizer(sz) + self.SetAutoLayout(True) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ +This control can be used to place a directory listing (with optional files) +on an arbitrary window. The control contains a TreeCtrl window representing +the directory hierarchy, and optionally, a Choice window containing a list +of filters. + +The filters work in the same manner as in FileDialog. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/GetMouseState.py b/demo/GetMouseState.py new file mode 100644 index 00000000..836650be --- /dev/null +++ b/demo/GetMouseState.py @@ -0,0 +1,158 @@ + +import wx + +#---------------------------------------------------------------------- + +class StaticText(wx.StaticText): + """ + A StaticText that only updates the label if it has changed, to + help reduce potential flicker since these controls would be + updated very frequently otherwise. + """ + def SetLabel(self, label): + if label <> self.GetLabel(): + wx.StaticText.SetLabel(self, label) + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(sizer) + sizer.Add((25,25)) + sizer.Add(wx.StaticText( + self, -1, + "Mouse and modifier state can be polled with wx.GetMouseState"), + 0, wx.CENTER|wx.ALL, 10) + sizer.Add(wx.StaticLine(self), 0, wx.EXPAND|wx.TOP, 10) + + row = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(row, 0, wx.CENTER) + + fgs = wx.FlexGridSizer(cols=2, hgap=5, vgap=10) + row.Add(fgs, 0, wx.ALL, 30) + + lbl = StaticText(self, -1, "X pos:") + self.x = StaticText(self, -1, "00000") + fgs.Add(lbl) + fgs.Add(self.x) + + lbl = StaticText(self, -1, "Y pos:") + self.y = StaticText(self, -1, "00000") + fgs.Add(lbl) + fgs.Add(self.y) + + + lbl = StaticText(self, -1, "Left down:") + self.lft = StaticText(self, -1, "False") + fgs.Add(lbl) + fgs.Add(self.lft) + + lbl = StaticText(self, -1, "Middle down:") + self.mid = StaticText(self, -1, "False") + fgs.Add(lbl) + fgs.Add(self.mid) + + lbl = StaticText(self, -1, "Right down:") + self.rgt = StaticText(self, -1, "False") + fgs.Add(lbl) + fgs.Add(self.rgt) + + lbl = StaticText(self, -1, "AUX1 down:") + self.aux1 = StaticText(self, -1, "False") + fgs.Add(lbl) + fgs.Add(self.aux1) + + lbl = StaticText(self, -1, "AUX2 down:") + self.aux2 = StaticText(self, -1, "False") + fgs.Add(lbl) + fgs.Add(self.aux2) + + fgs = wx.FlexGridSizer(cols=2, hgap=5, vgap=10) + row.Add(fgs, 0, wx.ALL, 30) + + lbl = StaticText(self, -1, "Control down:") + self.ctrl = StaticText(self, -1, "False") + fgs.Add(lbl) + fgs.Add(self.ctrl) + + lbl = StaticText(self, -1, "Shift down:") + self.shft = StaticText(self, -1, "False") + fgs.Add(lbl) + fgs.Add(self.shft) + + lbl = StaticText(self, -1, "Alt down:") + self.alt = StaticText(self, -1, "False") + fgs.Add(lbl) + fgs.Add(self.alt) + + lbl = StaticText(self, -1, "Meta down:") + self.meta = StaticText(self, -1, "False") + fgs.Add(lbl) + fgs.Add(self.meta) + + lbl = StaticText(self, -1, "Cmd down:") + self.cmd = StaticText(self, -1, "False") + fgs.Add(lbl) + fgs.Add(self.cmd) + + self.timer = wx.Timer(self) + self.Bind(wx.EVT_TIMER, self.OnTimer, self.timer) + self.timer.Start(100) + + + def OnTimer(self, evt): + ms = wx.GetMouseState() + self.x.SetLabel( str(ms.x) ) + self.y.SetLabel( str(ms.y) ) + + self.lft.SetLabel( str(ms.leftIsDown) ) + self.mid.SetLabel( str(ms.middleIsDown) ) + self.rgt.SetLabel( str(ms.rightIsDown) ) + self.aux1.SetLabel( str(ms.aux1IsDown) ) + self.aux2.SetLabel( str(ms.aux2IsDown) ) + + self.ctrl.SetLabel( str(ms.controlDown) ) + self.shft.SetLabel( str(ms.shiftDown) ) + self.alt.SetLabel( str(ms.altDown) ) + self.meta.SetLabel( str(ms.metaDown) ) + self.cmd.SetLabel( str(ms.cmdDown) ) + + + def ShutdownDemo(self): + self.timer.Stop() + del self.timer + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.GetMouseState

+ +The mouse and modifier state can be polled with the wx.GetMouseState +function. It returns an instance of a wx.MouseState object that +contains the current position of the mouse pointer in screen +coordinates, as well as boolean values indicating the up/down status +of the mouse buttons and the modifier keys. + + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/GraphicsContext.py b/demo/GraphicsContext.py new file mode 100644 index 00000000..56a29667 --- /dev/null +++ b/demo/GraphicsContext.py @@ -0,0 +1,219 @@ + +import wx +import colorsys +from math import cos, sin, radians + +from Main import opj + +#---------------------------------------------------------------------- + +BASE = 80.0 # sizes used in shapes drawn below +BASE2 = BASE/2 +BASE4 = BASE/4 + +USE_BUFFER = ('wxMSW' in wx.PlatformInfo) # use buffered drawing on Windows + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + self.Bind(wx.EVT_PAINT, self.OnPaint) + if USE_BUFFER: + self.Bind(wx.EVT_SIZE, self.OnSize) + + + def OnSize(self, evt): + # When there is a size event then recreate the buffer to match + # the new size of the window. + self.InitBuffer() + evt.Skip() + + + def OnPaint(self, evt): + if USE_BUFFER: + # The buffer already contains our drawing, so no need to + # do anything else but create the buffered DC. When this + # method exits and dc is collected then the buffer will be + # blitted to the paint DC automagically + dc = wx.BufferedPaintDC(self, self._buffer) + else: + # Otherwise we need to draw our content to the paint DC at + # this time. + dc = wx.PaintDC(self) + gc = self.MakeGC(dc) + self.Draw(gc) + + + def InitBuffer(self): + sz = self.GetClientSize() + sz.width = max(1, sz.width) + sz.height = max(1, sz.height) + self._buffer = wx.EmptyBitmap(sz.width, sz.height, 32) + + dc = wx.MemoryDC(self._buffer) + dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.Clear() + gc = self.MakeGC(dc) + self.Draw(gc) + + + def MakeGC(self, dc): + try: + if False: + # If you want to force the use of Cairo instead of the + # native GraphicsContext backend then create the + # context like this. It works on Windows so far, (on + # wxGTK the Cairo context is already being used as the + # native default.) + gcr = wx.GraphicsRenderer.GetCairoRenderer + gc = gcr() and gcr().CreateContext(dc) + if gc is None: + wx.MessageBox("Unable to create Cairo Context.", "Oops") + gc = wx.GraphicsContext.Create(dc) + else: + # Otherwise, creating it this way will use the native + # backend, (GDI+ on Windows, CoreGraphics on Mac, or + # Cairo on GTK). + gc = wx.GraphicsContext.Create(dc) + + except NotImplementedError: + dc.DrawText("This build of wxPython does not support the wx.GraphicsContext " + "family of classes.", + 25, 25) + return None + return gc + + + def Draw(self, gc): + font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + font.SetWeight(wx.BOLD) + gc.SetFont(font) + + # make a path that contains a circle and some lines, centered at 0,0 + path = gc.CreatePath() + path.AddCircle(0, 0, BASE2) + path.MoveToPoint(0, -BASE2) + path.AddLineToPoint(0, BASE2) + path.MoveToPoint(-BASE2, 0) + path.AddLineToPoint(BASE2, 0) + path.CloseSubpath() + path.AddRectangle(-BASE4, -BASE4/2, BASE2, BASE4) + + + # Now use that path to demonstrate various capbilites of the grpahics context + gc.PushState() # save current translation/scale/other state + gc.Translate(60, 75) # reposition the context origin + + gc.SetPen(wx.Pen("navy", 1)) + gc.SetBrush(wx.Brush("pink")) + + # show the difference between stroking, filling and drawing + for label, PathFunc in [("StrokePath", gc.StrokePath), + ("FillPath", gc.FillPath), + ("DrawPath", gc.DrawPath)]: + w, h = gc.GetTextExtent(label) + + gc.DrawText(label, -w/2, -BASE2-h-4) + PathFunc(path) + gc.Translate(2*BASE, 0) + + + gc.PopState() # restore saved state + gc.PushState() # save it again + gc.Translate(60, 200) # offset to the lower part of the window + + gc.DrawText("Scale", 0, -BASE2) + gc.Translate(0, 20) + + # for testing clipping + #gc.Clip(0, 0, 100, 100) + #rgn = wx.RegionFromPoints([ (0,0), (75,0), (75,25,), (100, 25), + # (100,100), (0,100), (0,0) ]) + #gc.ClipRegion(rgn) + #gc.ResetClip() + + gc.SetBrush(wx.Brush(wx.Colour(178, 34, 34, 128))) # 128 == half transparent + for cnt in range(8): + gc.Scale(1.08, 1.08) # increase scale by 8% + gc.Translate(5,5) + gc.DrawPath(path) + + + gc.PopState() # restore saved state + gc.PushState() # save it again + gc.Translate(400, 200) + gc.DrawText("Rotate", 0, -BASE2) + + # Move the origin over to the next location + gc.Translate(0, 75) + + # draw our path again, rotating it about the central point, + # and changing colors as we go + for angle in range(0, 360, 30): + gc.PushState() # save this new current state so we can + # pop back to it at the end of the loop + r, g, b = [int(c * 255) for c in colorsys.hsv_to_rgb(float(angle)/360, 1, 1)] + gc.SetBrush(wx.Brush(wx.Colour(r, g, b, 64))) + gc.SetPen(wx.Pen(wx.Colour(r, g, b, 128))) + + # use translate to artfully reposition each drawn path + gc.Translate(1.5 * BASE2 * cos(radians(angle)), + 1.5 * BASE2 * sin(radians(angle))) + + # use Rotate to rotate the path + gc.Rotate(radians(angle)) + + # now draw it + gc.DrawPath(path) + gc.PopState() + + # Draw a bitmap with an alpha channel on top of the last group + bmp = wx.Bitmap(opj('bitmaps/toucan.png')) + bsz = bmp.GetSize() + gc.DrawBitmap(bmp, + #-bsz.width, + #-bsz.height/2, + + -bsz.width/2.5, + -bsz.height/2.5, + + bsz.width, bsz.height) + + + gc.PopState() + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.GraphicsContext and wx.GraphicsPath

+ +The new advanced 2D drawing API is implemented via the +wx.GraphicsContext and wx.GraphicsPath classes. They wrap GDI+ on +Windows, Cairo on wxGTK and CoreGraphics on OS X. They allow +path-based drawing with alpha-blending and anti-aliasing, and use a +floating point cooridnate system. + +

When viewing this sample pay attention to how the rounded edges are +smoothed with anti-aliased drawing, and how the shapes on the lower +half of the window are partially transparent, allowing you to see what +was drawn before. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/GraphicsGradient.py b/demo/GraphicsGradient.py new file mode 100644 index 00000000..f53acf67 --- /dev/null +++ b/demo/GraphicsGradient.py @@ -0,0 +1,265 @@ + +import wx +g = wx + +# To test compatibility of gradients with the generic GraphicsContext classes +# uncomment this line +#import wx.lib.graphics as g + +#---------------------------------------------------------------------- + +class GradientPanel(wx.Panel): + """ + This panel will be painted with the gradient brush created by the + rest of the sample. + """ + def __init__(self, parent): + wx.Panel.__init__(self, parent, -1) + self.SetBackgroundStyle(wx.BG_STYLE_PAINT) + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.SetInitialSize((600,100)) + + # create a simple default brush we can use until a gradient + # brush is given to us + ctx = g.GraphicsContext.CreateMeasuringContext() + self.brush = ctx.CreateBrush(wx.Brush('white')) + + def DrawWithBrush(self, brush): + self.brush = brush + self.Refresh() + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + gc = g.GraphicsContext.Create(dc) + gc.SetBrush(self.brush) + gc.SetPen(wx.Pen('black', 1)) + w, h = gc.GetSize() + gc.DrawRectangle(0,0,w,h) + + + +class GradientStopPanel(wx.Panel): + """ + Contains the controls for editing each gradient stop. (Colour, + alpha and relative position.) + """ + def __init__(self, parent, posVal, colour=wx.BLACK, alpha=wx.ALPHA_OPAQUE): + wx.Panel.__init__(self, parent) + + # make some widgets + self.pos = wx.SpinCtrlDouble(self, value='%2f' % posVal, size=(65,-1), + min=0.0, max=1.0, initial=posVal, inc=0.01) + self.pos.SetToolTipString( + "A value between 0 and 1 representing the distance between (x1,y1) " + "and (x2,y2) for this gradient stop.") + self.colour = wx.ColourPickerCtrl(self, col=colour) + self.colour.SetToolTipString("The colour for this gradient stop") + self.minusBtn = wx.Button(self, -1, " - ", style=wx.BU_EXACTFIT) + self.minusBtn.SetToolTipString("Remove this gradient stop") + + # put them in a sizer + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(self.pos, 0, wx.ALIGN_CENTER_VERTICAL) + sizer.Add(self.colour, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 10) + sizer.Add(self.minusBtn, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 25) + border = wx.BoxSizer() + border.Add(sizer, 1, wx.EXPAND|wx.ALL, 4) + self.SetSizer(border) + + self.Bind(wx.EVT_BUTTON, self.OnMinusButton, self.minusBtn) + + + def OnMinusButton(self, evt): + wx.CallAfter(self.Parent.RemoveStop, self) + + + +class TestPanel(wx.Panel): + """ + The main panel for this sample + """ + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + # make the panel that will display the gradient + self.gpanel = GradientPanel(self) + + # and the other widgets for collecting data about the gradient + label1 = wx.StaticText(self, -1, "Geometry") + label1.SetFont(wx.FFont(15, wx.SWISS, wx.FONTFLAG_BOLD)) + x1 = 0 + x2 = self.gpanel.Size.width + y0 = self.gpanel.Size.height / 2 + self.x1 = wx.TextCtrl(self, value=str(x1), size=(50,-1)) + self.y1 = wx.TextCtrl(self, value=str(y0), size=(50,-1)) + self.x2 = wx.TextCtrl(self, value=str(x2), size=(50,-1)) + self.y2 = wx.TextCtrl(self, value=str(y0), size=(50,-1)) + + label2 = wx.StaticText(self, -1, "Stops") + label2.SetFont(wx.FFont(15, wx.SWISS, wx.FONTFLAG_BOLD)) + firstStop = GradientStopPanel(self, 0.0) + lastStop = GradientStopPanel(self, 1.0, wx.WHITE) + self.stops = [firstStop, lastStop] + addStopBtn = wx.Button(self, -1, " + ", style=wx.BU_EXACTFIT) + + + # bind some events + self.Bind(wx.EVT_BUTTON, self.OnAddStop, addStopBtn) + self.Bind(wx.EVT_SPINCTRLDOUBLE, self.OnPositionUpdated) + self.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnColourChanged) + self.Bind(wx.EVT_TEXT, self.OnGeometryChanged) + + + # do the layout + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.gpanel) + sizer.Add((1,15)) + sizer.Add(label1) + sizer.Add((1, 5)) + + fgs = wx.FlexGridSizer(cols=11, hgap=5, vgap=5) + fgs.AddMany([ (wx.StaticText(self, -1, "x1:"), 0, wx.ALIGN_CENTER_VERTICAL), + self.x1, + ((5,1)), + (wx.StaticText(self, -1, "y1:"), 0, wx.ALIGN_CENTER_VERTICAL), + self.y1] ) + fgs.Add((40,1)) + fgs.AddMany([ (wx.StaticText(self, -1, "x2:"), 0, wx.ALIGN_CENTER_VERTICAL), + self.x2, + ((5,1)), + (wx.StaticText(self, -1, "y2:"), 0, wx.ALIGN_CENTER_VERTICAL), + self.y2] ) + sizer.Add(fgs, 0, wx.LEFT, 25) + + sizer.Add((1,15)) + sizer.Add(label2) + sizer.Add((1, 5)) + self.stopSizer = wx.BoxSizer(wx.VERTICAL) + self.stopSizer.Add(firstStop) + self.stopSizer.Add(lastStop) + self.stopSizer.Add(addStopBtn, 0, wx.TOP, 10) + sizer.Add(self.stopSizer, 0, wx.LEFT, 25) + + border = wx.BoxSizer() + border.Add(sizer, 1, wx.EXPAND|wx.ALL, 15) + self.SetSizer(border) + + self.SetLimits() + self.UpdateBrush() + + + def RemoveStop(self, stop): + self.stops.remove(stop) + stop.Destroy() + self.Layout() + self.SetLimits() + self.UpdateBrush() + + + def OnAddStop(self, evt): + newstop = GradientStopPanel(self, 1.0) + self.stopSizer.Insert(len(self.stops), newstop) + self.stops.append(newstop) + self.Layout() + self.SetLimits() + self.UpdateBrush() + + + def OnPositionUpdated(self, evt): + # called when any of the spinctrls in the nested panels are updated + self.SetLimits() + self.UpdateBrush() + + + def OnColourChanged(self, evt): + # called when any of the color pickers are updated + self.UpdateBrush() + + def OnGeometryChanged(self, evt): + # called for changes to x1,y1 or x2,y2 + self.UpdateBrush() + + + def SetLimits(self): + # Tweak the panels in self.stops to set limits on the allowed + # positions, and to disable those that should not be changed or + # removed. + first = self.stops[0] + last = self.stops[-1] + + first.pos.Disable() + first.minusBtn.Disable() + last.pos.Disable() + last.minusBtn.Disable() + + for idx in range(1, len(self.stops)-1): + prev = self.stops[idx-1] + next = self.stops[idx+1] + stop = self.stops[idx] + + stop.pos.SetMin(prev.pos.GetValue()) + stop.pos.SetMax(next.pos.GetValue()) + stop.pos.Enable() + stop.minusBtn.Enable() + + + def UpdateBrush(self): + """ + This is where the magic happens. We convert all the values from the + widgets on this panel into a collection of gradient stops and then + create a brush from them, and finally, ask the display panel to + repaint itself with that new brush. + """ + def floatOrZero(value): + try: + return float(value) + except ValueError: + return 0.0 + + x1 = floatOrZero(self.x1.Value) + y1 = floatOrZero(self.y1.Value) + x2 = floatOrZero(self.x2.Value) + y2 = floatOrZero(self.y2.Value) + + gstops = g.GraphicsGradientStops() + gstops.SetStartColour(self.stops[0].colour.GetColour()) + gstops.SetEndColour(self.stops[-1].colour.GetColour()) + for s in self.stops[1:-1]: + gs = g.GraphicsGradientStop( + s.colour.GetColour(), s.pos.GetValue()) + gstops.Add(gs) + + ctx = g.GraphicsContext.CreateMeasuringContext() + brush = ctx.CreateLinearGradientBrush(x1,y1, x2,y2, gstops) + self.gpanel.DrawWithBrush(brush) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Gradients on a GraphicsContext

+ +Multi-stop gradients can be used as fills in a wx.GraphicsContext. +This sample shows how to use the GraphicsGradientStops class to +accomplish this and allows the user to experiment with gradients. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Grid.py b/demo/Grid.py new file mode 100644 index 00000000..98fac36c --- /dev/null +++ b/demo/Grid.py @@ -0,0 +1,96 @@ + +import wx + +#--------------------------------------------------------------------------- + +buttonDefs = { + 814 : ('GridSimple', ' Simple wx.Grid, catching all events '), + 815 : ('GridStdEdRend', ' wx.Grid showing Editors and Renderers '), + 818 : ('GridHugeTable', ' A wx.Grid with a HUGE table (100 MILLION cells!) '), + 817 : ('GridCustTable', ' wx.Grid using a custom Table, with non-string data '), + 819 : ('GridEnterHandler',' Remapping keys to behave differently '), + 820 : ('GridCustEditor', ' Shows how to create a custom Cell Editor '), + 821 : ('GridDragable', ' A wx.Grid with dragable rows and columns '), + 822 : ('GridDragAndDrop', ' Shows how to make a grid a drop target for files'), + } + + +class ButtonPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + box = wx.BoxSizer(wx.VERTICAL) + box.Add((20, 20)) + keys = buttonDefs.keys() + keys.sort() + + for k in keys: + text = buttonDefs[k][1] + btn = wx.Button(self, k, text) + box.Add(btn, 0, wx.ALIGN_CENTER|wx.ALL, 10) + self.Bind(wx.EVT_BUTTON, self.OnButton, btn) + + self.SetSizer(box) + box.Fit(self) + + + def OnButton(self, evt): + modName = buttonDefs[evt.GetId()][0] + module = __import__(modName) + frame = module.TestFrame(None, self.log) + frame.Show(True) + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = ButtonPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + + +overview = """\ + +

wx.grid.Grid

+ +This demo shows various ways of using the wx.grid.Grid class. +

+You can look at the sources for these samples to learn a lot about how +the new classes work. +

    +
  1. GridSimple.py A simple grid that shows +how to catch all the various events. + +

    +

  2. GridStdEdRend.py A grid that +uses non-default Cell Editors and Cell Renderers. + +

    +

  3. GridHugeTable.py A grid that +uses a non-default Grid Table. This table is read-only and simply +generates on the fly a unique string for each cell. + +

    +

  4. GridCustTable.py This grid +shows how to deal with tables that have non-string data, and how Cell +Editors and Cell Renderers are automatically chosen based on the data +type. + +

    +

  5. GridEnterHandler.pyThis one +changes how the ENTER key works, moving the current cell left to right +and wrapping around to the next row when needed. +
+

+ +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/GridBagSizer.py b/demo/GridBagSizer.py new file mode 100644 index 00000000..9ea8df74 --- /dev/null +++ b/demo/GridBagSizer.py @@ -0,0 +1,171 @@ + +import wx # This module uses the new wx namespace + +#---------------------------------------------------------------------- +gbsDescription = """\ +The wx.GridBagSizer is similar to the wx.FlexGridSizer except the items are explicitly positioned +in a virtual cell of the layout grid, and column or row spanning is allowed. For example, this +static text is positioned at (0,0) and it spans 7 columns. +""" + + +class TestFrame(wx.Frame): + def __init__(self): + wx.Frame.__init__(self, None, -1, "wx.GridBagSizer") + p = wx.Panel(self, -1, style = wx.TAB_TRAVERSAL + | wx.CLIP_CHILDREN + | wx.FULL_REPAINT_ON_RESIZE + ) + p.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + + gbs = self.gbs = wx.GridBagSizer(5, 5) + + gbs.Add( wx.StaticText(p, -1, gbsDescription), + (0,0), (1,7), wx.ALIGN_CENTER | wx.ALL, 5) + + gbs.Add( wx.TextCtrl(p, -1, "pos(1,0)"), (1,0) ) + gbs.Add( wx.TextCtrl(p, -1, "pos(1,1)"), (1,1) ) + gbs.Add( wx.TextCtrl(p, -1, "pos(2,0)"), (2,0) ) + gbs.Add( wx.TextCtrl(p, -1, "pos(2,1)"), (2,1) ) + + gbs.Add( wx.TextCtrl(p, -1, "pos(3,2), span(1,2)\nthis row and col are growable", style=wx.TE_MULTILINE), + (3,2), (1,2), flag=wx.EXPAND ) + + gbs.Add( wx.TextCtrl(p, -1, "pos(4,3), span(3,1)", style=wx.TE_MULTILINE), + (4,3), (3,1), wx.EXPAND) + + gbs.Add( wx.TextCtrl(p, -1, "pos(5,4)"), (5,4), flag=wx.EXPAND ) + gbs.Add( wx.TextCtrl(p, -1, "pos(6,5)"), (6,5), flag=wx.EXPAND ) + gbs.Add( wx.TextCtrl(p, -1, "pos(7,6)"), (7,6) ) + + moveBtn1 = wx.Button(p, -1, "Move this to (3,6)") + moveBtn2 = wx.Button(p, -1, "Move this to (3,6)"); + gbs.Add( moveBtn1, (10,2) ) + gbs.Add( moveBtn2, (10,3) ) + + hideBtn = wx.Button(p, -1, "Hide this item -->") + gbs.Add(hideBtn, (12, 3)) + + hideTxt = wx.TextCtrl(p, -1, "pos(12,4), size(150, -1)", size = (150,-1)) + gbs.Add( hideTxt, (12,4) ) + + showBtn = wx.Button(p, -1, "<-- Show it again") + gbs.Add(showBtn, (12, 5)) + showBtn.Disable() + self.hideBtn = hideBtn + self.showBtn = showBtn + self.hideTxt = hideTxt + + self.Bind(wx.EVT_BUTTON, self.OnHideButton, hideBtn) + self.Bind(wx.EVT_BUTTON, self.OnShowButton, showBtn) + self.Bind(wx.EVT_BUTTON, self.OnMoveButton, moveBtn1) + self.Bind(wx.EVT_BUTTON, self.OnMoveButton, moveBtn2) + + # Add a spacer at the end to ensure some extra space at the bottom + gbs.Add((10,10), (14,7)) + + gbs.AddGrowableRow(3) + gbs.AddGrowableCol(2) + + box = wx.BoxSizer() + box.Add(gbs, 1, wx.ALL|wx.EXPAND, 10) + + p.SetSizer(box) + self.SetClientSize(p.GetBestSize()) + + + def OnHideButton(self, evt): + self.gbs.Hide(self.hideTxt) + self.hideBtn.Disable() + self.showBtn.Enable() + self.gbs.Layout() + + + def OnShowButton(self, evt): + self.gbs.Show(self.hideTxt) + self.hideBtn.Enable() + self.showBtn.Disable() + self.gbs.Layout() + + + def OnMoveButton(self, evt): + btn = evt.GetEventObject() + curPos = self.gbs.GetItemPosition(btn) + + # if it's already at the "other" spot then move it back + if curPos == (3,6): + self.gbs.SetItemPosition(btn, self.lastPos) + btn.SetLabel("Move this to (3,6)") + else: + if self.gbs.CheckForIntersectionPos( (3,6), (1,1) ): + wx.MessageBox("""\ +wx.GridBagSizer will not allow items to be in the same cell as +another item, so this operation will fail. You will also get an +assert when compiled in debug mode.""", + "Warning", wx.OK | wx.ICON_INFORMATION) + + try: + if self.gbs.SetItemPosition(btn, (3,6)): + self.lastPos = curPos + btn.SetLabel("Move it back") + except wx.PyAssertionError: + pass + + self.gbs.Layout() + + + def OnLeftDown(self, evt): + pt = evt.GetPosition() + item = self.gbs.FindItemAtPoint(pt) + if item is None: + print "no item at", `pt` + else: + print "item found: ", `item.GetPos()`, "--", `item.GetSpan()` + + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show the GridBagSizer sample", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = TestFrame() + win.Show(True) + + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.GridBagSizer

+ +The wx.GridBagSizer is more or less a port of the the RowColSizer (that +has been in the wxPython.lib package for quite some time) to C++. It +allows items to be placed at specific layout grid cells, and items can +span across more than one row or column. + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/GridCustEditor.py b/demo/GridCustEditor.py new file mode 100644 index 00000000..22d6e5bc --- /dev/null +++ b/demo/GridCustEditor.py @@ -0,0 +1,243 @@ + +import string + +import wx +import wx.grid as gridlib + +#--------------------------------------------------------------------------- +class MyCellEditor(gridlib.PyGridCellEditor): + """ + This is a sample GridCellEditor that shows you how to make your own custom + grid editors. All the methods that can be overridden are shown here. The + ones that must be overridden are marked with "*Must Override*" in the + docstring. + """ + def __init__(self, log): + self.log = log + self.log.write("MyCellEditor ctor\n") + gridlib.PyGridCellEditor.__init__(self) + + + def Create(self, parent, id, evtHandler): + """ + Called to create the control, which must derive from wx.Control. + *Must Override* + """ + self.log.write("MyCellEditor: Create\n") + self._tc = wx.TextCtrl(parent, id, "") + self._tc.SetInsertionPoint(0) + self.SetControl(self._tc) + + if evtHandler: + self._tc.PushEventHandler(evtHandler) + + + def SetSize(self, rect): + """ + Called to position/size the edit control within the cell rectangle. + If you don't fill the cell (the rect) then be sure to override + PaintBackground and do something meaningful there. + """ + self.log.write("MyCellEditor: SetSize %s\n" % rect) + self._tc.SetDimensions(rect.x, rect.y, rect.width+2, rect.height+2, + wx.SIZE_ALLOW_MINUS_ONE) + + + def Show(self, show, attr): + """ + Show or hide the edit control. You can use the attr (if not None) + to set colours or fonts for the control. + """ + self.log.write("MyCellEditor: Show(self, %s, %s)\n" % (show, attr)) + super(MyCellEditor, self).Show(show, attr) + + + def PaintBackground(self, rect, attr): + """ + Draws the part of the cell not occupied by the edit control. The + base class version just fills it with background colour from the + attribute. In this class the edit control fills the whole cell so + don't do anything at all in order to reduce flicker. + """ + self.log.write("MyCellEditor: PaintBackground\n") + + + def BeginEdit(self, row, col, grid): + """ + Fetch the value from the table and prepare the edit control + to begin editing. Set the focus to the edit control. + *Must Override* + """ + self.log.write("MyCellEditor: BeginEdit (%d,%d)\n" % (row, col)) + self.startValue = grid.GetTable().GetValue(row, col) + self._tc.SetValue(self.startValue) + self._tc.SetInsertionPointEnd() + self._tc.SetFocus() + + # For this example, select the text + self._tc.SetSelection(0, self._tc.GetLastPosition()) + + + def EndEdit(self, row, col, grid, oldVal): + """ + End editing the cell. This function must check if the current + value of the editing control is valid and different from the + original value (available as oldval in its string form.) If + it has not changed then simply return None, otherwise return + the value in its string form. + *Must Override* + """ + self.log.write("MyCellEditor: EndEdit (%s)\n" % oldVal) + val = self._tc.GetValue() + if val != oldVal: #self.startValue: + return val + else: + return None + + + def ApplyEdit(self, row, col, grid): + """ + This function should save the value of the control into the + grid or grid table. It is called only after EndEdit() returns + a non-None value. + *Must Override* + """ + self.log.write("MyCellEditor: ApplyEdit (%d,%d)\n" % (row, col)) + val = self._tc.GetValue() + grid.GetTable().SetValue(row, col, val) # update the table + + self.startValue = '' + self._tc.SetValue('') + + + def Reset(self): + """ + Reset the value in the control back to its starting value. + *Must Override* + """ + self.log.write("MyCellEditor: Reset\n") + self._tc.SetValue(self.startValue) + self._tc.SetInsertionPointEnd() + + + def IsAcceptedKey(self, evt): + """ + Return True to allow the given key to start editing: the base class + version only checks that the event has no modifiers. F2 is special + and will always start the editor. + """ + self.log.write("MyCellEditor: IsAcceptedKey: %d\n" % (evt.GetKeyCode())) + + ## We can ask the base class to do it + #return super(MyCellEditor, self).IsAcceptedKey(evt) + + # or do it ourselves + return (not (evt.ControlDown() or evt.AltDown()) and + evt.GetKeyCode() != wx.WXK_SHIFT) + + + def StartingKey(self, evt): + """ + If the editor is enabled by pressing keys on the grid, this will be + called to let the editor do something about that first key if desired. + """ + self.log.write("MyCellEditor: StartingKey %d\n" % evt.GetKeyCode()) + key = evt.GetKeyCode() + ch = None + if key in [ wx.WXK_NUMPAD0, wx.WXK_NUMPAD1, wx.WXK_NUMPAD2, wx.WXK_NUMPAD3, + wx.WXK_NUMPAD4, wx.WXK_NUMPAD5, wx.WXK_NUMPAD6, wx.WXK_NUMPAD7, + wx.WXK_NUMPAD8, wx.WXK_NUMPAD9 + ]: + + ch = ch = chr(ord('0') + key - wx.WXK_NUMPAD0) + + elif key < 256 and key >= 0 and chr(key) in string.printable: + ch = chr(key) + + if ch is not None: + # For this example, replace the text. Normally we would append it. + #self._tc.AppendText(ch) + self._tc.SetValue(ch) + self._tc.SetInsertionPointEnd() + else: + evt.Skip() + + + def StartingClick(self): + """ + If the editor is enabled by clicking on the cell, this method will be + called to allow the editor to simulate the click on the control if + needed. + """ + self.log.write("MyCellEditor: StartingClick\n") + + + def Destroy(self): + """final cleanup""" + self.log.write("MyCellEditor: Destroy\n") + super(MyCellEditor, self).Destroy() + + + def Clone(self): + """ + Create a new object which is the copy of this one + *Must Override* + """ + self.log.write("MyCellEditor: Clone\n") + return MyCellEditor(self.log) + + +#--------------------------------------------------------------------------- +class GridEditorTest(gridlib.Grid): + def __init__(self, parent, log): + gridlib.Grid.__init__(self, parent, -1) + self.log = log + + self.CreateGrid(10, 3) + + # Somebody changed the grid so the type registry takes precedence + # over the default attribute set for editors and renderers, so we + # have to set null handlers for the type registry before the + # default editor will get used otherwise... + #self.RegisterDataType(wxGRID_VALUE_STRING, None, None) + #self.SetDefaultEditor(MyCellEditor(self.log)) + + # Or we could just do it like this: + #self.RegisterDataType(wx.GRID_VALUE_STRING, + # wx.GridCellStringRenderer(), + # MyCellEditor(self.log)) + # ) + + # but for this example, we'll just set the custom editor on one cell + self.SetCellEditor(1, 0, MyCellEditor(self.log)) + self.SetCellValue(1, 0, "Try to edit this box") + + # and on a column + attr = gridlib.GridCellAttr() + attr.SetEditor(MyCellEditor(self.log)) + self.SetColAttr(2, attr) + self.SetCellValue(1, 2, "or any in this column") + + self.SetColSize(0, 150) + self.SetColSize(1, 150) + self.SetColSize(2, 150) + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, "Custom Grid Cell Editor Test", + size=(640,480)) + grid = GridEditorTest(self, log) + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.PySimpleApp() + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + + diff --git a/demo/GridCustTable.py b/demo/GridCustTable.py new file mode 100644 index 00000000..17ec48d2 --- /dev/null +++ b/demo/GridCustTable.py @@ -0,0 +1,173 @@ + +import wx +import wx.grid as gridlib + +#--------------------------------------------------------------------------- + +class CustomDataTable(gridlib.PyGridTableBase): + def __init__(self, log): + gridlib.PyGridTableBase.__init__(self) + self.log = log + + self.colLabels = ['ID', 'Description', 'Severity', 'Priority', 'Platform', + 'Opened?', 'Fixed?', 'Tested?', 'TestFloat'] + + self.dataTypes = [gridlib.GRID_VALUE_NUMBER, + gridlib.GRID_VALUE_STRING, + gridlib.GRID_VALUE_CHOICE + ':only in a million years!,wish list,minor,normal,major,critical', + gridlib.GRID_VALUE_NUMBER + ':1,5', + gridlib.GRID_VALUE_CHOICE + ':all,MSW,GTK,other', + gridlib.GRID_VALUE_BOOL, + gridlib.GRID_VALUE_BOOL, + gridlib.GRID_VALUE_BOOL, + gridlib.GRID_VALUE_FLOAT + ':6,2', + ] + + self.data = [ + [1010, "The foo doesn't bar", "major", 1, 'MSW', 1, 1, 1, 1.12], + [1011, "I've got a wicket in my wocket", "wish list", 2, 'other', 0, 0, 0, 1.50], + [1012, "Rectangle() returns a triangle", "critical", 5, 'all', 0, 0, 0, 1.56] + + ] + + + #-------------------------------------------------- + # required methods for the wxPyGridTableBase interface + + def GetNumberRows(self): + return len(self.data) + 1 + + def GetNumberCols(self): + return len(self.data[0]) + + def IsEmptyCell(self, row, col): + try: + return not self.data[row][col] + except IndexError: + return True + + # Get/Set values in the table. The Python version of these + # methods can handle any data-type, (as long as the Editor and + # Renderer understands the type too,) not just strings as in the + # C++ version. + def GetValue(self, row, col): + try: + return self.data[row][col] + except IndexError: + return '' + + def SetValue(self, row, col, value): + def innerSetValue(row, col, value): + try: + self.data[row][col] = value + except IndexError: + # add a new row + self.data.append([''] * self.GetNumberCols()) + innerSetValue(row, col, value) + + # tell the grid we've added a row + msg = gridlib.GridTableMessage(self, # The table + gridlib.GRIDTABLE_NOTIFY_ROWS_APPENDED, # what we did to it + 1 # how many + ) + + self.GetView().ProcessTableMessage(msg) + innerSetValue(row, col, value) + + #-------------------------------------------------- + # Some optional methods + + # Called when the grid needs to display labels + def GetColLabelValue(self, col): + return self.colLabels[col] + + # Called to determine the kind of editor/renderer to use by + # default, doesn't necessarily have to be the same type used + # natively by the editor/renderer if they know how to convert. + def GetTypeName(self, row, col): + return self.dataTypes[col] + + # Called to determine how the data can be fetched and stored by the + # editor and renderer. This allows you to enforce some type-safety + # in the grid. + def CanGetValueAs(self, row, col, typeName): + colType = self.dataTypes[col].split(':')[0] + if typeName == colType: + return True + else: + return False + + def CanSetValueAs(self, row, col, typeName): + return self.CanGetValueAs(row, col, typeName) + + + + + +#--------------------------------------------------------------------------- + + + +class CustTableGrid(gridlib.Grid): + def __init__(self, parent, log): + gridlib.Grid.__init__(self, parent, -1) + + table = CustomDataTable(log) + + # The second parameter means that the grid is to take ownership of the + # table and will destroy it when done. Otherwise you would need to keep + # a reference to it and call it's Destroy method later. + self.SetTable(table, True) + + self.SetRowLabelSize(0) + self.SetMargins(0,0) + self.AutoSizeColumns(False) + + gridlib.EVT_GRID_CELL_LEFT_DCLICK(self, self.OnLeftDClick) + + + # I do this because I don't like the default behaviour of not starting the + # cell editor on double clicks, but only a second click. + def OnLeftDClick(self, evt): + if self.CanEnableCellControl(): + self.EnableCellEditControl() + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + + wx.Frame.__init__( + self, parent, -1, "Custom Table, data driven Grid Demo", size=(640,480) + ) + + p = wx.Panel(self, -1, style=0) + grid = CustTableGrid(p, log) + b = wx.Button(p, -1, "Another Control...") + b.SetDefault() + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + b.Bind(wx.EVT_SET_FOCUS, self.OnButtonFocus) + bs = wx.BoxSizer(wx.VERTICAL) + bs.Add(grid, 1, wx.GROW|wx.ALL, 5) + bs.Add(b) + p.SetSizer(bs) + + def OnButton(self, evt): + print "button selected" + + def OnButtonFocus(self, evt): + print "button focus" + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.PySimpleApp() + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + + +#--------------------------------------------------------------------------- diff --git a/demo/GridDragAndDrop.py b/demo/GridDragAndDrop.py new file mode 100644 index 00000000..f3e0e9c5 --- /dev/null +++ b/demo/GridDragAndDrop.py @@ -0,0 +1,99 @@ + +""" +Example showing how to make a grid a drop target for files. + +""" + +import wx +import wx.grid as gridlib + +#--------------------------------------------------------------------------- +# Set VIRTUAL to 1 to use a virtual grid +VIRTUAL = 1 +#--------------------------------------------------------------------------- + +class GridFileDropTarget(wx.FileDropTarget): + def __init__(self, grid): + wx.FileDropTarget.__init__(self) + self.grid = grid + + def OnDropFiles(self, x, y, filenames): + # the x,y coordinates here are Unscrolled coordinates. They must be changed + # to scrolled coordinates. + x, y = self.grid.CalcUnscrolledPosition(x, y) + + # now we need to get the row and column from the grid + col = self.grid.XToCol(x) + row = self.grid.YToRow(y) + + if row > -1 and col > -1: + self.grid.SetCellValue(row, col, filenames[0]) + self.grid.AutoSizeColumn(col) + self.grid.Refresh() + + + +class FooTable(gridlib.PyGridTableBase): + def __init__(self): + gridlib.PyGridTableBase.__init__(self) + self.dropTargets = {(0,0):"Drag", + (1,0):"A", + (2,0):"File", + (3,0):"To", + (4,0):"A", + (5,0):"Cell"} + def GetNumberCols(self): + return 100 + def GetNumberRows(self): + return 100 + def GetValue(self, row, col): + return self.dropTargets.get((row, col), "") + + +class SimpleGrid(gridlib.Grid): + def __init__(self, parent, log): + gridlib.Grid.__init__(self, parent, -1) + self.log = log + self.moveTo = None + + if VIRTUAL: + self.table = FooTable() + self.SetTable(self.table) + else: + self.CreateGrid(25, 25) + + # set the drag and drop target + dropTarget = GridFileDropTarget(self) + self.SetDropTarget(dropTarget) + self.EnableDragRowSize() + self.EnableDragColSize() + + def SetCellValue(self, row, col, value): + if VIRTUAL: + self.table.dropTargets[row, col] = value + else: + gridlib.Grid.SetCellValue(self, row, col, value) + + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, "DragAndDrop Grid", size=(640,480)) + grid = SimpleGrid(self, log) + + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.PySimpleApp() + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + + +#--------------------------------------------------------------------------- + + + + diff --git a/demo/GridDragable.py b/demo/GridDragable.py new file mode 100644 index 00000000..8f375b8e --- /dev/null +++ b/demo/GridDragable.py @@ -0,0 +1,205 @@ + +import wx +import wx.grid as gridlib +import wx.lib.gridmovers as gridmovers + +#--------------------------------------------------------------------------- + +class CustomDataTable(gridlib.PyGridTableBase): + def __init__(self, log): + gridlib.PyGridTableBase.__init__(self) + self.log = log + + self.identifiers = ['id','ds','sv','pr','pl','op','fx','ts'] + + self.rowLabels = ['Row1','Row2','Row3'] + + self.colLabels = {'id':'ID','ds':'Description','sv':'Severity', + 'pr':'Priority','pl':'Platform','op':'Opened?', + 'fx':'Fixed?','ts':'Tested?'} + + self.data = [{'id':1010, + 'ds':"The foo doesn't bar", + 'sv':"major", + 'pr':1, + 'pl':'MSW', + 'op':1, + 'fx':1, + 'ts':1 + }, + {'id':1011, + 'ds':"I've got a wicket in my wocket", + 'sv':"wish list", + 'pr':2, + 'pl':'other', + 'op':0, + 'fx':0, + 'ts':0 + }, + {'id':1012, + 'ds':"Rectangle() returns a triangle", + 'sv':"critical", + 'pr':5, + 'pl':'all', + 'op':0, + 'fx':0, + 'ts':0 + } + ] + + #-------------------------------------------------- + # required methods for the wxPyGridTableBase interface + + def GetNumberRows(self): + return len(self.data) + + def GetNumberCols(self): + return len(self.identifiers) + + def IsEmptyCell(self, row, col): + id = self.identifiers[col] + return not self.data[row][id] + + def GetValue(self, row, col): + id = self.identifiers[col] + return self.data[row][id] + + def SetValue(self, row, col, value): + id = self.identifiers[col] + self.data[row][id] = value + + #-------------------------------------------------- + # Some optional methods + + # Called when the grid needs to display column labels + def GetColLabelValue(self, col): + id = self.identifiers[col] + return self.colLabels[id] + + # Called when the grid needs to display row labels + def GetRowLabelValue(self,row): + return self.rowLabels[row] + + #-------------------------------------------------- + # Methods added for demo purposes. + + # The physical moving of the cols/rows is left to the implementer. + # Because of the dynamic nature of a wxGrid the physical moving of + # columns differs from implementation to implementation + + # Move the column + def MoveColumn(self,frm,to): + grid = self.GetView() + + if grid: + # Move the identifiers + old = self.identifiers[frm] + del self.identifiers[frm] + + if to > frm: + self.identifiers.insert(to-1,old) + else: + self.identifiers.insert(to,old) + + # Notify the grid + grid.BeginBatch() + msg = gridlib.GridTableMessage( + self, gridlib.GRIDTABLE_NOTIFY_COLS_DELETED, frm, 1 + ) + + grid.ProcessTableMessage(msg) + + msg = gridlib.GridTableMessage( + self, gridlib.GRIDTABLE_NOTIFY_COLS_INSERTED, to, 1 + ) + + grid.ProcessTableMessage(msg) + grid.EndBatch() + + # Move the row + def MoveRow(self,frm,to): + grid = self.GetView() + + if grid: + # Move the rowLabels and data rows + oldLabel = self.rowLabels[frm] + oldData = self.data[frm] + del self.rowLabels[frm] + del self.data[frm] + + if to > frm: + self.rowLabels.insert(to-1,oldLabel) + self.data.insert(to-1,oldData) + else: + self.rowLabels.insert(to,oldLabel) + self.data.insert(to,oldData) + + # Notify the grid + grid.BeginBatch() + + msg = gridlib.GridTableMessage( + self, gridlib.GRIDTABLE_NOTIFY_ROWS_DELETED, frm, 1 + ) + + grid.ProcessTableMessage(msg) + + msg = gridlib.GridTableMessage( + self, gridlib.GRIDTABLE_NOTIFY_ROWS_INSERTED, to, 1 + ) + + grid.ProcessTableMessage(msg) + grid.EndBatch() + + +#--------------------------------------------------------------------------- + + +class DragableGrid(gridlib.Grid): + def __init__(self, parent, log): + gridlib.Grid.__init__(self, parent, -1) + + table = CustomDataTable(log) + + # The second parameter means that the grid is to take ownership of the + # table and will destroy it when done. Otherwise you would need to keep + # a reference to it and call it's Destroy method later. + self.SetTable(table, True) + + # Enable Column moving + gridmovers.GridColMover(self) + self.Bind(gridmovers.EVT_GRID_COL_MOVE, self.OnColMove, self) + + # Enable Row moving + gridmovers.GridRowMover(self) + self.Bind(gridmovers.EVT_GRID_ROW_MOVE, self.OnRowMove, self) + + # Event method called when a column move needs to take place + def OnColMove(self,evt): + frm = evt.GetMoveColumn() # Column being moved + to = evt.GetBeforeColumn() # Before which column to insert + self.GetTable().MoveColumn(frm,to) + + # Event method called when a row move needs to take place + def OnRowMove(self,evt): + frm = evt.GetMoveRow() # Row being moved + to = evt.GetBeforeRow() # Before which row to insert + self.GetTable().MoveRow(frm,to) + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, "Custom Table, data driven Grid Demo", size=(640,480)) + grid = DragableGrid(self, log) + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.PySimpleApp() + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + +#--------------------------------------------------------------------------- diff --git a/demo/GridEnterHandler.py b/demo/GridEnterHandler.py new file mode 100644 index 00000000..638eac61 --- /dev/null +++ b/demo/GridEnterHandler.py @@ -0,0 +1,65 @@ + +import wx +import wx.grid as gridlib + +#--------------------------------------------------------------------------- + +class NewEnterHandlingGrid(gridlib.Grid): + def __init__(self, parent, log): + gridlib.Grid.__init__(self, parent, -1) + self.log = log + + self.CreateGrid(20, 6) + + self.SetCellValue(0, 0, "Enter moves to the right") + self.SetCellValue(0, 5, "Enter wraps to next row") + self.SetColSize(0, 150) + self.SetColSize(5, 150) + + self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) + + + def OnKeyDown(self, evt): + if evt.GetKeyCode() != wx.WXK_RETURN: + evt.Skip() + return + + if evt.ControlDown(): # the edit control needs this key + evt.Skip() + return + + self.DisableCellEditControl() + success = self.MoveCursorRight(evt.ShiftDown()) + + if not success: + newRow = self.GetGridCursorRow() + 1 + + if newRow < self.GetTable().GetNumberRows(): + self.SetGridCursor(newRow, 0) + self.MakeCellVisible(newRow, 0) + else: + # this would be a good place to add a new row if your app + # needs to do that + pass + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, "Simple Grid Demo", size=(640,480)) + grid = NewEnterHandlingGrid(self, log) + + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.PySimpleApp() + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + + +#--------------------------------------------------------------------------- diff --git a/demo/GridHugeTable.py b/demo/GridHugeTable.py new file mode 100644 index 00000000..cd5d2e25 --- /dev/null +++ b/demo/GridHugeTable.py @@ -0,0 +1,87 @@ + +import wx +import wx.grid as gridlib + +#--------------------------------------------------------------------------- + +class HugeTable(gridlib.PyGridTableBase): + + def __init__(self, log): + gridlib.PyGridTableBase.__init__(self) + self.log = log + + self.odd=gridlib.GridCellAttr() + self.odd.SetBackgroundColour("sky blue") + self.even=gridlib.GridCellAttr() + self.even.SetBackgroundColour("sea green") + + def GetAttr(self, row, col, kind): + attr = [self.even, self.odd][row % 2] + attr.IncRef() + return attr + + + + # This is all it takes to make a custom data table to plug into a + # wxGrid. There are many more methods that can be overridden, but + # the ones shown below are the required ones. This table simply + # provides strings containing the row and column values. + + def GetNumberRows(self): + return 10000 + + def GetNumberCols(self): + return 10000 + + def IsEmptyCell(self, row, col): + return False + + def GetValue(self, row, col): + return str( (row, col) ) + + def SetValue(self, row, col, value): + self.log.write('SetValue(%d, %d, "%s") ignored.\n' % (row, col, value)) + + +#--------------------------------------------------------------------------- + + + +class HugeTableGrid(gridlib.Grid): + def __init__(self, parent, log): + gridlib.Grid.__init__(self, parent, -1) + + table = HugeTable(log) + + # The second parameter means that the grid is to take ownership of the + # table and will destroy it when done. Otherwise you would need to keep + # a reference to it and call it's Destroy method later. + self.SetTable(table, True) + + self.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK, self.OnRightDown) + + def OnRightDown(self, event): + print "hello" + print self.GetSelectedRows() + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, "Huge (virtual) Table Demo", size=(640,480)) + grid = HugeTableGrid(self, log) + + grid.SetReadOnly(5,5, True) + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.PySimpleApp() + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + + +#--------------------------------------------------------------------------- diff --git a/demo/GridLabelRenderer.py b/demo/GridLabelRenderer.py new file mode 100644 index 00000000..7218ecb5 --- /dev/null +++ b/demo/GridLabelRenderer.py @@ -0,0 +1,112 @@ + +import wx +import wx.grid as grid +import wx.lib.mixins.gridlabelrenderer as glr + +#---------------------------------------------------------------------- + +class MyGrid(grid.Grid, glr.GridWithLabelRenderersMixin): + def __init__(self, *args, **kw): + grid.Grid.__init__(self, *args, **kw) + glr.GridWithLabelRenderersMixin.__init__(self) + + +class MyRowLabelRenderer(glr.GridLabelRenderer): + def __init__(self, bgcolor): + self._bgcolor = bgcolor + + def Draw(self, grid, dc, rect, row): + dc.SetBrush(wx.Brush(self._bgcolor)) + dc.SetPen(wx.TRANSPARENT_PEN) + dc.DrawRectangleRect(rect) + hAlign, vAlign = grid.GetRowLabelAlignment() + text = grid.GetRowLabelValue(row) + self.DrawBorder(grid, dc, rect) + self.DrawText(grid, dc, rect, text, hAlign, vAlign) + + +class MyColLabelRenderer(glr.GridLabelRenderer): + def __init__(self, bgcolor): + self._bgcolor = bgcolor + + def Draw(self, grid, dc, rect, col): + dc.SetBrush(wx.Brush(self._bgcolor)) + dc.SetPen(wx.TRANSPARENT_PEN) + dc.DrawRectangleRect(rect) + hAlign, vAlign = grid.GetColLabelAlignment() + text = grid.GetColLabelValue(col) + self.DrawBorder(grid, dc, rect) + self.DrawText(grid, dc, rect, text, hAlign, vAlign) + + +class MyCornerLabelRenderer(glr.GridLabelRenderer): + def __init__(self): + import images + self._bmp = images.Smiles.getBitmap() + + def Draw(self, grid, dc, rect, rc): + x = rect.left + (rect.width - self._bmp.GetWidth()) / 2 + y = rect.top + (rect.height - self._bmp.GetHeight()) / 2 + dc.DrawBitmap(self._bmp, x, y, True) + + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + ROWS = 27 + COLS = 15 + + g = MyGrid(self, size=(100,100)) + g.CreateGrid(ROWS, COLS) + + g.SetCornerLabelRenderer(MyCornerLabelRenderer()) + + for row in range(0, ROWS, 3): + g.SetRowLabelRenderer(row+0, MyRowLabelRenderer('#ffe0e0')) + g.SetRowLabelRenderer(row+1, MyRowLabelRenderer('#e0ffe0')) + g.SetRowLabelRenderer(row+2, MyRowLabelRenderer('#e0e0ff')) + + for col in range(0, COLS, 3): + g.SetColLabelRenderer(col+0, MyColLabelRenderer('#e0ffe0')) + g.SetColLabelRenderer(col+1, MyColLabelRenderer('#e0e0ff')) + g.SetColLabelRenderer(col+2, MyColLabelRenderer('#ffe0e0')) + + self.Sizer = wx.BoxSizer() + self.Sizer.Add(g, 1, wx.EXPAND) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

GridLabelRenderer

+ +The wx.lib.mixins.gridlabelrenderer module provides a mixin +class for wx.grid.Grid that enables it to have plugin renderers that +work like the normal cell renderers do. If desired you can specify a +different renderer for each row or col label, and even for the little +corner label in the upper left corner of the grid. When each of those +labels needs to be drawn the mixin calls the render's Draw method with +the dc and rectangle, allowing your renderer class do do just about +anything that it wants. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/GridSimple.py b/demo/GridSimple.py new file mode 100644 index 00000000..9939748a --- /dev/null +++ b/demo/GridSimple.py @@ -0,0 +1,269 @@ + +import wx +import wx.grid as gridlib +#import wx.lib.mixins.grid as mixins + +#--------------------------------------------------------------------------- + +class SimpleGrid(gridlib.Grid): ##, mixins.GridAutoEditMixin): + def __init__(self, parent, log): + gridlib.Grid.__init__(self, parent, -1) + ##mixins.GridAutoEditMixin.__init__(self) + self.log = log + self.moveTo = None + + self.Bind(wx.EVT_IDLE, self.OnIdle) + + self.CreateGrid(25, 25)#, gridlib.Grid.SelectRows) + ##self.EnableEditing(False) + + # simple cell formatting + self.SetColSize(3, 200) + self.SetRowSize(4, 45) + self.SetCellValue(0, 0, "First cell") + self.SetCellValue(1, 1, "Another cell") + self.SetCellValue(2, 2, "Yet another cell") + self.SetCellValue(3, 3, "This cell is read-only") + self.SetCellFont(0, 0, wx.Font(12, wx.ROMAN, wx.ITALIC, wx.NORMAL)) + self.SetCellTextColour(1, 1, wx.RED) + self.SetCellBackgroundColour(2, 2, wx.CYAN) + self.SetReadOnly(3, 3, True) + + self.SetCellEditor(5, 0, gridlib.GridCellNumberEditor(1,1000)) + self.SetCellValue(5, 0, "123") + self.SetCellEditor(6, 0, gridlib.GridCellFloatEditor()) + self.SetCellValue(6, 0, "123.34") + self.SetCellEditor(7, 0, gridlib.GridCellNumberEditor()) + + self.SetCellValue(6, 3, "You can veto editing this cell") + + #self.SetRowLabelSize(0) + #self.SetColLabelSize(0) + + # attribute objects let you keep a set of formatting values + # in one spot, and reuse them if needed + attr = gridlib.GridCellAttr() + attr.SetTextColour(wx.BLACK) + attr.SetBackgroundColour(wx.RED) + attr.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)) + + # you can set cell attributes for the whole row (or column) + self.SetRowAttr(5, attr) + + self.SetColLabelValue(0, "Custom") + self.SetColLabelValue(1, "column") + self.SetColLabelValue(2, "labels") + + self.SetColLabelAlignment(wx.ALIGN_LEFT, wx.ALIGN_BOTTOM) + + #self.SetDefaultCellOverflow(False) + #r = gridlib.GridCellAutoWrapStringRenderer() + #self.SetCellRenderer(9, 1, r) + + # overflow cells + self.SetCellValue( 9, 1, "This default cell will overflow into neighboring cells, but not if you turn overflow off."); + self.SetCellSize(11, 1, 3, 3); + self.SetCellAlignment(11, 1, wx.ALIGN_CENTRE, wx.ALIGN_CENTRE); + self.SetCellValue(11, 1, "This cell is set to span 3 rows and 3 columns"); + + + editor = gridlib.GridCellTextEditor() + editor.SetParameters('10') + self.SetCellEditor(0, 4, editor) + self.SetCellValue(0, 4, "Limited text") + + renderer = gridlib.GridCellAutoWrapStringRenderer() + self.SetCellRenderer(15,0, renderer) + self.SetCellValue(15,0, "The text in this cell will be rendered with word-wrapping") + + + # test all the events + self.Bind(gridlib.EVT_GRID_CELL_LEFT_CLICK, self.OnCellLeftClick) + self.Bind(gridlib.EVT_GRID_CELL_RIGHT_CLICK, self.OnCellRightClick) + self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.OnCellLeftDClick) + self.Bind(gridlib.EVT_GRID_CELL_RIGHT_DCLICK, self.OnCellRightDClick) + + self.Bind(gridlib.EVT_GRID_LABEL_LEFT_CLICK, self.OnLabelLeftClick) + self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_CLICK, self.OnLabelRightClick) + self.Bind(gridlib.EVT_GRID_LABEL_LEFT_DCLICK, self.OnLabelLeftDClick) + self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_DCLICK, self.OnLabelRightDClick) + + self.Bind(gridlib.EVT_GRID_COL_SORT, self.OnGridColSort) + + self.Bind(gridlib.EVT_GRID_ROW_SIZE, self.OnRowSize) + self.Bind(gridlib.EVT_GRID_COL_SIZE, self.OnColSize) + + self.Bind(gridlib.EVT_GRID_RANGE_SELECT, self.OnRangeSelect) + self.Bind(gridlib.EVT_GRID_CELL_CHANGE, self.OnCellChange) + self.Bind(gridlib.EVT_GRID_SELECT_CELL, self.OnSelectCell) + + self.Bind(gridlib.EVT_GRID_EDITOR_SHOWN, self.OnEditorShown) + self.Bind(gridlib.EVT_GRID_EDITOR_HIDDEN, self.OnEditorHidden) + self.Bind(gridlib.EVT_GRID_EDITOR_CREATED, self.OnEditorCreated) + + + def OnCellLeftClick(self, evt): + self.log.write("OnCellLeftClick: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + evt.Skip() + + def OnCellRightClick(self, evt): + self.log.write("OnCellRightClick: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + evt.Skip() + + def OnCellLeftDClick(self, evt): + self.log.write("OnCellLeftDClick: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + evt.Skip() + + def OnCellRightDClick(self, evt): + self.log.write("OnCellRightDClick: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + evt.Skip() + + def OnLabelLeftClick(self, evt): + self.log.write("OnLabelLeftClick: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + evt.Skip() + + def OnLabelRightClick(self, evt): + self.log.write("OnLabelRightClick: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + evt.Skip() + + def OnLabelLeftDClick(self, evt): + self.log.write("OnLabelLeftDClick: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + evt.Skip() + + def OnLabelRightDClick(self, evt): + self.log.write("OnLabelRightDClick: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + evt.Skip() + + def OnGridColSort(self, evt): + self.log.write("OnGridColSort: %s %s" % (evt.GetCol(), self.GetSortingColumn())) + self.SetSortingColumn(evt.GetCol()) + + def OnRowSize(self, evt): + self.log.write("OnRowSize: row %d, %s\n" % + (evt.GetRowOrCol(), evt.GetPosition())) + evt.Skip() + + def OnColSize(self, evt): + self.log.write("OnColSize: col %d, %s\n" % + (evt.GetRowOrCol(), evt.GetPosition())) + evt.Skip() + + def OnRangeSelect(self, evt): + if evt.Selecting(): + msg = 'Selected' + else: + msg = 'Deselected' + self.log.write("OnRangeSelect: %s top-left %s, bottom-right %s\n" % + (msg, evt.GetTopLeftCoords(), evt.GetBottomRightCoords())) + evt.Skip() + + + def OnCellChange(self, evt): + self.log.write("OnCellChange: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + + # Show how to stay in a cell that has bad data. We can't just + # call SetGridCursor here since we are nested inside one so it + # won't have any effect. Instead, set coordinates to move to in + # idle time. + value = self.GetCellValue(evt.GetRow(), evt.GetCol()) + + if value == 'no good': + self.moveTo = evt.GetRow(), evt.GetCol() + + + def OnIdle(self, evt): + if self.moveTo != None: + self.SetGridCursor(self.moveTo[0], self.moveTo[1]) + self.moveTo = None + + evt.Skip() + + + def OnSelectCell(self, evt): + if evt.Selecting(): + msg = 'Selected' + else: + msg = 'Deselected' + self.log.write("OnSelectCell: %s (%d,%d) %s\n" % + (msg, evt.GetRow(), evt.GetCol(), evt.GetPosition())) + + # Another way to stay in a cell that has a bad value... + row = self.GetGridCursorRow() + col = self.GetGridCursorCol() + + if self.IsCellEditControlEnabled(): + self.HideCellEditControl() + self.DisableCellEditControl() + + value = self.GetCellValue(row, col) + + if value == 'no good 2': + return # cancels the cell selection + + evt.Skip() + + + def OnEditorShown(self, evt): + if evt.GetRow() == 6 and evt.GetCol() == 3 and \ + wx.MessageBox("Are you sure you wish to edit this cell?", + "Checking", wx.YES_NO) == wx.NO: + evt.Veto() + return + + self.log.write("OnEditorShown: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + evt.Skip() + + + def OnEditorHidden(self, evt): + if evt.GetRow() == 6 and evt.GetCol() == 3 and \ + wx.MessageBox("Are you sure you wish to finish editing this cell?", + "Checking", wx.YES_NO) == wx.NO: + evt.Veto() + return + + self.log.write("OnEditorHidden: (%d,%d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetPosition())) + evt.Skip() + + + def OnEditorCreated(self, evt): + self.log.write("OnEditorCreated: (%d, %d) %s\n" % + (evt.GetRow(), evt.GetCol(), evt.GetControl())) + + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, "Simple Grid Demo", size=(640,480)) + self.grid = SimpleGrid(self, log) + + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + from wx.lib.mixins.inspection import InspectableApp + app = InspectableApp(False) + frame = TestFrame(None, sys.stdout) + frame.Show(True) + #import wx.lib.inspection + #wx.lib.inspection.InspectionTool().Show() + app.MainLoop() + + +#--------------------------------------------------------------------------- + + diff --git a/demo/GridStdEdRend.py b/demo/GridStdEdRend.py new file mode 100644 index 00000000..6a89c3e1 --- /dev/null +++ b/demo/GridStdEdRend.py @@ -0,0 +1,184 @@ + +import random + +import wx +import wx.grid as gridlib + +#--------------------------------------------------------------------------- + +class MyCustomRenderer(gridlib.PyGridCellRenderer): + def __init__(self): + gridlib.PyGridCellRenderer.__init__(self) + + def Draw(self, grid, attr, dc, rect, row, col, isSelected): + dc.SetBackgroundMode(wx.SOLID) + dc.SetBrush(wx.Brush(wx.BLACK, wx.SOLID)) + dc.SetPen(wx.TRANSPARENT_PEN) + dc.DrawRectangleRect(rect) + + dc.SetBackgroundMode(wx.TRANSPARENT) + dc.SetFont(attr.GetFont()) + + text = grid.GetCellValue(row, col) + colors = ["RED", "WHITE", "SKY BLUE"] + x = rect.x + 1 + y = rect.y + 1 + + for ch in text: + dc.SetTextForeground(random.choice(colors)) + dc.DrawText(ch, x, y) + w, h = dc.GetTextExtent(ch) + x = x + w + if x > rect.right - 5: + break + + + def GetBestSize(self, grid, attr, dc, row, col): + text = grid.GetCellValue(row, col) + dc.SetFont(attr.GetFont()) + w, h = dc.GetTextExtent(text) + return wx.Size(w, h) + + + def Clone(self): + return MyCustomRenderer() + + +#--------------------------------------------------------------------------- + +rendererDemoData = [ + ('GridCellStringRenderer\n(the default)', 'this is a text value', gridlib.GridCellStringRenderer, ()), + ('GridCellNumberRenderer', '12345', gridlib.GridCellNumberRenderer, ()), + ('GridCellFloatRenderer', '1234.5678', gridlib.GridCellFloatRenderer, (6,2)), + ('GridCellBoolRenderer', '1', gridlib.GridCellBoolRenderer, ()), + ('MyCustomRenderer', 'This is my renderer', MyCustomRenderer, ()), + ] + +editorDemoData = [ + ('GridCellTextEditor\n(the default)', 'Here is some more text', gridlib.GridCellTextEditor, ()), + ('GridCellNumberEditor\nwith min,max', '101', gridlib.GridCellNumberEditor, (5, 10005)), + ('GridCellNumberEditor\nwithout bounds', '101', gridlib.GridCellNumberEditor, ()), + ('GridCellFloatEditor', '1234.5678', gridlib.GridCellFloatEditor, ()), + ('GridCellBoolEditor', '1', gridlib.GridCellBoolEditor, ()), + ('GridCellChoiceEditor', 'one', gridlib.GridCellChoiceEditor, (['one', 'two', 'three', 'four', + 'kick', 'Microsoft', 'out the', + 'door'], False)), + ] + +comboDemoData = [ + ('GridCellNumberRenderer\nGridCellNumberEditor', '20792', gridlib.GridCellNumberRenderer, gridlib.GridCellNumberEditor), + ('GridCellBoolRenderer\nGridCellBoolEditor', '1', gridlib.GridCellBoolRenderer, gridlib.GridCellBoolEditor), + ] + + +class EditorsAndRenderersGrid(gridlib.Grid): + def __init__(self, parent, log): + gridlib.Grid.__init__(self, parent, -1) + self.log = log + + self.CreateGrid(25, 8) + renCol = 1 + edCol = 4 + + + self.SetCellValue(0, renCol, '''\ +Cell Renderers are used to draw +the contents of the cell when they +need to be refreshed. Different +types of Renderers can be plugged in +to different cells in the grid, it can +even be automatically determined based +on the type of data in the cell. +''') + + self.SetCellValue(0, edCol, '''\ +Cell Editors are used when the +value of the cell is edited by +the user. An editor class is +wrapped around a an object +derived from wxControl and it +implements some methods required +to integrate with the grid. +''') + + self.SetCellValue(16, renCol, '''\ +Here are some combinations of Editors and +Renderers used together. +''') + + row = 2 + + for label, value, renderClass, args in rendererDemoData: + renderer = renderClass(*args) + self.SetCellValue(row, renCol, label) + self.SetCellValue(row, renCol+1, value) + self.SetCellRenderer(row, renCol+1, renderer) + row = row + 2 + + + row = 2 + + for label, value, editorClass, args in editorDemoData: + editor = editorClass(*args) + self.SetCellValue(row, edCol, label) + self.SetCellValue(row, edCol+1, value) + self.SetCellEditor(row, edCol+1, editor) + row = row + 2 + + + row = 18 + + for label, value, renClass, edClass in comboDemoData: + self.SetCellValue(row, renCol, label) + self.SetCellValue(row, renCol+1, value) + editor = edClass() + renderer = renClass() + self.SetCellEditor(row, renCol+1, editor) + self.SetCellRenderer(row, renCol+1, renderer) + row = row + 2 + + font = self.GetFont() + font.SetWeight(wx.BOLD) + attr = gridlib.GridCellAttr() + attr.SetFont(font) + attr.SetBackgroundColour(wx.LIGHT_GREY) + attr.SetReadOnly(True) + attr.SetAlignment(wx.RIGHT, -1) + self.SetColAttr(renCol, attr) + attr.IncRef() + self.SetColAttr(edCol, attr) + + # There is a bug in wxGTK for this method... + self.AutoSizeColumns(True) + self.AutoSizeRows(True) + + self.Bind(gridlib.EVT_GRID_CELL_LEFT_DCLICK, self.OnLeftDClick) + + + # I do this because I don't like the default behaviour of not starting the + # cell editor on double clicks, but only a second click. + def OnLeftDClick(self, evt): + if self.CanEnableCellControl(): + self.EnableCellEditControl() + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, "Editors and Renderers Demo", size=(640,480)) + grid = EditorsAndRenderersGrid(self, log) + + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.PySimpleApp() + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + + +#--------------------------------------------------------------------------- diff --git a/demo/Grid_MegaExample.py b/demo/Grid_MegaExample.py new file mode 100644 index 00000000..54c02e3a --- /dev/null +++ b/demo/Grid_MegaExample.py @@ -0,0 +1,497 @@ + +import wx +import wx.grid as Grid + +import images + +#--------------------------------------------------------------------------- + +class MegaTable(Grid.PyGridTableBase): + """ + A custom wx.Grid Table using user supplied data + """ + def __init__(self, data, colnames, plugins): + """data is a list of the form + [(rowname, dictionary), + dictionary.get(colname, None) returns the data for column + colname + """ + # The base class must be initialized *first* + Grid.PyGridTableBase.__init__(self) + self.data = data + self.colnames = colnames + self.plugins = plugins or {} + # XXX + # we need to store the row length and column length to + # see if the table has changed size + self._rows = self.GetNumberRows() + self._cols = self.GetNumberCols() + + def GetNumberCols(self): + return len(self.colnames) + + def GetNumberRows(self): + return len(self.data) + + def GetColLabelValue(self, col): + return self.colnames[col] + + def GetRowLabelValue(self, row): + return "row %03d" % int(self.data[row][0]) + + def GetValue(self, row, col): + return str(self.data[row][1].get(self.GetColLabelValue(col), "")) + + def GetRawValue(self, row, col): + return self.data[row][1].get(self.GetColLabelValue(col), "") + + def SetValue(self, row, col, value): + self.data[row][1][self.GetColLabelValue(col)] = value + + def ResetView(self, grid): + """ + (Grid) -> Reset the grid view. Call this to + update the grid if rows and columns have been added or deleted + """ + grid.BeginBatch() + + for current, new, delmsg, addmsg in [ + (self._rows, self.GetNumberRows(), Grid.GRIDTABLE_NOTIFY_ROWS_DELETED, Grid.GRIDTABLE_NOTIFY_ROWS_APPENDED), + (self._cols, self.GetNumberCols(), Grid.GRIDTABLE_NOTIFY_COLS_DELETED, Grid.GRIDTABLE_NOTIFY_COLS_APPENDED), + ]: + + if new < current: + msg = Grid.GridTableMessage(self,delmsg,new,current-new) + grid.ProcessTableMessage(msg) + elif new > current: + msg = Grid.GridTableMessage(self,addmsg,new-current) + grid.ProcessTableMessage(msg) + self.UpdateValues(grid) + + grid.EndBatch() + + self._rows = self.GetNumberRows() + self._cols = self.GetNumberCols() + # update the column rendering plugins + self._updateColAttrs(grid) + + # update the scrollbars and the displayed part of the grid + grid.AdjustScrollbars() + grid.ForceRefresh() + + + def UpdateValues(self, grid): + """Update all displayed values""" + # This sends an event to the grid table to update all of the values + msg = Grid.GridTableMessage(self, Grid.GRIDTABLE_REQUEST_VIEW_GET_VALUES) + grid.ProcessTableMessage(msg) + + def _updateColAttrs(self, grid): + """ + wx.Grid -> update the column attributes to add the + appropriate renderer given the column name. (renderers + are stored in the self.plugins dictionary) + + Otherwise default to the default renderer. + """ + col = 0 + + for colname in self.colnames: + attr = Grid.GridCellAttr() + if colname in self.plugins: + renderer = self.plugins[colname](self) + + if renderer.colSize: + grid.SetColSize(col, renderer.colSize) + + if renderer.rowSize: + grid.SetDefaultRowSize(renderer.rowSize) + + attr.SetReadOnly(True) + attr.SetRenderer(renderer) + + grid.SetColAttr(col, attr) + col += 1 + + # ------------------------------------------------------ + # begin the added code to manipulate the table (non wx related) + def AppendRow(self, row): + #print 'append' + entry = {} + + for name in self.colnames: + entry[name] = "Appended_%i"%row + + # XXX Hack + # entry["A"] can only be between 1..4 + entry["A"] = random.choice(range(4)) + self.data.insert(row, ["Append_%i"%row, entry]) + + def DeleteCols(self, cols): + """ + cols -> delete the columns from the dataset + cols hold the column indices + """ + # we'll cheat here and just remove the name from the + # list of column names. The data will remain but + # it won't be shown + deleteCount = 0 + cols = cols[:] + cols.sort() + + for i in cols: + self.colnames.pop(i-deleteCount) + # we need to advance the delete count + # to make sure we delete the right columns + deleteCount += 1 + + if not len(self.colnames): + self.data = [] + + def DeleteRows(self, rows): + """ + rows -> delete the rows from the dataset + rows hold the row indices + """ + deleteCount = 0 + rows = rows[:] + rows.sort() + + for i in rows: + self.data.pop(i-deleteCount) + # we need to advance the delete count + # to make sure we delete the right rows + deleteCount += 1 + + def SortColumn(self, col): + """ + col -> sort the data based on the column indexed by col + """ + name = self.colnames[col] + _data = [] + + for row in self.data: + rowname, entry = row + _data.append((entry.get(name, None), row)) + + _data.sort() + self.data = [] + + for sortvalue, row in _data: + self.data.append(row) + + # end table manipulation code + # ---------------------------------------------------------- + + +# -------------------------------------------------------------------- +# Sample wx.Grid renderers + +class MegaImageRenderer(Grid.PyGridCellRenderer): + def __init__(self, table): + """ + Image Renderer Test. This just places an image in a cell + based on the row index. There are N choices and the + choice is made by choice[row%N] + """ + Grid.PyGridCellRenderer.__init__(self) + self.table = table + self._choices = [images.Smiles.GetBitmap, + images.Mondrian.GetBitmap, + images.WXPdemo.GetBitmap, + ] + + self.colSize = None + self.rowSize = None + + def Draw(self, grid, attr, dc, rect, row, col, isSelected): + choice = self.table.GetRawValue(row, col) + bmp = self._choices[ choice % len(self._choices)]() + image = wx.MemoryDC() + image.SelectObject(bmp) + + # clear the background + dc.SetBackgroundMode(wx.SOLID) + + if isSelected: + dc.SetBrush(wx.Brush(wx.BLUE, wx.SOLID)) + dc.SetPen(wx.Pen(wx.BLUE, 1, wx.SOLID)) + else: + dc.SetBrush(wx.Brush(wx.WHITE, wx.SOLID)) + dc.SetPen(wx.Pen(wx.WHITE, 1, wx.SOLID)) + dc.DrawRectangleRect(rect) + + + # copy the image but only to the size of the grid cell + width, height = bmp.GetWidth(), bmp.GetHeight() + + if width > rect.width-2: + width = rect.width-2 + + if height > rect.height-2: + height = rect.height-2 + + dc.Blit(rect.x+1, rect.y+1, width, height, + image, + 0, 0, wx.COPY, True) + + +class MegaFontRenderer(Grid.PyGridCellRenderer): + def __init__(self, table, color="blue", font="ARIAL", fontsize=8): + """Render data in the specified color and font and fontsize""" + Grid.PyGridCellRenderer.__init__(self) + self.table = table + self.color = color + self.font = wx.Font(fontsize, wx.DEFAULT, wx.NORMAL, wx.NORMAL, 0, font) + self.selectedBrush = wx.Brush("blue", wx.SOLID) + self.normalBrush = wx.Brush(wx.WHITE, wx.SOLID) + self.colSize = None + self.rowSize = 50 + + def Draw(self, grid, attr, dc, rect, row, col, isSelected): + # Here we draw text in a grid cell using various fonts + # and colors. We have to set the clipping region on + # the grid's DC, otherwise the text will spill over + # to the next cell + dc.SetClippingRect(rect) + + # clear the background + dc.SetBackgroundMode(wx.SOLID) + + if isSelected: + dc.SetBrush(wx.Brush(wx.BLUE, wx.SOLID)) + dc.SetPen(wx.Pen(wx.BLUE, 1, wx.SOLID)) + else: + dc.SetBrush(wx.Brush(wx.WHITE, wx.SOLID)) + dc.SetPen(wx.Pen(wx.WHITE, 1, wx.SOLID)) + dc.DrawRectangleRect(rect) + + text = self.table.GetValue(row, col) + dc.SetBackgroundMode(wx.SOLID) + + # change the text background based on whether the grid is selected + # or not + if isSelected: + dc.SetBrush(self.selectedBrush) + dc.SetTextBackground("blue") + else: + dc.SetBrush(self.normalBrush) + dc.SetTextBackground("white") + + dc.SetTextForeground(self.color) + dc.SetFont(self.font) + dc.DrawText(text, rect.x+1, rect.y+1) + + # Okay, now for the advanced class :) + # Let's add three dots "..." + # to indicate that that there is more text to be read + # when the text is larger than the grid cell + + width, height = dc.GetTextExtent(text) + + if width > rect.width-2: + width, height = dc.GetTextExtent("...") + x = rect.x+1 + rect.width-2 - width + dc.DrawRectangle(x, rect.y+1, width+1, height) + dc.DrawText("...", x, rect.y+1) + + dc.DestroyClippingRegion() + + +# -------------------------------------------------------------------- +# Sample Grid using a specialized table and renderers that can +# be plugged in based on column names + +class MegaGrid(Grid.Grid): + def __init__(self, parent, data, colnames, plugins=None): + """parent, data, colnames, plugins=None + Initialize a grid using the data defined in data and colnames + (see MegaTable for a description of the data format) + plugins is a dictionary of columnName -> column renderers. + """ + + # The base class must be initialized *first* + Grid.Grid.__init__(self, parent, -1) + self._table = MegaTable(data, colnames, plugins) + self.SetTable(self._table) + self._plugins = plugins + + self.Bind(Grid.EVT_GRID_LABEL_RIGHT_CLICK, self.OnLabelRightClicked) + + def Reset(self): + """reset the view based on the data in the table. Call + this when rows are added or destroyed""" + self._table.ResetView(self) + + def OnLabelRightClicked(self, evt): + # Did we click on a row or a column? + row, col = evt.GetRow(), evt.GetCol() + if row == -1: self.colPopup(col, evt) + elif col == -1: self.rowPopup(row, evt) + + def rowPopup(self, row, evt): + """(row, evt) -> display a popup menu when a row label is right clicked""" + appendID = wx.NewId() + deleteID = wx.NewId() + x = self.GetRowSize(row)/2 + + if not self.GetSelectedRows(): + self.SelectRow(row) + + menu = wx.Menu() + xo, yo = evt.GetPosition() + menu.Append(appendID, "Append Row") + menu.Append(deleteID, "Delete Row(s)") + + def append(event, self=self, row=row): + self._table.AppendRow(row) + self.Reset() + + def delete(event, self=self, row=row): + rows = self.GetSelectedRows() + self._table.DeleteRows(rows) + self.Reset() + + self.Bind(wx.EVT_MENU, append, id=appendID) + self.Bind(wx.EVT_MENU, delete, id=deleteID) + self.PopupMenu(menu) + menu.Destroy() + return + + + def colPopup(self, col, evt): + """(col, evt) -> display a popup menu when a column label is + right clicked""" + x = self.GetColSize(col)/2 + menu = wx.Menu() + id1 = wx.NewId() + sortID = wx.NewId() + + xo, yo = evt.GetPosition() + self.SelectCol(col) + cols = self.GetSelectedCols() + self.Refresh() + menu.Append(id1, "Delete Col(s)") + menu.Append(sortID, "Sort Column") + + def delete(event, self=self, col=col): + cols = self.GetSelectedCols() + self._table.DeleteCols(cols) + self.Reset() + + def sort(event, self=self, col=col): + self._table.SortColumn(col) + self.Reset() + + self.Bind(wx.EVT_MENU, delete, id=id1) + + if len(cols) == 1: + self.Bind(wx.EVT_MENU, sort, id=sortID) + + self.PopupMenu(menu) + menu.Destroy() + return + +# ----------------------------------------------------------------- +# Test data +# data is in the form +# [rowname, dictionary] +# where dictionary.get(colname, None) -> returns the value for the cell +# +# the colname must also be supplied +import random +colnames = ["Row", "This", "Is", "A", "Test"] + +data = [] + +for row in range(1000): + d = {} + for name in ["This", "Test", "Is"]: + d[name] = random.random() + + d["Row"] = len(data) + # XXX + # the "A" column can only be between one and 4 + d["A"] = random.choice(range(4)) + data.append((str(row), d)) + +class MegaFontRendererFactory: + def __init__(self, color, font, fontsize): + """ + (color, font, fontsize) -> set of a factory to generate + renderers when called. + func = MegaFontRenderFactory(color, font, fontsize) + renderer = func(table) + """ + self.color = color + self.font = font + self.fontsize = fontsize + + def __call__(self, table): + return MegaFontRenderer(table, self.color, self.font, self.fontsize) + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, plugins={"This":MegaFontRendererFactory("red", "ARIAL", 8), + "A":MegaImageRenderer, + "Test":MegaFontRendererFactory("orange", "TIMES", 24),}): + wx.Frame.__init__(self, parent, -1, + "Test Frame", size=(640,480)) + + grid = MegaGrid(self, data, colnames, plugins) + grid.Reset() + + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show the MegaGrid", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = TestFrame(self) + win.Show(True) + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + + +overview = """Mega Grid Example + +This example attempts to show many examples and tricks of +using a virtual grid object. Hopefully the source isn't too jumbled. + +Features: +
    +
  1. Uses a virtual grid +
  2. Columns and rows have popup menus (right click on labels) +
  3. Columns and rows can be deleted (i.e. table can be + resized) +
  4. Dynamic renderers. Renderers are plugins based on + column header name. Shows a simple Font Renderer and + an Image Renderer. +
+ +Look for 'XXX' in the code to indicate some workarounds for non-obvious +behavior and various hacks. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/HTML2_WebView.py b/demo/HTML2_WebView.py new file mode 100644 index 00000000..e57376a8 --- /dev/null +++ b/demo/HTML2_WebView.py @@ -0,0 +1,154 @@ + +import wx +import wx.html2 as webview + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log, frame=None): + self.log = log + wx.Panel.__init__(self, parent, -1) + + self.current = "http://wxPython.org" + self.frame = frame + if frame: + self.titleBase = frame.GetTitle() + + sizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + self.wv = webview.WebView.New(self) + self.Bind(webview.EVT_WEB_VIEW_NAVIGATING, self.OnWebViewNavigating, self.wv) + self.Bind(webview.EVT_WEB_VIEW_LOADED, self.OnWebViewLoaded, self.wv) + + + btn = wx.Button(self, -1, "Open", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnOpenButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, -1, "<--", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnPrevPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoBack, btn) + + btn = wx.Button(self, -1, "-->", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnNextPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + self.Bind(wx.EVT_UPDATE_UI, self.OnCheckCanGoForward, btn) + + btn = wx.Button(self, -1, "Stop", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnStopButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + btn = wx.Button(self, -1, "Refresh", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnRefreshPageButton, btn) + btnSizer.Add(btn, 0, wx.EXPAND|wx.ALL, 2) + + txt = wx.StaticText(self, -1, "Location:") + btnSizer.Add(txt, 0, wx.CENTER|wx.ALL, 2) + + self.location = wx.ComboBox( + self, -1, "", style=wx.CB_DROPDOWN|wx.TE_PROCESS_ENTER) + self.location.AppendItems(['http://wxPython.org', + 'http://wxwidgets.org', + 'http://google.com']) + self.Bind(wx.EVT_COMBOBOX, self.OnLocationSelect, self.location) + self.location.Bind(wx.EVT_TEXT_ENTER, self.OnLocationEnter) + btnSizer.Add(self.location, 1, wx.EXPAND|wx.ALL, 2) + + + sizer.Add(btnSizer, 0, wx.EXPAND) + sizer.Add(self.wv, 1, wx.EXPAND) + self.SetSizer(sizer) + + self.wv.LoadURL(self.current) + + + def ShutdownDemo(self): + # put the frame title back + if self.frame: + self.frame.SetTitle(self.titleBase) + + + # WebView events + def OnWebViewNavigating(self, evt): + # this event happens prior to trying to get a resource + if evt.GetURL() == 'http://www.microsoft.com/': + if wx.MessageBox("Are you sure you want to visit Microsoft?", + style=wx.YES_NO|wx.ICON_QUESTION) == wx.NO: + # This is how you can cancel loading a page. + evt.Veto() + + def OnWebViewLoaded(self, evt): + # The full document has loaded + self.current = evt.GetURL() + self.location.SetValue(self.current) + + + # Control bar events + def OnLocationSelect(self, evt): + url = self.location.GetStringSelection() + self.log.write('OnLocationSelect: %s\n' % url) + self.wv.LoadURL(url) + + def OnLocationEnter(self, evt): + url = self.location.GetValue() + self.location.Append(url) + self.wv.LoadURL(url) + + + def OnOpenButton(self, event): + dlg = wx.TextEntryDialog(self, "Open Location", + "Enter a full URL or local path", + self.current, wx.OK|wx.CANCEL) + dlg.CentreOnParent() + + if dlg.ShowModal() == wx.ID_OK: + self.current = dlg.GetValue() + self.wv.LoadURL(self.current) + + dlg.Destroy() + + def OnPrevPageButton(self, event): + self.wv.GoBack() + + def OnNextPageButton(self, event): + self.wv.GoForward() + + def OnCheckCanGoBack(self, event): + event.Enable(self.wv.CanGoBack()) + + def OnCheckCanGoForward(self, event): + event.Enable(self.wv.CanGoForward()) + + def OnStopButton(self, evt): + self.wv.Stop() + + def OnRefreshPageButton(self, evt): + self.wv.Reload() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

DemoName

+ +Say something nice here + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/HtmlWindow.py b/demo/HtmlWindow.py new file mode 100644 index 00000000..ec583b6b --- /dev/null +++ b/demo/HtmlWindow.py @@ -0,0 +1,224 @@ + +import os +import sys + +import wx +import wx.html as html +import wx.lib.wxpTag + +from Main import opj + +#---------------------------------------------------------------------- + +# This shows how to catch the OnLinkClicked non-event. (It's a virtual +# method in the C++ code...) +class MyHtmlWindow(html.HtmlWindow): + def __init__(self, parent, id, log): + html.HtmlWindow.__init__(self, parent, id, style=wx.NO_FULL_REPAINT_ON_RESIZE) + self.log = log + if "gtk2" in wx.PlatformInfo: + self.SetStandardFonts() + + def OnLinkClicked(self, linkinfo): + self.log.WriteText('OnLinkClicked: %s\n' % linkinfo.GetHref()) + super(MyHtmlWindow, self).OnLinkClicked(linkinfo) + + def OnSetTitle(self, title): + self.log.WriteText('OnSetTitle: %s\n' % title) + super(MyHtmlWindow, self).OnSetTitle(title) + + def OnCellMouseHover(self, cell, x, y): + self.log.WriteText('OnCellMouseHover: %s, (%d %d)\n' % (cell, x, y)) + super(MyHtmlWindow, self).OnCellMouseHover(cell, x, y) + + def OnCellClicked(self, cell, x, y, evt): + self.log.WriteText('OnCellClicked: %s, (%d %d)\n' % (cell, x, y)) + if isinstance(cell, html.HtmlWordCell): + sel = html.HtmlSelection() + self.log.WriteText(' %s\n' % cell.ConvertToText(sel)) + super(MyHtmlWindow, self).OnCellClicked(cell, x, y, evt) + + + +# This filter doesn't really do anything but show how to use filters +class MyHtmlFilter(html.HtmlFilter): + def __init__(self, log): + html.HtmlFilter.__init__(self) + self.log = log + + # This method decides if this filter is able to read the file + def CanRead(self, fsfile): + self.log.write("CanRead: %s\n" % fsfile.GetMimeType()) + return False + + # If CanRead returns True then this method is called to actually + # read the file and return the contents. + def ReadFile(self, fsfile): + return "" + + +class TestHtmlPanel(wx.Panel): + def __init__(self, parent, frame, log): + wx.Panel.__init__(self, parent, -1, style=wx.NO_FULL_REPAINT_ON_RESIZE) + self.log = log + self.frame = frame + self.cwd = os.path.split(sys.argv[0])[0] + + if not self.cwd: + self.cwd = os.getcwd() + if frame: + self.titleBase = frame.GetTitle() + + html.HtmlWindow_AddFilter(MyHtmlFilter(log)) + + self.html = MyHtmlWindow(self, -1, log) + self.html.SetRelatedFrame(frame, self.titleBase + " -- %s") + self.html.SetRelatedStatusBar(0) + + self.printer = html.HtmlEasyPrinting() + + self.box = wx.BoxSizer(wx.VERTICAL) + self.box.Add(self.html, 1, wx.GROW) + + subbox = wx.BoxSizer(wx.HORIZONTAL) + + btn = wx.Button(self, -1, "Load File") + self.Bind(wx.EVT_BUTTON, self.OnLoadFile, btn) + subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) + + btn = wx.Button(self, -1, "Load URL") + self.Bind(wx.EVT_BUTTON, self.OnLoadURL, btn) + subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) + + btn = wx.Button(self, -1, "With Widgets") + self.Bind(wx.EVT_BUTTON, self.OnWithWidgets, btn) + subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) + + btn = wx.Button(self, -1, "Back") + self.Bind(wx.EVT_BUTTON, self.OnBack, btn) + subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) + + btn = wx.Button(self, -1, "Forward") + self.Bind(wx.EVT_BUTTON, self.OnForward, btn) + subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) + + btn = wx.Button(self, -1, "Print") + self.Bind(wx.EVT_BUTTON, self.OnPrint, btn) + subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) + + btn = wx.Button(self, -1, "View Source") + self.Bind(wx.EVT_BUTTON, self.OnViewSource, btn) + subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) + + self.box.Add(subbox, 0, wx.GROW) + self.SetSizer(self.box) + self.SetAutoLayout(True) + + # A button with this ID is created on the widget test page. + self.Bind(wx.EVT_BUTTON, self.OnOk, id=wx.ID_OK) + + self.OnShowDefault(None) + + + def ShutdownDemo(self): + # put the frame title back + if self.frame: + self.frame.SetTitle(self.titleBase) + + + def OnShowDefault(self, event): + name = os.path.join(self.cwd, opj('data/test.htm')) + self.html.LoadPage(name) + + + def OnLoadFile(self, event): + dlg = wx.FileDialog(self, style=wx.OPEN, + wildcard='HTML Files|*.htm;*.html', ) + + if dlg.ShowModal(): + path = dlg.GetPath() + self.html.LoadPage(path) + + dlg.Destroy() + + + def OnLoadURL(self, event): + dlg = wx.TextEntryDialog(self, "Enter a URL") + + if dlg.ShowModal(): + url = dlg.GetValue() + self.html.LoadPage(url) + + dlg.Destroy() + + + def OnWithWidgets(self, event): + os.chdir(self.cwd) + name = os.path.join(self.cwd, opj('data/widgetTest.htm')) + self.html.LoadPage(name) + + + def OnOk(self, event): + self.log.WriteText("It works!\n") + + def OnBack(self, event): + if not self.html.HistoryBack(): + wx.MessageBox("No more items in history!") + + + def OnForward(self, event): + if not self.html.HistoryForward(): + wx.MessageBox("No more items in history!") + + + def OnViewSource(self, event): + import wx.lib.dialogs + + source = self.html.GetParser().GetSource() + + dlg = wx.lib.dialogs.ScrolledMessageDialog(self, source, 'HTML Source') + dlg.ShowModal() + dlg.Destroy() + + + def OnPrint(self, event): + self.printer.GetPrintData().SetPaperId(wx.PAPER_LETTER) + self.printer.PrintFile(self.html.GetOpenedPage()) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestHtmlPanel(nb, frame, log) + return win + + +#---------------------------------------------------------------------- + + +overview = """ +

wx.HtmlWindow

+ +

wx.HtmlWindow is capable of parsing and rendering most +simple HTML tags. + +

It is not intended to be a high-end HTML browser. If you're +looking for something like that see the IEHtmlWin class, which +wraps the core MSIE HTML viewer. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + + + + + + diff --git a/demo/I18N.py b/demo/I18N.py new file mode 100644 index 00000000..e35f483a --- /dev/null +++ b/demo/I18N.py @@ -0,0 +1,234 @@ +#Boa:FramePanel:LanguageSelectPanel +import os, sys +import wx +from wx.lib import langlistctrl +from Main import opj + + +# Normally you would just set _ to be a reference to the +# wx.GetTranslation function, and then wrap all you literal strings in +# _() function calls. Then everytime you use one of your literals, it +# would first pass through the translation function and try to load a +# translated version of the string from the current message catalogs. +# For this example, since we are changinb language on the fly, and +# since we are only translating the label for one widget, we'll not do +# it the automatic way and we'll be more explicit. See the setup in +# __init__() and the translation done in updateLanguage() below. + +_ = wx.GetTranslation + +exampleStrings = [ + 'the quick brown fox jumps over the lazy dog', # demo string + 'Tip of the Day', # wx built in translation + 'Warning', # wx built in translation +] + + +[wxID_LANGUAGESELECTPANEL, wxID_LANGUAGESELECTPANELENGLISHBASECH, + wxID_LANGUAGESELECTPANELLANGCTRLCONTAINER, + wxID_LANGUAGESELECTPANELLANGFILTERRB, wxID_LANGUAGESELECTPANELSTATICLINE1, + wxID_LANGUAGESELECTPANELSTATICTEXT1, wxID_LANGUAGESELECTPANELSTATICTEXT2, + wxID_LANGUAGESELECTPANELSTATICTEXT3, wxID_LANGUAGESELECTPANELTRANSLATEDST, +] = [wx.NewId() for _init_ctrls in range(9)] + +class LanguageSelectPanel(wx.Panel): + def _init_coll_boxSizer3_Items(self, parent): + # generated method, don't edit + + parent.AddWindow(self.langCtrlContainer, 1, border=0, flag=wx.GROW) + parent.AddSpacer(wx.Size(8, 8), border=0, flag=0) + parent.AddWindow(self.langFilterRB, 0, border=0, flag=0) + + def _init_coll_flexGridSizer1_Growables(self, parent): + # generated method, don't edit + + parent.AddGrowableRow(1) + parent.AddGrowableCol(0) + + def _init_coll_boxSizer1_Items(self, parent): + # generated method, don't edit + + parent.AddWindow(self.staticText1, 0, border=8, flag=wx.ALL) + parent.AddSizer(self.boxSizer3, 1, border=8, flag=wx.ALL | wx.GROW) + parent.AddSizer(self.boxSizer2, 0, border=8, flag=wx.GROW | wx.ALL) + + def _init_coll_boxSizer2_Items(self, parent): + # generated method, don't edit + + parent.AddWindow(self.staticText2, 0, border=8, flag=wx.ALL) + parent.AddWindow(self.englishBaseCh, 0, border=8, flag=wx.GROW | wx.ALL) + parent.AddWindow(self.staticLine1, 0, border=8, flag=wx.GROW | wx.ALL) + parent.AddWindow(self.staticText3, 0, border=8, flag=wx.ALL) + parent.AddWindow(self.translatedST, 0, border=8, flag=wx.GROW | wx.ALL) + + def _init_sizers(self): + # generated method, don't edit + self.boxSizer1 = wx.BoxSizer(orient=wx.VERTICAL) + + self.flexGridSizer1 = wx.FlexGridSizer(cols=2, hgap=8, rows=0, vgap=8) + + self.boxSizer3 = wx.BoxSizer(orient=wx.HORIZONTAL) + + self.boxSizer2 = wx.BoxSizer(orient=wx.VERTICAL) + + self._init_coll_boxSizer1_Items(self.boxSizer1) + self._init_coll_flexGridSizer1_Growables(self.flexGridSizer1) + self._init_coll_boxSizer3_Items(self.boxSizer3) + self._init_coll_boxSizer2_Items(self.boxSizer2) + + self.SetSizer(self.boxSizer1) + + def _init_ctrls(self, prnt): + # generated method, don't edit + wx.Panel.__init__(self, id=wxID_LANGUAGESELECTPANEL, + name='LanguageSelectPanel', parent=prnt, + style=wx.RESIZE_BORDER | wx.DEFAULT_DIALOG_STYLE) + + self.staticText1 = wx.StaticText(id=wxID_LANGUAGESELECTPANELSTATICTEXT1, + label='Choose a language that will be used for example translation.', + name='staticText1', parent=self, style=0) + + self.langCtrlContainer = wx.Panel(id=wxID_LANGUAGESELECTPANELLANGCTRLCONTAINER, + name='langCtrlContainer', parent=self, style=wx.TAB_TRAVERSAL) + self.langCtrlContainer.SetBackgroundColour(wx.Colour(255, 255, 255)) + self.langCtrlContainer.Bind(wx.EVT_SIZE, self.OnLangCtrlContainerSize) + + self.langFilterRB = wx.RadioBox(choices=['Translated example languages', + 'Available languages on your system', 'All languages'], + id=wxID_LANGUAGESELECTPANELLANGFILTERRB, label='Filter', + majorDimension=1, name='langFilterRB', parent=self, + style=wx.RA_SPECIFY_COLS) + self.langFilterRB.Bind(wx.EVT_RADIOBOX, self.OnLangFilterRBRadiobox, + id=wxID_LANGUAGESELECTPANELLANGFILTERRB) + + self.staticText2 = wx.StaticText(id=wxID_LANGUAGESELECTPANELSTATICTEXT2, + label='English Text:', name='staticText2', parent=self, + style=0) + + self.staticText3 = wx.StaticText(id=wxID_LANGUAGESELECTPANELSTATICTEXT3, + label='Translated Text:', name='staticText3', parent=self, + style=0) + + self.englishBaseCh = wx.Choice(choices=self.choices, + id=wxID_LANGUAGESELECTPANELENGLISHBASECH, name='englishBaseCh', + parent=self, style=0) + self.englishBaseCh.Bind(wx.EVT_CHOICE, self.OnLangSelectAndTranslate, + id=wxID_LANGUAGESELECTPANELENGLISHBASECH) + + self.staticLine1 = wx.StaticLine(id=wxID_LANGUAGESELECTPANELSTATICLINE1, + name='staticLine1', parent=self, style=0) + + self.translatedST = wx.StaticText(id=wxID_LANGUAGESELECTPANELTRANSLATEDST, + label='', name='translatedST', parent=self, style=0) + + self._init_sizers() + + def __init__(self, parent, log): + self.choices = [] + self.choices = exampleStrings + + self._init_ctrls(parent) + + self.log = log + + lang = wx.LANGUAGE_DEFAULT + filter = 'demo' + langs = (wx.LANGUAGE_AFRIKAANS, wx.LANGUAGE_ENGLISH, wx.LANGUAGE_DEFAULT, + wx.LANGUAGE_SPANISH, wx.LANGUAGE_GERMAN, wx.LANGUAGE_ITALIAN, + wx.LANGUAGE_FRENCH) + + + # usually you would define wx.Locale in your wx.App.OnInit class. + # for the demo we just define it in this module + self.locale = None + wx.Locale.AddCatalogLookupPathPrefix(opj('data/locale')) + self.updateLanguage(wx.LANGUAGE_DEFAULT) + + + self.filterMap = {'demo': langlistctrl.LC_ONLY, + 'available': langlistctrl.LC_AVAILABLE, + 'all': langlistctrl.LC_ALL} + + self.filterIdxMap = {0: 'demo', + 1: 'available', + 2: 'all'} + self.langs = langs + self.langCtrl = langlistctrl.LanguageListCtrl(self.langCtrlContainer, -1, + filter=self.filterMap[filter], only=langs, select=lang) + + self.langCtrl.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnLangSelectAndTranslate) + self.langCtrl.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnClearTranslatedText) + + self.OnLangCtrlContainerSize() + + self.englishBaseCh.Select(0) + self.OnLangSelectAndTranslate() + + + def updateLanguage(self, lang): + # Make *sure* any existing locale is deleted before the new + # one is created. The old C++ object needs to be deleted + # before the new one is created, and if we just assign a new + # instance to the old Python variable, the old C++ locale will + # not be destroyed soon enough, likely causing a crash. + if self.locale: + assert sys.getrefcount(self.locale) <= 2 + del self.locale + + # create a locale object for this language + self.locale = wx.Locale(lang) + if self.locale.IsOk(): + self.locale.AddCatalog('wxpydemo') + else: + self.locale = None + + def translateExample(self): + self.translatedST.SetLabel(_(self.englishBaseCh.GetStringSelection())) + + def OnLangCtrlContainerSize(self, event=None): + if event: event.Skip() + self.langCtrl.SetSize(self.langCtrlContainer.GetSize()) + + def OnLangFilterRBRadiobox(self, event): + self.langCtrl.SetUpFilter( + self.filterMap[self.filterIdxMap[self.langFilterRB.GetSelection()]], + self.langs) + + def OnLangSelectAndTranslate(self, event=None): + lang = self.langCtrl.GetLanguage() + + if lang is not None: + # set to the selected language + self.updateLanguage(lang) + + self.translateExample() + + # set back to default + self.updateLanguage(wx.LANGUAGE_DEFAULT) + + def OnClearTranslatedText(self, event): + self.translatedST.SetLabel('') + + +def runTest(frame, nb, log): + win = LanguageSelectPanel(nb, log) + return win + +#------------------------------------------------------------------------------- + +overview = """ +

Internationalization (I18N)

+

+This demo demonstrates how to setup and use the wx.Locale object to translate text. +

+It also shows the langlistctrl.LanguageListCtrl that can be used to display +languages with their associated countries flags, e.g. for setting the language +in your application. + + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])]) diff --git a/demo/Image.py b/demo/Image.py new file mode 100644 index 00000000..7b1cdb7c --- /dev/null +++ b/demo/Image.py @@ -0,0 +1,90 @@ + +import wx + +from Main import opj + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + bmp = wx.Image(opj('bitmaps/image.bmp'), wx.BITMAP_TYPE_BMP).ConvertToBitmap() + gif = wx.Image(opj('bitmaps/image.gif'), wx.BITMAP_TYPE_GIF).ConvertToBitmap() + png = wx.Image(opj('bitmaps/image.png'), wx.BITMAP_TYPE_PNG).ConvertToBitmap() + jpg = wx.Image(opj('bitmaps/image.jpg'), wx.BITMAP_TYPE_JPEG).ConvertToBitmap() + + panel = wx.Panel(nb, -1) + + pos = 10 + wx.StaticBitmap(panel, -1, bmp, (10, pos)) + + pos = pos + bmp.GetHeight() + 10 + wx.StaticBitmap(panel, -1, gif, (10, pos)) + + pos = pos + gif.GetHeight() + 10 + wx.StaticBitmap(panel, -1, png, (10, pos)) + + pos = pos + png.GetHeight() + 10 + wx.StaticBitmap(panel, -1, jpg, (10, pos)) + + + greyscale = wx.Image(opj('bitmaps/image.png'), wx.BITMAP_TYPE_PNG).ConvertToGreyscale().ConvertToBitmap() + disabled = wx.Image(opj('bitmaps/image.png'), wx.BITMAP_TYPE_PNG).ConvertToDisabled().ConvertToBitmap() + mono = wx.Image(opj('bitmaps/image.png'), wx.BITMAP_TYPE_PNG).ConvertToMono(0,255,255).ConvertToBitmap() + + pos = 10 + wx.StaticBitmap(panel, -1, greyscale, (320, pos)) + + pos = pos + greyscale.GetHeight() + 10 + wx.StaticBitmap(panel, -1, disabled, (320, pos)) + + pos = pos + disabled.GetHeight() + 10 + wx.StaticBitmap(panel, -1, mono, (320, pos)) + + + return panel + +#---------------------------------------------------------------------- + + + +overview = """\ + + +This class encapsulates a platform-independent image. An image can be created +from data, or using wxBitmap.ConvertToImage. An image can be loaded from +a file in a variety of formats, and is extensible to new formats via image +format handlers. Functions are available to set and get image bits, so it can +be used for basic image manipulation. + +

The following image handlers are available. + +

+ + + + + + + + + + + + + +
wxBMPHandler For loading and saving, always installed.
wxPNGHandler For loading and saving.
wxJPEGHandler For loading and saving.
wxGIFHandler Only for loading, due to legal issues.
wxPCXHandler For loading and saving.
wxPNMHandler For loading and saving.
wxTIFFHandler For loading and saving.
wxIFFHandler For loading only.
wxXPMHandler For loading and saving.
wxICOHandler For loading and saving.
wxCURHandler For loading and saving.
wxANIHandler For loading only.
+ +

When saving in PCX format, wxPCXHandler will count the number of different +colours in the image; if there are 256 or less colours, it will save as 8 bit, +else it will save as 24 bit. + +

Loading PNMs only works for ASCII or raw RGB images. When saving in PNM format, +wxPNMHandler will always save as raw RGB. + + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ImageAlpha.py b/demo/ImageAlpha.py new file mode 100644 index 00000000..9613a8ce --- /dev/null +++ b/demo/ImageAlpha.py @@ -0,0 +1,86 @@ + +import wx # This module uses the new wx namespace +from Main import opj + + +#---------------------------------------------------------------------- + +msg = "Some text will appear mixed in the image's shadow..." + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + dc.SetBackground(wx.Brush("WHITE")) + dc.Clear() + + dc.SetFont(wx.Font(16, wx.SWISS, wx.NORMAL, wx.BOLD, True)) + dc.DrawText("Bitmap alpha blending (on all ports but gtk+ 1.2)", + 25,25) + + bmp = wx.Bitmap(opj('bitmaps/toucan.png')) + if "gtk1" in wx.PlatformInfo: + # Try to make up for lack of alpha support in wxGTK (gtk+ + # 1.2) by converting the alpha blending into a + # transparency mask. + + # first convert to a wx.Image + img = bmp.ConvertToImage() + + # Then convert the alpha channel to a mask, specifying the + # threshold below which alpha will be made fully + # transparent + img.ConvertAlphaToMask(220) + + # convert back to a wx.Bitmap + bmp = img.ConvertToBitmap() + + + dc.DrawBitmap(bmp, 25,100, True) + + dc.SetFont(self.GetFont()) + y = 75 + for line in range(10): + y += dc.GetCharHeight() + 5 + dc.DrawText(msg, 200, y) + dc.DrawBitmap(bmp, 250,100, True) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Images with Alpha

+ +wxMSW and wxMac now support alpha channels of supported image +types, and will properly blend that channel when drawing a +bitmap. It is not supported yet on wxGTK, (if you would like to +change that please submit a patch!) + +

On wxGTK this demo turns the alpha channel into a 1-bit mask, so +yes, it looks like crap. Please help us fix it! + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ImageBrowser.py b/demo/ImageBrowser.py new file mode 100644 index 00000000..31509a9d --- /dev/null +++ b/demo/ImageBrowser.py @@ -0,0 +1,68 @@ +#---------------------------------------------------------------------------- +# Name: ImageBrowser.py +# Purpose: Image Selection dialog for wxPython demo +# +# Author: Lorne White (email: lorne.white@telusplanet.net) +# +# Version 0.5 +# Date: Feb 26, 2001 +# Licence: wxWindows license +#---------------------------------------------------------------------------- + +import os + +import wx +import wx.lib.imagebrowser as ib + + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show an ImageDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + # get current working directory + dir = os.getcwd() + + # set the initial directory for the demo bitmaps + initial_dir = os.path.join(dir, 'bitmaps') + + # open the image browser dialog + dlg = ib.ImageDialog(self, initial_dir) + + dlg.Centre() + + if dlg.ShowModal() == wx.ID_OK: + # show the selected file + self.log.WriteText("You Selected File: " + dlg.GetFile()) + else: + self.log.WriteText("You pressed Cancel\n") + + dlg.Destroy() + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = """\ +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ImageFromStream.py b/demo/ImageFromStream.py new file mode 100644 index 00000000..15e1e399 --- /dev/null +++ b/demo/ImageFromStream.py @@ -0,0 +1,46 @@ + +import cStringIO + +import wx + +from Main import opj + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + + data = open(opj('bitmaps/image.png'), "rb").read() + stream = cStringIO.StringIO(data) + + bmp = wx.BitmapFromImage( wx.ImageFromStream( stream )) + + wx.StaticText( + self, -1, "This image was loaded from a Python file-like object:", + (15, 15) + ) + + wx.StaticBitmap(self, -1, bmp, (15, 45))#, (bmp.GetWidth(), bmp.GetHeight())) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ +At long last there is finally a way to load any supported image type +directly from any Python file-like object, such as a memory buffer +using StringIO. """ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/Img2PyArtProvider.py b/demo/Img2PyArtProvider.py new file mode 100644 index 00000000..206979f0 --- /dev/null +++ b/demo/Img2PyArtProvider.py @@ -0,0 +1,98 @@ + +import wx +from wx.lib.art import flagart, img2pyartprov + +FlagArtProvider = None + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(sizer) + + title = wx.StaticText(self, -1, "Img2PyArtProvider") + title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)) + sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + + line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL) + sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + sizer.Add((20,20)) + + box = wx.BoxSizer(wx.HORIZONTAL) + ch = wx.ComboBox(self, -1, 'BLANK', choices=flagart.index, + style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.Bind(wx.EVT_COMBOBOX, self.OnSelectCountry, ch) + box.Add(ch, 0, wx.ALIGN_CENTER_VERTICAL) + box.Add((50,10)) + + bmp = wx.EmptyBitmap(32,22) + self.bmpFlag = wx.StaticBitmap(self, -1, bmp) + box.Add(self.bmpFlag, 0, wx.ALIGN_CENTER_VERTICAL) + + sizer.Add(box, 0, wx.CENTER|wx.ALL, 10) + + self.country = 'BLANK' + global FlagArtProvider + if FlagArtProvider is None: + FlagArtProvider = img2pyartprov.Img2PyArtProvider(flagart, + artIdPrefix='wx.ART_') + wx.ArtProvider.Push(FlagArtProvider) + + self.getArt() + + + def OnSelectCountry(self, evt): + self.log.write("OnSelectCountry\n") + self.country = evt.GetString() + self.getArt() + + + def getArt(self): + bmp = wx.ArtProvider.GetBitmap('wx.ART_'+self.country, wx.ART_OTHER, (32,22)) + if not bmp.Ok(): + bmp = wx.EmptyBitmap(32,22) + self.clearBmp(bmp) + self.bmpFlag.SetBitmap(bmp) + + + def clearBmp(self, bmp): + dc = wx.MemoryDC() + dc.SelectObject(bmp) + dc.SetBackground(wx.Brush("white")) + dc.Clear() + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Img2PyArtProvider

+ +Img2PyArtProvider is an ArtProvider class that publishes images from +modules generated by img2py. + +

+This sample shows how to access the flag images in wx.lib.art.flagart +via the ArtProvider. + + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/InfoBar.py b/demo/InfoBar.py new file mode 100644 index 00000000..533b75e0 --- /dev/null +++ b/demo/InfoBar.py @@ -0,0 +1,125 @@ +import wx + +#---------------------------------------------------------------------- + +flags = [ (wx.ICON_NONE, "ICON_NONE"), + (wx.ICON_INFORMATION, "ICON_INFORMATION"), + (wx.ICON_QUESTION, "ICON_QUESTION"), + (wx.ICON_WARNING, "ICON_WARNING"), + (wx.ICON_ERROR, "ICON_ERROR") + ] + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + # Create the InfoBar. It starts out in a hidden state so it + # won't be visible until we need it. + self.info = wx.InfoBar(self) + panel = wx.Panel(self) + + self.message = wx.TextCtrl(panel, -1, "Hello World", size=(250,-1)) + self.flags = wx.Choice(panel, choices=[f[1] for f in flags]) + self.flags.SetSelection(1) # wx.ICON_INFORMATION is the default + + smBtn = wx.Button(panel, -1, "Show Message") + dmBtn = wx.Button(panel, -1, "Dismiss") + addBtn = wx.Button(panel, -1, "Add Button") + + fgs = wx.FlexGridSizer(cols=3, vgap=10, hgap=10) + fgs.Add(wx.StaticText(panel, -1, "Message:"), 0, + wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT) + fgs.Add(self.message) + fgs.Add(self.flags) + fgs.AddSpacer(5) + + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add(smBtn, 0, wx.RIGHT, 5) + hbox.Add(dmBtn) + fgs.Add(hbox) + fgs.AddSpacer(5) + fgs.AddSpacer(5) + fgs.Add(addBtn) + + panel.Sizer = wx.BoxSizer(wx.VERTICAL) + text = """\ +An info bar is a transient window shown at top or bottom of its parent window +to display non-critical information to the user.""" + panel.Sizer.Add(wx.StaticText(panel, -1, text), 0, wx.TOP|wx.LEFT, 25) + panel.Sizer.Add(fgs, 1, wx.EXPAND|wx.ALL, 25) + + self.Sizer = wx.BoxSizer(wx.VERTICAL) + self.Sizer.Add(self.info, 0, wx.EXPAND) + self.Sizer.Add(panel, 1, wx.EXPAND) + + self.Bind(wx.EVT_BUTTON, self.OnShowMessage, smBtn) + self.Bind(wx.EVT_BUTTON, self.OnDismiss, dmBtn) + self.Bind(wx.EVT_BUTTON, self.OnAddButton, addBtn) + + + def OnShowMessage(self, evt): + msg = self.message.GetValue() + flag = flags[self.flags.GetSelection()][0] + self.info.ShowMessage(msg, flag) + + + def OnDismiss(self, evt): + self.info.Dismiss() + + + def OnAddButton(self, evt): + btnId = wx.NewId() + self.info.AddButton(btnId, "new button") + self.info.Bind(wx.EVT_BUTTON, self.OnButtonClicked, id=btnId) + + + def OnButtonClicked(self, evt): + wx.MessageBox("New button clicked") + # Calling evt.Skip() will allow the default handler to run + # which will dismiss the info bar. If you don't want it to be + # dismissed for a particular button then then don't call + # Skip(). + evt.Skip() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.InfoBar

+ +An info bar is a transient window shown at top or bottom of its parent +window to display non-critical information to the user. + +

This class provides another way to show messages to the user, +intermediate between message boxes and status bar messages. The +message boxes are modal and thus interrupt the users work flow and +should be used sparingly for this reason. However status bar messages +are often too easy not to notice at all. An info bar provides a way to +present the messages which has a much higher chance to be noticed by +the user but without being annoying. + +

Info bar may show an icon (on the left), text message and, optionally, +buttons allowing the user to react to the information presented. It +always has a close button at the right allowing the user to dismiss it +so it isn't necessary to provide a button just to close it. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/IntCtrl.py b/demo/IntCtrl.py new file mode 100644 index 00000000..ba3d2b04 --- /dev/null +++ b/demo/IntCtrl.py @@ -0,0 +1,342 @@ + +import wx +import wx.lib.intctrl + +#---------------------------------------------------------------------- + +class TestPanel( wx.Panel ): + def __init__( self, parent, log ): + + wx.Panel.__init__( self, parent, -1 ) + self.log = log + panel = wx.Panel( self, -1 ) + + self.set_min = wx.CheckBox( panel, -1, "Set minimum value:" ) + self.min = wx.lib.intctrl.IntCtrl( panel, size=( 50, -1 ) ) + self.min.Enable( False ) + + self.set_max = wx.CheckBox( panel, -1, "Set maximum value:" ) + self.max = wx.lib.intctrl.IntCtrl( panel, size=( 50, -1 ) ) + self.max.Enable( False ) + + self.limit_target = wx.CheckBox( panel, -1, "Limit control" ) + self.allow_none = wx.CheckBox( panel, -1, "Allow empty control" ) + self.allow_long = wx.CheckBox( panel, -1, "Allow long integers" ) + + label = wx.StaticText( panel, -1, "Resulting integer control:" ) + self.target_ctl = wx.lib.intctrl.IntCtrl( panel ) + + grid = wx.FlexGridSizer( cols=2 ) + grid.Add( self.set_min, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + grid.Add( self.min, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + grid.Add(self.set_max, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + grid.Add( self.max, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + grid.Add( self.limit_target, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid.Add( self.allow_none, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid.Add( self.allow_long, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + grid.Add( label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + grid.Add( self.target_ctl, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + outer_box = wx.BoxSizer( wx.VERTICAL ) + outer_box.Add( grid, 0, wx.ALIGN_CENTRE|wx.ALL, 20 ) + + panel.SetAutoLayout( True ) + panel.SetSizer( outer_box ) + outer_box.Fit( panel ) + panel.Move( (50,50) ) + self.panel = panel + + self.Bind(wx.EVT_CHECKBOX, self.OnSetMin, self.set_min) + self.Bind(wx.EVT_CHECKBOX, self.OnSetMax, self.set_max) + self.Bind(wx.EVT_CHECKBOX, self.SetTargetMinMax, self.limit_target) + self.Bind(wx.EVT_CHECKBOX, self.OnSetAllowNone, self.allow_none) + self.Bind(wx.EVT_CHECKBOX, self.OnSetAllowLong, self.allow_long) + + self.Bind(wx.lib.intctrl.EVT_INT, self.SetTargetMinMax, self.min) + self.Bind(wx.lib.intctrl.EVT_INT, self.SetTargetMinMax, self.max) + self.Bind(wx.lib.intctrl.EVT_INT, self.OnTargetChange, self.target_ctl) + + + def OnSetMin( self, event ): + self.min.Enable( self.set_min.GetValue() ) + self.SetTargetMinMax() + + def OnSetMax( self, event ): + self.max.Enable( self.set_max.GetValue() ) + self.SetTargetMinMax() + + + def SetTargetMinMax( self, event=None ): + min = max = None + self.target_ctl.SetLimited( self.limit_target.GetValue() ) + + if self.set_min.GetValue(): + min = self.min.GetValue() + + if self.set_max.GetValue(): + max = self.max.GetValue() + + cur_min, cur_max = self.target_ctl.GetBounds() + + if min != cur_min and not self.target_ctl.SetMin( min ): + self.log.write( "min (%d) > current max (%d) -- bound not set\n" % ( min, self.target_ctl.GetMax() ) ) + self.min.SetForegroundColour( wx.RED ) + else: + self.min.SetForegroundColour( wx.BLACK ) + + self.min.Refresh() + + if max != cur_max and not self.target_ctl.SetMax( max ): + self.log.write( "max (%d) < current min (%d) -- bound not set\n" % ( max, self.target_ctl.GetMin() ) ) + self.max.SetForegroundColour( wx.RED ) + else: + self.max.SetForegroundColour( wx.BLACK ) + + self.max.Refresh() + + if min != cur_min or max != cur_max: + new_min, new_max = self.target_ctl.GetBounds() + self.log.write( "current min, max: (%s, %s)\n" % ( str(new_min), str(new_max) ) ) + + + def OnSetAllowNone( self, event ): + self.target_ctl.SetNoneAllowed( self.allow_none.GetValue() ) + + + def OnSetAllowLong( self, event ): + self.target_ctl.SetLongAllowed( self.allow_long.GetValue() ) + + + def OnTargetChange( self, event ): + ctl = event.GetEventObject() + value = ctl.GetValue() + ib_str = [ " (out of bounds)", "" ] + self.log.write( "integer value = %s%s\n" % ( str(value), ib_str[ ctl.IsInBounds(value) ] ) ) + + +#---------------------------------------------------------------------- + +def runTest( frame, nb, log ): + win = TestPanel( nb, log ) + return win + +#---------------------------------------------------------------------- + +overview = """ +

+IntCtrl provides a control that takes and returns integers as +value, and provides bounds support and optional value limiting. +

+

+Here's the API for IntCtrl: +

+    IntCtrl(
+         parent, id = -1,
+         value = 0,
+         min = None,
+         max = None,
+         limited = False,
+         allow_none = False,
+         allow_long = False,
+         default_color = wxBLACK,
+         oob_color = wxRED,
+         pos = wxDefaultPosition,
+         size = wxDefaultSize,
+         style = 0,
+         name = "integer")
+
+
    +
    value +
    If no initial value is set, the default will be zero, or + the minimum value, if specified. If an illegal string is specified, + a ValueError will result. (You can always later set the initial + value with SetValue() after instantiation of the control.) +
    +
    min +
    The minimum value that the control should allow. This can be + adjusted with SetMin(). If the control is not limited, any value + below this bound will be colored with the current out-of-bounds color. +
    +
    max +
    The maximum value that the control should allow. This can be + adjusted with SetMax(). If the control is not limited, any value + above this bound will be colored with the current out-of-bounds color. +
    +
    limited +
    Boolean indicating whether the control prevents values from + exceeding the currently set minimum and maximum values (bounds). + If False and bounds are set, out-of-bounds values will + be colored with the current out-of-bounds color. +
    +
    allow_none +
    Boolean indicating whether or not the control is allowed to be + empty, representing a value of None for the control. +
    +
    allow_long +
    Boolean indicating whether or not the control is allowed to hold + and return a value of type long as well as int. If False, the + control will be implicitly limited to have a value such that + -sys.maxint-1 <= n <= sys.maxint. +
    +
    default_color +
    Color value used for in-bounds values of the control. +
    +
    oob_color +
    Color value used for out-of-bounds values of the control + when the bounds are set but the control is not limited. +
+
+
+
EVT_INT(win, id, func) +
Respond to a wxEVT_COMMAND_INT_UPDATED event, generated when the +value changes. Notice that this event will always be sent when the +control's contents changes - whether this is due to user input or +comes from the program itself (for example, if SetValue() is called.) +
+
+
SetValue(int) +
Sets the value of the control to the integer value specified. +The resulting actual value of the control may be altered to +conform with the bounds set on the control if limited, +or colored if not limited but the value is out-of-bounds. +A ValueError exception will be raised if an invalid value +is specified. +
+
GetValue() +
Retrieves the integer value from the control. The value +retrieved will be sized as an int if possible or a long, +if necessary. +
+
+
SetMin(min=None) +
Sets the expected minimum value, or lower bound, of the control. +(The lower bound will only be enforced if the control is +configured to limit its values to the set bounds.) +If a value of None is provided, then the control will have +no explicit lower bound. If the value specified is greater than +the current lower bound, then the function returns 0 and the +lower bound will not change from its current setting. On success, +the function returns 1. +
If successful and the current value is +lower than the new lower bound, if the control is limited, the +value will be automatically adjusted to the new minimum value; +if not limited, the value in the control will be colored with +the current out-of-bounds color. +
+
GetMin() +
Gets the current lower bound value for the control. +It will return None if no lower bound is currently specified. +
+
+
SetMax(max=None) +
Sets the expected maximum value, or upper bound, of the control. +(The upper bound will only be enforced if the control is +configured to limit its values to the set bounds.) +If a value of None is provided, then the control will +have no explicit upper bound. If the value specified is less +than the current lower bound, then the function returns 0 and +the maximum will not change from its current setting. On success, +the function returns 1. +
If successful and the current value +is greater than the new upper bound, if the control is limited +the value will be automatically adjusted to the new maximum value; +if not limited, the value in the control will be colored with the +current out-of-bounds color. +
+
GetMax() +
Gets the current upper bound value for the control. +It will return None if no upper bound is currently specified. +
+
+
SetBounds(min=None,max=None) +
This function is a convenience function for setting the min and max +values at the same time. The function only applies the maximum bound +if setting the minimum bound is successful, and returns True +only if both operations succeed. Note: leaving out an argument +will remove the corresponding bound. +
GetBounds() +
This function returns a two-tuple (min,max), indicating the +current bounds of the control. Each value can be None if +that bound is not set. +
+
+
IsInBounds(value=None) +
Returns True if no value is specified and the current value +of the control falls within the current bounds. This function can also +be called with a value to see if that value would fall within the current +bounds of the given control. +
+
+
SetLimited(bool) +
If called with a value of True, this function will cause the control +to limit the value to fall within the bounds currently specified. +If the control's value currently exceeds the bounds, it will then +be limited accordingly. +If called with a value of 0, this function will disable value +limiting, but coloring of out-of-bounds values will still take +place if bounds have been set for the control. +
IsLimited() +
Returns True if the control is currently limiting the +value to fall within the current bounds. +
+
+
SetNoneAllowed(bool) +
If called with a value of True, this function will cause the control +to allow the value to be empty, representing a value of None. +If called with a value of false, this function will prevent the value +from being None. If the value of the control is currently None, +ie. the control is empty, then the value will be changed to that +of the lower bound of the control, or 0 if no lower bound is set. +
IsNoneAllowed() +
Returns True if the control currently allows its +value to be None. +
+
+
SetLongAllowed(bool) +
If called with a value of True, this function will cause the +control to allow the value to be a long. If called with a value +of False, and the value of the control is currently a long value, +the value of the control will be adjusted to fall within the +size of an integer type, at either the sys.maxint or -sys.maxint-1, +for positive and negative values, respectively. +
IsLongAllowed() +
Returns True if the control currently allows its +value to be of type long. +
+
+
SetColors(default_color=wxBLACK, oob_color=wxRED) +
Tells the control what colors to use for normal and out-of-bounds +values. If the value currently exceeds the bounds, it will be +recolored accordingly. +
GetColors() +
Returns a tuple of (default_color, oob_color) indicating +the current color settings for the control. +
+
+
Cut() +
Will allow cuts to the clipboard of the text portion of the value, +leaving the value of zero if the entire contents are "cut." +
Paste() +
Will paste the contents of the clipboard to the selected portion +of the value; if the resulting string does not represent a legal +value, a ValueError will result. If the result is out-of bounds, +it will either be adjusted or colored as appropriate. +
+ +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/ItemsPicker.py b/demo/ItemsPicker.py new file mode 100644 index 00000000..c7a27b41 --- /dev/null +++ b/demo/ItemsPicker.py @@ -0,0 +1,92 @@ +import wx +from wx.lib.itemspicker import ItemsPicker, \ + EVT_IP_SELECTION_CHANGED, \ + IP_SORT_CHOICES, IP_SORT_SELECTED,\ + IP_REMOVE_FROM_CHOICES + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + sizer = wx.BoxSizer(wx.HORIZONTAL) + box = wx.StaticBox(self,-1,"ItemPicker styles") + boxSizer = wx.StaticBoxSizer(box,wx.VERTICAL) + self.sortChoices = wx.CheckBox(self,-1,'IP_SORT_CHOICES') + boxSizer.Add(self.sortChoices) + self.sortSelected = wx.CheckBox(self,-1,'IP_SORT_SELECTED') + boxSizer.Add(self.sortSelected) + self.removeFromChoices = wx.CheckBox(self,-1,'IP_REMOVE_FROM_CHOICES') + boxSizer.Add(self.removeFromChoices) + sizer.Add(boxSizer,0,wx.ALL,10) + b = wx.Button(self,-1,"Go") + b.Bind(wx.EVT_BUTTON,self.Go) + sizer.Add(b,0,wx.ALL,10) + self.SetSizer(sizer) + + def Go(self,e): + style = 0 + if self.sortChoices.GetValue(): + style |= IP_SORT_CHOICES + if self.sortSelected.GetValue(): + style |= IP_SORT_SELECTED + if self.removeFromChoices.GetValue(): + style |= IP_REMOVE_FROM_CHOICES + d = ItemsPickerDialog(self, style, self.log) + d.ShowModal() + + +class ItemsPickerDialog(wx.Dialog): + def __init__(self,parent, style, log): + wx.Dialog.__init__(self,parent) + self.log = log + sizer =wx.BoxSizer(wx.VERTICAL) + b = wx.Button(self, -1, "Add Item") + b.Bind(wx.EVT_BUTTON, self.OnAdd) + sizer.Add(b, 0, wx.ALL, 5) + self.ip = ItemsPicker(self,-1, + ['ThisIsItem3','ThisIsItem2','ThisIsItem1'], + 'Stuff:', 'Selected stuff:',ipStyle = style) + self.ip.Bind(EVT_IP_SELECTION_CHANGED, self.OnSelectionChange) + self.ip._source.SetMinSize((-1,150)) + sizer.Add(self.ip, 0, wx.ALL, 10) + self.SetSizer(sizer) + self.itemCount = 3 + self.Fit() + + def OnAdd(self,e): + items = self.ip.GetItems() + self.itemCount += 1 + newItem = "item%d" % self.itemCount + self.ip.SetItems(items + [newItem]) + + def OnSelectionChange(self, e): + self.log.write("EVT_IP_SELECTION_CHANGED %s\n" % \ + ",".join(e.GetItems())) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

ItemsPicker

+ +ItemsPicker is a widget that allows the user to choose a set of picked +items out of a given list + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Joystick.py b/demo/Joystick.py new file mode 100644 index 00000000..f26d7e1a --- /dev/null +++ b/demo/Joystick.py @@ -0,0 +1,1089 @@ +#---------------------------------------------------------------------------- +# Name: Joystick.py +# Purpose: Demonstrate use of wx.Joystick +# +# Author: Jeff Grimmett (grimmtoo@softhome.net), adapted from original +# .wdr-derived demo +# +# Created: 02-Jan-2004 +# RCS-ID: $Id$ +# Copyright: +# Licence: wxWindows license +#---------------------------------------------------------------------------- +# + +import math +import wx + +haveJoystick = True +if wx.Platform == "__WXMAC__": + haveJoystick = False + +#---------------------------------------------------------------------------- + +# Once all supported versions of Python support 32-bit integers on all +# platforms, this can go up to 32. +MAX_BUTTONS = 16 + +#---------------------------------------------------------------------------- + +class Label(wx.StaticText): + # A derived StaticText that always aligns right and renders + # in a bold font. + def __init__(self, parent, label): + wx.StaticText.__init__(self, parent, -1, label, style=wx.ALIGN_RIGHT) + + f = parent.GetFont() + f.SetWeight(wx.BOLD) + self.SetFont(f) + +#---------------------------------------------------------------------------- + + +class JoyGauge(wx.Panel): + def __init__(self, parent, stick): + + self.stick = stick + size = (100,100) + + wx.Panel.__init__(self, parent, -1, size=size) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_ERASE_BACKGROUND, lambda e: None) + + self.buffer = wx.EmptyBitmap(*size) + dc = wx.BufferedDC(None, self.buffer) + self.DrawFace(dc) + self.DrawJoystick(dc) + + + def OnSize(self, event): + # The face Bitmap init is done here, to make sure the buffer is always + # the same size as the Window + w, h = self.GetClientSize() + self.buffer = wx.EmptyBitmap(w,h) + dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) + self.DrawFace(dc) + self.DrawJoystick(dc) + + + def DrawFace(self, dc): + dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.Clear() + + + def OnPaint(self, evt): + # When dc is destroyed it will blit self.buffer to the window, + # since no other drawing is needed we'll just return and let it + # do it's thing + dc = wx.BufferedPaintDC(self, self.buffer) + + + def DrawJoystick(self, dc): + # draw the guage as a maxed square in the center of this window. + w, h = self.GetClientSize() + edgeSize = min(w, h) + + xorigin = (w - edgeSize) / 2 + yorigin = (h - edgeSize) / 2 + center = edgeSize / 2 + + # Restrict our drawing activities to the square defined + # above. + dc.SetClippingRegion(xorigin, yorigin, edgeSize, edgeSize) + + # Optimize drawing a bit (for Win) + dc.BeginDrawing() + + dc.SetBrush(wx.Brush(wx.Colour(251, 252, 237))) + dc.DrawRectangle(xorigin, yorigin, edgeSize, edgeSize) + + dc.SetPen(wx.Pen(wx.BLACK, 1, wx.DOT_DASH)) + + dc.DrawLine(xorigin, yorigin + center, xorigin + edgeSize, yorigin + center) + dc.DrawLine(xorigin + center, yorigin, xorigin + center, yorigin + edgeSize) + + if self.stick: + # Get the joystick position as a float + joyx = float(self.stick.GetPosition().x) + joyy = float(self.stick.GetPosition().y) + + # Get the joystick range of motion + xmin = self.stick.GetXMin() + xmax = self.stick.GetXMax() + if xmin < 0: + xmax += abs(xmin) + joyx += abs(xmin) + xmin = 0 + xrange = max(xmax - xmin, 1) + + ymin = self.stick.GetYMin() + ymax = self.stick.GetYMax() + if ymin < 0: + ymax += abs(ymin) + joyy += abs(ymin) + ymin = 0 + yrange = max(ymax - ymin, 1) + + # calc a ratio of our range versus the joystick range + xratio = float(edgeSize) / xrange + yratio = float(edgeSize) / yrange + + # calc the displayable value based on position times ratio + xval = int(joyx * xratio) + yval = int(joyy * yratio) + + # and normalize the value from our brush's origin + x = xval + xorigin + y = yval + yorigin + + # Now to draw it. + dc.SetPen(wx.Pen(wx.RED, 2)) + dc.CrossHair(x, y) + + # Turn off drawing optimization + dc.EndDrawing() + + + def Update(self): + dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) + self.DrawFace(dc) + self.DrawJoystick(dc) + + +#---------------------------------------------------------------------------- + +class JoyPanel(wx.Panel): + def __init__(self, parent, stick): + + self.stick = stick + + wx.Panel.__init__(self, parent, -1) + + sizer = wx.BoxSizer(wx.VERTICAL) + + fn = parent.GetFont() + fn.SetPointSize(fn.GetPointSize() + 3) + fn.SetWeight(wx.BOLD) + + t = wx.StaticText(self, -1, "X - Y Axes", style = wx.ALIGN_CENTRE) + t.SetFont(fn) + sizer.Add(t, 0, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTER_HORIZONTAL, 1) + + self.control = JoyGauge(self, self.stick) + sizer.Add(self.control, 1, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER | wx.ALIGN_CENTER_HORIZONTAL, 1) + + self.SetSizer(sizer) + sizer.Fit(self) + + def Update(self): + self.control.Update() + + +#---------------------------------------------------------------------------- + +class POVGauge(wx.Panel): + # + # Display the current postion of the POV control + # + def __init__(self, parent, stick): + + self.stick = stick + self.size = (100, 100) + self.avail = False + self.fourDir = False + self.cts = False + + wx.Panel.__init__(self, parent, -1, size=self.size) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_ERASE_BACKGROUND, lambda e: None) + + self.buffer = wx.EmptyBitmap(*self.size) + dc = wx.BufferedDC(None, self.buffer) + self.DrawFace(dc) + self.DrawPOV(dc) + + + def OnSize(self, event): + # calculate the size of our display and make a buffer for it. + w, h = self.GetClientSize() + s = min(w, h) + self.size = (s, s) + self.buffer = wx.EmptyBitmap(w,h) + dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) + self.DrawFace(dc) + self.DrawPOV(dc) + + + def DrawFace(self, dc): + dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.Clear() + + + def OnPaint(self, evt): + # When dc is destroyed it will blit self.buffer to the window, + # since no other drawing is needed we'll just return and let it + # do it's thing + dc = wx.BufferedPaintDC(self, self.buffer) + + + def DrawPOV(self, dc): + # draw the guage as a maxed circle in the center of this window. + w, h = self.GetClientSize() + diameter = min(w, h) + + xorigin = (w - diameter) / 2 + yorigin = (h - diameter) / 2 + xcenter = xorigin + diameter / 2 + ycenter = yorigin + diameter / 2 + + # Optimize drawing a bit (for Win) + dc.BeginDrawing() + + # our 'raster'. + dc.SetBrush(wx.Brush(wx.WHITE)) + dc.DrawCircle(xcenter, ycenter, diameter/2) + dc.SetBrush(wx.Brush(wx.BLACK)) + dc.DrawCircle(xcenter, ycenter, 10) + + # fancy decorations + dc.SetPen(wx.Pen(wx.BLACK, 1, wx.DOT_DASH)) + dc.DrawLine(xorigin, ycenter, xorigin + diameter, ycenter) + dc.DrawLine(xcenter, yorigin, xcenter, yorigin + diameter) + + if self.stick: + if self.avail: + + pos = -1 + + # use the appropriate function to get the POV position + if self.fourDir: + pos = self.stick.GetPOVPosition() + + if self.cts: + pos = self.stick.GetPOVCTSPosition() + + # trap invalid values + if 0 <= pos <= 36000: + vector = 30 + else: + vector = 0 + + # rotate CCW by 90 so that 0 is up. + pos = (pos / 100) - 90 + + # Normalize + if pos < 0: + pos = pos + 360 + + # Stolen from wx.lib.analogclock :-) + radiansPerDegree = math.pi / 180 + pointX = int(round(vector * math.cos(pos * radiansPerDegree))) + pointY = int(round(vector * math.sin(pos * radiansPerDegree))) + + # normalise value to match our actual center. + nx = pointX + xcenter + ny = pointY + ycenter + + # Draw the line + dc.SetPen(wx.Pen(wx.BLUE, 2)) + dc.DrawLine(xcenter, ycenter, nx, ny) + + # And a little thing to show the endpoint + dc.SetBrush(wx.Brush(wx.BLUE)) + dc.DrawCircle(nx, ny, 8) + + # Turn off drawing optimization + dc.EndDrawing() + + + def Update(self): + dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) + self.DrawFace(dc) + self.DrawPOV(dc) + + + def Calibrate(self): + s = self.stick + self.avail = s.HasPOV() + self.fourDir = s.HasPOV4Dir() + self.cts = s.HasPOVCTS() + + +#---------------------------------------------------------------------------- + +class POVStatus(wx.Panel): + # + # Displays static info about the POV control + # + def __init__(self, parent, stick): + + self.stick = stick + + wx.Panel.__init__(self, parent, -1, size=(100, 100)) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add((20,20)) + + self.avail = wx.CheckBox(self, -1, "Available") + sizer.Add(self.avail, 0, wx.ALL | wx.EXPAND | wx.ALIGN_LEFT, 2) + + self.fourDir = wx.CheckBox(self, -1, "4-Way Only") + sizer.Add(self.fourDir, 0, wx.ALL | wx.EXPAND | wx.ALIGN_LEFT, 2) + + self.cts = wx.CheckBox(self, -1, "Continuous") + sizer.Add(self.cts, 0, wx.ALL | wx.EXPAND | wx.ALIGN_LEFT, 2) + + self.SetSizer(sizer) + sizer.Fit(self) + + # Effectively makes the checkboxes read-only. + self.Bind(wx.EVT_CHECKBOX, self.Calibrate) + + + def Calibrate(self, evt=None): + s = self.stick + self.avail.SetValue(s.HasPOV()) + self.fourDir.SetValue(s.HasPOV4Dir()) + self.cts.SetValue(s.HasPOVCTS()) + + +#---------------------------------------------------------------------------- + +class POVPanel(wx.Panel): + def __init__(self, parent, stick): + + self.stick = stick + + wx.Panel.__init__(self, parent, -1, size=(100, 100)) + + sizer = wx.BoxSizer(wx.HORIZONTAL) + gsizer = wx.BoxSizer(wx.VERTICAL) + + sizer.Add((25,25)) + + fn = parent.GetFont() + fn.SetPointSize(fn.GetPointSize() + 3) + fn.SetWeight(wx.BOLD) + + t = wx.StaticText(self, -1, "POV Control", style = wx.ALIGN_CENTER) + t.SetFont(fn) + gsizer.Add(t, 0, wx.ALL | wx.EXPAND, 1) + + self.display = POVGauge(self, stick) + gsizer.Add(self.display, 1, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 1) + sizer.Add(gsizer, 1, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 1) + + self.status = POVStatus(self, stick) + sizer.Add(self.status, 1, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 1) + + self.SetSizer(sizer) + sizer.Fit(self) + + + def Calibrate(self): + self.display.Calibrate() + self.status.Calibrate() + + + def Update(self): + self.display.Update() + + +#---------------------------------------------------------------------------- + +class LED(wx.Panel): + def __init__(self, parent, number): + + self.state = -1 + self.size = (20, 20) + self.number = number + + fn = parent.GetFont() + fn.SetPointSize(fn.GetPointSize() - 1) + fn.SetWeight(wx.BOLD) + self.fn = fn + + wx.Panel.__init__(self, parent, -1, size=self.size) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_ERASE_BACKGROUND, lambda e: None) + + self.buffer = wx.EmptyBitmap(*self.size) + dc = wx.BufferedDC(None, self.buffer) + self.DrawFace(dc) + self.DrawLED(dc) + + + def OnSize(self, event): + # calculate the size of our display. + w, h = self.GetClientSize() + s = min(w, h) + self.size = (s, s) + self.buffer = wx.EmptyBitmap(*self.size) + dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) + self.DrawFace(dc) + self.DrawLED(dc) + + + def DrawFace(self, dc): + dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.Clear() + + + def OnPaint(self, evt): + # When dc is destroyed it will blit self.buffer to the window, + # since no other drawing is needed we'll just return and let it + # do it's thing + dc = wx.BufferedPaintDC(self, self.buffer) + + + def DrawLED(self, dc): + # bitmap size + bw, bh = self.size + + # center of bitmap + center = bw / 2 + + # calc the 0, 0 origin of the bitmap + xorigin = center - (bw / 2) + yorigin = center - (bh / 2) + + # Optimize drawing a bit (for Win) + dc.BeginDrawing() + + # our 'raster'. + if self.state == 0: + dc.SetBrush(wx.Brush(wx.RED)) + elif self.state == 1: + dc.SetBrush(wx.Brush(wx.GREEN)) + else: + dc.SetBrush(wx.Brush(wx.BLACK)) + + dc.DrawCircle(center, center, bw/2) + + txt = str(self.number) + + # Set the font for the DC ... + dc.SetFont(self.fn) + # ... and calculate how much space our value + # will take up. + fw, fh = dc.GetTextExtent(txt) + + # Calc the center of the LED, and from that + # derive the origin of our value. + tx = center - (fw/2) + ty = center - (fh/2) + + # I draw the value twice so as to give it a pseudo-shadow. + # This is (mostly) because I'm too lazy to figure out how + # to blit my text onto the gauge using one of the logical + # functions. The pseudo-shadow gives the text contrast + # regardless of whether the bar is under it or not. + dc.SetTextForeground(wx.WHITE) + dc.DrawText(txt, tx, ty) + + # Turn off drawing optimization + dc.EndDrawing() + + + def Update(self): + dc = wx.BufferedDC(wx.ClientDC(self), self.buffer) + self.DrawFace(dc) + self.DrawLED(dc) + + +#---------------------------------------------------------------------------- + +class JoyButtons(wx.Panel): + def __init__(self, parent, stick): + + self.stick = stick + self.leds = {} + + wx.Panel.__init__(self, parent, -1) + + tsizer = wx.BoxSizer(wx.VERTICAL) + + fn = parent.GetFont() + fn.SetPointSize(fn.GetPointSize() + 3) + fn.SetWeight(wx.BOLD) + + t = wx.StaticText(self, -1, "Buttons", style = wx.ALIGN_LEFT) + t.SetFont(fn) + tsizer.Add(t, 0, wx.ALL | wx.EXPAND | wx.ALIGN_LEFT, 1) + + sizer = wx.FlexGridSizer(4, 16, 2, 2) + + fn.SetPointSize(parent.GetFont().GetPointSize() + 1) + + for i in range(0, MAX_BUTTONS): + t = LED(self, i) + self.leds[i] = t + sizer.Add(t, 1, wx.ALL|wx.ALIGN_CENTER|wx.ALIGN_CENTER_VERTICAL, 1) + sizer.AddGrowableCol(i) + + tsizer.Add(sizer, 1, wx.ALL | wx.EXPAND | wx.ALIGN_LEFT, 1) + + self.SetSizer(tsizer) + tsizer.Fit(self) + + def Calibrate(self): + for i in range(0, MAX_BUTTONS): + self.leds[i].state = -1 + + t = self.stick.GetNumberButtons() + + for i in range(0, t): + self.leds[i].state = 0 + + def Update(self): + t = self.stick.GetButtonState() + + for i in range(0, MAX_BUTTONS): + if self.leds[i].state == 1: + self.leds[i].state = 0 + + if (t & (1< + +

wx.Joystick

+This demo illustrates the use of the wx.Joystick class, which is an interface to +one or more joysticks attached to your system. + +

The data that can be retrieved from the joystick comes in four basic flavors. +All of these are illustrated in the demo. In fact, this demo illustrates everything +you can get from the wx.Joystick control. + +

    +
  • Static information such as Manufacturer ID and model name, +
  • Analog input from up to six axes, including X and Y for the actual stick, +
  • Button input from the fire button and any other buttons that the stick has, +
  • and the POV control (a kind of mini-joystick on top of the joystick) that many sticks come with. +
+ +

Getting data from the joystick can be event-driven thanks to four event types associated +with wx.JoystickEvent, or the joystick can be polled programatically to get data on +a regular basis. + +

Data types

+ +Data from the joystick comes in two flavors: that which defines the boundaries, and that +which defines the current state of the stick. Thus, we have Get*Max() and Get*Min() +methods for all axes, the max number of axes, the max number of buttons, and so on. In +general, this data can be read once and stored to speed computation up. + +

Analog Input

+ +Analog input (the axes) is delivered as a whole, positive number. If you need to know +if the axis is at zero (centered) or not, you will first have to calculate that center +based on the max and min values. The demo shows a bar graph for each axis expressed +in native numerical format, plus a 'centered' X-Y axis compass showing the relationship +of that input to the calculated stick position. + +Analog input may be jumpy and spurious, so the control has a means of 'smoothing' the +analog data by setting a movement threshold. This demo sets the threshold to 10, but +you can set it at any valid value between the min and max. + +

Button Input

+ +Button state is retrieved as one int that contains each button state mapped to a bit. +You get the state of a button by AND-ing its bit against the returned value, in the form + +
+     # assume buttonState is what the stick returned, and buttonBit 
+     # is the bit you want to examine
+     
+     if (buttonState & ( 1 << buttonBit )) :
+         # button pressed, do something with it
+
+ +

The problem here is that some OSs return a 32-bit value for up to 32 buttons +(imagine that stick!). Python V2.3 will generate an exception for bit +values over 30. For that reason, this demo is limited to 16 buttons. + +

Note that more than one button can be pressed at a time, so be sure to check all of them! + + +

POV Input

+ +POV hats come in two flavors: four-way, and continuous. four-way POVs are restricted to +the cardinal points of the compass; continuous, or CTS POV hats can deliver input in +.01 degree increments, theoreticaly. The data is returned as a whole number; the last +two digits are considered to be to the right of the decimal point, so in order to +use this information, you need to divide by 100 right off the bat. + +

Different methods are provided to retrieve the POV data for a CTS hat +versus a four-way hat. + +

Caveats

+ +The wx.Joystick control is in many ways incomplete at the C++ library level, but it is +not insurmountable. In short, while the joystick interface can be event-driven, +the wx.JoystickEvent class lacks event binders for all event types. Thus, you cannot +rely on wx.JoystickEvents to tell you when something has changed, necessarilly. + +
    +
  • There are no events associated with the POV control. +
  • There are no events associated with the Rudder +
  • There are no events associated with the U and V axes. +
+ +

Fortunately, there is an easy workaround. In the top level frame, create a wx.Timer +that will poll the stick at a set interval. Of course, if you do this, you might as +well forgo catching wxEVT_JOYSTICK_* events at all and rely on the timer to do the +polling. + +

Ideally, the timer should be a one-shot; after it fires, collect and process data as +needed, then re-start the timer, possibly using wx.CallAfter(). + + + +""" + +#---------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/KeyEvents.py b/demo/KeyEvents.py new file mode 100644 index 00000000..90277cc0 --- /dev/null +++ b/demo/KeyEvents.py @@ -0,0 +1,429 @@ + +import wx +import wx.lib.mixins.listctrl as listmix + +#---------------------------------------------------------------------- + +keyMap = { + wx.WXK_BACK : "WXK_BACK", + wx.WXK_TAB : "WXK_TAB", + wx.WXK_RETURN : "WXK_RETURN", + wx.WXK_ESCAPE : "WXK_ESCAPE", + wx.WXK_SPACE : "WXK_SPACE", + wx.WXK_DELETE : "WXK_DELETE", + wx.WXK_START : "WXK_START", + wx.WXK_LBUTTON : "WXK_LBUTTON", + wx.WXK_RBUTTON : "WXK_RBUTTON", + wx.WXK_CANCEL : "WXK_CANCEL", + wx.WXK_MBUTTON : "WXK_MBUTTON", + wx.WXK_CLEAR : "WXK_CLEAR", + wx.WXK_SHIFT : "WXK_SHIFT", + wx.WXK_ALT : "WXK_ALT", + wx.WXK_MENU : "WXK_MENU", + wx.WXK_PAUSE : "WXK_PAUSE", + wx.WXK_CAPITAL : "WXK_CAPITAL", + #wx.WXK_PRIOR : "WXK_PRIOR", + #wx.WXK_NEXT : "WXK_NEXT", + wx.WXK_END : "WXK_END", + wx.WXK_HOME : "WXK_HOME", + wx.WXK_LEFT : "WXK_LEFT", + wx.WXK_UP : "WXK_UP", + wx.WXK_RIGHT : "WXK_RIGHT", + wx.WXK_DOWN : "WXK_DOWN", + wx.WXK_SELECT : "WXK_SELECT", + wx.WXK_PRINT : "WXK_PRINT", + wx.WXK_EXECUTE : "WXK_EXECUTE", + wx.WXK_SNAPSHOT : "WXK_SNAPSHOT", + wx.WXK_INSERT : "WXK_INSERT", + wx.WXK_HELP : "WXK_HELP", + wx.WXK_NUMPAD0 : "WXK_NUMPAD0", + wx.WXK_NUMPAD1 : "WXK_NUMPAD1", + wx.WXK_NUMPAD2 : "WXK_NUMPAD2", + wx.WXK_NUMPAD3 : "WXK_NUMPAD3", + wx.WXK_NUMPAD4 : "WXK_NUMPAD4", + wx.WXK_NUMPAD5 : "WXK_NUMPAD5", + wx.WXK_NUMPAD6 : "WXK_NUMPAD6", + wx.WXK_NUMPAD7 : "WXK_NUMPAD7", + wx.WXK_NUMPAD8 : "WXK_NUMPAD8", + wx.WXK_NUMPAD9 : "WXK_NUMPAD9", + wx.WXK_MULTIPLY : "WXK_MULTIPLY", + wx.WXK_ADD : "WXK_ADD", + wx.WXK_SEPARATOR : "WXK_SEPARATOR", + wx.WXK_SUBTRACT : "WXK_SUBTRACT", + wx.WXK_DECIMAL : "WXK_DECIMAL", + wx.WXK_DIVIDE : "WXK_DIVIDE", + wx.WXK_F1 : "WXK_F1", + wx.WXK_F2 : "WXK_F2", + wx.WXK_F3 : "WXK_F3", + wx.WXK_F4 : "WXK_F4", + wx.WXK_F5 : "WXK_F5", + wx.WXK_F6 : "WXK_F6", + wx.WXK_F7 : "WXK_F7", + wx.WXK_F8 : "WXK_F8", + wx.WXK_F9 : "WXK_F9", + wx.WXK_F10 : "WXK_F10", + wx.WXK_F11 : "WXK_F11", + wx.WXK_F12 : "WXK_F12", + wx.WXK_F13 : "WXK_F13", + wx.WXK_F14 : "WXK_F14", + wx.WXK_F15 : "WXK_F15", + wx.WXK_F16 : "WXK_F16", + wx.WXK_F17 : "WXK_F17", + wx.WXK_F18 : "WXK_F18", + wx.WXK_F19 : "WXK_F19", + wx.WXK_F20 : "WXK_F20", + wx.WXK_F21 : "WXK_F21", + wx.WXK_F22 : "WXK_F22", + wx.WXK_F23 : "WXK_F23", + wx.WXK_F24 : "WXK_F24", + wx.WXK_NUMLOCK : "WXK_NUMLOCK", + wx.WXK_SCROLL : "WXK_SCROLL", + wx.WXK_PAGEUP : "WXK_PAGEUP", + wx.WXK_PAGEDOWN : "WXK_PAGEDOWN", + wx.WXK_NUMPAD_SPACE : "WXK_NUMPAD_SPACE", + wx.WXK_NUMPAD_TAB : "WXK_NUMPAD_TAB", + wx.WXK_NUMPAD_ENTER : "WXK_NUMPAD_ENTER", + wx.WXK_NUMPAD_F1 : "WXK_NUMPAD_F1", + wx.WXK_NUMPAD_F2 : "WXK_NUMPAD_F2", + wx.WXK_NUMPAD_F3 : "WXK_NUMPAD_F3", + wx.WXK_NUMPAD_F4 : "WXK_NUMPAD_F4", + wx.WXK_NUMPAD_HOME : "WXK_NUMPAD_HOME", + wx.WXK_NUMPAD_LEFT : "WXK_NUMPAD_LEFT", + wx.WXK_NUMPAD_UP : "WXK_NUMPAD_UP", + wx.WXK_NUMPAD_RIGHT : "WXK_NUMPAD_RIGHT", + wx.WXK_NUMPAD_DOWN : "WXK_NUMPAD_DOWN", + #wx.WXK_NUMPAD_PRIOR : "WXK_NUMPAD_PRIOR", + wx.WXK_NUMPAD_PAGEUP : "WXK_NUMPAD_PAGEUP", + #wx.WXK_NUMPAD_NEXT : "WXK_NUMPAD_NEXT", + wx.WXK_NUMPAD_PAGEDOWN : "WXK_NUMPAD_PAGEDOWN", + wx.WXK_NUMPAD_END : "WXK_NUMPAD_END", + wx.WXK_NUMPAD_BEGIN : "WXK_NUMPAD_BEGIN", + wx.WXK_NUMPAD_INSERT : "WXK_NUMPAD_INSERT", + wx.WXK_NUMPAD_DELETE : "WXK_NUMPAD_DELETE", + wx.WXK_NUMPAD_EQUAL : "WXK_NUMPAD_EQUAL", + wx.WXK_NUMPAD_MULTIPLY : "WXK_NUMPAD_MULTIPLY", + wx.WXK_NUMPAD_ADD : "WXK_NUMPAD_ADD", + wx.WXK_NUMPAD_SEPARATOR : "WXK_NUMPAD_SEPARATOR", + wx.WXK_NUMPAD_SUBTRACT : "WXK_NUMPAD_SUBTRACT", + wx.WXK_NUMPAD_DECIMAL : "WXK_NUMPAD_DECIMAL", + wx.WXK_NUMPAD_DIVIDE : "WXK_NUMPAD_DIVIDE", + + wx.WXK_WINDOWS_LEFT : "WXK_WINDOWS_LEFT", + wx.WXK_WINDOWS_RIGHT : "WXK_WINDOWS_RIGHT", + wx.WXK_WINDOWS_MENU : "WXK_WINDOWS_MENU", + + wx.WXK_SPECIAL1 : "WXK_SPECIAL1", + wx.WXK_SPECIAL2 : "WXK_SPECIAL2", + wx.WXK_SPECIAL3 : "WXK_SPECIAL3", + wx.WXK_SPECIAL4 : "WXK_SPECIAL4", + wx.WXK_SPECIAL5 : "WXK_SPECIAL5", + wx.WXK_SPECIAL6 : "WXK_SPECIAL6", + wx.WXK_SPECIAL7 : "WXK_SPECIAL7", + wx.WXK_SPECIAL8 : "WXK_SPECIAL8", + wx.WXK_SPECIAL9 : "WXK_SPECIAL9", + wx.WXK_SPECIAL10 : "WXK_SPECIAL10", + wx.WXK_SPECIAL11 : "WXK_SPECIAL11", + wx.WXK_SPECIAL12 : "WXK_SPECIAL12", + wx.WXK_SPECIAL13 : "WXK_SPECIAL13", + wx.WXK_SPECIAL14 : "WXK_SPECIAL14", + wx.WXK_SPECIAL15 : "WXK_SPECIAL15", + wx.WXK_SPECIAL16 : "WXK_SPECIAL16", + wx.WXK_SPECIAL17 : "WXK_SPECIAL17", + wx.WXK_SPECIAL18 : "WXK_SPECIAL18", + wx.WXK_SPECIAL19 : "WXK_SPECIAL19", + wx.WXK_SPECIAL2 : "WXK_SPECIAL2", +} + +if 'wxMac' in wx.PlatformInfo: + keyMap[wx.WXK_RAW_CONTROL] = 'WXK_RAW_CONTROL' + keyMap[wx.WXK_CONTROL] = "WXK_CONTROL" + keyMap[wx.WXK_COMMAND] = "WXK_COMMAND" +else: + keyMap[wx.WXK_COMMAND] = "WXK_COMMAND" + keyMap[wx.WXK_CONTROL] = "WXK_CONTROL" + + +#---------------------------------------------------------------------- + +class KeySink(wx.Window): + def __init__(self, parent): + wx.Window.__init__(self, parent, -1, style=wx.WANTS_CHARS + #| wx.RAISED_BORDER + #| wx.SUNKEN_BORDER + , name="sink") + + self.SetBackgroundColour(wx.BLUE) + self.haveFocus = False + self.callSkip = True + self.logKeyDn = True + self.logKeyUp = True + self.logChar = True + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) + self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) + self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse) + + self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) + self.Bind(wx.EVT_KEY_UP, self.OnKeyUp) + self.Bind(wx.EVT_CHAR, self.OnChar) + + + def SetCallSkip(self, skip): + self.callSkip = skip + + def SetLogKeyUp(self, val): + self.logKeyUp = val + + def SetLogKeyDn(self, val): + self.logKeyDn = val + + def SetLogChar(self, val): + self.logChar = val + + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + rect = self.GetClientRect() + dc.SetTextForeground(wx.WHITE) + dc.DrawLabel("Click here and then press some keys", + rect, wx.ALIGN_CENTER | wx.ALIGN_TOP) + if self.haveFocus: + dc.SetTextForeground(wx.GREEN) + dc.DrawLabel("Have Focus", rect, wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM) + else: + dc.SetTextForeground(wx.RED) + dc.DrawLabel("Need Focus!", rect, wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM) + + + def OnSetFocus(self, evt): + self.haveFocus = True + self.Refresh() + + def OnKillFocus(self, evt): + self.haveFocus = False + self.Refresh() + + def OnMouse(self, evt): + if evt.ButtonDown(): + self.SetFocus() + + + def OnKeyDown(self, evt): + if self.logKeyDn: + self.GetParent().keylog.LogKeyEvent("KeyDown", evt) + if self.callSkip: + evt.Skip() + + def OnKeyUp(self, evt): + if self.logKeyUp: + self.GetParent().keylog.LogKeyEvent("KeyUp", evt) + if self.callSkip: + evt.Skip() + + def OnChar(self, evt): + if self.logChar: + self.GetParent().keylog.LogKeyEvent("Char", evt) + + +#---------------------------------------------------------------------- + +class KeyLog(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): + colHeaders = [ "Event Type", + "Key Name", + "Key Code", + "Modifiers", + "Unicode", + "UniChr", + "RawKeyCode", + "RawKeyFlags", + ] + + def __init__(self, parent): + wx.ListCtrl.__init__(self, parent, -1, + style = wx.LC_REPORT|wx.LC_VRULES|wx.LC_HRULES) + listmix.ListCtrlAutoWidthMixin.__init__(self) + + for idx, header in enumerate(self.colHeaders): + self.InsertColumn(idx, header) + idx += 1 + self.InsertColumn(idx, "") + + for x in range(idx): + self.SetColumnWidth(x, wx.LIST_AUTOSIZE_USEHEADER) + + self.SetColumnWidth(1, 125) + + + def LogKeyEvent(self, evType, evt): + keycode = evt.GetKeyCode() + keyname = keyMap.get(keycode, None) + + if keyname is None: + if keycode < 256: + if keycode == 0: + keyname = "NUL" + elif keycode < 27: + keyname = u"Ctrl-%s" % unichr(ord('A') + keycode-1) + else: + keyname = u"\"%s\"" % unichr(keycode) + else: + keyname = u"(%s)" % keycode + + UniChr = '' + if "unicode" in wx.PlatformInfo: + UniChr = "\"" + unichr(evt.GetUnicodeKey()) + "\"" + + modifiers = "" + for mod, ch in [(evt.ControlDown(), 'C'), + (evt.AltDown(), 'A'), + (evt.ShiftDown(), 'S'), + (evt.MetaDown(), 'M'), + (evt.RawControlDown(), 'R'),]: + if mod: + modifiers += ch + else: + modifiers += '-' + + id = self.InsertStringItem(self.GetItemCount(), evType) + self.SetStringItem(id, 1, keyname) + self.SetStringItem(id, 2, str(keycode)) + self.SetStringItem(id, 3, modifiers) + self.SetStringItem(id, 4, str(evt.GetUnicodeKey())) + self.SetStringItem(id, 5, UniChr) + self.SetStringItem(id, 6, str(evt.GetRawKeyCode())) + self.SetStringItem(id, 7, str(evt.GetRawKeyFlags())) + + #print ( id, evType, keyname, str(keycode), modifiers, str(evt.GetRawKeyCode()), str(evt.GetRawKeyFlags())) + + self.EnsureVisible(id) + + + def ClearLog(self): + self.DeleteAllItems() + + def CopyLog(self): + # build a newline and tab delimited string to put into the clipboard + if "unicode" in wx.PlatformInfo: + st = u"" + else: + st = "" + for h in self.colHeaders: + st += h + "\t" + st += "\n" + + for idx in range(self.GetItemCount()): + for col in range(self.GetColumnCount()): + item = self.GetItem(idx, col) + st += item.GetText() + "\t" + st += "\n" + + data = wx.TextDataObject() + data.SetText(st) + if wx.TheClipboard.Open(): + wx.TheClipboard.SetData(data) + wx.TheClipboard.Close() + else: + wx.MessageBox("Unable to open the clipboard", "Error") + + + + +#---------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1, style=0) + self.keysink = KeySink(self) + self.keysink.SetMinSize((100, 65)) + self.keylog = KeyLog(self) + + btn = wx.Button(self, -1, "Clear", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnClearBtn, btn) + btn.SetToolTipString( + "Clear the items from the log window") + + btn2 = wx.Button(self, -1, "Copy", style=wx.BU_EXACTFIT) + self.Bind(wx.EVT_BUTTON, self.OnCopyBtn, btn2) + btn2.SetToolTipString( + "Copy the contents of the log window to the clipboard") + + cb1 = wx.CheckBox(self, -1, "Call evt.Skip in Key* events") + self.Bind(wx.EVT_CHECKBOX, self.OnSkipCB, cb1) + cb1.SetValue(True) + + cb2 = wx.CheckBox(self, -1, "KEY_UP") + self.Bind(wx.EVT_CHECKBOX, self.OnKeyUpCB, cb2) + cb2.SetValue(True) + + cb3 = wx.CheckBox(self, -1, "KEY_DOWN") + self.Bind(wx.EVT_CHECKBOX, self.OnKeyDnCB, cb3) + cb3.SetValue(True) + + cb4 = wx.CheckBox(self, -1, "CHAR") + self.Bind(wx.EVT_CHECKBOX, self.OnCharCB, cb4) + cb4.SetValue(True) + + buttons = wx.BoxSizer(wx.HORIZONTAL) + buttons.Add(btn, 0, wx.ALL, 4) + buttons.Add(btn2, 0, wx.ALL, 4) + buttons.Add(cb1, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 6) + buttons.Add(cb2, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6) + buttons.Add(cb3, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6) + buttons.Add(cb4, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT, 6) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.keysink, 0, wx.GROW) + sizer.Add(buttons) + sizer.Add(self.keylog, 1, wx.GROW) + + self.SetSizer(sizer) + + + def OnClearBtn(self, evt): + self.keylog.ClearLog() + + def OnCopyBtn(self, evt): + self.keylog.CopyLog() + + def OnSkipCB(self, evt): + self.keysink.SetCallSkip(evt.GetInt()) + + def OnKeyUpCB(self, evt): + self.keysink.SetLogKeyUp(evt.GetInt()) + + def OnKeyDnCB(self, evt): + self.keysink.SetLogKeyDn(evt.GetInt()) + + def OnCharCB(self, evt): + self.keysink.SetLogChar(evt.GetInt()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wxKeyEvents

+ +This demo simply catches all key events and prints info about them. +It is meant to be used as a compatibility test for cross platform work. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/LEDNumberCtrl.py b/demo/LEDNumberCtrl.py new file mode 100644 index 00000000..0217d691 --- /dev/null +++ b/demo/LEDNumberCtrl.py @@ -0,0 +1,116 @@ + +import time + +import wx +import wx.gizmos as gizmos + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + led = gizmos.LEDNumberCtrl(self, -1, (25,25), (280, 50)) + led.SetValue("01234") + + led = gizmos.LEDNumberCtrl(self, -1, (25,100), (280, 50)) + led.SetValue("56789") + led.SetAlignment(gizmos.LED_ALIGN_RIGHT) + led.SetDrawFaded(False) + + led = gizmos.LEDNumberCtrl(self, -1, (25,175), (280, 50), + gizmos.LED_ALIGN_CENTER)# | gizmos.LED_DRAW_FADED) + self.clock = led + self.OnTimer(None) + + self.timer = wx.Timer(self) + self.timer.Start(1000) + self.Bind(wx.EVT_TIMER, self.OnTimer) + + + def OnTimer(self, evt): + t = time.localtime(time.time()) + st = time.strftime("%I-%M-%S", t) + self.clock.SetValue(st) + + + def ShutdownDemo(self): + self.timer.Stop() + del self.timer + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = """\ + + +The following was gleaned as best I could from the wxWindows +source, which was a bit reluctant to reveal its secrets. My appologies if +I missed anything - jmg +

+LEDNumberCtrl( parent, id=-1, pos=wx.DefaultPosition, +size=wx.DefaultSize, style=LED_ALIGN_LEFT | LED_DRAW_FADED) + +

This is a control that simulates an LED clock display. It only accepts +numeric input. + +

Styles + +

+
LED_ALIGN_LEFT +
Align to the left. + +
LED_ALIGN_RIGHT +
Align to the right. + +
LED_ALIGN_CENTER +
Center on display. + +
LED_DRAW_FADED +
Not implemented. + +
+ +

Methods (and best guesses at what they do) + +

+
GetAlignment() +
Returns the alignment attribute for the control. + +
GetDrawFaded() +
Returns the DrawFaded attribute for the control. + +
GetValue() +
Returns the current value of the control. + +
SetAlignment(alignment) +
Set the alignment attribute for the control. + +
SetDrawFaded(value) +
Set the DrawFaded attribute for the control. + +
SetValue(number) +
Set the value for the control. Only numeric values are accepted. + +
+ +

Additionally, several methods of wx.Window are available as well. + + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/LayoutAnchors.py b/demo/LayoutAnchors.py new file mode 100644 index 00000000..153450e0 --- /dev/null +++ b/demo/LayoutAnchors.py @@ -0,0 +1,257 @@ + +import wx +import wx.lib.anchors as anchors + +#---------------------------------------------------------------------- + +# Nifty little trick here; apply wx.NewId() to generate a series of +# IDs used later on in the app. + +[ ID_ANCHORSDEMOFRAMEANCHOREDPANEL, + ID_ANCHORSDEMOFRAMEHELPSTATICTEXT, + ID_ANCHORSDEMOFRAMEMAINPANEL, + ID_ANCHORSDEMOFRAMEBACKGROUNDPANEL, + ID_ANCHORSDEMOFRAMERIGHTCHECKBOX, + ID_ANCHORSDEMOFRAMEOKBUTTON, + ID_ANCHORSDEMOFRAMETOPCHECKBOX, + ID_ANCHORSDEMOFRAMEBOTTOMCHECKBOX, + ID_ANCHORSDEMOFRAME, + ID_ANCHORSDEMOFRAMELEFTCHECKBOX, + ] = map(lambda _init_ctrls: wx.NewId(), range(10)) + +# A small note here: while only certain parts of this frame are actually demonstrating +# the capabilities of the LayoutAnchors feature, all the controls are within the same +# frame; therefore, all controls and windows within the frame must use LayoutAnchors. +# You can't mix LayoutAnchors and sizers. +class AnchorsDemoFrame(wx.Frame): + def _init_utils(self): + pass + + def _init_ctrls(self, prnt): + wx.Frame.__init__( + self, size=(328, 187), id=ID_ANCHORSDEMOFRAME, + title='LayoutAnchors Demonstration', parent=prnt, + name='AnchorsDemoFrame', + style = wx.DEFAULT_FRAME_STYLE | wx.CLIP_CHILDREN, pos=(261, 123) + ) + + self._init_utils() + + self.mainPanel = wx.Panel( + size=(320, 160), parent=self, + id=ID_ANCHORSDEMOFRAMEMAINPANEL, name='panel1', + style=wx.TAB_TRAVERSAL | wx.CLIP_CHILDREN + | wx.FULL_REPAINT_ON_RESIZE, + pos=(0, 0) + ) + + self.mainPanel.SetAutoLayout(True) + + self.okButton = wx.Button( + label='OK', id=ID_ANCHORSDEMOFRAMEOKBUTTON, + parent=self.mainPanel, name='okButton', + size=(72, 24), style=0, pos=(240, 128) + ) + + self.okButton.SetConstraints( + anchors.LayoutAnchors(self.okButton, False, False, True, True) + ) + + self.Bind( + wx.EVT_BUTTON, self.OnOkButtonButton, id=ID_ANCHORSDEMOFRAMEOKBUTTON + ) + + self.backgroundPanel = wx.Panel( + size=(304, 80), parent=self.mainPanel, + id=ID_ANCHORSDEMOFRAMEBACKGROUNDPANEL, + name='backgroundPanel', + style=wx.SIMPLE_BORDER | wx.CLIP_CHILDREN, + pos = (8, 40) + ) + + self.backgroundPanel.SetBackgroundColour(wx.Colour(255, 255, 255)) + self.backgroundPanel.SetConstraints( + anchors.LayoutAnchors(self.backgroundPanel, True, True, True, True) + ) + + self.anchoredPanel = wx.Panel( + size=(88, 48), id=ID_ANCHORSDEMOFRAMEANCHOREDPANEL, + parent=self.backgroundPanel, name='anchoredPanel', + style=wx.SIMPLE_BORDER, pos=(104, 16) + ) + + self.anchoredPanel.SetBackgroundColour(wx.Colour(0, 0, 222)) + self.anchoredPanel.SetConstraints( + anchors.LayoutAnchors(self.anchoredPanel, False, False, False, False) + ) + + self.leftCheckBox = wx.CheckBox( + label='Left', id=ID_ANCHORSDEMOFRAMELEFTCHECKBOX, + parent=self.mainPanel, name='leftCheckBox', + style=0, pos=(8, 8) + ) + + self.leftCheckBox.SetConstraints( + anchors.LayoutAnchors(self.leftCheckBox, False, True, False, False) + ) + + self.Bind( + wx.EVT_CHECKBOX, self.OnCheckboxCheckbox, source=self.leftCheckBox, + id=ID_ANCHORSDEMOFRAMELEFTCHECKBOX + ) + + self.topCheckBox = wx.CheckBox( + label='Top', id=ID_ANCHORSDEMOFRAMETOPCHECKBOX, + parent=self.mainPanel, name='topCheckBox', + style=0, pos=(88, 8) + ) + + self.topCheckBox.SetConstraints( + anchors.LayoutAnchors(self.topCheckBox, False, True, False, False) + ) + + self.Bind( + wx.EVT_CHECKBOX, self.OnCheckboxCheckbox, source=self.topCheckBox, + id=ID_ANCHORSDEMOFRAMETOPCHECKBOX + ) + + self.rightCheckBox = wx.CheckBox( + label='Right', id=ID_ANCHORSDEMOFRAMERIGHTCHECKBOX, + parent=self.mainPanel, name='rightCheckBox', + style=0, pos=(168, 8) + ) + + self.rightCheckBox.SetConstraints( + anchors.LayoutAnchors(self.rightCheckBox, False, True, False, False) + ) + + self.Bind( + wx.EVT_CHECKBOX, self.OnCheckboxCheckbox, source=self.rightCheckBox, + id=ID_ANCHORSDEMOFRAMERIGHTCHECKBOX + ) + + self.bottomCheckBox = wx.CheckBox( + label='Bottom', id=ID_ANCHORSDEMOFRAMEBOTTOMCHECKBOX, + parent=self.mainPanel, name='bottomCheckBox', + style=0, pos=(248, 8) + ) + + self.bottomCheckBox.SetConstraints( + anchors.LayoutAnchors(self.bottomCheckBox, False, True, False, False) + ) + + self.Bind( + wx.EVT_CHECKBOX, self.OnCheckboxCheckbox, source=self.bottomCheckBox, + id=ID_ANCHORSDEMOFRAMEBOTTOMCHECKBOX + ) + + self.helpStaticText = wx.StaticText( + label='Select anchor options above, then resize window to see the effect', + id=ID_ANCHORSDEMOFRAMEHELPSTATICTEXT, + parent=self.mainPanel, name='helpStaticText', + size=(224, 24), style=wx.ST_NO_AUTORESIZE, + pos=(8, 128) + ) + + self.helpStaticText.SetConstraints( + anchors.LayoutAnchors(self.helpStaticText, True, False, True, True) + ) + + def __init__(self, parent): + self._init_ctrls(parent) + + # Based on the values of the above checkboxes, we will adjust the layout constraints + # on the sample window whenever one of the checkboxes changes state. + def OnCheckboxCheckbox(self, event): + self.anchoredPanel.SetConstraints( + anchors.LayoutAnchors(self.anchoredPanel, + self.leftCheckBox.GetValue(), self.topCheckBox.GetValue(), + self.rightCheckBox.GetValue(), self.bottomCheckBox.GetValue() + ) + ) + + def OnOkButtonButton(self, event): + self.Close() + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show the LayoutAnchors sample", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = AnchorsDemoFrame(self) + win.Show(True) + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """ +

LayoutAnchors

+ A class that implements Delphi's Anchors with wxLayoutConstraints. +

+ Anchored sides maintain the distance from the edge of the + control to the same edge of the parent. + When neither side is selected, the control keeps the same + relative position to both sides. +

+ The current position and size of the control and it's parent + is used when setting up the constraints. To change the size or + position of an already anchored control, set the constraints to + None, reposition or resize and reapply the anchors. +

+ Examples: +

+ Let's anchor the right and bottom edge of a control and + resize it's parent. +

+

+        ctrl.SetConstraints(LayoutAnchors(ctrl, left=0, top=0, right=1, bottom=1))
+
+        +=========+         +===================+
+        | +-----+ |         |                   |
+        | |     * |   ->    |                   |
+        | +--*--+ |         |           +-----+ |
+        +---------+         |           |     * |
+                            |           +--*--+ |
+                            +-------------------+
+        * = anchored edge
+
+

+ When anchored on both sides the control will stretch horizontally. +

+

+        ctrl.SetConstraints(LayoutAnchors(ctrl, 1, 0, 1, 1))
+
+        +=========+         +===================+
+        | +-----+ |         |                   |
+        | *     * |   ->    |                   |
+        | +--*--+ |         | +---------------+ |
+        +---------+         | *     ctrl      * |
+                            | +-------*-------+ |
+                            +-------------------+
+        * = anchored edge
+
+ +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/LayoutConstraints.py b/demo/LayoutConstraints.py new file mode 100644 index 00000000..3484fe5d --- /dev/null +++ b/demo/LayoutConstraints.py @@ -0,0 +1,148 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestLayoutConstraints(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, -1) + self.SetAutoLayout(True) + self.Bind(wx.EVT_BUTTON, self.OnButton, id=100) + + self.SetBackgroundColour(wx.NamedColour("MEDIUM ORCHID")) + + self.panelA = wx.Window(self, -1, style=wx.SIMPLE_BORDER) + self.panelA.SetBackgroundColour(wx.BLUE) + + txt = wx.StaticText( + self.panelA, -1, + "Resize the window and see\n" + "what happens... Notice that\n" + "there is no OnSize handler.", + (5,5), (-1, 50) + ) + + txt.SetBackgroundColour(wx.BLUE) + txt.SetForegroundColour(wx.WHITE) + + lc = wx.LayoutConstraints() + lc.top.SameAs(self, wx.Top, 10) + lc.left.SameAs(self, wx.Left, 10) + lc.bottom.SameAs(self, wx.Bottom, 10) + lc.right.PercentOf(self, wx.Right, 50) + self.panelA.SetConstraints(lc) + + self.panelB = wx.Window(self, -1, style=wx.SIMPLE_BORDER) + self.panelB.SetBackgroundColour(wx.RED) + lc = wx.LayoutConstraints() + lc.top.SameAs(self, wx.Top, 10) + lc.right.SameAs(self, wx.Right, 10) + lc.bottom.PercentOf(self, wx.Bottom, 30) + lc.left.RightOf(self.panelA, 10) + self.panelB.SetConstraints(lc) + + self.panelC = wx.Window(self, -1, style=wx.SIMPLE_BORDER) + self.panelC.SetBackgroundColour(wx.WHITE) + lc = wx.LayoutConstraints() + lc.top.Below(self.panelB, 10) + lc.right.SameAs(self, wx.Right, 10) + lc.bottom.SameAs(self, wx.Bottom, 10) + lc.left.RightOf(self.panelA, 10) + self.panelC.SetConstraints(lc) + + b = wx.Button(self.panelA, 100, ' Panel A ') + lc = wx.LayoutConstraints() + lc.centreX.SameAs (self.panelA, wx.CentreX) + lc.centreY.SameAs (self.panelA, wx.CentreY) + lc.height.AsIs () + lc.width.PercentOf (self.panelA, wx.Width, 50) + b.SetConstraints(lc) + + b = wx.Button(self.panelB, 100, ' Panel B ') + lc = wx.LayoutConstraints() + lc.top.SameAs (self.panelB, wx.Top, 2) + lc.right.SameAs (self.panelB, wx.Right, 4) + lc.height.AsIs () + lc.width.AsIs () + b.SetConstraints(lc) + + self.panelD = wx.Window(self.panelC, -1, style=wx.SIMPLE_BORDER) + self.panelD.SetBackgroundColour(wx.GREEN) + wx.StaticText( + self.panelD, -1, "Panel D", (4, 4) + ).SetBackgroundColour(wx.GREEN) + + b = wx.Button(self.panelC, 100, ' Panel C ') + lc = wx.LayoutConstraints() + lc.top.Below (self.panelD) + lc.left.RightOf (self.panelD) + lc.height.AsIs () + lc.width.AsIs () + b.SetConstraints(lc) + + lc = wx.LayoutConstraints() + lc.bottom.PercentOf (self.panelC, wx.Height, 50) + lc.right.PercentOf (self.panelC, wx.Width, 50) + lc.height.SameAs (b, wx.Height) + lc.width.SameAs (b, wx.Width) + self.panelD.SetConstraints(lc) + + + def OnButton(self, event): + wx.Bell() + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestLayoutConstraints(nb) + return win + +#--------------------------------------------------------------------------- + + + +overview = """\ + +Objects of this class can be associated with a window to define its +layout constraints, with respect to siblings or its parent. + +

The class consists of the following eight constraints of class +wxIndividualLayoutConstraint, some or all of which should be accessed +directly to set the appropriate constraints. + +

    +
  • left: represents the left hand edge of the window + +
  • right: represents the right hand edge of the window + +
  • top: represents the top edge of the window + +
  • bottom: represents the bottom edge of the window + +
  • width: represents the width of the window + +
  • height: represents the height of the window + +
  • centreX: represents the horizontal centre point of the window + +
  • centreY: represents the vertical centre point of the window +
+

Most constraints are initially set to have the relationship +wxUnconstrained, which means that their values should be calculated by +looking at known constraints. The exceptions are width and height, +which are set to wxAsIs to ensure that if the user does not specify a +constraint, the existing width and height will be used, to be +compatible with panel items which often have take a default size. If +the constraint is wxAsIs, the dimension will not be changed. + +""" + + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Layoutf.py b/demo/Layoutf.py new file mode 100644 index 00000000..b5b5e385 --- /dev/null +++ b/demo/Layoutf.py @@ -0,0 +1,68 @@ + +import wx +import wx.lib.layoutf as layoutf + +#--------------------------------------------------------------------------- + +class TestLayoutf(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, -1) + + self.SetAutoLayout(True) + self.Bind(wx.EVT_BUTTON, self.OnButton) + + self.panelA = wx.Window(self, -1, style=wx.SIMPLE_BORDER) + self.panelA.SetBackgroundColour(wx.BLUE) + self.panelA.SetConstraints( + layoutf.Layoutf('t=t10#1;l=l10#1;b=b10#1;r%r50#1',(self,)) + ) + + self.panelB = wx.Window(self, -1, style=wx.SIMPLE_BORDER) + self.panelB.SetBackgroundColour(wx.RED) + self.panelB.SetConstraints( + layoutf.Layoutf('t=t10#1;r=r10#1;b%b30#1;l>10#2', (self,self.panelA)) + ) + + self.panelC = wx.Window(self, -1, style=wx.SIMPLE_BORDER) + self.panelC.SetBackgroundColour(wx.WHITE) + self.panelC.SetConstraints( + layoutf.Layoutf('t_10#3;r=r10#1;b=b10#1;l>10#2', (self,self.panelA,self.panelB)) + ) + + b = wx.Button(self.panelA, -1, ' Panel A ') + b.SetConstraints(layoutf.Layoutf('X=X#1;Y=Y#1;h*;w%w50#1', (self.panelA,))) + + b = wx.Button(self.panelB, -1, ' Panel B ') + b.SetConstraints(layoutf.Layoutf('t=t2#1;r=r4#1;h*;w*', (self.panelB,))) + + self.panelD = wx.Window(self.panelC, -1, style=wx.SIMPLE_BORDER) + self.panelD.SetBackgroundColour(wx.GREEN) + self.panelD.SetConstraints( + layoutf.Layoutf('b%h50#1;r%w50#1;h=h#2;w=w#2', (self.panelC, b)) + ) + + b = wx.Button(self.panelC, -1, ' Panel C ') + b.SetConstraints(layoutf.Layoutf('t_#1;l>#1;h*;w*', (self.panelD,))) + + wx.StaticText(self.panelD, -1, "Panel D", (4, 4)).SetBackgroundColour(wx.GREEN) + + def OnButton(self, event): + wx.Bell() + + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestLayoutf(nb) + return win + +#--------------------------------------------------------------------------- + +overview = layoutf.Layoutf.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ListBox.py b/demo/ListBox.py new file mode 100644 index 00000000..0e1816a8 --- /dev/null +++ b/demo/ListBox.py @@ -0,0 +1,161 @@ + +import wx + +#--------------------------------------------------------------------------- + +# This listbox subclass lets you type the starting letters of what you want to +# select, and scrolls the list to the match if it is found. +class FindPrefixListBox(wx.ListBox): + def __init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, + choices=[], style=0, validator=wx.DefaultValidator): + wx.ListBox.__init__(self, parent, id, pos, size, choices, style, validator) + self.typedText = '' + self.log = parent.log + self.Bind(wx.EVT_KEY_DOWN, self.OnKey) + + + def FindPrefix(self, prefix): + self.log.WriteText('Looking for prefix: %s\n' % prefix) + + if prefix: + prefix = prefix.lower() + length = len(prefix) + + # Changed in 2.5 because ListBox.Number() is no longer supported. + # ListBox.GetCount() is now the appropriate way to go. + for x in range(self.GetCount()): + text = self.GetString(x) + text = text.lower() + + if text[:length] == prefix: + self.log.WriteText('Prefix %s is found.\n' % prefix) + return x + + self.log.WriteText('Prefix %s is not found.\n' % prefix) + return -1 + + + def OnKey(self, evt): + key = evt.GetKeyCode() + + if key >= 32 and key <= 127: + self.typedText = self.typedText + chr(key) + item = self.FindPrefix(self.typedText) + + if item != -1: + self.SetSelection(item) + + elif key == wx.WXK_BACK: # backspace removes one character and backs up + self.typedText = self.typedText[:-1] + + if not self.typedText: + self.SetSelection(0) + else: + item = self.FindPrefix(self.typedText) + + if item != -1: + self.SetSelection(item) + else: + self.typedText = '' + evt.Skip() + + def OnKeyDown(self, evt): + pass + + +#--------------------------------------------------------------------------- + +class TestListBox(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', + 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', + 'twelve', 'thirteen', 'fourteen'] + + wx.StaticText(self, -1, "This example uses the wx.ListBox control.", (45, 10)) + wx.StaticText(self, -1, "Select one:", (15, 50)) + self.lb1 = wx.ListBox(self, 60, (100, 50), (90, 120), sampleList, wx.LB_SINGLE) + self.Bind(wx.EVT_LISTBOX, self.EvtListBox, self.lb1) + self.Bind(wx.EVT_LISTBOX_DCLICK, self.EvtListBoxDClick, self.lb1) + self.lb1.Bind(wx.EVT_RIGHT_UP, self.EvtRightButton) + self.lb1.SetSelection(3) + self.lb1.Append("with data", "This one has data"); + self.lb1.SetClientData(2, "This one has data"); + + + wx.StaticText(self, -1, "Select many:", (220, 50)) + self.lb2 = wx.ListBox(self, 70, (320, 50), (90, 120), sampleList, wx.LB_EXTENDED) + self.Bind(wx.EVT_LISTBOX, self.EvtMultiListBox, self.lb2) + self.lb2.Bind(wx.EVT_RIGHT_UP, self.EvtRightButton) + self.lb2.SetSelection(0) + + sampleList = sampleList + ['test a', 'test aa', 'test aab', + 'test ab', 'test abc', 'test abcc', + 'test abcd' ] + sampleList.sort() + wx.StaticText(self, -1, "Find Prefix:", (15, 250)) + fp = FindPrefixListBox(self, -1, (100, 250), (90, 120), sampleList, wx.LB_SINGLE) + fp.SetSelection(0) + + + def EvtListBox(self, event): + self.log.WriteText('EvtListBox: %s, %s, %s, %s\n' % + (event.GetString(), + event.IsSelection(), + event.GetSelection(), + event.GetClientData())) + + lb = event.GetEventObject() + data = lb.GetClientData(lb.GetSelection()) + + if data is not None: + self.log.WriteText('\tdata: %s\n' % data) + + + def EvtListBoxDClick(self, event): + self.log.WriteText('EvtListBoxDClick: %s\n' % self.lb1.GetSelection()) + self.lb1.Delete(self.lb1.GetSelection()) + + def EvtMultiListBox(self, event): + self.log.WriteText('EvtMultiListBox: %s\n' % str(self.lb2.GetSelections())) + + def EvtRightButton(self, event): + self.log.WriteText('EvtRightButton: %s\n' % event.GetPosition()) + + if event.GetEventObject().GetId() == 70: + selections = list(self.lb2.GetSelections()) + selections.reverse() + + for index in selections: + self.lb2.Delete(index) + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestListBox(nb, log) + return win + +#--------------------------------------------------------------------------- + + + + +overview = """ +A listbox is used to select one or more of a list of +strings. The strings are displayed in a scrolling box, with the +selected string(s) marked in reverse video. A listbox can be single +selection (if an item is selected, the previous selection is removed) +or multiple selection (clicking an item toggles the item on or off +independently of other selections). + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ListCtrl.py b/demo/ListCtrl.py new file mode 100644 index 00000000..7ad06c1d --- /dev/null +++ b/demo/ListCtrl.py @@ -0,0 +1,513 @@ +#---------------------------------------------------------------------------- +# Name: ListCtrl.py +# Purpose: Testing lots of stuff, controls, window types, etc. +# +# Author: Robin Dunn & Gary Dumer +# +# Created: +# RCS-ID: $Id$ +# Copyright: (c) 1998 by Total Control Software +# Licence: wxWindows license +#---------------------------------------------------------------------------- + +import sys +import wx +import wx.lib.mixins.listctrl as listmix + +import images + +#--------------------------------------------------------------------------- + +musicdata = { +1 : ("Bad English", "The Price Of Love", "Rock"), +2 : ("DNA featuring Suzanne Vega", "Tom's Diner", "Rock"), +3 : ("George Michael", "Praying For Time", "Rock"), +4 : ("Gloria Estefan", "Here We Are", "Rock"), +5 : ("Linda Ronstadt", "Don't Know Much", "Rock"), +6 : ("Michael Bolton", "How Am I Supposed To Live Without You", "Blues"), +7 : ("Paul Young", "Oh Girl", "Rock"), +8 : ("Paula Abdul", "Opposites Attract", "Rock"), +9 : ("Richard Marx", "Should've Known Better", "Rock"), +10: ("Rod Stewart", "Forever Young", "Rock"), +11: ("Roxette", "Dangerous", "Rock"), +12: ("Sheena Easton", "The Lover In Me", "Rock"), +13: ("Sinead O'Connor", "Nothing Compares 2 U", "Rock"), +14: ("Stevie B.", "Because I Love You", "Rock"), +15: ("Taylor Dayne", "Love Will Lead You Back", "Rock"), +16: ("The Bangles", "Eternal Flame", "Rock"), +17: ("Wilson Phillips", "Release Me", "Rock"), +18: ("Billy Joel", "Blonde Over Blue", "Rock"), +19: ("Billy Joel", "Famous Last Words", "Rock"), +20: ("Janet Jackson", "State Of The World", "Rock"), +21: ("Janet Jackson", "The Knowledge", "Rock"), +22: ("Spyro Gyra", "End of Romanticism", "Jazz"), +23: ("Spyro Gyra", "Heliopolis", "Jazz"), +24: ("Spyro Gyra", "Jubilee", "Jazz"), +25: ("Spyro Gyra", "Little Linda", "Jazz"), +26: ("Spyro Gyra", "Morning Dance", "Jazz"), +27: ("Spyro Gyra", "Song for Lorraine", "Jazz"), +28: ("Yes", "Owner Of A Lonely Heart", "Rock"), +29: ("Yes", "Rhythm Of Love", "Rock"), +30: ("Billy Joel", "Lullabye (Goodnight, My Angel)", "Rock"), +31: ("Billy Joel", "The River Of Dreams", "Rock"), +32: ("Billy Joel", "Two Thousand Years", "Rock"), +33: ("Janet Jackson", "Alright", "Rock"), +34: ("Janet Jackson", "Black Cat", "Rock"), +35: ("Janet Jackson", "Come Back To Me", "Rock"), +36: ("Janet Jackson", "Escapade", "Rock"), +37: ("Janet Jackson", "Love Will Never Do (Without You)", "Rock"), +38: ("Janet Jackson", "Miss You Much", "Rock"), +39: ("Janet Jackson", "Rhythm Nation", "Rock"), +40: ("Cusco", "Dream Catcher", "New Age"), +41: ("Cusco", "Geronimos Laughter", "New Age"), +42: ("Cusco", "Ghost Dance", "New Age"), +43: ("Blue Man Group", "Drumbone", "New Age"), +44: ("Blue Man Group", "Endless Column", "New Age"), +45: ("Blue Man Group", "Klein Mandelbrot", "New Age"), +46: ("Kenny G", "Silhouette", "Jazz"), +47: ("Sade", "Smooth Operator", "Jazz"), +48: ("David Arkenstone", "Papillon (On The Wings Of The Butterfly)", "New Age"), +49: ("David Arkenstone", "Stepping Stars", "New Age"), +50: ("David Arkenstone", "Carnation Lily Lily Rose", "New Age"), +51: ("David Lanz", "Behind The Waterfall", "New Age"), +52: ("David Lanz", "Cristofori's Dream", "New Age"), +53: ("David Lanz", "Heartsounds", "New Age"), +54: ("David Lanz", "Leaves on the Seine", "New Age"), +} + +#--------------------------------------------------------------------------- + +class TestListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): + def __init__(self, parent, ID, pos=wx.DefaultPosition, + size=wx.DefaultSize, style=0): + wx.ListCtrl.__init__(self, parent, ID, pos, size, style) + listmix.ListCtrlAutoWidthMixin.__init__(self) + + +class TestListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS) + + self.log = log + tID = wx.NewId() + + sizer = wx.BoxSizer(wx.VERTICAL) + + if wx.Platform == "__WXMAC__" and \ + hasattr(wx.GetApp().GetTopWindow(), "LoadDemo"): + self.useNative = wx.CheckBox(self, -1, "Use native listctrl") + self.useNative.SetValue( + not wx.SystemOptions.GetOptionInt("mac.listctrl.always_use_generic") ) + self.Bind(wx.EVT_CHECKBOX, self.OnUseNative, self.useNative) + sizer.Add(self.useNative, 0, wx.ALL | wx.ALIGN_RIGHT, 4) + + self.il = wx.ImageList(16, 16) + + self.idx1 = self.il.Add(images.Smiles.GetBitmap()) + self.sm_up = self.il.Add(images.SmallUpArrow.GetBitmap()) + self.sm_dn = self.il.Add(images.SmallDnArrow.GetBitmap()) + + self.list = TestListCtrl(self, tID, + style=wx.LC_REPORT + #| wx.BORDER_SUNKEN + | wx.BORDER_NONE + | wx.LC_EDIT_LABELS + | wx.LC_SORT_ASCENDING + #| wx.LC_NO_HEADER + #| wx.LC_VRULES + #| wx.LC_HRULES + #| wx.LC_SINGLE_SEL + ) + + self.list.SetImageList(self.il, wx.IMAGE_LIST_SMALL) + sizer.Add(self.list, 1, wx.EXPAND) + + self.PopulateList() + + # Now that the list exists we can init the other base class, + # see wx/lib/mixins/listctrl.py + self.itemDataMap = musicdata + listmix.ColumnSorterMixin.__init__(self, 3) + #self.SortListItems(0, True) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list) + self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self.list) + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self.list) + self.Bind(wx.EVT_LIST_DELETE_ITEM, self.OnItemDelete, self.list) + self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list) + self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColRightClick, self.list) + self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, self.list) + self.Bind(wx.EVT_LIST_COL_DRAGGING, self.OnColDragging, self.list) + self.Bind(wx.EVT_LIST_COL_END_DRAG, self.OnColEndDrag, self.list) + self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list) + + self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) + self.list.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) + + # for wxMSW + self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightClick) + + # for wxGTK + self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightClick) + + + def OnUseNative(self, event): + wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", not event.IsChecked()) + wx.GetApp().GetTopWindow().LoadDemo("ListCtrl") + + def PopulateList(self): + if 0: + # for normal, simple columns, you can add them like this: + self.list.InsertColumn(0, "Artist") + self.list.InsertColumn(1, "Title", wx.LIST_FORMAT_RIGHT) + self.list.InsertColumn(2, "Genre") + else: + # but since we want images on the column header we have to do it the hard way: + info = wx.ListItem() + info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT + info.m_image = -1 + info.m_format = 0 + info.m_text = "Artist" + self.list.InsertColumnInfo(0, info) + + info.m_format = wx.LIST_FORMAT_RIGHT + info.m_text = "Title" + self.list.InsertColumnInfo(1, info) + + info.m_format = 0 + info.m_text = "Genre" + self.list.InsertColumnInfo(2, info) + + items = musicdata.items() + for key, data in items: + index = self.list.InsertImageStringItem(sys.maxint, data[0], self.idx1) + self.list.SetStringItem(index, 1, data[1]) + self.list.SetStringItem(index, 2, data[2]) + self.list.SetItemData(index, key) + + self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(2, 100) + + # show how to select an item + self.list.SetItemState(5, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) + + # show how to change the colour of a couple items + item = self.list.GetItem(1) + item.SetTextColour(wx.BLUE) + self.list.SetItem(item) + item = self.list.GetItem(4) + item.SetTextColour(wx.RED) + self.list.SetItem(item) + + self.currentItem = 0 + + + # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py + def GetListCtrl(self): + return self.list + + # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py + def GetSortImages(self): + return (self.sm_dn, self.sm_up) + + + def OnRightDown(self, event): + x = event.GetX() + y = event.GetY() + self.log.WriteText("x, y = %s\n" % str((x, y))) + item, flags = self.list.HitTest((x, y)) + + if item != wx.NOT_FOUND and flags & wx.LIST_HITTEST_ONITEM: + self.list.Select(item) + + event.Skip() + + + def getColumnText(self, index, col): + item = self.list.GetItem(index, col) + return item.GetText() + + + def OnItemSelected(self, event): + ##print event.GetItem().GetTextColour() + self.currentItem = event.m_itemIndex + self.log.WriteText("OnItemSelected: %s, %s, %s, %s\n" % + (self.currentItem, + self.list.GetItemText(self.currentItem), + self.getColumnText(self.currentItem, 1), + self.getColumnText(self.currentItem, 2))) + + if self.currentItem == 10: + self.log.WriteText("OnItemSelected: Veto'd selection\n") + #event.Veto() # doesn't work + # this does + self.list.SetItemState(10, 0, wx.LIST_STATE_SELECTED) + + event.Skip() + + + def OnItemDeselected(self, evt): + item = evt.GetItem() + self.log.WriteText("OnItemDeselected: %d" % evt.m_itemIndex) + + # Show how to reselect something we don't want deselected + if evt.m_itemIndex == 11: + wx.CallAfter(self.list.SetItemState, 11, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) + + + def OnItemActivated(self, event): + self.currentItem = event.m_itemIndex + self.log.WriteText("OnItemActivated: %s\nTopItem: %s" % + (self.list.GetItemText(self.currentItem), self.list.GetTopItem())) + + def OnBeginEdit(self, event): + self.log.WriteText("OnBeginEdit") + event.Allow() + + def OnItemDelete(self, event): + self.log.WriteText("OnItemDelete\n") + + def OnColClick(self, event): + self.log.WriteText("OnColClick: %d\n" % event.GetColumn()) + event.Skip() + + def OnColRightClick(self, event): + item = self.list.GetColumn(event.GetColumn()) + self.log.WriteText("OnColRightClick: %d %s\n" % + (event.GetColumn(), (item.GetText(), item.GetAlign(), + item.GetWidth(), item.GetImage()))) + if self.list.HasColumnOrderSupport(): + self.log.WriteText("OnColRightClick: column order: %d\n" % + self.list.GetColumnOrder(event.GetColumn())) + + def OnColBeginDrag(self, event): + self.log.WriteText("OnColBeginDrag\n") + ## Show how to not allow a column to be resized + #if event.GetColumn() == 0: + # event.Veto() + + + def OnColDragging(self, event): + self.log.WriteText("OnColDragging\n") + + def OnColEndDrag(self, event): + self.log.WriteText("OnColEndDrag\n") + + def OnDoubleClick(self, event): + self.log.WriteText("OnDoubleClick item %s\n" % self.list.GetItemText(self.currentItem)) + event.Skip() + + def OnRightClick(self, event): + self.log.WriteText("OnRightClick %s\n" % self.list.GetItemText(self.currentItem)) + + # only do this part the first time so the events are only bound once + if not hasattr(self, "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + self.popupID4 = wx.NewId() + self.popupID5 = wx.NewId() + self.popupID6 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + self.Bind(wx.EVT_MENU, self.OnPopupFour, id=self.popupID4) + self.Bind(wx.EVT_MENU, self.OnPopupFive, id=self.popupID5) + self.Bind(wx.EVT_MENU, self.OnPopupSix, id=self.popupID6) + + # make a menu + menu = wx.Menu() + # add some items + menu.Append(self.popupID1, "FindItem tests") + menu.Append(self.popupID2, "Iterate Selected") + menu.Append(self.popupID3, "ClearAll and repopulate") + menu.Append(self.popupID4, "DeleteAllItems") + menu.Append(self.popupID5, "GetItem") + menu.Append(self.popupID6, "Edit") + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + self.PopupMenu(menu) + menu.Destroy() + + + def OnPopupOne(self, event): + self.log.WriteText("Popup one\n") + print "FindItem:", self.list.FindItem(-1, "Roxette") + print "FindItemData:", self.list.FindItemData(-1, 11) + + def OnPopupTwo(self, event): + self.log.WriteText("Selected items:\n") + index = self.list.GetFirstSelected() + + while index != -1: + self.log.WriteText(" %s: %s\n" % (self.list.GetItemText(index), self.getColumnText(index, 1))) + index = self.list.GetNextSelected(index) + + def OnPopupThree(self, event): + self.log.WriteText("Popup three\n") + self.list.ClearAll() + wx.CallAfter(self.PopulateList) + + def OnPopupFour(self, event): + self.list.DeleteAllItems() + + def OnPopupFive(self, event): + item = self.list.GetItem(self.currentItem) + print item.m_text, item.m_itemId, self.list.GetItemData(self.currentItem) + + def OnPopupSix(self, event): + self.list.EditLabel(self.currentItem) + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestListCtrlPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ + + +A list control presents lists in a number of formats: list view, report view, +icon view and small icon view. In any case, elements are numbered from zero. +For all these modes (but not for virtual list controls), the items are stored +in the control and must be added to it using InsertItem method. + +

To intercept events from a list control, use the event table macros described in +wxListEvent. + +

Mix-ins

+This example demonstrates how to use mixins. The following mixins are available. + +

ColumnSorterMixin

+ +ColumnSorterMixin(numColumns) + +

A mixin class that handles sorting of a wxListCtrl in REPORT mode when the column +header is clicked on. + +

There are a few requirments needed in order for this to work genericly: +

    +
  1. The combined class must have a GetListCtrl method that returns + the ListCtrl to be sorted, and the list control must exist at the time the + ColumnSorterMixin.__init__()method is called because it uses + GetListCtrl. + +
  2. Items in the list control must have a unique data value set with + list.SetItemData. + +
  3. The combined class must have an attribute named itemDataMap + that is a dictionary mapping the data values to a sequence of objects + representing the values in each column. These valuesare compared in + the column sorter to determine sort order. +
+ +

Interesting methods to override are GetColumnSorter, +GetSecondarySortValues, and GetSortImages. + +

Methods
+
+
SetColumnCount(newNumColumns) +
Informs the mixin as to the number of columns in the control. When it is +set, it also sets up an event handler for EVT_LIST_COL_CLICK events. + +
SortListItems(col=-1, ascending=1) +
Sort the list on demand. Can also be used to set the sort column and order. + +
GetColumnWidths() +
Returns a list of column widths. Can be used to help restore the current +view later. + +
GetSortImages() +
Returns a tuple of image list indexes the indexes in the image list for an +image to be put on the column header when sorting in descending order + +
GetColumnSorter() +
Returns a callable object to be used for comparing column values when sorting. + +
GetSecondarySortValues(col, key1, key2) +
Returns a tuple of 2 values to use for secondary sort values when the +items in the selected column match equal. The default just returns the +item data values. + +
+ +

ListCtrlAutoWidthMixin

+ +ListCtrlAutoWidthMixin() + +

A mix-in class that automatically resizes the last column to take up the +remaining width of the ListCtrl. + +

This causes the ListCtrl to automatically take up the full width of the list, +without either a horizontal scroll bar (unless absolutely necessary) or empty +space to the right of the last column. + +

NOTE: This only works for report-style lists. + +

WARNING: If you override the EVT_SIZE event in your ListCtrl, +make sure you call event.Skip() to ensure that the mixin's _OnResize method is +called. + +

This mix-in class was written by Erik Westra + +

Methods
+
+ +
resizeLastColumn(minWidth) +
Resize the last column appropriately. If the list's columns are too wide to +fit within the window, we use a horizontal scrollbar. Otherwise, we expand the +right-most column to take up the remaining free space in the list. This method is +called automatically when the ListCtrl is resized; you can also call it yourself +whenever you want the last column to be resized appropriately (eg, when adding, +removing or resizing columns). 'minWidth' is the preferred minimum width for +the last column. + +
+ + +

ListCtrlSelectionManagerMix

+ +ListCtrlSelectionManagerMix() + +

Mixin that defines a platform independent selection policy + +

As selection single and multi-select list return the item index or a +list of item indexes respectively. + +

Methods
+
+ +
getPopupMenu() +
Override to implement dynamic menus (create) + +
setPopupMenu(menu) +
Must be set for default behaviour. + +
afterPopupMenu() +
Override to implement dynamic menus (destroy). + +
getSelection() +
Returns the current selection (or selections as a Python list if extended +selection is enabled) + + + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ListCtrl_edit.py b/demo/ListCtrl_edit.py new file mode 100644 index 00000000..f352931e --- /dev/null +++ b/demo/ListCtrl_edit.py @@ -0,0 +1,152 @@ +#---------------------------------------------------------------------------- +# Name: ListCtrl_edit.py +# Purpose: Testing editing a ListCtrl +# +# Author: Pim van Heuven +# +# Created: 2004/10/15 +# Copyright: (c) Pim Van Heuven +# Licence: wxWindows license +#---------------------------------------------------------------------------- + +import sys +import wx +import wx.lib.mixins.listctrl as listmix + +#--------------------------------------------------------------------------- + +listctrldata = { +1 : ("Hey!", "You can edit", "me!"), +2 : ("Try changing the contents", "by", "clicking"), +3 : ("in", "a", "cell"), +4 : ("See how the length columns", "change", "?"), +5 : ("You can use", "TAB,", "cursor down,"), +6 : ("and cursor up", "to", "navigate"), +} + +#--------------------------------------------------------------------------- + +class TestListCtrl(wx.ListCtrl, + listmix.ListCtrlAutoWidthMixin, + listmix.TextEditMixin): + + def __init__(self, parent, ID, pos=wx.DefaultPosition, + size=wx.DefaultSize, style=0): + wx.ListCtrl.__init__(self, parent, ID, pos, size, style) + + listmix.ListCtrlAutoWidthMixin.__init__(self) + self.Populate() + listmix.TextEditMixin.__init__(self) + + def Populate(self): + # for normal, simple columns, you can add them like this: + self.InsertColumn(0, "Column 1") + self.InsertColumn(1, "Column 2") + self.InsertColumn(2, "Column 3") + self.InsertColumn(3, "Len 1", wx.LIST_FORMAT_RIGHT) + self.InsertColumn(4, "Len 2", wx.LIST_FORMAT_RIGHT) + self.InsertColumn(5, "Len 3", wx.LIST_FORMAT_RIGHT) + + items = listctrldata.items() + for key, data in items: + index = self.InsertStringItem(sys.maxint, data[0]) + self.SetStringItem(index, 1, data[1]) + self.SetStringItem(index, 2, data[2]) + self.SetItemData(index, key) + + self.SetColumnWidth(0, wx.LIST_AUTOSIZE) + self.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.SetColumnWidth(2, 100) + + self.currentItem = 0 + + + def SetStringItem(self, index, col, data): + if col in range(3): + wx.ListCtrl.SetStringItem(self, index, col, data) + wx.ListCtrl.SetStringItem(self, index, 3+col, str(len(data))) + else: + try: + datalen = int(data) + except: + return + + wx.ListCtrl.SetStringItem(self, index, col, data) + + data = self.GetItem(index, col-3).GetText() + wx.ListCtrl.SetStringItem(self, index, col-3, data[0:datalen]) + + + + +class TestListCtrlPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS) + + self.log = log + tID = wx.NewId() + + sizer = wx.BoxSizer(wx.VERTICAL) + + if wx.Platform == "__WXMAC__" and \ + hasattr(wx.GetApp().GetTopWindow(), "LoadDemo"): + self.useNative = wx.CheckBox(self, -1, "Use native listctrl") + self.useNative.SetValue( + not wx.SystemOptions.GetOptionInt("mac.listctrl.always_use_generic") ) + self.Bind(wx.EVT_CHECKBOX, self.OnUseNative, self.useNative) + sizer.Add(self.useNative, 0, wx.ALL | wx.ALIGN_RIGHT, 4) + + self.list = TestListCtrl(self, tID, + style=wx.LC_REPORT + | wx.BORDER_NONE + | wx.LC_SORT_ASCENDING + ) + + sizer.Add(self.list, 1, wx.EXPAND) + self.SetSizer(sizer) + self.SetAutoLayout(True) + + + def OnUseNative(self, event): + wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", not event.IsChecked()) + wx.GetApp().GetTopWindow().LoadDemo("ListCtrl_edit") + + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestListCtrlPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ + + + +This demo demonstrates direct editing of all cells of a ListCtrl. To +enable it just include the TextEditMixin. The ListCtrl can be +navigated with the TAB and up/down cursor keys. + +

Another facet of this demo is that the remaining space of the +ListCtrls is divided over the first three columns. This is achieved +with the extended syntax of ListCtrlAutoWidthMixin: +listmix.ListCtrlAutoWidthMixin.__init__(self, startcol, endcol) +(Look at the general ListCtrl demo for more information about the +ListCtrlAutoWidthMixin) + +

Finally, the ListCtrl is automatically scrolled, if needed, when +TAB is pressed consecutively (Windows only). + + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ListCtrl_virtual.py b/demo/ListCtrl_virtual.py new file mode 100644 index 00000000..ff211aa2 --- /dev/null +++ b/demo/ListCtrl_virtual.py @@ -0,0 +1,145 @@ + +import wx +import images + +#---------------------------------------------------------------------- + +class TestVirtualList(wx.ListCtrl): + def __init__(self, parent, log): + wx.ListCtrl.__init__( + self, parent, -1, + style=wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES + ) + + self.log = log + + self.il = wx.ImageList(16, 16) + self.idx1 = self.il.Add(images.Smiles.GetBitmap()) + empty = self.makeBlank() + self.idx2 = self.il.Add(empty) + self.SetImageList(self.il, wx.IMAGE_LIST_SMALL) + + + self.InsertColumn(0, "First") + self.InsertColumn(1, "Second") + self.InsertColumn(2, "Third") + self.SetColumnWidth(0, 175) + self.SetColumnWidth(1, 175) + self.SetColumnWidth(2, 175) + + self.SetItemCount(1000000) + + self.attr1 = wx.ListItemAttr() + self.attr1.SetBackgroundColour("yellow") + + self.attr2 = wx.ListItemAttr() + self.attr2.SetBackgroundColour("light blue") + + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated) + self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected) + + + def makeBlank(self): + empty = wx.EmptyBitmap(16,16,32) + dc = wx.MemoryDC(empty) + dc.SetBackground(wx.Brush((0,0,0,0))) + dc.Clear() + del dc + empty.SetMaskColour((0,0,0)) + return empty + + + def OnItemSelected(self, event): + self.currentItem = event.m_itemIndex + self.log.WriteText('OnItemSelected: "%s", "%s", "%s", "%s"\n' % + (self.currentItem, + self.GetItemText(self.currentItem), + self.getColumnText(self.currentItem, 1), + self.getColumnText(self.currentItem, 2))) + + def OnItemActivated(self, event): + self.currentItem = event.m_itemIndex + self.log.WriteText("OnItemActivated: %s\nTopItem: %s\n" % + (self.GetItemText(self.currentItem), self.GetTopItem())) + + def getColumnText(self, index, col): + item = self.GetItem(index, col) + return item.GetText() + + def OnItemDeselected(self, evt): + self.log.WriteText("OnItemDeselected: %s" % evt.m_itemIndex) + + + #----------------------------------------------------------------- + # These methods are callbacks for implementing the "virtualness" + # of the list... Normally you would determine the text, + # attributes and/or image based on values from some external data + # source, but for this demo we'll just calculate them + def OnGetItemText(self, item, col): + return "Item %d, column %d" % (item, col) + + def OnGetItemImage(self, item): + if item % 3 == 0: + return self.idx1 + else: + return self.idx2 + + def OnGetItemAttr(self, item): + if item % 3 == 1: + return self.attr1 + elif item % 3 == 2: + return self.attr2 + else: + return None + + +class TestVirtualListPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS) + + self.log = log + sizer = wx.BoxSizer(wx.VERTICAL) + + if wx.Platform == "__WXMAC__" and \ + hasattr(wx.GetApp().GetTopWindow(), "LoadDemo"): + self.useNative = wx.CheckBox(self, -1, "Use native listctrl") + self.useNative.SetValue( + not wx.SystemOptions.GetOptionInt("mac.listctrl.always_use_generic") ) + self.Bind(wx.EVT_CHECKBOX, self.OnUseNative, self.useNative) + sizer.Add(self.useNative, 0, wx.ALL | wx.ALIGN_RIGHT, 4) + + self.list = TestVirtualList(self, self.log) + sizer.Add(self.list, 1, wx.EXPAND) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + def OnUseNative(self, event): + wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", not event.IsChecked()) + wx.GetApp().GetTopWindow().LoadDemo("ListCtrl_virtual") + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestVirtualListPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ +This example demonstrates the ListCtrl's Virtual List features. A Virtual list +can contain any number of cells, but data is not loaded into the control itself. +It is loaded on demand via virtual methods OnGetItemText(), OnGetItemImage(), +and OnGetItemAttr(). This greatly reduces the amount of memory required +without limiting what can be done with the list control itself. +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Listbook.py b/demo/Listbook.py new file mode 100644 index 00000000..f5840e56 --- /dev/null +++ b/demo/Listbook.py @@ -0,0 +1,103 @@ + +import wx + +import ColorPanel +import images + +colourList = [ "Aquamarine", "Black", "Blue", "Blue Violet", "Brown", "Cadet Blue", + "Coral", "Cornflower Blue", "Cyan", "Dark Grey", "Dark Green", + "Dark Olive Green", + ] + +#---------------------------------------------------------------------------- + +class TestLB(wx.Listbook): + def __init__(self, parent, id, log): + wx.Listbook.__init__(self, parent, id, style= + wx.BK_DEFAULT + #wx.BK_TOP + #wx.BK_BOTTOM + #wx.BK_LEFT + #wx.BK_RIGHT + ) + self.log = log + + # make an image list using the LBXX images + il = wx.ImageList(32, 32) + for x in range(12): + obj = getattr(images, 'LB%02d' % (x+1)) + bmp = obj.GetBitmap() + il.Add(bmp) + self.AssignImageList(il) + + # Now make a bunch of panels for the list book + first = True + imID = 0 + for colour in colourList: + win = self.makeColorPanel(colour) + self.AddPage(win, colour, imageId=imID) + imID += 1 + if imID == il.GetImageCount(): imID = 0 + if first: + st = wx.StaticText(win.win, -1, + "You can put nearly any type of window here,\n" + "and the list can be on any side of the Listbook", + wx.Point(10, 10)) + first = False + + self.Bind(wx.EVT_LISTBOOK_PAGE_CHANGED, self.OnPageChanged) + self.Bind(wx.EVT_LISTBOOK_PAGE_CHANGING, self.OnPageChanging) + + + def makeColorPanel(self, color): + p = wx.Panel(self, -1) + win = ColorPanel.ColoredPanel(p, color) + p.win = win + def OnCPSize(evt, win=win): + win.SetPosition((0,0)) + win.SetSize(evt.GetSize()) + p.Bind(wx.EVT_SIZE, OnCPSize) + return p + + + def OnPageChanged(self, event): + old = event.GetOldSelection() + new = event.GetSelection() + sel = self.GetSelection() + self.log.write('OnPageChanged, old:%d, new:%d, sel:%d\n' % (old, new, sel)) + event.Skip() + + def OnPageChanging(self, event): + old = event.GetOldSelection() + new = event.GetSelection() + sel = self.GetSelection() + self.log.write('OnPageChanging, old:%d, new:%d, sel:%d\n' % (old, new, sel)) + event.Skip() + +#---------------------------------------------------------------------------- + +def runTest(frame, nb, log): + testWin = TestLB(nb, -1, log) + return testWin + +#---------------------------------------------------------------------------- + + +overview = """\ + +

wx.Listbook

+

+This class is a control similar to a notebook control, but with a +wx.ListCtrl instead of a set of tabs. + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + diff --git a/demo/MDIDemo.py b/demo/MDIDemo.py new file mode 100644 index 00000000..d884f114 --- /dev/null +++ b/demo/MDIDemo.py @@ -0,0 +1,87 @@ + +import wx + +# Importing ScrolledWindow demo to make use of the MyCanvas +# class defined within. +import ScrolledWindow +import images + +SHOW_BACKGROUND = 1 + +#---------------------------------------------------------------------- +ID_New = wx.NewId() +ID_Exit = wx.NewId() +#---------------------------------------------------------------------- + +class MyParentFrame(wx.MDIParentFrame): + def __init__(self): + wx.MDIParentFrame.__init__(self, None, -1, "MDI Parent", size=(600,400)) + + self.winCount = 0 + menu = wx.Menu() + menu.Append(ID_New, "&New Window") + menu.AppendSeparator() + menu.Append(ID_Exit, "E&xit") + + menubar = wx.MenuBar() + menubar.Append(menu, "&File") + self.SetMenuBar(menubar) + + self.CreateStatusBar() + + self.Bind(wx.EVT_MENU, self.OnNewWindow, id=ID_New) + self.Bind(wx.EVT_MENU, self.OnExit, id=ID_Exit) + + if SHOW_BACKGROUND: + self.bg_bmp = images.GridBG.GetBitmap() + self.GetClientWindow().Bind( + wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground + ) + + + def OnExit(self, evt): + self.Close(True) + + + def OnNewWindow(self, evt): + self.winCount = self.winCount + 1 + win = wx.MDIChildFrame(self, -1, "Child Window: %d" % self.winCount) + canvas = ScrolledWindow.MyCanvas(win) + win.Show(True) + + + def OnEraseBackground(self, evt): + dc = evt.GetDC() + + # tile the background bitmap + sz = self.GetClientSize() + w = self.bg_bmp.GetWidth() + h = self.bg_bmp.GetHeight() + x = 0 + + while x < sz.width: + y = 0 + + while y < sz.height: + dc.DrawBitmap(self.bg_bmp, x, y) + y = y + h + + x = x + w + + +#---------------------------------------------------------------------- + +if __name__ == '__main__': + class MyApp(wx.App): + def OnInit(self): + frame = MyParentFrame() + frame.Show(True) + self.SetTopWindow(frame) + return True + + + app = MyApp(False) + app.MainLoop() + + + diff --git a/demo/MDISashDemo.py b/demo/MDISashDemo.py new file mode 100644 index 00000000..ad7b3261 --- /dev/null +++ b/demo/MDISashDemo.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python + +import wx + +import ScrolledWindow + +#---------------------------------------------------------------------- +# There are better ways to do IDs, but this demo requires that the window +# IDs be in a specific range. There are better ways to do that, too, but +# this will do for purposes of this demo. + +ID_Menu_New = 5004 +ID_Menu_Exit = 5005 + +ID_WINDOW_TOP = 5000 +ID_WINDOW_LEFT1 = 5001 +ID_WINDOW_LEFT2 = 5002 +ID_WINDOW_BOTTOM = 5003 + +#---------------------------------------------------------------------- + +class MyParentFrame(wx.MDIParentFrame): + def __init__(self): + wx.MDIParentFrame.__init__( + self, None, -1, "MDI Parent", size=(600,400), + style = wx.DEFAULT_FRAME_STYLE | wx.HSCROLL | wx.VSCROLL + ) + + self.winCount = 0 + menu = wx.Menu() + menu.Append(ID_Menu_New, "&New Window") + menu.AppendSeparator() + menu.Append(ID_Menu_Exit, "E&xit") + + menubar = wx.MenuBar() + menubar.Append(menu, "&File") + self.SetMenuBar(menubar) + + #self.CreateStatusBar() + + self.Bind(wx.EVT_MENU, self.OnNewWindow, id=ID_Menu_New) + self.Bind(wx.EVT_MENU, self.OnExit, id=ID_Menu_Exit) + + self.Bind( + wx.EVT_SASH_DRAGGED_RANGE, self.OnSashDrag, id=ID_WINDOW_TOP, + id2=ID_WINDOW_BOTTOM + ) + + self.Bind(wx.EVT_SIZE, self.OnSize) + + + # Create some layout windows + # A window like a toolbar + win = wx.SashLayoutWindow(self, ID_WINDOW_TOP, style=wx.NO_BORDER|wx.SW_3D) + win.SetDefaultSize((1000, 30)) + win.SetOrientation(wx.LAYOUT_HORIZONTAL) + win.SetAlignment(wx.LAYOUT_TOP) + win.SetBackgroundColour(wx.Colour(255, 0, 0)) + win.SetSashVisible(wx.SASH_BOTTOM, True) + + self.topWindow = win + + + # A window like a statusbar + win = wx.SashLayoutWindow(self, ID_WINDOW_BOTTOM, style=wx.NO_BORDER|wx.SW_3D) + win.SetDefaultSize((1000, 30)) + win.SetOrientation(wx.LAYOUT_HORIZONTAL) + win.SetAlignment(wx.LAYOUT_BOTTOM) + win.SetBackgroundColour(wx.Colour(0, 0, 255)) + win.SetSashVisible(wx.SASH_TOP, True) + + self.bottomWindow = win + + + # A window to the left of the client window + win = wx.SashLayoutWindow(self, ID_WINDOW_LEFT1, style=wx.NO_BORDER|wx.SW_3D) + win.SetDefaultSize((120, 1000)) + win.SetOrientation(wx.LAYOUT_VERTICAL) + win.SetAlignment(wx.LAYOUT_LEFT) + win.SetBackgroundColour(wx.Colour(0, 255, 0)) + win.SetSashVisible(wx.SASH_RIGHT, True) + win.SetExtraBorderSize(10) + textWindow = wx.TextCtrl(win, -1, "", style=wx.TE_MULTILINE|wx.SUNKEN_BORDER) + textWindow.SetValue("A sub window") + + self.leftWindow1 = win + + + # Another window to the left of the client window + win = wx.SashLayoutWindow(self, ID_WINDOW_LEFT2, style=wx.NO_BORDER|wx.SW_3D) + win.SetDefaultSize((120, 1000)) + win.SetOrientation(wx.LAYOUT_VERTICAL) + win.SetAlignment(wx.LAYOUT_LEFT) + win.SetBackgroundColour(wx.Colour(0, 255, 255)) + win.SetSashVisible(wx.SASH_RIGHT, True) + + self.leftWindow2 = win + + + def OnSashDrag(self, event): + if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE: + return + + eID = event.GetId() + + if eID == ID_WINDOW_TOP: + self.topWindow.SetDefaultSize((1000, event.GetDragRect().height)) + + elif eID == ID_WINDOW_LEFT1: + self.leftWindow1.SetDefaultSize((event.GetDragRect().width, 1000)) + + elif eID == ID_WINDOW_LEFT2: + self.leftWindow2.SetDefaultSize((event.GetDragRect().width, 1000)) + + elif eID == ID_WINDOW_BOTTOM: + self.bottomWindow.SetDefaultSize((1000, event.GetDragRect().height)) + + wx.LayoutAlgorithm().LayoutMDIFrame(self) + self.GetClientWindow().Refresh() + + + def OnSize(self, event): + wx.LayoutAlgorithm().LayoutMDIFrame(self) + + + def OnExit(self, evt): + self.Close(True) + + + def OnNewWindow(self, evt): + self.winCount = self.winCount + 1 + win = wx.MDIChildFrame(self, -1, "Child Window: %d" % self.winCount) + canvas = ScrolledWindow.MyCanvas(win) + win.Show(True) + + +#---------------------------------------------------------------------- + +if __name__ == '__main__': + class MyApp(wx.App): + def OnInit(self): + frame = MyParentFrame() + frame.Show(True) + self.SetTopWindow(frame) + return True + + app = MyApp(False) + app.MainLoop() + + + diff --git a/demo/MDIWindows.py b/demo/MDIWindows.py new file mode 100644 index 00000000..4fa3ad01 --- /dev/null +++ b/demo/MDIWindows.py @@ -0,0 +1,78 @@ + +import wx +import os +import sys + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b1 = wx.Button(self, -1, "MDI demo") + self.Bind(wx.EVT_BUTTON, self.ShowMDIDemo, b1) + + b2 = wx.Button(self, -1, "MDI with SashWindows demo") + self.Bind(wx.EVT_BUTTON, self.ShowMDISashDemo, b2) + + box = wx.BoxSizer(wx.VERTICAL) + box.Add((20, 30)) + box.Add(b1, 0, wx.ALIGN_CENTER|wx.ALL, 15) + box.Add(b2, 0, wx.ALIGN_CENTER|wx.ALL, 15) + self.SetAutoLayout(True) + self.SetSizer(box) + + + # These are spawned as new processes because on Mac there can be + # some problems related to having regular frames and MDI frames in + # the same app. + def ShowMDIDemo(self, evt): + exe, spawn = self.GetPyExecutable() + spawn(os.P_NOWAIT, exe, exe, "MDIDemo.py") + + def ShowMDISashDemo(self, evt): + exe, spawn = self.GetPyExecutable() + spawn(os.P_NOWAIT, exe, exe, "MDISashDemo.py") + + # TODO: This hack can be removed once we fix the way the Python + # app bundles are generated so that they are not bundling and + # pointing to an otherwise unused and non-GUI-friendly version of + # Python on OS X. + def GetPyExecutable(self): + if 'wxMac' in wx.PlatformInfo: + # sys.executable will be wrong if running the demo from + # an app bundle. But the bundle is always using a system + # framework so just hardcode the path to it. + if sys.version[:3] == "2.4": + return '/usr/local/bin/pythonw', os.spawnl + else: + return '/usr/bin/pythonw', os.spawnl + else: + return sys.executable, os.spawnl + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Multiple Document Interface

+ +Although Microsoft has deprecated the MDI model, wxWindows still supports +it. Here are a couple samples of how to use it - one straightforward, the other +showing how the MDI interface can be integrated into a SashWindow interface. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/MVCTree.py b/demo/MVCTree.py new file mode 100644 index 00000000..3f1f5256 --- /dev/null +++ b/demo/MVCTree.py @@ -0,0 +1,78 @@ + +import os +import sys + +import wx +import wx.lib.mvctree as tree + +logger = None +def selchanging(evt): + logger.write("SelChanging!\n") + +def selchanged(evt): + logger.write("SelChange!\n") + logger.write(str(evt.node)) +def expanded(evt): + logger.write("Expanded\n") +def closed(evt): + logger.write("Closed!\n") +def key(evt): + logger.write("Key\n") +def add(evt): + logger.write("Add\n") +def delitem(evt): + logger.write("Delete\n") + +def runTest(frame, nb, log): + #f = wx.Frame(frame, -1, "MVCTree", (0,0), (200,500)) + global logger + logger = log + p = tree.MVCTree(nb, -1) + #f = wx.Frame(frame, -1, "MVCTree") + #p = tree.MVCTree(f, -1) + p.SetAssumeChildren(True) + p.SetModel(tree.LateFSTreeModel(os.path.normpath(os.getcwd() + os.sep +'..'))) + + #Uncomment this to enable live filename editing! +# p.AddEditor(FileEditor(p)) + + p.SetMultiSelect(True) + tree.EVT_MVCTREE_SEL_CHANGING(p, p.GetId(), selchanging) + tree.EVT_MVCTREE_SEL_CHANGED(p, p.GetId(), selchanged) + tree.EVT_MVCTREE_ITEM_EXPANDED(p, p.GetId(), expanded) + tree.EVT_MVCTREE_ITEM_COLLAPSED(p, p.GetId(), closed) + tree.EVT_MVCTREE_ADD_ITEM(p, p.GetId(), add) + tree.EVT_MVCTREE_DELETE_ITEM(p, p.GetId(), delitem) + tree.EVT_MVCTREE_KEY_DOWN(p, p.GetId(), key) + + return p + #frame.otherWin = f + #f.Show(True) + #return None + + +overview = """\ + +MVCTree is a control which handles hierarchical data. It is +constructed in model-view-controller architecture, so the display of +that data, and the content of the data can be changed greatly without +affecting the other parts. + +Multiple selections are possible by holding down the Ctrl key. + +This demo shows the wxPython directory structure. The interesting part +is that the tree model is late-bound to the filesystem, so the +filenames are not retrieved until the directory is expanded. In +mvctree.py are models for generic data, and both the early and +late-bound filesystem models. + +There is also support for editing, though it's not enabled in this +demo, to avoid accidentally renaming files! + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/Main.py b/demo/Main.py new file mode 100644 index 00000000..f3ff53b6 --- /dev/null +++ b/demo/Main.py @@ -0,0 +1,3009 @@ +#!/bin/env python +#---------------------------------------------------------------------------- +# Name: Main.py +# Purpose: Testing lots of stuff, controls, window types, etc. +# +# Author: Robin Dunn +# +# Created: A long time ago, in a galaxy far, far away... +# RCS-ID: $Id$ +# Copyright: (c) 1999 by Total Control Software +# Licence: wxWindows license +#---------------------------------------------------------------------------- + +# FIXME List: +# * Problems with flickering related to ERASE_BACKGROUND +# and the splitters. Might be a problem with this 2.5 beta...? +# UPDATE: can't see on 2.5.2 GTK - maybe just a faster machine :) +# * Demo Code menu? +# * Annoying switching between tabs and resulting flicker +# how to replace a page in the notebook without deleting/adding? +# Where is SetPage!? tried freeze...tried reparent of dummy panel.... +# AG: It looks like this issue is fixed by Freeze()ing and Thaw()ing the +# main frame and not the notebook + +# TODO List: +# * UI design more professional (is the new version more professional?) +# * save file positions (new field in demoModules) (@ LoadDemoSource) +# * Update main overview + +# * Why don't we move _treeList into a separate module + +# ===================== +# = EXTERNAL Packages = +# ===================== +# In order to let a package (like AGW) be included in the wxPython demo, +# the package owner should create a sub-directory of the wxPython demo folder +# in which all the package's demos should live. In addition, the sub-folder +# should contain a Python file called __demo__.py which, when imported, should +# contain the following methods: +# +# * GetDemoBitmap: returns the bitmap to be used in the wxPython demo tree control +# in a PyEmbeddedImage format; +# * GetRecentAdditions: returns a list of demos which will be displayed under the +# "Recent Additions/Updates" tree item. This list should be a subset (or the full +# set) of the package's demos; +# * GetDemos: returns a tuple. The first item of the tuple is the package's name +# as will be displayed in the wxPython demo tree, right after the "Custom Controls" +# item. The second element of the tuple is the list of demos for the external package. +# * GetOverview: returns a wx.html-ready representation of the package's documentation. +# +# Please see the __demo__.py file in the demo/agw/ folder for an example. +# Last updated: Andrea Gavana, 20 Oct 2008, 18.00 GMT + +import sys, os, time, traceback, types +import cPickle, cStringIO, re, urllib2 +import shutil +from threading import Thread + +import wx +import wx.aui +import wx.html +from wx.lib.msgpanel import MessagePanel + +import wx.lib.mixins.inspection + +import version + +# We won't import the images module yet, but we'll assign it to this +# global when we do. +images = None + +# For debugging +##wx.Trap(); +##print "wx.VERSION_STRING = %s (%s)" % (wx.VERSION_STRING, wx.USE_UNICODE and 'unicode' or 'ansi') +##print "pid:", os.getpid() +##raw_input("Press Enter...") + +#--------------------------------------------------------------------------- + +USE_CUSTOMTREECTRL = False +DEFAULT_PERSPECTIVE = "Default Perspective" + +#--------------------------------------------------------------------------- + +_demoPngs = ["overview", "recent", "frame", "dialog", "moredialog", "core", + "book", "customcontrol", "morecontrols", "layout", "process", + "clipboard", "images", "miscellaneous"] + +_treeList = [ + # new stuff + ('Recent Additions/Updates', [ + 'PropertyGrid', + 'SystemSettings', + 'GridLabelRenderer', + 'InfoBar', + 'WrapSizer', + 'UIActionSimulator', + 'GraphicsGradient', + 'PDFViewer', + 'ItemsPicker', + 'CommandLinkButton', + 'DVC_DataViewModel', + 'DVC_IndexListModel', + 'DVC_ListCtrl', + 'DVC_TreeCtrl', + 'DVC_CustomRenderer', + 'PenAndBrushStyles', + 'HTML2_WebView', + ]), + + # managed windows == things with a (optional) caption you can close + ('Frames and Dialogs', [ + 'AUI_DockingWindowMgr', + 'AUI_MDI', + 'Dialog', + 'Frame', + 'MDIWindows', + 'MiniFrame', + 'Wizard', + ]), + + # the common dialogs + ('Common Dialogs', [ + 'AboutBox', + 'ColourDialog', + 'DirDialog', + 'FileDialog', + 'FindReplaceDialog', + 'FontDialog', + 'MessageDialog', + 'MultiChoiceDialog', + 'PageSetupDialog', + 'PrintDialog', + 'ProgressDialog', + 'SingleChoiceDialog', + 'TextEntryDialog', + ]), + + # dialogs from libraries + ('More Dialogs', [ + 'ImageBrowser', + 'ScrolledMessageDialog', + ]), + + # core controls + ('Core Windows/Controls', [ + 'BitmapButton', + 'Button', + 'CheckBox', + 'CheckListBox', + 'Choice', + 'ComboBox', + 'CommandLinkButton', + 'DVC_CustomRenderer', + 'DVC_DataViewModel', + 'DVC_IndexListModel', + 'DVC_ListCtrl', + 'DVC_TreeCtrl', + 'Gauge', + 'Grid', + 'Grid_MegaExample', + 'GridLabelRenderer', + 'ListBox', + 'ListCtrl', + 'ListCtrl_virtual', + 'ListCtrl_edit', + 'Menu', + 'PopupMenu', + 'PopupWindow', + 'RadioBox', + 'RadioButton', + 'SashWindow', + 'ScrolledWindow', + 'SearchCtrl', + 'Slider', + 'SpinButton', + 'SpinCtrl', + 'SpinCtrlDouble', + 'SplitterWindow', + 'StaticBitmap', + 'StaticBox', + 'StaticText', + 'StatusBar', + 'StockButtons', + 'TextCtrl', + 'ToggleButton', + 'ToolBar', + 'TreeCtrl', + 'Validator', + ]), + + ('"Book" Controls', [ + 'AUI_Notebook', + 'Choicebook', + 'FlatNotebook', + 'Listbook', + 'Notebook', + 'Toolbook', + 'Treebook', + ]), + + ('Custom Controls', [ + 'AnalogClock', + 'ColourSelect', + 'ComboTreeBox', + 'Editor', + 'GenericButtons', + 'GenericDirCtrl', + 'ItemsPicker', + 'LEDNumberCtrl', + 'MultiSash', + 'PlateButton', + 'PopupControl', + 'PyColourChooser', + 'TreeListCtrl', + ]), + + # controls coming from other libraries + ('More Windows/Controls', [ + 'ActiveX_FlashWindow', + 'ActiveX_IEHtmlWindow', + 'ActiveX_PDFWindow', + 'BitmapComboBox', + 'Calendar', + 'CalendarCtrl', + 'CheckListCtrlMixin', + 'CollapsiblePane', + 'ComboCtrl', + 'ContextHelp', + 'DatePickerCtrl', + 'DynamicSashWindow', + 'EditableListBox', + 'ExpandoTextCtrl', + 'FancyText', + 'FileBrowseButton', + 'FloatBar', + 'FloatCanvas', + 'HtmlWindow', + 'HTML2_WebView', + 'InfoBar', + 'IntCtrl', + 'MVCTree', + 'MaskedEditControls', + 'MaskedNumCtrl', + 'MediaCtrl', + 'MultiSplitterWindow', + 'OwnerDrawnComboBox', + 'Pickers', + 'PropertyGrid', + 'PyCrust', + 'PyPlot', + 'PyShell', + 'ResizeWidget', + 'RichTextCtrl', + 'ScrolledPanel', + 'SplitTree', + 'StyledTextCtrl_1', + 'StyledTextCtrl_2', + 'TablePrint', + 'Throbber', + 'Ticker', + 'TimeCtrl', + 'TreeMixin', + 'VListBox', + ]), + + # How to lay out the controls in a frame/dialog + ('Window Layout', [ + 'GridBagSizer', + 'LayoutAnchors', + 'LayoutConstraints', + 'Layoutf', + 'RowColSizer', + 'ScrolledPanel', + 'SizedControls', + 'Sizers', + 'WrapSizer', + 'XmlResource', + 'XmlResourceHandler', + 'XmlResourceSubclass', + ]), + + # ditto + ('Process and Events', [ + 'DelayedResult', + 'EventManager', + 'KeyEvents', + 'Process', + 'PythonEvents', + 'Threads', + 'Timer', + ##'infoframe', # needs better explanation and some fixing + ]), + + # Clipboard and DnD + ('Clipboard and DnD', [ + 'CustomDragAndDrop', + 'DragAndDrop', + 'URLDragAndDrop', + ]), + + # Images + ('Using Images', [ + 'AdjustChannels', + 'AlphaDrawing', + 'AnimateCtrl', + 'ArtProvider', + 'BitmapFromBuffer', + 'Cursor', + 'DragImage', + 'Image', + 'ImageAlpha', + 'ImageFromStream', + 'Img2PyArtProvider', + 'Mask', + 'RawBitmapAccess', + 'Throbber', + ]), + + # Other stuff + ('Miscellaneous', [ + 'AlphaDrawing', + 'Cairo', + 'Cairo_Snippets', + 'ColourDB', + ##'DialogUnits', # needs more explanations + 'DragScroller', + 'DrawXXXList', + 'FileHistory', + 'FontEnumerator', + 'GraphicsContext', + 'GraphicsGradient', + 'GLCanvas', + 'I18N', + 'Joystick', + 'MimeTypesManager', + 'MouseGestures', + 'OGL', + 'PDFViewer', + 'PenAndBrushStyles', + 'PrintFramework', + 'PseudoDC', + 'RendererNative', + 'ShapedWindow', + 'Sound', + 'StandardPaths', + 'SystemSettings', + 'UIActionSimulator', + 'Unicode', + ]), + + + ('Check out the samples dir too', [] ), + +] + +#--------------------------------------------------------------------------- + +_styleTable = '

Window %s

\n' \ + '

This class supports the following window %s:\n' \ + '

' + +_eventTable = '

Events

\n' \ + '

Events emitted by this class:\n' \ + '

' + +_appearanceTable = '

Appearance

\n' \ + '

Control appearance on various platform:\n' \ + '

' + +_styleHeaders = ["Style Name", "Description"] +_eventHeaders = ["Event Name", "Description"] +_headerTable = '' +_styleTag = '' +_eventTag = '' +_hexValues = '' +_description = '' +_imageTag = '' +_platformTag = '' + +_trunkURL = "http://docs.wxwidgets.org/trunk/" +_docsURL = _trunkURL + "classwx%s.html" +_platformNames = ["wxMSW", "wxGTK", "wxMac"] + + +_importList = ["wx.aui", "wx.calendar", "wx.html", "wx.media", "wx.wizard", + "wx.combo", "wx.animate", "wx.gizmos", "wx.glcanvas", "wx.grid", + "wx.richtext", "wx.stc"] + +_dirWX = dir(wx) +for mod in _importList: + try: + module = __import__(mod) + except ImportError: + continue + +#--------------------------------------------------------------------------- + +def ReplaceCapitals(string): + """ + Replaces the capital letter in a string with an underscore plus the + corresponding lowercase character. + + **Parameters:** + + * `string`: the string to be analyzed. + """ + + newString = "" + for char in string: + if char.isupper(): + newString += "_%s"%char.lower() + else: + newString += char + + return newString + + +def RemoveHTMLTags(data): + """ + Removes all the HTML tags from a string. + + **Parameters:** + + * `data`: the string to be analyzed. + """ + + p = re.compile(r'<[^<]*?>') + return p.sub('', data) + + +def FormatDocs(keyword, values, num): + + names = values.keys() + names.sort() + + headers = (num == 2 and [_eventHeaders] or [_styleHeaders])[0] + table = (num == 2 and [_eventTable] or [_styleTable])[0] + if num == 3: + text = "
" + table%(keyword.lower(), keyword.lower()) + "\n\n" + else: + text = "
" + table + + for indx in xrange(2): + text += _headerTable%headers[indx] + + text += "\n\n" + + for name in names: + + text += "\n" + + description = values[name].strip() + pythonValue = name.replace("wx", "wx.") + + if num == 3: + + colour = "#ff0000" + value = "Unavailable" + cutValue = pythonValue[3:] + + if cutValue in _dirWX: + try: + val = eval(pythonValue) + value = "%s"%hex(val) + colour = "#0000ff" + except AttributeError: + value = "Unavailable" + else: + for packages in _importList: + if cutValue in dir(eval(packages)): + val = eval("%s.%s"%(packages, cutValue)) + value = "%s"%hex(val) + colour = "#0000ff" + pythonValue = "%s.%s"%(packages, cutValue) + break + + text += _styleTag%pythonValue + "\n" + + else: + + text += _eventTag%pythonValue + "\n" + + text += _description%FormatDescription(description) + "\n" + text += "\n" + + text += "\n
%s%s%s %s %s%s%s
\n\n

" + return text + + +def FormatDescription(description): + """ + Formats a wxWidgets C++ description in a more wxPython-based way. + + **Parameters:** + + * `description`: the string description to be formatted. + """ + + description = description.replace("wx", "wx.") + description = description.replace("EVT_COMMAND", "wxEVT_COMMAND") + description = description.replace("wx.Widgets", "wxWidgets") + + return description + + +def FormatImages(appearance): + + text = "


" + _appearanceTable + + for indx in xrange(2): + text += "\n\n" + for key in _platformNames: + if indx == 0: + src = appearance[key] + alt = key + "Appearance" + text += _imageTag%(src, src, alt) + else: + text += _platformTag%key + + text += "\n" + + text += "\n\n\n

" + return text + + +def FindWindowStyles(text, originalText, widgetName): + """ + Finds the windows styles and events in the input text. + + **Parameters:** + + * `text`: the wxWidgets C++ docs for a particular widget/event, stripped + of all HTML tags; + * `originalText`: the wxWidgets C++ docs for a particular widget/event, with + all HTML tags. + """ + + winStyles, winEvents, winExtra, winAppearance = {}, {}, {}, {} + inStyle = inExtra = inEvent = False + + for line in text: + if "following styles:" in line: + inStyle = True + continue + + elif "Event macros" in line: + inEvent = True + continue + + if "following extra styles:" in line: + inExtra = True + continue + + if "Appearance:" in line: + winAppearance = FindImages(originalText, widgetName) + continue + + elif not line.strip(): + inStyle = inEvent = inExtra = False + continue + + if inStyle: + start = line.index(':') + windowStyle = line[0:start] + styleDescription = line[start+1:] + winStyles[windowStyle] = styleDescription + elif inEvent: + start = line.index(':') + eventName = line[0:start] + eventDescription = line[start+1:] + winEvents[eventName] = eventDescription + elif inExtra: + start = line.index(':') + styleName = line[0:start] + styleDescription = line[start+1:] + winExtra[styleName] = styleDescription + + return winStyles, winEvents, winExtra, winAppearance + + +def FindImages(text, widgetName): + """ + When the wxWidgets docs contain athe control appearance (a screenshot of the + control), this method will try and download the images. + + **Parameters:** + + * `text`: the wxWidgets C++ docs for a particular widget/event, with + all HTML tags. + """ + + winAppearance = {} + start = text.find("class='appearance'") + + if start < 0: + return winAppearance + + imagesDir = GetDocImagesDir() + + end = start + text.find("") + text = text[start:end] + split = text.split() + + for indx, items in enumerate(split): + + if "src=" in items: + possibleImage = items.replace("src=", "").strip() + possibleImage = possibleImage.replace("'", "") + f = urllib2.urlopen(_trunkURL + possibleImage) + stream = f.read() + + elif "alt=" in items: + plat = items.replace("alt=", "").replace("'", "").strip() + path = os.path.join(imagesDir, plat, widgetName + ".png") + if not os.path.isfile(path): + image = wx.ImageFromStream(cStringIO.StringIO(stream)) + image.SaveFile(path, wx.BITMAP_TYPE_PNG) + + winAppearance[plat] = path + + return winAppearance + + +#--------------------------------------------------------------------------- +# Set up a thread that will scan the wxWidgets docs for window styles, +# events and widgets screenshots + +class InternetThread(Thread): + """ Worker thread class to attempt connection to the internet. """ + + def __init__(self, notifyWindow, selectedClass): + + Thread.__init__(self) + + self.notifyWindow = notifyWindow + self.selectedClass = selectedClass + self.keepRunning = True + self.setDaemon(True) + + self.start() + + + def run(self): + """ Run the worker thread. """ + + # This is the code executing in the new thread. Simulation of + # a long process as a simple urllib2 call + + try: + url = _docsURL % ReplaceCapitals(self.selectedClass) + fid = urllib2.urlopen(url) + + originalText = fid.read() + text = RemoveHTMLTags(originalText).split("\n") + data = FindWindowStyles(text, originalText, self.selectedClass) + + if not self.keepRunning: + return + + wx.CallAfter(self.notifyWindow.LoadDocumentation, data) + except (IOError, urllib2.HTTPError): + # Unable to get to the internet + t, v = sys.exc_info()[:2] + message = traceback.format_exception_only(t, v) + wx.CallAfter(self.notifyWindow.StopDownload, message) + except: + # Some other strange error... + t, v = sys.exc_info()[:2] + message = traceback.format_exception_only(t, v) + wx.CallAfter(self.notifyWindow.StopDownload, message) + + +#--------------------------------------------------------------------------- +# Show how to derive a custom wxLog class + +class MyLog(wx.PyLog): + def __init__(self, textCtrl, logTime=0): + wx.PyLog.__init__(self) + self.tc = textCtrl + self.logTime = logTime + + def DoLogText(self, message): + if self.tc: + self.tc.AppendText(message + '\n') + + + +#--------------------------------------------------------------------------- +# A class to be used to display source code in the demo. Try using the +# wxSTC in the StyledTextCtrl_2 sample first, fall back to wxTextCtrl +# if there is an error, such as the stc module not being present. +# + +try: + ##raise ImportError # for testing the alternate implementation + from wx import stc + from StyledTextCtrl_2 import PythonSTC + + class DemoCodeEditor(PythonSTC): + def __init__(self, parent, style=wx.BORDER_NONE): + PythonSTC.__init__(self, parent, -1, style=style) + self.SetUpEditor() + + # Some methods to make it compatible with how the wxTextCtrl is used + def SetValue(self, value): + if wx.USE_UNICODE: + value = value.decode('iso8859_1') + val = self.GetReadOnly() + self.SetReadOnly(False) + self.SetText(value) + self.EmptyUndoBuffer() + self.SetSavePoint() + self.SetReadOnly(val) + + def SetEditable(self, val): + self.SetReadOnly(not val) + + def IsModified(self): + return self.GetModify() + + def Clear(self): + self.ClearAll() + + def SetInsertionPoint(self, pos): + self.SetCurrentPos(pos) + self.SetAnchor(pos) + + def ShowPosition(self, pos): + line = self.LineFromPosition(pos) + #self.EnsureVisible(line) + self.GotoLine(line) + + def GetLastPosition(self): + return self.GetLength() + + def GetPositionFromLine(self, line): + return self.PositionFromLine(line) + + def GetRange(self, start, end): + return self.GetTextRange(start, end) + + def GetSelection(self): + return self.GetAnchor(), self.GetCurrentPos() + + def SetSelection(self, start, end): + self.SetSelectionStart(start) + self.SetSelectionEnd(end) + + def SelectLine(self, line): + start = self.PositionFromLine(line) + end = self.GetLineEndPosition(line) + self.SetSelection(start, end) + + def SetUpEditor(self): + """ + This method carries out the work of setting up the demo editor. + It's seperate so as not to clutter up the init code. + """ + import keyword + + self.SetLexer(stc.STC_LEX_PYTHON) + self.SetKeyWords(0, " ".join(keyword.kwlist)) + + # Enable folding + self.SetProperty("fold", "1" ) + + # Highlight tab/space mixing (shouldn't be any) + self.SetProperty("tab.timmy.whinge.level", "1") + + # Set left and right margins + self.SetMargins(2,2) + + # Set up the numbers in the margin for margin #1 + self.SetMarginType(1, wx.stc.STC_MARGIN_NUMBER) + # Reasonable value for, say, 4-5 digits using a mono font (40 pix) + self.SetMarginWidth(1, 40) + + # Indentation and tab stuff + self.SetIndent(4) # Proscribed indent size for wx + self.SetIndentationGuides(True) # Show indent guides + self.SetBackSpaceUnIndents(True)# Backspace unindents rather than delete 1 space + self.SetTabIndents(True) # Tab key indents + self.SetTabWidth(4) # Proscribed tab size for wx + self.SetUseTabs(False) # Use spaces rather than tabs, or + # TabTimmy will complain! + # White space + self.SetViewWhiteSpace(False) # Don't view white space + + # EOL: Since we are loading/saving ourselves, and the + # strings will always have \n's in them, set the STC to + # edit them that way. + self.SetEOLMode(wx.stc.STC_EOL_LF) + self.SetViewEOL(False) + + # No right-edge mode indicator + self.SetEdgeMode(stc.STC_EDGE_NONE) + + # Setup a margin to hold fold markers + self.SetMarginType(2, stc.STC_MARGIN_SYMBOL) + self.SetMarginMask(2, stc.STC_MASK_FOLDERS) + self.SetMarginSensitive(2, True) + self.SetMarginWidth(2, 12) + + # and now set up the fold markers + self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "black") + + # Global default style + if wx.Platform == '__WXMSW__': + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, + 'fore:#000000,back:#FFFFFF,face:Courier New') + elif wx.Platform == '__WXMAC__': + # TODO: if this looks fine on Linux too, remove the Mac-specific case + # and use this whenever OS != MSW. + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, + 'fore:#000000,back:#FFFFFF,face:Monaco') + else: + defsize = wx.SystemSettings.GetFont(wx.SYS_ANSI_FIXED_FONT).GetPointSize() + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, + 'fore:#000000,back:#FFFFFF,face:Courier,size:%d'%defsize) + + # Clear styles and revert to default. + self.StyleClearAll() + + # Following style specs only indicate differences from default. + # The rest remains unchanged. + + # Line numbers in margin + self.StyleSetSpec(wx.stc.STC_STYLE_LINENUMBER,'fore:#000000,back:#99A9C2') + # Highlighted brace + self.StyleSetSpec(wx.stc.STC_STYLE_BRACELIGHT,'fore:#00009D,back:#FFFF00') + # Unmatched brace + self.StyleSetSpec(wx.stc.STC_STYLE_BRACEBAD,'fore:#00009D,back:#FF0000') + # Indentation guide + self.StyleSetSpec(wx.stc.STC_STYLE_INDENTGUIDE, "fore:#CDCDCD") + + # Python styles + self.StyleSetSpec(wx.stc.STC_P_DEFAULT, 'fore:#000000') + # Comments + self.StyleSetSpec(wx.stc.STC_P_COMMENTLINE, 'fore:#008000,back:#F0FFF0') + self.StyleSetSpec(wx.stc.STC_P_COMMENTBLOCK, 'fore:#008000,back:#F0FFF0') + # Numbers + self.StyleSetSpec(wx.stc.STC_P_NUMBER, 'fore:#008080') + # Strings and characters + self.StyleSetSpec(wx.stc.STC_P_STRING, 'fore:#800080') + self.StyleSetSpec(wx.stc.STC_P_CHARACTER, 'fore:#800080') + # Keywords + self.StyleSetSpec(wx.stc.STC_P_WORD, 'fore:#000080,bold') + # Triple quotes + self.StyleSetSpec(wx.stc.STC_P_TRIPLE, 'fore:#800080,back:#FFFFEA') + self.StyleSetSpec(wx.stc.STC_P_TRIPLEDOUBLE, 'fore:#800080,back:#FFFFEA') + # Class names + self.StyleSetSpec(wx.stc.STC_P_CLASSNAME, 'fore:#0000FF,bold') + # Function names + self.StyleSetSpec(wx.stc.STC_P_DEFNAME, 'fore:#008080,bold') + # Operators + self.StyleSetSpec(wx.stc.STC_P_OPERATOR, 'fore:#800000,bold') + # Identifiers. I leave this as not bold because everything seems + # to be an identifier if it doesn't match the above criterae + self.StyleSetSpec(wx.stc.STC_P_IDENTIFIER, 'fore:#000000') + + # Caret color + self.SetCaretForeground("BLUE") + # Selection background + self.SetSelBackground(1, '#66CCFF') + + self.SetSelBackground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT)) + self.SetSelForeground(True, wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)) + + def RegisterModifiedEvent(self, eventHandler): + self.Bind(wx.stc.EVT_STC_CHANGE, eventHandler) + + +except ImportError: + class DemoCodeEditor(wx.TextCtrl): + def __init__(self, parent): + wx.TextCtrl.__init__(self, parent, -1, style = + wx.TE_MULTILINE | wx.HSCROLL | wx.TE_RICH2 | wx.TE_NOHIDESEL) + + def RegisterModifiedEvent(self, eventHandler): + self.Bind(wx.EVT_TEXT, eventHandler) + + def SetReadOnly(self, flag): + self.SetEditable(not flag) + # NOTE: STC already has this method + + def GetText(self): + return self.GetValue() + + def GetPositionFromLine(self, line): + return self.XYToPosition(0,line) + + def GotoLine(self, line): + pos = self.GetPositionFromLine(line) + self.SetInsertionPoint(pos) + self.ShowPosition(pos) + + def SelectLine(self, line): + start = self.GetPositionFromLine(line) + end = start + self.GetLineLength(line) + self.SetSelection(start, end) + + +#--------------------------------------------------------------------------- +# Constants for module versions + +modOriginal = 0 +modModified = 1 +modDefault = modOriginal + +#--------------------------------------------------------------------------- + +class DemoCodePanel(wx.Panel): + """Panel for the 'Demo Code' tab""" + def __init__(self, parent, mainFrame): + wx.Panel.__init__(self, parent, size=(1,1)) + if 'wxMSW' in wx.PlatformInfo: + self.Hide() + self.mainFrame = mainFrame + self.editor = DemoCodeEditor(self) + self.editor.RegisterModifiedEvent(self.OnCodeModified) + + self.btnSave = wx.Button(self, -1, "Save Changes") + self.btnRestore = wx.Button(self, -1, "Delete Modified") + self.btnSave.Enable(False) + self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave) + self.btnRestore.Bind(wx.EVT_BUTTON, self.OnRestore) + + self.radioButtons = { modOriginal: wx.RadioButton(self, -1, "Original", style = wx.RB_GROUP), + modModified: wx.RadioButton(self, -1, "Modified") } + + self.controlBox = wx.BoxSizer(wx.HORIZONTAL) + self.controlBox.Add(wx.StaticText(self, -1, "Active Version:"), 0, + wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER_VERTICAL, 5) + for modID, radioButton in self.radioButtons.items(): + self.controlBox.Add(radioButton, 0, wx.EXPAND | wx.RIGHT, 5) + radioButton.modID = modID # makes it easier for the event handler + radioButton.Bind(wx.EVT_RADIOBUTTON, self.OnRadioButton) + + self.controlBox.Add(self.btnSave, 0, wx.RIGHT, 5) + self.controlBox.Add(self.btnRestore, 0) + + self.box = wx.BoxSizer(wx.VERTICAL) + self.box.Add(self.controlBox, 0, wx.EXPAND) + self.box.Add(wx.StaticLine(self), 0, wx.EXPAND) + self.box.Add(self.editor, 1, wx.EXPAND) + + self.box.Fit(self) + self.SetSizer(self.box) + + + # Loads a demo from a DemoModules object + def LoadDemo(self, demoModules): + self.demoModules = demoModules + if (modDefault == modModified) and demoModules.Exists(modModified): + demoModules.SetActive(modModified) + else: + demoModules.SetActive(modOriginal) + self.radioButtons[demoModules.GetActiveID()].Enable(True) + self.ActiveModuleChanged() + + + def ActiveModuleChanged(self): + self.LoadDemoSource(self.demoModules.GetSource()) + self.UpdateControlState() + self.mainFrame.pnl.Freeze() + self.ReloadDemo() + self.mainFrame.pnl.Thaw() + + + def LoadDemoSource(self, source): + self.editor.Clear() + self.editor.SetValue(source) + self.JumpToLine(0) + self.btnSave.Enable(False) + + + def JumpToLine(self, line, highlight=False): + self.editor.GotoLine(line) + self.editor.SetFocus() + if highlight: + self.editor.SelectLine(line) + + + def UpdateControlState(self): + active = self.demoModules.GetActiveID() + # Update the radio/restore buttons + for moduleID in self.radioButtons: + btn = self.radioButtons[moduleID] + if moduleID == active: + btn.SetValue(True) + else: + btn.SetValue(False) + + if self.demoModules.Exists(moduleID): + btn.Enable(True) + if moduleID == modModified: + self.btnRestore.Enable(True) + else: + btn.Enable(False) + if moduleID == modModified: + self.btnRestore.Enable(False) + + + def OnRadioButton(self, event): + radioSelected = event.GetEventObject() + modSelected = radioSelected.modID + if modSelected != self.demoModules.GetActiveID(): + busy = wx.BusyInfo("Reloading demo module...") + self.demoModules.SetActive(modSelected) + self.ActiveModuleChanged() + + + def ReloadDemo(self): + if self.demoModules.name != __name__: + self.mainFrame.RunModule() + + + def OnCodeModified(self, event): + self.btnSave.Enable(self.editor.IsModified()) + + + def OnSave(self, event): + if self.demoModules.Exists(modModified): + if self.demoModules.GetActiveID() == modOriginal: + overwriteMsg = "You are about to overwrite an already existing modified copy\n" + \ + "Do you want to continue?" + dlg = wx.MessageDialog(self, overwriteMsg, "wxPython Demo", + wx.YES_NO | wx.NO_DEFAULT| wx.ICON_EXCLAMATION) + result = dlg.ShowModal() + if result == wx.ID_NO: + return + dlg.Destroy() + + self.demoModules.SetActive(modModified) + modifiedFilename = GetModifiedFilename(self.demoModules.name) + + # Create the demo directory if one doesn't already exist + if not os.path.exists(GetModifiedDirectory()): + try: + os.makedirs(GetModifiedDirectory()) + if not os.path.exists(GetModifiedDirectory()): + wx.LogMessage("BUG: Created demo directory but it still doesn't exist") + raise AssertionError + except: + wx.LogMessage("Error creating demo directory: %s" % GetModifiedDirectory()) + return + else: + wx.LogMessage("Created directory for modified demos: %s" % GetModifiedDirectory()) + + # Save + f = open(modifiedFilename, "wt") + source = self.editor.GetText() + try: + f.write(source) + finally: + f.close() + + busy = wx.BusyInfo("Reloading demo module...") + self.demoModules.LoadFromFile(modModified, modifiedFilename) + self.ActiveModuleChanged() + + self.mainFrame.SetTreeModified(True) + + + def OnRestore(self, event): # Handles the "Delete Modified" button + modifiedFilename = GetModifiedFilename(self.demoModules.name) + self.demoModules.Delete(modModified) + os.unlink(modifiedFilename) # Delete the modified copy + busy = wx.BusyInfo("Reloading demo module...") + + self.ActiveModuleChanged() + + self.mainFrame.SetTreeModified(False) + + +#--------------------------------------------------------------------------- + +def opj(path): + """Convert paths to the platform-specific separator""" + st = apply(os.path.join, tuple(path.split('/'))) + # HACK: on Linux, a leading / gets lost... + if path.startswith('/'): + st = '/' + st + return st + + +def GetDataDir(): + """ + Return the standard location on this platform for application data + """ + sp = wx.StandardPaths.Get() + return sp.GetUserDataDir() + + +def GetModifiedDirectory(): + """ + Returns the directory where modified versions of the demo files + are stored + """ + return os.path.join(GetDataDir(), "modified") + + +def GetModifiedFilename(name): + """ + Returns the filename of the modified version of the specified demo + """ + if not name.endswith(".py"): + name = name + ".py" + return os.path.join(GetModifiedDirectory(), name) + + +def GetOriginalFilename(name): + """ + Returns the filename of the original version of the specified demo + """ + if not name.endswith(".py"): + name = name + ".py" + + if os.path.isfile(name): + return name + + originalDir = os.getcwd() + listDir = os.listdir(originalDir) + # Loop over the content of the demo directory + for item in listDir: + if not os.path.isdir(item): + # Not a directory, continue + continue + dirFile = os.listdir(item) + # See if a file called "name" is there + if name in dirFile: + return os.path.join(item, name) + + # We must return a string... + return "" + + +def DoesModifiedExist(name): + """Returns whether the specified demo has a modified copy""" + if os.path.exists(GetModifiedFilename(name)): + return True + else: + return False + + +def GetConfig(): + if not os.path.exists(GetDataDir()): + os.makedirs(GetDataDir()) + + config = wx.FileConfig( + localFilename=os.path.join(GetDataDir(), "options")) + return config + + +def MakeDocDirs(): + + docDir = os.path.join(GetDataDir(), "docs") + if not os.path.exists(docDir): + os.makedirs(docDir) + + for plat in _platformNames: + imageDir = os.path.join(docDir, "images", plat) + if not os.path.exists(imageDir): + os.makedirs(imageDir) + + +def GetDocFile(): + + docFile = os.path.join(GetDataDir(), "docs", "TrunkDocs.pkl") + + return docFile + + +def GetDocImagesDir(): + + MakeDocDirs() + return os.path.join(GetDataDir(), "docs", "images") + + +def SearchDemo(name, keyword): + """ Returns whether a demo contains the search keyword or not. """ + fid = open(GetOriginalFilename(name), "rt") + fullText = fid.read() + fid.close() + + fullText = fullText.decode("iso-8859-1") + + if fullText.find(keyword) >= 0: + return True + + return False + + +def HuntExternalDemos(): + """ + Searches for external demos (i.e. packages like AGW) in the wxPython + demo sub-directories. In order to be found, these external packages + must have a __demo__.py file in their directory. + """ + + externalDemos = {} + originalDir = os.getcwd() + listDir = os.listdir(originalDir) + # Loop over the content of the demo directory + for item in listDir: + if not os.path.isdir(item): + # Not a directory, continue + continue + dirFile = os.listdir(item) + # See if a __demo__.py file is there + if "__demo__.py" in dirFile: + # Extend sys.path and import the external demos + sys.path.append(item) + externalDemos[item] = __import__("__demo__") + + if not externalDemos: + # Nothing to import... + return {} + + # Modify the tree items and icons + index = 0 + for category, demos in _treeList: + # We put the external packages right before the + # More Windows/Controls item + if category == "More Windows/Controls": + break + index += 1 + + # Sort and reverse the external demos keys so that they + # come back in alphabetical order + keys = externalDemos.keys() + keys.sort() + keys.reverse() + + # Loop over all external packages + for extern in keys: + package = externalDemos[extern] + # Insert a new package in the _treeList of demos + _treeList.insert(index, package.GetDemos()) + # Get the recent additions for this package + _treeList[0][1].extend(package.GetRecentAdditions()) + # Extend the demo bitmaps and the catalog + _demoPngs.insert(index+1, extern) + images.catalog[extern] = package.GetDemoBitmap() + + # That's all folks... + return externalDemos + + +def LookForExternals(externalDemos, demoName): + """ + Checks if a demo name is in any of the external packages (like AGW) or + if the user clicked on one of the external packages parent items in the + tree, in which case it returns the html overview for the package. + """ + + pkg = overview = None + # Loop over all the external demos + for key, package in externalDemos.items(): + # Get the tree item name for the package and its demos + treeName, treeDemos = package.GetDemos() + # Get the overview for the package + treeOverview = package.GetOverview() + if treeName == demoName: + # The user clicked on the parent tree item, return the overview + return pkg, treeOverview + elif demoName in treeDemos: + # The user clicked on a real demo, return the package + return key, overview + + # No match found, return None for both + return pkg, overview + +#--------------------------------------------------------------------------- + +class ModuleDictWrapper(object): + """Emulates a module with a dynamically compiled __dict__""" + def __init__(self, dict): + self.dict = dict + + def __getattr__(self, name): + if name in self.dict: + return self.dict[name] + else: + raise AttributeError + +class DemoModules(object): + """ + Dynamically manages the original/modified versions of a demo + module + """ + def __init__(self, name): + self.modActive = -1 + self.name = name + + # (dict , source , filename , description , error information ) + # ( 0 , 1 , 2 , 3 , 4 ) + self.modules = [[dict(), "" , "" , "" , None], + [dict(), "" , "" , "" , None]] + + for i in [modOriginal, modModified]: + self.modules[i][0]['__file__'] = \ + os.path.join(os.getcwdu(), GetOriginalFilename(name)) + + # load original module + self.LoadFromFile(modOriginal, GetOriginalFilename(name)) + self.SetActive(modOriginal) + + # load modified module (if one exists) + if DoesModifiedExist(name): + self.LoadFromFile(modModified, GetModifiedFilename(name)) + + + def LoadFromFile(self, modID, filename): + self.modules[modID][2] = filename + file = open(filename, "rt") + self.LoadFromSource(modID, file.read()) + file.close() + + + def LoadFromSource(self, modID, source): + self.modules[modID][1] = source + self.LoadDict(modID) + + + def LoadDict(self, modID): + if self.name != __name__: + source = self.modules[modID][1] + description = self.modules[modID][2] + description = description.encode(sys.getfilesystemencoding()) + + try: + code = compile(source, description, "exec") + exec code in self.modules[modID][0] + except: + self.modules[modID][4] = DemoError(sys.exc_info()) + self.modules[modID][0] = None + else: + self.modules[modID][4] = None + + + def SetActive(self, modID): + if modID != modOriginal and modID != modModified: + raise LookupError + else: + self.modActive = modID + + + def GetActive(self): + dict = self.modules[self.modActive][0] + if dict is None: + return None + else: + return ModuleDictWrapper(dict) + + + def GetActiveID(self): + return self.modActive + + + def GetSource(self, modID = None): + if modID is None: + modID = self.modActive + return self.modules[modID][1] + + + def GetFilename(self, modID = None): + if modID is None: + modID = self.modActive + return self.modules[self.modActive][2] + + + def GetErrorInfo(self, modID = None): + if modID is None: + modID = self.modActive + return self.modules[self.modActive][4] + + + def Exists(self, modID): + return self.modules[modID][1] != "" + + + def UpdateFile(self, modID = None): + """Updates the file from which a module was loaded + with (possibly updated) source""" + if modID is None: + modID = self.modActive + + source = self.modules[modID][1] + filename = self.modules[modID][2] + + try: + file = open(filename, "wt") + file.write(source) + finally: + file.close() + + + def Delete(self, modID): + if self.modActive == modID: + self.SetActive(0) + + self.modules[modID][0] = None + self.modules[modID][1] = "" + self.modules[modID][2] = "" + + +#--------------------------------------------------------------------------- + +class DemoError(object): + """Wraps and stores information about the current exception""" + def __init__(self, exc_info): + import copy + + excType, excValue = exc_info[:2] + # traceback list entries: (filename, line number, function name, text) + self.traceback = traceback.extract_tb(exc_info[2]) + + # --Based on traceback.py::format_exception_only()-- + if type(excType) == types.ClassType: + self.exception_type = excType.__name__ + else: + self.exception_type = excType + + # If it's a syntax error, extra information needs + # to be added to the traceback + if excType is SyntaxError: + try: + msg, (filename, lineno, self.offset, line) = excValue + except: + pass + else: + if not filename: + filename = "" + line = line.strip() + self.traceback.append( (filename, lineno, "", line) ) + excValue = msg + try: + self.exception_details = str(excValue) + except: + self.exception_details = "" & type(excValue).__name__ + + del exc_info + + def __str__(self): + ret = "Type %s \n \ + Traceback: %s \n \ + Details : %s" % ( str(self.exception_type), str(self.traceback), self.exception_details ) + return ret + +#--------------------------------------------------------------------------- + +class DemoErrorPanel(wx.Panel): + """Panel put into the demo tab when the demo fails to run due to errors""" + + def __init__(self, parent, codePanel, demoError, log): + wx.Panel.__init__(self, parent, -1)#, style=wx.NO_FULL_REPAINT_ON_RESIZE) + self.codePanel = codePanel + self.nb = parent + self.log = log + + self.box = wx.BoxSizer(wx.VERTICAL) + + # Main Label + self.box.Add(wx.StaticText(self, -1, "An error has occurred while trying to run the demo") + , 0, wx.ALIGN_CENTER | wx.TOP, 10) + + # Exception Information + boxInfo = wx.StaticBox(self, -1, "Exception Info" ) + boxInfoSizer = wx.StaticBoxSizer(boxInfo, wx.VERTICAL ) # Used to center the grid within the box + boxInfoGrid = wx.FlexGridSizer( cols=2 ) + textFlags = wx.ALIGN_RIGHT | wx.LEFT | wx.RIGHT | wx.TOP + boxInfoGrid.Add(wx.StaticText(self, -1, "Type: "), 0, textFlags, 5 ) + boxInfoGrid.Add(wx.StaticText(self, -1, str(demoError.exception_type)) , 0, textFlags, 5 ) + boxInfoGrid.Add(wx.StaticText(self, -1, "Details: ") , 0, textFlags, 5 ) + boxInfoGrid.Add(wx.StaticText(self, -1, demoError.exception_details) , 0, textFlags, 5 ) + boxInfoSizer.Add(boxInfoGrid, 0, wx.ALIGN_CENTRE | wx.ALL, 5 ) + self.box.Add(boxInfoSizer, 0, wx.ALIGN_CENTER | wx.ALL, 5) + + # Set up the traceback list + # This one automatically resizes last column to take up remaining space + from ListCtrl import TestListCtrl + self.list = TestListCtrl(self, -1, style=wx.LC_REPORT | wx.SUNKEN_BORDER) + self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) + self.list.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) + self.list.InsertColumn(0, "Filename") + self.list.InsertColumn(1, "Line", wx.LIST_FORMAT_RIGHT) + self.list.InsertColumn(2, "Function") + self.list.InsertColumn(3, "Code") + self.InsertTraceback(self.list, demoError.traceback) + self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(2, wx.LIST_AUTOSIZE) + self.box.Add(wx.StaticText(self, -1, "Traceback:") + , 0, wx.ALIGN_CENTER | wx.TOP, 5) + self.box.Add(self.list, 1, wx.GROW | wx.ALIGN_CENTER | wx.ALL, 5) + self.box.Add(wx.StaticText(self, -1, "Entries from the demo module are shown in blue\n" + + "Double-click on them to go to the offending line") + , 0, wx.ALIGN_CENTER | wx.BOTTOM, 5) + + self.box.Fit(self) + self.SetSizer(self.box) + + + def InsertTraceback(self, list, traceback): + #Add the traceback data + for x in range(len(traceback)): + data = traceback[x] + list.InsertStringItem(x, os.path.basename(data[0])) # Filename + list.SetStringItem(x, 1, str(data[1])) # Line + list.SetStringItem(x, 2, str(data[2])) # Function + list.SetStringItem(x, 3, str(data[3])) # Code + + # Check whether this entry is from the demo module + if data[0] == "" or data[0] == "": # FIXME: make more generalised + self.list.SetItemData(x, int(data[1])) # Store line number for easy access + # Give it a blue colour + item = self.list.GetItem(x) + item.SetTextColour(wx.BLUE) + self.list.SetItem(item) + else: + self.list.SetItemData(x, -1) # Editor can't jump into this one's code + + + def OnItemSelected(self, event): + # This occurs before OnDoubleClick and can be used to set the + # currentItem. OnDoubleClick doesn't get a wxListEvent.... + self.currentItem = event.m_itemIndex + event.Skip() + + + def OnDoubleClick(self, event): + # If double-clicking on a demo's entry, jump to the line number + line = self.list.GetItemData(self.currentItem) + if line != -1: + self.nb.SetSelection(1) # Switch to the code viewer tab + wx.CallAfter(self.codePanel.JumpToLine, line-1, True) + event.Skip() + + +#--------------------------------------------------------------------------- + +class MainPanel(wx.Panel): + """ + Just a simple derived panel where we override Freeze and Thaw so they are + only used on wxMSW. + """ + def Freeze(self): + if 'wxMSW' in wx.PlatformInfo: + return super(MainPanel, self).Freeze() + + def Thaw(self): + if 'wxMSW' in wx.PlatformInfo: + return super(MainPanel, self).Thaw() + +#--------------------------------------------------------------------------- + +class DemoTaskBarIcon(wx.TaskBarIcon): + TBMENU_RESTORE = wx.NewId() + TBMENU_CLOSE = wx.NewId() + TBMENU_CHANGE = wx.NewId() + TBMENU_REMOVE = wx.NewId() + + def __init__(self, frame): + wx.TaskBarIcon.__init__(self, wx.TBI_DOCK) # wx.TBI_CUSTOM_STATUSITEM + self.frame = frame + + # Set the image + icon = self.MakeIcon(images.WXPdemo.GetImage()) + self.SetIcon(icon, "wxPython Demo") + self.imgidx = 1 + + # bind some events + self.Bind(wx.EVT_TASKBAR_LEFT_DCLICK, self.OnTaskBarActivate) + self.Bind(wx.EVT_MENU, self.OnTaskBarActivate, id=self.TBMENU_RESTORE) + self.Bind(wx.EVT_MENU, self.OnTaskBarClose, id=self.TBMENU_CLOSE) + self.Bind(wx.EVT_MENU, self.OnTaskBarChange, id=self.TBMENU_CHANGE) + self.Bind(wx.EVT_MENU, self.OnTaskBarRemove, id=self.TBMENU_REMOVE) + + + def CreatePopupMenu(self): + """ + This method is called by the base class when it needs to popup + the menu for the default EVT_RIGHT_DOWN event. Just create + the menu how you want it and return it from this function, + the base class takes care of the rest. + """ + menu = wx.Menu() + menu.Append(self.TBMENU_RESTORE, "Restore wxPython Demo") + menu.Append(self.TBMENU_CLOSE, "Close wxPython Demo") + menu.AppendSeparator() + menu.Append(self.TBMENU_CHANGE, "Change the TB Icon") + menu.Append(self.TBMENU_REMOVE, "Remove the TB Icon") + return menu + + + def MakeIcon(self, img): + """ + The various platforms have different requirements for the + icon size... + """ + if "wxMSW" in wx.PlatformInfo: + img = img.Scale(16, 16) + elif "wxGTK" in wx.PlatformInfo: + img = img.Scale(22, 22) + # wxMac can be any size upto 128x128, so leave the source img alone.... + icon = wx.IconFromBitmap(img.ConvertToBitmap() ) + return icon + + + def OnTaskBarActivate(self, evt): + if self.frame.IsIconized(): + self.frame.Iconize(False) + if not self.frame.IsShown(): + self.frame.Show(True) + self.frame.Raise() + + + def OnTaskBarClose(self, evt): + wx.CallAfter(self.frame.Close) + + + def OnTaskBarChange(self, evt): + names = [ "WXPdemo", "Mondrian", "Pencil", "Carrot" ] + name = names[self.imgidx] + + eImg = getattr(images, name) + self.imgidx += 1 + if self.imgidx >= len(names): + self.imgidx = 0 + + icon = self.MakeIcon(eImg.Image) + self.SetIcon(icon, "This is a new icon: " + name) + + + def OnTaskBarRemove(self, evt): + self.RemoveIcon() + + +#--------------------------------------------------------------------------- +class wxPythonDemo(wx.Frame): + + overviewText = "wxPython Demo" + + def __init__(self, parent, title): + wx.Frame.__init__(self, parent, -1, title, size = (970, 720), + style=wx.DEFAULT_FRAME_STYLE | wx.NO_FULL_REPAINT_ON_RESIZE) + + self.SetMinSize((640,480)) + + self.pnl = pnl = MainPanel(self) + + self.mgr = wx.aui.AuiManager() + self.mgr.SetManagedWindow(pnl) + + self.loaded = False + self.cwd = os.getcwd() + self.curOverview = "" + self.demoPage = None + self.codePage = None + self.shell = None + self.firstTime = True + self.finddlg = None + + icon = images.WXPdemo.GetIcon() + self.SetIcon(icon) + + try: + self.tbicon = DemoTaskBarIcon(self) + except: + self.tbicon = None + + self.otherWin = None + + self.allowDocs = False + self.downloading = False + self.internetThread = None + self.downloadImage = 2 + self.sendDownloadError = True + self.downloadTimer = wx.Timer(self, wx.ID_ANY) + + self.Bind(wx.EVT_IDLE, self.OnIdle) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + self.Bind(wx.EVT_ICONIZE, self.OnIconfiy) + self.Bind(wx.EVT_MAXIMIZE, self.OnMaximize) + self.Bind(wx.EVT_TIMER, self.OnDownloadTimer, self.downloadTimer) + + self.Centre(wx.BOTH) + + self.statusBar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + self.statusBar.SetStatusWidths([-2, -1]) + + statusText = "Welcome to wxPython %s"%version.VERSION_STRING + self.statusBar.SetStatusText(statusText, 0) + + self.downloadGauge = wx.Gauge(self.statusBar, -1, 50) + self.downloadGauge.SetToolTipString("Downloading Docs...") + self.downloadGauge.Hide() + + self.sizeChanged = False + self.Reposition() + + self.statusBar.Bind(wx.EVT_SIZE, self.OnStatusBarSize) + self.statusBar.Bind(wx.EVT_IDLE, self.OnStatusBarIdle) + + self.dying = False + self.skipLoad = False + self.allowAuiFloating = False + + def EmptyHandler(evt): pass + + self.ReadConfigurationFile() + self.externalDemos = HuntExternalDemos() + + # Create a Notebook + self.nb = wx.Notebook(pnl, -1, style=wx.CLIP_CHILDREN) + imgList = wx.ImageList(16, 16) + for png in ["overview", "code", "demo"]: + bmp = images.catalog[png].GetBitmap() + imgList.Add(bmp) + for indx in xrange(9): + bmp = images.catalog["spinning_nb%d"%indx].GetBitmap() + imgList.Add(bmp) + + self.nb.AssignImageList(imgList) + + self.BuildMenuBar() + + self.finddata = wx.FindReplaceData() + self.finddata.SetFlags(wx.FR_DOWN) + + # Create a TreeCtrl + leftPanel = wx.Panel(pnl, style=wx.TAB_TRAVERSAL|wx.CLIP_CHILDREN) + self.treeMap = {} + self.searchItems = {} + + self.tree = wxPythonDemoTree(leftPanel) + + self.filter = wx.SearchCtrl(leftPanel, style=wx.TE_PROCESS_ENTER) + self.filter.ShowCancelButton(True) + self.filter.Bind(wx.EVT_TEXT, self.RecreateTree) + self.filter.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN, + lambda e: self.filter.SetValue('')) + self.filter.Bind(wx.EVT_TEXT_ENTER, self.OnSearch) + + searchMenu = wx.Menu() + item = searchMenu.AppendRadioItem(-1, "Sample Name") + self.Bind(wx.EVT_MENU, self.OnSearchMenu, item) + item = searchMenu.AppendRadioItem(-1, "Sample Content") + self.Bind(wx.EVT_MENU, self.OnSearchMenu, item) + self.filter.SetMenu(searchMenu) + + self.RecreateTree() + self.tree.SetExpansionState(self.expansionState) + self.tree.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded) + self.tree.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed) + self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged) + self.tree.Bind(wx.EVT_LEFT_DOWN, self.OnTreeLeftDown) + + # Set up a wx.html.HtmlWindow on the Overview Notebook page + # we put it in a panel first because there seems to be a + # refresh bug of some sort (wxGTK) when it is directly in + # the notebook... + + if 0: # the old way + self.ovr = wx.html.HtmlWindow(self.nb, -1, size=(400, 400)) + self.nb.AddPage(self.ovr, self.overviewText, imageId=0) + + else: # hopefully I can remove this hacky code soon, see SF bug #216861 + panel = wx.Panel(self.nb, -1, style=wx.CLIP_CHILDREN) + self.ovr = wx.html.HtmlWindow(panel, -1, size=(400, 400)) + self.nb.AddPage(panel, self.overviewText, imageId=0) + + def OnOvrSize(evt, ovr=self.ovr): + ovr.SetSize(evt.GetSize()) + panel.Bind(wx.EVT_SIZE, OnOvrSize) + panel.Bind(wx.EVT_ERASE_BACKGROUND, EmptyHandler) + + if "gtk2" in wx.PlatformInfo: + self.ovr.SetStandardFonts() + self.SetOverview(self.overviewText, mainOverview) + + + # Set up a log window + self.log = wx.TextCtrl(pnl, -1, + style = wx.TE_MULTILINE|wx.TE_READONLY|wx.HSCROLL) + if wx.Platform == "__WXMAC__": + self.log.MacCheckSpelling(False) + + # Set the wxWindows log target to be this textctrl + #wx.Log_SetActiveTarget(wx.LogTextCtrl(self.log)) + + # But instead of the above we want to show how to use our own wx.Log class + wx.Log_SetActiveTarget(MyLog(self.log)) + + # for serious debugging + #wx.Log_SetActiveTarget(wx.LogStderr()) + #wx.Log_SetTraceMask(wx.TraceMessages) + + self.Bind(wx.EVT_ACTIVATE, self.OnActivate) + wx.GetApp().Bind(wx.EVT_ACTIVATE_APP, self.OnAppActivate) + + # add the windows to the splitter and split it. + leftBox = wx.BoxSizer(wx.VERTICAL) + leftBox.Add(self.tree, 1, wx.EXPAND) + leftBox.Add(wx.StaticText(leftPanel, label = "Filter Demos:"), 0, wx.TOP|wx.LEFT, 5) + leftBox.Add(self.filter, 0, wx.EXPAND|wx.ALL, 5) + if 'wxMac' in wx.PlatformInfo: + leftBox.Add((5,5)) # Make sure there is room for the focus ring + leftPanel.SetSizer(leftBox) + + # select initial items + self.nb.SetSelection(0) + self.tree.SelectItem(self.root) + + # Load 'Main' module + self.LoadDemo(self.overviewText) + self.loaded = True + + # select some other initial module? + if len(sys.argv) > 1: + arg = sys.argv[1] + if arg.endswith('.py'): + arg = arg[:-3] + selectedDemo = self.treeMap.get(arg, None) + if selectedDemo: + self.tree.SelectItem(selectedDemo) + self.tree.EnsureVisible(selectedDemo) + + # Use the aui manager to set up everything + self.mgr.AddPane(self.nb, wx.aui.AuiPaneInfo().CenterPane().Name("Notebook")) + self.mgr.AddPane(leftPanel, + wx.aui.AuiPaneInfo(). + Left().Layer(2).BestSize((240, -1)). + MinSize((240, -1)). + Floatable(self.allowAuiFloating).FloatingSize((240, 700)). + Caption("wxPython Demos"). + CloseButton(False). + Name("DemoTree")) + self.mgr.AddPane(self.log, + wx.aui.AuiPaneInfo(). + Bottom().BestSize((-1, 150)). + MinSize((-1, 140)). + Floatable(self.allowAuiFloating).FloatingSize((500, 160)). + Caption("Demo Log Messages"). + CloseButton(False). + Name("LogWindow")) + + self.auiConfigurations[DEFAULT_PERSPECTIVE] = self.mgr.SavePerspective() + self.mgr.Update() + + self.mgr.SetFlags(self.mgr.GetFlags() ^ wx.aui.AUI_MGR_TRANSPARENT_DRAG) + + + def ReadConfigurationFile(self): + + self.auiConfigurations = {} + self.expansionState = [0, 1] + + config = GetConfig() + val = config.Read('ExpansionState') + if val: + self.expansionState = eval(val) + + val = config.Read('AUIPerspectives') + if val: + self.auiConfigurations = eval(val) + + val = config.Read('AllowDownloads') + if val: + self.allowDocs = eval(val) + + val = config.Read('AllowAUIFloating') + if val: + self.allowAuiFloating = eval(val) + + MakeDocDirs() + pickledFile = GetDocFile() + + if not os.path.isfile(pickledFile): + self.pickledData = {} + return + + fid = open(pickledFile, "rb") + try: + self.pickledData = cPickle.load(fid) + except: + self.pickledData = {} + + fid.close() + + + def BuildMenuBar(self): + + # Make a File menu + self.mainmenu = wx.MenuBar() + menu = wx.Menu() + item = menu.Append(-1, '&Redirect Output', + 'Redirect print statements to a window', + wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnToggleRedirect, item) + + wx.App.SetMacExitMenuItemId(9123) + exitItem = wx.MenuItem(menu, 9123, 'E&xit\tCtrl-Q', 'Get the heck outta here!') + exitItem.SetBitmap(images.catalog['exit'].GetBitmap()) + menu.AppendItem(exitItem) + self.Bind(wx.EVT_MENU, self.OnFileExit, exitItem) + self.mainmenu.Append(menu, '&File') + + # Make a Demo menu + menu = wx.Menu() + for indx, item in enumerate(_treeList[:-1]): + menuItem = wx.MenuItem(menu, -1, item[0]) + submenu = wx.Menu() + for childItem in item[1]: + mi = submenu.Append(-1, childItem) + self.Bind(wx.EVT_MENU, self.OnDemoMenu, mi) + menuItem.SetBitmap(images.catalog[_demoPngs[indx+1]].GetBitmap()) + menuItem.SetSubMenu(submenu) + menu.AppendItem(menuItem) + self.mainmenu.Append(menu, '&Demo') + + # Make an Option menu + + menu = wx.Menu() + item = wx.MenuItem(menu, -1, 'Allow download of docs', 'Docs for window styles and events from the web', wx.ITEM_CHECK) + menu.AppendItem(item) + item.Check(self.allowDocs) + self.Bind(wx.EVT_MENU, self.OnAllowDownload, item) + + item = wx.MenuItem(menu, -1, 'Delete saved docs', 'Deletes the cPickle file where docs are stored') + item.SetBitmap(images.catalog['deletedocs'].GetBitmap()) + menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnDeleteDocs, item) + + menu.AppendSeparator() + item = wx.MenuItem(menu, -1, 'Allow floating panes', 'Allows the demo panes to be floated using wxAUI', wx.ITEM_CHECK) + menu.AppendItem(item) + item.Check(self.allowAuiFloating) + self.Bind(wx.EVT_MENU, self.OnAllowAuiFloating, item) + + auiPerspectives = self.auiConfigurations.keys() + auiPerspectives.sort() + perspectivesMenu = wx.Menu() + item = wx.MenuItem(perspectivesMenu, -1, DEFAULT_PERSPECTIVE, "Load startup default perspective", wx.ITEM_RADIO) + self.Bind(wx.EVT_MENU, self.OnAUIPerspectives, item) + perspectivesMenu.AppendItem(item) + for indx, key in enumerate(auiPerspectives): + if key == DEFAULT_PERSPECTIVE: + continue + item = wx.MenuItem(perspectivesMenu, -1, key, "Load user perspective %d"%indx, wx.ITEM_RADIO) + perspectivesMenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnAUIPerspectives, item) + + menu.AppendMenu(wx.ID_ANY, "&AUI Perspectives", perspectivesMenu) + self.perspectives_menu = perspectivesMenu + + item = wx.MenuItem(menu, -1, 'Save Perspective', 'Save AUI perspective') + item.SetBitmap(images.catalog['saveperspective'].GetBitmap()) + menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnSavePerspective, item) + + item = wx.MenuItem(menu, -1, 'Delete Perspective', 'Delete AUI perspective') + item.SetBitmap(images.catalog['deleteperspective'].GetBitmap()) + menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnDeletePerspective, item) + + menu.AppendSeparator() + + item = wx.MenuItem(menu, -1, 'Restore Tree Expansion', 'Restore the initial tree expansion state') + item.SetBitmap(images.catalog['expansion'].GetBitmap()) + menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnTreeExpansion, item) + + self.mainmenu.Append(menu, '&Options') + self.options_menu = menu + + # Make a Help menu + menu = wx.Menu() + findItem = wx.MenuItem(menu, -1, '&Find\tCtrl-F', 'Find in the Demo Code') + findItem.SetBitmap(images.catalog['find'].GetBitmap()) + if 'wxMac' not in wx.PlatformInfo: + findNextItem = wx.MenuItem(menu, -1, 'Find &Next\tF3', 'Find Next') + else: + findNextItem = wx.MenuItem(menu, -1, 'Find &Next\tCtrl-G', 'Find Next') + findNextItem.SetBitmap(images.catalog['findnext'].GetBitmap()) + menu.AppendItem(findItem) + menu.AppendItem(findNextItem) + menu.AppendSeparator() + + shellItem = wx.MenuItem(menu, -1, 'Open Py&Shell Window\tF5', + 'An interactive interpreter window with the demo app and frame objects in the namesapce') + shellItem.SetBitmap(images.catalog['pyshell'].GetBitmap()) + menu.AppendItem(shellItem) + inspToolItem = wx.MenuItem(menu, -1, 'Open &Widget Inspector\tF6', + 'A tool that lets you browse the live widgets and sizers in an application') + inspToolItem.SetBitmap(images.catalog['inspect'].GetBitmap()) + menu.AppendItem(inspToolItem) + if 'wxMac' not in wx.PlatformInfo: + menu.AppendSeparator() + helpItem = menu.Append(wx.ID_ABOUT, '&About wxPython Demo', 'wxPython RULES!!!') + + self.Bind(wx.EVT_MENU, self.OnOpenShellWindow, shellItem) + self.Bind(wx.EVT_MENU, self.OnOpenWidgetInspector, inspToolItem) + self.Bind(wx.EVT_MENU, self.OnHelpAbout, helpItem) + self.Bind(wx.EVT_MENU, self.OnHelpFind, findItem) + self.Bind(wx.EVT_MENU, self.OnFindNext, findNextItem) + self.Bind(wx.EVT_FIND, self.OnFind) + self.Bind(wx.EVT_FIND_NEXT, self.OnFind) + self.Bind(wx.EVT_FIND_CLOSE, self.OnFindClose) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateFindItems, findItem) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateFindItems, findNextItem) + self.mainmenu.Append(menu, '&Help') + self.SetMenuBar(self.mainmenu) + + self.EnableAUIMenu() + + if False: + # This is another way to set Accelerators, in addition to + # using the '\t' syntax in the menu items. + aTable = wx.AcceleratorTable([(wx.ACCEL_ALT, ord('X'), exitItem.GetId()), + (wx.ACCEL_CTRL, ord('H'), helpItem.GetId()), + (wx.ACCEL_CTRL, ord('F'), findItem.GetId()), + (wx.ACCEL_NORMAL, wx.WXK_F3, findNextItem.GetId()), + (wx.ACCEL_NORMAL, wx.WXK_F9, shellItem.GetId()), + ]) + self.SetAcceleratorTable(aTable) + + + #--------------------------------------------- + def RecreateTree(self, evt=None): + # Catch the search type (name or content) + searchMenu = self.filter.GetMenu().GetMenuItems() + fullSearch = searchMenu[1].IsChecked() + + if evt: + if fullSearch: + # Do not`scan all the demo files for every char + # the user input, use wx.EVT_TEXT_ENTER instead + return + + expansionState = self.tree.GetExpansionState() + + current = None + item = self.tree.GetSelection() + if item: + prnt = self.tree.GetItemParent(item) + if prnt: + current = (self.tree.GetItemText(item), + self.tree.GetItemText(prnt)) + + self.tree.Freeze() + self.tree.DeleteAllItems() + self.root = self.tree.AddRoot("wxPython Overview") + self.tree.SetItemImage(self.root, 0) + self.tree.SetItemPyData(self.root, 0) + + treeFont = self.tree.GetFont() + catFont = self.tree.GetFont() + + # The native treectrl on MSW has a bug where it doesn't draw + # all of the text for an item if the font is larger than the + # default. It seems to be clipping the item's label as if it + # was the size of the same label in the default font. + if USE_CUSTOMTREECTRL or 'wxMSW' not in wx.PlatformInfo: + treeFont.SetPointSize(treeFont.GetPointSize()+2) + + treeFont.SetWeight(wx.BOLD) + catFont.SetWeight(wx.BOLD) + self.tree.SetItemFont(self.root, treeFont) + + firstChild = None + selectItem = None + filter = self.filter.GetValue() + count = 0 + + for category, items in _treeList: + count += 1 + if filter: + if fullSearch: + items = self.searchItems[category] + else: + items = [item for item in items if filter.lower() in item.lower()] + if items: + child = self.tree.AppendItem(self.root, category, image=count) + self.tree.SetItemFont(child, catFont) + self.tree.SetItemPyData(child, count) + if not firstChild: firstChild = child + for childItem in items: + image = count + if DoesModifiedExist(childItem): + image = len(_demoPngs) + theDemo = self.tree.AppendItem(child, childItem, image=image) + self.tree.SetItemPyData(theDemo, count) + self.treeMap[childItem] = theDemo + if current and (childItem, category) == current: + selectItem = theDemo + + + self.tree.Expand(self.root) + if firstChild: + self.tree.Expand(firstChild) + if filter: + self.tree.ExpandAll() + elif expansionState: + self.tree.SetExpansionState(expansionState) + if selectItem: + self.skipLoad = True + self.tree.SelectItem(selectItem) + self.skipLoad = False + + self.tree.Thaw() + self.searchItems = {} + + + def OnStatusBarSize(self, evt): + self.Reposition() # for normal size events + + # Set a flag so the idle time handler will also do the repositioning. + # It is done this way to get around a buglet where GetFieldRect is not + # accurate during the EVT_SIZE resulting from a frame maximize. + self.sizeChanged = True + + + def OnStatusBarIdle(self, evt): + if self.sizeChanged: + self.Reposition() + + + # reposition the download gauge + def Reposition(self): + rect = self.statusBar.GetFieldRect(1) + self.downloadGauge.SetPosition((rect.x+2, rect.y+2)) + self.downloadGauge.SetSize((rect.width-4, rect.height-4)) + self.sizeChanged = False + + + def OnSearchMenu(self, event): + + # Catch the search type (name or content) + searchMenu = self.filter.GetMenu().GetMenuItems() + fullSearch = searchMenu[1].IsChecked() + + if fullSearch: + self.OnSearch() + else: + self.RecreateTree() + + + def OnSearch(self, event=None): + + value = self.filter.GetValue() + if not value: + self.RecreateTree() + return + + wx.BeginBusyCursor() + + for category, items in _treeList: + self.searchItems[category] = [] + for childItem in items: + if SearchDemo(childItem, value): + self.searchItems[category].append(childItem) + + wx.EndBusyCursor() + self.RecreateTree() + + + def SetTreeModified(self, modified): + item = self.tree.GetSelection() + if modified: + image = len(_demoPngs) + else: + image = self.tree.GetItemPyData(item) + self.tree.SetItemImage(item, image) + + + def WriteText(self, text): + if text[-1:] == '\n': + text = text[:-1] + wx.LogMessage(text) + + def write(self, txt): + self.WriteText(txt) + + #--------------------------------------------- + def OnItemExpanded(self, event): + item = event.GetItem() + wx.LogMessage("OnItemExpanded: %s" % self.tree.GetItemText(item)) + event.Skip() + + #--------------------------------------------- + def OnItemCollapsed(self, event): + item = event.GetItem() + wx.LogMessage("OnItemCollapsed: %s" % self.tree.GetItemText(item)) + event.Skip() + + #--------------------------------------------- + def OnTreeLeftDown(self, event): + # reset the overview text if the tree item is clicked on again + pt = event.GetPosition(); + item, flags = self.tree.HitTest(pt) + if item == self.tree.GetSelection(): + self.SetOverview(self.tree.GetItemText(item)+" Overview", self.curOverview) + event.Skip() + + #--------------------------------------------- + def OnSelChanged(self, event): + if self.dying or not self.loaded or self.skipLoad: + return + + self.StopDownload() + + item = event.GetItem() + itemText = self.tree.GetItemText(item) + self.LoadDemo(itemText) + + self.StartDownload() + + #--------------------------------------------- + def LoadDemo(self, demoName): + try: + wx.BeginBusyCursor() + self.pnl.Freeze() + + os.chdir(self.cwd) + self.ShutdownDemoModule() + + if demoName == self.overviewText: + # User selected the "wxPython Overview" node + # ie: _this_ module + # Changing the main window at runtime not yet supported... + self.demoModules = DemoModules(__name__) + self.SetOverview(self.overviewText, mainOverview) + self.LoadDemoSource() + self.UpdateNotebook(0) + else: + if os.path.exists(GetOriginalFilename(demoName)): + wx.LogMessage("Loading demo %s.py..." % demoName) + self.demoModules = DemoModules(demoName) + self.LoadDemoSource() + + else: + + package, overview = LookForExternals(self.externalDemos, demoName) + + if package: + wx.LogMessage("Loading demo %s.py..." % ("%s/%s"%(package, demoName))) + self.demoModules = DemoModules("%s/%s"%(package, demoName)) + self.LoadDemoSource() + elif overview: + self.SetOverview(demoName, overview) + self.codePage = None + self.UpdateNotebook(0) + else: + self.SetOverview("wxPython", mainOverview) + self.codePage = None + self.UpdateNotebook(0) + + finally: + wx.EndBusyCursor() + self.pnl.Thaw() + + #--------------------------------------------- + def LoadDemoSource(self): + self.codePage = None + self.codePage = DemoCodePanel(self.nb, self) + self.codePage.LoadDemo(self.demoModules) + + #--------------------------------------------- + def RunModule(self): + """Runs the active module""" + + module = self.demoModules.GetActive() + self.ShutdownDemoModule() + overviewText = "" + + # o The RunTest() for all samples must now return a window that can + # be palced in a tab in the main notebook. + # o If an error occurs (or has occurred before) an error tab is created. + + if module is not None: + wx.LogMessage("Running demo module...") + if hasattr(module, "overview"): + overviewText = module.overview + + try: + self.demoPage = module.runTest(self, self.nb, self) + except: + self.demoPage = DemoErrorPanel(self.nb, self.codePage, + DemoError(sys.exc_info()), self) + + bg = self.nb.GetThemeBackgroundColour() + if bg: + self.demoPage.SetBackgroundColour(bg) + + assert self.demoPage is not None, "runTest must return a window!" + + else: + # There was a previous error in compiling or exec-ing + self.demoPage = DemoErrorPanel(self.nb, self.codePage, + self.demoModules.GetErrorInfo(), self) + + self.SetOverview(self.demoModules.name + " Overview", overviewText) + + if self.firstTime: + # change to the demo page the first time a module is run + self.UpdateNotebook(2) + self.firstTime = False + else: + # otherwise just stay on the same tab in case the user has changed to another one + self.UpdateNotebook() + + #--------------------------------------------- + def ShutdownDemoModule(self): + if self.demoPage: + # inform the window that it's time to quit if it cares + if hasattr(self.demoPage, "ShutdownDemo"): + self.demoPage.ShutdownDemo() +## wx.YieldIfNeeded() # in case the page has pending events + self.demoPage = None + + #--------------------------------------------- + def UpdateNotebook(self, select = -1): + nb = self.nb + debug = False + self.pnl.Freeze() + + def UpdatePage(page, pageText): + pageExists = False + pagePos = -1 + for i in range(nb.GetPageCount()): + if nb.GetPageText(i) == pageText: + pageExists = True + pagePos = i + break + + if page: + if not pageExists: + # Add a new page + nb.AddPage(page, pageText, imageId=nb.GetPageCount()) + if debug: wx.LogMessage("DBG: ADDED %s" % pageText) + else: + if nb.GetPage(pagePos) != page: + # Reload an existing page + nb.DeletePage(pagePos) + nb.InsertPage(pagePos, page, pageText, imageId=pagePos) + if debug: wx.LogMessage("DBG: RELOADED %s" % pageText) + else: + # Excellent! No redraw/flicker + if debug: wx.LogMessage("DBG: SAVED from reloading %s" % pageText) + elif pageExists: + # Delete a page + nb.DeletePage(pagePos) + if debug: wx.LogMessage("DBG: DELETED %s" % pageText) + else: + if debug: wx.LogMessage("DBG: STILL GONE - %s" % pageText) + + if select == -1: + select = nb.GetSelection() + + UpdatePage(self.codePage, "Demo Code") + UpdatePage(self.demoPage, "Demo") + + if select >= 0 and select < nb.GetPageCount(): + nb.SetSelection(select) + + self.pnl.Thaw() + + #--------------------------------------------- + def SetOverview(self, name, text): + self.curOverview = text + lead = text[:6] + if lead != '' and lead != '': + text = '
'.join(text.split('\n')) + if wx.USE_UNICODE: + text = text.decode('iso8859_1') + self.ovr.SetPage(text) + self.nb.SetPageText(0, os.path.split(name)[1]) + + #--------------------------------------------- + + def StartDownload(self): + + if self.downloading or not self.allowDocs: + return + + item = self.tree.GetSelection() + if self.tree.ItemHasChildren(item): + return + + itemText = self.tree.GetItemText(item) + + if itemText in self.pickledData: + self.LoadDocumentation(self.pickledData[itemText]) + return + + text = self.curOverview + text += "

Checking for documentation on the wxWidgets website, please stand by...
" + + lead = text[:6] + if lead != '' and lead != '': + text = '
'.join(text.split('\n')) + + self.ovr.SetPage(text) + + self.downloadTimer.Start(100) + self.downloadGauge.Show() + self.Reposition() + self.downloading = True + self.internetThread = InternetThread(self, itemText) + + #--------------------------------------------- + + def StopDownload(self, error=None): + + self.downloadTimer.Stop() + + if not self.downloading: + return + + if error: + if self.sendDownloadError: + self.log.write("Warning: problems in downloading documentation from the wxWidgets website.\n") + self.log.write("Error message from the documentation downloader was:\n") + self.log.write("\n".join(error)) + self.sendDownloadError = False + + self.nb.SetPageImage(0, 0) + + self.internetThread.keepRunning = False + self.internetThread = None + + self.downloading = False + self.downloadGauge.Hide() + self.Reposition() + + text = self.curOverview + + lead = text[:6] + if lead != '' and lead != '': + text = '
'.join(text.split('\n')) + + self.ovr.SetPage(text) + + #--------------------------------------------- + + def LoadDocumentation(self, data): + + text = self.curOverview + addHtml = False + + if '' not in text and '' not in text: + text = '
'.join(text.split('\n')) + + styles, events, extra, appearance = data + + if appearance: + text += FormatImages(appearance) + + for names, values in zip(["Styles", "Extra Styles", "Events"], [styles, extra, events]): + if not values: + continue + + headers = (names == "Events" and [2] or [3])[0] + text += "

" + FormatDocs(names, values, headers) + + item = self.tree.GetSelection() + itemText = self.tree.GetItemText(item) + + self.pickledData[itemText] = data + + if wx.USE_UNICODE: + text = text.decode('iso8859_1') + + self.StopDownload() + self.ovr.SetPage(text) + #print "load time: ", time.time() - start + + # Menu methods + def OnFileExit(self, *event): + self.Close() + + def OnToggleRedirect(self, event): + app = wx.GetApp() + if event.Checked(): + app.RedirectStdio() + print "Print statements and other standard output will now be directed to this window." + else: + app.RestoreStdio() + print "Print statements and other standard output will now be sent to the usual location." + + + def OnAllowDownload(self, event): + + self.allowDocs = event.Checked() + if self.allowDocs: + self.StartDownload() + else: + self.StopDownload() + + + def OnDeleteDocs(self, event): + + deleteMsg = "You are about to delete the downloaded documentation.\n" + \ + "Do you want to continue?" + dlg = wx.MessageDialog(self, deleteMsg, "wxPython Demo", + wx.YES_NO | wx.NO_DEFAULT| wx.ICON_QUESTION) + result = dlg.ShowModal() + if result == wx.ID_NO: + dlg.Destroy() + return + + dlg.Destroy() + + busy = wx.BusyInfo("Deleting downloaded data...") + wx.SafeYield() + + pickledFile = GetDocFile() + docDir = os.path.split(pickledFile)[0] + + if os.path.exists(docDir): + shutil.rmtree(docDir, ignore_errors=True) + + self.pickledData = {} + del busy + self.sendDownloadError = True + + + def OnAllowAuiFloating(self, event): + + self.allowAuiFloating = event.Checked() + for pane in self.mgr.GetAllPanes(): + if pane.name != "Notebook": + pane.Floatable(self.allowAuiFloating) + + self.EnableAUIMenu() + self.mgr.Update() + + + def EnableAUIMenu(self): + + menuItems = self.options_menu.GetMenuItems() + for indx in xrange(4, len(menuItems)-1): + item = menuItems[indx] + item.Enable(self.allowAuiFloating) + + + def OnAUIPerspectives(self, event): + perspective = self.perspectives_menu.GetLabel(event.GetId()) + self.mgr.LoadPerspective(self.auiConfigurations[perspective]) + self.mgr.Update() + + + def OnSavePerspective(self, event): + dlg = wx.TextEntryDialog(self, "Enter a name for the new perspective:", "AUI Configuration") + + dlg.SetValue(("Perspective %d")%(len(self.auiConfigurations)+1)) + if dlg.ShowModal() != wx.ID_OK: + return + + perspectiveName = dlg.GetValue() + menuItems = self.perspectives_menu.GetMenuItems() + for item in menuItems: + if item.GetLabel() == perspectiveName: + wx.MessageBox("The selected perspective name:\n\n%s\n\nAlready exists."%perspectiveName, + "Error", style=wx.ICON_ERROR) + return + + item = wx.MenuItem(self.perspectives_menu, -1, dlg.GetValue(), + "Load user perspective %d"%(len(self.auiConfigurations)+1), + wx.ITEM_RADIO) + self.Bind(wx.EVT_MENU, self.OnAUIPerspectives, item) + self.perspectives_menu.AppendItem(item) + item.Check(True) + self.auiConfigurations.update({dlg.GetValue(): self.mgr.SavePerspective()}) + + + def OnDeletePerspective(self, event): + menuItems = self.perspectives_menu.GetMenuItems() + lst = [] + loadDefault = False + + for indx, item in enumerate(menuItems): + if indx > 0: + lst.append(item.GetLabel()) + + dlg = wx.MultiChoiceDialog(self, + "Please select the perspectives\nyou would like to delete:", + "Delete AUI Perspectives", lst) + + if dlg.ShowModal() == wx.ID_OK: + selections = dlg.GetSelections() + strings = [lst[x] for x in selections] + for sel in strings: + self.auiConfigurations.pop(sel) + item = menuItems[lst.index(sel)+1] + if item.IsChecked(): + loadDefault = True + self.perspectives_menu.GetMenuItems()[0].Check(True) + self.perspectives_menu.DeleteItem(item) + lst.remove(sel) + + if loadDefault: + self.mgr.LoadPerspective(self.auiConfigurations[DEFAULT_PERSPECTIVE]) + self.mgr.Update() + + + def OnTreeExpansion(self, event): + self.tree.SetExpansionState(self.expansionState) + + + def OnHelpAbout(self, event): + from About import MyAboutBox + about = MyAboutBox(self) + about.ShowModal() + about.Destroy() + + def OnHelpFind(self, event): + if self.finddlg != None: + return + + self.nb.SetSelection(1) + self.finddlg = wx.FindReplaceDialog(self, self.finddata, "Find", + wx.FR_NOMATCHCASE | wx.FR_NOWHOLEWORD) + self.finddlg.Show(True) + + + def OnUpdateFindItems(self, evt): + evt.Enable(self.finddlg == None) + + + def OnFind(self, event): + editor = self.codePage.editor + self.nb.SetSelection(1) + end = editor.GetLastPosition() + textstring = editor.GetRange(0, end).lower() + findstring = self.finddata.GetFindString().lower() + backward = not (self.finddata.GetFlags() & wx.FR_DOWN) + if backward: + start = editor.GetSelection()[0] + loc = textstring.rfind(findstring, 0, start) + else: + start = editor.GetSelection()[1] + loc = textstring.find(findstring, start) + if loc == -1 and start != 0: + # string not found, start at beginning + if backward: + start = end + loc = textstring.rfind(findstring, 0, start) + else: + start = 0 + loc = textstring.find(findstring, start) + if loc == -1: + dlg = wx.MessageDialog(self, 'Find String Not Found', + 'Find String Not Found in Demo File', + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + if self.finddlg: + if loc == -1: + self.finddlg.SetFocus() + return + else: + self.finddlg.Destroy() + self.finddlg = None + editor.ShowPosition(loc) + editor.SetSelection(loc, loc + len(findstring)) + + + + def OnFindNext(self, event): + if self.finddata.GetFindString(): + self.OnFind(event) + else: + self.OnHelpFind(event) + + def OnFindClose(self, event): + event.GetDialog().Destroy() + self.finddlg = None + + + def OnOpenShellWindow(self, evt): + if self.shell: + # if it already exists then just make sure it's visible + s = self.shell + if s.IsIconized(): + s.Iconize(False) + s.Raise() + else: + # Make a PyShell window + from wx import py + namespace = { 'wx' : wx, + 'app' : wx.GetApp(), + 'frame' : self, + } + self.shell = py.shell.ShellFrame(None, locals=namespace) + self.shell.SetSize((640,480)) + self.shell.Show() + + # Hook the close event of the main frame window so that we + # close the shell at the same time if it still exists + def CloseShell(evt): + if self.shell: + self.shell.Close() + evt.Skip() + self.Bind(wx.EVT_CLOSE, CloseShell) + + + def OnOpenWidgetInspector(self, evt): + # Activate the widget inspection tool + from wx.lib.inspection import InspectionTool + if not InspectionTool().initialized: + InspectionTool().Init() + + # Find a widget to be selected in the tree. Use either the + # one under the cursor, if any, or this frame. + wnd = wx.FindWindowAtPointer() + if not wnd: + wnd = self + InspectionTool().Show(wnd, True) + + + #--------------------------------------------- + def OnCloseWindow(self, event): + self.mgr.UnInit() + self.dying = True + self.demoPage = None + self.codePage = None + self.mainmenu = None + self.StopDownload() + + if self.tbicon is not None: + self.tbicon.Destroy() + + config = GetConfig() + config.Write('ExpansionState', str(self.tree.GetExpansionState())) + config.Write('AUIPerspectives', str(self.auiConfigurations)) + config.Write('AllowDownloads', str(self.allowDocs)) + config.Write('AllowAUIFloating', str(self.allowAuiFloating)) + + config.Flush() + + MakeDocDirs() + pickledFile = GetDocFile() + fid = open(pickledFile, "wb") + cPickle.dump(self.pickledData, fid, cPickle.HIGHEST_PROTOCOL) + fid.close() + + self.Destroy() + + + #--------------------------------------------- + def OnIdle(self, event): + if self.otherWin: + self.otherWin.Raise() + self.demoPage = self.otherWin + self.otherWin = None + + + #--------------------------------------------- + + def OnDownloadTimer(self, event): + + self.downloadGauge.Pulse() + + self.downloadImage += 1 + if self.downloadImage > 9: + self.downloadImage = 3 + + self.nb.SetPageImage(0, self.downloadImage) +## wx.SafeYield() + + #--------------------------------------------- + + def ShowTip(self): + config = GetConfig() + showTipText = config.Read("tips") + if showTipText: + showTip, index = eval(showTipText) + else: + showTip, index = (1, 0) + + if showTip: + tp = wx.CreateFileTipProvider(opj("data/tips.txt"), index) + showTip = wx.ShowTip(self, tp) + index = tp.GetCurrentTip() + config.Write("tips", str( (showTip, index) )) + config.Flush() + + #--------------------------------------------- + def OnDemoMenu(self, event): + try: + selectedDemo = self.treeMap[self.mainmenu.GetLabel(event.GetId())] + except: + selectedDemo = None + if selectedDemo: + self.tree.SelectItem(selectedDemo) + self.tree.EnsureVisible(selectedDemo) + + + #--------------------------------------------- + def OnIconfiy(self, evt): + wx.LogMessage("OnIconfiy: %s" % evt.Iconized()) + evt.Skip() + + #--------------------------------------------- + def OnMaximize(self, evt): + wx.LogMessage("OnMaximize") + evt.Skip() + + #--------------------------------------------- + def OnActivate(self, evt): + wx.LogMessage("OnActivate: %s" % evt.GetActive()) + evt.Skip() + + #--------------------------------------------- + def OnAppActivate(self, evt): + wx.LogMessage("OnAppActivate: %s" % evt.GetActive()) + evt.Skip() + +#--------------------------------------------------------------------------- +#--------------------------------------------------------------------------- + +class MySplashScreen(wx.SplashScreen): + def __init__(self): + bmp = wx.Image(opj("bitmaps/splash.png")).ConvertToBitmap() + wx.SplashScreen.__init__(self, bmp, + wx.SPLASH_CENTRE_ON_SCREEN | wx.SPLASH_TIMEOUT, + 5000, None, -1) + self.Bind(wx.EVT_CLOSE, self.OnClose) + self.fc = wx.FutureCall(2000, self.ShowMain) + + + def OnClose(self, evt): + # Make sure the default handler runs too so this window gets + # destroyed + evt.Skip() + self.Hide() + + # if the timer is still running then go ahead and show the + # main frame now + if self.fc.IsRunning(): + self.fc.Stop() + self.ShowMain() + + + def ShowMain(self): + frame = wxPythonDemo(None, "wxPython: (A Demonstration)") + frame.Show() + if self.fc.IsRunning(): + self.Raise() + wx.CallAfter(frame.ShowTip) + + + + +#--------------------------------------------------------------------------- + +from wx.lib.mixins.treemixin import ExpansionState +if USE_CUSTOMTREECTRL: + import wx.lib.customtreectrl as CT + TreeBaseClass = CT.CustomTreeCtrl +else: + TreeBaseClass = wx.TreeCtrl + + +class wxPythonDemoTree(ExpansionState, TreeBaseClass): + def __init__(self, parent): + TreeBaseClass.__init__(self, parent, style=wx.TR_DEFAULT_STYLE| + wx.TR_HAS_VARIABLE_ROW_HEIGHT) + self.BuildTreeImageList() + if USE_CUSTOMTREECTRL: + self.SetSpacing(10) + self.SetWindowStyle(self.GetWindowStyle() & ~wx.TR_LINES_AT_ROOT) + + self.SetInitialSize((100,80)) + + + def AppendItem(self, parent, text, image=-1, wnd=None): + if USE_CUSTOMTREECTRL: + item = TreeBaseClass.AppendItem(self, parent, text, image=image, wnd=wnd) + else: + item = TreeBaseClass.AppendItem(self, parent, text, image=image) + return item + + def BuildTreeImageList(self): + imgList = wx.ImageList(16, 16) + for png in _demoPngs: + imgList.Add(images.catalog[png].GetBitmap()) + + # add the image for modified demos. + imgList.Add(images.catalog["custom"].GetBitmap()) + + self.AssignImageList(imgList) + + def GetItemIdentity(self, item): + return self.GetPyData(item) + + def Freeze(self): + if 'wxMSW' in wx.PlatformInfo: + return super(wxPythonDemoTree, self).Freeze() + + def Thaw(self): + if 'wxMSW' in wx.PlatformInfo: + return super(wxPythonDemoTree, self).Thaw() + +#--------------------------------------------------------------------------- + +class MyApp(wx.App, wx.lib.mixins.inspection.InspectionMixin): + def OnInit(self): + + # Check runtime version + if version.VERSION_STRING != wx.VERSION_STRING: + wx.MessageBox(caption="Warning", + message="You're using version %s of wxPython, but this copy of the demo was written for version %s.\n" + "There may be some version incompatibilities..." + % (wx.VERSION_STRING, version.VERSION_STRING)) + + self.InitInspection() # for the InspectionMixin base class + + # Now that we've warned the user about possibile problems, + # lets import images + import images as i + global images + images = i + + # For debugging + #self.SetAssertMode(wx.PYAPP_ASSERT_DIALOG|wx.PYAPP_ASSERT_EXCEPTION) + + wx.SystemOptions.SetOptionInt("mac.window-plain-transition", 1) + self.SetAppName("wxPyDemo") + + # Create and show the splash screen. It will then create and + # show the main frame when it is time to do so. Normally when + # using a SplashScreen you would create it, show it and then + # continue on with the applicaiton's initialization, finally + # creating and showing the main application window(s). In + # this case we have nothing else to do so we'll delay showing + # the main frame until later (see ShowMain above) so the users + # can see the SplashScreen effect. + splash = MySplashScreen() + splash.Show() + + return True + + + +#--------------------------------------------------------------------------- + +def main(): + try: + demoPath = os.path.dirname(__file__) + os.chdir(demoPath) + except: + pass + app = MyApp(False) + app.MainLoop() + +#--------------------------------------------------------------------------- + + +mainOverview = """ +

wxPython

+ +

wxPython is a GUI toolkit for the Python programming +language. It allows Python programmers to create programs with a +robust, highly functional graphical user interface, simply and easily. +It is implemented as a Python extension module (native code) that +wraps the popular wxWindows cross platform GUI library, which is +written in C++. + +

Like Python and wxWindows, wxPython is Open Source which +means that it is free for anyone to use and the source code is +available for anyone to look at and modify. Or anyone can contribute +fixes or enhancements to the project. + +

wxPython is a cross-platform toolkit. This means that the +same program will run on multiple platforms without modification. +Currently supported platforms are 32-bit Microsoft Windows, most Unix +or unix-like systems, and Macintosh OS X. Since the language is +Python, wxPython programs are simple, easy to write and easy to +understand. + +

This demo is not only a collection of test cases for +wxPython, but is also designed to help you learn about and how to use +wxPython. Each sample is listed in the tree control on the left. +When a sample is selected in the tree then a module is loaded and run +(usually in a tab of this notebook,) and the source code of the module +is loaded in another tab for you to browse and learn from. + +""" + + +#---------------------------------------------------------------------------- +#---------------------------------------------------------------------------- + +if __name__ == '__main__': + __name__ = 'Main' + main() + +#---------------------------------------------------------------------------- + diff --git a/demo/Mask.py b/demo/Mask.py new file mode 100644 index 00000000..01d773f3 --- /dev/null +++ b/demo/Mask.py @@ -0,0 +1,136 @@ + +import wx + +#---------------------------------------------------------------------- + +logicList = [ + ('wx.AND', wx.AND), + ('wx.AND_INVERT', wx.AND_INVERT), + ('wx.AND_REVERSE', wx.AND_REVERSE), + ('wx.CLEAR', wx.CLEAR), + ('wx.COPY', wx.COPY), + ('wx.EQUIV', wx.EQUIV), + ('wx.INVERT', wx.INVERT), + ('wx.NAND', wx.NAND), + + ('wx.NO_OP', wx.NO_OP), + ('wx.OR', wx.OR), + ('wx.OR_INVERT', wx.OR_INVERT), + ('wx.OR_REVERSE', wx.OR_REVERSE), + ('wx.SET', wx.SET), + ('wx.SRC_INVERT', wx.SRC_INVERT), + ('wx.XOR', wx.XOR), +] + +if 'mac-cg' in wx.PlatformInfo: + # that's all, folks! + logicList = [ + ('wx.COPY', wx.COPY), + ('wx.INVERT', wx.INVERT), + ('wx.XOR', wx.XOR), + ] + +import images + +class TestMaskWindow(wx.ScrolledWindow): + def __init__(self, parent): + wx.ScrolledWindow.__init__(self, parent, -1) + self.SetBackgroundColour(wx.Colour(0,128,0)) + + # A reference bitmap that we won't mask + self.bmp_nomask = images.TestStar2.GetBitmap() + + # One that we will + self.bmp_withmask = images.TestStar2.GetBitmap() + + # this mask comes from a monochrome bitmap + self.bmp_themask = images.TestMask.GetBitmap() + mask = wx.Mask(self.bmp_themask) + + # set the mask on our bitmap + self.bmp_withmask.SetMask(mask) + + # Now we'll create a mask in a bit of an easier way, by picking a + # colour in the image that is to be the transparent colour. + self.bmp_withcolourmask = images.TestStar2.GetBitmap() + mask = wx.Mask(self.bmp_withcolourmask, wx.WHITE) + self.bmp_withcolourmask.SetMask(mask) + + self.SetScrollbars(20, 20, 700/20, 460/20) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def OnPaint (self, e): + self.SetBackgroundColour(wx.Colour(0,128,0)) + dc = wx.PaintDC(self) + self.PrepareDC(dc) + dc.SetTextForeground(wx.WHITE) + + # make an interesting background... + dc.SetPen(wx.MEDIUM_GREY_PEN) + for i in range(100): + dc.DrawLine(0,i*10, i*10,0) + + # draw raw image, mask, and masked images + dc.DrawText('original image', 0,0) + dc.DrawBitmap(self.bmp_nomask, 0,20, 0) + dc.DrawText('with colour mask', 0,100) + dc.DrawBitmap(self.bmp_withcolourmask, 0,120, 1) + dc.DrawText('the mask image', 0,200) + dc.DrawBitmap(self.bmp_themask, 0,220, 0) + dc.DrawText('masked image', 0,300) + dc.DrawBitmap(self.bmp_withmask, 0,320, 1) + + cx,cy = self.bmp_themask.GetWidth(), self.bmp_themask.GetHeight() + + # draw array of assorted blit operations + mdc = wx.MemoryDC() + i = 0 + + for text, code in logicList: + x,y = 120+150*(i%4), 20+100*(i/4) + dc.DrawText(text, x, y-20) + mdc.SelectObject(self.bmp_withcolourmask) + dc.Blit(x,y, cx,cy, mdc, 0,0, code, True) + i = i + 1 + + +# On wxGTK there needs to be a panel under wx.ScrolledWindows if they are +# going to be in a wxNotebook... +class TestPanel(wx.Panel): + def __init__(self, parent, ID): + wx.Panel.__init__(self, parent, ID) + self.win = TestMaskWindow(self) + self.Bind(wx.EVT_SIZE, self.OnSize) + + def OnSize(self, evt): + self.win.SetSize(evt.GetSize()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, -1) + return win + +#---------------------------------------------------------------------- + + +overview = """\ +This class encapsulates a monochrome mask bitmap, where the masked area is black +and the unmasked area is white. When associated with a bitmap and drawn in a device +context, the unmasked area of the bitmap will be drawn, and the masked area will +not be drawn. + +This example shows not only how to create a Mask, but the effects of the Device +Context (dc) Blit() method's logic codes. +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/MaskedEditControls.py b/demo/MaskedEditControls.py new file mode 100644 index 00000000..5923db9b --- /dev/null +++ b/demo/MaskedEditControls.py @@ -0,0 +1,647 @@ + +import string +import sys +import traceback + +import wx +import wx.lib.masked as masked +import wx.lib.scrolledpanel as scroll + + +class demoMixin: + """ + Centralized routines common to demo pages, to remove repetition. + """ + def labelGeneralTable(self, sizer): + description = wx.StaticText( self, -1, "Description", ) + mask = wx.StaticText( self, -1, "Mask Value" ) + formatcode = wx.StaticText( self, -1, "Format" ) + regex = wx.StaticText( self, -1, "Regexp Validator(opt.)" ) + ctrl = wx.StaticText( self, -1, "Masked TextCtrl" ) + + description.SetFont( wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD)) + mask.SetFont( wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD)) + formatcode.SetFont( wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD) ) + regex.SetFont( wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD)) + ctrl.SetFont( wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD)) + + sizer.Add(description) + sizer.Add(mask) + sizer.Add(formatcode) + sizer.Add(regex) + sizer.Add(ctrl) + + + def layoutGeneralTable(self, controls, sizer): + for control in controls: + sizer.Add( wx.StaticText( self, -1, control[0]) ) + sizer.Add( wx.StaticText( self, -1, control[1]) ) + sizer.Add( wx.StaticText( self, -1, control[3]) ) + sizer.Add( wx.StaticText( self, -1, control[4]) ) + + if control in controls: + newControl = masked.TextCtrl( self, -1, "", + mask = control[1], + excludeChars = control[2], + formatcodes = control[3], + includeChars = "", + validRegex = control[4], + validRange = control[5], + choices = control[6], + choiceRequired = True, + defaultValue = control[7], + demo = True, + name = control[0]) + self.editList.append(newControl) + sizer.Add(newControl) + + + def changeControlParams(self, event, parameter, checked_value, notchecked_value): + if event.IsChecked(): value = checked_value + else: value = notchecked_value + + kwargs = {parameter: value} + + for control in self.editList: + control.SetCtrlParameters(**kwargs) + control.Refresh() + + self.Refresh() + + + +#---------------------------------------------------------------------------- +class demoPage1(scroll.ScrolledPanel, demoMixin): + def __init__(self, parent, log): + scroll.ScrolledPanel.__init__(self, parent, -1) + self.sizer = wx.BoxSizer( wx.VERTICAL ) + self.editList = [] + + label = wx.StaticText( self, -1, """\ +Here are some basic masked TextCtrls to give you an idea of what you can do +with this control. Note that all controls have been auto-sized by including 'F' in +the format codes. + +Try entering nonsensical or partial values in validated fields to see what happens. +Note that the State and Last Name fields are list-limited (valid last names are: +Smith, Jones, Williams). Signs on numbers can be toggled with the minus key. +""") + label.SetForegroundColour( "Blue" ) + header = wx.BoxSizer( wx.HORIZONTAL ) + header.Add( label, 0, flag=wx.ALIGN_LEFT|wx.ALL, border = 5 ) + + highlight = wx.CheckBox( self, -1, "Highlight Empty" ) + disallow = wx.CheckBox( self, -1, "Disallow Empty" ) + showFill = wx.CheckBox( self, -1, "change fillChar" ) + + vbox = wx.BoxSizer( wx.VERTICAL ) + vbox.Add( highlight, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + vbox.Add( disallow, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + vbox.Add( showFill, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + header.Add((15, 0)) + header.Add(vbox, 0, flag=wx.ALIGN_LEFT|wx.ALL, border=5 ) + + self.Bind(wx.EVT_CHECKBOX, self.onHighlightEmpty, id=highlight.GetId()) + self.Bind(wx.EVT_CHECKBOX, self.onDisallowEmpty, id=disallow.GetId()) + self.Bind(wx.EVT_CHECKBOX, self.onShowFill, id=showFill.GetId()) + + grid = wx.FlexGridSizer( cols=5, vgap=10, hgap=10 ) + self.labelGeneralTable(grid) + + # The following list is of the controls for the demo. Feel free to play around with + # the options! + controls = [ + #description mask excl format regexp range,list,initial + ("Phone No", "(###) ###-#### x:###", "", 'F^-', "^\(\d{3}\) \d{3}-\d{4}", '','',''), + ("Social Sec#", "###-##-####", "", 'F', "\d{3}-\d{2}-\d{4}", '','',''), + ("Full Name", "C{14}", "", 'F_', '^[A-Z][a-zA-Z]+ [A-Z][a-zA-Z]+', '','',''), + ("Last Name Only", "C{14}", "", 'F {list}', '^[A-Z][a-zA-Z]+', '',('Smith','Jones','Williams'),''), + ("Zip plus 4", "#{5}-#{4}", "", 'F', "\d{5}-(\s{4}|\d{4})", '','',''), + ("Customer No", "\CAA-###", "", 'F!', "C[A-Z]{2}-\d{3}", '','',''), + ("Invoice Total", "#{9}.##", "", 'F-_,', "", '','',''), + ("Integer", "#{9}", "", 'F-_', "", '','',''), + ] + + self.layoutGeneralTable(controls, grid) + self.sizer.Add( header, 0, flag=wx.ALIGN_LEFT|wx.ALL, border=5 ) + self.sizer.Add( grid, 0, flag= wx.ALIGN_LEFT|wx.LEFT, border=5 ) + self.SetSizer(self.sizer) + self.SetupScrolling() + self.SetAutoLayout(1) + + + def onDisallowEmpty( self, event ): + """ Set emptyInvalid parameter on/off """ + self.changeControlParams( event, "emptyInvalid", True, False ) + + def onHighlightEmpty( self, event ): + """ Highlight empty values""" + self.changeControlParams( event, "emptyBackgroundColour", "Blue", "White" ) + + def onShowFill( self, event ): + """ Set fillChar parameter to '?' or ' ' """ + self.changeControlParams( event, "fillChar", '?', ' ' ) + + +class demoPage2(scroll.ScrolledPanel, demoMixin): + def __init__( self, parent, log ): + self.log = log + scroll.ScrolledPanel.__init__( self, parent, -1 ) + self.sizer = wx.BoxSizer( wx.VERTICAL ) + + label = wx.StaticText( self, -1, """\ +All these controls have been created by passing a single parameter, the autoformat code, +and use the factory class masked.Ctrl with its default controlType. +The masked package contains an internal dictionary of types and formats (autoformats). +Many of these already do complicated validation; To see some examples, try +29 Feb 2002 vs. 2004 for the date formats, or email address validation. +""") + + label.SetForegroundColour( "Blue" ) + self.sizer.Add( label, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + description = wx.StaticText( self, -1, "Description") + autofmt = wx.StaticText( self, -1, "AutoFormat Code") + ctrl = wx.StaticText( self, -1, "Masked Ctrl") + + description.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) + autofmt.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) + ctrl.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) + + grid = wx.FlexGridSizer( cols=3, vgap=10, hgap=5 ) + grid.Add( description, 0, wx.ALIGN_LEFT ) + grid.Add( autofmt, 0, wx.ALIGN_LEFT ) + grid.Add( ctrl, 0, wx.ALIGN_LEFT ) + + for autoformat, desc in masked.autoformats: + grid.Add( wx.StaticText( self, -1, desc), 0, wx.ALIGN_LEFT ) + grid.Add( wx.StaticText( self, -1, autoformat), 0, wx.ALIGN_LEFT ) + grid.Add( masked.Ctrl( self, -1, "", + autoformat = autoformat, + demo = True, + name = autoformat), + 0, wx.ALIGN_LEFT ) + + self.sizer.Add( grid, 0, wx.ALIGN_LEFT|wx.ALL, border=5 ) + self.SetSizer( self.sizer ) + self.SetAutoLayout( 1 ) + self.SetupScrolling() + + +class demoPage3(scroll.ScrolledPanel, demoMixin): + def __init__(self, parent, log): + self.log = log + scroll.ScrolledPanel.__init__(self, parent, -1) + self.sizer = wx.BoxSizer( wx.VERTICAL ) + self.editList = [] + + label = wx.StaticText( self, -1, """\ +Here masked TextCtrls that have default values. The states +control has a list of valid values, and the unsigned integer +has a legal range specified. +""") + label.SetForegroundColour( "Blue" ) + requireValid = wx.CheckBox( self, -1, "Require Valid Value" ) + self.Bind(wx.EVT_CHECKBOX, self.onRequireValid, id=requireValid.GetId()) + + header = wx.BoxSizer( wx.HORIZONTAL ) + header.Add( label, 0, flag=wx.ALIGN_LEFT|wx.ALL, border = 5) + header.Add((75, 0)) + header.Add( requireValid, 0, flag=wx.ALIGN_LEFT|wx.ALL, border=10 ) + + grid = wx.FlexGridSizer( cols=5, vgap=10, hgap=10 ) + self.labelGeneralTable( grid ) + + controls = [ + #description mask excl format regexp range,list,initial + ("U.S. State (2 char)", "AA", "", 'F!_', "[A-Z]{2}", '', masked.states, masked.states[0]), + ("Integer (signed)", "#{6}", "", 'F-_', "", '','', ' 0 '), + ("Integer (unsigned)\n(1-399)","######", "", 'F_', "", (1,399),'', '1 '), + ("Float (signed)", "#{6}.#{9}", "", 'F-_R', "", '','', '000000.000000000'), + ("Date (MDY) + Time", "##/##/#### ##:##:## AM", 'BCDEFGHIJKLMNOQRSTUVWXYZ','DF!',"", '','', wx.DateTime_Now().Format("%m/%d/%Y %I:%M:%S %p")), + ] + self.layoutGeneralTable( controls, grid ) + + self.sizer.Add( header, 0, flag=wx.ALIGN_LEFT|wx.ALL, border=5 ) + self.sizer.Add( grid, 0, flag=wx.ALIGN_LEFT|wx.ALL, border=5 ) + + self.SetSizer( self.sizer ) + self.SetAutoLayout( 1 ) + self.SetupScrolling() + + def onRequireValid( self, event ): + """ Set validRequired parameter on/off """ + self.changeControlParams( event, "validRequired", True, False ) + + +class demoPage4(scroll.ScrolledPanel, demoMixin): + def __init__( self, parent, log ): + self.log = log + scroll.ScrolledPanel.__init__( self, parent, -1 ) + self.sizer = wx.BoxSizer( wx.VERTICAL ) + + label = wx.StaticText( self, -1, """\ +These controls have field-specific choice lists and allow autocompletion. + +Down arrow or Page Down in an uncompleted field with an auto-completable field will attempt +to auto-complete a field if it has a choice list. +Page Down and Shift-Down arrow will also auto-complete, or cycle through the complete list. +Page Up and Shift-Up arrow will similarly cycle backwards through the list. +""") + + label.SetForegroundColour( "Blue" ) + self.sizer.Add( label, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + description = wx.StaticText( self, -1, "Description" ) + autofmt = wx.StaticText( self, -1, "AutoFormat Code" ) + fields = wx.StaticText( self, -1, "Field Objects" ) + ctrl = wx.StaticText( self, -1, "Masked TextCtrl" ) + + description.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) + autofmt.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) + fields.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) + ctrl.SetFont( wx.Font( 9, wx.SWISS, wx.NORMAL, wx.BOLD ) ) + + grid = wx.FlexGridSizer( cols=4, vgap=10, hgap=10 ) + grid.Add( description, 0, wx.ALIGN_LEFT ) + grid.Add( autofmt, 0, wx.ALIGN_LEFT ) + grid.Add( fields, 0, wx.ALIGN_LEFT ) + grid.Add( ctrl, 0, wx.ALIGN_LEFT ) + + autoformat = "USPHONEFULLEXT" + fieldsDict = {0: masked.Field(choices=["617","781","508","978","413"], choiceRequired=True)} + fieldsLabel = """\ +{0: Field(choices=[ + "617","781", + "508","978","413"], + choiceRequired=True)}""" + grid.Add( wx.StaticText( self, -1, "Restricted Area Code"), 0, wx.ALIGN_LEFT ) + grid.Add( wx.StaticText( self, -1, autoformat), 0, wx.ALIGN_LEFT ) + grid.Add( wx.StaticText( self, -1, fieldsLabel), 0, wx.ALIGN_LEFT ) + grid.Add( masked.TextCtrl( self, -1, "", + autoformat = autoformat, + fields = fieldsDict, + demo = True, + name = autoformat), + 0, wx.ALIGN_LEFT ) + + autoformat = "EXPDATEMMYY" + fieldsDict = {1: masked.Field(choices=["03", "04", "05"], choiceRequired=True)} + fieldsLabel = """\ +{1: Field(choices=[ + "03", "04", "05"], + choiceRequired=True)}""" + exp = masked.TextCtrl( self, -1, "", + autoformat = autoformat, + fields = fieldsDict, + demo = True, + name = autoformat) + + grid.Add( wx.StaticText( self, -1, "Restricted Expiration"), 0, wx.ALIGN_LEFT ) + grid.Add( wx.StaticText( self, -1, autoformat), 0, wx.ALIGN_LEFT ) + grid.Add( wx.StaticText( self, -1, fieldsLabel), 0, wx.ALIGN_LEFT ) + grid.Add( exp, 0, wx.ALIGN_LEFT ) + + fieldsDict = {0: masked.Field(choices=["02134","02155"], choiceRequired=True), + 1: masked.Field(choices=["1234", "5678"], choiceRequired=False)} + fieldsLabel = """\ +{0: Field(choices=["02134","02155"], + choiceRequired=True), + 1: Field(choices=["1234", "5678"], + choiceRequired=False)}""" + autoformat = "USZIPPLUS4" + zip = masked.TextCtrl( self, -1, "", + autoformat = autoformat, + fields = fieldsDict, + demo = True, + name = autoformat) + + grid.Add( wx.StaticText( self, -1, "Restricted Zip + 4"), 0, wx.ALIGN_LEFT ) + grid.Add( wx.StaticText( self, -1, autoformat), 0, wx.ALIGN_LEFT ) + grid.Add( wx.StaticText( self, -1, fieldsLabel), 0, wx.ALIGN_LEFT ) + grid.Add( zip, 0, wx.ALIGN_LEFT ) + + self.sizer.Add( grid, 0, wx.ALIGN_LEFT|wx.ALL, border=5 ) + self.SetSizer( self.sizer ) + self.SetAutoLayout(1) + self.SetupScrolling() + + +class demoPage5(scroll.ScrolledPanel, demoMixin): + def __init__( self, parent, log ): + self.log = log + scroll.ScrolledPanel.__init__( self, parent, -1 ) + self.sizer = wx.BoxSizer( wx.VERTICAL ) + + + labelMaskedCombos = wx.StaticText( self, -1, """\ +These are some examples of masked.ComboBox:""") + labelMaskedCombos.SetForegroundColour( "Blue" ) + + + label_statecode = wx.StaticText( self, -1, """\ +A state selector; only +"legal" values can be +entered:""") + statecode = masked.ComboBox( self, -1, masked.states[0], + choices = masked.states, + autoformat="USSTATE") + + label_statename = wx.StaticText( self, -1, """\ +A state name selector, +with auto-select:""") + + # Create this one using factory function: + statename = masked.Ctrl( self, -1, masked.state_names[0], + controlType = masked.controlTypes.COMBO, + choices = masked.state_names, + autoformat="USSTATENAME", + autoSelect=True) + statename.SetCtrlParameters(formatcodes = 'F!V_') + + + numerators = [ str(i) for i in range(1, 4) ] + denominators = [ string.ljust(str(i), 2) for i in [2,3,4,5,8,16,32,64] ] + fieldsDict = {0: masked.Field(choices=numerators, choiceRequired=False), + 1: masked.Field(choices=denominators, choiceRequired=True)} + choices = [] + for n in numerators: + for d in denominators: + if n != d: + choices.append( '%s/%s' % (n,d) ) + + + label_fraction = wx.StaticText( self, -1, """\ +A masked ComboBox for fraction selection. +Choices for each side of the fraction can +be selected with PageUp/Down:""") + + fraction = masked.Ctrl( self, -1, "", + controlType = masked.controlTypes.COMBO, + choices = choices, + choiceRequired = True, + mask = "#/##", + formatcodes = "F_", + validRegex = "^\d\/\d\d?", + fields = fieldsDict ) + + + label_code = wx.StaticText( self, -1, """\ +A masked ComboBox to validate +text from a list of numeric codes:""") + + choices = ["91", "136", "305", "4579"] + code = masked.ComboBox( self, -1, choices[0], + choices = choices, + choiceRequired = True, + formatcodes = "F_r", + mask = "####") + + label_selector = wx.StaticText( self, -1, """\ +Programmatically set +choice sets:""") + self.list_selector = wx.ComboBox(self, -1, '', choices = ['list1', 'list2', 'list3']) + self.dynamicbox = masked.Ctrl( self, -1, ' ', + controlType = masked.controlTypes.COMBO, + mask = 'XXXX', + formatcodes = 'F_', + # these are to give dropdown some initial height, + # as base control apparently only sets that size + # during initial construction : + choices = ['', '1', '2', '3', '4', '5'] ) + + self.dynamicbox.Clear() # get rid of initial choices used to size the dropdown + + + labelIpAddrs = wx.StaticText( self, -1, """\ +Here are some examples of IpAddrCtrl, a control derived from masked.TextCtrl:""") + labelIpAddrs.SetForegroundColour( "Blue" ) + + + label_ipaddr1 = wx.StaticText( self, -1, "An empty control:") + ipaddr1 = masked.IpAddrCtrl( self, -1, style = wx.TE_PROCESS_TAB ) + + + label_ipaddr2 = wx.StaticText( self, -1, "A restricted mask:") + ipaddr2 = masked.IpAddrCtrl( self, -1, mask=" 10. 1.109.###" ) + + + label_ipaddr3 = wx.StaticText( self, -1, """\ +A control with restricted legal values: +10. (1|2) . (129..255) . (0..255)""") + ipaddr3 = masked.Ctrl( self, -1, + controlType = masked.controlTypes.IPADDR, + mask=" 10. #.###.###") + ipaddr3.SetFieldParameters(0, validRegex="1|2",validRequired=False ) # requires entry to match or not allowed + + # This allows any value in penultimate field, but colors anything outside of the range invalid: + ipaddr3.SetFieldParameters(1, validRange=(129,255), validRequired=False ) + + + + labelNumerics = wx.StaticText( self, -1, """\ +Here are some useful configurations of a masked.TextCtrl for integer and floating point input that still treat +the control as a text control. (For a true numeric control, check out the masked.NumCtrl class!)""") + labelNumerics.SetForegroundColour( "Blue" ) + + label_intctrl1 = wx.StaticText( self, -1, """\ +An integer entry control with +shifting insert enabled:""") + self.intctrl1 = masked.TextCtrl(self, -1, name='intctrl', mask="#{9}", formatcodes = '_-,F>') + label_intctrl2 = wx.StaticText( self, -1, """\ + Right-insert integer entry:""") + self.intctrl2 = masked.TextCtrl(self, -1, name='intctrl', mask="#{9}", formatcodes = '_-,Fr') + + label_floatctrl = wx.StaticText( self, -1, """\ +A floating point entry control +with right-insert for ordinal:""") + self.floatctrl = masked.TextCtrl(self, -1, name='floatctrl', mask="#{9}.#{2}", formatcodes="F,_-R", useParensForNegatives=False) + self.floatctrl.SetFieldParameters(0, formatcodes='r<', validRequired=True) # right-insert, require explicit cursor movement to change fields + self.floatctrl.SetFieldParameters(1, defaultValue='00') # don't allow blank fraction + + label_numselect = wx.StaticText( self, -1, """\ +<= Programmatically set the value + of the float entry ctrl:""") + numselect = wx.ComboBox(self, -1, choices = [ '', '111', '222.22', '-3', '54321.666666666', '-1353.978', + '1234567', '-1234567', '123456789', '-123456789.1', + '1234567890.', '-1234567890.1' ]) + + parens_check = wx.CheckBox(self, -1, "Use () to indicate negatives in above controls") + + + + gridCombos = wx.FlexGridSizer( cols=4, vgap=10, hgap = 10 ) + gridCombos.Add( label_statecode, 0, wx.ALIGN_LEFT ) + gridCombos.Add( statecode, 0, wx.ALIGN_LEFT ) + gridCombos.Add( label_fraction, 0, wx.ALIGN_LEFT ) + gridCombos.Add( fraction, 0, wx.ALIGN_LEFT ) + gridCombos.Add( label_statename, 0, wx.ALIGN_LEFT ) + gridCombos.Add( statename, 0, wx.ALIGN_LEFT ) + gridCombos.Add( label_code, 0, wx.ALIGN_LEFT ) + gridCombos.Add( code, 0, wx.ALIGN_LEFT ) + gridCombos.Add( label_selector, 0, wx.ALIGN_LEFT) + hbox = wx.BoxSizer( wx.HORIZONTAL ) + hbox.Add( self.list_selector, 0, wx.ALIGN_LEFT ) + hbox.Add(wx.StaticText(self, -1, ' => '), 0, wx.ALIGN_LEFT) + hbox.Add( self.dynamicbox, 0, wx.ALIGN_LEFT ) + gridCombos.Add( hbox, 0, wx.ALIGN_LEFT ) + + gridIpAddrs = wx.FlexGridSizer( cols=4, vgap=10, hgap = 15 ) + gridIpAddrs.Add( label_ipaddr1, 0, wx.ALIGN_LEFT ) + gridIpAddrs.Add( ipaddr1, 0, wx.ALIGN_LEFT ) + gridIpAddrs.Add( label_ipaddr2, 0, wx.ALIGN_LEFT ) + gridIpAddrs.Add( ipaddr2, 0, wx.ALIGN_LEFT ) + gridIpAddrs.Add( label_ipaddr3, 0, wx.ALIGN_LEFT ) + gridIpAddrs.Add( ipaddr3, 0, wx.ALIGN_LEFT ) + + gridNumerics = wx.FlexGridSizer( cols=4, vgap=10, hgap = 10 ) + gridNumerics.Add( label_intctrl1, 0, wx.ALIGN_LEFT ) + gridNumerics.Add( self.intctrl1, 0, wx.ALIGN_LEFT ) + gridNumerics.Add( label_intctrl2, 0, wx.ALIGN_RIGHT ) + gridNumerics.Add( self.intctrl2, 0, wx.ALIGN_LEFT ) + gridNumerics.Add( label_floatctrl, 0, wx.ALIGN_LEFT ) + gridNumerics.Add( self.floatctrl, 0, wx.ALIGN_LEFT ) + gridNumerics.Add( label_numselect, 0, wx.ALIGN_RIGHT ) + gridNumerics.Add( numselect, 0, wx.ALIGN_LEFT ) + + self.sizer.Add( labelMaskedCombos, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + self.sizer.Add( gridCombos, 0, wx.ALIGN_LEFT|wx.ALL, border=5 ) + self.sizer.Add( wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, border=8 ) + self.sizer.Add( labelIpAddrs, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + self.sizer.Add( gridIpAddrs, 0, wx.ALIGN_LEFT|wx.ALL, border=5 ) + self.sizer.Add( wx.StaticLine(self, -1), 0, wx.EXPAND|wx.TOP|wx.BOTTOM, border=8 ) + self.sizer.Add( labelNumerics, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + self.sizer.Add( gridNumerics, 0, wx.ALIGN_LEFT|wx.ALL, border=5 ) + self.sizer.Add( parens_check, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + self.SetSizer( self.sizer ) + self.SetAutoLayout(1) + self.SetupScrolling() + + self.Bind(wx.EVT_COMBOBOX, self.OnComboSelection, id=fraction.GetId()) + self.Bind(wx.EVT_COMBOBOX, self.OnComboSelection, id=code.GetId()) + self.Bind(wx.EVT_COMBOBOX, self.OnComboSelection, id=statecode.GetId()) + self.Bind(wx.EVT_COMBOBOX, self.OnComboSelection, id=statename.GetId()) + self.Bind(wx.EVT_TEXT, self.OnTextChange, id=code.GetId()) + self.Bind(wx.EVT_TEXT, self.OnTextChange, id=statecode.GetId()) + self.Bind(wx.EVT_TEXT, self.OnTextChange, id=statename.GetId()) + self.Bind(wx.EVT_COMBOBOX, self.OnListSelection, id=self.list_selector.GetId()) + + self.Bind(wx.EVT_TEXT, self.OnTextChange, id=self.intctrl1.GetId()) + self.Bind(wx.EVT_TEXT, self.OnTextChange, id=self.intctrl2.GetId()) + self.Bind(wx.EVT_TEXT, self.OnTextChange, id=self.floatctrl.GetId()) + self.Bind(wx.EVT_COMBOBOX, self.OnNumberSelect, id=numselect.GetId()) + self.Bind(wx.EVT_CHECKBOX, self.OnParensCheck, id=parens_check.GetId()) + + self.Bind(wx.EVT_TEXT, self.OnIpAddrChange, id=ipaddr1.GetId()) + self.Bind(wx.EVT_TEXT, self.OnIpAddrChange, id=ipaddr2.GetId()) + self.Bind(wx.EVT_TEXT, self.OnIpAddrChange, id=ipaddr3.GetId()) + + + + + def OnComboSelection( self, event ): + ctl = self.FindWindowById( event.GetId() ) + if not ctl.IsValid(): + self.log.write('current value not a valid choice') + self.log.write('new value = %s' % ctl.GetValue()) + + def OnTextChange( self, event ): + ctl = self.FindWindowById( event.GetId() ) + if ctl.IsValid(): + self.log.write('new value = %s\n' % ctl.GetValue() ) + + def OnNumberSelect( self, event ): + value = event.GetString() + # Format choice to fit into format for #{9}.#{2}, with sign position reserved: + # (ordinal + fraction == 11 + decimal point + sign == 13) + if value: + floattext = "%13.2f" % float(value) + else: + floattext = value # clear the value again + try: + self.floatctrl.SetValue(floattext) + except: + type, value, tb = sys.exc_info() + for line in traceback.format_exception_only(type, value): + self.log.write(line) + + def OnParensCheck( self, event ): + self.intctrl1.SetCtrlParameters(useParensForNegatives=event.IsChecked()) + self.intctrl2.SetCtrlParameters(useParensForNegatives=event.IsChecked()) + self.floatctrl.SetCtrlParameters(useParensForNegatives=event.IsChecked()) + + def OnIpAddrChange( self, event ): + ipaddr = self.FindWindowById( event.GetId() ) + if ipaddr.IsValid(): + self.log.write('new addr = %s\n' % ipaddr.GetAddress() ) + + def OnListSelection( self, event ): + list = self.list_selector.GetStringSelection() + formatcodes = 'F_' + if list == 'list1': + choices = ['abc', 'defg', 'hi'] + mask = 'aaaa' + elif list == 'list2': + choices = ['1', '2', '34', '567'] + formatcodes += 'r' + mask = '###' + else: + choices = masked.states + mask = 'AA' + formatcodes += '!' + self.dynamicbox.SetCtrlParameters( mask = mask, + choices = choices, + choiceRequired=True, + autoSelect=True, + formatcodes=formatcodes) + self.dynamicbox.SetValue(choices[0]) + +# --------------------------------------------------------------------- +class TestMaskedTextCtrls(wx.Notebook): + def __init__(self, parent, id, log): + wx.Notebook.__init__(self, parent, id) + self.log = log + + win = demoPage1(self, log) + self.AddPage(win, "General examples") + + win = demoPage2(self, log) + self.AddPage(win, 'Auto-formatted controls') + + win = demoPage3(self, log) + self.AddPage(win, "Using default values") + + win = demoPage4(self, log) + self.AddPage(win, 'Using auto-complete fields') + + win = demoPage5(self, log) + self.AddPage(win, 'Other masked controls') + + +#---------------------------------------------------------------------------- + +def runTest(frame, nb, log): + testWin = TestMaskedTextCtrls(nb, -1, log) + return testWin + +def RunStandalone(): + app = wx.PySimpleApp() + frame = wx.Frame(None, -1, "Test MaskedEditCtrls", size=(640, 480)) + win = TestMaskedTextCtrls(frame, -1, sys.stdout) + frame.Show(True) + app.MainLoop() +#---------------------------------------------------------------------------- +import wx.lib.masked.maskededit as maskededit +# strip out module header used for pydoc: +demodoc = '\n'.join(maskededit.__doc__.split('\n')[2:]) +overview = """ +


+""" + demodoc + """
+
+""" + +if __name__ == "__main__": + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/MaskedNumCtrl.py b/demo/MaskedNumCtrl.py new file mode 100644 index 00000000..c009529b --- /dev/null +++ b/demo/MaskedNumCtrl.py @@ -0,0 +1,358 @@ + +import string +import sys +import traceback + +import wx +from wx.lib import masked + +#---------------------------------------------------------------------- + +class TestPanel( wx.Panel ): + def __init__( self, parent, log ): + + wx.Panel.__init__( self, parent, -1 ) + self.log = log + panel = wx.Panel( self, -1 ) + + header = wx.StaticText(panel, -1, """\ +This shows the various options for masked.NumCtrl. +The controls at the top reconfigure the resulting control at the bottom. +""") + header.SetForegroundColour( "Blue" ) + + intlabel = wx.StaticText( panel, -1, "Integer width:" ) + self.integerwidth = masked.NumCtrl( + panel, value=10, integerWidth=2, allowNegative=False + ) + + fraclabel = wx.StaticText( panel, -1, "Fraction width:" ) + self.fractionwidth = masked.NumCtrl( + panel, value=0, integerWidth=2, allowNegative=False + ) + + groupcharlabel = wx.StaticText( panel,-1, "Grouping char:" ) + self.groupchar = masked.TextCtrl( + panel, -1, value=',', mask='*', includeChars = ' ', excludeChars = '-()0123456789', + formatcodes='F', emptyInvalid=False, validRequired=True + ) + + decimalcharlabel = wx.StaticText( panel,-1, "Decimal char:" ) + self.decimalchar = masked.TextCtrl( + panel, -1, value='.', mask='&', excludeChars = '-()', + formatcodes='F', emptyInvalid=True, validRequired=True + ) + + self.set_min = wx.CheckBox( panel, -1, "Set minimum value:" ) + # Create this masked.NumCtrl using factory, to show how: + self.min = masked.Ctrl( panel, integerWidth=5, fractionWidth=2, controlType=masked.controlTypes.NUMBER ) + self.min.Enable( False ) + + self.set_max = wx.CheckBox( panel, -1, "Set maximum value:" ) + self.max = masked.NumCtrl( panel, integerWidth=5, fractionWidth=2 ) + self.max.Enable( False ) + + + self.limit_target = wx.CheckBox( panel, -1, "Limit control" ) + self.limit_on_field_change = wx.CheckBox( panel, -1, "Limit on field change" ) + self.allow_none = wx.CheckBox( panel, -1, "Allow empty control" ) + self.group_digits = wx.CheckBox( panel, -1, "Group digits" ) + self.group_digits.SetValue( True ) + self.allow_negative = wx.CheckBox( panel, -1, "Allow negative values" ) + self.allow_negative.SetValue( True ) + self.use_parens = wx.CheckBox( panel, -1, "Use parentheses" ) + self.select_on_entry = wx.CheckBox( panel, -1, "Select on entry" ) + self.select_on_entry.SetValue( True ) + + label = wx.StaticText( panel, -1, "Resulting numeric control:" ) + font = label.GetFont() + font.SetWeight(wx.BOLD) + label.SetFont(font) + + self.target_ctl = masked.NumCtrl( panel, -1, name="target control" ) + + label_numselect = wx.StaticText( panel, -1, """\ +Programmatically set the above +value entry ctrl:""") + self.numselect = wx.ComboBox(panel, -1, choices = [ '0', '111', '222.22', '-3', '54321.666666666', '-1353.978', + '1234567', '-1234567', '123456789', '-123456789.1', + '1234567890.', '-9876543210.9' ]) + + grid1 = wx.FlexGridSizer( cols=4 ) + grid1.Add( intlabel, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + grid1.Add( self.integerwidth, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + grid1.Add( groupcharlabel, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + grid1.Add( self.groupchar, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + grid1.Add( fraclabel, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + grid1.Add( self.fractionwidth, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + grid1.Add( decimalcharlabel, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + grid1.Add( self.decimalchar, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + grid1.Add( self.set_min, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + grid1.Add( self.min, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid1.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + grid1.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + + grid1.Add( self.set_max, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + grid1.Add( self.max, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid1.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + grid1.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + + + grid1.Add( self.limit_target, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid1.Add( self.limit_on_field_change, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + hbox1 = wx.BoxSizer( wx.HORIZONTAL ) + hbox1.Add( (17,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + hbox1.Add( self.allow_none, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid1.Add( hbox1, 0, wx.ALIGN_LEFT|wx.ALL, 5) + grid1.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + + grid1.Add( self.group_digits, 0, wx.ALIGN_LEFT|wx.LEFT, 5 ) + grid1.Add( self.allow_negative, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + hbox2 = wx.BoxSizer( wx.HORIZONTAL ) + hbox2.Add( (17,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + hbox2.Add( self.use_parens, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid1.Add( hbox2, 0, wx.ALIGN_LEFT|wx.ALL, 5) + grid1.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + + grid1.Add( self.select_on_entry, 0, wx.ALIGN_LEFT|wx.LEFT, 5 ) + grid1.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + grid1.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + grid1.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + + grid2 = wx.FlexGridSizer( cols=2 ) + grid2.Add( label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + grid2.Add( self.target_ctl, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid2.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + grid2.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + grid2.Add( label_numselect, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + grid2.Add( self.numselect, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid2.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + grid2.Add( (5,5), 0, wx.ALIGN_LEFT|wx.ALL, 5) + grid2.AddGrowableCol(1) + + self.outer_box = wx.BoxSizer( wx.VERTICAL ) + self.outer_box.Add(header, 0, wx.ALIGN_LEFT|wx.TOP|wx.LEFT, 20) + self.outer_box.Add( grid1, 0, wx.ALIGN_CENTRE|wx.LEFT|wx.BOTTOM|wx.RIGHT, 20 ) + self.outer_box.Add( grid2, 0, wx.ALIGN_LEFT|wx.ALL, 20 ) + self.grid2 = grid2 + + panel.SetAutoLayout( True ) + panel.SetSizer( self.outer_box ) + self.outer_box.Fit( panel ) + panel.Move( (50,10) ) + self.panel = panel + + self.Bind(masked.EVT_NUM, self.OnSetIntWidth, self.integerwidth ) + self.Bind(masked.EVT_NUM, self.OnSetFractionWidth, self.fractionwidth ) + self.Bind(wx.EVT_TEXT, self.OnSetGroupChar, self.groupchar ) + self.Bind(wx.EVT_TEXT, self.OnSetDecimalChar, self.decimalchar ) + + self.Bind(wx.EVT_CHECKBOX, self.OnSetMin, self.set_min ) + self.Bind(wx.EVT_CHECKBOX, self.OnSetMax, self.set_max ) + self.Bind(masked.EVT_NUM, self.SetTargetMinMax, self.min ) + self.Bind(masked.EVT_NUM, self.SetTargetMinMax, self.max ) + + self.Bind(wx.EVT_CHECKBOX, self.OnSetLimited, self.limit_target ) + self.Bind(wx.EVT_CHECKBOX, self.OnSetLimitOnFieldChange, self.limit_on_field_change ) + self.Bind(wx.EVT_CHECKBOX, self.OnSetAllowNone, self.allow_none ) + self.Bind(wx.EVT_CHECKBOX, self.OnSetGroupDigits, self.group_digits ) + self.Bind(wx.EVT_CHECKBOX, self.OnSetAllowNegative, self.allow_negative ) + self.Bind(wx.EVT_CHECKBOX, self.OnSetUseParens, self.use_parens ) + self.Bind(wx.EVT_CHECKBOX, self.OnSetSelectOnEntry, self.select_on_entry ) + + self.Bind(masked.EVT_NUM, self.OnTargetChange, self.target_ctl ) + self.Bind(wx.EVT_COMBOBOX, self.OnNumberSelect, self.numselect ) + + + def OnSetIntWidth(self, event ): + width = self.integerwidth.GetValue() + + if width < 1: + self.log.write("integer width must be positive\n") + self.integerwidth.SetForegroundColour(wx.RED) + else: + self.integerwidth.SetForegroundColour(wx.BLACK) + self.log.write("setting integer width to %d\n" % width) + self.target_ctl.SetParameters( integerWidth = width) + # Now resize and fit the dialog as appropriate: + self.grid2.SetItemMinSize(self.target_ctl, self.target_ctl.GetSize()) + self.outer_box.Fit( self.panel ) + self.outer_box.SetSizeHints( self.panel ) + + + def OnSetFractionWidth(self, event ): + width = self.fractionwidth.GetValue() + self.log.write("setting fraction width to %d\n" % width) + self.target_ctl.SetParameters( fractionWidth = width) + # Now resize and fit the dialog as appropriate: + self.grid2.SetItemMinSize(self.target_ctl, self.target_ctl.GetSize()) + self.outer_box.Fit( self.panel ) + self.outer_box.SetSizeHints( self.panel ) + + + def OnSetGroupChar( self, event ): + char = self.groupchar.GetValue() + if self.target_ctl.GetDecimalChar() == char: + self.log.write("group and decimal chars must be different\n") + self.groupchar.SetForegroundColour(wx.RED) + else: + self.groupchar.SetForegroundColour(wx.BLACK) + self.log.write("setting group char to %s\n" % char) + self.target_ctl.SetGroupChar( char ) + + def OnSetDecimalChar( self, event ): + char = self.decimalchar.GetValue() + if self.target_ctl.GetGroupChar() == char: + self.log.write("group and decimal chars must be different\n") + self.decimalchar.SetForegroundColour(wx.RED) + else: + self.decimalchar.SetForegroundColour(wx.BLACK) + self.log.write("setting decimal char to %s\n" % char) + self.target_ctl.SetDecimalChar( char ) + + + def OnSetMin( self, event ): + self.min.Enable( self.set_min.GetValue() ) + self.SetTargetMinMax() + + def OnSetMax( self, event ): + self.max.Enable( self.set_max.GetValue() ) + self.SetTargetMinMax() + + + def OnSetLimited( self, event ): + limited = self.limit_target.GetValue() + self.target_ctl.SetLimited( limited ) + limit_on_field_change = self.limit_on_field_change.GetValue() + if limited and limit_on_field_change: + self.limit_on_field_change.SetValue(False) + self.target_ctl.SetLimitOnFieldChange( False ) + self.SetTargetMinMax() + + + def OnSetLimitOnFieldChange( self, event ): + limit_on_field_change = self.limit_on_field_change.GetValue() + self.target_ctl.SetLimitOnFieldChange( limit_on_field_change ) + limited = self.limit_target.GetValue() + if limited and limit_on_field_change: + self.limit_target.SetValue(False) + self.target_ctl.SetLimited( False ) + + def SetTargetMinMax( self, event=None ): + min = max = None + if self.set_min.GetValue(): + min = self.min.GetValue() + if self.set_max.GetValue(): + max = self.max.GetValue() + + cur_min, cur_max = self.target_ctl.GetBounds() + + if min != cur_min and not self.target_ctl.SetMin( min ): + if self.target_ctl.GetMax() is None and cur_max > min: + self.log.write( "min (%d) won't fit in control -- bound not set\n" % min ) + else: + self.log.write( "min (%d) > current max (%d) -- bound not set\n" % ( min, self.target_ctl.GetMax() ) ) + self.min.SetParameters( signedForegroundColour=wx.RED, foregroundColour=wx.RED ) + else: + self.min.SetParameters( signedForegroundColour=wx.BLACK, foregroundColour=wx.BLACK ) + self.min.Refresh() + + if max != cur_max and not self.target_ctl.SetMax( max ): + if self.target_ctl.GetMax() is None and cur_min < max: + self.log.write( "max (%d) won't fit in control -- bound not set\n" % max ) + else: + self.log.write( "max (%d) < current min (%d) -- bound not set\n" % ( max, self.target_ctl.GetMin() ) ) + self.max.SetParameters( signedForegroundColour=wx.RED, foregroundColour=wx.RED ) + else: + self.max.SetParameters( signedForegroundColour=wx.BLACK, foregroundColour=wx.BLACK ) + self.max.Refresh() + + if min != cur_min or max != cur_max: + new_min, new_max = self.target_ctl.GetBounds() + self.log.write( "current min, max: (%s, %s)\n" % ( str(new_min), str(new_max) ) ) + + + def OnSetAllowNone( self, event ): + self.target_ctl.SetAllowNone( self.allow_none.GetValue() ) + + + def OnSetGroupDigits( self, event ): + self.target_ctl.SetGroupDigits( self.group_digits.GetValue() ) + # Now resize and fit the dialog as appropriate: + self.grid2.SetItemMinSize(self.target_ctl, self.target_ctl.GetSize()) + self.outer_box.Fit( self.panel ) + self.outer_box.SetSizeHints( self.panel ) + + + def OnSetAllowNegative( self, event ): + if self.allow_negative.GetValue(): + self.use_parens.Enable(True) + self.target_ctl.SetParameters(allowNegative=True, + useParensForNegatives = self.use_parens.GetValue()) + else: + self.target_ctl.SetAllowNegative(False) + # Now resize and fit the dialog as appropriate: + self.grid2.SetItemMinSize(self.target_ctl, self.target_ctl.GetSize()) + self.outer_box.Fit( self.panel ) + self.outer_box.SetSizeHints( self.panel ) + + + def OnSetUseParens( self, event ): + self.target_ctl.SetUseParensForNegatives( self.use_parens.GetValue() ) + # Now resize and fit the dialog as appropriate: + self.grid2.SetItemMinSize(self.target_ctl, self.target_ctl.GetSize()) + self.outer_box.Fit( self.panel ) + self.outer_box.SetSizeHints( self.panel ) + + + def OnSetSelectOnEntry( self, event ): + self.target_ctl.SetSelectOnEntry( self.select_on_entry.GetValue() ) + + + def OnTargetChange( self, event ): + ctl = event.GetEventObject() + value = ctl.GetValue() + ib_str = [ " (out of bounds)", "" ] + self.log.write( "value = %s (%s)%s\n" % ( repr(value), repr(type(value)), ib_str[ ctl.IsInBounds(value) ] ) ) + + + def OnNumberSelect( self, event ): + value = event.GetString() + if value: + if value.find('.') != -1: + numvalue = float(value) + else: + numvalue = long(value) + else: + numvalue = value # try to clear the value again + + try: + self.target_ctl.SetValue(numvalue) + except: + type, value, tb = sys.exc_info() + for line in traceback.format_exception_only(type, value): + self.log.write(line) + + +#---------------------------------------------------------------------- + +def runTest( frame, nb, log ): + win = TestPanel( nb, log ) + return win + +#---------------------------------------------------------------------- +import wx.lib.masked.numctrl as mnum +overview = """ +

+""" + mnum.__doc__ + """
+
""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/MediaCtrl.py b/demo/MediaCtrl.py new file mode 100644 index 00000000..539a3c40 --- /dev/null +++ b/demo/MediaCtrl.py @@ -0,0 +1,189 @@ + +import wx +import wx.media +import os + +#---------------------------------------------------------------------- + +class StaticText(wx.StaticText): + """ + A StaticText that only updates the label if it has changed, to + help reduce potential flicker since these controls would be + updated very frequently otherwise. + """ + def SetLabel(self, label): + if label <> self.GetLabel(): + wx.StaticText.SetLabel(self, label) + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1, + style=wx.TAB_TRAVERSAL|wx.CLIP_CHILDREN) + + # Create some controls + try: + backend = "" + if 'wxMSW' in wx.PlatformInfo: + # the default backend doesn't always send the EVT_MEDIA_LOADED + # event which we depend upon, so use a different backend by + # default for this demo. + backend = wx.media.MEDIABACKEND_QUICKTIME + + self.mc = wx.media.PreMediaCtrl() + ok = self.mc.Create(self, style=wx.SIMPLE_BORDER, + szBackend=backend) + if not ok: + raise NotImplementedError + self.mc.PostCreate(self.mc) + except NotImplementedError: + self.Destroy() + raise + + self.Bind(wx.media.EVT_MEDIA_LOADED, self.OnMediaLoaded) + + btn1 = wx.Button(self, -1, "Load File") + self.Bind(wx.EVT_BUTTON, self.OnLoadFile, btn1) + + btn2 = wx.Button(self, -1, "Play") + self.Bind(wx.EVT_BUTTON, self.OnPlay, btn2) + self.playBtn = btn2 + + btn3 = wx.Button(self, -1, "Pause") + self.Bind(wx.EVT_BUTTON, self.OnPause, btn3) + + btn4 = wx.Button(self, -1, "Stop") + self.Bind(wx.EVT_BUTTON, self.OnStop, btn4) + + slider = wx.Slider(self, -1, 0, 0, 10) + self.slider = slider + slider.SetMinSize((150, -1)) + self.Bind(wx.EVT_SLIDER, self.OnSeek, slider) + + self.st_size = StaticText(self, -1, size=(100,-1)) + self.st_len = StaticText(self, -1, size=(100,-1)) + self.st_pos = StaticText(self, -1, size=(100,-1)) + + + # setup the layout + sizer = wx.GridBagSizer(5,5) + sizer.Add(self.mc, (1,1), span=(5,1))#, flag=wx.EXPAND) + sizer.Add(btn1, (1,3)) + sizer.Add(btn2, (2,3)) + sizer.Add(btn3, (3,3)) + sizer.Add(btn4, (4,3)) + sizer.Add(slider, (6,1), flag=wx.EXPAND) + sizer.Add(self.st_size, (1, 5)) + sizer.Add(self.st_len, (2, 5)) + sizer.Add(self.st_pos, (3, 5)) + self.SetSizer(sizer) + + #self.DoLoadFile(os.path.abspath("data/testmovie.mpg")) + wx.CallAfter(self.DoLoadFile, os.path.abspath("data/testmovie.mpg")) + + self.timer = wx.Timer(self) + self.Bind(wx.EVT_TIMER, self.OnTimer) + self.timer.Start(100) + + + + def OnLoadFile(self, evt): + dlg = wx.FileDialog(self, message="Choose a media file", + defaultDir=os.getcwd(), defaultFile="", + style=wx.OPEN | wx.CHANGE_DIR ) + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + self.DoLoadFile(path) + dlg.Destroy() + + + def DoLoadFile(self, path): + self.playBtn.Disable() + if not self.mc.Load(path): + wx.MessageBox("Unable to load %s: Unsupported format?" % path, + "ERROR", + wx.ICON_ERROR | wx.OK) + else: + self.mc.SetInitialSize() + self.GetSizer().Layout() + self.slider.SetRange(0, self.mc.Length()) + + def OnMediaLoaded(self, evt): + self.playBtn.Enable() + + def OnPlay(self, evt): + if not self.mc.Play(): + wx.MessageBox("Unable to Play media : Unsupported format?", + "ERROR", + wx.ICON_ERROR | wx.OK) + else: + self.mc.SetInitialSize() + self.GetSizer().Layout() + self.slider.SetRange(0, self.mc.Length()) + + def OnPause(self, evt): + self.mc.Pause() + + def OnStop(self, evt): + self.mc.Stop() + + + def OnSeek(self, evt): + offset = self.slider.GetValue() + self.mc.Seek(offset) + + def OnTimer(self, evt): + offset = self.mc.Tell() + self.slider.SetValue(offset) + self.st_size.SetLabel('size: %s' % self.mc.GetBestSize()) + self.st_len.SetLabel('length: %d seconds' % (self.mc.Length()/1000)) + self.st_pos.SetLabel('position: %d' % offset) + + def ShutdownDemo(self): + self.timer.Stop() + del self.timer + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + try: + win = TestPanel(nb, log) + return win + except NotImplementedError: + from wx.lib.msgpanel import MessagePanel + win = MessagePanel(nb, 'wx.MediaCtrl is not available on this platform.', + 'Sorry', wx.ICON_WARNING) + return win + + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.MediaCtrl

+ +wx.MediaCtrl is a class that allows a way to convieniently display +various types of media, such as videos, audio files, natively through +native codecs. Several different formats of audio and video files are +supported, but some formats may not be playable on all platforms or +may require specific codecs to be installed. + +

+wx.MediaCtrl uses native backends to render media, for example on Windows +there is a ActiveMovie/DirectShow backend, and on Macintosh there is a +QuickTime backend. +

+wx.MediaCtrl is not currently available on unix systems. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/Menu.py b/demo/Menu.py new file mode 100644 index 00000000..2e97d754 --- /dev/null +++ b/demo/Menu.py @@ -0,0 +1,300 @@ + +import time +import wx +import images + +#------------------------------------------------------------------- + +class MyFrame(wx.Frame): + + def __init__(self, parent, id, log): + wx.Frame.__init__(self, parent, id, 'Playing with menus', size=(500, 250)) + self.log = log + self.CenterOnScreen() + + self.CreateStatusBar() + self.SetStatusText("This is the statusbar") + + tc = wx.TextCtrl(self, -1, """ +A bunch of bogus menus have been created for this frame. You +can play around with them to see how they behave and then +check the source for this sample to see how to implement them. +""", style=wx.TE_READONLY|wx.TE_MULTILINE) + + # Prepare the menu bar + menuBar = wx.MenuBar() + + # 1st menu from left + menu1 = wx.Menu() + menu1.Append(101, "&Mercury", "This the text in the Statusbar") + menu1.Append(102, "&Venus", "") + menu1.Append(103, "&Earth", "You may select Earth too") + menu1.AppendSeparator() + menu1.Append(104, "&Close", "Close this frame") + # Add menu to the menu bar + menuBar.Append(menu1, "&Planets") + + # 2nd menu from left + menu2 = wx.Menu() + menu2.Append(201, "Hydrogen") + menu2.Append(202, "Helium") + # a submenu in the 2nd menu + submenu = wx.Menu() + submenu.Append(2031,"Lanthanium") + submenu.Append(2032,"Cerium") + submenu.Append(2033,"Praseodymium") + menu2.AppendMenu(203, "Lanthanides", submenu) + # Append 2nd menu + menuBar.Append(menu2, "&Elements") + + menu3 = wx.Menu() + # Radio items + menu3.Append(301, "IDLE", "a Python shell using tcl/tk as GUI", wx.ITEM_RADIO) + menu3.Append(302, "PyCrust", "a Python shell using wxPython as GUI", wx.ITEM_RADIO) + menu3.Append(303, "psi", "a simple Python shell using wxPython as GUI", wx.ITEM_RADIO) + menu3.AppendSeparator() + menu3.Append(304, "project1", "", wx.ITEM_NORMAL) + menu3.Append(305, "project2", "", wx.ITEM_NORMAL) + menuBar.Append(menu3, "&Shells") + + menu4 = wx.Menu() + # Check menu items + menu4.Append(401, "letters", "abcde...", wx.ITEM_CHECK) + menu4.Append(402, "digits", "123...", wx.ITEM_CHECK) + menu4.Append(403, "letters and digits", "abcd... + 123...", wx.ITEM_CHECK) + menuBar.Append(menu4, "Chec&k") + + menu5 = wx.Menu() + # Show how to put an icon in the menu + item = wx.MenuItem(menu5, 500, "&Smile!\tCtrl+S", "This one has an icon") + item.SetBitmap(images.Smiles.GetBitmap()) + menu5.AppendItem(item) + + # Shortcuts + menu5.Append(501, "Interesting thing\tCtrl+A", "Note the shortcut!") + menu5.AppendSeparator() + menu5.Append(502, "Hello\tShift+H") + menu5.AppendSeparator() + menu5.Append(503, "remove the submenu") + menu6 = wx.Menu() + menu6.Append(601, "Submenu Item") + menu5.AppendMenu(504, "submenu", menu6) + menu5.Append(505, "remove this menu") + menu5.Append(506, "this is updated") + menu5.Append(507, "insert after this...") + menu5.Append(508, "...and before this") + menuBar.Append(menu5, "&Fun") + + self.SetMenuBar(menuBar) + + # Menu events + self.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.OnMenuHighlight) + + self.Bind(wx.EVT_MENU, self.Menu101, id=101) + self.Bind(wx.EVT_MENU, self.Menu102, id=102) + self.Bind(wx.EVT_MENU, self.Menu103, id=103) + self.Bind(wx.EVT_MENU, self.CloseWindow, id=104) + + self.Bind(wx.EVT_MENU, self.Menu201, id=201) + self.Bind(wx.EVT_MENU, self.Menu202, id=202) + self.Bind(wx.EVT_MENU, self.Menu2031, id=2031) + self.Bind(wx.EVT_MENU, self.Menu2032, id=2032) + self.Bind(wx.EVT_MENU, self.Menu2033, id=2033) + + self.Bind(wx.EVT_MENU, self.Menu301To303, id=301) + self.Bind(wx.EVT_MENU, self.Menu301To303, id=302) + self.Bind(wx.EVT_MENU, self.Menu301To303, id=303) + self.Bind(wx.EVT_MENU, self.Menu304, id=304) + self.Bind(wx.EVT_MENU, self.Menu305, id=305) + + # Range of menu items + self.Bind(wx.EVT_MENU_RANGE, self.Menu401To403, id=401, id2=403) + + self.Bind(wx.EVT_MENU, self.Menu500, id=500) + self.Bind(wx.EVT_MENU, self.Menu501, id=501) + self.Bind(wx.EVT_MENU, self.Menu502, id=502) + self.Bind(wx.EVT_MENU, self.TestRemove, id=503) + self.Bind(wx.EVT_MENU, self.TestRemove2, id=505) + self.Bind(wx.EVT_MENU, self.TestInsert, id=507) + self.Bind(wx.EVT_MENU, self.TestInsert, id=508) + + wx.GetApp().Bind(wx.EVT_UPDATE_UI, self.TestUpdateUI, id=506) + + # Methods + + def OnMenuHighlight(self, event): + # Show how to get menu item info from this event handler + id = event.GetMenuId() + item = self.GetMenuBar().FindItemById(id) + if item: + text = item.GetText() + help = item.GetHelp() + + # but in this case just call Skip so the default is done + event.Skip() + + + def Menu101(self, event): + self.log.write('Welcome to Mercury\n') + + def Menu102(self, event): + self.log.write('Welcome to Venus\n') + + def Menu103(self, event): + self.log.write('Welcome to the Earth\n') + + def CloseWindow(self, event): + self.Close() + + def Menu201(self, event): + self.log.write('Chemical element number 1\n') + + def Menu202(self, event): + self.log.write('Chemical element number 2\n') + + def Menu2031(self, event): + self.log.write('Element number 57\n') + + def Menu2032(self, event): + self.log.write('Element number 58\n') + + def Menu2033(self, event): + self.log.write('Element number 59\n') + + def Menu301To303(self, event): + id = event.GetId() + self.log.write('Event id: %d\n' % id) + + def Menu304(self, event): + self.log.write('Not yet available\n') + + def Menu305(self, event): + self.log.write('Still vapour\n') + + def Menu401To403(self, event): + self.log.write('From a EVT_MENU_RANGE event\n') + + def Menu500(self, event): + self.log.write('Have a happy day!\n') + + def Menu501(self, event): + self.log.write('Look in the code how the shortcut has been realized\n') + + def Menu502(self, event): + self.log.write('Hello from Jean-Michel\n') + + + def TestRemove(self, evt): + mb = self.GetMenuBar() + submenuItem = mb.FindItemById(601) + + if not submenuItem: + return + + submenu = submenuItem.GetMenu() + menu = submenu.GetParent() + + # This works + #menu.Remove(504) + + # this also works + menu.RemoveItem(mb.FindItemById(504)) + + # This doesn't work, as expected since submenuItem is not on menu + #menu.RemoveItem(submenuItem) + + + def TestRemove2(self, evt): + mb = self.GetMenuBar() + mb.Remove(4) + + + def TestUpdateUI(self, evt): + text = time.ctime() + evt.SetText(text) + + + def TestInsert(self, evt): + theID = 508 + # get the menu + mb = self.GetMenuBar() + menuItem = mb.FindItemById(theID) + menu = menuItem.GetMenu() + + # figure out the position to insert at + pos = 0 + + for i in menu.GetMenuItems(): + if i.GetId() == theID: + break + + pos += 1 + + # now insert the new item + ID = wx.NewId() + item = wx.MenuItem(menu, ID, "NewItem " + str(ID)) + menu.InsertItem(pos, item) + + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show the Menu sample", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = MyFrame(self, -1, self.log) + win.Show(True) + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#------------------------------------------------------------------- + + +overview = """\ +A demo of using wx.MenuBar and wx.Menu in various ways. + +A menu is a popup (or pull down) list of items, one of which may be selected +before the menu goes away (clicking elsewhere dismisses the menu). Menus may be +used to construct either menu bars or popup menus. + +A menu item has an integer ID associated with it which can be used to identify +the selection, or to change the menu item in some way. A menu item with a special +identifier -1 is a separator item and doesn't have an associated command but just +makes a separator line appear in the menu. + +Menu items may be either normal items, check items or radio items. Normal items +don't have any special properties while the check items have a boolean flag associated +to them and they show a checkmark in the menu when the flag is set. wxWindows +automatically toggles the flag value when the item is clicked and its value may +be retrieved using either IsChecked method of wx.Menu or wx.MenuBar itself or by +using wxEvent.IsChecked when you get the menu notification for the item in question. + +The radio items are similar to the check items except that all the other items +in the same radio group are unchecked when a radio item is checked. The radio group +is formed by a contiguous range of radio items, i.e. it starts at the first item of +this kind and ends with the first item of a different kind (or the end of the menu). +Notice that because the radio groups are defined in terms of the item positions +inserting or removing the items in the menu containing the radio items risks to not +work correctly. Finally note that the radio items are only supported under Windows +and GTK+ currently. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/MessageDialog.py b/demo/MessageDialog.py new file mode 100644 index 00000000..75dd639f --- /dev/null +++ b/demo/MessageDialog.py @@ -0,0 +1,53 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a MessageDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + dlg = wx.MessageDialog(self, 'Hello from Python and wxPython!', + 'A Message Box', + wx.OK | wx.ICON_INFORMATION + #wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_INFORMATION + ) + dlg.ShowModal() + dlg.Destroy() + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + + +overview = """\ + +

wx.MessageDialog

+ +This class represents a dialog that shows a single or multi-line +message, with a choice of OK, Yes, No and Cancel buttons. +Additionally, various style flags can determine whether an icon is +displayed, and, if so, what kind. The return value of ShowModal +indicates which button was pressed. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/MimeTypesManager.py b/demo/MimeTypesManager.py new file mode 100644 index 00000000..b4d9f048 --- /dev/null +++ b/demo/MimeTypesManager.py @@ -0,0 +1,357 @@ +#---------------------------------------------------------------------- +# Name: wxMimeTypesManager +# Purpose: Demonstrate use of wx.MimeTypesManager, wx.FileType +# +# Author: Jeff Grimmett (grimmtoo@softhome.net), adapted from original +# .wdr-derived demo +# +# Created: 12/31/03 +# RCS-ID: $Id$ +# Copyright: +# Licence: wxWindows license +#---------------------------------------------------------------------- +# + + +import pprint +import wx +import images + + +# helper function to make sure we don't convert unicode objects to strings +# or vice versa when converting lists and None values to text. +convert = str +if 'unicode' in wx.PlatformInfo: + convert = unicode + +#---------------------------------------------------------------------------- + +class MimeTypesDemoPanel(wx.Panel): + def __init__(self, parent, log): + + self.log = log + + wx.Panel.__init__(self, parent, -1) + + # This will be used for all of the labels that follow (bold label) + bfont = self.GetFont() + bfont.SetWeight(wx.BOLD) + + # Contains everything + tsizer = wx.BoxSizer(wx.VERTICAL) + + # Contains upper controls + usizer = wx.BoxSizer(wx.HORIZONTAL) + + # Text control for ext / type entry plus label. + t = wx.StaticText(self, -1, 'Extension / MIME type: ', style = wx.ALIGN_RIGHT ) + t.SetFont(bfont) + usizer.Add(t, 0, wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 2) + + self.ext = wx.TextCtrl(self, -1, value="wav", style = wx.TE_PROCESS_ENTER ) + usizer.Add(self.ext, 0, wx.ALL | wx.ALIGN_TOP, 4) + self.Bind(wx.EVT_TEXT_ENTER, self.OnLookup, self.ext) + + # Select how to look it up + self.useExt = wx.RadioButton(self, -1, "By extension", style = wx.RB_GROUP) + self.useMime = wx.RadioButton(self, -1, "By MIME type") + + usizer.Add(self.useExt, 0, wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 4) + usizer.Add(self.useMime, 0, wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 4) + self.useExt.SetValue(1) + + # Trigger a lookup (hitting ENTER in the text ctrl will do the same thing) + self.go = wx.Button(self, -1, "Go get it!") + usizer.Add(self.go, 0, wx.ALL | wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 4) + self.Bind(wx.EVT_BUTTON, self.OnLookup, self.go) + + # StaticBox with larger label than usual + lbox = wx.StaticBox(self, -1, 'wx.FileType') + + f = self.GetFont() + f.SetPointSize(f.GetPointSize() * 2) + f.SetWeight(wx.BOLD) + lbox.SetFont(f) + + lsizer = wx.StaticBoxSizer(lbox, wx.HORIZONTAL) + + # Contains the wx.FileType info + llsizer = wx.GridBagSizer(2, 2) + + #------- Icon info + + t = wx.StaticText(self, -1, 'GetIconInfo: ', style = wx.ALIGN_RIGHT ) + t.SetFont(bfont) + llsizer.Add(t, (0, 0), (1, 1), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + self.icon = wx.StaticBitmap(self, -1, images.NoIcon.GetBitmap()) + llsizer.Add(self.icon, (0, 1), (1, 1), wx.ALL | wx.ALIGN_CENTER, 2) + + self.iconsource = wx.TextCtrl(self, -1, value="", size=(125, -1), style = wx.TE_READONLY ) + llsizer.Add(self.iconsource, (0, 2), (1, 1), wx.ALL | wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, 2) + + self.iconoffset = wx.TextCtrl(self, -1, value="", size=(25,-1), style = wx.TE_READONLY ) + llsizer.Add(self.iconoffset, (0, 3), (1, 1), wx.ALL | wx.ALIGN_CENTER_VERTICAL, 2) + + #------- MIME Type + + t = wx.StaticText(self, -1, 'GetMimeType: ', style = wx.ALIGN_RIGHT ) + t.SetFont(bfont) + llsizer.Add(t, (1, 0), (1, 1), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + self.mimetype = wx.TextCtrl(self, -1, value="", style = wx.TE_READONLY ) + llsizer.Add(self.mimetype, (1, 1), (1, 3), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + #------- MIME Types + + t = wx.StaticText(self, -1, 'GetMimeTypes: ', style = wx.ALIGN_RIGHT ) + t.SetFont(bfont) + llsizer.Add(t, (2, 0), (1, 1), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + self.mimetypes = wx.TextCtrl(self, -1, value="", style = wx.TE_READONLY ) + llsizer.Add(self.mimetypes, (2, 1), (1, 3), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + #------- Extensions + + t = wx.StaticText(self, -1, 'GetExtensions: ', style = wx.ALIGN_RIGHT ) + t.SetFont(bfont) + llsizer.Add(t, (3, 0), (1, 1), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + self.extensions = wx.TextCtrl(self, -1, value="", style = wx.TE_READONLY ) + llsizer.Add(self.extensions, (3, 1), (1, 3), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + #------- Description + + t = wx.StaticText(self, -1, 'GetDescription: ', style = wx.ALIGN_RIGHT ) + t.SetFont(bfont) + llsizer.Add(t, (4, 0), (1, 1), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + self.description = wx.TextCtrl(self, -1, value="", style = wx.TE_READONLY) + llsizer.Add(self.description, (4, 1), (1, 3), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + #------- Open command + + t = wx.StaticText(self, -1, 'GetOpenCommand: ', style = wx.ALIGN_RIGHT ) + t.SetFont(bfont) + llsizer.Add(t, (5, 0), (1, 1), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + self.opencommand = wx.TextCtrl(self, -1, value="", style = wx.TE_READONLY ) + llsizer.Add(self.opencommand, (5, 1), (1, 3), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + #------- Print command + + t = wx.StaticText(self, -1, 'GetPrintCommand: ', style = wx.ALIGN_RIGHT ) + t.SetFont(bfont) + llsizer.Add(t, (6, 0), (1, 1), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + self.printcommand = wx.TextCtrl(self, -1, value="", style = wx.TE_READONLY ) + llsizer.Add(self.printcommand, (6, 1), (1, 3), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + #------- All commands + + t = wx.StaticText(self, -1, 'GetAllCommands: ', style = wx.ALIGN_RIGHT ) + t.SetFont(bfont) + llsizer.Add(t, (7, 0), (1, 1), wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 2) + + self.allcommands = wx.TextCtrl(self, -1, value="", style = wx.TE_READONLY | wx.TE_DONTWRAP | wx.TE_MULTILINE ) + + # Set the default height to be smaller than normal (for + # multi-line) so the sizer can then expand it to whatever + # space is available + self.allcommands.SetSize((-1, 20)) + + llsizer.Add(self.allcommands, (7, 1), (1, 3), wx.ALL | wx.GROW | wx.ALIGN_CENTER, 2) + + # Tell the sizer to expand this row as needed + llsizer.AddGrowableRow(7) + llsizer.AddGrowableCol(2) + + #---------------------------------------------------------------------------- + + lrsizer = wx.BoxSizer(wx.VERTICAL) + + #------- List box with known MIME types + + t = wx.StaticText(self, -1, 'Known MIME types') + t.SetFont(bfont) + lrsizer.Add(t, 0, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 4) + + self.mimelist = wx.ListBox(self, -1, choices=[], style = wx.LB_SINGLE)# | wx.LB_SORT) + lrsizer.Add(self.mimelist, 1, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER | wx.FIXED_MINSIZE, 4) + self.Bind(wx.EVT_LISTBOX, self.OnListbox, self.mimelist) + + #---------------------------------------------------------------------------- + + lsizer.Add(llsizer, 1, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 4) + lsizer.Add(lrsizer, 0, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 4) + + #---------------------------------------------------------------------------- + + tsizer.Add(usizer, 0, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 4) + tsizer.Add(lsizer, 1, wx.ALL | wx.EXPAND | wx.ALIGN_CENTER, 4) + + #---------------------------------------------------------------------------- + + self.SetSizer(tsizer) + tsizer.Fit(self) + + # Populate the Known MIME types list with what is in the database + try: + mtypes = wx.TheMimeTypesManager.EnumAllFileTypes() + except wx.PyAssertionError: + mtypes = [] + + # TODO: On wxMac, EnumAllFileTypes produces tons of dupes, which + # causes quirky behavior because the list control doesn't expect + # dupes, and simply wastes space. So remove the dupes for now, + # then remove this hack when we fix EnumAllFileTypes on Mac. + mimes = [] + for mt in mtypes: + if mt not in mimes: + #self.mimelist.Append(mt) + mimes.append(mt) + if mimes: + mimes.sort() + self.mimelist.AppendItems(mimes) + + # Do a lookup of *.wav for a starting position + self.OnLookup() + + # Grab the selection from the listbox, push that into + # the text box at top, select 'MIME', and then look it up. + def OnListbox(self, event): + mimetype = event.GetString() + self.ext.SetValue(mimetype) + self.useMime.SetValue(1) + self.OnLookup() + + # Look up a given file extension or MIME type. + def OnLookup(self, event=None): + txt = self.ext.GetValue() + + # For MIME lookups + if self.useMime.GetValue() == 1: + fileType = wx.TheMimeTypesManager.GetFileTypeFromMimeType(txt) + msg = "Mime type" + + # Select the entered value in the list + if fileType: + if self.mimelist.FindString(txt) != -1: + self.mimelist.SetSelection(self.mimelist.FindString(txt)) + + # Must be an extension lookup + else: + fileType = wx.TheMimeTypesManager.GetFileTypeFromExtension(txt) + msg = "File extension" + + # Select the entered value in the list + if fileType: + if self.mimelist.FindString(convert(fileType.GetMimeType())) != -1: + # Using CallAfter to ensure that GUI is ready before trying to + # select it (otherwise, it's selected but not visible) + wx.CallAfter(self.mimelist.SetSelection, self.mimelist.FindString(convert(fileType.GetMimeType()))) + + + if fileType is None: + wx.MessageBox(msg + " not found.", "Oops!") + else: + self.DoUpdate(fileType) + + # Populate the wx.FileType fields with actual values. + def DoUpdate(self, ft): + + #------- Icon info + info = ft.GetIconInfo() + + if info is None: + bmp = images.NoIcon.GetBitmap() + self.icon.SetBitmap(bmp) + self.iconsource.SetValue("") + self.iconoffset.SetValue("") + else: + icon, file, idx = info + if icon.Ok(): + self.icon.SetIcon(icon) + else: + bmp = images.NoIcon.GetBitmap() + self.icon.SetBitmap(bmp) + self.iconsource.SetValue(file) + self.iconoffset.SetValue(convert(idx)) + + #------- MIME type + self.mimetype.SetValue(convert(ft.GetMimeType())) + #------- MIME types + self.mimetypes.SetValue(convert(ft.GetMimeTypes())) + #------- Associated extensions + self.extensions.SetValue(convert(ft.GetExtensions())) + #------- Description of file type + self.description.SetValue(convert(ft.GetDescription())) + + #------- Prep a fake command line command + extList = ft.GetExtensions() + + if extList: + ext = extList[0] + if len(ext) > 0 and ext[0] == ".": ext = ext[1:] + else: + ext = "" + + filename = "SPAM" + "." + ext + mime = ft.GetMimeType() or "" + + #------- OPEN command + cmd = ft.GetOpenCommand(filename, mime) + self.opencommand.SetValue(convert(cmd)) + + #------- PRINT command + cmd = ft.GetPrintCommand(filename, mime) + self.printcommand.SetValue(convert(cmd)) + + #------- All commands + all = ft.GetAllCommands(filename, mime) + + if all is None: + self.allcommands.SetValue("") + else: + verbs, commands = all + text = pprint.pformat(map(None, verbs, commands)) + self.allcommands.SetValue(text) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = MimeTypesDemoPanel(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = """\ + +The wx.MimeTypesManager class allows the application to retrieve the +information about all known MIME types from a system-specific location and the +filename extensions to the MIME types and vice versa. After initialization the +methods GetFileTypeFromMimeType() and GetFileTypeFromExtension() +may be called: they will return a wx.FileType object which may be further +queried for file description, icon and other attributes. + +A global instance of wx.MimeTypesManager is always available as +wx.TheMimeTypesManager. It is recommended to use this instance instead +of creating your own because gathering MIME information may take quite a long +on Unix systems. + +This demo shows how to use wx.TheMimeTypesManager to list all known MIME types +and retrieve that information as a wx.FileType from either an extension or +MIME type. + +For further information please consult the wxWindows documentation for +wx.MimeTypesManager and wx.FileType. + +""" + +#---------------------------------------------------------------------- + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/MiniFrame.py b/demo/MiniFrame.py new file mode 100644 index 00000000..2bea751f --- /dev/null +++ b/demo/MiniFrame.py @@ -0,0 +1,66 @@ + +import wx + +#--------------------------------------------------------------------------- +class MyMiniFrame(wx.MiniFrame): + def __init__( + self, parent, title, pos=wx.DefaultPosition, size=wx.DefaultSize, + style=wx.DEFAULT_FRAME_STYLE + ): + + wx.MiniFrame.__init__(self, parent, -1, title, pos, size, style) + panel = wx.Panel(self, -1) + + button = wx.Button(panel, -1, "Close Me") + button.SetPosition((15, 15)) + self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + def OnCloseMe(self, event): + self.Close(True) + + def OnCloseWindow(self, event): + print "OnCloseWindow" + self.Destroy() + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a MiniFrame", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = MyMiniFrame(self, "This is a wx.MiniFrame", + style=wx.DEFAULT_FRAME_STYLE | wx.TINY_CAPTION_HORIZ) + win.SetSize((200, 200)) + win.CenterOnParent(wx.BOTH) + win.Show(True) + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = """\ +A MiniFrame is a Frame with a small title bar. It is suitable for floating +toolbars that must not take up too much screen area. In other respects, it's the +same as a wx.Frame. +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/MouseGestures.py b/demo/MouseGestures.py new file mode 100644 index 00000000..d4af8490 --- /dev/null +++ b/demo/MouseGestures.py @@ -0,0 +1,195 @@ +#******************* +#By Daniel Pozmanter + +#Thanks to Robin Dunn for taking the time to show me how to do this +#via the mailing list. + +#Version 0.0.0 + +#This is a hacked version of DragAndDrop.py from the wxPython demo 2.5.2.8 + +import wx, wx.lib.dialogs +from wx.lib.gestures import MouseGestures + +#ToDo: + +#Add a dialog to record gestures (Have it showcase the manual mode) +#Allow users to remove gestures + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + + ID_GESTURE = wx.NewId() + ID_MOUSE = wx.NewId() + ID_MODIFIER = wx.NewId() + ID_VISIBLE = wx.NewId() + + self.log = log + + #Mouse Gestures: + + self.mg = MouseGestures(self, Auto=True, + MouseButton=wx.MOUSE_BTN_RIGHT) + + self.mg.SetGesturesVisible(True) + + self.mg.AddGesture('LR', self.ShowSomethingClever, 'Left then Right!') + self.mg.AddGesture('39', self.ShowSomethingClever, 'You made a V!') + self.mg.AddGesture('L', self.LogSomethingClever, 'You moved left') + self.mg.AddGesture('9', self.LogSomethingClever, 'You moved right and up') + self.mg.AddGesture('U', self.LogSomethingClever, 'You moved up') + self.mg.AddGesture('DR', self.OnDownThenRight) + self.mg.AddGesture('LDRU', self.SetToBlue) + self.mg.AddGesture('RDLU', self.SetToOrange) + + #Widgets: + + self.btnAddGesture = wx.Button(self, ID_GESTURE, 'Add New Gesture') + self.btnChangeMouseButton = wx.Button(self, ID_MOUSE, 'Change Mouse Button') + self.btnChangeModifier = wx.Button(self, ID_MODIFIER, 'Change Modifier') + self.btnToggleVisible = wx.ToggleButton(self, ID_VISIBLE, 'Toggle Gestures Visible') + self.btnToggleVisible.SetValue(True) + + msg = "Mouse Gestures" + text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE) + text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + text.SetLabel(msg) + + w,h = text.GetTextExtent(msg) + text.SetSize(wx.Size(w,h+1)) + text.SetForegroundColour(wx.BLUE) + + #Sizer: + outsideSizer = wx.BoxSizer(wx.VERTICAL) + + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + + outsideSizer.Add(text, 0, wx.EXPAND|wx.ALL, 5) + outsideSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) + outsideSizer.Add(wx.StaticText(self, -1, ' '), 0, wx.EXPAND) + outsideSizer.Add(wx.StaticText(self, -1, 'Hold The Middle Mouse Button Down to Gesticulate'), 0, wx.EXPAND) + outsideSizer.Add(wx.StaticText(self, -1, 'Left Then Right, Left, The Diagonal Up/Right, Down Then Right, Diagonal Down/Right Then Diagonal Up/Right, and Up are Preset'), 0, wx.EXPAND) + outsideSizer.Add(wx.StaticText(self, -1, 'Left,Down,Right,Up Sets the line colour to Blue.'), 0, wx.EXPAND) + outsideSizer.Add(wx.StaticText(self, -1, 'Right,Down,Left,Up Sets the line colour to Orange.'), 0, wx.EXPAND) + outsideSizer.Add(wx.StaticText(self, -1, ' '), 0, wx.EXPAND) + btnSizer.Add(self.btnAddGesture, 0, wx.SHAPED) + btnSizer.Add(self.btnChangeMouseButton, 0, wx.SHAPED) + btnSizer.Add(self.btnChangeModifier, 0, wx.SHAPED) + btnSizer.Add(self.btnToggleVisible, 0, wx.SHAPED) + outsideSizer.Add(btnSizer, 0, wx.SHAPED) + + self.SetAutoLayout(True) + self.SetSizer(outsideSizer) + + #Events: + self.Bind(wx.EVT_BUTTON, self.OnAddGesture, id=ID_GESTURE) + self.Bind(wx.EVT_BUTTON, self.OnChangeMouseButton, id=ID_MOUSE) + self.Bind(wx.EVT_BUTTON, self.OnChangeModifiers, id=ID_MODIFIER) + self.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggleVisible, id=ID_VISIBLE) + + def LogSomethingClever(self, somethingclever): + self.log.WriteText(somethingclever) + + def OnAddGesture(self, event): + d = wx.TextEntryDialog(self, "Enter Gesture (LRUD1379) (EG Right Then Up Then DownLeft is RU1):", "Add New Gesture", "") + answer1 = d.ShowModal() + gesture = d.GetValue() + d.Destroy() + + d = wx.TextEntryDialog(self, 'Print the following text on "%s":' % gesture, "Gesture Action", "") + answer2 = d.ShowModal() + text = d.GetValue() + d.Destroy() + + if (answer1 == wx.ID_OK) and (answer2 == wx.ID_OK): + self.mg.AddGesture(gesture.upper(), self.LogSomethingClever, text) + + def OnChangeModifiers(self, event): + choices = [wx.WXK_CONTROL, wx.WXK_SHIFT, wx.WXK_ALT] + schoices = ['Control', 'Shift', 'Alt'] + + d = wx.lib.dialogs.MultipleChoiceDialog(self, 'Select Modifier Keys:\n(Select None if you do not want to use modifier keys\n\n', "Change Modifier Keys", schoices) + answer = d.ShowModal() + tuply = d.GetValue() + d.Destroy() + + if (answer == wx.ID_OK): + if len(tuply) > 0: + modifiers = [] + modstring = '' + for x in tuply: + modifiers.append(choices[x]) + modstring += schoices[x] + ' ' + self.mg.SetModifiers(modifiers) + self.log.WriteText('Set Modifiers to: ' + modstring) + else: + self.mg.SetModifiers() + self.log.WriteText('UnSet All Modifiers') + + def OnChangeMouseButton(self, event): + choices = [wx.MOUSE_BTN_LEFT, wx.MOUSE_BTN_MIDDLE, wx.MOUSE_BTN_RIGHT] + schoices = ['Left', 'Middle', 'Right'] + d = wx.SingleChoiceDialog(self, "Set Mouse Button To", "Change Mouse Button", schoices, + wx.CHOICEDLG_STYLE|wx.OK|wx.CANCEL) + d.SetSize(wx.Size(250, 200)) + answer = d.ShowModal() + i = d.GetSelection() + d.Destroy() + if (answer == wx.ID_OK): + self.mg.SetMouseButton(choices[i]) + self.log.WriteText('Set the Mouse Button to ' + schoices[i]) + + def OnDownThenRight(self): + self.log.WriteText('You made an "L"!') + + def OnToggleVisible(self, event): + visual = self.btnToggleVisible.GetValue() + self.mg.SetGesturesVisible(visual) + if visual: + self.log.WriteText('Made Gestures Visible') + else: + self.log.WriteText('Made Gestures Invisible') + + def SetToBlue(self): + self.mg.SetGesturePen(wx.Colour(0, 144, 255), 5) + self.log.WriteText('Set Gesture Colour to Blue') + + def SetToOrange(self): + self.mg.SetGesturePen(wx.Colour(255, 156, 0), 5) + self.log.WriteText('Set Gesture Colour to Orange') + + def ShowSomethingClever(self, somethingclever): + d = wx.MessageDialog(self, somethingclever, 'Mouse Gesture Action', wx.OK) + d.ShowModal() + d.Destroy() + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ + + +This demo shows how to add MouseGestures +to your program, and showcases the MouseGestures +class in all it's mousey glory. +

+ + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/MultiChoiceDialog.py b/demo/MultiChoiceDialog.py new file mode 100644 index 00000000..3ce70774 --- /dev/null +++ b/demo/MultiChoiceDialog.py @@ -0,0 +1,58 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a wx.MultiChoiceDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + lst = [ 'apple', 'pear', 'banana', 'coconut', 'orange', 'grape', 'pineapple', + 'blueberry', 'raspberry', 'blackberry', 'snozzleberry', + 'etc', 'etc..', 'etc...' ] + + dlg = wx.MultiChoiceDialog( self, + "Pick some fruit from\nthis list", + "wx.MultiChoiceDialog", lst) + + if (dlg.ShowModal() == wx.ID_OK): + selections = dlg.GetSelections() + strings = [lst[x] for x in selections] + self.log.write("Selections: %s -> %s\n" % (selections, strings)) + + dlg.Destroy() + + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + + +overview = """\ + + +

wx.MultiChoiceDialog

+ +This class represents a dialog that shows a list of strings, and +allows the user to select one or more. + + + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/MultiSash.py b/demo/MultiSash.py new file mode 100644 index 00000000..6af173b5 --- /dev/null +++ b/demo/MultiSash.py @@ -0,0 +1,94 @@ + +import wx +import wx.lib.multisash as sash +import wx.stc as stc + +#--------------------------------------------------------------------------- + +sampleText="""\ +You can drag the little tab on the vertical sash left to create another view, +or you can drag the tab on the horizontal sash to the top to create another +horizontal view. + +The red blocks on the sashes will destroy the view (bottom,left) this block +belongs to. + +A yellow rectangle also highlights the current selected view. + +By calling GetSaveData on the multiSash control the control will return its +contents and the positions of each sash as a dictionary. +Calling SetSaveData with such a dictionary will restore the control to the +state it was in when it was saved. + +If the class, that is used as a view, has GetSaveData/SetSaveData implemented, +these will also be called to save/restore their state. Any object can be +returned by GetSaveData, as it is just another object in the dictionary. +""" + +#--------------------------------------------------------------------------- + +class TestWindow(stc.StyledTextCtrl): + + # shared document reference + doc = None + + def __init__(self, parent): + stc.StyledTextCtrl.__init__(self, parent, -1, style=wx.NO_BORDER) + self.SetMarginWidth(1,0) + + if wx.Platform == '__WXMSW__': + fSize = 10 + else: + fSize = 12 + + self.StyleSetFont( + stc.STC_STYLE_DEFAULT, + wx.Font(fSize, wx.MODERN, wx.NORMAL, wx.NORMAL) + ) + + if self.doc: + self.SetDocPointer(self.doc) + else: + self.SetText(sampleText) + TestWindow.doc = self.GetDocPointer() + + + def ShutDownDemo(self): + # Reset doc reference in case this demo is run again + TestWindow.doc = None + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + multi = sash.MultiSash(nb, -1, pos = (0,0), size = (640,480)) + + # Use this method to set the default class that will be created when + # a new sash is created. The class's constructor needs 1 parameter + # which is the parent of the window + multi.SetDefaultChildClass(TestWindow) + + return multi + +#---------------------------------------------------------------------- + + + +overview = """ +

MultiSash

+ +MultiSash allows the user to split a window any number of times +either horizontally or vertically, and to close the split off windows +when desired. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/MultiSplitterWindow.py b/demo/MultiSplitterWindow.py new file mode 100644 index 00000000..e8a3f158 --- /dev/null +++ b/demo/MultiSplitterWindow.py @@ -0,0 +1,167 @@ + +import wx +from wx.lib.splitter import MultiSplitterWindow + +#---------------------------------------------------------------------- + +class SamplePane(wx.Panel): + """ + Just a simple test window to put into the splitter. + """ + def __init__(self, parent, colour, label): + wx.Panel.__init__(self, parent, style=wx.BORDER_SUNKEN) + self.SetBackgroundColour(colour) + wx.StaticText(self, -1, label, (5,5)) + + def SetOtherLabel(self, label): + wx.StaticText(self, -1, label, (5, 30)) + + + +class ControlPane(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent) + + hvBox = wx.RadioBox(self, -1, "Orientation", + choices=["Horizontal", "Vertical"], + style=wx.RA_SPECIFY_COLS, + majorDimension=1) + hvBox.SetSelection(0) + self.Bind(wx.EVT_RADIOBOX, self.OnSetHV, hvBox) + + luCheck = wx.CheckBox(self, -1, "Live Update") + luCheck.SetValue(True) + self.Bind(wx.EVT_CHECKBOX, self.OnSetLiveUpdate, luCheck) + + btn = wx.Button(self, -1, "Swap 2 && 4") + self.Bind(wx.EVT_BUTTON, self.OnSwapButton, btn) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(hvBox) + sizer.Add(luCheck, 0, wx.TOP, 5) + sizer.Add(btn, 0, wx.TOP, 5) + border = wx.BoxSizer() + border.Add(sizer, 1, wx.EXPAND|wx.ALL, 5) + self.SetSizer(border) + + + def OnSetHV(self, evt): + rb = evt.GetEventObject() + self.GetParent().SetOrientation(rb.GetSelection()) + + + def OnSetLiveUpdate(self, evt): + check = evt.GetEventObject() + self.GetParent().SetLiveUpdate(check.GetValue()) + + + def OnSwapButton(self, evt): + self.GetParent().Swap2and4() + + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + cp = ControlPane(self) + + splitter = MultiSplitterWindow(self, style=wx.SP_LIVE_UPDATE) + self.splitter = splitter + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(cp) + sizer.Add(splitter, 1, wx.EXPAND) + self.SetSizer(sizer) + + + p1 = SamplePane(splitter, "pink", "Panel One") + p1.SetOtherLabel( + "There are two sash\n" + "drag modes. Try\n" + "dragging with and\n" + "without the Shift\n" + "key held down." + ) + splitter.AppendWindow(p1, 140) + + p2 = SamplePane(splitter, "sky blue", "Panel Two") + p2.SetOtherLabel("This window\nhas a\nminsize.") + p2.SetMinSize(p2.GetBestSize()) + splitter.AppendWindow(p2, 150) + + p3 = SamplePane(splitter, "yellow", "Panel Three") + splitter.AppendWindow(p3, 125) + + p4 = SamplePane(splitter, "Lime Green", "Panel Four") + splitter.AppendWindow(p4) + + self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged) + self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnChanging) + + + def OnChanging(self, evt): + self.log.write( "Changing sash:%d %s\n" % + (evt.GetSashIdx(), evt.GetSashPosition())) + # This is one way to control the sash limits + #if evt.GetSashPosition() < 50: + # evt.Veto() + + # Or you can reset the sash position to whatever you want + #if evt.GetSashPosition() < 5: + # evt.SetSashPosition(25) + + + def OnChanged(self, evt): + self.log.write( "Changed sash:%d %s\n" % + (evt.GetSashIdx(), evt.GetSashPosition())) + + + def SetOrientation(self, value): + if value: + self.splitter.SetOrientation(wx.VERTICAL) + else: + self.splitter.SetOrientation(wx.HORIZONTAL) + self.splitter.SizeWindows() + + + def SetLiveUpdate(self, enable): + if enable: + self.splitter.SetWindowStyle(wx.SP_LIVE_UPDATE) + else: + self.splitter.SetWindowStyle(0) + + + def Swap2and4(self): + win2 = self.splitter.GetWindow(1) + win4 = self.splitter.GetWindow(3) + self.splitter.ExchangeWindows(win2, win4) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

MultiSplitterWindow

+ +This class is very similar to wx.SplitterWindow except that it +allows for more than two windows and more than one sash. Many of +the same styles, constants, and methods behave the same as in +wx.SplitterWindow. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/MultipleChoiceDialog.py b/demo/MultipleChoiceDialog.py new file mode 100644 index 00000000..3a36e987 --- /dev/null +++ b/demo/MultipleChoiceDialog.py @@ -0,0 +1,100 @@ + +import wx +import wx.lib.dialogs + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a MultipleChoiceDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + lst = [ 'apple', 'pear', 'banana', 'coconut', 'orange', 'grape', 'pineapple', + 'blueberry', 'raspberry', 'blackberry', 'snozzleberry', + 'etc', 'etc..', 'etc...' ] + + dlg = wx.lib.dialogs.MultipleChoiceDialog( + self, + "Pick some from\n this list\nblah blah...", + "m.s.d.", lst) + + if (dlg.ShowModal() == wx.ID_OK): + self.log.write("Selection: %s -> %s\n" % (dlg.GetValue(), dlg.GetValueString())) + + dlg.Destroy() + + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + + +overview = """\ + + + +This is a Python implementation of a dialog that is not yet implemented in wxWindows +proper, so don't let the wxWindows documentation mislead you. + +

MultipleChoiceDialog(self, parent, msg, title, lst, +pos = wx.wxDefaultPosition, size = (200,200), style = wx.DEFAULT_DIALOG_STYLE) + + +

+
parent +
The parent window + +
msg +
The message that will be displayed above the list + +
title +
The text that will appear on the title bar + +
lst +
A Python list of choices that will appear in the dialog. + +
pos +
The position of the dialog + +
size +
The size of the dialog + +
style +
The style for the dialog. Only styles normally available to wxDialog are +available. + +
+ +Methods + +
+
GetValue +
Returns a tuple containing the indices of the selected items + +
GetValueString +
Returns a tuple containing the text of the selected items + +
+ +Additionally, MultipleChoiceDialog.lbox is a standard wx.ListBox which supports all +methods applicable to that class. + + + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/Notebook.py b/demo/Notebook.py new file mode 100644 index 00000000..8eeaca7c --- /dev/null +++ b/demo/Notebook.py @@ -0,0 +1,131 @@ + +import sys + +import wx + +import ColorPanel +import GridSimple +import ListCtrl +import ScrolledWindow +import images + +#---------------------------------------------------------------------------- + +class TestNB(wx.Notebook): + def __init__(self, parent, id, log): + wx.Notebook.__init__(self, parent, id, size=(21,21), style= + wx.BK_DEFAULT + #wx.BK_TOP + #wx.BK_BOTTOM + #wx.BK_LEFT + #wx.BK_RIGHT + # | wx.NB_MULTILINE + ) + self.log = log + + win = self.makeColorPanel(wx.BLUE) + self.AddPage(win, "Blue") + st = wx.StaticText(win.win, -1, + "You can put nearly any type of window here,\n" + "and if the platform supports it then the\n" + "tabs can be on any side of the notebook.", + (10, 10)) + + st.SetForegroundColour(wx.WHITE) + st.SetBackgroundColour(wx.BLUE) + + # Show how to put an image on one of the notebook tabs, + # first make the image list: + il = wx.ImageList(16, 16) + idx1 = il.Add(images.Smiles.GetBitmap()) + self.AssignImageList(il) + + # now put an image on the first tab we just created: + self.SetPageImage(0, idx1) + + + win = self.makeColorPanel(wx.RED) + self.AddPage(win, "Red") + + win = ScrolledWindow.MyCanvas(self) + self.AddPage(win, 'ScrolledWindow') + + win = self.makeColorPanel(wx.GREEN) + self.AddPage(win, "Green") + + win = GridSimple.SimpleGrid(self, log) + self.AddPage(win, "Grid") + + win = ListCtrl.TestListCtrlPanel(self, log) + self.AddPage(win, 'List') + + win = self.makeColorPanel(wx.CYAN) + self.AddPage(win, "Cyan") + + win = self.makeColorPanel(wx.NamedColour('Midnight Blue')) + self.AddPage(win, "Midnight Blue") + + win = self.makeColorPanel(wx.NamedColour('Indian Red')) + self.AddPage(win, "Indian Red") + + self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged) + self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGING, self.OnPageChanging) + + + def makeColorPanel(self, color): + p = wx.Panel(self, -1) + win = ColorPanel.ColoredPanel(p, color) + p.win = win + def OnCPSize(evt, win=win): + win.SetPosition((0,0)) + win.SetSize(evt.GetSize()) + p.Bind(wx.EVT_SIZE, OnCPSize) + return p + + + def OnPageChanged(self, event): + old = event.GetOldSelection() + new = event.GetSelection() + sel = self.GetSelection() + self.log.write('OnPageChanged, old:%d, new:%d, sel:%d\n' % (old, new, sel)) + event.Skip() + + def OnPageChanging(self, event): + old = event.GetOldSelection() + new = event.GetSelection() + sel = self.GetSelection() + self.log.write('OnPageChanging, old:%d, new:%d, sel:%d\n' % (old, new, sel)) + event.Skip() + +#---------------------------------------------------------------------------- + +def runTest(frame, nb, log): + testWin = TestNB(nb, -1, log) + return testWin + +#---------------------------------------------------------------------------- + + +overview = """\ + +

wx.Notebook

+

+This class represents a notebook control, which manages multiple +windows with associated tabs. +

+To use the class, create a wx.Notebook object and call AddPage or +InsertPage, passing a window to be used as the page. Do not explicitly +delete the window for a page that is currently managed by wx.Notebook. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + + + diff --git a/demo/OGL.py b/demo/OGL.py new file mode 100644 index 00000000..bc62f7dd --- /dev/null +++ b/demo/OGL.py @@ -0,0 +1,431 @@ +# -*- coding: utf-8 -*- +# 11/20/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Updated for wx namespace +# +# 20040508 - Pierre Hjälm +# +# o Changed to use the python version of OGL +# o Added TextShape, CompositeShape and CompositeShape with divisions +# +# 20040830 - Pierre Hjälm +# +# o Added DrawnShape +# + +import wx +import wx.lib.ogl as ogl + +import images + +#---------------------------------------------------------------------- + +class DrawnShape(ogl.DrawnShape): + def __init__(self): + ogl.DrawnShape.__init__(self) + + self.SetDrawnBrush(wx.WHITE_BRUSH) + self.SetDrawnPen(wx.BLACK_PEN) + self.DrawArc((0, -10), (30, 0), (-30, 0)) + + self.SetDrawnPen(wx.Pen("#ff8030")) + self.DrawLine((-30, 5), (30, 5)) + + self.SetDrawnPen(wx.Pen("#00ee10")) + self.DrawRoundedRectangle((-20, 10, 40, 10), 5) + + self.SetDrawnPen(wx.Pen("#9090f0")) + self.DrawEllipse((-30, 25, 60, 20)) + + self.SetDrawnTextColour(wx.BLACK) + self.SetDrawnFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL)) + self.DrawText("DrawText", (-26, 28)) + + self.SetDrawnBrush(wx.GREEN_BRUSH) + self.DrawPolygon([(-100, 5), (-45, 30), (-35, 20), (-30, 5)]) + + self.SetDrawnPen(wx.BLACK_PEN) + self.DrawLines([(30, -45), (40, -45), (40 ,45), (30, 45)]) + + # Make sure to call CalculateSize when all drawing is done + self.CalculateSize() + +#---------------------------------------------------------------------- + +class DiamondShape(ogl.PolygonShape): + def __init__(self, w=0.0, h=0.0): + ogl.PolygonShape.__init__(self) + if w == 0.0: + w = 60.0 + if h == 0.0: + h = 60.0 + + points = [ (0.0, -h/2.0), + (w/2.0, 0.0), + (0.0, h/2.0), + (-w/2.0, 0.0), + ] + + self.Create(points) + + +#---------------------------------------------------------------------- + +class RoundedRectangleShape(ogl.RectangleShape): + def __init__(self, w=0.0, h=0.0): + ogl.RectangleShape.__init__(self, w, h) + self.SetCornerRadius(-0.3) + + +#---------------------------------------------------------------------- + +class CompositeDivisionShape(ogl.CompositeShape): + def __init__(self, canvas): + ogl.CompositeShape.__init__(self) + + self.SetCanvas(canvas) + + # create a division in the composite + self.MakeContainer() + + # add a shape to the original division + shape2 = ogl.RectangleShape(40, 60) + self.GetDivisions()[0].AddChild(shape2) + + # now divide the division so we get 2 + self.GetDivisions()[0].Divide(wx.HORIZONTAL) + + # and add a shape to the second division (and move it to the + # centre of the division) + shape3 = ogl.CircleShape(40) + shape3.SetBrush(wx.CYAN_BRUSH) + self.GetDivisions()[1].AddChild(shape3) + shape3.SetX(self.GetDivisions()[1].GetX()) + + for division in self.GetDivisions(): + division.SetSensitivityFilter(0) + +#---------------------------------------------------------------------- + +class CompositeShape(ogl.CompositeShape): + def __init__(self, canvas): + ogl.CompositeShape.__init__(self) + + self.SetCanvas(canvas) + + constraining_shape = ogl.RectangleShape(120, 100) + constrained_shape1 = ogl.CircleShape(50) + constrained_shape2 = ogl.RectangleShape(80, 20) + + constraining_shape.SetBrush(wx.BLUE_BRUSH) + constrained_shape2.SetBrush(wx.RED_BRUSH) + + self.AddChild(constraining_shape) + self.AddChild(constrained_shape1) + self.AddChild(constrained_shape2) + + constraint = ogl.Constraint(ogl.CONSTRAINT_MIDALIGNED_BOTTOM, constraining_shape, [constrained_shape1, constrained_shape2]) + self.AddConstraint(constraint) + self.Recompute() + + # If we don't do this, the shapes will be able to move on their + # own, instead of moving the composite + constraining_shape.SetDraggable(False) + constrained_shape1.SetDraggable(False) + constrained_shape2.SetDraggable(False) + + # If we don't do this the shape will take all left-clicks for itself + constraining_shape.SetSensitivityFilter(0) + + +#---------------------------------------------------------------------- + +class DividedShape(ogl.DividedShape): + def __init__(self, width, height, canvas): + ogl.DividedShape.__init__(self, width, height) + + region1 = ogl.ShapeRegion() + region1.SetText('DividedShape') + region1.SetProportions(0.0, 0.2) + region1.SetFormatMode(ogl.FORMAT_CENTRE_HORIZ) + self.AddRegion(region1) + + region2 = ogl.ShapeRegion() + region2.SetText('This is Region number two.') + region2.SetProportions(0.0, 0.3) + region2.SetFormatMode(ogl.FORMAT_CENTRE_HORIZ|ogl.FORMAT_CENTRE_VERT) + self.AddRegion(region2) + + region3 = ogl.ShapeRegion() + region3.SetText('Region 3\nwith embedded\nline breaks') + region3.SetProportions(0.0, 0.5) + region3.SetFormatMode(ogl.FORMAT_NONE) + self.AddRegion(region3) + + self.SetRegionSizes() + self.ReformatRegions(canvas) + + + def ReformatRegions(self, canvas=None): + rnum = 0 + + if canvas is None: + canvas = self.GetCanvas() + + dc = wx.ClientDC(canvas) # used for measuring + + for region in self.GetRegions(): + text = region.GetText() + self.FormatText(dc, text, rnum) + rnum += 1 + + + def OnSizingEndDragLeft(self, pt, x, y, keys, attch): + print "***", self + ogl.DividedShape.OnSizingEndDragLeft(self, pt, x, y, keys, attch) + self.SetRegionSizes() + self.ReformatRegions() + self.GetCanvas().Refresh() + + +#---------------------------------------------------------------------- + +class MyEvtHandler(ogl.ShapeEvtHandler): + def __init__(self, log, frame): + ogl.ShapeEvtHandler.__init__(self) + self.log = log + self.statbarFrame = frame + + def UpdateStatusBar(self, shape): + x, y = shape.GetX(), shape.GetY() + width, height = shape.GetBoundingBoxMax() + self.statbarFrame.SetStatusText("Pos: (%d, %d) Size: (%d, %d)" % + (x, y, width, height)) + + + def OnLeftClick(self, x, y, keys=0, attachment=0): + shape = self.GetShape() + canvas = shape.GetCanvas() + dc = wx.ClientDC(canvas) + canvas.PrepareDC(dc) + + if shape.Selected(): + shape.Select(False, dc) + #canvas.Redraw(dc) + canvas.Refresh(False) + else: + redraw = False + shapeList = canvas.GetDiagram().GetShapeList() + toUnselect = [] + + for s in shapeList: + if s.Selected(): + # If we unselect it now then some of the objects in + # shapeList will become invalid (the control points are + # shapes too!) and bad things will happen... + toUnselect.append(s) + + shape.Select(True, dc) + + if toUnselect: + for s in toUnselect: + s.Select(False, dc) + + ##canvas.Redraw(dc) + canvas.Refresh(False) + + self.UpdateStatusBar(shape) + + + def OnEndDragLeft(self, x, y, keys=0, attachment=0): + shape = self.GetShape() + ogl.ShapeEvtHandler.OnEndDragLeft(self, x, y, keys, attachment) + + if not shape.Selected(): + self.OnLeftClick(x, y, keys, attachment) + + self.UpdateStatusBar(shape) + + + def OnSizingEndDragLeft(self, pt, x, y, keys, attch): + ogl.ShapeEvtHandler.OnSizingEndDragLeft(self, pt, x, y, keys, attch) + self.UpdateStatusBar(self.GetShape()) + + + def OnMovePost(self, dc, x, y, oldX, oldY, display): + shape = self.GetShape() + ogl.ShapeEvtHandler.OnMovePost(self, dc, x, y, oldX, oldY, display) + self.UpdateStatusBar(shape) + if "wxMac" in wx.PlatformInfo: + shape.GetCanvas().Refresh(False) + + def OnRightClick(self, *dontcare): + self.log.WriteText("%s\n" % self.GetShape()) + + +#---------------------------------------------------------------------- + +class TestWindow(ogl.ShapeCanvas): + def __init__(self, parent, log, frame): + ogl.ShapeCanvas.__init__(self, parent) + + maxWidth = 1000 + maxHeight = 1000 + self.SetScrollbars(20, 20, maxWidth/20, maxHeight/20) + + self.log = log + self.frame = frame + self.SetBackgroundColour("LIGHT BLUE") #wx.WHITE) + self.diagram = ogl.Diagram() + self.SetDiagram(self.diagram) + self.diagram.SetCanvas(self) + self.shapes = [] + self.save_gdi = [] + + rRectBrush = wx.Brush("MEDIUM TURQUOISE", wx.SOLID) + dsBrush = wx.Brush("WHEAT", wx.SOLID) + + self.MyAddShape( + CompositeDivisionShape(self), + 270, 310, wx.BLACK_PEN, wx.BLUE_BRUSH, "Division" + ) + + self.MyAddShape( + CompositeShape(self), + 100, 260, wx.BLACK_PEN, wx.RED_BRUSH, "Composite" + ) + + self.MyAddShape( + ogl.CircleShape(80), + 75, 110, wx.Pen(wx.BLUE, 3), wx.GREEN_BRUSH, "Circle" + ) + + self.MyAddShape( + ogl.TextShape(120, 45), + 160, 35, wx.GREEN_PEN, wx.LIGHT_GREY_BRUSH, "OGL is now a\npure Python lib!" + ) + + self.MyAddShape( + ogl.RectangleShape(85, 50), + 305, 60, wx.BLACK_PEN, wx.LIGHT_GREY_BRUSH, "Rectangle" + ) + + self.MyAddShape( + DrawnShape(), + 500, 80, wx.BLACK_PEN, wx.BLACK_BRUSH, "DrawnShape" + ) + + ds = self.MyAddShape( + DividedShape(140, 150, self), + 520, 265, wx.BLACK_PEN, dsBrush, '' + ) + + self.MyAddShape( + DiamondShape(90, 90), + 355, 260, wx.Pen(wx.BLUE, 3, wx.DOT), wx.RED_BRUSH, "Polygon" + ) + + self.MyAddShape( + RoundedRectangleShape(95, 70), + 345, 145, wx.Pen(wx.RED, 2), rRectBrush, "Rounded Rect" + ) + + bmp = images.Test2.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + bmp.SetMask(mask) + + s = ogl.BitmapShape() + s.SetBitmap(bmp) + self.MyAddShape(s, 225, 130, None, None, "Bitmap") + + #dc = wx.ClientDC(self) + #self.PrepareDC(dc) + + for x in range(len(self.shapes)): + fromShape = self.shapes[x] + if x+1 == len(self.shapes): + toShape = self.shapes[0] + else: + toShape = self.shapes[x+1] + + line = ogl.LineShape() + line.SetCanvas(self) + line.SetPen(wx.BLACK_PEN) + line.SetBrush(wx.BLACK_BRUSH) + line.AddArrow(ogl.ARROW_ARROW) + line.MakeLineControlPoints(2) + fromShape.AddLine(line, toShape) + self.diagram.AddShape(line) + line.Show(True) + + + def MyAddShape(self, shape, x, y, pen, brush, text): + # Composites have to be moved for all children to get in place + if isinstance(shape, ogl.CompositeShape): + dc = wx.ClientDC(self) + self.PrepareDC(dc) + shape.Move(dc, x, y) + else: + shape.SetDraggable(True, True) + shape.SetCanvas(self) + shape.SetX(x) + shape.SetY(y) + if pen: shape.SetPen(pen) + if brush: shape.SetBrush(brush) + if text: + for line in text.split('\n'): + shape.AddText(line) + #shape.SetShadowMode(ogl.SHADOW_RIGHT) + self.diagram.AddShape(shape) + shape.Show(True) + + evthandler = MyEvtHandler(self.log, self.frame) + evthandler.SetShape(shape) + evthandler.SetPreviousHandler(shape.GetEventHandler()) + shape.SetEventHandler(evthandler) + + self.shapes.append(shape) + return shape + + + def OnBeginDragLeft(self, x, y, keys): + self.log.write("OnBeginDragLeft: %s, %s, %s\n" % (x, y, keys)) + + def OnEndDragLeft(self, x, y, keys): + self.log.write("OnEndDragLeft: %s, %s, %s\n" % (x, y, keys)) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + # This creates some pens and brushes that the OGL library uses. + # It should be called after the app object has been created, but + # before OGL is used. + ogl.OGLInitialize() + + win = TestWindow(nb, log, frame) + return win + +#---------------------------------------------------------------------- + + +overview = """ +

Object Graphics Library

+ +The Object Graphics Library is a library supporting the creation and +manipulation of simple and complex graphic images on a canvas. + +

The OGL library was originally written in C++ and provided to +wxPython via an extension module wrapper as is most of the rest of +wxPython. The code has now been ported to Python (with many thanks to +Pierre Hjälm!) in order to make it be more easily maintainable and +less likely to get rusty because nobody cares about the C++ lib any +more. + +""" + +if __name__ == '__main__': + import sys, os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/OwnerDrawnComboBox.py b/demo/OwnerDrawnComboBox.py new file mode 100644 index 00000000..ada91fb1 --- /dev/null +++ b/demo/OwnerDrawnComboBox.py @@ -0,0 +1,151 @@ + +import wx +import wx.combo + +#---------------------------------------------------------------------- +# This ComboBox class graphically displays the various pen styles that +# are available, making it easy for the user to choose the style they +# want. + +class PenStyleComboBox(wx.combo.OwnerDrawnComboBox): + + # Overridden from OwnerDrawnComboBox, called to draw each + # item in the list + def OnDrawItem(self, dc, rect, item, flags): + if item == wx.NOT_FOUND: + # painting the control, but there is no valid item selected yet + return + + r = wx.Rect(*rect) # make a copy + r.Deflate(3, 5) + + penStyle = wx.SOLID + if item == 1: + penStyle = wx.TRANSPARENT + elif item == 2: + penStyle = wx.DOT + elif item == 3: + penStyle = wx.LONG_DASH + elif item == 4: + penStyle = wx.SHORT_DASH + elif item == 5: + penStyle = wx.DOT_DASH + elif item == 6: + penStyle = wx.BDIAGONAL_HATCH + elif item == 7: + penStyle = wx.CROSSDIAG_HATCH + elif item == 8: + penStyle = wx.FDIAGONAL_HATCH + elif item == 9: + penStyle = wx.CROSS_HATCH + elif item == 10: + penStyle = wx.HORIZONTAL_HATCH + elif item == 11: + penStyle = wx.VERTICAL_HATCH + + pen = wx.Pen(dc.GetTextForeground(), 3, penStyle) + dc.SetPen(pen) + + if flags & wx.combo.ODCB_PAINTING_CONTROL: + # for painting the control itself + dc.DrawLine( r.x+5, r.y+r.height/2, r.x+r.width - 5, r.y+r.height/2 ) + + else: + # for painting the items in the popup + dc.DrawText(self.GetString( item ), + r.x + 3, + (r.y + 0) + ( (r.height/2) - dc.GetCharHeight() )/2 + ) + dc.DrawLine( r.x+5, r.y+((r.height/4)*3)+1, r.x+r.width - 5, r.y+((r.height/4)*3)+1 ) + + + # Overridden from OwnerDrawnComboBox, called for drawing the + # background area of each item. + def OnDrawBackground(self, dc, rect, item, flags): + # If the item is selected, or its item # iseven, or we are painting the + # combo control itself, then use the default rendering. + if (item & 1 == 0 or flags & (wx.combo.ODCB_PAINTING_CONTROL | + wx.combo.ODCB_PAINTING_SELECTED)): + wx.combo.OwnerDrawnComboBox.OnDrawBackground(self, dc, rect, item, flags) + return + + # Otherwise, draw every other background with different colour. + bgCol = wx.Colour(240,240,250) + dc.SetBrush(wx.Brush(bgCol)) + dc.SetPen(wx.Pen(bgCol)) + dc.DrawRectangleRect(rect); + + + + # Overridden from OwnerDrawnComboBox, should return the height + # needed to display an item in the popup, or -1 for default + def OnMeasureItem(self, item): + # Simply demonstrate the ability to have variable-height items + if item & 1: + return 36 + else: + return 24 + + # Overridden from OwnerDrawnComboBox. Callback for item width, or + # -1 for default/undetermined + def OnMeasureItemWidth(self, item): + return -1; # default - will be measured from text width + + + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + penStyles = [ + "Solid", + "Transparent", + "Dot", + "Long Dash", + "Short Dash", + "Dot Dash", + "Backward Diagonal Hatch", + "Cross-diagonal Hatch", + "Forward Diagonal Hatch", + "Cross Hatch", + "Horizontal Hatch", + "Vertical Hatch", + ] + + wx.StaticText(self, -1, "Pen Styles:", (20, 20)) + pscb = PenStyleComboBox(self, choices=penStyles, style=wx.CB_READONLY, + pos=(20,40), size=(250, -1)) + + self.pscb = pscb + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.combo.OwnerDrawnComboBox

+ +wx.combo.OwnerDrawnComboBox is a combobox with owner-drawn list +items. In essence, it is a wx.combo.ComboCtrl with wx.VListBox popup and +wx.ControlWithItems interface. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/PDFViewer.py b/demo/PDFViewer.py new file mode 100644 index 00000000..a48a8a69 --- /dev/null +++ b/demo/PDFViewer.py @@ -0,0 +1,100 @@ + +import wx + +try: + import pyPdf + from wx.lib.pdfviewer import pdfViewer, pdfButtonPanel + havePyPdf = True +except ImportError: + havePyPdf = False + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + hsizer = wx.BoxSizer( wx.HORIZONTAL ) + vsizer = wx.BoxSizer( wx.VERTICAL ) + self.buttonpanel = pdfButtonPanel(self, wx.NewId(), + wx.DefaultPosition, wx.DefaultSize, 0) + vsizer.Add(self.buttonpanel, 0, + wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT|wx.TOP, 5) + self.viewer = pdfViewer( self, wx.NewId(), wx.DefaultPosition, + wx.DefaultSize, wx.HSCROLL|wx.VSCROLL|wx.SUNKEN_BORDER) + vsizer.Add(self.viewer, 1, wx.GROW|wx.LEFT|wx.RIGHT|wx.BOTTOM, 5) + loadbutton = wx.Button(self, wx.NewId(), "Load PDF file", + wx.DefaultPosition, wx.DefaultSize, 0 ) + vsizer.Add(loadbutton, 0, wx.ALIGN_CENTER|wx.ALL, 5) + hsizer.Add(vsizer, 1, wx.GROW|wx.ALIGN_CENTER_HORIZONTAL|wx.ALL, 5) + self.SetSizer(hsizer) + self.SetAutoLayout(True) + + # introduce buttonpanel and viewer to each other + self.buttonpanel.viewer = self.viewer + self.viewer.buttonpanel = self.buttonpanel + + self.Bind(wx.EVT_BUTTON, self.OnLoadButton, loadbutton) + + def OnLoadButton(self, event): + dlg = wx.FileDialog(self, wildcard="*.pdf") + if dlg.ShowModal() == wx.ID_OK: + wx.BeginBusyCursor() + self.viewer.LoadFile(dlg.GetPath()) + wx.EndBusyCursor() + dlg.Destroy() + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + if havePyPdf: + win = TestPanel(nb, log) + return win + else: + from Main import MessagePanel + win = MessagePanel(nb, + 'This demo requires the pyPdf package to be installed.\n' + 'See: http://pybrary.net/pyPdf/', + 'Sorry', wx.ICON_WARNING) + return win + +overview = """\ + +

wx.lib.pdfviewer

+ +The wx.lib.pdfviewer.pdfViewer class is derived from wx.ScrolledWindow +and can display and print PDF files. The whole file can be scrolled from +end to end at whatever magnification (zoom-level) is specified. + +

The viewer uses pyPdf to parse the pdf file so it is a requirement that +this must be installed. The pyPdf home page is http://pybrary.net/pyPdf/ +and the library can also be downloaded from http://pypi.python.org/pypi/pyPdf/1.12 + +

There is an optional pdfButtonPanel class, derived from wx.lib.agw.buttonpanel, +that can be placed, for example, at the top of the scrolled viewer window, +and which contains navigation and zoom controls. + +

Alternatively you can drive the viewer from controls in your own application. +Externally callable methods are: LoadFile, Save, Print, SetZoom, and GoPage. +(See pdfviewer.__init__.py) + +

The viewer renders the pdf file content using Cairo if installed, +otherwise wx.GraphicsContext is used. Printing is achieved by writing +directly to a wx.PrintDC and using wx.Printer. + +

Please note that pdfviewer is a far from complete implementation of the pdf +specification and will probably fail to display any random file you supply. +However it does seem to be OK with the sort of files produced by ReportLab that +use Western languages. The biggest limitation is probably that it doesn't (yet?) +support embedded fonts and will substitute one of the standard fonts instead. + + +""" + +#---------------------------------------------------------------------- + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/PageSetupDialog.py b/demo/PageSetupDialog.py new file mode 100644 index 00000000..d81a3149 --- /dev/null +++ b/demo/PageSetupDialog.py @@ -0,0 +1,69 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a PageSetupDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + data = wx.PageSetupDialogData() + data.SetMarginTopLeft( (15, 15) ) + data.SetMarginBottomRight( (15, 15) ) + #data.SetDefaultMinMargins(True) + data.SetPaperId(wx.PAPER_LETTER) + + dlg = wx.PageSetupDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetPageSetupData() + tl = data.GetMarginTopLeft() + br = data.GetMarginBottomRight() + self.log.WriteText('Margins are: %s %s\n' % (str(tl), str(br))) + + dlg.Destroy() + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = """\ +This class represents the page setup common dialog. The page setup dialog is standard +from Windows 95 on, replacing the print setup dialog (which is retained in Windows +and wxWindows for backward compatibility). On Windows 95 and NT 4.0 and above, +the page setup dialog is native to the windowing system, otherwise it is emulated. + +The page setup dialog contains controls for paper size (A4, A5 etc.), orientation +(landscape or portrait), and controls for setting left, top, right and bottom margin +sizes in millimetres. + +When the dialog has been closed, you need to query the wx.PageSetupDialogData object +associated with the dialog. + +Note that the OK and Cancel buttons do not destroy the dialog; this must be done by +the application. As with other dialogs, do not destroy the dialog until you are done +with the data, and, conversely, do not use the wx.PageSetupDialogData after the +dialog is destroyed. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/PenAndBrushStyles.py b/demo/PenAndBrushStyles.py new file mode 100644 index 00000000..b66dc816 --- /dev/null +++ b/demo/PenAndBrushStyles.py @@ -0,0 +1,180 @@ +import wx +import images + + +pen_styles = ["wx.SOLID", "wx.TRANSPARENT", "wx.DOT", "wx.LONG_DASH", + "wx.SHORT_DASH", "wx.DOT_DASH", "wx.BDIAGONAL_HATCH", + "wx.CROSSDIAG_HATCH", "wx.FDIAGONAL_HATCH", "wx.CROSS_HATCH", + "wx.HORIZONTAL_HATCH", "wx.VERTICAL_HATCH", "wx.USER_DASH"] +if 'wxMSW' in wx.PlatformInfo: + pen_styles.append("wx.STIPPLE") + +brush_styles = ["wx.SOLID", "wx.TRANSPARENT", "wx.STIPPLE", "wx.BDIAGONAL_HATCH", + "wx.CROSSDIAG_HATCH", "wx.FDIAGONAL_HATCH", "wx.CROSS_HATCH", + "wx.HORIZONTAL_HATCH", "wx.VERTICAL_HATCH"] + + + + +class BasePanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, style=wx.SUNKEN_BORDER|wx.WANTS_CHARS) + + self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def OnSize(self, event): + event.Skip() + self.Refresh() + + +class PenPanel(BasePanel): + + def __init__(self, parent, pen_name): + BasePanel.__init__(self, parent) + self.pen_name = pen_name + + + def OnPaint(self, event): + width, height = self.GetClientSize() + + dc = wx.AutoBufferedPaintDC(self) + dc.SetBackground(wx.WHITE_BRUSH) + dc.Clear() + + font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + font.MakeSmaller() + dc.SetFont(font) + w, labelHeight = dc.GetTextExtent('Wy') + + name = self.pen_name + + if "STIPPLE" in name: + bmp = images.Smiles.GetBitmap() + penWidth = 8 #bmp.GetHeight() + pen = wx.Pen(wx.BLUE, penWidth, eval(name)) + pen.SetStipple(bmp) + else: + penWidth = 3 + if 'HATCH' in name: + penWidth = 8 + pen = wx.Pen(wx.BLUE, penWidth, eval(name)) + + if "USER" in name: + # dash values represent units on, off, on. off... + pen.SetDashes([2, 5, 2, 2]) + name += " ([2, 5, 2, 2])" + + dc.SetTextForeground(wx.BLACK) + dc.DrawText(name, 1, 1) + + dc.SetPen(pen) + y = labelHeight + (height - labelHeight)/2 + dc.DrawLine(5, y, width-5, y) + + +class BrushPanel(BasePanel): + def __init__(self, parent, brush_name): + BasePanel.__init__(self, parent) + self.brush_name = brush_name + + + def OnPaint(self, event): + width, height = self.GetClientSize() + + dc = wx.AutoBufferedPaintDC(self) + dc.SetBackground(wx.WHITE_BRUSH) + dc.Clear() + + font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + font.MakeSmaller() + dc.SetFont(font) + w, labelHeight = dc.GetTextExtent('Wy') + + dc.SetPen(wx.TRANSPARENT_PEN) + name = self.brush_name + + if "STIPPLE" in name: + bmp = images.Smiles.GetBitmap() + bmp.SetMask(None) + brush = wx.BrushFromBitmap(bmp) + else: + brush = wx.Brush(wx.BLUE, eval(name)) + + dc.SetTextForeground(wx.BLACK) + dc.DrawText(name, 1, 1) + + dc.SetBrush(brush) + dc.DrawRectangle(5, labelHeight+2, width-10, height-labelHeight-5-2) + + + +class TestPanel(wx.Panel): + def __init__(self, *args, **kw): + wx.Panel.__init__(self, *args, **kw) + + font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + font.SetWeight(wx.BOLD) + + mainSizer = wx.BoxSizer(wx.VERTICAL) + label1 = wx.StaticText(self, -1, "Pen Styles:") + label1.SetFont(font) + + mainSizer.Add(label1, 0, wx.EXPAND|wx.ALL, 10) + + gs1 = wx.GridSizer(4, 4, 3, 3) # rows, cols, vgap, hgap + + for pen_name in pen_styles: + small = PenPanel(self, pen_name) + gs1.Add(small, 0, wx.EXPAND) + + mainSizer.Add(gs1, 1, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, 10) + + label2 = wx.StaticText(self, -1, "Brush Styles:") + label2.SetFont(font) + + mainSizer.Add(label2, 0, wx.EXPAND|wx.ALL, 10) + + gs2 = wx.GridSizer(3, 3, 3, 3) # rows, cols, vgap, hgap + + for brush_name in brush_styles: + small = BrushPanel(self, brush_name) + gs2.Add(small, 0, wx.EXPAND) + + mainSizer.Add(gs2, 1, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.BOTTOM, 10) + + self.SetSizer(mainSizer) + + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Pen and Brush Styles

+ +This sample shows an e3xample of drawing with each of the available +wx.Pen and wx.Brush styles. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + diff --git a/demo/Pickers.py b/demo/Pickers.py new file mode 100644 index 00000000..1291533a --- /dev/null +++ b/demo/Pickers.py @@ -0,0 +1,119 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + box = wx.BoxSizer(wx.VERTICAL) + title = wx.StaticText(self, -1, "Picker Controls") + title.SetFont(wx.FFont(24, wx.FONTFAMILY_SWISS, wx.FONTFLAG_BOLD)) + title.SetForegroundColour("navy") + box.Add(title, 0, wx.ALIGN_CENTER|wx.ALL, 5) + #print title.GetBestSize(), title.GetMinSize(), title.GetSize() + + box.Add(wx.StaticLine(self), 0, wx.EXPAND) + + fgs = wx.FlexGridSizer(cols=4, hgap=5, vgap=5) + fgs.AddGrowableCol(3) + fgs.Add((10,10)) # spacer + lbl = wx.StaticText(self, -1, "default style") + lbl.SetFont(wx.FFont(12, wx.FONTFAMILY_SWISS, wx.FONTFLAG_BOLD)) + fgs.Add(lbl) + fgs.Add((10,10)) # spacer + lbl = wx.StaticText(self, -1, "with textctrl") + lbl.SetFont(wx.FFont(12, wx.FONTFAMILY_SWISS, wx.FONTFLAG_BOLD)) + fgs.Add(lbl, 0, wx.ALIGN_CENTER) + + fgs.Add(wx.StaticText(self, -1, "wx.ColourPickerCtrl:"), 0, wx.ALIGN_CENTER_VERTICAL) + cp1 = wx.ColourPickerCtrl(self) + fgs.Add(cp1, 0, wx.ALIGN_CENTER) + fgs.Add((10,10)) # spacer + cp2 = wx.ColourPickerCtrl(self, style=wx.CLRP_USE_TEXTCTRL) + cp2.SetTextCtrlProportion(5) + fgs.Add(cp2, 0, wx.EXPAND) + fgs.Add(wx.StaticText(self, -1, " with label:"), 0, wx.ALIGN_CENTER_VERTICAL) + cp3 = wx.ColourPickerCtrl(self, style=wx.CLRP_SHOW_LABEL) + fgs.Add(cp3, 0, wx.ALIGN_CENTER) + fgs.Add((10,10)) # spacer + fgs.Add((10,10)) # spacer + self.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnPickColor, cp1) + self.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnPickColor, cp2) + self.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnPickColor, cp3) + + fgs.Add(wx.StaticText(self, -1, "wx.DirPickerCtrl:"), 0, wx.ALIGN_CENTER_VERTICAL) + dp1 = wx.DirPickerCtrl(self) + fgs.Add(dp1, 0, wx.ALIGN_CENTER) + fgs.Add((10,10)) # spacer + dp2 = wx.DirPickerCtrl(self, style=wx.DIRP_USE_TEXTCTRL) + dp2.SetTextCtrlProportion(2) + fgs.Add(dp2, 0, wx.EXPAND) + self.Bind(wx.EVT_DIRPICKER_CHANGED, self.OnPickFileDir, dp1) + self.Bind(wx.EVT_DIRPICKER_CHANGED, self.OnPickFileDir, dp2) + + fgs.Add(wx.StaticText(self, -1, "wx.FilePickerCtrl:"), 0, wx.ALIGN_CENTER_VERTICAL) + fp1 = wx.FilePickerCtrl(self) + fgs.Add(fp1, 0, wx.ALIGN_CENTER) + fgs.Add((10,10)) # spacer + fp2 = wx.FilePickerCtrl(self, style=wx.FLP_USE_TEXTCTRL) + fp2.SetTextCtrlProportion(2) + fgs.Add(fp2, 0, wx.EXPAND) + self.Bind(wx.EVT_FILEPICKER_CHANGED, self.OnPickFileDir, fp1) + self.Bind(wx.EVT_FILEPICKER_CHANGED, self.OnPickFileDir, fp2) + + fgs.Add(wx.StaticText(self, -1, "wx.FontPickerCtrl:"), 0, wx.ALIGN_CENTER_VERTICAL) + fnt1 = wx.FontPickerCtrl(self, style=wx.FNTP_FONTDESC_AS_LABEL) + fgs.Add(fnt1, 0, wx.ALIGN_CENTER) + fgs.Add((10,10)) # spacer + fnt2 = wx.FontPickerCtrl(self, style=wx.FNTP_FONTDESC_AS_LABEL|wx.FNTP_USE_TEXTCTRL) + fnt2.SetTextCtrlProportion(2) + fgs.Add(fnt2, 0, wx.EXPAND) + self.Bind(wx.EVT_FONTPICKER_CHANGED, self.OnPickFont, fnt1) + self.Bind(wx.EVT_FONTPICKER_CHANGED, self.OnPickFont, fnt2) + + + box.Add(fgs, 1, wx.EXPAND|wx.ALL, 5) + self.SetSizer(box) + + + def OnPickColor(self, evt): + self.log.write("You chose: %s\n" % repr(evt.GetColour())) + + def OnPickFileDir(self, evt): + self.log.write("You chose: %s\n" % repr(evt.GetPath())) + + def OnPickFont(self, evt): + font = evt.GetFont() + self.log.write("You chose: %s\n" % font.GetNativeFontInfoUserDesc()) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Picker Controls

+ +The Picker controls are either native or generic controls usually +comprised of a button and with an optional text control next to it. +The pickers enable the user to choose something using one of the +common dialogs and then displays the result in some way. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/PlateButton.py b/demo/PlateButton.py new file mode 100644 index 00000000..33c10de0 --- /dev/null +++ b/demo/PlateButton.py @@ -0,0 +1,428 @@ +############################################################################### +# Name: PlateButtonDemo.py # +# Purpose: PlateButton Test and Demo File # +# Author: Cody Precord # +# Copyright: (c) 2007 Cody Precord # +# Licence: wxWindows Licence # +############################################################################### + +#-----------------------------------------------------------------------------# +# Imports +import os +import webbrowser +import wx +import wx.lib.scrolledpanel as scrolled +try: + import wx.lib.platebtn as platebtn +except ImportError: + import platebtn + +#-----------------------------------------------------------------------------# + +class TestPanel(scrolled.ScrolledPanel): + def __init__(self, parent, log): + self.log = log + scrolled.ScrolledPanel.__init__(self, parent, size=(400, 400)) + + # Layout + self.__DoLayout() + self.SetupScrolling() + + # Event Handlers + self.Bind(wx.EVT_BUTTON, self.OnButton) + self.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggleButton) + self.Bind(wx.EVT_MENU, self.OnMenu) + + def __DoLayout(self): + """Layout the panel""" + # Make three different panels of buttons with different backgrounds + # to test transparency and appearance of buttons under different use + # cases + p1 = wx.Panel(self) + p2 = GradientPanel(self) + p3 = wx.Panel(self) + p3.SetBackgroundColour(wx.BLUE) + + self.__LayoutPanel(p1, "Default Background:") + self.__LayoutPanel(p2, "Gradient Background:", exstyle=True) + self.__LayoutPanel(p3, "Solid Background:") + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.AddMany([(p1, 0, wx.EXPAND), (p2, 0, wx.EXPAND), + (p3, 0, wx.EXPAND)]) + hsizer = wx.BoxSizer(wx.HORIZONTAL) + hsizer.Add(sizer, 1, wx.EXPAND) + self.SetSizer(hsizer) + self.SetAutoLayout(True) + + def __LayoutPanel(self, panel, label, exstyle=False): + """Puts a set of controls in the panel + @param panel: panel to layout + @param label: panels title + @param exstyle: Set the PB_STYLE_NOBG or not + + """ + # Bitmaps (32x32) and (16x16) + devil = Devil.GetBitmap() # 32x32 + monkey = Monkey.GetBitmap() # 32x32 + address = Address.GetBitmap() # 16x16 + folder = Home.GetBitmap() + bookmark = Book.GetBitmap() # 16x16 + + vsizer = wx.BoxSizer(wx.VERTICAL) + hsizer1 = wx.BoxSizer(wx.HORIZONTAL) + hsizer1.Add((15, 15)) + hsizer2 = wx.BoxSizer(wx.HORIZONTAL) + hsizer2.Add((15, 15)) + hsizer3 = wx.BoxSizer(wx.HORIZONTAL) + hsizer3.Add((15, 15)) + hsizer4 = wx.BoxSizer(wx.HORIZONTAL) + hsizer4.Add((15, 15)) + + # Button Styles + default = platebtn.PB_STYLE_DEFAULT + square = platebtn.PB_STYLE_SQUARE + sqgrad = platebtn.PB_STYLE_SQUARE | platebtn.PB_STYLE_GRADIENT + gradient = platebtn.PB_STYLE_GRADIENT + droparrow = platebtn.PB_STYLE_DROPARROW + toggle = default | platebtn.PB_STYLE_TOGGLE + + # Create a number of different PlateButtons + # Each button is created in the below loop by using the data set in this + # lists tuple + # (bmp, label, Style, Variant, Menu, Color, Enable) + btype = [(None, "Normal PlateButton", default, None, None, None, True), + (devil, "Normal w/Bitmap", default, None, None, None, True), + (devil, "Disabled", default, None, None, None, False), + (None, "Normal w/Menu", default, None, True, None, True), + (folder, "Home Folder", default, None, True, None, True), + # Row 2 + (None, "Square PlateButton", square, None, None, None, True), + (address, "Square/Bitmap", square, None, None, None, True), + (monkey, "Square/Gradient", sqgrad, None, None, None, True), + (address, "Square/Small", square, wx.WINDOW_VARIANT_SMALL, True, None, True), + (address, "Small Bitmap", default, wx.WINDOW_VARIANT_SMALL, None, wx.Colour(33, 33, 33), True), + # Row 3 + (devil, "Custom Color", default, None, None, wx.RED, True), + (monkey, "Gradient Highlight", gradient, None, None, None, True), + (monkey, "Custom Gradient", gradient, None, None, wx.Colour(245, 55, 245), True), + (None, "Drop Arrow", droparrow, None, None, None, True), + (devil, "", default, None, None, None, True), + (bookmark, "", default, None, True, None, True), + (monkey, "", square, None, None, None, True), + # Row 4 + (None, "Toggle PlateButton", toggle, None, None, None, True), + (devil, "Toggle w/Bitmap", toggle, None, None, None, True), + (None, "Toggle w/Menu", toggle, None, True, None, True), + ] + + # Make and layout three rows of buttons in the panel + for btn in btype: + if exstyle: + # With this style flag set the button can appear transparent on + # on top of a background that is not solid in color, such as the + # gradient panel in this demo. + # + # Note: This flag only has affect on wxMSW and should only be + # set when the background is not a solid color. On wxMac + # it is a no-op as this type of transparency is achieved + # without any help needed. On wxGtk it doesn't hurt to + # set but also unfortunatly doesn't help at all. + bstyle = btn[2] | platebtn.PB_STYLE_NOBG + else: + bstyle = btn[2] + + if btype.index(btn) < 5: + tsizer = hsizer1 + elif btype.index(btn) < 10: + tsizer = hsizer2 + elif btype.index(btn) < 17: + tsizer = hsizer3 + else: + tsizer = hsizer4 + + tbtn = platebtn.PlateButton(panel, wx.ID_ANY, btn[1], btn[0], style=bstyle) + + # Set a custom window size variant? + if btn[3] is not None: + tbtn.SetWindowVariant(btn[3]) + + # Make a menu for the button? + if btn[4] is not None: + menu = wx.Menu() + if btn[0] is not None and btn[0] == folder: + for fname in os.listdir(wx.GetHomeDir()): + if not fname.startswith('.'): + menu.Append(wx.NewId(), fname) + elif btn[0] is not None and btn[0] == bookmark: + for url in ['http://wxpython.org', 'http://slashdot.org', + 'http://editra.org', 'http://xkcd.com']: + menu.Append(wx.NewId(), url, "Open %s in your browser" % url) + else: + menu.Append(wx.NewId(), "Menu Item 1") + menu.Append(wx.NewId(), "Menu Item 2") + menu.Append(wx.NewId(), "Menu Item 3") + tbtn.SetMenu(menu) + + # Set a custom colour? + if btn[5] is not None: + tbtn.SetPressColor(btn[5]) + + if btn[2] == droparrow: + + tbtn.Bind(platebtn.EVT_PLATEBTN_DROPARROW_PRESSED, self.OnDropArrowPressed) + + # Enable/Disable button state + tbtn.Enable(btn[6]) + + tsizer.AddMany([(tbtn, 0, wx.ALIGN_CENTER), ((10, 10))]) + + txt_sz = wx.BoxSizer(wx.HORIZONTAL) + txt_sz.AddMany([((5, 5)), (wx.StaticText(panel, label=label), 0, wx.ALIGN_LEFT)]) + vsizer.AddMany([((10, 10)), + (txt_sz, 0, wx.ALIGN_LEFT), + ((10, 10)), (hsizer1, 0, wx.EXPAND), ((10, 10)), + (hsizer2, 0, wx.EXPAND), ((10, 10)), + (hsizer3, 0, wx.EXPAND), ((10, 10)), + (hsizer4, 0, wx.EXPAND), ((10, 10))]) + panel.SetSizer(vsizer) + + def OnDropArrowPressed(self, evt): + self.log.write("DROPARROW PRESSED") + + def OnButton(self, evt): + self.log.write("BUTTON CLICKED: Id: %d, Label: %s" % \ + (evt.GetId(), evt.GetEventObject().LabelText)) + + def OnToggleButton(self, evt): + self.log.write("TOGGLE BUTTON CLICKED: Id: %d, Label: %s, Pressed: %s" % \ + (evt.GetId(), evt.GetEventObject().LabelText, + evt.GetEventObject().IsPressed())) + + def OnChildFocus(self, evt): + """Override ScrolledPanel.OnChildFocus to prevent erratic + scrolling on wxMac. + + """ + if wx.Platform != '__WXMAC__': + evt.Skip() + + child = evt.GetWindow() + self.ScrollChildIntoView(child) + + def OnMenu(self, evt): + """Events from button menus""" + self.log.write("MENU SELECTED: %d" % evt.GetId()) + e_obj = evt.GetEventObject() + mitem = e_obj.FindItemById(evt.GetId()) + if mitem != wx.NOT_FOUND: + label = mitem.GetItemLabel() + if label.startswith('http://'): + webbrowser.open(label, True) + +#-----------------------------------------------------------------------------# + +class GradientPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + gc = wx.GraphicsContext.Create(dc) + col1 = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DSHADOW) + col2 = platebtn.AdjustColour(col1, -90) + col1 = platebtn.AdjustColour(col1, 90) + rect = self.GetClientRect() + grad = gc.CreateLinearGradientBrush(0, 1, 0, rect.height - 1, col2, col1) + + pen_col = tuple([min(190, x) for x in platebtn.AdjustColour(col1, -60)]) + gc.SetPen(gc.CreatePen(wx.Pen(pen_col, 1))) + gc.SetBrush(grad) + gc.DrawRectangle(0, 1, rect.width - 0.5, rect.height - 0.5) + + evt.Skip() +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +class TestLog: + def __init__(self): + pass + + def write(self, msg): + print msg + +#---------------------------------------------------------------------- + +overview = platebtn.__doc__ + +#---------------------------------------------------------------------- +# Icon Data +# All icons from the Tango Icon Set +from wx.lib.embeddedimage import PyEmbeddedImage + +Book = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAkdJ" + "REFUOI2VkslrU1EUh787vJeXNNpMGA01DlECrd0UWrD+A06oIIoLwY24FwQRNIu6EBeKy4Jb" + "XRS6dEK0WrC2XSgFFZq0RUoHmg4WYslrxuuiGpJWKv4295zLOd/vnssR/FbX8ZvXQTzAGPPn" + "ziAMgJAie//ifKL7ZC6pjOwylJc01WGiHUsaoLe3tz+bzZ6fmJwisxQTd25d3iAIwMDde09i" + "L76W3GhbjL37jyLtfaysvP0QXf52VQF0dnb2pVIpdvj9DAx/JxiN8Dk9x+TMMm6hxMT4NDeu" + "HaG97RB281ksZz9Se+OyNDqvqVMul6NcyrOyukp2cRUAR1cpl/LkfpYpV8voiotQkmJ+Bo+U" + "OVkPqFQqVErrFAsuBXeNortGad2lXHT5Ml5gZk5QyQ9g8q+ZnR6magqfGgAAQtlobWPZHpTl" + "QWkLIS32xOKEdp/ArbYjrBijYxaW+2OsASCEQFteLMeH7fjxeJuwHC/a8jI3O0c6M4URMbA7" + "mF9sQhwYXNebXyClQkqF0hYASllIpWlpaSGZTIIQCKExRgDQALBtuxbvCvmpVmsrgeNVm702" + "DOsTn88HgDHw8c0IIwOjtb1q8jUjhNge4PF4AHj/aoh4bCcH4wHevRzCGMPCwgLpdHoLoGEE" + "x3EAuHLhGJfOdSOlpP/ZCI+fDtLa2koikdgeEIlEeHj7NEopMpkMQgjaDwd5lDpDMBgE2DJG" + "AyAQCBAIBBBC1Arrz7/9QQMgFAptKfiXNEA4HH7e09Nz6n8aw+FwH8AvVXjA30OIWrcAAAAA" + "SUVORK5CYII=") + +Address = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAmtJ" + "REFUOI19kstLlFEYxn/nfN+ZizPOeBnHS1OklmQSFVjRH9CiTUKbIKRl4V8QuFBwIUTtgqBF" + "u3BfuW0XtAhsYWk6BqOZl7mgc/+c73JafKmZ1gNnc+D9ned5ziu0fqievep/Hg83HpXqAVa2" + "2inXgmgE/9HUzPToJICYfvn0xe0r22MXL9wEM0WusEQ6N8DmbjMaiZQ+aB9XtRqUNmd5cH2c" + "eMfIY1NJPTbQP4QZuQUiRDJhkC/OsZrrI7haQdX38JRBpStBPRGnsy1CCYh3jFDMvXliWrbC" + "A/AskBLX3sauS2KrWQo9Z2hEmzCtPeKZTVxlQFuEpmDjIIu5stlGrtxGB+9xXYHjZimmY+wk" + "ezAaNsn5FbQQ7JxLEfuRhd5OwgH7EGC7BmU9jFXcIp9dIpG8RimTYW8wSmIhQymVJLpVwAkF" + "UDULgI/fLGy1zNe5JiRAQIWxvG62iuepub14tkQLgXRctGGAEATLNZxw4Nh3SAAh/I61MPyr" + "SAhVtbBam/3XA4rY2jal050AeEQPIxzl+SCvt4tY+ifFs9044SCIozsRyijuzsDlxZoP0GjQ" + "kGyP+046WijtOcTWs6hqHTegyA/1nbhRvgMNSpm0tESxbIfO1gixcBAGTh34ih/x+BegUq3z" + "bvYDptR42j+OoxFSEFAGQggE4LoemfW811Ury++LiwD3TIAv8yvcGIwcrO1JklJSEy0sFxpy" + "rfcSw7/NmAC7lSp9yWZSqZ5jg+KPAhfSGyd2MPUpnZ9w6jVvI9+QoZDCsZ0jgfcRjutx52q7" + "fvu5cEAVgLw//noSmPin/xM0Mz0qAH4B9vTxRRZgeg8AAAAASUVORK5CYII=") + +Home = PyEmbeddedImage( + "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") + +Monkey = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAACDhJ" + "REFUWIXtlmuMXVUVgL+99zn33HvnPmbmDtOZYabTKXSGmdAWi6JAi6U1GgMN2qAIgYgaMAKJ" + "4g8jRhN+GGNMTESDxogQEhtjIiAYqT+0pfZhkdBSSqedFqbTofN+3Lnv89zbH/dOGNtiUjXR" + "H65kZWc/17fWXmftA/+X/7KIy1m8eSg1JNB3xIS+UxvRE2nRDKCkWZLCvOsb+VuDfPHAcHn4" + "Pwqwub9pg23rJ1PJ1KYN67qsdb1dsZZMikQiAUCtWiVfLHNmfNI/dnoyqNYqR/1APnzgdOXN" + "fxtg6zWJh51E4gcfv3F9/Jq+LlmdG6OanyCoLmGCGgBWLImVzJJs7SbZtoaTo+/q3QePu4Hn" + "feOVU7Un/2WAW4fi32zONn/77ttubgoWzpEfPw7aRwmQDRWAAbSpK5ZDa+91iHQHu36/v1Ks" + "VL67d9j9/mUD3DLQtL4pLvffv3N7dv7sEZbKFdxIYjAkbEkyLJBRPlJAKYpRUllqgUYiiCtN" + "W7aZ5tVD/PK5PYWax5a/jFSOXxbAtsHE8O23XDvoBEvMlYps2fwxBoc2oKwY09MT7NmzG7M0" + "Xj+geTXbtt1GZ+eVhFHIqVNvsX/vbjraWikHNn84dPrknpO1ofcFuGkgl46p6o+M4W6MUFLy" + "11Tc/sB9OzZnRk68xu07PktXRwdRdRETBQhlo+0MT+96FoAv3ns/0i9iQg+hLKzUFUzNzfPS" + "C7sYWv9hnn5+T7EamKNacyPCRELwaz9Kfu3QyEJJAfR3ij1dzeoTH+qLJVpTUpU9VvddmYvH" + "TIVMppkbNl1PsDSFCV1M6GN8Fxm5XDO0if6rB0iEBbRbwEQhJvTRboFsayeTM9OU8guEBqfm" + "easHu2xroMOyQ82gFwTbzs4GT6tb+pOfbM+Ihwa7nNTpWcnQVWuZz1dF96pWjF9k44braYkL" + "tFfChAEm8jGRj/arWGEVJ6rU56IAowOMDiGKAIN0UoyOjqBiTcwXamLT+iFOnS/Ql1NW1Quz" + "uSb7mIzHeWxjj5U9u6j41hd2sPPmIXo7WjCA0YZkwkG7JUzgYoxmMu/xzJ/PMlUCYcUQlsNU" + "GZ7Ze47JQoSQFsZotFsimUyitQZgoDvHzi3r+c5D93K+aLGxx8rG4zwmo4iBQAuG1vaQiQlM" + "FNDelqNcqSGkwPUCUDYylkI6KR78yX4e3/U3HnjiFaSTRjppHnjiFR7/1as8+ON9SKe+TtpJ" + "/AikUpSqLu25FrRfI2HBxsF1hFoQRQxIQGhtsASY0EfGkvT39TBb9InFU0zNzmI15ZBOEzLW" + "xNhMAYCxmUIdIJ5mbHp5rFgHjTVhpduZmJrESaSYWqyyrrcHE3iY0MdSCq0NgJCWEmdiSnBi" + "9Dyu6yKUw5qeKzk3tUgm28bJkWHCeBvCSSOdFI9+bivppMOj92xHOmmUk+LRe7bXx+6+te59" + "PINOdXLixBuk0i1MzJfp6+4AKQmCgDdPnsFWAkuJM2LrYOKOzmb17Np2JztTVmy/YSMvHThB" + "SyZGT4sg197NHZ+6F1OeRUgLoWyEskEqhJAs10JjNOiokYwRKtvN8889Q356lNHpGnPFgJ2b" + "+zk8PE7Ccjk/7xamlqLPq7H5cGRV1v6MJGrtbtbW0bcnWSi4bLo6RyqVZvPWT/PG0ddZKFao" + "+JpIKFAOltOEFUsirBghinItIF+sMDEzz9vnJjg5cpLrb7iVmakxMnHD6fEFphcXySU95pYC" + "b3LJjOwdrn5dAHxkKNOaJPxZoNmpJOq6vmaRa4I77/oyuUySwA+YWaoys1hkdnGJ+XyRhaUi" + "rusSaY1tW7Rks7TnWljV1kpXWwuduQxO3CFf9fnNsz9kruBzbLxiIk1kS56vYn3l8HBx0QI4" + "PFxcBO766EexzGxitiWdaPH9Ei1tHRg3j+3EWd3dQm/fVUgrjrDjCMupX4eQGKProQ89TOCi" + "Q7fRerRc0Y0XBLRmmjCmvCRX1dr37CNcLsVyZV3et49QQ0JKCcYglIWQCiFV/c6lArWcBw7S" + "Tta/BDuJUHUgGnuQCqksEAKMQSqJhsS+FcYvAgBQMFeuuVjKIj8/jbATYExDaagBdN1zHdYT" + "EH3RGmknWZybwLJsKjUfBXMX2rsIAMyL0wuVINRwaP9urGRr3Qsd1o1F/nuh9spor4T2yvVK" + "GXr1eR0gAJVu49De36E1TOUrAZgXL+HwP0rPKuutUiX8Uk97OlFYmsVSkp7+TRD69TrPcjSi" + "ej/034MKPUzkIaSFne3gtYMvc+z1/WgR4/hYsRhJ7hufC4v/FGB8Liz25iy9WPZu7GhNxd4d" + "O8X83AS9/ZtwUs1gDEZHjUep8TjpsJEzNirZjGckf3zhKY4c/hNGORx5J192Pf29/afc3Rfa" + "u9QPiQ3ENw8kfpFO2DvW96aTNh5KWVw1cC3XXreZ9q41NKVzWI4DCMIwoFpcZG56nLeOHuDM" + "8BGiKCTA4fi5UrVY9V8+eNp9BHABr9FeEiDe0AQQ/+Ba55F0wnqoO5ewenJxy0QutpIIKYl0" + "VE+2xilKKrTRhKFGqjjn8144PlcNC5XgqSNj/s8bRl2g1mirgLkQILFC40CiM6uuXtNuf9VW" + "8qbWtBO1pa1EOm7hOArV2B0Z8PyIshsxVwzcxZKn/DB6dXQ2+OlsUY+uMLoMUAUql4qAABwg" + "2QBwlttMk7qip9nakkmKLUqxTiJaNSJW32QCg1kMQ/NOocrB8/nwUKkWzTfCvazLxsuN/vvm" + "wLIoILbiWmKAtUKXX6LlM+rFAUIgAoIVXruA35i/yOPLEXGB4WVdzga9AsRc6oD/Ofk7fswD" + "nMQUbKYAAAAASUVORK5CYII=") + +Devil = PyEmbeddedImage( + "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" + "kwAAAABJRU5ErkJggg==") + + +#-----------------------------------------------------------------------------# +if __name__ == '__main__': + try: + import sys + import run + except ImportError: + app = wx.PySimpleApp(False) + frame = wx.Frame(None, title="PlateButton Test") + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(TestPanel(frame, TestLog()), 1, wx.EXPAND) + frame.CreateStatusBar() + frame.SetSizer(sizer) + frame.SetInitialSize() + frame.Show() + app.MainLoop() + else: + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/PopupControl.py b/demo/PopupControl.py new file mode 100644 index 00000000..d5b17f56 --- /dev/null +++ b/demo/PopupControl.py @@ -0,0 +1,97 @@ + +import wx +import wx.lib.popupctl as pop +import wx.calendar as cal + +class TestDateControl(pop.PopupControl): + def __init__(self,*_args,**_kwargs): + pop.PopupControl.__init__(self, *_args, **_kwargs) + + self.win = wx.Window(self,-1,pos = (0,0),style = 0) + self.cal = cal.CalendarCtrl(self.win,-1,pos = (0,0)) + + bz = self.cal.GetBestSize() + self.win.SetSize(bz) + + # This method is needed to set the contents that will be displayed + # in the popup + self.SetPopupContent(self.win) + + # Event registration for date selection + self.cal.Bind(cal.EVT_CALENDAR, self.OnCalSelected) + + + # Method called when a day is selected in the calendar + def OnCalSelected(self,evt): + self.PopDown() + date = self.cal.GetDate() + + # Format the date that was selected for the text part of the control + self.SetValue('%02d/%02d/%04d' % (date.GetDay(), + date.GetMonth()+1, + date.GetYear())) + evt.Skip() + + + # Method overridden from PopupControl + # This method is called just before the popup is displayed + # Use this method to format any controls in the popup + def FormatContent(self): + # I parse the value in the text part to resemble the correct date in + # the calendar control + txtValue = self.GetValue() + dmy = txtValue.split('/') + didSet = False + + if len(dmy) == 3: + date = self.cal.GetDate() + d = int(dmy[0]) + m = int(dmy[1]) - 1 + y = int(dmy[2]) + + if d > 0 and d < 31: + if m >= 0 and m < 12: + if y > 1000: + self.cal.SetDate(wx.DateTimeFromDMY(d,m,y)) + didSet = True + + if not didSet: + self.cal.SetDate(wx.DateTime.Today()) + + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + date = TestDateControl(self, -1, pos = (30,30)) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = """ +

PopupControl

+ +PopupControl is a class that can display a value and has a button +that will popup another window similar to how a wx.ComboBox works. The +popup window can contain whatever is needed to edit the value. This +example uses a wx.CalendarCtrl. + +

Currently a wx.Dialog is used for the popup. Eventually a +wx.PopupWindow should be used... + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/PopupMenu.py b/demo/PopupMenu.py new file mode 100644 index 00000000..7d6a9059 --- /dev/null +++ b/demo/PopupMenu.py @@ -0,0 +1,156 @@ + +import wx + +import images + +#---------------------------------------------------------------------- + +text = """\ + +Right-click on any bare area of this panel (or Ctrl-click on the Mac) +to show a popup menu. Then look at the code for this sample. Notice +how the PopupMenu method is similar to the ShowModal method of a +wx.Dialog in that it doesn't return until the popup menu has been +dismissed. The event handlers for the popup menu items can either be +attached to the menu itself, or to the window that invokes PopupMenu. +""" + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + box = wx.BoxSizer(wx.VERTICAL) + + # Make and layout the controls + fs = self.GetFont().GetPointSize() + bf = wx.Font(fs+4, wx.SWISS, wx.NORMAL, wx.BOLD) + nf = wx.Font(fs+2, wx.SWISS, wx.NORMAL, wx.NORMAL) + + t = wx.StaticText(self, -1, "PopupMenu") + t.SetFont(bf) + box.Add(t, 0, wx.CENTER|wx.ALL, 5) + + box.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) + box.Add((10,20)) + + t = wx.StaticText(self, -1, text) + t.SetFont(nf) + box.Add(t, 0, wx.CENTER|wx.ALL, 5) + t.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) + + self.SetSizer(box) + + self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) + + + def OnContextMenu(self, event): + self.log.WriteText("OnContextMenu\n") + + # only do this part the first time so the events are only bound once + # + # Yet another anternate way to do IDs. Some prefer them up top to + # avoid clutter, some prefer them close to the object of interest + # for clarity. + if not hasattr(self, "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + self.popupID4 = wx.NewId() + self.popupID5 = wx.NewId() + self.popupID6 = wx.NewId() + self.popupID7 = wx.NewId() + self.popupID8 = wx.NewId() + self.popupID9 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + self.Bind(wx.EVT_MENU, self.OnPopupFour, id=self.popupID4) + self.Bind(wx.EVT_MENU, self.OnPopupFive, id=self.popupID5) + self.Bind(wx.EVT_MENU, self.OnPopupSix, id=self.popupID6) + self.Bind(wx.EVT_MENU, self.OnPopupSeven, id=self.popupID7) + self.Bind(wx.EVT_MENU, self.OnPopupEight, id=self.popupID8) + self.Bind(wx.EVT_MENU, self.OnPopupNine, id=self.popupID9) + + # make a menu + menu = wx.Menu() + # Show how to put an icon in the menu + item = wx.MenuItem(menu, self.popupID1,"One") + bmp = images.Smiles.GetBitmap() + item.SetBitmap(bmp) + menu.AppendItem(item) + # add some other items + menu.Append(self.popupID2, "Two") + menu.Append(self.popupID3, "Three") + menu.Append(self.popupID4, "Four") + menu.Append(self.popupID5, "Five") + menu.Append(self.popupID6, "Six") + # make a submenu + sm = wx.Menu() + sm.Append(self.popupID8, "sub item 1") + sm.Append(self.popupID9, "sub item 1") + menu.AppendMenu(self.popupID7, "Test Submenu", sm) + + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + self.PopupMenu(menu) + menu.Destroy() + + + def OnPopupOne(self, event): + self.log.WriteText("Popup one\n") + + def OnPopupTwo(self, event): + self.log.WriteText("Popup two\n") + + def OnPopupThree(self, event): + self.log.WriteText("Popup three\n") + + def OnPopupFour(self, event): + self.log.WriteText("Popup four\n") + + def OnPopupFive(self, event): + self.log.WriteText("Popup five\n") + + def OnPopupSix(self, event): + self.log.WriteText("Popup six\n") + + def OnPopupSeven(self, event): + self.log.WriteText("Popup seven\n") + + def OnPopupEight(self, event): + self.log.WriteText("Popup eight\n") + + def OnPopupNine(self, event): + self.log.WriteText("Popup nine\n") + + + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

PopupMenu

+""" + text + """ + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/PopupWindow.py b/demo/PopupWindow.py new file mode 100644 index 00000000..2928ff27 --- /dev/null +++ b/demo/PopupWindow.py @@ -0,0 +1,226 @@ +# +# 11/30/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Some issues with the listbox example; I tried correcting +# it but it's still not working the way it should. Commented +# out for now, as I found it. +# + +import wx + +#--------------------------------------------------------------------------- + +class TestPopup(wx.PopupWindow): + """Adds a bit of text and mouse movement to the wx.PopupWindow""" + def __init__(self, parent, style): + wx.PopupWindow.__init__(self, parent, style) + pnl = self.pnl = wx.Panel(self) + pnl.SetBackgroundColour("CADET BLUE") + + + st = wx.StaticText(pnl, -1, + "This is a special kind of top level\n" + "window that can be used for\n" + "popup menus, combobox popups\n" + "and such.\n\n" + "Try positioning the demo near\n" + "the bottom of the screen and \n" + "hit the button again.\n\n" + "In this demo this window can\n" + "be dragged with the left button\n" + "and closed with the right." + , + pos=(10,10)) + + sz = st.GetBestSize() + self.SetSize( (sz.width+20, sz.height+20) ) + pnl.SetSize( (sz.width+20, sz.height+20) ) + + pnl.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) + pnl.Bind(wx.EVT_MOTION, self.OnMouseMotion) + pnl.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) + pnl.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) + + st.Bind(wx.EVT_LEFT_DOWN, self.OnMouseLeftDown) + st.Bind(wx.EVT_MOTION, self.OnMouseMotion) + st.Bind(wx.EVT_LEFT_UP, self.OnMouseLeftUp) + st.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) + + wx.CallAfter(self.Refresh) + + + def OnMouseLeftDown(self, evt): + self.Refresh() + self.ldPos = evt.GetEventObject().ClientToScreen(evt.GetPosition()) + self.wPos = self.ClientToScreen((0,0)) + self.pnl.CaptureMouse() + + def OnMouseMotion(self, evt): + if evt.Dragging() and evt.LeftIsDown(): + dPos = evt.GetEventObject().ClientToScreen(evt.GetPosition()) + nPos = (self.wPos.x + (dPos.x - self.ldPos.x), + self.wPos.y + (dPos.y - self.ldPos.y)) + self.Move(nPos) + + def OnMouseLeftUp(self, evt): + if self.pnl.HasCapture(): + self.pnl.ReleaseMouse() + + def OnRightUp(self, evt): + self.Show(False) + self.Destroy() + + + +class TestTransientPopup(wx.PopupTransientWindow): + """Adds a bit of text and mouse movement to the wx.PopupWindow""" + def __init__(self, parent, style, log): + wx.PopupTransientWindow.__init__(self, parent, style) + self.log = log + panel = wx.Panel(self) + panel.SetBackgroundColour("#FFB6C1") + + st = wx.StaticText(panel, -1, + "wx.PopupTransientWindow is a\n" + "wx.PopupWindow which disappears\n" + "automatically when the user\n" + "clicks the mouse outside it or if it\n" + "(or its first child) loses focus in \n" + "any other way.") + btn = wx.Button(panel, -1, "Press Me") + spin = wx.SpinCtrl(panel, -1, "Hello", size=(100,-1)) + btn.Bind(wx.EVT_BUTTON, self.OnButton) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(st, 0, wx.ALL, 5) + sizer.Add(btn, 0, wx.ALL, 5) + sizer.Add(spin, 0, wx.ALL, 5) + panel.SetSizer(sizer) + + sizer.Fit(panel) + sizer.Fit(self) + self.Layout() + + + def ProcessLeftDown(self, evt): + self.log.write("ProcessLeftDown: %s\n" % evt.GetPosition()) + return wx.PopupTransientWindow.ProcessLeftDown(self, evt) + + def OnDismiss(self): + self.log.write("OnDismiss\n") + + def OnButton(self, evt): + btn = evt.GetEventObject() + if btn.GetLabel() == "Press Me": + btn.SetLabel("Pressed") + else: + btn.SetLabel("Press Me") + + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + b = wx.Button(self, -1, "Show wx.PopupWindow", (25, 50)) + self.Bind(wx.EVT_BUTTON, self.OnShowPopup, b) + + b = wx.Button(self, -1, "Show wx.PopupTransientWindow", (25, 95)) + self.Bind(wx.EVT_BUTTON, self.OnShowPopupTransient, b) + + # This isn't working so well, not sure why. Commented out for + # now. + +# b = wx.Button(self, -1, "Show wx.PopupWindow with listbox", (25, 140)) +# self.Bind(wx.EVT_BUTTON, self.OnShowPopupListbox, b) + + + def OnShowPopup(self, evt): + win = TestPopup(self.GetTopLevelParent(), wx.SIMPLE_BORDER) + #win = TestPopupWithListbox(self, wx.SIMPLE_BORDER, self.log) + + # Show the popup right below or above the button + # depending on available screen space... + btn = evt.GetEventObject() + pos = btn.ClientToScreen( (0,0) ) + sz = btn.GetSize() + win.Position(pos, (0, sz[1])) + + win.Show(True) + + + def OnShowPopupTransient(self, evt): + win = TestTransientPopup(self, + wx.SIMPLE_BORDER, + self.log) + + # Show the popup right below or above the button + # depending on available screen space... + btn = evt.GetEventObject() + pos = btn.ClientToScreen( (0,0) ) + sz = btn.GetSize() + win.Position(pos, (0, sz[1])) + + win.Popup() + + + def OnShowPopupListbox(self, evt): + win = TestPopupWithListbox(self, wx.NO_BORDER, self.log) + + # Show the popup right below or above the button + # depending on available screen space... + btn = evt.GetEventObject() + pos = btn.ClientToScreen( (0,0) ) + sz = btn.GetSize() + win.Position(pos, (0, sz[1])) + + win.Show(True) + + + +# This class is currently not implemented in the demo. It does not +# behave the way it should, so for the time being it's only here +# for show. If you figure out how to make it work, please send +# a corrected file to Robin! +class TestPopupWithListbox(wx.PopupWindow): + def __init__(self, parent, style, log): + wx.PopupWindow.__init__(self, parent, style) + self.log = log + import keyword + self.lb = wx.ListBox(self, -1, choices = keyword.kwlist) + #sz = self.lb.GetBestSize() + self.SetSize((150, 75)) #sz) + self.lb.SetSize(self.GetClientSize()) + self.lb.SetFocus() + self.Bind(wx.EVT_LISTBOX, self.OnListBox) + self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnListBoxDClick) + + def OnListBox(self, evt): + obj = evt.GetEventObject() + self.log.write("OnListBox: %s\n" % obj) + self.log.write('Selected: %s\n' % obj.GetString(evt.GetInt())) + evt.Skip() + + def OnListBoxDClick(self, evt): + self.Hide() + self.Destroy() + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/PrintDialog.py b/demo/PrintDialog.py new file mode 100644 index 00000000..e86dddf2 --- /dev/null +++ b/demo/PrintDialog.py @@ -0,0 +1,60 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a PrintDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + data = wx.PrintDialogData() + + data.EnableSelection(True) + data.EnablePrintToFile(True) + data.EnablePageNumbers(True) + data.SetMinPage(1) + data.SetMaxPage(5) + data.SetAllPages(True) + + dlg = wx.PrintDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetPrintDialogData() + self.log.WriteText('GetAllPages: %d\n' % data.GetAllPages()) + + dlg.Destroy() + + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ +This class represents the print and print setup common dialogs. You may obtain +a wx.PrinterDC device context from a successfully dismissed print dialog. + +User information is stored in a wx.PrintDialogData object that is passed to the +dialog at creation time, and it is filled in by the user. As with other dialogs, +do not use this data once the dialog is dismissed, and do not destroy the dialog +until you have everything you need from it. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/PrintFramework.py b/demo/PrintFramework.py new file mode 100644 index 00000000..4cc1c940 --- /dev/null +++ b/demo/PrintFramework.py @@ -0,0 +1,232 @@ + +import wx +import ScrolledWindow + +#---------------------------------------------------------------------- + + +class MyPrintout(wx.Printout): + def __init__(self, canvas, log): + wx.Printout.__init__(self) + self.canvas = canvas + self.log = log + + def OnBeginDocument(self, start, end): + self.log.WriteText("MyPrintout.OnBeginDocument\n") + return super(MyPrintout, self).OnBeginDocument(start, end) + + def OnEndDocument(self): + self.log.WriteText("MyPrintout.OnEndDocument\n") + super(MyPrintout, self).OnEndDocument() + + def OnBeginPrinting(self): + self.log.WriteText("MyPrintout.OnBeginPrinting\n") + super(MyPrintout, self).OnBeginPrinting() + + def OnEndPrinting(self): + self.log.WriteText("MyPrintout.OnEndPrinting\n") + super(MyPrintout, self).OnEndPrinting() + + def OnPreparePrinting(self): + self.log.WriteText("MyPrintout.OnPreparePrinting\n") + super(MyPrintout, self).OnPreparePrinting() + + def HasPage(self, page): + self.log.WriteText("MyPrintout.HasPage: %d\n" % page) + if page <= 2: + return True + else: + return False + + def GetPageInfo(self): + self.log.WriteText("MyPrintout.GetPageInfo\n") + return (1, 2, 1, 2) + + def OnPrintPage(self, page): + self.log.WriteText("MyPrintout.OnPrintPage: %d\n" % page) + dc = self.GetDC() + + #------------------------------------------- + # One possible method of setting scaling factors... + + maxX = self.canvas.getWidth() + maxY = self.canvas.getHeight() + + # Let's have at least 50 device units margin + marginX = 50 + marginY = 50 + + # Add the margin to the graphic size + maxX = maxX + (2 * marginX) + maxY = maxY + (2 * marginY) + + # Get the size of the DC in pixels + (w, h) = dc.GetSizeTuple() + + # Calculate a suitable scaling factor + scaleX = float(w) / maxX + scaleY = float(h) / maxY + + # Use x or y scaling factor, whichever fits on the DC + actualScale = min(scaleX, scaleY) + + # Calculate the position on the DC for centering the graphic + posX = (w - (self.canvas.getWidth() * actualScale)) / 2.0 + posY = (h - (self.canvas.getHeight() * actualScale)) / 2.0 + + # Set the scale and origin + dc.SetUserScale(actualScale, actualScale) + dc.SetDeviceOrigin(int(posX), int(posY)) + + #------------------------------------------- + + self.canvas.DoDrawing(dc, True) + dc.DrawText("Page: %d" % page, marginX/2, maxY-marginY) + + return True + + +#---------------------------------------------------------------------- + + +class TestPrintPanel(wx.Panel): + def __init__(self, parent, frame, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + self.frame = frame + + self.printData = wx.PrintData() + self.printData.SetPaperId(wx.PAPER_LETTER) + self.printData.SetPrintMode(wx.PRINT_MODE_PRINTER) + + self.box = wx.BoxSizer(wx.VERTICAL) + self.canvas = ScrolledWindow.MyCanvas(self) + self.box.Add(self.canvas, 1, wx.GROW) + + subbox = wx.BoxSizer(wx.HORIZONTAL) + btn = wx.Button(self, -1, "Page Setup") + self.Bind(wx.EVT_BUTTON, self.OnPageSetup, btn) + subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) + + btn = wx.Button(self, -1, "Print Preview") + self.Bind(wx.EVT_BUTTON, self.OnPrintPreview, btn) + subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) + + btn = wx.Button(self, -1, "Print") + self.Bind(wx.EVT_BUTTON, self.OnDoPrint, btn) + subbox.Add(btn, 1, wx.GROW | wx.ALL, 2) + + self.box.Add(subbox, 0, wx.GROW) + + self.SetAutoLayout(True) + self.SetSizer(self.box) + + + + def OnPageSetup(self, evt): + psdd = wx.PageSetupDialogData(self.printData) + psdd.EnablePrinter(True) + psdd.CalculatePaperSizeFromId() + dlg = wx.PageSetupDialog(self, psdd) + dlg.ShowModal() + + # this makes a copy of the wx.PrintData instead of just saving + # a reference to the one inside the PrintDialogData that will + # be destroyed when the dialog is destroyed + self.printData = wx.PrintData( dlg.GetPageSetupData().GetPrintData() ) + + dlg.Destroy() + + def OnPrintPreview(self, event): + data = wx.PrintDialogData(self.printData) + printout = MyPrintout(self.canvas, self.log) + printout2 = MyPrintout(self.canvas, self.log) + self.preview = wx.PrintPreview(printout, printout2, data) + + if not self.preview.Ok(): + self.log.WriteText("Houston, we have a problem...\n") + return + + pfrm = wx.PreviewFrame(self.preview, self.frame, "This is a print preview") + + pfrm.Initialize() + pfrm.SetPosition(self.frame.GetPosition()) + pfrm.SetSize(self.frame.GetSize()) + pfrm.Show(True) + + + + def OnDoPrint(self, event): + pdd = wx.PrintDialogData(self.printData) + pdd.SetToPage(2) + printer = wx.Printer(pdd) + printout = MyPrintout(self.canvas, self.log) + + if not printer.Print(self.frame, printout, True): + wx.MessageBox("There was a problem printing.\nPerhaps your current printer is not set correctly?", "Printing", wx.OK) + else: + self.printData = wx.PrintData( printer.GetPrintDialogData().GetPrintData() ) + printout.Destroy() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPrintPanel(nb, frame, log) + return win + + +#---------------------------------------------------------------------- + + + + + +overview = """\ + + +

PrintFramework

+ +This is an overview of the classes and methods used to print documents. +It also demonstrates how to do print previews and invoke the printer +setup dialog. + +

Classes demonstrated here:

+

    +
  • wx.Printout() - This class encapsulates the functionality of printing out + an application document. A new class must be derived and members overridden + to respond to calls such as OnPrintPage and HasPage. Instances of this class + are passed to wx.Printer.Print() or a wx.PrintPreview object to initiate + printing or previewing.

    + +

  • wx.PrintData() - This class holds a variety of information related to + printers and printer device contexts. This class is used to create a + wx.PrinterDC and a wx.PostScriptDC. It is also used as a data member of + wx.PrintDialogData and wx.PageSetupDialogData, as part of the mechanism for + transferring data between the print dialogs and the application.

    + +

  • wx.PrintDialog() - This class represents the print and print setup + common dialogs. You may obtain a wx.PrinterDC device context from a + successfully dismissed print dialog.

    + +

  • wx.PrintPreview() - Objects of this class manage the print preview + process. The object is passed a wx.Printout object, and the wx.PrintPreview + object itself is passed to a wx.PreviewFrame object. Previewing is started by + initializing and showing the preview frame. Unlike wxPrinter.Print, flow of + control returns to the application immediately after the frame is shown.

    +

+ +

Other classes are also demonstrated, but this is the gist of the printer interface +framework in wxPython. + + + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Process.py b/demo/Process.py new file mode 100644 index 00000000..ad6827cc --- /dev/null +++ b/demo/Process.py @@ -0,0 +1,162 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, ID, log): + wx.Panel.__init__(self, parent, ID) + self.log = log + + self.process = None + self.Bind(wx.EVT_IDLE, self.OnIdle) + + # We can either derive from wx.Process and override OnTerminate + # or we can let wx.Process send this window an event that is + # caught in the normal way... + self.Bind(wx.EVT_END_PROCESS, self.OnProcessEnded) + + + # Make the controls + prompt = wx.StaticText(self, -1, 'Command line:') + self.cmd = wx.TextCtrl(self, -1, 'python -u data/echo.py') + self.exBtn = wx.Button(self, -1, 'Execute') + + self.out = wx.TextCtrl(self, -1, '', + style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2) + + self.inp = wx.TextCtrl(self, -1, '', style=wx.TE_PROCESS_ENTER) + self.sndBtn = wx.Button(self, -1, 'Send') + self.termBtn = wx.Button(self, -1, 'Close Stream') + self.inp.Enable(False) + self.sndBtn.Enable(False) + self.termBtn.Enable(False) + + # Hook up the events + self.Bind(wx.EVT_BUTTON, self.OnExecuteBtn, self.exBtn) + self.Bind(wx.EVT_BUTTON, self.OnSendText, self.sndBtn) + self.Bind(wx.EVT_BUTTON, self.OnCloseStream, self.termBtn) + self.Bind(wx.EVT_TEXT_ENTER, self.OnSendText, self.inp) + + + # Do the layout + box1 = wx.BoxSizer(wx.HORIZONTAL) + box1.Add(prompt, 0, wx.ALIGN_CENTER) + box1.Add(self.cmd, 1, wx.ALIGN_CENTER|wx.LEFT|wx.RIGHT, 5) + box1.Add(self.exBtn, 0) + + box2 = wx.BoxSizer(wx.HORIZONTAL) + box2.Add(self.inp, 1, wx.ALIGN_CENTER) + box2.Add(self.sndBtn, 0, wx.LEFT, 5) + box2.Add(self.termBtn, 0, wx.LEFT, 5) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(box1, 0, wx.EXPAND|wx.ALL, 10) + sizer.Add(self.out, 1, wx.EXPAND|wx.ALL, 10) + sizer.Add(box2, 0, wx.EXPAND|wx.ALL, 10) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + + def __del__(self): + if self.process is not None: + self.process.Detach() + self.process.CloseOutput() + self.process = None + + + def OnExecuteBtn(self, evt): + cmd = self.cmd.GetValue() + + self.process = wx.Process(self) + self.process.Redirect(); + pid = wx.Execute(cmd, wx.EXEC_ASYNC, self.process) + self.log.write('OnExecuteBtn: "%s" pid: %s\n' % (cmd, pid)) + + self.inp.Enable(True) + self.sndBtn.Enable(True) + self.termBtn.Enable(True) + self.cmd.Enable(False) + self.exBtn.Enable(False) + self.inp.SetFocus() + + + def OnSendText(self, evt): + text = self.inp.GetValue() + self.inp.SetValue('') + self.log.write('OnSendText: "%s"\n' % text) + self.process.GetOutputStream().write(text + '\n') + self.inp.SetFocus() + + + def OnCloseStream(self, evt): + self.log.write('OnCloseStream\n') + #print "b4 CloseOutput" + self.process.CloseOutput() + #print "after CloseOutput" + + def OnIdle(self, evt): + if self.process is not None: + stream = self.process.GetInputStream() + + if stream.CanRead(): + text = stream.read() + self.out.AppendText(text) + + + def OnProcessEnded(self, evt): + self.log.write('OnProcessEnded, pid:%s, exitCode: %s\n' % + (evt.GetPid(), evt.GetExitCode())) + + stream = self.process.GetInputStream() + + if stream.CanRead(): + text = stream.read() + self.out.AppendText(text) + + self.process.Destroy() + self.process = None + self.inp.Enable(False) + self.sndBtn.Enable(False) + self.termBtn.Enable(False) + self.cmd.Enable(True) + self.exBtn.Enable(True) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, -1, log) + return win + + +#---------------------------------------------------------------------- + + +overview = """\ + +

wx.Process

+ +wx.Process lets you get notified when an asyncronous child process +started by wxExecute terminates, and also to get input/output streams +for the child process's stdout, stderr and stdin. + +

+This demo launches a simple python script that echos back on stdout +lines that it reads from stdin. You can send text to the echo +process' stdin by typing in the lower textctrl and clicking Send. + +

+Clicking the Close Stream button will close the demo's end of the +stdin pipe to the child process. In our case that will cause the +child process to exit its main loop. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/ProgressDialog.py b/demo/ProgressDialog.py new file mode 100644 index 00000000..bb8879aa --- /dev/null +++ b/demo/ProgressDialog.py @@ -0,0 +1,86 @@ +# 11/21/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Updated for wx namespace +# +# 11/30/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o wx.ProgressDialog appears to be broken. No abort button +# and it's not possible to dismiss it otherwise. +# + +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a ProgressDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + max = 80 + + dlg = wx.ProgressDialog("Progress dialog example", + "An informative message", + maximum = max, + parent=self, + style = 0 + | wx.PD_APP_MODAL + | wx.PD_CAN_ABORT + #| wx.PD_CAN_SKIP + #| wx.PD_ELAPSED_TIME + | wx.PD_ESTIMATED_TIME + | wx.PD_REMAINING_TIME + #| wx.PD_AUTO_HIDE + ) + + keepGoing = True + count = 0 + + while keepGoing and count < max: + count += 1 + wx.MilliSleep(250) + wx.Yield() + + if count >= max / 2: + (keepGoing, skip) = dlg.Update(count, "Half-time!") + else: + (keepGoing, skip) = dlg.Update(count) + + + dlg.Destroy() + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ + +This class represents a dialog that shows a short message and a progress bar. +Optionally, it can display an ABORT button +

+This dialog indicates the progress of some event that takes a while to accomplish, +usually, such as file copy progress, download progress, and so on. The display +is completely under control of the program; you must update the dialog from +within the program creating it. +

+When the dialog closes, you must check to see if the user aborted the process or +not, and act accordingly -- that is, if the PD_CAN_ABORT style flag is set. +If not then you may progress blissfully onward. + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/PropertyGrid.py b/demo/PropertyGrid.py new file mode 100644 index 00000000..3d5928d7 --- /dev/null +++ b/demo/PropertyGrid.py @@ -0,0 +1,1042 @@ + +import sys, time, math, os, os.path + +import wx +_ = wx.GetTranslation +import wx.propgrid as wxpg + + +############################################################################ +# +# TEST RELATED CODE AND VARIABLES +# +############################################################################ + +default_object_content2 = """\ +object.title = "Object Title" +object.index = 1 +object.PI = %f +object.wxpython_rules = True +"""%(math.pi) + +default_object_content1 = """\ + +# +# Note that the results of autofill will appear on the second page. + +# +# Set number of iterations appropriately to test performance +iterations = 100 + +# +# Test result for 100,000 iterations on Athlon XP 2000+: +# +# Time spent per property: 0.054ms +# Memory allocated per property: ~350 bytes (includes Python object) +# + +for i in range(0,iterations): + setattr(object,'title%i'%i,"Object Title") + setattr(object,'index%i'%i,1) + setattr(object,'PI%i'%i,3.14) + setattr(object,'wxpython_rules%i'%i,True) +""" + + +############################################################################ +# +# CUSTOM PROPERTY SAMPLES +# +############################################################################ + + +class ValueObject: + def __init__(self): + pass + + +class IntProperty2(wxpg.PyProperty): + """\ + This is a simple re-implementation of wxIntProperty. + """ + def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=0): + wxpg.PyProperty.__init__(self, label, name) + self.SetValue(value) + + def GetClassName(self): + """\ + This is not 100% necessary and in future is probably going to be + automated to return class name. + """ + return "IntProperty2" + + def GetEditor(self): + return "TextCtrl" + + def ValueToString(self, value, flags): + return str(value) + + def StringToValue(self, s, flags): + """ If failed, return False or (False, None). If success, return tuple + (True, newValue). + """ + try: + v = int(s) + if self.GetValue() != v: + return (True, v) + except (ValueError, TypeError): + if flags & wxpg.PG_REPORT_ERROR: + wx.MessageBox("Cannot convert '%s' into a number."%s, "Error") + return False + + def IntToValue(self, v, flags): + """ If failed, return False or (False, None). If success, return tuple + (True, newValue). + """ + if (self.GetValue() != v): + return (True, v) + return False + + def ValidateValue(self, value, validationInfo): + """ Let's limit the value to range -10000 and 10000. + """ + # Just test this function to make sure validationInfo and + # wxPGVFBFlags work properly. + oldvfb__ = validationInfo.GetFailureBehavior() + + # Mark the cell if validaton failred + validationInfo.SetFailureBehavior(wxpg.PG_VFB_MARK_CELL) + + if value < -10000 or value > 10000: + return False + + return (True, value) + + +class SizeProperty(wxpg.PyProperty): + """ Demonstrates a property with few children. + """ + def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=wx.Size(0, 0)): + wxpg.PyProperty.__init__(self, label, name) + + value = self._ConvertValue(value) + + self.AddPrivateChild( wxpg.IntProperty("X", value=value.x) ) + self.AddPrivateChild( wxpg.IntProperty("Y", value=value.y) ) + + self.m_value = value + + def GetClassName(self): + return self.__class__.__name__ + + def GetEditor(self): + return "TextCtrl" + + def RefreshChildren(self): + size = self.m_value + self.Item(0).SetValue( size.x ) + self.Item(1).SetValue( size.y ) + + def _ConvertValue(self, value): + """ Utility convert arbitrary value to a real wx.Size. + """ + from operator import isSequenceType + if isinstance(value, wx.Point): + value = wx.Size(value.x, value.y) + elif isSequenceType(value): + value = wx.Size(*value) + return value + + def ChildChanged(self, thisValue, childIndex, childValue): + # FIXME: This does not work yet. ChildChanged needs be fixed "for" + # wxPython in wxWidgets SVN trunk, and that has to wait for + # 2.9.1, as wxPython 2.9.0 uses WX_2_9_0_BRANCH. + size = self._ConvertValue(self.m_value) + if childIndex == 0: + size.x = childValue + elif childIndex == 1: + size.y = childValue + else: + raise AssertionError + + return size + + +class DirsProperty(wxpg.PyArrayStringProperty): + """ Sample of a custom custom ArrayStringProperty. + + Because currently some of the C++ helpers from wxArrayStringProperty + and wxProperytGrid are not available, our implementation has to quite + a bit 'manually'. Which is not too bad since Python has excellent + string and list manipulation facilities. + """ + def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=[]): + wxpg.PyArrayStringProperty.__init__(self, label, name, value) + + # Set default delimiter + self.SetAttribute("Delimiter", ',') + + def GetEditor(self): + return "TextCtrlAndButton" + + def ValueToString(self, value, flags): + return self.m_display + + def OnSetValue(self): + self.GenerateValueAsString() + + def DoSetAttribute(self, name, value): + # Proper way to call same method from super class + retval = self.CallSuperMethod("DoSetAttribute", name, value) + + # + # Must re-generate cached string when delimiter changes + if name == "Delimiter": + self.GenerateValueAsString(delim=value) + + return retval + + def GenerateValueAsString(self, delim=None): + """ This function creates a cached version of displayed text + (self.m_display). + """ + if not delim: + delim = self.GetAttribute("Delimiter") + if not delim: + delim = ',' + + ls = self.GetValue() + if delim == '"' or delim == "'": + text = ' '.join(['%s%s%s'%(delim,a,delim) for a in ls]) + else: + text = ', '.join(ls) + self.m_display = text + + def StringToValue(self, text, argFlags): + """ If failed, return False or (False, None). If success, return tuple + (True, newValue). + """ + delim = self.GetAttribute("Delimiter") + if delim == '"' or delim == "'": + # Proper way to call same method from super class + return self.CallSuperMethod("StringToValue", text, 0) + v = [a.strip() for a in text.split(delim)] + return (True, v) + + def OnEvent(self, propgrid, primaryEditor, event): + if event.GetEventType() == wx.wxEVT_COMMAND_BUTTON_CLICKED: + dlg = wx.DirDialog(propgrid, + _("Select a directory to be added to " + "the list:")) + + if dlg.ShowModal() == wx.ID_OK: + new_path = dlg.GetPath() + old_value = self.m_value + if old_value: + new_value = list(old_value) + new_value.append(new_path) + else: + new_value = [new_path] + self.SetValueInEvent(new_value) + retval = True + else: + retval = False + + dlg.Destroy() + return retval + + return False + + +class PyObjectPropertyValue: + """\ + Value type of our sample PyObjectProperty. We keep a simple dash-delimited + list of string given as argument to constructor. + """ + def __init__(self, s=None): + try: + self.ls = [a.strip() for a in s.split('-')] + except: + self.ls = [] + + def __repr__(self): + return ' - '.join(self.ls) + + +class PyObjectProperty(wxpg.PyProperty): + """\ + Another simple example. This time our value is a PyObject. + + NOTE: We can't return an arbitrary python object in DoGetValue. It cannot + be a simple type such as int, bool, double, or string, nor an array + or wxObject based. Dictionary, None, or any user-specified Python + class is allowed. + """ + def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=None): + wxpg.PyProperty.__init__(self, label, name) + self.SetValue(value) + + def GetClassName(self): + return self.__class__.__name__ + + def GetEditor(self): + return "TextCtrl" + + def ValueToString(self, value, flags): + return repr(value) + + def StringToValue(self, s, flags): + """ If failed, return False or (False, None). If success, return tuple + (True, newValue). + """ + v = PyObjectPropertyValue(s) + return (True, v) + + +class SampleMultiButtonEditor(wxpg.PyTextCtrlEditor): + def __init__(self): + wxpg.PyTextCtrlEditor.__init__(self) + + def CreateControls(self, propGrid, property, pos, sz): + # Create and populate buttons-subwindow + buttons = wxpg.PGMultiButton(propGrid, sz) + + # Add two regular buttons + buttons.AddButton("...") + buttons.AddButton("A") + # Add a bitmap button + buttons.AddBitmapButton(wx.ArtProvider.GetBitmap(wx.ART_FOLDER)) + + # Create the 'primary' editor control (textctrl in this case) + wnd = self.CallSuperMethod("CreateControls", + propGrid, + property, + pos, + buttons.GetPrimarySize()) + + # Finally, move buttons-subwindow to correct position and make sure + # returned wxPGWindowList contains our custom button list. + buttons.Finalize(propGrid, pos); + + # We must maintain a reference to any editor objects we created + # ourselves. Otherwise they might be freed prematurely. Also, + # we need it in OnEvent() below, because in Python we cannot "cast" + # result of wxPropertyGrid.GetEditorControlSecondary() into + # PGMultiButton instance. + self.buttons = buttons + + return (wnd, buttons) + + def OnEvent(self, propGrid, prop, ctrl, event): + if event.GetEventType() == wx.wxEVT_COMMAND_BUTTON_CLICKED: + buttons = self.buttons + evtId = event.GetId() + + if evtId == buttons.GetButtonId(0): + # Do something when the first button is pressed + wx.LogDebug("First button pressed"); + return False # Return false since value did not change + if evtId == buttons.GetButtonId(1): + # Do something when the second button is pressed + wx.MessageBox("Second button pressed"); + return False # Return false since value did not change + if evtId == buttons.GetButtonId(2): + # Do something when the third button is pressed + wx.MessageBox("Third button pressed"); + return False # Return false since value did not change + + return self.CallSuperMethod("OnEvent", propGrid, prop, ctrl, event) + + +class SingleChoiceDialogAdapter(wxpg.PyEditorDialogAdapter): + """ This demonstrates use of wxpg.PyEditorDialogAdapter. + """ + def __init__(self, choices): + wxpg.PyEditorDialogAdapter.__init__(self) + self.choices = choices + + def DoShowDialog(self, propGrid, property): + s = wx.GetSingleChoice("Message", "Caption", self.choices) + + if s: + self.SetValue(s) + return True + + return False; + + +class SingleChoiceProperty(wxpg.PyStringProperty): + def __init__(self, label, name=wxpg.LABEL_AS_NAME, value=''): + wxpg.PyStringProperty.__init__(self, label, name, value) + + # Prepare choices + dialog_choices = [] + dialog_choices.append("Cat"); + dialog_choices.append("Dog"); + dialog_choices.append("Gibbon"); + dialog_choices.append("Otter"); + + self.dialog_choices = dialog_choices + + def GetEditor(self): + # Set editor to have button + return "TextCtrlAndButton" + + def GetEditorDialog(self): + # Set what happens on button click + return SingleChoiceDialogAdapter(self.dialog_choices) + + +class TrivialPropertyEditor(wxpg.PyEditor): + """\ + This is a simple re-creation of TextCtrlWithButton. Note that it does + not take advantage of wx.TextCtrl and wx.Button creation helper functions + in wx.PropertyGrid. + """ + def __init__(self): + wxpg.PyEditor.__init__(self) + + def CreateControls(self, propgrid, property, pos, sz): + """ Create the actual wxPython controls here for editing the + property value. + + You must use propgrid.GetPanel() as parent for created controls. + + Return value is either single editor control or tuple of two + editor controls, of which first is the primary one and second + is usually a button. + """ + try: + x, y = pos + w, h = sz + h = 64 + 6 + + # Make room for button + bw = propgrid.GetRowHeight() + w -= bw + + s = property.GetDisplayedString(); + + tc = wx.TextCtrl(propgrid.GetPanel(), wxpg.PG_SUBID1, s, + (x,y), (w,h), + wx.TE_PROCESS_ENTER) + btn = wx.Button(propgrid.GetPanel(), wxpg.PG_SUBID2, '...', + (x+w, y), + (bw, h), wx.WANTS_CHARS) + return (tc, btn) + except: + import traceback + print(traceback.print_exc()) + + def UpdateControl(self, property, ctrl): + ctrl.SetValue(property.GetDisplayedString()) + + def DrawValue(self, dc, rect, property, text): + if not property.IsValueUnspecified(): + dc.DrawText(property.GetDisplayedString(), rect.x+5, rect.y) + + def OnEvent(self, propgrid, property, ctrl, event): + """ Return True if modified editor value should be committed to + the property. To just mark the property value modified, call + propgrid.EditorsValueWasModified(). + """ + if not ctrl: + return False + + evtType = event.GetEventType() + + if evtType == wx.wxEVT_COMMAND_TEXT_ENTER: + if propgrid.IsEditorsValueModified(): + return True + elif evtType == wx.wxEVT_COMMAND_TEXT_UPDATED: + # + # Pass this event outside wxPropertyGrid so that, + # if necessary, program can tell when user is editing + # a textctrl. + event.Skip() + event.SetId(propgrid.GetId()) + + propgrid.EditorsValueWasModified() + return False + + return False + + def GetValueFromControl(self, property, ctrl): + """ Return tuple (wasSuccess, newValue), where wasSuccess is True if + different value was acquired succesfully. + """ + tc = ctrl + textVal = tc.GetValue() + + if property.UsesAutoUnspecified() and not textVal: + return (True, None) + + res, value = property.StringToValue(textVal, + wxpg.PG_EDITABLE_VALUE) + + # Changing unspecified always causes event (returning + # True here should be enough to trigger it). + if not res and value is None: + res = True + + return (res, value) + + def SetValueToUnspecified(self, property, ctrl): + ctrl.Remove(0,len(ctrl.GetValue())) + + def SetControlStringValue(self, property, ctrl, text): + ctrl.SetValue(text) + + def OnFocus(self, property, ctrl): + ctrl.SetSelection(-1,-1) + ctrl.SetFocus() + + +class LargeImagePickerCtrl(wx.Panel): + """\ + Control created and used by LargeImageEditor. + """ + def __init__(self): + pre = wx.PrePanel() + self.PostCreate(pre) + + def Create(self, parent, id_, pos, size, style = 0): + wx.Panel.Create(self, parent, id_, pos, size, + style | wx.BORDER_SIMPLE) + img_spc = size[1] + self.tc = wx.TextCtrl(self, -1, "", (img_spc,0), (2048,size[1]), + wx.BORDER_NONE) + self.SetBackgroundColour(wx.WHITE) + self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + self.property = None + self.bmp = None + self.Bind(wx.EVT_PAINT, self.OnPaint) + + def OnPaint(self, event): + dc = wx.BufferedPaintDC(self) + + whiteBrush = wx.Brush(wx.WHITE) + dc.SetBackground(whiteBrush) + dc.Clear() + + bmp = self.bmp + if bmp: + dc.DrawBitmap(bmp, 2, 2) + else: + dc.SetPen(wx.Pen(wx.BLACK)) + dc.SetBrush(whiteBrush) + dc.DrawRectangle(2, 2, 64, 64) + + def RefreshThumbnail(self): + """\ + We use here very simple image scaling code. + """ + if not self.property: + self.bmp = None + return + + path = self.property.DoGetValue() + + if not os.path.isfile(path): + self.bmp = None + return + + image = wx.Image(path) + image.Rescale(64, 64) + self.bmp = wx.BitmapFromImage(image) + + def SetProperty(self, property): + self.property = property + self.tc.SetValue(property.GetDisplayedString()) + self.RefreshThumbnail() + + def SetValue(self, s): + self.RefreshThumbnail() + self.tc.SetValue(s) + + def GetLastPosition(self): + return self.tc.GetLastPosition() + + +class LargeImageEditor(wxpg.PyEditor): + """\ + Double-height text-editor with image in front. + """ + def __init__(self): + wxpg.PyEditor.__init__(self) + + def CreateControls(self, propgrid, property, pos, sz): + try: + x, y = pos + w, h = sz + h = 64 + 6 + + # Make room for button + bw = propgrid.GetRowHeight() + w -= bw + + lipc = LargeImagePickerCtrl() + if sys.platform.startswith('win'): + lipc.Hide() + lipc.Create(propgrid.GetPanel(), wxpg.PG_SUBID1, (x,y), (w,h)) + lipc.SetProperty(property) + # Hmmm.. how to have two-stage creation without subclassing? + #btn = wx.PreButton() + #pre = wx.PreWindow() + #self.PostCreate(pre) + #if sys.platform == 'win32': + # btn.Hide() + #btn.Create(propgrid, wxpg.PG_SUBID2, '...', (x2-bw,pos[1]), + # (bw,h), wx.WANTS_CHARS) + btn = wx.Button(propgrid.GetPanel(), wxpg.PG_SUBID2, '...', + (x+w, y), + (bw, h), wx.WANTS_CHARS) + return (lipc, btn) + except: + import traceback + print(traceback.print_exc()) + + def UpdateControl(self, property, ctrl): + ctrl.SetValue(property.GetDisplayedString()) + + def DrawValue(self, dc, rect, property, text): + if not property.IsValueUnspecified(): + dc.DrawText(property.GetDisplayedString(), rect.x+5, rect.y) + + def OnEvent(self, propgrid, property, ctrl, event): + """ Return True if modified editor value should be committed to + the property. To just mark the property value modified, call + propgrid.EditorsValueWasModified(). + """ + if not ctrl: + return False + + evtType = event.GetEventType() + + if evtType == wx.wxEVT_COMMAND_TEXT_ENTER: + if propgrid.IsEditorsValueModified(): + return True + elif evtType == wx.wxEVT_COMMAND_TEXT_UPDATED: + # + # Pass this event outside wxPropertyGrid so that, + # if necessary, program can tell when user is editing + # a textctrl. + event.Skip() + event.SetId(propgrid.GetId()) + + propgrid.EditorsValueWasModified() + return False + + return False + + def GetValueFromControl(self, property, ctrl): + """ Return tuple (wasSuccess, newValue), where wasSuccess is True if + different value was acquired succesfully. + """ + tc = ctrl.tc + textVal = tc.GetValue() + + if property.UsesAutoUnspecified() and not textVal: + return (None, True) + + res, value = property.StringToValue(textVal, + wxpg.PG_EDITABLE_VALUE) + + # Changing unspecified always causes event (returning + # True here should be enough to trigger it). + if not res and value is None: + res = True + + return (res, value) + + def SetValueToUnspecified(self, property, ctrl): + ctrl.tc.Remove(0,len(ctrl.tc.GetValue())) + + def SetControlStringValue(self, property, ctrl, txt): + ctrl.SetValue(txt) + + def OnFocus(self, property, ctrl): + ctrl.tc.SetSelection(-1,-1) + ctrl.tc.SetFocus() + + def CanContainCustomImage(self): + return True + + +############################################################################ +# +# MAIN PROPERTY GRID TEST PANEL +# +############################################################################ + +class TestPanel( wx.Panel ): + + def __init__( self, parent, log ): + wx.Panel.__init__(self, parent, wx.ID_ANY) + self.log = log + + self.panel = panel = wx.Panel(self, wx.ID_ANY) + topsizer = wx.BoxSizer(wx.VERTICAL) + + # Difference between using PropertyGridManager vs PropertyGrid is that + # the manager supports multiple pages and a description box. + self.pg = pg = wxpg.PropertyGridManager(panel, + style=wxpg.PG_SPLITTER_AUTO_CENTER | + wxpg.PG_AUTO_SORT | + wxpg.PG_TOOLBAR) + + # Show help as tooltips + pg.SetExtraStyle(wxpg.PG_EX_HELP_AS_TOOLTIPS) + + pg.Bind( wxpg.EVT_PG_CHANGED, self.OnPropGridChange ) + pg.Bind( wxpg.EVT_PG_PAGE_CHANGED, self.OnPropGridPageChange ) + pg.Bind( wxpg.EVT_PG_SELECTED, self.OnPropGridSelect ) + pg.Bind( wxpg.EVT_PG_RIGHT_CLICK, self.OnPropGridRightClick ) + + + # + # Let's use some simple custom editor + # + # NOTE: Editor must be registered *before* adding a property that + # uses it. + if not getattr(sys, '_PropGridEditorsRegistered', False): + pg.RegisterEditor(TrivialPropertyEditor) + pg.RegisterEditor(SampleMultiButtonEditor) + pg.RegisterEditor(LargeImageEditor) + # ensure we only do it once + sys._PropGridEditorsRegistered = True + + # + # Add properties + # + + pg.AddPage( "Page 1 - Testing All" ) + + pg.Append( wxpg.PropertyCategory("1 - Basic Properties") ) + pg.Append( wxpg.StringProperty("String",value="Some Text") ) + pg.Append( wxpg.IntProperty("Int",value=100) ) + pg.Append( wxpg.FloatProperty("Float",value=100.0) ) + pg.Append( wxpg.BoolProperty("Bool",value=True) ) + pg.Append( wxpg.BoolProperty("Bool_with_Checkbox",value=True) ) + pg.SetPropertyAttribute("Bool_with_Checkbox", "UseCheckbox", True) + + pg.Append( wxpg.PropertyCategory("2 - More Properties") ) + pg.Append( wxpg.LongStringProperty("LongString", + value="This is a\\nmulti-line string\\nwith\\ttabs\\nmixed\\tin.")) + pg.Append( wxpg.DirProperty("Dir",value="C:\\Windows") ) + pg.Append( wxpg.FileProperty("File",value="C:\\Windows\\system.ini") ) + pg.Append( wxpg.ArrayStringProperty("ArrayString",value=['A','B','C']) ) + + pg.Append( wxpg.EnumProperty("Enum","Enum", + ['wxPython Rules', + 'wxPython Rocks', + 'wxPython Is The Best'], + [10,11,12], + 0) ) + pg.Append( wxpg.EditEnumProperty("EditEnum","EditEnumProperty", + ['A','B','C'], + [0,1,2], + "Text Not in List") ) + + pg.Append( wxpg.PropertyCategory("3 - Advanced Properties") ) + pg.Append( wxpg.DateProperty("Date",value=wx.DateTime_Now()) ) + pg.Append( wxpg.FontProperty("Font",value=panel.GetFont()) ) + pg.Append( wxpg.ColourProperty("Colour", + value=panel.GetBackgroundColour()) ) + pg.Append( wxpg.SystemColourProperty("SystemColour") ) + pg.Append( wxpg.ImageFileProperty("ImageFile") ) + pg.Append( wxpg.MultiChoiceProperty("MultiChoice", + choices=['wxWidgets','QT','GTK+']) ) + + pg.Append( wxpg.PropertyCategory("4 - Additional Properties") ) + #pg.Append( wxpg.PointProperty("Point",value=panel.GetPosition()) ) + #pg.Append( SizeProperty("Size",value=panel.GetSize()) ) + #pg.Append( wxpg.FontDataProperty("FontData") ) + pg.Append( wxpg.IntProperty("IntWithSpin",value=256) ) + pg.SetPropertyEditor("IntWithSpin","SpinCtrl") + + pg.SetPropertyAttribute( "File", wxpg.PG_FILE_SHOW_FULL_PATH, 0 ) + pg.SetPropertyAttribute( "File", wxpg.PG_FILE_INITIAL_PATH, + "C:\\Program Files\\Internet Explorer" ) + pg.SetPropertyAttribute( "Date", wxpg.PG_DATE_PICKER_STYLE, + wx.DP_DROPDOWN|wx.DP_SHOWCENTURY ) + + pg.Append( wxpg.PropertyCategory("5 - Custom Properties and Editors") ) + pg.Append( IntProperty2("IntProperty2", value=1024) ) + + pg.Append( PyObjectProperty("PyObjectProperty") ) + + pg.Append( DirsProperty("Dirs1",value=['C:/Lib','C:/Bin']) ) + pg.Append( DirsProperty("Dirs2",value=['/lib','/bin']) ) + + # Test another type of delimiter + pg.SetPropertyAttribute("Dirs2", "Delimiter", '"') + + # SampleMultiButtonEditor + pg.Append( wxpg.LongStringProperty("MultipleButtons") ); + pg.SetPropertyEditor("MultipleButtons", "SampleMultiButtonEditor"); + pg.Append( SingleChoiceProperty("SingleChoiceProperty") ) + + # Custom editor samples + prop = pg.Append( wxpg.StringProperty("StringWithCustomEditor", + value="test value") ) + pg.SetPropertyEditor(prop, "TrivialPropertyEditor") + + pg.Append( wxpg.ImageFileProperty("ImageFileWithLargeEditor") ) + pg.SetPropertyEditor("ImageFileWithLargeEditor", "LargeImageEditor") + + # When page is added, it will become the target page for AutoFill + # calls (and for other property insertion methods as well) + pg.AddPage( "Page 2 - Results of AutoFill will appear here" ) + + topsizer.Add(pg, 1, wx.EXPAND) + + rowsizer = wx.BoxSizer(wx.HORIZONTAL) + but = wx.Button(panel,-1,"SetPropertyValues") + but.Bind( wx.EVT_BUTTON, self.OnSetPropertyValues ) + rowsizer.Add(but,1) + but = wx.Button(panel,-1,"GetPropertyValues") + but.Bind( wx.EVT_BUTTON, self.OnGetPropertyValues ) + rowsizer.Add(but,1) + topsizer.Add(rowsizer,0,wx.EXPAND) + rowsizer = wx.BoxSizer(wx.HORIZONTAL) + but = wx.Button(panel,-1,"GetPropertyValues(as_strings=True)") + but.Bind( wx.EVT_BUTTON, self.OnGetPropertyValues2 ) + rowsizer.Add(but,1) + but = wx.Button(panel,-1,"AutoFill") + but.Bind( wx.EVT_BUTTON, self.OnAutoFill ) + rowsizer.Add(but,1) + topsizer.Add(rowsizer,0,wx.EXPAND) + rowsizer = wx.BoxSizer(wx.HORIZONTAL) + but = wx.Button(panel,-1,"Delete") + but.Bind( wx.EVT_BUTTON, self.OnDeleteProperty ) + rowsizer.Add(but,1) + but = wx.Button(panel,-1,"Run Tests") + but.Bind( wx.EVT_BUTTON, self.RunTests ) + rowsizer.Add(but,1) + topsizer.Add(rowsizer,0,wx.EXPAND) + + panel.SetSizer(topsizer) + topsizer.SetSizeHints(panel) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(panel, 1, wx.EXPAND) + self.SetSizer(sizer) + self.SetAutoLayout(True) + + def OnPropGridChange(self, event): + p = event.GetProperty() + if p: + self.log.write('%s changed to "%s"\n' % (p.GetName(),p.GetValueAsString())) + + def OnPropGridSelect(self, event): + p = event.GetProperty() + if p: + self.log.write('%s selected\n' % (event.GetProperty().GetName())) + else: + self.log.write('Nothing selected\n') + + def OnDeleteProperty(self, event): + p = self.pg.GetSelectedProperty() + if p: + self.pg.DeleteProperty(p) + else: + wx.MessageBox("First select a property to delete") + + def OnReserved(self, event): + pass + + def OnSetPropertyValues(self,event): + try: + d = self.pg.GetPropertyValues(inc_attributes=True) + + ss = [] + for k,v in d.iteritems(): + v = repr(v) + if not v or v[0] != '<': + if k.startswith('@'): + ss.append('setattr(obj, "%s", %s)'%(k,v)) + else: + ss.append('obj.%s = %s'%(k,v)) + + dlg = MemoDialog(self, + "Enter Content for Object Used in SetPropertyValues", + '\n'.join(ss)) # default_object_content1 + + if dlg.ShowModal() == wx.ID_OK: + import datetime + sandbox = {'obj':ValueObject(), + 'wx':wx, + 'datetime':datetime} + exec dlg.tc.GetValue() in sandbox + t_start = time.time() + #print(sandbox['obj'].__dict__) + self.pg.SetPropertyValues(sandbox['obj']) + t_end = time.time() + self.log.write('SetPropertyValues finished in %.0fms\n' % + ((t_end-t_start)*1000.0)) + except: + import traceback + traceback.print_exc() + + def OnGetPropertyValues(self,event): + try: + t_start = time.time() + d = self.pg.GetPropertyValues(inc_attributes=True) + t_end = time.time() + self.log.write('GetPropertyValues finished in %.0fms\n' % + ((t_end-t_start)*1000.0)) + ss = ['%s: %s'%(k,repr(v)) for k,v in d.iteritems()] + dlg = MemoDialog(self,"GetPropertyValues Result", + 'Contents of resulting dictionary:\n\n'+'\n'.join(ss)) + dlg.ShowModal() + except: + import traceback + traceback.print_exc() + + def OnGetPropertyValues2(self,event): + try: + t_start = time.time() + d = self.pg.GetPropertyValues(as_strings=True) + t_end = time.time() + self.log.write('GetPropertyValues(as_strings=True) finished in %.0fms\n' % + ((t_end-t_start)*1000.0)) + ss = ['%s: %s'%(k,repr(v)) for k,v in d.iteritems()] + dlg = MemoDialog(self,"GetPropertyValues Result", + 'Contents of resulting dictionary:\n\n'+'\n'.join(ss)) + dlg.ShowModal() + except: + import traceback + traceback.print_exc() + + def OnAutoFill(self,event): + try: + dlg = MemoDialog(self,"Enter Content for Object Used for AutoFill",default_object_content1) + if dlg.ShowModal() == wx.ID_OK: + sandbox = {'object':ValueObject(),'wx':wx} + exec dlg.tc.GetValue() in sandbox + t_start = time.time() + self.pg.AutoFill(sandbox['object']) + t_end = time.time() + self.log.write('AutoFill finished in %.0fms\n' % + ((t_end-t_start)*1000.0)) + except: + import traceback + traceback.print_exc() + + def OnPropGridRightClick(self, event): + p = event.GetProperty() + if p: + self.log.write('%s right clicked\n' % (event.GetProperty().GetName())) + else: + self.log.write('Nothing right clicked\n') + + def OnPropGridPageChange(self, event): + index = self.pg.GetSelectedPage() + self.log.write('Page Changed to \'%s\'\n' % (self.pg.GetPageName(index))) + + def RunTests(self, event): + pg = self.pg + log = self.log + + # Validate client data + log.write('Testing client data set/get') + pg.SetPropertyClientData( "Bool", 1234 ) + if pg.GetPropertyClientData( "Bool" ) != 1234: + raise ValueError("Set/GetPropertyClientData() failed") + + # Test setting unicode string + log.write('Testing setting an unicode string value') + pg.GetPropertyByName("String").SetValue(u"Some Unicode Text") + + # + # Test some code that *should* fail (but not crash) + try: + if wx.GetApp().GetAssertionMode() == wx.PYAPP_ASSERT_EXCEPTION: + log.write('Testing exception handling compliancy') + a_ = pg.GetPropertyValue( "NotARealProperty" ) + pg.EnableProperty( "NotAtAllRealProperty", False ) + pg.SetPropertyHelpString("AgaintNotARealProperty", + "Dummy Help String" ) + except: + pass + + # GetPyIterator + log.write('GetPage(0).GetPyIterator()\n') + it = pg.GetPage(0).GetPyIterator(wxpg.PG_ITERATE_ALL) + for prop in it: + log.write('Iterating \'%s\'\n' % (prop.GetName())) + + # VIterator + log.write('GetPyVIterator()\n') + it = pg.GetPyVIterator(wxpg.PG_ITERATE_ALL) + for prop in it: + log.write('Iterating \'%s\'\n' % (prop.GetName())) + + # Properties + log.write('GetPage(0).Properties\n') + it = pg.GetPage(0).Properties + for prop in it: + log.write('Iterating \'%s\'\n' % (prop.GetName())) + + # Items + log.write('GetPage(0).Items\n') + it = pg.GetPage(0).Items + for prop in it: + log.write('Iterating \'%s\'\n' % (prop.GetName())) + +#--------------------------------------------------------------------------- + + +class MemoDialog(wx.Dialog): + """\ + Dialog for multi-line text editing. + """ + def __init__(self,parent=None,title="",text="",pos=None,size=(500,500)): + wx.Dialog.__init__(self,parent,-1,title,style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) + + topsizer = wx.BoxSizer( wx.VERTICAL ) + + tc = wx.TextCtrl(self,11,text,style=wx.TE_MULTILINE) + self.tc = tc + topsizer.Add(tc,1,wx.EXPAND|wx.ALL,8) + + rowsizer = wx.BoxSizer( wx.HORIZONTAL ) + rowsizer.Add(wx.Button(self,wx.ID_OK,'Ok'),0,wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL,8) + rowsizer.Add((0,0),1,wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL,8) + rowsizer.Add(wx.Button(self,wx.ID_CANCEL,'Cancel'),0,wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL,8) + topsizer.Add(rowsizer,0,wx.EXPAND|wx.ALL,8) + + self.SetSizer( topsizer ) + topsizer.Layout() + + self.SetSize( size ) + if not pos: + self.CenterOnScreen() + else: + self.Move(pos) + +#---------------------------------------------------------------------- + +def runTest( frame, nb, log ): + win = TestPanel( nb, log ) + return win + +#---------------------------------------------------------------------- + + +overview = """\ + +

+This demo shows all basic wxPropertyGrid properties, in addition to +some custom property classes. + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/PseudoDC.py b/demo/PseudoDC.py new file mode 100644 index 00000000..15ef8da4 --- /dev/null +++ b/demo/PseudoDC.py @@ -0,0 +1,343 @@ + +import wx +import images +import random + +#--------------------------------------------------------------------------- + +W = 2000 +H = 2000 +SW = 150 +SH = 150 +SHAPE_COUNT = 2500 +hitradius = 5 + +#--------------------------------------------------------------------------- + +colours = [ + "BLACK", + "BLUE", + "BLUE VIOLET", + "BROWN", + "CYAN", + "DARK GREY", + "DARK GREEN", + "GOLD", + "GREY", + "GREEN", + "MAGENTA", + "NAVY", + "PINK", + "RED", + "SKY BLUE", + "VIOLET", + "YELLOW", + ] + + + +class MyCanvas(wx.ScrolledWindow): + def __init__(self, parent, id, log, size = wx.DefaultSize): + wx.ScrolledWindow.__init__(self, parent, id, (0, 0), size=size, style=wx.SUNKEN_BORDER) + + self.lines = [] + self.maxWidth = W + self.maxHeight = H + self.x = self.y = 0 + self.curLine = [] + self.drawing = False + + self.SetBackgroundColour("WHITE") + bmp = images.Test2.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + bmp.SetMask(mask) + self.bmp = bmp + + self.SetVirtualSize((self.maxWidth, self.maxHeight)) + self.SetScrollRate(20,20) + + # create a PseudoDC to record our drawing + self.pdc = wx.PseudoDC() + self.pen_cache = {} + self.brush_cache = {} + self.DoDrawing(self.pdc) + log.write('Created PseudoDC draw list with %d operations!'%self.pdc.GetLen()) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_ERASE_BACKGROUND, lambda x:None) + self.Bind(wx.EVT_MOUSE_EVENTS, self.OnMouse) + + # vars for handling mouse clicks + self.dragid = -1 + self.lastpos = (0,0) + + def ConvertEventCoords(self, event): + xView, yView = self.GetViewStart() + xDelta, yDelta = self.GetScrollPixelsPerUnit() + return (event.GetX() + (xView * xDelta), + event.GetY() + (yView * yDelta)) + + def OffsetRect(self, r): + xView, yView = self.GetViewStart() + xDelta, yDelta = self.GetScrollPixelsPerUnit() + r.OffsetXY(-(xView*xDelta),-(yView*yDelta)) + + def OnMouse(self, event): + global hitradius + if event.LeftDown(): + x,y = self.ConvertEventCoords(event) + #l = self.pdc.FindObjectsByBBox(x, y) + l = self.pdc.FindObjects(x, y, hitradius) + for id in l: + if not self.pdc.GetIdGreyedOut(id): + self.dragid = id + self.lastpos = (event.GetX(),event.GetY()) + break + elif event.RightDown(): + x,y = self.ConvertEventCoords(event) + #l = self.pdc.FindObjectsByBBox(x, y) + l = self.pdc.FindObjects(x, y, hitradius) + if l: + self.pdc.SetIdGreyedOut(l[0], not self.pdc.GetIdGreyedOut(l[0])) + r = self.pdc.GetIdBounds(l[0]) + r.Inflate(4,4) + self.OffsetRect(r) + self.RefreshRect(r, False) + elif event.Dragging() or event.LeftUp(): + if self.dragid != -1: + x,y = self.lastpos + dx = event.GetX() - x + dy = event.GetY() - y + r = self.pdc.GetIdBounds(self.dragid) + self.pdc.TranslateId(self.dragid, dx, dy) + r2 = self.pdc.GetIdBounds(self.dragid) + r = r.Union(r2) + r.Inflate(4,4) + self.OffsetRect(r) + self.RefreshRect(r, False) + self.lastpos = (event.GetX(),event.GetY()) + if event.LeftUp(): + self.dragid = -1 + + def RandomPen(self): + c = random.choice(colours) + t = random.randint(1, 4) + if not self.pen_cache.has_key( (c, t) ): + self.pen_cache[(c, t)] = wx.Pen(c, t) + return self.pen_cache[(c, t)] + + + def RandomBrush(self): + c = random.choice(colours) + if not self.brush_cache.has_key(c): + self.brush_cache[c] = wx.Brush(c) + + return self.brush_cache[c] + + def RandomColor(self): + return random.choice(colours) + + + def OnPaint(self, event): + # Create a buffered paint DC. It will create the real + # wx.PaintDC and then blit the bitmap to it when dc is + # deleted. + dc = wx.BufferedPaintDC(self) + # use PrepateDC to set position correctly + self.PrepareDC(dc) + # we need to clear the dc BEFORE calling PrepareDC + bg = wx.Brush(self.GetBackgroundColour()) + dc.SetBackground(bg) + dc.Clear() + # create a clipping rect from our position and size + # and the Update Region + xv, yv = self.GetViewStart() + dx, dy = self.GetScrollPixelsPerUnit() + x, y = (xv * dx, yv * dy) + rgn = self.GetUpdateRegion() + rgn.Offset(x,y) + r = rgn.GetBox() + # draw to the dc using the calculated clipping rect + self.pdc.DrawToDCClipped(dc,r) + + def DoDrawing(self, dc): + random.seed() + self.objids = [] + self.boundsdict = {} + dc.BeginDrawing() + for i in range(SHAPE_COUNT): + id = wx.NewId() + dc.SetId(id) + choice = random.randint(0,8) + if choice in (0,1): + x = random.randint(0, W) + y = random.randint(0, H) + pen = self.RandomPen() + dc.SetPen(pen) + dc.DrawPoint(x,y) + r = wx.Rect(x,y,1,1) + r.Inflate(pen.GetWidth(),pen.GetWidth()) + dc.SetIdBounds(id,r) + elif choice in (2,3): + x1 = random.randint(0, W-SW) + y1 = random.randint(0, H-SH) + x2 = random.randint(x1, x1+SW) + y2 = random.randint(y1, y1+SH) + pen = self.RandomPen() + dc.SetPen(pen) + dc.DrawLine(x1,y1,x2,y2) + r = wx.Rect(x1,y1,x2-x1,y2-y1) + r.Inflate(pen.GetWidth(),pen.GetWidth()) + dc.SetIdBounds(id,r) + elif choice in (4,5): + w = random.randint(10, SW) + h = random.randint(10, SH) + x = random.randint(0, W - w) + y = random.randint(0, H - h) + pen = self.RandomPen() + dc.SetPen(pen) + dc.SetBrush(self.RandomBrush()) + dc.DrawRectangle(x,y,w,h) + r = wx.Rect(x,y,w,h) + r.Inflate(pen.GetWidth(),pen.GetWidth()) + dc.SetIdBounds(id,r) + self.objids.append(id) + elif choice == 6: + Np = 8 # number of characters in text + word = [] + for i in range(Np): + c = chr( random.randint(48, 122) ) + word.append( c ) + word = "".join(word) + w,h = self.GetFullTextExtent(word)[0:2] + x = random.randint(0, W-w) + y = random.randint(0, H-h) + dc.SetFont(self.GetFont()) + dc.SetTextForeground(self.RandomColor()) + dc.SetTextBackground(self.RandomColor()) + dc.DrawText(word, x, y) + r = wx.Rect(x,y,w,h) + r.Inflate(2,2) + dc.SetIdBounds(id, r) + self.objids.append(id) + elif choice == 7: + Np = 8 # number of points per polygon + poly = [] + minx = SW + miny = SH + maxx = 0 + maxy = 0 + for i in range(Np): + x = random.randint(0, SW) + y = random.randint(0, SH) + if x < minx: minx = x + if x > maxx: maxx = x + if y < miny: miny = y + if y > maxy: maxy = y + poly.append(wx.Point(x,y)) + x = random.randint(0, W-SW) + y = random.randint(0, H-SH) + pen = self.RandomPen() + dc.SetPen(pen) + dc.SetBrush(self.RandomBrush()) + dc.DrawPolygon(poly, x,y) + r = wx.Rect(minx+x,miny+y,maxx-minx,maxy-miny) + r.Inflate(pen.GetWidth(),pen.GetWidth()) + dc.SetIdBounds(id,r) + self.objids.append(id) + elif choice == 8: + w,h = self.bmp.GetSize() + x = random.randint(0, W-w) + y = random.randint(0, H-h) + dc.DrawBitmap(self.bmp,x,y,True) + dc.SetIdBounds(id,wx.Rect(x,y,w,h)) + self.objids.append(id) + dc.EndDrawing() + +class ControlPanel(wx.Panel): + def __init__(self, parent, id, pos=wx.DefaultPosition, + size=wx.DefaultSize, style = wx.TAB_TRAVERSAL): + wx.Panel.__init__(self,parent,id,pos,size,style) + lbl = wx.StaticText(self, wx.ID_ANY, "Hit Test Radius: ") + lbl2 = wx.StaticText(self, wx.ID_ANY, "Left Click to drag, Right Click to enable/disable") + sc = wx.SpinCtrl(self, wx.ID_ANY, "5") + sc.SetRange(0,100) + global hitradius + sc.SetValue(hitradius) + self.sc = sc + sz = wx.BoxSizer(wx.HORIZONTAL) + sz.Add(lbl,0,wx.EXPAND) + sz.Add(sc,0) + sz.Add(lbl2,0,wx.LEFT,5) + sz.Add((10,10),1,wx.EXPAND) + self.SetSizerAndFit(sz) + sc.Bind(wx.EVT_SPINCTRL,self.OnChange) + sc.Bind(wx.EVT_TEXT,self.OnChange) + + def OnChange(self, event): + global hitradius + hitradius = self.sc.GetValue() + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + pnl = wx.Panel(nb, wx.ID_ANY,size=(200,30)) + pnl2 = ControlPanel(pnl,wx.ID_ANY) + win = MyCanvas(pnl, wx.ID_ANY, log) + sz = wx.BoxSizer(wx.VERTICAL) + sz.Add(pnl2,0,wx.EXPAND|wx.ALL,5) + sz.Add(win,1,wx.EXPAND) + pnl.SetSizerAndFit(sz) + return pnl + +#--------------------------------------------------------------------------- + + + +overview = """ + + +

wx.PseudoDC

+ +The wx.PseudoDC class provides a way to record operations on a DC and then +play them back later. The PseudoDC can be passed to a drawing routine as +if it were a real DC. All Drawing methods are supported except Blit but +GetXXX methods are not supported and none of the drawing methods return +a value. The PseudoDC records the drawing to an operation +list. The operations can be played back to a real DC using:
+DrawToDC(dc)
+
+The operations can be tagged with an id in order to associated them with a +specific object. To do this use:
+    SetId(id)
+
+Every operation after this will be associated with id until SetId is called +again. The PseudoDC also supports object level clipping. To enable this use:
+    SetIdBounds(id,rect)
+
+for each object that should be clipped. Then use:
+    DrawToDCClipped(dc, clippingRect)
+
+To draw the PseudoDC to a real dc. This is useful for large scrolled windows +where many objects are offscreen. + +Objects can be moved around without re-drawing using:
+    TranslateId(id, dx, dy)
+
+ +To re-draw an object use:
+    ClearId(id)
+    SetId(id)
+
+and then re-draw the object. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/PyColourChooser.py b/demo/PyColourChooser.py new file mode 100644 index 00000000..32921e15 --- /dev/null +++ b/demo/PyColourChooser.py @@ -0,0 +1,59 @@ + +import wx +import wx.lib.colourchooser as cc + +#--------------------------------------------------------------- + +class TestColourChooser(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + chooser = cc.PyColourChooser(self, -1) + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(chooser, 0, wx.ALL, 25) + + self.SetAutoLayout(True) + self.SetSizer(sizer) + +#--------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestColourChooser(nb, log) + return win + +#--------------------------------------------------------------- + +overview = """ +The PyColourChooser component creates a colour chooser window +that is similar to the Microsoft Windows colour chooser dialog. +This dialog component is drawn in a panel, and thus can be +embedded inside any widget (although it cannot be resized). +This colour chooser may also be substituted for the colour +chooser on any platform that might have an ugly one :) + +How to use it +------------------------------ + +The demo (demo/PyColourChooser.py code shows how to display +a colour chooser and retrieve its options. + +Contact and Author Info +------------------------------ + +PyColourChooser was written and is maintained by: + + Michael Gilfix + +You can find the latest PyColourChooser code at +http://sourceforge.net/projects/wxcolourchooser/. If you have +any suggestions or want to submit a patch, please send +it my way at: mgilfix@eecs.tufts.edu +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/PyCrust.py b/demo/PyCrust.py new file mode 100644 index 00000000..3fd96ebe --- /dev/null +++ b/demo/PyCrust.py @@ -0,0 +1,20 @@ + +import wx.py as py + +#---------------------------------------------------------------------- + +intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % py.version.VERSION + +def runTest(frame, nb, log): + win = py.crust.Crust(nb, intro=intro) + return win + +#---------------------------------------------------------------------- + +overview = py.filling.__doc__ + "\n\n" + py.crust.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/PyPlot.py b/demo/PyPlot.py new file mode 100644 index 00000000..84866f64 --- /dev/null +++ b/demo/PyPlot.py @@ -0,0 +1,144 @@ + +import wx + +hadImportError = False +try: + import wx.lib.plot +except ImportError: + hadImportError = True + + +################################################################\ +# Where's the code??? | +# | +# wx.lib.plot.py came with its own excellent demo built in, | +# for testing purposes, but it serves quite well to demonstrate | +# the code and classes within, so we are simply borrowing that | +# code for the demo. Please load up wx.lib.plot.py for a review | +# of the code itself. The demo/test is at the bottom of | +# the file, as expected. | +################################################################/ + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show the PyPlot sample", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = wx.lib.plot.TestFrame(self, -1, "PlotCanvas Demo") + win.Show() + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + if not hadImportError: + win = TestPanel(nb, log) + else: + from wx.lib.msgpanel import MessagePanel + win = MessagePanel(nb, """\ +This demo requires the Numeric or numarray module, +which could not be imported. It probably is not installed +(it's not part of the standard Python distribution). See the +Python site (http://www.python.org) for information on +downloading source or binaries.""", + 'Sorry', wx.ICON_WARNING) + + return win + + +#---------------------------------------------------------------------- + +if hadImportError: + overview = "" +else: + overview = """\ + +

PyPlot

+ +This demo illustrates the features of the new PyPlot modules, found +in wx.lib.plot.py. All methods and functions are documented clearly +therein; only the overview is included here. + +

+PyPlot is an improvement over wxPlotCanvas, which is now deprecated. +If you are using wxPlotCanvas now, please make plans to migrate in +anticipation of the time that wxPlotCanvas disappears completely. + +

+The demo illustrates four different plot styles (with appropriate +variations on fonts, etc, to show how flexible it is) as well as +provides you with a means to tinker with all the features that +come with the class itself. + +

    +
  • File Menu + +
      +
    • Page Setup + +

      This allows you to set up how the plot will be printed. This + is built into the library itself. + +

    • Print Preview + +

      As you might expect, this allows you to preview how the plot + will look when printed, in light of the page setup you may + have selected above. + +

    • Print + +

      Surprise! It prints the current plot to your printer! :-) + +

    • Save Plot + +

      That's right, the library even provides you with the means + to export the plotted data out to a graphics file. Several + formats are allowed for, basically any image class that + supports saving. +

    + +
  • Plot Menu + +
      +
    • Plot 1 ... Plot 5 + +

      Different data with different plot formats, including one empty + plot. + +

    • Enable Zoom + +

      If Zoom is enabled, you can rubber-band select an area of the + plot to examine it in detail using the left mouse button. Right + mouse button zooms back out. This is automatically supported + by the library, all you have to do is turn it on. + +

    • Enable Grid + +

      Plots can have different styles of grids, and and these grids can + be turned on or off as needed. + +

    • Enable Legend + +

      Plot can have legends or not, the contents which are definable + by you. +

    +
+ +
+%s
+ +""" % wx.lib.plot.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/PyShell.py b/demo/PyShell.py new file mode 100644 index 00000000..0c9fa949 --- /dev/null +++ b/demo/PyShell.py @@ -0,0 +1,21 @@ + +import wx.py as py + +#---------------------------------------------------------------------- + +intro = 'Welcome To PyCrust %s - The Flakiest Python Shell' % py.version.VERSION + +def runTest(frame, nb, log): + win = py.shell.Shell(nb, -1, introText=intro) + return win + +#---------------------------------------------------------------------- + +overview = py.shell.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/PythonEvents.py b/demo/PythonEvents.py new file mode 100644 index 00000000..b65a9183 --- /dev/null +++ b/demo/PythonEvents.py @@ -0,0 +1,108 @@ + +import sys + +import wx + +#---------------------------------------------------------------------- + +# This shows the new 'official' way to do custom events as derived +# from the wxPython 2.5 migration guide. + +#######################################################\ +# *** Old and busted *** | +# | +# myEVT_BUTTON_CLICKPOS = wx.NewEventType() | +# | +# def EVT_BUTTON_CLICKPOS(win, id, func): | +# win.Connect(id, -1, myEVT_BUTTON_CLICKPOS, func) | +#######################################################/ + +#############################\ +# *** The new Hottness *** | +#############################/ +myEVT_BUTTON_CLICKPOS = wx.NewEventType() +EVT_BUTTON_CLICKPOS = wx.PyEventBinder(myEVT_BUTTON_CLICKPOS, 1) + +#---------------------------------------------------------------------- + + +class MyEvent(wx.PyCommandEvent): + def __init__(self, evtType, id): + wx.PyCommandEvent.__init__(self, evtType, id) + self.myVal = None + + #def __del__(self): + # print '__del__' + # wx.PyCommandEvent.__del__(self) + + def SetMyVal(self, val): + self.myVal = val + + def GetMyVal(self): + return self.myVal + + +class MyButton(wx.Button): + def __init__(self, parent, id, txt, pos): + wx.Button.__init__(self, parent, id, txt, pos) + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + + def OnLeftDown(self, event): + pt = event.GetPosition() + evt = MyEvent(myEVT_BUTTON_CLICKPOS, self.GetId()) + evt.SetMyVal(pt) + #print id(evt), sys.getrefcount(evt) + self.GetEventHandler().ProcessEvent(evt) + #print id(evt), sys.getrefcount(evt) + event.Skip() + + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + b = MyButton(self, -1, " Click me ", (30,30)) + self.Bind(wx.EVT_BUTTON, self.OnClick, id=b.GetId()) + + # This is our custom event binder created above. + self.Bind(EVT_BUTTON_CLICKPOS, self.OnMyEvent, id=b.GetId()) + + wx.StaticText( + self, -1, "Please see the Overview and Demo Code for details...", + (30, 80) + ) + + + def OnClick(self, event): + self.log.WriteText("OnClick\n") + + def OnMyEvent(self, event): + #print id(event), sys.getrefcount(event) + self.log.WriteText("MyEvent: %s\n" % (event.GetMyVal(), ) ) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ +This demo is a contrived example of defining an event class in wxPython and +sending it up the containment hierarchy for processing. + +V2.5 note: this demo also shows the new style of creating event binders that +is required if you used the *.Bind() method of setting up event handlers. +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/README.txt b/demo/README.txt new file mode 100644 index 00000000..c1f635e9 --- /dev/null +++ b/demo/README.txt @@ -0,0 +1,7 @@ +To run the main demo in this directory, execute demo.py. In other +words, one of the following commands should do it: + + demo.py + python demo.py + pythonw demo.py + diff --git a/demo/RadioBox.py b/demo/RadioBox.py new file mode 100644 index 00000000..6f728dcc --- /dev/null +++ b/demo/RadioBox.py @@ -0,0 +1,66 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestRadioBox(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + #self.SetBackgroundColour(wx.BLUE) + + sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', + 'six', 'seven', 'eight'] + + sizer = wx.BoxSizer(wx.VERTICAL) + + rb = wx.RadioBox( + self, -1, "wx.RadioBox", wx.DefaultPosition, wx.DefaultSize, + sampleList, 2, wx.RA_SPECIFY_COLS + ) + + self.Bind(wx.EVT_RADIOBOX, self.EvtRadioBox, rb) + #rb.SetBackgroundColour(wx.BLUE) + rb.SetToolTip(wx.ToolTip("This is a ToolTip!")) + #rb.SetLabel("wx.RadioBox") + + sizer.Add(rb, 0, wx.ALL, 20) + + rb = wx.RadioBox( + self, -1, "", wx.DefaultPosition, wx.DefaultSize, + sampleList, 3, wx.RA_SPECIFY_COLS | wx.NO_BORDER + ) + + self.Bind(wx.EVT_RADIOBOX, self.EvtRadioBox, rb) + rb.SetToolTip(wx.ToolTip("This box has no label")) + + sizer.Add(rb, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, 20) + + self.SetSizer(sizer) + + + def EvtRadioBox(self, event): + self.log.WriteText('EvtRadioBox: %d\n' % event.GetInt()) + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestRadioBox(nb, log) + return win + + + +overview = """\ +A RadioBox is used to select one of a number of mutually exclusive +choices. It is displayed as a vertical column or horizontal row of +labelled buttons, surrounded by a box that can optionally have a +label. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/RadioButton.py b/demo/RadioButton.py new file mode 100644 index 00000000..b84e7e21 --- /dev/null +++ b/demo/RadioButton.py @@ -0,0 +1,126 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel( wx.Panel ): + def __init__( self, parent, log ): + + wx.Panel.__init__( self, parent, -1 ) + self.log = log + panel = wx.Panel( self, -1 ) + + # Layout controls on panel: + vs = wx.BoxSizer( wx.VERTICAL ) + + box1_title = wx.StaticBox( panel, -1, "Group 1" ) + box1 = wx.StaticBoxSizer( box1_title, wx.VERTICAL ) + grid1 = wx.FlexGridSizer( cols=2 ) + + # 1st group of controls: + self.group1_ctrls = [] + radio1 = wx.RadioButton( panel, -1, " Radio1 ", style = wx.RB_GROUP ) + radio2 = wx.RadioButton( panel, -1, " Radio2 " ) + radio3 = wx.RadioButton( panel, -1, " Radio3 " ) + text1 = wx.TextCtrl( panel, -1, "" ) + text2 = wx.TextCtrl( panel, -1, "" ) + text3 = wx.TextCtrl( panel, -1, "" ) + self.group1_ctrls.append((radio1, text1)) + self.group1_ctrls.append((radio2, text2)) + self.group1_ctrls.append((radio3, text3)) + + for radio, text in self.group1_ctrls: + grid1.Add( radio, 0, wx.ALIGN_CENTRE|wx.LEFT|wx.RIGHT|wx.TOP, 5 ) + grid1.Add( text, 0, wx.ALIGN_CENTRE|wx.LEFT|wx.RIGHT|wx.TOP, 5 ) + + box1.Add( grid1, 0, wx.ALIGN_CENTRE|wx.ALL, 5 ) + vs.Add( box1, 0, wx.ALIGN_CENTRE|wx.ALL, 5 ) + + box2_title = wx.StaticBox( panel, -1, "Group 2" ) + box2 = wx.StaticBoxSizer( box2_title, wx.VERTICAL ) + grid2 = wx.FlexGridSizer( cols=2 ) + + # 2nd group of controls: + self.group2_ctrls = [] + radio4 = wx.RadioButton( panel, -1, " Radio1 ", style = wx.RB_GROUP ) + radio5 = wx.RadioButton( panel, -1, " Radio2 " ) + radio6 = wx.RadioButton( panel, -1, " Radio3 " ) + text4 = wx.TextCtrl( panel, -1, "" ) + text5 = wx.TextCtrl( panel, -1, "" ) + text6 = wx.TextCtrl( panel, -1, "" ) + self.group2_ctrls.append((radio4, text4)) + self.group2_ctrls.append((radio5, text5)) + self.group2_ctrls.append((radio6, text6)) + + for radio, text in self.group2_ctrls: + grid2.Add( radio, 0, wx.ALIGN_CENTRE|wx.LEFT|wx.RIGHT|wx.TOP, 5 ) + grid2.Add( text, 0, wx.ALIGN_CENTRE|wx.LEFT|wx.RIGHT|wx.TOP, 5 ) + + box2.Add( grid2, 0, wx.ALIGN_CENTRE|wx.ALL, 5 ) + vs.Add( box2, 0, wx.ALIGN_CENTRE|wx.ALL, 5 ) + + panel.SetSizer( vs ) + vs.Fit( panel ) + panel.Move( (50,50) ) + self.panel = panel + + # Setup event handling and initial state for controls: + for radio, text in self.group1_ctrls: + self.Bind(wx.EVT_RADIOBUTTON, self.OnGroup1Select, radio ) + + for radio, text in self.group2_ctrls: + self.Bind(wx.EVT_RADIOBUTTON, self.OnGroup2Select, radio ) + + for radio, text in self.group1_ctrls + self.group2_ctrls: + radio.SetValue(0) + text.Enable(False) + + def OnGroup1Select( self, event ): + radio_selected = event.GetEventObject() + self.log.write('Group1 %s selected\n' % radio_selected.GetLabel() ) + + for radio, text in self.group1_ctrls: + if radio is radio_selected: + text.Enable(True) + else: + text.Enable(False) + + def OnGroup2Select( self, event ): + radio_selected = event.GetEventObject() + self.log.write('Group2 %s selected\n' % radio_selected.GetLabel() ) + + for radio, text in self.group2_ctrls: + if radio is radio_selected: + text.Enable(True) + else: + text.Enable(False) + +#---------------------------------------------------------------------- + +def runTest( frame, nb, log ): + win = TestPanel( nb, log ) + return win + +#---------------------------------------------------------------------- + + +overview = """\ + +

+This demo shows how individual radio buttons can be used to build +more complicated selection mechanisms... +

+It uses 2 groups of wx.RadioButtons, where the groups are defined by +instantiation. When a wx.RadioButton is created with the wx.RB_GROUP +style, all subsequent wx.RadioButtons created without it are implicitly +added to that group by the framework. + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/RawBitmapAccess.py b/demo/RawBitmapAccess.py new file mode 100644 index 00000000..b4b6b768 --- /dev/null +++ b/demo/RawBitmapAccess.py @@ -0,0 +1,206 @@ +import wx + +# use the numpy code instead of the raw access code for comparison +USE_NUMPY = False + +# time the execution of making a bitmap? +TIMEIT = False + +# how big to make the bitmaps +DIM = 100 + +# should we use a wx.GraphicsContext for painting? +TEST_GC = False + +#---------------------------------------------------------------------- +# attempt to import a numeric module if requested to + +if USE_NUMPY: + try: + import numpy + def makeByteArray(shape): + return numpy.empty(shape, numpy.uint8) + numtype = 'numpy' + except ImportError: + try: + import numarray + def makeByteArray(shape): + arr = numarray.array(shape=shape, typecode='u1') + arr[:] = 0 + return arr + numtype = 'numarray' + except ImportError: + USE_NUMPY = False + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + if TIMEIT: + import timeit + timeit.s = self # Put self in timeit's global namespace as + # 's' so it can be found in the code + # snippets being tested. + if not USE_NUMPY: + t = timeit.Timer("bmp = s.MakeBitmap(10, 20, 30)") + else: + t = timeit.Timer("bmp = s.MakeBitmap2(10, 20, 30)") + log.write("Timing...\n") + num = 100 + tm = t.timeit(num) + log.write("%d passes in %f seconds == %f seconds per pass " % + (num, tm, tm/num)) + + if not USE_NUMPY: + log.write("using raw access\n") + self.redBmp = self.MakeBitmap(178, 34, 34) + self.greenBmp = self.MakeBitmap( 35, 142, 35) + self.blueBmp = self.MakeBitmap( 0, 0, 139) + else: + log.write("using %s\n" % numtype) + self.redBmp = self.MakeBitmap2(178, 34, 34) + self.greenBmp = self.MakeBitmap2( 35, 142, 35) + self.blueBmp = self.MakeBitmap2( 0, 0, 139) + + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + if not TEST_GC: + dc.DrawBitmap(self.redBmp, 50, 50, True) + dc.DrawBitmap(self.greenBmp, 110, 110, True) + dc.DrawBitmap(self.blueBmp, 170, 50, True) + self.log.write("using wx.DC\n") + else: + gc = wx.GraphicsContext.Create(dc) + gc.DrawBitmap(self.redBmp, 50, 50, DIM,DIM) + gc.DrawBitmap(self.greenBmp, 110, 110, DIM,DIM) + gc.DrawBitmap(self.blueBmp, 170, 50, DIM,DIM) + self.log.write("using wx.GraphicsContext\n") + + def MakeBitmap(self, red, green, blue, alpha=128): + # Create the bitmap that we will stuff pixel values into using + # the raw bitmap access classes. + bmp = wx.EmptyBitmap(DIM, DIM, 32) + + # Create an object that facilitates access to the bitmap's + # pixel buffer + pixelData = wx.AlphaPixelData(bmp) + if not pixelData: + raise RuntimeError("Failed to gain raw access to bitmap data.") + + # We have two ways to access each pixel, first we'll use an + # iterator to set every pixel to the colour and alpha values + # passed in. + for pixel in pixelData: + pixel.Set(red, green, blue, alpha) + + # This block of code is another way to do the same as above, + # but with the accessor interface instead of the Python + # iterator. It is a bit faster than the above because it + # avoids the iterator/generator magic, but it is not nearly as + # 'clean' looking ;-) + #pixels = pixelData.GetPixels() + #for y in xrange(DIM): + # pixels.MoveTo(pixelData, 0, y) + # for x in xrange(DIM): + # pixels.Set(red, green, blue, alpha) + # pixels.nextPixel() + + + + # Next we'll use the pixel accessor to set the border pixels + # to be fully opaque + pixels = pixelData.GetPixels() + for x in xrange(DIM): + pixels.MoveTo(pixelData, x, 0) + pixels.Set(red, green, blue, wx.ALPHA_OPAQUE) + pixels.MoveTo(pixelData, x, DIM-1) + pixels.Set(red, green, blue, wx.ALPHA_OPAQUE) + for y in xrange(DIM): + pixels.MoveTo(pixelData, 0, y) + pixels.Set(red, green, blue, wx.ALPHA_OPAQUE) + pixels.MoveTo(pixelData, DIM-1, y) + pixels.Set(red, green, blue, wx.ALPHA_OPAQUE) + + return bmp + + + def MakeBitmap2(self, red, green, blue, alpha=128): + # Make an array of bytes that is DIM*DIM in size, with enough + # slots for each pixel to have a RGB and A value + arr = makeByteArray( (DIM,DIM, 4) ) + + # just some indexes to keep track of which byte is which + R, G, B, A = range(4) + + # initialize all pixel values to the values passed in + arr[:,:,R] = red + arr[:,:,G] = green + arr[:,:,B] = blue + arr[:,:,A] = alpha + + # Set the alpha for the border pixels to be fully opaque + arr[0, 0:DIM, A] = wx.ALPHA_OPAQUE # first row + arr[DIM-1, 0:DIM, A] = wx.ALPHA_OPAQUE # last row + arr[0:DIM, 0, A] = wx.ALPHA_OPAQUE # first col + arr[0:DIM, DIM-1, A] = wx.ALPHA_OPAQUE # last col + + # finally, use the array to create a bitmap + bmp = wx.BitmapFromBufferRGBA(DIM, DIM, arr) + return bmp + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Raw Bitmap Access

+ +wx.NativePixelData and wx.AlphaPixelData provide a cross-platform way +to access the platform-specific pixel buffer within a wx.Bitmap. They +provide both a random access method, and an iterator interface. + +

Unfortunately, although these classes are convienient ways to access +and update the contents of a wx.Bitmap, we lose most of the efficiency +of the C++ classes by requiring one or more Python-to-C++ transitions +for each pixel. In fact it can be much slower than the other +ways of creating a bitmap from scratch, especially now that +wx.BitmapFromBuffer exists and can save the time needed to copy from a +wx.Image. + +

To see this difference for yourself this module has been +instrumented to allow you to experiment with using either the raw +access or numpy/numarray, and also to time how long it takes to create +100 bitmaps like you see on the screen. Simply edit this module in +the \"Demo Code\" tab and set TIMEIT to True and then watch +the log window when the sample is reloaded. To try numpy or numarray +(if you have them installed) then set USE_NUMPY to True as well, and +watch the log window again. On my machines there is about an +order of magnitude difference between the raw access functions +and using a numarray.array with wx.BitmapFromBufferRGBA! Almost +another order of magnitude improvement can be gained with using the +new numpy module! + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/RendererNative.py b/demo/RendererNative.py new file mode 100644 index 00000000..b0d94c4b --- /dev/null +++ b/demo/RendererNative.py @@ -0,0 +1,156 @@ +import wx +import os + +#---------------------------------------------------------------------- +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent) + + # Event Handlers + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def OnPaint(self, event): + dc = wx.GCDC(wx.PaintDC(self)) + #dc = wx.PaintDC(self) + render = wx.RendererNative.Get() + + # Setup Brushes + dc.SetBrush(wx.BLACK_BRUSH) + dc.SetTextForeground(wx.BLACK) + dc.SetFont(wx.NORMAL_FONT) + + # The below code will use RendererNative to draw controls in + # various states. The wx.CONTROL_* flags are used to tell the + # Renderer which state to draw the control in. + + # Draw some checkboxes + cb_lbl = "DrawCheckBoxes:" + dc.DrawText(cb_lbl, 15, 15) + render.DrawCheckBox(self, dc, (25, 35, 16, 16), wx.CONTROL_CHECKED) + render.DrawCheckBox(self, dc, (45, 35, 16, 16), wx.CONTROL_CHECKABLE) + render.DrawCheckBox(self, dc, (65, 35, 16, 16)) + render.DrawCheckBox(self, dc, (85, 35, 16, 16), wx.CONTROL_CHECKED | wx.CONTROL_DISABLED) + + lbl = "DrawRadioBitmap:" + dc.DrawText(lbl, 375, 15) + render.DrawRadioBitmap(self, dc, (385, 35, 16, 16), wx.CONTROL_CHECKED) + render.DrawRadioBitmap(self, dc, (405, 35, 16, 16), wx.CONTROL_CHECKABLE) + render.DrawRadioBitmap(self, dc, (425, 35, 16, 16)) + render.DrawRadioBitmap(self, dc, (445, 35, 16, 16), wx.CONTROL_CHECKED | wx.CONTROL_DISABLED) + + # Draw ComboBoxDropButton + xpos = self.GetTextExtent(cb_lbl)[0] + 40 + cb_lbl = "DrawComboBoxDropButton:" + dc.DrawText(cb_lbl, xpos, 15) + render.DrawComboBoxDropButton(self, dc, (xpos + 4, 35, 24, 24), wx.CONTROL_CURRENT) + render.DrawComboBoxDropButton(self, dc, (xpos + 44, 35, 24, 24), wx.CONTROL_PRESSED) + render.DrawComboBoxDropButton(self, dc, (xpos + 84, 35, 24, 24), wx.CONTROL_CURRENT | wx.CONTROL_DISABLED) + render.DrawComboBoxDropButton(self, dc, (xpos + 124, 35, 24, 24), wx.CONTROL_PRESSED | wx.CONTROL_DISABLED) + + # Draw DropArrow + da_lbl = "DrawDropArrow:" + dc.DrawText(da_lbl, 15, 80) + render.DrawDropArrow(self, dc, (15, 100, 24, 24), wx.CONTROL_CURRENT) + render.DrawDropArrow(self, dc, (35, 100, 24, 24), wx.CONTROL_PRESSED) + render.DrawDropArrow(self, dc, (55, 100, 24, 24), wx.CONTROL_CURRENT | wx.CONTROL_DISABLED) + + # Draw HeaderButton + dc.DrawText("DrawHeaderButton:", xpos, 80) + # Set some extra options for drawing + opts = wx.HeaderButtonParams() + hb_lbl = "HeaderButton Selected" + opts.m_labelText = hb_lbl + render.DrawHeaderButton(self, dc, (xpos, 100, self.GetTextExtent(hb_lbl)[0] + 30, 16), + wx.CONTROL_SELECTED, wx.HDR_SORT_ICON_DOWN, opts) + hb_lbl = "HeaderButton Normal" + opts.m_labelText = hb_lbl + render.DrawHeaderButton(self, dc, (xpos, 125, self.GetTextExtent(hb_lbl)[0] + 30, 16), + sortArrow=wx.HDR_SORT_ICON_UP, params=opts) + + hb_lbl = "HeaderButton Current" + opts.m_labelText = hb_lbl + render.DrawHeaderButton(self, dc, (xpos, 150, self.GetTextExtent(hb_lbl)[0] + 30, 16), + wx.CONTROL_CURRENT, params=opts) + + # Draw ItemSelectionRect + isr_lbl = "DrawItemSelectionRect:" + dc.DrawText(isr_lbl, 15, 185) + render.DrawItemSelectionRect(self, dc, (15, 205, 40, 24), wx.CONTROL_SELECTED) + render.DrawItemSelectionRect(self, dc, (65, 205, 40, 24), wx.CONTROL_CURRENT) + render.DrawItemSelectionRect(self, dc, (115, 205, 40, 24), wx.CONTROL_FOCUSED) + + # DrawPushButton + pb_lbl = "DrawPushButton:" + dc.DrawText(pb_lbl, 15, 255) + render.DrawPushButton(self, dc, (15, 275, 45, 24), wx.CONTROL_CURRENT) + render.DrawPushButton(self, dc, (70, 275, 45, 24), wx.CONTROL_PRESSED | wx.CONTROL_SELECTED) + render.DrawPushButton(self, dc, (125, 275, 45, 24), wx.CONTROL_ISDEFAULT) + render.DrawPushButton(self, dc, (180, 275, 45, 24), wx.CONTROL_CURRENT | wx.CONTROL_DISABLED) + + # DrawTreeItemButton + ti_lbl = "DrawTreeItemButton:" + dc.DrawText(ti_lbl, 15, 330) + render.DrawTreeItemButton(self, dc, (15, 350, 16, 16)) + render.DrawTreeItemButton(self, dc, (45, 350, 16, 16), wx.CONTROL_EXPANDED) + + # DrawComboBox + dc.DrawText("DrawComboBox:", 270, 185) + render.DrawComboBox(self, dc, (270, 205, 100, 21)) + render.DrawComboBox(self, dc, (270, 230, 100, 21), wx.CONTROL_DISABLED) + render.DrawComboBox(self, dc, (270, 255, 100, 21), wx.CONTROL_CURRENT) + render.DrawComboBox(self, dc, (270, 280, 100, 21), wx.CONTROL_PRESSED | wx.CONTROL_SELECTED) + render.DrawComboBox(self, dc, (270, 305, 100, 21), wx.CONTROL_FOCUSED) + + # DrawChoice + dc.DrawText("DrawChoice:", 400, 185) + render.DrawChoice(self, dc, (400, 205, 100, 21)) + render.DrawChoice(self, dc, (400, 230, 100, 21), wx.CONTROL_DISABLED) + render.DrawChoice(self, dc, (400, 255, 100, 21), wx.CONTROL_CURRENT) + render.DrawChoice(self, dc, (400, 280, 100, 21), wx.CONTROL_PRESSED | wx.CONTROL_SELECTED) + render.DrawChoice(self, dc, (400, 305, 100, 21), wx.CONTROL_FOCUSED) + + # DrawTextCtrl + dc.DrawText("DrawTextCtrl:", 270, 350) + render.DrawTextCtrl(self, dc, (270, 375, 100, 21)) + render.DrawTextCtrl(self, dc, (380, 375, 100, 21), wx.CONTROL_FOCUSED) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = """ +

wx.RendererNative

+

wx.RendererNative is a class which virtualizes drawing. It abstracts the +operations of drawing controls and allows you to draw say, a button, without +caring about exactly how it is done, in a native and platform independant way. +

+ +

All drawing functions take some standard parameters:

+

    +
  • win: is the window being drawn.
  • +
  • dc: is the wxDC to draw on. Only this device context should be used + for drawing.
  • +
  • rect: The bounding rectangle for the element to be drawn.
  • +
  • flags: The optional flags (none by default) which can be a + combination of the wx.CONTROL_XXX constants.
  • +
+ +

Note: Each drawing function restores the wxDC attributes if it +changes them, so it is safe to assume that the same pen, brush and colours +that were active before the call to this function are still in effect +after it.

+ +""" + +#---------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/ResizeWidget.py b/demo/ResizeWidget.py new file mode 100644 index 00000000..2f824230 --- /dev/null +++ b/demo/ResizeWidget.py @@ -0,0 +1,76 @@ + +import wx +import wx.lib.resizewidget as rw + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + rw1 = rw.ResizeWidget(self) + rw2 = rw.ResizeWidget(self) + self.rw2 = rw2 + + # This one we will reparent to the ResizeWidget... + tst = wx.Panel(self) + tst.SetBackgroundColour('pink') + wx.StaticText(tst, -1, "a panel,\nwith limits") + tst.SetMinSize((80,35)) + tst.SetMaxSize((200,100)) + rw1.SetManagedChild(tst) + + # This one we will create as a child of the resizer to start with + lb = wx.ListBox(rw2, size=(100,70), + choices="zero one two three four five six seven eight nine".split()) + + # now make a sizer with a bunch of other widgets + fgs = wx.FlexGridSizer(cols=4, vgap=5, hgap=5) + for i in range(16): + if i == 5: + fgs.Add(rw1) + elif i == 10: + fgs.Add(rw2) + else: + fgs.Add(wx.Button(self)) + + self.Bind(wx.EVT_BUTTON, self.OnButton) + + self.Sizer = wx.BoxSizer() + self.Sizer.Add(fgs, 0, wx.ALL, 10) + + self.Bind(rw.EVT_RW_LAYOUT_NEEDED, self.OnLayoutNeeded) + + + def OnLayoutNeeded(self, evt): + self.Layout() + + + def OnButton(self, evt): + self.rw2.EnableResize(not self.rw2.IsResizeEnabled()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

ResizeWidget

+

%s

+ +""" % rw.__doc__ + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/RichTextCtrl.py b/demo/RichTextCtrl.py new file mode 100644 index 00000000..d5bc40d1 --- /dev/null +++ b/demo/RichTextCtrl.py @@ -0,0 +1,730 @@ + +import wx +import wx.richtext as rt +import images + +#---------------------------------------------------------------------- + +class RichTextFrame(wx.Frame): + def __init__(self, *args, **kw): + wx.Frame.__init__(self, *args, **kw) + + self.MakeMenuBar() + self.MakeToolBar() + self.CreateStatusBar() + self.SetStatusText("Welcome to wx.richtext.RichTextCtrl!") + + self.rtc = rt.RichTextCtrl(self, style=wx.VSCROLL|wx.HSCROLL|wx.NO_BORDER); + wx.CallAfter(self.rtc.SetFocus) + + self.rtc.Freeze() + self.rtc.BeginSuppressUndo() + + self.rtc.BeginParagraphSpacing(0, 20) + + self.rtc.BeginAlignment(wx.TEXT_ALIGNMENT_CENTRE) + self.rtc.BeginBold() + + self.rtc.BeginFontSize(14) + self.rtc.WriteText("Welcome to wxRichTextCtrl, a wxWidgets control for editing and presenting styled text and images") + self.rtc.EndFontSize() + self.rtc.Newline() + + self.rtc.BeginItalic() + self.rtc.WriteText("by Julian Smart") + self.rtc.EndItalic() + + self.rtc.EndBold() + + self.rtc.Newline() + self.rtc.WriteImage(images._rt_zebra.GetImage()) + + self.rtc.EndAlignment() + + self.rtc.Newline() + self.rtc.Newline() + + self.rtc.WriteText("What can you do with this thing? ") + self.rtc.WriteImage(images._rt_smiley.GetImage()) + self.rtc.WriteText(" Well, you can change text ") + + self.rtc.BeginTextColour((255, 0, 0)) + self.rtc.WriteText("colour, like this red bit.") + self.rtc.EndTextColour() + + self.rtc.BeginTextColour((0, 0, 255)) + self.rtc.WriteText(" And this blue bit.") + self.rtc.EndTextColour() + + self.rtc.WriteText(" Naturally you can make things ") + self.rtc.BeginBold() + self.rtc.WriteText("bold ") + self.rtc.EndBold() + self.rtc.BeginItalic() + self.rtc.WriteText("or italic ") + self.rtc.EndItalic() + self.rtc.BeginUnderline() + self.rtc.WriteText("or underlined.") + self.rtc.EndUnderline() + + self.rtc.BeginFontSize(14) + self.rtc.WriteText(" Different font sizes on the same line is allowed, too.") + self.rtc.EndFontSize() + + self.rtc.WriteText(" Next we'll show an indented paragraph.") + + self.rtc.BeginLeftIndent(60) + self.rtc.Newline() + + self.rtc.WriteText("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable.") + self.rtc.EndLeftIndent() + + self.rtc.Newline() + + self.rtc.WriteText("Next, we'll show a first-line indent, achieved using BeginLeftIndent(100, -40).") + + self.rtc.BeginLeftIndent(100, -40) + self.rtc.Newline() + + self.rtc.WriteText("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable.") + self.rtc.EndLeftIndent() + + self.rtc.Newline() + + self.rtc.WriteText("Numbered bullets are possible, again using sub-indents:") + + self.rtc.BeginNumberedBullet(1, 100, 60) + self.rtc.Newline() + + self.rtc.WriteText("This is my first item. Note that wxRichTextCtrl doesn't automatically do numbering, but this will be added later.") + self.rtc.EndNumberedBullet() + + self.rtc.BeginNumberedBullet(2, 100, 60) + self.rtc.Newline() + + self.rtc.WriteText("This is my second item.") + self.rtc.EndNumberedBullet() + + self.rtc.Newline() + + self.rtc.WriteText("The following paragraph is right-indented:") + + self.rtc.BeginRightIndent(200) + self.rtc.Newline() + + self.rtc.WriteText("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable.") + self.rtc.EndRightIndent() + + self.rtc.Newline() + + self.rtc.WriteText("The following paragraph is right-aligned with 1.5 line spacing:") + + self.rtc.BeginAlignment(wx.TEXT_ALIGNMENT_RIGHT) + self.rtc.BeginLineSpacing(wx.TEXT_ATTR_LINE_SPACING_HALF) + self.rtc.Newline() + + self.rtc.WriteText("It was in January, the most down-trodden month of an Edinburgh winter. An attractive woman came into the cafe, which is nothing remarkable.") + self.rtc.EndLineSpacing() + self.rtc.EndAlignment() + + self.rtc.Newline() + self.rtc.WriteText("Other notable features of wxRichTextCtrl include:") + + self.rtc.BeginSymbolBullet('*', 100, 60) + self.rtc.Newline() + self.rtc.WriteText("Compatibility with wxTextCtrl API") + self.rtc.EndSymbolBullet() + + self.rtc.BeginSymbolBullet('*', 100, 60) + self.rtc.Newline() + self.rtc.WriteText("Easy stack-based BeginXXX()...EndXXX() style setting in addition to SetStyle()") + self.rtc.EndSymbolBullet() + + self.rtc.BeginSymbolBullet('*', 100, 60) + self.rtc.Newline() + self.rtc.WriteText("XML loading and saving") + self.rtc.EndSymbolBullet() + + self.rtc.BeginSymbolBullet('*', 100, 60) + self.rtc.Newline() + self.rtc.WriteText("Undo/Redo, with batching option and Undo suppressing") + self.rtc.EndSymbolBullet() + + self.rtc.BeginSymbolBullet('*', 100, 60) + self.rtc.Newline() + self.rtc.WriteText("Clipboard copy and paste") + self.rtc.EndSymbolBullet() + + self.rtc.BeginSymbolBullet('*', 100, 60) + self.rtc.Newline() + self.rtc.WriteText("wxRichTextStyleSheet with named character and paragraph styles, and control for applying named styles") + self.rtc.EndSymbolBullet() + + self.rtc.BeginSymbolBullet('*', 100, 60) + self.rtc.Newline() + self.rtc.WriteText("A design that can easily be extended to other content types, ultimately with text boxes, tables, controls, and so on") + self.rtc.EndSymbolBullet() + + self.rtc.Newline() + + self.rtc.WriteText("Note: this sample content was generated programmatically from within the MyFrame constructor in the demo. The images were loaded from inline XPMs. Enjoy wxRichTextCtrl!") + + self.rtc.Newline() + self.rtc.Newline() + self.rtc.BeginFontSize(12) + self.rtc.BeginBold() + self.rtc.WriteText("Additional comments by David Woods:") + self.rtc.EndBold() + self.rtc.EndFontSize() + self.rtc.Newline() + self.rtc.WriteText("I find some of the RichTextCtrl method names, as used above, to be misleading. Some character styles are stacked in the RichTextCtrl, and they are removed in the reverse order from how they are added, regardless of the method called. Allow me to demonstrate what I mean.") + self.rtc.Newline() + + self.rtc.WriteText('Start with plain text. ') + self.rtc.BeginBold() + self.rtc.WriteText('BeginBold() makes it bold. ') + self.rtc.BeginItalic() + self.rtc.WriteText('BeginItalic() makes it bold-italic. ') + self.rtc.EndBold() + self.rtc.WriteText('EndBold() should make it italic but instead makes it bold. ') + self.rtc.EndItalic() + self.rtc.WriteText('EndItalic() takes us back to plain text. ') + self.rtc.Newline() + + self.rtc.WriteText('Start with plain text. ') + self.rtc.BeginBold() + self.rtc.WriteText('BeginBold() makes it bold. ') + self.rtc.BeginUnderline() + self.rtc.WriteText('BeginUnderline() makes it bold-underline. ') + self.rtc.EndBold() + self.rtc.WriteText('EndBold() should make it underline but instead makes it bold. ') + self.rtc.EndUnderline() + self.rtc.WriteText('EndUnderline() takes us back to plain text. ') + self.rtc.Newline() + + self.rtc.WriteText('According to Julian, this functions "as expected" because of the way the RichTextCtrl is written. I wrote the SetFontStyle() method here to demonstrate a way to work with overlapping styles that solves this problem.') + self.rtc.Newline() + + # Create and initialize text attributes + self.textAttr = rt.RichTextAttr() + self.SetFontStyle(fontColor=wx.Colour(0, 0, 0), fontBgColor=wx.Colour(255, 255, 255), fontFace='Times New Roman', fontSize=10, fontBold=False, fontItalic=False, fontUnderline=False) + self.rtc.WriteText('Start with plain text. ') + self.SetFontStyle(fontBold=True) + self.rtc.WriteText('Bold. ') + self.SetFontStyle(fontItalic=True) + self.rtc.WriteText('Bold-italic. ') + self.SetFontStyle(fontBold=False) + self.rtc.WriteText('Italic. ') + self.SetFontStyle(fontItalic=False) + self.rtc.WriteText('Back to plain text. ') + self.rtc.Newline() + + self.rtc.WriteText('Start with plain text. ') + self.SetFontStyle(fontBold=True) + self.rtc.WriteText('Bold. ') + self.SetFontStyle(fontUnderline=True) + self.rtc.WriteText('Bold-Underline. ') + self.SetFontStyle(fontBold=False) + self.rtc.WriteText('Underline. ') + self.SetFontStyle(fontUnderline=False) + self.rtc.WriteText('Back to plain text. ') + self.rtc.Newline() + self.rtc.EndParagraphSpacing() + + self.rtc.EndSuppressUndo() + self.rtc.Thaw() + + + def SetFontStyle(self, fontColor = None, fontBgColor = None, fontFace = None, fontSize = None, + fontBold = None, fontItalic = None, fontUnderline = None): + if fontColor: + self.textAttr.SetTextColour(fontColor) + if fontBgColor: + self.textAttr.SetBackgroundColour(fontBgColor) + if fontFace: + self.textAttr.SetFontFaceName(fontFace) + if fontSize: + self.textAttr.SetFontSize(fontSize) + if fontBold != None: + if fontBold: + self.textAttr.SetFontWeight(wx.FONTWEIGHT_BOLD) + else: + self.textAttr.SetFontWeight(wx.FONTWEIGHT_NORMAL) + if fontItalic != None: + if fontItalic: + self.textAttr.SetFontStyle(wx.FONTSTYLE_ITALIC) + else: + self.textAttr.SetFontStyle(wx.FONTSTYLE_NORMAL) + if fontUnderline != None: + if fontUnderline: + self.textAttr.SetFontUnderlined(True) + else: + self.textAttr.SetFontUnderlined(False) + self.rtc.SetDefaultStyle(self.textAttr) + + def OnURL(self, evt): + wx.MessageBox(evt.GetString(), "URL Clicked") + + + def OnFileOpen(self, evt): + # This gives us a string suitable for the file dialog based on + # the file handlers that are loaded + wildcard, types = rt.RichTextBuffer.GetExtWildcard(save=False) + dlg = wx.FileDialog(self, "Choose a filename", + wildcard=wildcard, + style=wx.OPEN) + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + if path: + fileType = types[dlg.GetFilterIndex()] + self.rtc.LoadFile(path, fileType) + dlg.Destroy() + + + def OnFileSave(self, evt): + if not self.rtc.GetFilename(): + self.OnFileSaveAs(evt) + return + self.rtc.SaveFile() + + + def OnFileSaveAs(self, evt): + wildcard, types = rt.RichTextBuffer.GetExtWildcard(save=True) + + dlg = wx.FileDialog(self, "Choose a filename", + wildcard=wildcard, + style=wx.SAVE) + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + if path: + fileType = types[dlg.GetFilterIndex()] + ext = rt.RichTextBuffer.FindHandlerByType(fileType).GetExtension() + if not path.endswith(ext): + path += '.' + ext + self.rtc.SaveFile(path, fileType) + dlg.Destroy() + + + def OnFileViewHTML(self, evt): + # Get an instance of the html file handler, use it to save the + # document to a StringIO stream, and then display the + # resulting html text in a dialog with a HtmlWindow. + handler = rt.RichTextHTMLHandler() + handler.SetFlags(rt.RICHTEXT_HANDLER_SAVE_IMAGES_TO_MEMORY) + handler.SetFontSizeMapping([7,9,11,12,14,22,100]) + + import cStringIO + stream = cStringIO.StringIO() + if not handler.SaveStream(self.rtc.GetBuffer(), stream): + return + + import wx.html + dlg = wx.Dialog(self, title="HTML", style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) + html = wx.html.HtmlWindow(dlg, size=(500,400), style=wx.BORDER_SUNKEN) + html.SetPage(stream.getvalue()) + btn = wx.Button(dlg, wx.ID_CANCEL) + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(html, 1, wx.ALL|wx.EXPAND, 5) + sizer.Add(btn, 0, wx.ALL|wx.CENTER, 10) + dlg.SetSizer(sizer) + sizer.Fit(dlg) + + dlg.ShowModal() + + handler.DeleteTemporaryImages() + + + + def OnFileExit(self, evt): + self.Close(True) + + + def OnBold(self, evt): + self.rtc.ApplyBoldToSelection() + + def OnItalic(self, evt): + self.rtc.ApplyItalicToSelection() + + def OnUnderline(self, evt): + self.rtc.ApplyUnderlineToSelection() + + def OnAlignLeft(self, evt): + self.rtc.ApplyAlignmentToSelection(wx.TEXT_ALIGNMENT_LEFT) + + def OnAlignRight(self, evt): + self.rtc.ApplyAlignmentToSelection(wx.TEXT_ALIGNMENT_RIGHT) + + def OnAlignCenter(self, evt): + self.rtc.ApplyAlignmentToSelection(wx.TEXT_ALIGNMENT_CENTRE) + + def OnIndentMore(self, evt): + attr = wx.TextAttr() + attr.SetFlags(wx.TEXT_ATTR_LEFT_INDENT) + ip = self.rtc.GetInsertionPoint() + if self.rtc.GetStyle(ip, attr): + r = rt.RichTextRange(ip, ip) + if self.rtc.HasSelection(): + r = self.rtc.GetSelectionRange() + + attr.SetLeftIndent(attr.GetLeftIndent() + 100) + attr.SetFlags(wx.TEXT_ATTR_LEFT_INDENT) + self.rtc.SetStyle(r, attr) + + + def OnIndentLess(self, evt): + attr = wx.TextAttr() + attr.SetFlags(wx.TEXT_ATTR_LEFT_INDENT) + ip = self.rtc.GetInsertionPoint() + if self.rtc.GetStyle(ip, attr): + r = rt.RichTextRange(ip, ip) + if self.rtc.HasSelection(): + r = self.rtc.GetSelectionRange() + + if attr.GetLeftIndent() >= 100: + attr.SetLeftIndent(attr.GetLeftIndent() - 100) + attr.SetFlags(wx.TEXT_ATTR_LEFT_INDENT) + self.rtc.SetStyle(r, attr) + + + def OnParagraphSpacingMore(self, evt): + attr = wx.TextAttr() + attr.SetFlags(wx.TEXT_ATTR_PARA_SPACING_AFTER) + ip = self.rtc.GetInsertionPoint() + if self.rtc.GetStyle(ip, attr): + r = rt.RichTextRange(ip, ip) + if self.rtc.HasSelection(): + r = self.rtc.GetSelectionRange() + + attr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter() + 20); + attr.SetFlags(wx.TEXT_ATTR_PARA_SPACING_AFTER) + self.rtc.SetStyle(r, attr) + + + def OnParagraphSpacingLess(self, evt): + attr = wx.TextAttr() + attr.SetFlags(wx.TEXT_ATTR_PARA_SPACING_AFTER) + ip = self.rtc.GetInsertionPoint() + if self.rtc.GetStyle(ip, attr): + r = rt.RichTextRange(ip, ip) + if self.rtc.HasSelection(): + r = self.rtc.GetSelectionRange() + + if attr.GetParagraphSpacingAfter() >= 20: + attr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter() - 20); + attr.SetFlags(wx.TEXT_ATTR_PARA_SPACING_AFTER) + self.rtc.SetStyle(r, attr) + + + def OnLineSpacingSingle(self, evt): + attr = wx.TextAttr() + attr.SetFlags(wx.TEXT_ATTR_LINE_SPACING) + ip = self.rtc.GetInsertionPoint() + if self.rtc.GetStyle(ip, attr): + r = rt.RichTextRange(ip, ip) + if self.rtc.HasSelection(): + r = self.rtc.GetSelectionRange() + + attr.SetFlags(wx.TEXT_ATTR_LINE_SPACING) + attr.SetLineSpacing(10) + self.rtc.SetStyle(r, attr) + + + def OnLineSpacingHalf(self, evt): + attr = wx.TextAttr() + attr.SetFlags(wx.TEXT_ATTR_LINE_SPACING) + ip = self.rtc.GetInsertionPoint() + if self.rtc.GetStyle(ip, attr): + r = rt.RichTextRange(ip, ip) + if self.rtc.HasSelection(): + r = self.rtc.GetSelectionRange() + + attr.SetFlags(wx.TEXT_ATTR_LINE_SPACING) + attr.SetLineSpacing(15) + self.rtc.SetStyle(r, attr) + + + def OnLineSpacingDouble(self, evt): + attr = wx.TextAttr() + attr.SetFlags(wx.TEXT_ATTR_LINE_SPACING) + ip = self.rtc.GetInsertionPoint() + if self.rtc.GetStyle(ip, attr): + r = rt.RichTextRange(ip, ip) + if self.rtc.HasSelection(): + r = self.rtc.GetSelectionRange() + + attr.SetFlags(wx.TEXT_ATTR_LINE_SPACING) + attr.SetLineSpacing(20) + self.rtc.SetStyle(r, attr) + + + def OnFont(self, evt): + if not self.rtc.HasSelection(): + return + + r = self.rtc.GetSelectionRange() + fontData = wx.FontData() + fontData.EnableEffects(False) + attr = wx.TextAttr() + attr.SetFlags(wx.TEXT_ATTR_FONT) + if self.rtc.GetStyle(self.rtc.GetInsertionPoint(), attr): + fontData.SetInitialFont(attr.GetFont()) + + dlg = wx.FontDialog(self, fontData) + if dlg.ShowModal() == wx.ID_OK: + fontData = dlg.GetFontData() + font = fontData.GetChosenFont() + if font: + attr.SetFlags(wx.TEXT_ATTR_FONT) + attr.SetFont(font) + self.rtc.SetStyle(r, attr) + dlg.Destroy() + + + def OnColour(self, evt): + colourData = wx.ColourData() + attr = wx.TextAttr() + attr.SetFlags(wx.TEXT_ATTR_TEXT_COLOUR) + if self.rtc.GetStyle(self.rtc.GetInsertionPoint(), attr): + colourData.SetColour(attr.GetTextColour()) + + dlg = wx.ColourDialog(self, colourData) + if dlg.ShowModal() == wx.ID_OK: + colourData = dlg.GetColourData() + colour = colourData.GetColour() + if colour: + if not self.rtc.HasSelection(): + self.rtc.BeginTextColour(colour) + else: + r = self.rtc.GetSelectionRange() + attr.SetFlags(wx.TEXT_ATTR_TEXT_COLOUR) + attr.SetTextColour(colour) + self.rtc.SetStyle(r, attr) + dlg.Destroy() + + + + def OnUpdateBold(self, evt): + evt.Check(self.rtc.IsSelectionBold()) + + def OnUpdateItalic(self, evt): + evt.Check(self.rtc.IsSelectionItalics()) + + def OnUpdateUnderline(self, evt): + evt.Check(self.rtc.IsSelectionUnderlined()) + + def OnUpdateAlignLeft(self, evt): + evt.Check(self.rtc.IsSelectionAligned(wx.TEXT_ALIGNMENT_LEFT)) + + def OnUpdateAlignCenter(self, evt): + evt.Check(self.rtc.IsSelectionAligned(wx.TEXT_ALIGNMENT_CENTRE)) + + def OnUpdateAlignRight(self, evt): + evt.Check(self.rtc.IsSelectionAligned(wx.TEXT_ALIGNMENT_RIGHT)) + + + def ForwardEvent(self, evt): + # The RichTextCtrl can handle menu and update events for undo, + # redo, cut, copy, paste, delete, and select all, so just + # forward the event to it. + self.rtc.ProcessEvent(evt) + + + def MakeMenuBar(self): + def doBind(item, handler, updateUI=None): + self.Bind(wx.EVT_MENU, handler, item) + if updateUI is not None: + self.Bind(wx.EVT_UPDATE_UI, updateUI, item) + + fileMenu = wx.Menu() + doBind( fileMenu.Append(-1, "&Open\tCtrl+O", "Open a file"), + self.OnFileOpen ) + doBind( fileMenu.Append(-1, "&Save\tCtrl+S", "Save a file"), + self.OnFileSave ) + doBind( fileMenu.Append(-1, "&Save As...\tF12", "Save to a new file"), + self.OnFileSaveAs ) + fileMenu.AppendSeparator() + doBind( fileMenu.Append(-1, "&View as HTML", "View HTML"), + self.OnFileViewHTML) + fileMenu.AppendSeparator() + doBind( fileMenu.Append(-1, "E&xit\tCtrl+Q", "Quit this program"), + self.OnFileExit ) + + editMenu = wx.Menu() + doBind( editMenu.Append(wx.ID_UNDO, "&Undo\tCtrl+Z"), + self.ForwardEvent, self.ForwardEvent) + doBind( editMenu.Append(wx.ID_REDO, "&Redo\tCtrl+Y"), + self.ForwardEvent, self.ForwardEvent ) + editMenu.AppendSeparator() + doBind( editMenu.Append(wx.ID_CUT, "Cu&t\tCtrl+X"), + self.ForwardEvent, self.ForwardEvent ) + doBind( editMenu.Append(wx.ID_COPY, "&Copy\tCtrl+C"), + self.ForwardEvent, self.ForwardEvent) + doBind( editMenu.Append(wx.ID_PASTE, "&Paste\tCtrl+V"), + self.ForwardEvent, self.ForwardEvent) + doBind( editMenu.Append(wx.ID_CLEAR, "&Delete\tDel"), + self.ForwardEvent, self.ForwardEvent) + editMenu.AppendSeparator() + doBind( editMenu.Append(wx.ID_SELECTALL, "Select A&ll\tCtrl+A"), + self.ForwardEvent, self.ForwardEvent ) + + #doBind( editMenu.AppendSeparator(), ) + #doBind( editMenu.Append(-1, "&Find...\tCtrl+F"), ) + #doBind( editMenu.Append(-1, "&Replace...\tCtrl+R"), ) + + formatMenu = wx.Menu() + doBind( formatMenu.AppendCheckItem(-1, "&Bold\tCtrl+B"), + self.OnBold, self.OnUpdateBold) + doBind( formatMenu.AppendCheckItem(-1, "&Italic\tCtrl+I"), + self.OnItalic, self.OnUpdateItalic) + doBind( formatMenu.AppendCheckItem(-1, "&Underline\tCtrl+U"), + self.OnUnderline, self.OnUpdateUnderline) + formatMenu.AppendSeparator() + doBind( formatMenu.AppendCheckItem(-1, "L&eft Align"), + self.OnAlignLeft, self.OnUpdateAlignLeft) + doBind( formatMenu.AppendCheckItem(-1, "&Centre"), + self.OnAlignCenter, self.OnUpdateAlignCenter) + doBind( formatMenu.AppendCheckItem(-1, "&Right Align"), + self.OnAlignRight, self.OnUpdateAlignRight) + formatMenu.AppendSeparator() + doBind( formatMenu.Append(-1, "Indent &More"), self.OnIndentMore) + doBind( formatMenu.Append(-1, "Indent &Less"), self.OnIndentLess) + formatMenu.AppendSeparator() + doBind( formatMenu.Append(-1, "Increase Paragraph &Spacing"), self.OnParagraphSpacingMore) + doBind( formatMenu.Append(-1, "Decrease &Paragraph Spacing"), self.OnParagraphSpacingLess) + formatMenu.AppendSeparator() + doBind( formatMenu.Append(-1, "Normal Line Spacing"), self.OnLineSpacingSingle) + doBind( formatMenu.Append(-1, "1.5 Line Spacing"), self.OnLineSpacingHalf) + doBind( formatMenu.Append(-1, "Double Line Spacing"), self.OnLineSpacingDouble) + formatMenu.AppendSeparator() + doBind( formatMenu.Append(-1, "&Font..."), self.OnFont) + + mb = wx.MenuBar() + mb.Append(fileMenu, "&File") + mb.Append(editMenu, "&Edit") + mb.Append(formatMenu, "F&ormat") + self.SetMenuBar(mb) + + + def MakeToolBar(self): + def doBind(item, handler, updateUI=None): + self.Bind(wx.EVT_TOOL, handler, item) + if updateUI is not None: + self.Bind(wx.EVT_UPDATE_UI, updateUI, item) + + tbar = self.CreateToolBar() + doBind( tbar.AddTool(-1, images._rt_open.GetBitmap(), + shortHelpString="Open"), self.OnFileOpen) + doBind( tbar.AddTool(-1, images._rt_save.GetBitmap(), + shortHelpString="Save"), self.OnFileSave) + tbar.AddSeparator() + doBind( tbar.AddTool(wx.ID_CUT, images._rt_cut.GetBitmap(), + shortHelpString="Cut"), self.ForwardEvent, self.ForwardEvent) + doBind( tbar.AddTool(wx.ID_COPY, images._rt_copy.GetBitmap(), + shortHelpString="Copy"), self.ForwardEvent, self.ForwardEvent) + doBind( tbar.AddTool(wx.ID_PASTE, images._rt_paste.GetBitmap(), + shortHelpString="Paste"), self.ForwardEvent, self.ForwardEvent) + tbar.AddSeparator() + doBind( tbar.AddTool(wx.ID_UNDO, images._rt_undo.GetBitmap(), + shortHelpString="Undo"), self.ForwardEvent, self.ForwardEvent) + doBind( tbar.AddTool(wx.ID_REDO, images._rt_redo.GetBitmap(), + shortHelpString="Redo"), self.ForwardEvent, self.ForwardEvent) + tbar.AddSeparator() + doBind( tbar.AddTool(-1, images._rt_bold.GetBitmap(), isToggle=True, + shortHelpString="Bold"), self.OnBold, self.OnUpdateBold) + doBind( tbar.AddTool(-1, images._rt_italic.GetBitmap(), isToggle=True, + shortHelpString="Italic"), self.OnItalic, self.OnUpdateItalic) + doBind( tbar.AddTool(-1, images._rt_underline.GetBitmap(), isToggle=True, + shortHelpString="Underline"), self.OnUnderline, self.OnUpdateUnderline) + tbar.AddSeparator() + doBind( tbar.AddTool(-1, images._rt_alignleft.GetBitmap(), isToggle=True, + shortHelpString="Align Left"), self.OnAlignLeft, self.OnUpdateAlignLeft) + doBind( tbar.AddTool(-1, images._rt_centre.GetBitmap(), isToggle=True, + shortHelpString="Center"), self.OnAlignCenter, self.OnUpdateAlignCenter) + doBind( tbar.AddTool(-1, images._rt_alignright.GetBitmap(), isToggle=True, + shortHelpString="Align Right"), self.OnAlignRight, self.OnUpdateAlignRight) + tbar.AddSeparator() + doBind( tbar.AddTool(-1, images._rt_indentless.GetBitmap(), + shortHelpString="Indent Less"), self.OnIndentLess) + doBind( tbar.AddTool(-1, images._rt_indentmore.GetBitmap(), + shortHelpString="Indent More"), self.OnIndentMore) + tbar.AddSeparator() + doBind( tbar.AddTool(-1, images._rt_font.GetBitmap(), + shortHelpString="Font"), self.OnFont) + doBind( tbar.AddTool(-1, images._rt_colour.GetBitmap(), + shortHelpString="Font Colour"), self.OnColour) + + tbar.Realize() + + + +#---------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show the RichTextCtrl sample", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + self.AddRTCHandlers() + + + def AddRTCHandlers(self): + # make sure we haven't already added them. + if rt.RichTextBuffer.FindHandlerByType(rt.RICHTEXT_TYPE_HTML) is not None: + return + + # This would normally go in your app's OnInit method. I'm + # not sure why these file handlers are not loaded by + # default by the C++ richtext code, I guess it's so you + # can change the name or extension if you wanted... + rt.RichTextBuffer.AddHandler(rt.RichTextHTMLHandler()) + rt.RichTextBuffer.AddHandler(rt.RichTextXMLHandler()) + + # ...like this + rt.RichTextBuffer.AddHandler(rt.RichTextXMLHandler(name="Other XML", + ext="ox", + type=99)) + + # This is needed for the view as HTML option since we tell it + # to store the images in the memory file system. + wx.FileSystem.AddHandler(wx.MemoryFSHandler()) + + + def OnButton(self, evt): + win = RichTextFrame(self, -1, "wx.richtext.RichTextCtrl", + size=(700, 500), + style = wx.DEFAULT_FRAME_STYLE) + win.Show(True) + + # give easy access to the demo's PyShell if it's running + self.rtfrm = win + self.rtc = win.rtc + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.richtext.RichTextCtrl

+ + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/RightTextCtrl.py b/demo/RightTextCtrl.py new file mode 100644 index 00000000..c24da5c1 --- /dev/null +++ b/demo/RightTextCtrl.py @@ -0,0 +1,62 @@ +#####################################################################\ +# Note: This control is deprecated because wx.TextCtrl now supports | +# the wx.TE_RIGHT style flag, which makes this control completely | +# superfluous. | +#####################################################################/ + +import wx +import wx.lib.rightalign as right + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, -1) + + fgs = wx.FlexGridSizer(cols=2, vgap=5, hgap=5) + + txt = wx.StaticText( + self, -1, + "These text controls will align their contents to\n" + "the right (on wxMSW) when they don't have focus.", + style=wx.ALIGN_RIGHT + ) + + fgs.Add(txt) + fgs.Add(right.RightTextCtrl(self, -1, "", size=(75, -1))) + + fgs.Add((10,10)) + fgs.Add(right.RightTextCtrl(self, -1, "123.45", size=(75, -1))) + + fgs.Add((10,10)) + fgs.Add(right.RightTextCtrl(self, -1, "234.56", size=(75, -1))) + + fgs.Add((10,10)) + fgs.Add(right.RightTextCtrl(self, -1, "345.67", size=(75, -1))) + + fgs.Add((10,10)) + fgs.Add(right.RightTextCtrl(self, -1, "456.78", size=(75, -1))) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(fgs, 0, wx.ALL, 25) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb) + return win + +#---------------------------------------------------------------------- + +overview = right.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/RowColSizer.py b/demo/RowColSizer.py new file mode 100644 index 00000000..d1fb3f56 --- /dev/null +++ b/demo/RowColSizer.py @@ -0,0 +1,92 @@ + +import wx +import wx.lib.rcsizer as rcs + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, -1) + + sizer = rcs.RowColSizer() + + text = "This sizer lays out it's items by row and column "\ + "that are specified explicitly when the item is \n"\ + "added to the sizer. Grid cells with nothing in "\ + "them are supported and column- or row-spanning is \n"\ + "handled as well. Growable rows and columns are "\ + "specified just like the wxFlexGridSizer." + + sizer.Add(wx.StaticText(self, -1, text), row=1, col=1, colspan=5) + + sizer.Add(wx.TextCtrl(self, -1, "(3,1)"), flag=wx.EXPAND, row=3, col=1) + sizer.Add(wx.TextCtrl(self, -1, "(3,2)"), row=3, col=2) + sizer.Add(wx.TextCtrl(self, -1, "(3,3)"), row=3, col=3) + sizer.Add(wx.TextCtrl(self, -1, "(3,4)"), row=3, col=4) + sizer.Add( + wx.TextCtrl(self, -1, "(4,2) span:(2,2)"), + flag=wx.EXPAND, row=4, col=2, rowspan=2, colspan=2 + ) + + sizer.Add(wx.TextCtrl(self, -1, "(6,4)"), row=6, col=4) + sizer.Add(wx.TextCtrl(self, -1, "(7,2)"), row=7, col=2) + sizer.Add(wx.TextCtrl(self, -1, "(8,3)"), row=8, col=3) + sizer.Add( + wx.TextCtrl(self, -1, "(10,1) colspan: 4"), + flag=wx.EXPAND, pos=(10,1), colspan=4 + ) + + sizer.Add( + wx.TextCtrl(self, -1, "(3,5) rowspan: 8, growable col", style=wx.TE_MULTILINE), + flag=wx.EXPAND, pos=(3,5), size=(8,1) + ) + + box = wx.BoxSizer(wx.VERTICAL) + box.Add(wx.Button(self, -1, "A vertical box"), flag=wx.EXPAND) + box.Add(wx.Button(self, -1, "sizer put in the"), flag=wx.EXPAND) + box.Add(wx.Button(self, -1, "RowColSizer at (12,1)"), flag=wx.EXPAND) + sizer.Add(box, pos=(12,1)) + + sizer.Add( + wx.TextCtrl(self, -1, "(12,2) align bottom"), + flag=wx.ALIGN_BOTTOM, pos=(12,2) + ) + + sizer.Add( + wx.TextCtrl(self, -1, "(12,3) align center"), + flag=wx.ALIGN_CENTER_VERTICAL, pos=(12,3) + ) + + sizer.Add(wx.TextCtrl(self, -1, "(12,4)"),pos=(12,4)) + sizer.Add( + wx.TextCtrl(self, -1, "(12,5) full border"), + flag=wx.EXPAND|wx.ALL, border=15, pos=(12,5) + ) + + sizer.AddGrowableCol(5) + sizer.AddGrowableRow(9) + + sizer.AddSpacer(10,10, pos=(1,6)) + sizer.AddSpacer(10,10, pos=(13,1)) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb) + return win + + +#---------------------------------------------------------------------- + + +overview = rcs.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/SashWindow.py b/demo/SashWindow.py new file mode 100644 index 00000000..72b6357c --- /dev/null +++ b/demo/SashWindow.py @@ -0,0 +1,149 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestSashWindow(wx.Panel): + + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + + self.log = log + winids = [] + + # Create some layout windows + # A window like a toolbar + topwin = wx.SashLayoutWindow( + self, -1, wx.DefaultPosition, (200, 30), + wx.NO_BORDER|wx.SW_3D + ) + + topwin.SetDefaultSize((1000, 30)) + topwin.SetOrientation(wx.LAYOUT_HORIZONTAL) + topwin.SetAlignment(wx.LAYOUT_TOP) + topwin.SetBackgroundColour(wx.Colour(255, 0, 0)) + topwin.SetSashVisible(wx.SASH_BOTTOM, True) + + self.topWindow = topwin + winids.append(topwin.GetId()) + + # A window like a statusbar + bottomwin = wx.SashLayoutWindow( + self, -1, wx.DefaultPosition, (200, 30), + wx.NO_BORDER|wx.SW_3D + ) + + bottomwin.SetDefaultSize((1000, 30)) + bottomwin.SetOrientation(wx.LAYOUT_HORIZONTAL) + bottomwin.SetAlignment(wx.LAYOUT_BOTTOM) + bottomwin.SetBackgroundColour(wx.Colour(0, 0, 255)) + bottomwin.SetSashVisible(wx.SASH_TOP, True) + + self.bottomWindow = bottomwin + winids.append(bottomwin.GetId()) + + # A window to the left of the client window + leftwin1 = wx.SashLayoutWindow( + self, -1, wx.DefaultPosition, (200, 30), + wx.NO_BORDER|wx.SW_3D + ) + + leftwin1.SetDefaultSize((120, 1000)) + leftwin1.SetOrientation(wx.LAYOUT_VERTICAL) + leftwin1.SetAlignment(wx.LAYOUT_LEFT) + leftwin1.SetBackgroundColour(wx.Colour(0, 255, 0)) + leftwin1.SetSashVisible(wx.SASH_RIGHT, True) + leftwin1.SetExtraBorderSize(10) + textWindow = wx.TextCtrl( + leftwin1, -1, "", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.SUNKEN_BORDER + ) + + textWindow.SetValue("A sub window") + + self.leftWindow1 = leftwin1 + winids.append(leftwin1.GetId()) + + + # Another window to the left of the client window + leftwin2 = wx.SashLayoutWindow( + self, -1, wx.DefaultPosition, (200, 30), + wx.NO_BORDER|wx.SW_3D + ) + + leftwin2.SetDefaultSize((120, 1000)) + leftwin2.SetOrientation(wx.LAYOUT_VERTICAL) + leftwin2.SetAlignment(wx.LAYOUT_LEFT) + leftwin2.SetBackgroundColour(wx.Colour(0, 255, 255)) + leftwin2.SetSashVisible(wx.SASH_RIGHT, True) + + self.leftWindow2 = leftwin2 + winids.append(leftwin2.GetId()) + + # will occupy the space not used by the Layout Algorithm + self.remainingSpace = wx.Panel(self, -1, style=wx.SUNKEN_BORDER) + + self.Bind( + wx.EVT_SASH_DRAGGED_RANGE, self.OnSashDrag, + id=min(winids), id2=max(winids) + ) + + self.Bind(wx.EVT_SIZE, self.OnSize) + + + def OnSashDrag(self, event): + if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE: + self.log.write('drag is out of range') + return + + eobj = event.GetEventObject() + + if eobj is self.topWindow: + self.log.write('topwin received drag event') + self.topWindow.SetDefaultSize((1000, event.GetDragRect().height)) + + elif eobj is self.leftWindow1: + self.log.write('leftwin1 received drag event') + self.leftWindow1.SetDefaultSize((event.GetDragRect().width, 1000)) + + + elif eobj is self.leftWindow2: + self.log.write('leftwin2 received drag event') + self.leftWindow2.SetDefaultSize((event.GetDragRect().width, 1000)) + + elif eobj is self.bottomWindow: + self.log.write('bottomwin received drag event') + self.bottomWindow.SetDefaultSize((1000, event.GetDragRect().height)) + + wx.LayoutAlgorithm().LayoutWindow(self, self.remainingSpace) + self.remainingSpace.Refresh() + + def OnSize(self, event): + wx.LayoutAlgorithm().LayoutWindow(self, self.remainingSpace) + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestSashWindow(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ +wx.SashLayoutWindow responds to OnCalculateLayout events generated by +wxLayoutAlgorithm. It allows the application to use simple accessors to +specify how the window should be laid out, rather than having to respond +to events. The fact that the class derives from wx.SashWindow allows sashes +to be used if required, to allow the windows to be user-resizable. + +The documentation for wx.LayoutAlgorithm explains the purpose of this class +in more detail. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/ScrolledMessageDialog.py b/demo/ScrolledMessageDialog.py new file mode 100644 index 00000000..8620a7b1 --- /dev/null +++ b/demo/ScrolledMessageDialog.py @@ -0,0 +1,53 @@ + +import wx +import wx.lib.dialogs + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a ScrolledMessageDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + f = open("Main.py", "r") + msg = f.read() + f.close() + + dlg = wx.lib.dialogs.ScrolledMessageDialog(self, msg, "message test") + dlg.ShowModal() + + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + + +overview = """\ + +ScrolledMessageDialog(parent, msg, caption, pos=wx.DefaultPosition, size=(500,300)) + +This class represents a message dialog that uses a wxTextCtrl to display the +message. This allows more flexible information display without having to be +as much concerned with layout requirements. A text file can simply be used + +This dialog offers no special attributes or methods beyond those supported +by wxDialog. + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/ScrolledPanel.py b/demo/ScrolledPanel.py new file mode 100644 index 00000000..e5226cf7 --- /dev/null +++ b/demo/ScrolledPanel.py @@ -0,0 +1,123 @@ + +import wx +import wx.lib.scrolledpanel as scrolled + +#---------------------------------------------------------------------- + +text = "one two buckle my shoe three four shut the door five six pick up sticks seven eight lay them straight nine ten big fat hen" + + +class TestPanel(scrolled.ScrolledPanel): + def __init__(self, parent, log): + self.log = log + scrolled.ScrolledPanel.__init__(self, parent, -1) + + vbox = wx.BoxSizer(wx.VERTICAL) + desc = wx.StaticText(self, -1, + "ScrolledPanel extends wx.ScrolledWindow, adding all " + "the necessary bits to set up scroll handling for you.\n\n" + "Here are three fixed size examples of its use. The " + "demo panel for this sample is also using it -- the \nwxStaticLine " + "below is intentionally made too long so a scrollbar will be " + "activated." + ) + desc.SetForegroundColour("Blue") + vbox.Add(desc, 0, wx.ALIGN_LEFT|wx.ALL, 5) + vbox.Add(wx.StaticLine(self, -1, size=(1024,-1)), 0, wx.ALL, 5) + vbox.Add((20,20)) + + words = text.split() + + panel1 = scrolled.ScrolledPanel(self, -1, size=(140, 300), + style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER, name="panel1" ) + fgs1 = wx.FlexGridSizer(cols=2, vgap=4, hgap=4) + + for word in words: + label = wx.StaticText(panel1, -1, word+":") + + # A test for scrolling with a too big control + #if word == "three": + # tc = wx.TextCtrl(panel1, -1, word, size=(150,-1)) + #else: + # tc = wx.TextCtrl(panel1, -1, word, size=(50,-1)) + + tc = wx.TextCtrl(panel1, -1, word, size=(50,-1)) + + fgs1.Add(label, flag=wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border=10) + fgs1.Add(tc, flag=wx.RIGHT, border=10) + + panel1.SetSizer( fgs1 ) + panel1.SetAutoLayout(1) + panel1.SetupScrolling() + + panel2 = scrolled.ScrolledPanel(self, -1, size=(350, 50), + style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER, name="panel2") + panel3 = scrolled.ScrolledPanel(self, -1, size=(200,100), + style = wx.TAB_TRAVERSAL|wx.SUNKEN_BORDER, name="panel3") + + fgs2 = wx.FlexGridSizer(cols=25, vgap=4, hgap=4) + fgs3 = wx.FlexGridSizer(cols=5, vgap=4, hgap=4) + + for i in range(len(words)): + word = words[i] + if i % 5 != 4: + label2 = wx.StaticText(panel2, -1, word) + fgs2.Add(label2, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) + label3 = wx.StaticText(panel3, -1, word) + fgs3.Add(label3, flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) + else: + tc2 = wx.TextCtrl(panel2, -1, word, size=(50,-1)) + fgs2.Add(tc2, flag=wx.LEFT, border=5) + tc3 = wx.TextCtrl(panel3, -1, word ) + fgs3.Add(tc3, flag=wx.LEFT, border=5) + + panel2.SetSizer( fgs2 ) + panel2.SetAutoLayout(1) + panel2.SetupScrolling(scroll_y = False) + + panel3.SetSizer( fgs3 ) + panel3.SetAutoLayout(1) + panel3.SetupScrolling() + + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add((20,20)) + hbox.Add(panel1, 0, wx.FIXED_MINSIZE) + hbox.Add((40, 10)) + + vbox2 = wx.BoxSizer(wx.VERTICAL) + vbox2.Add(panel2, 0, wx.FIXED_MINSIZE) + vbox2.Add((20, 50)) + + vbox2.Add(panel3, 0, wx.FIXED_MINSIZE) + vbox2.Add((20, 10)) + hbox.Add(vbox2) + + vbox.Add(hbox, 0) + self.SetSizer(vbox) + self.SetAutoLayout(1) + self.SetupScrolling() + + +#---------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +ScrolledPanel fills a "hole" in the implementation of wx.ScrolledWindow, +providing automatic scrollbar and scrolling behavior and the tab traversal +mangement that wx.ScrolledWindow lacks. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/ScrolledWindow.py b/demo/ScrolledWindow.py new file mode 100644 index 00000000..fcd1d74f --- /dev/null +++ b/demo/ScrolledWindow.py @@ -0,0 +1,260 @@ + +import wx +import images + +# There are two different approaches to drawing, buffered or direct. +# This sample shows both approaches so you can easily compare and +# contrast the two by changing this value. +BUFFERED = 1 + +#--------------------------------------------------------------------------- + +class MyCanvas(wx.ScrolledWindow): + def __init__(self, parent, id = -1, size = wx.DefaultSize): + wx.ScrolledWindow.__init__(self, parent, id, (0, 0), size=size, style=wx.SUNKEN_BORDER) + + self.lines = [] + self.maxWidth = 1000 + self.maxHeight = 1000 + self.x = self.y = 0 + self.curLine = [] + self.drawing = False + + self.SetBackgroundColour("WHITE") + self.SetCursor(wx.StockCursor(wx.CURSOR_PENCIL)) + bmp = images.Test2.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + bmp.SetMask(mask) + self.bmp = bmp + + self.SetVirtualSize((self.maxWidth, self.maxHeight)) + self.SetScrollRate(20,20) + + if BUFFERED: + # Initialize the buffer bitmap. No real DC is needed at this point. + self.buffer = wx.EmptyBitmap(self.maxWidth, self.maxHeight) + dc = wx.BufferedDC(None, self.buffer) + dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.Clear() + self.DoDrawing(dc) + + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftButtonEvent) + self.Bind(wx.EVT_LEFT_UP, self.OnLeftButtonEvent) + self.Bind(wx.EVT_MOTION, self.OnLeftButtonEvent) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def getWidth(self): + return self.maxWidth + + def getHeight(self): + return self.maxHeight + + + def OnPaint(self, event): + if BUFFERED: + # Create a buffered paint DC. It will create the real + # wx.PaintDC and then blit the bitmap to it when dc is + # deleted. Since we don't need to draw anything else + # here that's all there is to it. + dc = wx.BufferedPaintDC(self, self.buffer, wx.BUFFER_VIRTUAL_AREA) + else: + dc = wx.PaintDC(self) + self.PrepareDC(dc) + # Since we're not buffering in this case, we have to + # (re)paint the all the contents of the window, which can + # be potentially time consuming and flickery depending on + # what is being drawn and how much of it there is. + self.DoDrawing(dc) + + + def DoDrawing(self, dc, printing=False): + dc.BeginDrawing() + dc.SetPen(wx.Pen('RED')) + dc.DrawRectangle(5, 5, 50, 50) + + dc.SetBrush(wx.LIGHT_GREY_BRUSH) + dc.SetPen(wx.Pen('BLUE', 4)) + dc.DrawRectangle(15, 15, 50, 50) + + dc.SetFont(wx.Font(14, wx.SWISS, wx.NORMAL, wx.NORMAL)) + dc.SetTextForeground(wx.Colour(0xFF, 0x20, 0xFF)) + te = dc.GetTextExtent("Hello World") + dc.DrawText("Hello World", 60, 65) + + dc.SetPen(wx.Pen('VIOLET', 4)) + dc.DrawLine(5, 65+te[1], 60+te[0], 65+te[1]) + + lst = [(100,110), (150,110), (150,160), (100,160)] + dc.DrawLines(lst, -60) + dc.SetPen(wx.GREY_PEN) + dc.DrawPolygon(lst, 75) + dc.SetPen(wx.GREEN_PEN) + dc.DrawSpline(lst+[(100,100)]) + + dc.DrawBitmap(self.bmp, 200, 20, True) + dc.SetTextForeground(wx.Colour(0, 0xFF, 0x80)) + dc.DrawText("a bitmap", 200, 85) + + font = wx.Font(20, wx.SWISS, wx.NORMAL, wx.NORMAL) + dc.SetFont(font) + dc.SetTextForeground(wx.BLACK) + + for a in range(0, 360, 45): + dc.DrawRotatedText("Rotated text...", 300, 300, a) + + dc.SetPen(wx.TRANSPARENT_PEN) + dc.SetBrush(wx.BLUE_BRUSH) + dc.DrawRectangle(50,500, 50,50) + dc.DrawRectangle(100,500, 50,50) + + dc.SetPen(wx.Pen('RED')) + dc.DrawEllipticArc(200,500, 50,75, 0, 90) + + if not printing: + # This has troubles when used on a print preview in wxGTK, + # probably something to do with the pen styles and the scaling + # it does... + y = 20 + + for style in [wx.DOT, wx.LONG_DASH, wx.SHORT_DASH, wx.DOT_DASH, wx.USER_DASH]: + pen = wx.Pen("DARK ORCHID", 1, style) + if style == wx.USER_DASH: + pen.SetCap(wx.CAP_BUTT) + pen.SetDashes([1,2]) + pen.SetColour("RED") + dc.SetPen(pen) + dc.DrawLine(300,y, 400,y) + y = y + 10 + + dc.SetBrush(wx.TRANSPARENT_BRUSH) + dc.SetPen(wx.Pen(wx.Colour(0xFF, 0x20, 0xFF), 1, wx.SOLID)) + dc.DrawRectangle(450,50, 100,100) + old_pen = dc.GetPen() + new_pen = wx.Pen("BLACK", 5) + dc.SetPen(new_pen) + dc.DrawRectangle(470,70, 60,60) + dc.SetPen(old_pen) + dc.DrawRectangle(490,90, 20,20) + + dc.GradientFillLinear((20, 260, 50, 50), + "red", "blue") + dc.GradientFillConcentric((20, 325, 50, 50), + "red", "blue", (25,25)) + self.DrawSavedLines(dc) + dc.EndDrawing() + + + def DrawSavedLines(self, dc): + dc.SetPen(wx.Pen('MEDIUM FOREST GREEN', 4)) + for line in self.lines: + for coords in line: + apply(dc.DrawLine, coords) + + + def SetXY(self, event): + self.x, self.y = self.ConvertEventCoords(event) + + def ConvertEventCoords(self, event): + newpos = self.CalcUnscrolledPosition(event.GetX(), event.GetY()) + return newpos + + def OnLeftButtonEvent(self, event): + if self.IsAutoScrolling(): + self.StopAutoScrolling() + + if event.LeftDown(): + self.SetFocus() + self.SetXY(event) + self.curLine = [] + self.CaptureMouse() + self.drawing = True + + elif event.Dragging() and self.drawing: + if BUFFERED: + # If doing buffered drawing we'll just update the + # buffer here and then refresh that portion of the + # window. Then the system will send an event and that + # portion of the buffer will be redrawn in the + # EVT_PAINT handler. + dc = wx.BufferedDC(None, self.buffer) + else: + # otherwise we'll draw directly to a wx.ClientDC + dc = wx.ClientDC(self) + self.PrepareDC(dc) + + dc.SetPen(wx.Pen('MEDIUM FOREST GREEN', 4)) + coords = (self.x, self.y) + self.ConvertEventCoords(event) + self.curLine.append(coords) + dc.DrawLine(*coords) + self.SetXY(event) + + if BUFFERED: + # figure out what part of the window to refresh, based + # on what parts of the buffer we just updated + x1,y1, x2,y2 = dc.GetBoundingBox() + x1,y1 = self.CalcScrolledPosition(x1, y1) + x2,y2 = self.CalcScrolledPosition(x2, y2) + # make a rectangle + rect = wx.Rect() + rect.SetTopLeft((x1,y1)) + rect.SetBottomRight((x2,y2)) + rect.Inflate(2,2) + # refresh it + self.RefreshRect(rect) + + elif event.LeftUp() and self.drawing: + self.lines.append(self.curLine) + self.curLine = [] + self.ReleaseMouse() + self.drawing = False + + +## This is an example of what to do for the EVT_MOUSEWHEEL event, +## but since wx.ScrolledWindow does this already it's not +## necessary to do it ourselves. You would need to add an event table +## entry to __init__() to direct wheelmouse events to this handler. + +## wheelScroll = 0 +## def OnWheel(self, evt): +## delta = evt.GetWheelDelta() +## rot = evt.GetWheelRotation() +## linesPer = evt.GetLinesPerAction() +## print delta, rot, linesPer +## ws = self.wheelScroll +## ws = ws + rot +## lines = ws / delta +## ws = ws - lines * delta +## self.wheelScroll = ws +## if lines != 0: +## lines = lines * linesPer +## vsx, vsy = self.GetViewStart() +## scrollTo = vsy - lines +## self.Scroll(-1, scrollTo) + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = MyCanvas(nb) + return win + +#--------------------------------------------------------------------------- + + + +overview = """ + + +The wx.ScrolledWindow class manages scrolling for its client area, transforming the +coordinates according to the scrollbar positions, and setting the scroll positions, +thumb sizes and ranges according to the area in view. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/SearchCtrl.py b/demo/SearchCtrl.py new file mode 100644 index 00000000..8776ea85 --- /dev/null +++ b/demo/SearchCtrl.py @@ -0,0 +1,106 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent) + + # Create controls + sb = wx.StaticBox(self, -1, "Options") + searchBtnOpt = wx.CheckBox(self, -1, "Search button") + searchBtnOpt.SetValue(True) + cancelBtnOpt = wx.CheckBox(self, -1, "Cancel button") + menuBtnOpt = wx.CheckBox(self, -1, "Search menu") + + self.search = wx.SearchCtrl(self, size=(200,-1), style=wx.TE_PROCESS_ENTER) + + # Setup the layout + box = wx.StaticBoxSizer(sb, wx.VERTICAL) + box.Add(searchBtnOpt, 0, wx.ALL, 5) + box.Add(cancelBtnOpt, 0, wx.ALL, 5) + box.Add(menuBtnOpt, 0, wx.ALL, 5) + + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(box, 0, wx.ALL, 15) + sizer.Add((15,15)) + sizer.Add(self.search, 0, wx.ALL, 15) + +## self.tc = wx.TextCtrl(self) # just for testing that heights match... +## sizer.Add(self.tc, 0, wx.TOP, 15) + + self.SetSizer(sizer) + + + # Set event bindings + self.Bind(wx.EVT_CHECKBOX, self.OnToggleSearchButton, searchBtnOpt) + self.Bind(wx.EVT_CHECKBOX, self.OnToggleCancelButton, cancelBtnOpt) + self.Bind(wx.EVT_CHECKBOX, self.OnToggleSearchMenu, menuBtnOpt) + + self.Bind(wx.EVT_SEARCHCTRL_SEARCH_BTN, self.OnSearch, self.search) + self.Bind(wx.EVT_SEARCHCTRL_CANCEL_BTN, self.OnCancel, self.search) + self.Bind(wx.EVT_TEXT_ENTER, self.OnDoSearch, self.search) + ##self.Bind(wx.EVT_TEXT, self.OnDoSearch, self.search) + + + def OnToggleSearchButton(self, evt): + self.search.ShowSearchButton( evt.GetInt() ) + + def OnToggleCancelButton(self, evt): + self.search.ShowCancelButton( evt.GetInt() ) + + def OnToggleSearchMenu(self, evt): + if evt.GetInt(): + self.search.SetMenu( self.MakeMenu() ) + else: + self.search.SetMenu(None) + + + def OnSearch(self, evt): + self.log.write("OnSearch") + + def OnCancel(self, evt): + self.log.write("OnCancel") + + def OnDoSearch(self, evt): + self.log.write("OnDoSearch: " + self.search.GetValue()) + + + def MakeMenu(self): + menu = wx.Menu() + item = menu.Append(-1, "Recent Searches") + item.Enable(False) + for txt in [ "You can maintain", + "a list of old", + "search strings here", + "and bind EVT_MENU to", + "catch their selections" ]: + menu.Append(-1, txt) + return menu + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.SearchCtrl

+ + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/ShapedWindow.py b/demo/ShapedWindow.py new file mode 100644 index 00000000..80983b1e --- /dev/null +++ b/demo/ShapedWindow.py @@ -0,0 +1,136 @@ + +import wx +import images + +#---------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + self.log = log + wx.Frame.__init__(self, parent, -1, "Shaped Window", + style = + wx.FRAME_SHAPED + | wx.SIMPLE_BORDER + | wx.FRAME_NO_TASKBAR + | wx.STAY_ON_TOP + ) + + self.hasShape = False + self.delta = (0,0) + + self.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) + self.Bind(wx.EVT_MOTION, self.OnMouseMove) + self.Bind(wx.EVT_RIGHT_UP, self.OnExit) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + self.bmp = images.Vippi.GetBitmap() + w, h = self.bmp.GetWidth(), self.bmp.GetHeight() + self.SetClientSize( (w, h) ) + + if wx.Platform != "__WXMAC__": + # wxMac clips the tooltip to the window shape, YUCK!!! + self.SetToolTipString("Right-click to close the window\n" + "Double-click the image to set/unset the window shape") + + if wx.Platform == "__WXGTK__": + # wxGTK requires that the window be created before you can + # set its shape, so delay the call to SetWindowShape until + # this event. + self.Bind(wx.EVT_WINDOW_CREATE, self.SetWindowShape) + else: + # On wxMSW and wxMac the window has already been created, so go for it. + self.SetWindowShape() + + dc = wx.ClientDC(self) + dc.DrawBitmap(self.bmp, 0,0, True) + + + def SetWindowShape(self, *evt): + # Use the bitmap's mask to determine the region + r = wx.RegionFromBitmap(self.bmp) + self.hasShape = self.SetShape(r) + + + def OnDoubleClick(self, evt): + if self.hasShape: + self.SetShape(wx.Region()) + self.hasShape = False + else: + self.SetWindowShape() + + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + dc.DrawBitmap(self.bmp, 0,0, True) + + def OnExit(self, evt): + self.Close() + + + def OnLeftDown(self, evt): + self.CaptureMouse() + x, y = self.ClientToScreen(evt.GetPosition()) + originx, originy = self.GetPosition() + dx = x - originx + dy = y - originy + self.delta = ((dx, dy)) + + + def OnLeftUp(self, evt): + if self.HasCapture(): + self.ReleaseMouse() + + + def OnMouseMove(self, evt): + if evt.Dragging() and evt.LeftIsDown(): + x, y = self.ClientToScreen(evt.GetPosition()) + fp = (x - self.delta[0], y - self.delta[1]) + self.Move(fp) + + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show the ShapedWindow sample", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = TestFrame(self, self.log) + win.Show(True) + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Shaped Window

+ +Top level windows now have a SetShape method that lets you set a +non-rectangular shape for the window using a wxRegion. All pixels +outside of the region will not be drawn and the window will not be +sensitive to the mouse in those areas either. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/SingleChoiceDialog.py b/demo/SingleChoiceDialog.py new file mode 100644 index 00000000..2317d7e3 --- /dev/null +++ b/demo/SingleChoiceDialog.py @@ -0,0 +1,55 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a SingleChoiceDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + dlg = wx.SingleChoiceDialog( + self, 'Test Single Choice', 'The Caption', + ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight'], + wx.CHOICEDLG_STYLE + ) + + if dlg.ShowModal() == wx.ID_OK: + self.log.WriteText('You selected: %s\n' % dlg.GetStringSelection()) + + dlg.Destroy() + + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win +#--------------------------------------------------------------------------- + + + + +overview = """\ +This class represents a dialog that shows a list of strings, and allows the user +to select one. Double-clicking on a list item is equivalent to single-clicking +and then pressing OK. + +As with all dialogs, be sure to retrieve the information you need BEFORE you +destroy the dialog. +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/SizedControls.py b/demo/SizedControls.py new file mode 100644 index 00000000..d5f3c2fb --- /dev/null +++ b/demo/SizedControls.py @@ -0,0 +1,400 @@ +import wx +import wx.lib.sized_controls as sc + +overview = """\ +

Sized Controls

+SizedControls is an addon library that attempts to simplify the +creation of sizer-based layouts. It adds the following classes: + +

SizedPanel

+ +This class automatically creates its own sizer (a vertical box sizer +by default) and automatically adds its children to the sizer. You can +change the SizedPanel's sizer type by calling +panel.SetSizerType(\"type\", [args]), where valid types are +\"horizontal\", \"vertical\", \"form\" (a 2-col flex grid sizer), and +\"grid\". Args include \"cols\" and \"rows\" attributes for +grids. This class also applies control borders that adhere to the +native platform's Human Interface Guidelines (HIG) on Win, GTK and +Mac. + +

SizedScrolledPanel

+ +This class automatically creates its own sizer (a vertical box sizer +by default) and automatically adds its children to the sizer. You can +change the SizedScrolledPanel's sizer type by calling +panel.SetSizerType(\"type\", [args]), where valid types are +\"horizontal\", \"vertical\", \"form\" (a 2-col flex grid sizer), and +\"grid\". Args include \"cols\" and \"rows\" attributes for +grids. This class also applies control borders that adhere to the +native platform's Human Interface Guidelines (HIG) on Win, GTK and +Mac. + +

SizedFrame and SizedDialog

+ +These classes automatically setup a SizedPanel which is appropriately +positioned and given appropriate borders in accordance with the +platform's HIGs. + +

Since controls are added to the parent's sizer upon creation, you +don't need to use sizer.Add or even create sizers yourself. You just +use SetSizerType() to change the sizer you want to use, and +control.SetSizerProps() to change the sizer properties of the +control. So as a result, code that used to look like this: + +
+... wx.Dialog init code...
+
+panel = wx.Panel(self, -1)
+b1 = wx.Button(panel, -1)
+b2 = wx.Button(panel, -1)
+t1 = wx.TextCtrl(panel, -1)
+b3 = wx.Button(panel, -1)
+
+sizer = wx.BoxSizer(wx.HORIZONTAL)
+sizer.Add(b1, 0, wx.ALL, 6)
+sizer.Add(b2, 0, wx.ALL, 6)
+sizer.Add(t1, 0, wx.EXPAND | wx.ALL, 6)
+sizer.Add(b3, 0, wx.ALL, 6)
+panel.SetSizer(sizer)
+
+dlgSizer = wx.BoxSizer()
+dlgSizer.Add(panel, 1, wx.EXPAND)
+self.SetSizer(dlgSizer)
+self.SetAutoLayout(True)
+
+... rest of dialog ...
+
+ +would now look like this: + +
+... wx.Dialog init code...
+
+panel = self.GetContentsPane()
+panel.SetSizerType(\"horizontal\")
+
+b1 = wx.Button(panel, -1)
+b2 = wx.Button(panel, -1)
+
+t1 = wx.TextCtrl(panel, -1)
+t1.SetSizerProps(expand=True)
+
+b3 = wx.Button(panel, -1)
+
+... rest of dialog ...
+
+ +and the latter example will adhere to HIG spacing guidelines on all platforms, +unlike the former example. Please check the demos for more complete and sophisticated examples of SizedControls +in action. + +

wx.Window.SetSizerProps Quick Reference

+ +

wx.Window.SetSizerProps(<props>)
+ +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Parameter Values Summary
expand True/FalseWhether or not the control should grow to fill free space if +free space is available.
proportion Number (typically 0-10)How much of the free space the control should take up. Note that this value is +relative to other controls, so a proportion of 2 means take up +'twice as much' space as controls with a proportion of 1.
halign "left", "center", "centre", "right"Determines horizontal alignment of control.
valign "top", "center", "centre", "bottom"Determines vertical alignment of control.
border Tuple: ([dirs], integer)Specifies amount of border padding to apply to specified directions.
+Example: (["left", "right"], 6) would add six pixels to left and right borders.
+Note that, unfortunately, +it is not currently possible to assign different border sizes to each direction.
minsize One of the following string values: "fixed", "adjust"Determines whether or not the minsize can be updated when the control's best size changes.
+""" + +class FormDialog(sc.SizedDialog): + def __init__(self, parent, id): + sc.SizedDialog.__init__(self, None, -1, "SizedForm Dialog", + style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER) + + pane = self.GetContentsPane() + pane.SetSizerType("form") + + # row 1 + wx.StaticText(pane, -1, "Name") + textCtrl = wx.TextCtrl(pane, -1, "Your name here") + textCtrl.SetSizerProps(expand=True) + + # row 2 + wx.StaticText(pane, -1, "Email") + emailCtrl = wx.TextCtrl(pane, -1, "") + emailCtrl.SetSizerProps(expand=True) + + # row 3 + wx.StaticText(pane, -1, "Gender") + wx.Choice(pane, -1, choices=["male", "female"]) + + # row 4 + wx.StaticText(pane, -1, "State") + wx.TextCtrl(pane, -1, size=(60, -1)) # two chars for state + + # row 5 + wx.StaticText(pane, -1, "Title") + + # here's how to add a 'nested sizer' using sized_controls + radioPane = sc.SizedPanel(pane, -1) + radioPane.SetSizerType("horizontal") + radioPane.SetSizerProps(expand=True) + + # make these children of the radioPane to have them use + # the horizontal layout + wx.RadioButton(radioPane, -1, "Mr.") + wx.RadioButton(radioPane, -1, "Mrs.") + wx.RadioButton(radioPane, -1, "Dr.") + # end row 5 + + # add dialog buttons + self.SetButtonSizer(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL)) + + # a little trick to make sure that you can't resize the dialog to + # less screen space than the controls need + self.Fit() + self.SetMinSize(self.GetSize()) + + +class ScrolledFormDialog(sc.SizedDialog): + def __init__(self, parent, id): + sc.SizedDialog.__init__(self, None, -1, "SizedForm Dialog with a scolled panel", + style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, + size=wx.Size(-1, 220)) + + cPane = self.GetContentsPane() + pane = sc.SizedScrolledPanel(cPane, wx.ID_ANY) + pane.SetSizerProps(expand=True, proportion=1) + pane.SetSizerType("form") + + # row 1 + wx.StaticText(pane, -1, "Name") + textCtrl = wx.TextCtrl(pane, -1, "Your name here") + textCtrl.SetSizerProps(expand=True) + + # row 2 + wx.StaticText(pane, -1, "Email") + emailCtrl = wx.TextCtrl(pane, -1, "") + emailCtrl.SetSizerProps(expand=True) + + # row 3 + wx.StaticText(pane, -1, "Gender") + wx.Choice(pane, -1, choices=["male", "female"]) + + # row 4 + wx.StaticText(pane, -1, "State") + wx.TextCtrl(pane, -1, size=(60, -1)) # two chars for state + + # row 5 + wx.StaticText(pane, -1, "Title") + + # here's how to add a 'nested sizer' using sized_controls + radioPane = sc.SizedPanel(pane, -1) + radioPane.SetSizerType("horizontal") + radioPane.SetSizerProps(expand=True) + + # make these children of the radioPane to have them use + # the horizontal layout + wx.RadioButton(radioPane, -1, "Mr.") + wx.RadioButton(radioPane, -1, "Mrs.") + wx.RadioButton(radioPane, -1, "Dr.") + # end row 5 + + # add dialog buttons + self.SetButtonSizer(self.CreateStdDialogButtonSizer(wx.OK | wx.CANCEL)) + + +class ErrorDialog(sc.SizedDialog): + def __init__(self, parent, id): + sc.SizedDialog.__init__(self, parent, id, "Error log viewer", + style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER) + + # Always use self.GetContentsPane() - this ensures that your dialog + # automatically adheres to HIG spacing requirements on all platforms. + # pane here is a sc.SizedPanel with a vertical sizer layout. All children + # should be added to this pane, NOT to self. + pane = self.GetContentsPane() + + # first row + self.listCtrl = wx.ListCtrl(pane, -1, size=(300, -1), style=wx.LC_REPORT) + self.listCtrl.SetSizerProps(expand=True, proportion=1) + self.ConfigureListCtrl() + + # second row + self.lblDetails = wx.StaticText(pane, -1, "Error Details") + + # third row + self.details = wx.TextCtrl(pane, -1, style=wx.TE_MULTILINE) + self.details.SetSizerProps(expand=True, proportion=1) + + # final row + # since we want to use a custom button layout, we won't use the + # CreateStdDialogBtnSizer here, we'll just create our own panel with + # a horizontal layout and add the buttons to that. + btnpane = sc.SizedPanel(pane, -1) + btnpane.SetSizerType("horizontal") + btnpane.SetSizerProps(expand=True) + + self.saveBtn = wx.Button(btnpane, wx.ID_SAVE) + spacer = sc.SizedPanel(btnpane, -1) + spacer.SetSizerProps(expand=True, proportion=1) + + self.clearBtn = wx.Button(btnpane, -1, "Clear") + + self.Fit() + self.SetMinSize(self.GetSize()) + + def ConfigureListCtrl(self): + self.listCtrl.InsertColumn(0, "Time") + self.listCtrl.InsertColumn(1, "Error Message") + self.listCtrl.SetColumnWidth(0, 100) + self.listCtrl.SetColumnWidth(1, 280) + + +class GridFrame(sc.SizedFrame): + def __init__(self, parent, id): + sc.SizedFrame.__init__(self, parent, id, "Grid Layout Demo Frame") + + pane = self.GetContentsPane() + pane.SetSizerType("grid", {"cols":3}) # 3-column grid layout + + # row 1 + wx.TextCtrl(pane, -1).SetSizerProps(halign="left") + wx.TextCtrl(pane, -1).SetSizerProps(halign="center") + wx.TextCtrl(pane, -1).SetSizerProps(halign="right") + + # row 2 + wx.TextCtrl(pane, -1).SetSizerProps(valign="center") + wx.TextCtrl(pane, -1).SetSizerProps(expand=True, proportion=1) + wx.TextCtrl(pane, -1).SetSizerProps(valign="center") + + # row 3 + wx.TextCtrl(pane, -1).SetSizerProps(halign="left") + wx.TextCtrl(pane, -1).SetSizerProps(halign="center") + wx.TextCtrl(pane, -1).SetSizerProps(halign="right") + + self.CreateStatusBar() # should always do this when there's a resize border + + self.Fit() + self.SetMinSize(self.GetSize()) + + +#--------------------------------------------------------------------------- + +class TestPanel(sc.SizedScrolledPanel): + def __init__(self, parent, log): + self.log = log + self.parent = parent + sc.SizedScrolledPanel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Sized Controls Form Dialog") + b.SetSizerProps({'halign': 'center', 'border': ('all', 15)}) + self.Bind(wx.EVT_BUTTON, self.OnFormButton, b) + + b1 = wx.Button(self, -1, "Sized Controls Form Dialog with scrolled panel") + b1.SetSizerProps({'halign': 'center', 'border': ('all', 15)}) + self.Bind(wx.EVT_BUTTON, self.OnFormScrolledButton, b1) + + b2 = wx.Button(self, -1, "Sized Controls Error Dialog") + b2.SetSizerProps({'halign': 'center', 'border': ('all', 15)}) + self.Bind(wx.EVT_BUTTON, self.OnErrorButton, b2) + + b3 = wx.Button(self, -1, "Sized Controls Grid Layout Demo") + b3.SetSizerProps({'halign': 'center', 'border': ('all', 15)}) + self.Bind(wx.EVT_BUTTON, self.OnGridButton, b3) + + + def OnFormButton(self, evt): + + dlg = FormDialog(self, -1) + dlg.CenterOnScreen() + + # this does not return until the dialog is closed. + val = dlg.ShowModal() + + if val == wx.ID_OK: + self.log.WriteText("You pressed OK\n") + else: + self.log.WriteText("You pressed Cancel\n") + + dlg.Destroy() + + def OnFormScrolledButton(self, evt): + + dlg = ScrolledFormDialog(self, -1) + dlg.CenterOnScreen() + + # this does not return until the dialog is closed. + val = dlg.ShowModal() + + if val == wx.ID_OK: + self.log.WriteText("You pressed OK\n") + else: + self.log.WriteText("You pressed Cancel\n") + + dlg.Destroy() + + def OnErrorButton(self, evt): + + dlg = ErrorDialog(self, -1) + dlg.CenterOnScreen() + + # this does not return until the dialog is closed. + val = dlg.ShowModal() + + if val == wx.ID_OK: + self.log.WriteText("You pressed OK\n") + else: + self.log.WriteText("You pressed Cancel\n") + + dlg.Destroy() + + def OnGridButton(self, evt): + + dlg = GridFrame(self, -1) + dlg.CenterOnScreen() + + dlg.Show() + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Sizers.py b/demo/Sizers.py new file mode 100644 index 00000000..1d79096a --- /dev/null +++ b/demo/Sizers.py @@ -0,0 +1,601 @@ +# 11/26/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Had to do a bit of rework for the demo; there was no panel attached +# to the demo window, so all buttons were showing as dark gray on +# dark gray. I have no idea why this didn't break before. Robin, +# please examine my changes to ensure you approve. It's rather +# hackish looking. +# + +#---------------------------------------------------------------------- +# sizer test code +#---------------------------------------------------------------------- + +import wx + +#---------------------------------------------------------------------- + +class SampleWindow(wx.PyWindow): + """ + A simple window that is used as sizer items in the tests below to + show how the various sizers work. + """ + def __init__(self, parent, text, pos=wx.DefaultPosition, size=wx.DefaultSize): + wx.PyWindow.__init__(self, parent, -1, + #style=wx.RAISED_BORDER + #style=wx.SUNKEN_BORDER + style=wx.SIMPLE_BORDER + ) + self.text = text + if size != wx.DefaultSize: + self.bestsize = size + else: + self.bestsize = (80,25) + self.SetSize(self.GetBestSize()) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_LEFT_UP, self.OnCloseParent) + + + def OnPaint(self, evt): + sz = self.GetSize() + dc = wx.PaintDC(self) + w,h = dc.GetTextExtent(self.text) + dc.Clear() + dc.DrawText(self.text, (sz.width-w)/2, (sz.height-h)/2) + + def OnSize(self, evt): + self.Refresh() + + def OnCloseParent(self, evt): + p = wx.GetTopLevelParent(self) + if p: + p.Close() + + def DoGetBestSize(self): + return self.bestsize + + +#---------------------------------------------------------------------- + +def makeSimpleBox1(win): + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(SampleWindow(win, "one"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "two"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "three"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "four"), 0, wx.EXPAND) + + return box + +#---------------------------------------------------------------------- + +def makeSimpleBox2(win): + box = wx.BoxSizer(wx.VERTICAL) + box.Add(SampleWindow(win, "one"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "two"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "three"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "four"), 0, wx.EXPAND) + + return box + +#---------------------------------------------------------------------- + +def makeSimpleBox3(win): + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(SampleWindow(win, "one"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "two"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "three"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "four"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "five"), 1, wx.EXPAND) + + return box + +#---------------------------------------------------------------------- + +def makeSimpleBox4(win): + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(SampleWindow(win, "one"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "two"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "three"), 1, wx.EXPAND) + box.Add(SampleWindow(win, "four"), 1, wx.EXPAND) + box.Add(SampleWindow(win, "five"), 1, wx.EXPAND) + + return box + +#---------------------------------------------------------------------- + +def makeSimpleBox5(win): + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(SampleWindow(win, "one"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "two"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "three"), 3, wx.EXPAND) + box.Add(SampleWindow(win, "four"), 1, wx.EXPAND) + box.Add(SampleWindow(win, "five"), 1, wx.EXPAND) + + return box + +#---------------------------------------------------------------------- + +def makeSimpleBox6(win): + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(SampleWindow(win, "one"), 1, wx.ALIGN_TOP) + box.Add(SampleWindow(win, "two"), 1, wx.EXPAND) + box.Add(SampleWindow(win, "three"), 1, wx.ALIGN_CENTER) + box.Add(SampleWindow(win, "four"), 1, wx.EXPAND) + box.Add(SampleWindow(win, "five"), 1, wx.ALIGN_BOTTOM) + + return box + +#---------------------------------------------------------------------- + +def makeSimpleBox7(win): + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(SampleWindow(win, "one"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "two"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "three"), 0, wx.EXPAND) + box.Add((60, 20), 0, wx.EXPAND) + box.Add(SampleWindow(win, "five"), 1, wx.EXPAND) + + return box + +#---------------------------------------------------------------------- + +def makeSimpleBox8(win): + box = wx.BoxSizer(wx.VERTICAL) + box.Add(SampleWindow(win, "one"), 0, wx.EXPAND) + box.Add((0,0), 1) + box.Add(SampleWindow(win, "two"), 0, wx.ALIGN_CENTER) + box.Add((0,0), 1) + box.Add(SampleWindow(win, "three"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "four"), 0, wx.EXPAND) +# box.Add(SampleWindow(win, "five"), 1, wx.EXPAND) + + return box + +#---------------------------------------------------------------------- +#---------------------------------------------------------------------- + +def makeSimpleBorder1(win): + bdr = wx.BoxSizer(wx.HORIZONTAL) + btn = SampleWindow(win, "border") + btn.SetSize((80, 80)) + bdr.Add(btn, 1, wx.EXPAND|wx.ALL, 15) + + return bdr + +#---------------------------------------------------------------------- + +def makeSimpleBorder2(win): + bdr = wx.BoxSizer(wx.HORIZONTAL) + btn = SampleWindow(win, "border") + btn.SetSize((80, 80)) + bdr.Add(btn, 1, wx.EXPAND | wx.EAST | wx.WEST, 15) + + return bdr + +#---------------------------------------------------------------------- + +def makeSimpleBorder3(win): + bdr = wx.BoxSizer(wx.HORIZONTAL) + btn = SampleWindow(win, "border") + btn.SetSize((80, 80)) + bdr.Add(btn, 1, wx.EXPAND | wx.NORTH | wx.WEST, 15) + + return bdr + +#---------------------------------------------------------------------- +#---------------------------------------------------------------------- + +def makeBoxInBox(win): + box = wx.BoxSizer(wx.VERTICAL) + + box.Add(SampleWindow(win, "one"), 0, wx.EXPAND) + + box2 = wx.BoxSizer(wx.HORIZONTAL) + box2.Add(SampleWindow(win, "two"), 0, wx.EXPAND) + btn3 = SampleWindow(win, "three") + box2.Add(btn3, 0, wx.EXPAND) + box2.Add(SampleWindow(win, "four"), 0, wx.EXPAND) + box2.Add(SampleWindow(win, "five"), 0, wx.EXPAND) + + box3 = wx.BoxSizer(wx.VERTICAL) + box3.AddMany([ (SampleWindow(win, "six"), 0, wx.EXPAND), + (SampleWindow(win, "seven"), 2, wx.EXPAND), + (SampleWindow(win, "eight"), 1, wx.EXPAND), + (SampleWindow(win, "nine"), 1, wx.EXPAND), + ]) + + box2.Add(box3, 1, wx.EXPAND) + box.Add(box2, 1, wx.EXPAND) + + box.Add(SampleWindow(win, "ten"), 0, wx.EXPAND) + + ##box.Hide(btn3) + + return box + +#---------------------------------------------------------------------- + +def makeBoxInBorder(win): + bdr = wx.BoxSizer(wx.HORIZONTAL) + box = makeSimpleBox3(win) + bdr.Add(box, 1, wx.EXPAND | wx.ALL, 15) + + return bdr + +#---------------------------------------------------------------------- + +def makeBorderInBox(win): + insideBox = wx.BoxSizer(wx.HORIZONTAL) + + box2 = wx.BoxSizer(wx.HORIZONTAL) + box2.AddMany([ (SampleWindow(win, "one"), 0, wx.EXPAND), + (SampleWindow(win, "two"), 0, wx.EXPAND), + (SampleWindow(win, "three"), 0, wx.EXPAND), + (SampleWindow(win, "four"), 0, wx.EXPAND), + (SampleWindow(win, "five"), 0, wx.EXPAND), + ]) + + insideBox.Add(box2, 0, wx.EXPAND) + + bdr = wx.BoxSizer(wx.HORIZONTAL) + bdr.Add(SampleWindow(win, "border"), 1, wx.EXPAND | wx.ALL) + insideBox.Add(bdr, 1, wx.EXPAND | wx.ALL, 20) + + box3 = wx.BoxSizer(wx.VERTICAL) + box3.AddMany([ (SampleWindow(win, "six"), 0, wx.EXPAND), + (SampleWindow(win, "seven"), 2, wx.EXPAND), + (SampleWindow(win, "eight"), 1, wx.EXPAND), + (SampleWindow(win, "nine"), 1, wx.EXPAND), + ]) + insideBox.Add(box3, 1, wx.EXPAND) + + outsideBox = wx.BoxSizer(wx.VERTICAL) + outsideBox.Add(SampleWindow(win, "top"), 0, wx.EXPAND) + outsideBox.Add(insideBox, 1, wx.EXPAND) + outsideBox.Add(SampleWindow(win, "bottom"), 0, wx.EXPAND) + + return outsideBox + + +#---------------------------------------------------------------------- + +def makeGrid1(win): + gs = wx.GridSizer(3, 3, 2, 2) # rows, cols, vgap, hgap + + gs.AddMany([ (SampleWindow(win, 'one'), 0, wx.EXPAND), + (SampleWindow(win, 'two'), 0, wx.EXPAND), + (SampleWindow(win, 'three'), 0, wx.EXPAND), + (SampleWindow(win, 'four'), 0, wx.EXPAND), + (SampleWindow(win, 'five'), 0, wx.EXPAND), + #(75, 50), + (SampleWindow(win, 'six'), 0, wx.EXPAND), + (SampleWindow(win, 'seven'), 0, wx.EXPAND), + (SampleWindow(win, 'eight'), 0, wx.EXPAND), + (SampleWindow(win, 'nine'), 0, wx.EXPAND), + ]) + + return gs + +#---------------------------------------------------------------------- + +def makeGrid2(win): + gs = wx.GridSizer(3, 3) # rows, cols, vgap, hgap + + box = wx.BoxSizer(wx.VERTICAL) + box.Add(SampleWindow(win, 'A'), 0, wx.EXPAND) + box.Add(SampleWindow(win, 'B'), 1, wx.EXPAND) + + gs2 = wx.GridSizer(2,2, 4, 4) + gs2.AddMany([ (SampleWindow(win, 'C'), 0, wx.EXPAND), + (SampleWindow(win, 'E'), 0, wx.EXPAND), + (SampleWindow(win, 'F'), 0, wx.EXPAND), + (SampleWindow(win, 'G'), 0, wx.EXPAND)]) + + gs.AddMany([ (SampleWindow(win, 'one'), 0, wx.ALIGN_RIGHT | wx.ALIGN_BOTTOM), + (SampleWindow(win, 'two'), 0, wx.EXPAND), + (SampleWindow(win, 'three'), 0, wx.ALIGN_LEFT | wx.ALIGN_BOTTOM), + (SampleWindow(win, 'four'), 0, wx.EXPAND), + (SampleWindow(win, 'five'), 0, wx.ALIGN_CENTER), + (SampleWindow(win, 'six'), 0, wx.EXPAND), + (box, 0, wx.EXPAND | wx.ALL, 10), + (SampleWindow(win, 'eight'), 0, wx.EXPAND), + (gs2, 0, wx.EXPAND | wx.ALL, 4), + ]) + + return gs + +#---------------------------------------------------------------------- + +def makeGrid3(win): + gs = wx.FlexGridSizer(3, 3, 2, 2) # rows, cols, vgap, hgap + + gs.AddMany([ (SampleWindow(win, 'one'), 0, wx.EXPAND), + (SampleWindow(win, 'two'), 0, wx.EXPAND), + (SampleWindow(win, 'three'), 0, wx.EXPAND), + (SampleWindow(win, 'four'), 0, wx.EXPAND), + #(SampleWindow(win, 'five'), 0, wx.EXPAND), + ((175, 50)), + (SampleWindow(win, 'six'), 0, wx.EXPAND), + (SampleWindow(win, 'seven'), 0, wx.EXPAND), + (SampleWindow(win, 'eight'), 0, wx.EXPAND), + (SampleWindow(win, 'nine'), 0, wx.EXPAND), + ]) + + gs.AddGrowableRow(0) + gs.AddGrowableRow(2) + gs.AddGrowableCol(1) + return gs + +#---------------------------------------------------------------------- + +def makeGrid4(win): + bpos = wx.DefaultPosition + bsize = wx.Size(100, 50) + gs = wx.GridSizer(3, 3, 2, 2) # rows, cols, vgap, hgap + + gs.AddMany([ (SampleWindow(win, 'one', bpos, bsize), + 0, wx.ALIGN_TOP | wx.ALIGN_LEFT ), + (SampleWindow(win, 'two', bpos, bsize), + 0, wx.ALIGN_TOP | wx.ALIGN_CENTER_HORIZONTAL ), + (SampleWindow(win, 'three', bpos, bsize), + 0, wx.ALIGN_TOP | wx.ALIGN_RIGHT ), + (SampleWindow(win, 'four', bpos, bsize), + 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT ), + (SampleWindow(win, 'five', bpos, bsize), + 0, wx.ALIGN_CENTER ), + (SampleWindow(win, 'six', bpos, bsize), + 0, wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT ), + (SampleWindow(win, 'seven', bpos, bsize), + 0, wx.ALIGN_BOTTOM | wx.ALIGN_LEFT ), + (SampleWindow(win, 'eight', bpos, bsize), + 0, wx.ALIGN_BOTTOM | wx.ALIGN_CENTER_HORIZONTAL ), + (SampleWindow(win, 'nine', bpos, bsize), + 0, wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT ), + ]) + + return gs + +#---------------------------------------------------------------------- + +def makeShapes(win): + bpos = wx.DefaultPosition + bsize = wx.Size(100, 50) + gs = wx.GridSizer(3, 3, 2, 2) # rows, cols, vgap, hgap + + gs.AddMany([ (SampleWindow(win, 'one', bpos, bsize), + 0, wx.SHAPED | wx.ALIGN_TOP | wx.ALIGN_LEFT ), + (SampleWindow(win, 'two', bpos, bsize), + 0, wx.SHAPED | wx.ALIGN_TOP | wx.ALIGN_CENTER_HORIZONTAL ), + (SampleWindow(win, 'three', bpos, bsize), + 0, wx.SHAPED | wx.ALIGN_TOP | wx.ALIGN_RIGHT ), + (SampleWindow(win, 'four', bpos, bsize), + 0, wx.SHAPED | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT ), + (SampleWindow(win, 'five', bpos, bsize), + 0, wx.SHAPED | wx.ALIGN_CENTER ), + (SampleWindow(win, 'six', bpos, bsize), + 0, wx.SHAPED | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT ), + (SampleWindow(win, 'seven', bpos, bsize), + 0, wx.SHAPED | wx.ALIGN_BOTTOM | wx.ALIGN_LEFT ), + (SampleWindow(win, 'eight', bpos, bsize), + 0, wx.SHAPED | wx.ALIGN_BOTTOM | wx.ALIGN_CENTER_HORIZONTAL ), + (SampleWindow(win, 'nine', bpos, bsize), + 0, wx.SHAPED | wx.ALIGN_BOTTOM | wx.ALIGN_RIGHT ), + ]) + + return gs + +#---------------------------------------------------------------------- + +def makeSimpleBoxShaped(win): + box = wx.BoxSizer(wx.HORIZONTAL) + box.Add(SampleWindow(win, "one"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "two"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "three"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "four"), 0, wx.EXPAND) + box.Add(SampleWindow(win, "five"), 1, wx.SHAPED) + + return box + +#---------------------------------------------------------------------- + +theTests = [ + ("Simple horizontal boxes", makeSimpleBox1, + "This is a HORIZONTAL box sizer with four non-stretchable buttons held " + "within it. Notice that the buttons are added and aligned in the horizontal " + "dimension. Also notice that they are fixed size in the horizontal dimension, " + "but will stretch vertically." + ), + + ("Simple vertical boxes", makeSimpleBox2, + "Exactly the same as the previous sample but using a VERTICAL box sizer " + "instead of a HORIZONTAL one." + ), + + ("Add a stretchable", makeSimpleBox3, + "We've added one more button with the stretchable flag turned on. Notice " + "how it grows to fill the extra space in the otherwise fixed dimension." + ), + + ("More than one stretchable", makeSimpleBox4, + "Here there are several items that are stretchable, they all divide up the " + "extra space evenly." + ), + + ("Weighting factor", makeSimpleBox5, + "This one shows more than one stretchable, but one of them has a weighting " + "factor so it gets more of the free space." + ), + + ("Edge Affinity", makeSimpleBox6, + "For items that don't completly fill their allotted space, and don't " + "stretch, you can specify which side (or the center) they should stay " + "attached to." + ), + + ("Spacer", makeSimpleBox7, + "You can add empty space to be managed by a Sizer just as if it were a " + "window or another Sizer." + ), + + ("Centering in available space", makeSimpleBox8, + "This one shows an item that does not expand to fill it's space, but rather" + "stays centered within it." + ), + +# ("Percent Sizer", makeSimpleBox6, +# "You can use the wx.BoxSizer like a Percent Sizer. Just make sure that all " +# "the weighting factors add up to 100!" +# ), + + ("", None, ""), + + ("Simple border sizer", makeSimpleBorder1, + "The wx.BoxSizer can leave empty space around its contents. This one " + "gives a border all the way around." + ), + + ("East and West border", makeSimpleBorder2, + "You can pick and choose which sides have borders." + ), + + ("North and West border", makeSimpleBorder3, + "You can pick and choose which sides have borders." + ), + + ("", None, ""), + + ("Boxes inside of boxes", makeBoxInBox, + "This one shows nesting of boxes within boxes within boxes, using both " + "orientations. Notice also that button seven has a greater weighting " + "factor than its siblings." + ), + + ("Boxes inside a Border", makeBoxInBorder, + "Sizers of different types can be nested within each other as well. " + "Here is a box sizer with several buttons embedded within a border sizer." + ), + + ("Border in a Box", makeBorderInBox, + "Another nesting example. This one has Boxes and a Border inside another Box." + ), + + ("", None, ""), + + ("Simple Grid", makeGrid1, + "This is an example of the wx.GridSizer. In this case all row heights " + "and column widths are kept the same as all the others and all items " + "fill their available space. The horizontal and vertical gaps are set to " + "2 pixels each." + ), + + ("More Grid Features", makeGrid2, + "This is another example of the wx.GridSizer. This one has no gaps in the grid, " + "but various cells are given different alignment options and some of them " + "hold nested sizers." + ), + + ("Flexible Grid", makeGrid3, + "This grid allows the rows to have different heights and the columns to have " + "different widths. You can also specify rows and columns that are growable, " + "which we have done for the first and last row and the middle column for " + "this example.\n" + "\nThere is also a spacer in the middle cell instead of an actual window." + ), + + ("Grid with Alignment", makeGrid4, + "New alignment flags allow for the positioning of items in any corner or centered " + "position." + ), + + ("", None, ""), + + ("Proportional resize", makeSimpleBoxShaped, + "Managed items can preserve their original aspect ratio. The last item has the " + "wx.SHAPED flag set and will resize proportional to its original size." + ), + + ("Proportional resize with Alignments", makeShapes, + "This one shows various alignments as well as proportional resizing for all items." + ), + + ] +#---------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, title, sizerFunc): + wx.Frame.__init__(self, parent, -1, title) + + p = wx.Panel(self, -1) + + self.sizer = sizerFunc(p) + self.CreateStatusBar() + self.SetStatusText("Resize this frame to see how the sizers respond...") + + p.SetSizer(self.sizer) + self.sizer.Fit(p) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + self.Fit() + + def OnCloseWindow(self, event): + self.MakeModal(False) + self.Destroy() + + +#---------------------------------------------------------------------- + +class TestSelectionPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent) + + self.list = wx.ListBox(self, -1, + wx.DLG_PNT(self, 10, 10), wx.DLG_SZE(self, 100, 100), + []) + self.Bind(wx.EVT_LISTBOX, self.OnSelect, self.list) + self.Bind(wx.EVT_LISTBOX_DCLICK, self.OnDClick, self.list) + + wx.Button(self, -1, "Try it!", wx.DLG_PNT(self, 120, 10)).SetDefault() + self.Bind(wx.EVT_BUTTON, self.OnDClick) + + self.text = wx.TextCtrl(self, -1, "", + wx.DLG_PNT(self, 10, 115), + wx.DLG_SZE(self, 200, 50), + wx.TE_MULTILINE | wx.TE_READONLY) + + for item in theTests: + self.list.Append(item[0]) + + + def OnSelect(self, event): + pos = self.list.GetSelection() + self.text.SetValue(theTests[pos][2]) + + + def OnDClick(self, event): + pos = self.list.GetSelection() + title = theTests[pos][0] + func = theTests[pos][1] + + if func: + win = TestFrame(self, title, func) + win.CentreOnParent(wx.BOTH) + win.Show(True) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestSelectionPanel(nb) + return win + +overview = "" + +#---------------------------------------------------------------------- + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + +#---------------------------------------------------------------------- diff --git a/demo/Slider.py b/demo/Slider.py new file mode 100644 index 00000000..7be4bdb5 --- /dev/null +++ b/demo/Slider.py @@ -0,0 +1,48 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + self.count = 0 + + wx.StaticText(self, -1, "This is a wx.Slider.", (45, 15)) + + slider = wx.Slider( + self, 100, 25, 1, 100, (30, 60), (250, -1), + wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS + ) + + slider.SetTickFreq(5, 1) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + + +overview = """\ +A slider is a control with a handle which can be pulled back and forth to +change the value. + +In Windows versions below Windows 95, a scrollbar is used to simulate the slider. +In Windows 95, the track bar control is used. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Sound.py b/demo/Sound.py new file mode 100644 index 00000000..2a2977f7 --- /dev/null +++ b/demo/Sound.py @@ -0,0 +1,93 @@ + +import wx + +from Main import opj + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + b = wx.Button(self, -1, "Play Sound 1 (sync)", (25, 25)) + self.Bind(wx.EVT_BUTTON, self.OnButton1, b) + + b = wx.Button(self, -1, "Play Sound 2 (async)", (25, 65)) + self.Bind(wx.EVT_BUTTON, self.OnButton2, b) + + b = wx.Button(self, -1, "Select .WAV file", (25, 105)) + self.Bind(wx.EVT_BUTTON, self.OnSelectSound, b) + + + def OnButton1(self, evt): + try: + sound = wx.Sound(opj('data/anykey.wav')) + self.log.write("before Play...\n") + sound.Play(wx.SOUND_SYNC) + self.log.write("...after Play\n") + except NotImplementedError, v: + wx.MessageBox(str(v), "Exception Message") + + + def OnButton2(self, evt): + try: + if True: + sound = wx.Sound(opj('data/plan.wav')) + else: + # sounds can also be loaded from a buffer object + data = open(opj('data/plan.wav'), 'rb').read() + sound = wx.SoundFromData(data) + + self.log.write("before Play...\n") + sound.Play(wx.SOUND_ASYNC) + self.sound = sound # save a reference (This shoudln't be needed, but there seems to be a bug...) + wx.YieldIfNeeded() + self.log.write("...after Play\n") + except NotImplementedError, v: + wx.MessageBox(str(v), "Exception Message") + + + def OnSelectSound(self, evt): + dlg = wx.FileDialog(wx.GetTopLevelParent(self), + "Choose a sound file", + wildcard="WAV files (*.wav)|*.wav", + style=wx.OPEN) + if dlg.ShowModal() == wx.ID_OK: + try: + #sound = wx.Sound(dlg.GetPath(), wx.SOUND_SYNC) + #sound.Play() + + # another way to do it. + wx.Sound.PlaySound(dlg.GetPath(), wx.SOUND_SYNC) + + except NotImplementedError, v: + wx.MessageBox(str(v), "Exception Message") + dlg.Destroy() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """ +

Sound

+This class represents a short wave file, in Windows WAV format, that can +be stored in memory and played. +

+This demo offers two examples, both driven by buttons, but obviously the event +that drives the playing of the sound can come from anywhere. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/SpinButton.py b/demo/SpinButton.py new file mode 100644 index 00000000..12fb117f --- /dev/null +++ b/demo/SpinButton.py @@ -0,0 +1,61 @@ +# 11/30/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o EVT_SPIN events (or something about them) freezes up the app. +# + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + self.count = 0 + + wx.StaticText(self, -1, "This example uses the wx.SpinButton control.", (45, 15)) + + self.text = wx.TextCtrl(self, -1, "1", (30, 50), (60, -1)) + h = self.text.GetSize().height + w = self.text.GetSize().width + self.text.GetPosition().x + 2 + + self.spin = wx.SpinButton(self, -1, + (w, 50), + (h*2/3, h), + wx.SP_VERTICAL) + self.spin.SetRange(1, 100) + self.spin.SetValue(1) + + self.Bind(wx.EVT_SPIN, self.OnSpin, self.spin) + + + def OnSpin(self, event): + self.text.SetValue(str(event.GetPosition())) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ +A wx.SpinButton has two small up and down (or left and right) arrow buttons. +It is often used next to a text control for increment and decrementing a value. +Portable programs should try to use wx.SpinCtrl instead as wx.SpinButton is not +implemented for all platforms (Win32 and GTK only currently). + +NB: the range supported by this control (and wx.SpinCtrl) depends on the platform +but is at least -0x8000 to 0x7fff. Under GTK and Win32 with sufficiently new version +of comctrl32.dll (at least 4.71 is required, 5.80 is recommended) the full 32 bit +range is supported. + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/SpinCtrl.py b/demo/SpinCtrl.py new file mode 100644 index 00000000..b110ab0d --- /dev/null +++ b/demo/SpinCtrl.py @@ -0,0 +1,55 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + wx.StaticText(self, -1, "This example uses the wx.SpinCtrl control.", (45, 15)) + sc = wx.SpinCtrl(self, -1, "", (30, 50)) + sc.SetRange(1,100) + sc.SetValue(5) + self.sc = sc + + self.Bind(wx.EVT_SPINCTRL, self.OnSpin, sc) + self.Bind(wx.EVT_TEXT, self.OnText, sc) + + + def OnSpin(self, evt): + self.log.write('OnSpin: %d\n' % self.sc.GetValue()) + + def OnText(self, evt): + self.log.write('OnText: %d\n' % self.sc.GetValue()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = """\ +wx.SpinCtrl combines wx.TextCtrl and wx.SpinButton in one control. + +Portable programs should try to use this control as wx.SpinButton is not +implemented for all platforms (Win32 and GTK only currently). + +NB: the range supported by this control depends on the platform +but is at least -0x8000 to 0x7fff. Under GTK and Win32 with sufficiently new version +of comctrl32.dll (at least 4.71 is required, 5.80 is recommended) the full 32 bit +range is supported. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/SpinCtrlDouble.py b/demo/SpinCtrlDouble.py new file mode 100644 index 00000000..bf608bc1 --- /dev/null +++ b/demo/SpinCtrlDouble.py @@ -0,0 +1,41 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + wx.StaticText(self, -1, "wx.SpinCtrlDouble:", pos=(25,25)) + spin = wx.SpinCtrlDouble(self, value='0.00', pos=(75,50), size=(80,-1), + min=-5.0, max=25.25, inc=0.25) + spin.SetDigits(2) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.SpinCtrlDouble

+ +Essentially the same as a wx.SpinCtrl, except it can handle floating +point numbers, and fractional increments. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/SplitTree.py b/demo/SplitTree.py new file mode 100644 index 00000000..2e95db5b --- /dev/null +++ b/demo/SplitTree.py @@ -0,0 +1,145 @@ +# 11/13/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Updated for wx namespace +# +# 11/26/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Bigtime errors on startup. Blows up with a program error. +# Error: +# +# 21:04:11: Debug: ..\..\src\msw\treectrl.cpp(1508): assert "IsVisible(item)" +# failed: The item you call GetNextVisible() for must be visible itself! +# +# I suspect this error is in the lib itself. +# + +import wx +import wx.gizmos as gizmos + + +#---------------------------------------------------------------------- + +class TestTree(gizmos.RemotelyScrolledTreeCtrl): + def __init__(self, parent, style=wx.TR_HAS_BUTTONS): + gizmos.RemotelyScrolledTreeCtrl.__init__(self, parent, -1, style=style) + + # make an image list + im1 = im2 = -1 + self.il = wx.ImageList(16, 16) + im1 = self.il.Add(wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_TOOLBAR, (16,16))) + im2 = self.il.Add(wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_TOOLBAR, (16,16))) + self.SetImageList(self.il) + + # Add some items + root = self.AddRoot("Root") + + for i in range(30): + item = self.AppendItem(root, "Item %d" % i, im1) + + for j in range(10): + child = self.AppendItem(item, "Child %d" % j, im2) + + self.Expand(root) + + + +class TestValueWindow(gizmos.TreeCompanionWindow): + def __init__(self, parent, style=0): + gizmos.TreeCompanionWindow.__init__(self, parent, -1, style=style) + self.SetBackgroundColour("WHITE") + + # This method is called to draw each item in the value window + def DrawItem(self, dc, itemId, rect): + tree = self.GetTreeCtrl() + + if tree: + text = "This is " + parent = tree.GetItemParent(itemId) + + if parent.IsOk(): + ptext = tree.GetItemText(parent) + text = text + ptext + " --> " + + text = text + tree.GetItemText(itemId) + pen = wx.Pen( + wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DLIGHT), + 1, wx.SOLID + ) + + dc.SetPen(pen) + dc.SetBrush(wx.Brush(self.GetBackgroundColour(), wx.SOLID)) + dc.DrawRectangle(rect.x, rect.y, rect.width+1, rect.height+1) + dc.SetTextForeground("BLACK") + dc.SetBackgroundMode(wx.TRANSPARENT) + tw, th = dc.GetTextExtent(text) + x = 5 + y = rect.y + max(0, (rect.height - th) / 2) + dc.DrawText(text, x, y) + + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1, size=(640,480)) + self.log = log + + scroller = gizmos.SplitterScrolledWindow( + self, -1, style=wx.NO_BORDER | wx.CLIP_CHILDREN | wx.VSCROLL + ) + + splitter = gizmos.ThinSplitterWindow( + scroller, -1, style=wx.SP_3DBORDER | wx.CLIP_CHILDREN + ) + + splitter.SetSashSize(2) + tree = TestTree(splitter, style = wx.TR_HAS_BUTTONS | + wx.TR_NO_LINES | + wx.TR_ROW_LINES | + #wx.TR_HIDE_ROOT | + wx.NO_BORDER ) + + valueWindow = TestValueWindow(splitter, style=wx.NO_BORDER) + + wx.CallAfter(splitter.SplitVertically, tree, valueWindow, 150) + scroller.SetTargetWindow(tree) + scroller.EnableScrolling(False, False) + + valueWindow.SetTreeCtrl(tree) + tree.SetCompanionWindow(valueWindow) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(scroller, 1, wx.EXPAND|wx.ALL, 25) + self.SetSizer(sizer) + self.Layout() + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + if wx.Platform == "__WXMAC__": + from wx.lib.msgpanel import MessagePanel + win = MessagePanel(nb, 'This demo currently fails on the Mac. The problem is being looked into...', + 'Sorry', wx.ICON_WARNING) + return win + + win = TestPanel(nb, log) + return win + + +#---------------------------------------------------------------------- + + +overview = """\ +This demo shows a collection of classes that were designed to operate +together and provide a tree control with additional columns for each +item. The classes are wx.RemotelyScrolledTreeCtrl, wx.TreeCompanionWindow, +wx.ThinSplitterWindow, and wx.SplitterScrolledWindow, some of which may +also be useful by themselves. +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/SplitterWindow.py b/demo/SplitterWindow.py new file mode 100644 index 00000000..dafc4600 --- /dev/null +++ b/demo/SplitterWindow.py @@ -0,0 +1,61 @@ + +import wx + +#--------------------------------------------------------------------------- + +class MySplitter(wx.SplitterWindow): + def __init__(self, parent, ID, log): + wx.SplitterWindow.__init__(self, parent, ID, + style = wx.SP_LIVE_UPDATE + ) + self.log = log + + self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged) + self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging) + + def OnSashChanged(self, evt): + self.log.WriteText("sash changed to %s\n" % str(evt.GetSashPosition())) + + def OnSashChanging(self, evt): + self.log.WriteText("sash changing to %s\n" % str(evt.GetSashPosition())) + # uncomment this to not allow the change + #evt.SetSashPosition(-1) + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + splitter = MySplitter(nb, -1, log) + + #sty = wx.BORDER_NONE + #sty = wx.BORDER_SIMPLE + sty = wx.BORDER_SUNKEN + + p1 = wx.Window(splitter, style=sty) + p1.SetBackgroundColour("pink") + wx.StaticText(p1, -1, "Panel One", (5,5)) + + p2 = wx.Window(splitter, style=sty) + p2.SetBackgroundColour("sky blue") + wx.StaticText(p2, -1, "Panel Two", (5,5)) + + splitter.SetMinimumPaneSize(20) + splitter.SplitVertically(p1, p2, -100) + + return splitter + + +#--------------------------------------------------------------------------- + + +overview = """\ +This class manages up to two subwindows. The current view can be split +into two programmatically (perhaps from a menu command), and unsplit +either programmatically or via the wx.SplitterWindow user interface. +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/StandardPaths.py b/demo/StandardPaths.py new file mode 100644 index 00000000..a3a7fed6 --- /dev/null +++ b/demo/StandardPaths.py @@ -0,0 +1,112 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + sizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5) + sizer.AddGrowableCol(1) + box = wx.BoxSizer(wx.VERTICAL) + fs = self.GetFont().GetPointSize() + bf = wx.Font(fs+4, wx.SWISS, wx.NORMAL, wx.BOLD) + + t = wx.StaticText(self, -1, "StandardPaths") + t.SetFont(bf) + box.Add(t, 0, wx.CENTER|wx.ALL, 4) + box.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) + + # get the global (singleton) instance of wx.StandardPaths + sp = wx.StandardPaths.Get() + + # StandardPaths will use the value of wx.App().GetAppName() + # for some of the stnadard path components. Let's set it to + # something that makes that obvious for the demo. In your own + # apps you'll set it in to something more meaningfull for your + # app in your OnInit, (or just let it default.) + wx.GetApp().SetAppName("AppName") + + self.help = {} + + # Loop through all of the getters in wx.StandardPaths and make + # a set of items in the sizer for each. + def makeitem(name, *args): + func = getattr(sp, name) + sizer.Add(wx.StaticText(self, -1, "%s%s:" %(name, repr(args))), + 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + sizer.Add(wx.TextCtrl(self, -1, func(*args), + size=(275,-1), style=wx.TE_READONLY), + 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL) + + btn = wx.Button(self, wx.ID_HELP) + sizer.Add(btn) + self.help[btn] = func.__doc__ + + for x in ['GetConfigDir', + 'GetUserConfigDir', + 'GetDataDir', + 'GetLocalDataDir', + 'GetUserDataDir', + 'GetUserLocalDataDir', + 'GetDocumentsDir', + 'GetAppDocumentsDir', + 'GetPluginsDir', + 'GetInstallPrefix', + 'GetResourcesDir', + 'GetTempDir', + 'GetExecutablePath', + ]: + makeitem(x) + + # this one needs parameters + makeitem('GetLocalizedResourcesDir', 'en', + wx.StandardPaths.ResourceCat_Messages ) + + self.Bind(wx.EVT_BUTTON, self.OnShowDoc, id=wx.ID_HELP) + + box.Add(sizer, 0, wx.CENTER|wx.EXPAND|wx.ALL, 20) + self.SetSizer(box) + + + def OnShowDoc(self, evt): + doc = self.help[evt.GetEventObject()] + + # trim the whitespace from each line + lines = [] + for line in doc.split('\n'): + lines.append(line.strip()) + doc = '\n'.join(lines) + wx.TipWindow(self, doc, 500) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

StandardPaths

+ +wxWidgets provides this class to simply determine where to locate +certain types of files in a platform specific manner. This includes +things like configuration files, general data files writeable by the +user, and application files that are shared by all user. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/StaticBitmap.py b/demo/StaticBitmap.py new file mode 100644 index 00000000..968e3659 --- /dev/null +++ b/demo/StaticBitmap.py @@ -0,0 +1,55 @@ + +import wx +import images + + +USE_GENERIC = 0 + +if USE_GENERIC: + from wx.lib.stattext import GenStaticText as StaticText + from wx.lib.statbmp import GenStaticBitmap as StaticBitmap +else: + StaticText = wx.StaticText + StaticBitmap = wx.StaticBitmap + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + ##self.SetBackgroundColour("sky blue") + + StaticText(self, -1, "This is a wx.StaticBitmap.", (45, 15)) + + bmp = images.Test2.GetBitmap() + mask = wx.Mask(bmp, wx.BLUE) + bmp.SetMask(mask) + StaticBitmap(self, -1, bmp, (80, 50), (bmp.GetWidth(), bmp.GetHeight())) + + bmp = images.Robin.GetBitmap() + StaticBitmap(self, -1, bmp, (80, 150)) + + StaticText(self, -1, "Hey, if Ousterhout can do it, so can I.", (200, 175)) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = """\ +A StaticBitmap control displays a bitmap. + +A bitmap can be derived from most image formats using the wx.Image class. + +""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/StaticBox.py b/demo/StaticBox.py new file mode 100644 index 00000000..f4ab8934 --- /dev/null +++ b/demo/StaticBox.py @@ -0,0 +1,47 @@ + +import wx + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + box = wx.StaticBox(self, -1, "This is a wx.StaticBox") + bsizer = wx.StaticBoxSizer(box, wx.VERTICAL) + + t = wx.StaticText(self, -1, "Controls placed \"inside\" the box are really its siblings") + bsizer.Add(t, 0, wx.TOP|wx.LEFT, 10) + + + border = wx.BoxSizer() + border.Add(bsizer, 1, wx.EXPAND|wx.ALL, 25) + self.SetSizer(border) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.StaticBox

+ +This control draws a box and can be used to group other controls. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/StaticText.py b/demo/StaticText.py new file mode 100644 index 00000000..52b738ee --- /dev/null +++ b/demo/StaticText.py @@ -0,0 +1,68 @@ + +import wx + + +USE_GENERIC = 0 + +if USE_GENERIC: + from wx.lib.stattext import GenStaticText as StaticText +else: + StaticText = wx.StaticText + + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, -1) + ##self.SetBackgroundColour("sky blue") + + StaticText(self, -1, "This is an example of static text", (20, 10)) + StaticText(self, -1, "using the wx.StaticText Control.", (20, 30)) + + StaticText( + self, -1, "Is this yellow?", (20, 70), (120, -1) + ).SetBackgroundColour('Yellow') + + StaticText( + self, -1, "align center", (160, 70), (120, -1), wx.ALIGN_CENTER + ).SetBackgroundColour('Yellow') + + StaticText( + self, -1, "align right", (300, 70), (120, -1), wx.ALIGN_RIGHT + ).SetBackgroundColour('Yellow') + + str = "This is a different font." + text = StaticText(self, -1, str, (20, 120)) + font = wx.Font(18, wx.SWISS, wx.NORMAL, wx.NORMAL) + text.SetFont(font) + + StaticText(self, -1, + "Multi-line wx.StaticText\nline 2\nline 3\n\nafter empty line", + (20,170)) + StaticText(self, -1, + "Align right multi-line\nline 2\nline 3\n\nafter empty line", + (220,170), style=wx.ALIGN_RIGHT) + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + panel = TestPanel(nb) + return panel + + +#--------------------------------------------------------------------------- + + +overview = '''\ +A StaticText control displays one or more lines of read-only text. + +''' + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/StatusBar.py b/demo/StatusBar.py new file mode 100644 index 00000000..3f218842 --- /dev/null +++ b/demo/StatusBar.py @@ -0,0 +1,140 @@ + +import time +import wx + +#--------------------------------------------------------------------------- + +class CustomStatusBar(wx.StatusBar): + def __init__(self, parent, log): + wx.StatusBar.__init__(self, parent, -1) + + # This status bar has three fields + self.SetFieldsCount(3) + # Sets the three fields to be relative widths to each other. + self.SetStatusWidths([-2, -1, -2]) + self.log = log + self.sizeChanged = False + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_IDLE, self.OnIdle) + + # Field 0 ... just text + self.SetStatusText("A Custom StatusBar...", 0) + + # This will fall into field 1 (the second field) + self.cb = wx.CheckBox(self, 1001, "toggle clock") + self.Bind(wx.EVT_CHECKBOX, self.OnToggleClock, self.cb) + self.cb.SetValue(True) + + # set the initial position of the checkbox + self.Reposition() + + # We're going to use a timer to drive a 'clock' in the last + # field. + self.timer = wx.PyTimer(self.Notify) + self.timer.Start(1000) + self.Notify() + + + # Handles events from the timer we started in __init__(). + # We're using it to drive a 'clock' in field 2 (the third field). + def Notify(self): + t = time.localtime(time.time()) + st = time.strftime("%d-%b-%Y %I:%M:%S", t) + self.SetStatusText(st, 2) + self.log.WriteText("tick...\n") + + + # the checkbox was clicked + def OnToggleClock(self, event): + if self.cb.GetValue(): + self.timer.Start(1000) + self.Notify() + else: + self.timer.Stop() + + + def OnSize(self, evt): + evt.Skip() + self.Reposition() # for normal size events + + # Set a flag so the idle time handler will also do the repositioning. + # It is done this way to get around a buglet where GetFieldRect is not + # accurate during the EVT_SIZE resulting from a frame maximize. + self.sizeChanged = True + + + def OnIdle(self, evt): + if self.sizeChanged: + self.Reposition() + + + # reposition the checkbox + def Reposition(self): + rect = self.GetFieldRect(1) + rect.x += 1 + rect.y += 1 + self.cb.SetRect(rect) + self.sizeChanged = False + + + +class TestCustomStatusBar(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, 'Test Custom StatusBar') + + self.sb = CustomStatusBar(self, log) + self.SetStatusBar(self.sb) + tc = wx.TextCtrl(self, -1, "", style=wx.TE_READONLY|wx.TE_MULTILINE) + + self.SetSize((640, 480)) + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + def OnCloseWindow(self, event): + self.sb.timer.Stop() + del self.sb.timer + self.Destroy() + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show the StatusBar sample", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = TestCustomStatusBar(self, self.log) + win.Show(True) + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = """\ +A status bar is a narrow window that can be placed along the bottom of +a frame to give small amounts of status information. It can contain +one or more fields, one or more of which can be variable length +according to the size of the window. + +This example demonstrates how to create a custom status bar with actual +gadgets embedded in it. In this case, the first field is just plain text, +The second one has a checkbox that enables the timer, and the third +field has a clock that shows the current time when it is enabled. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/StockButtons.py b/demo/StockButtons.py new file mode 100644 index 00000000..59957a7c --- /dev/null +++ b/demo/StockButtons.py @@ -0,0 +1,112 @@ + +import wx + +#---------------------------------------------------------------------- + + +stockIDs = [ + wx.ID_ABOUT, + wx.ID_ADD, + wx.ID_APPLY, + wx.ID_BOLD, + wx.ID_CANCEL, + wx.ID_CLEAR, + wx.ID_CLOSE, + wx.ID_COPY, + wx.ID_CUT, + wx.ID_DELETE, + wx.ID_EDIT, + wx.ID_FIND, + wx.ID_FILE, + wx.ID_REPLACE, + wx.ID_BACKWARD, + wx.ID_DOWN, + wx.ID_FORWARD, + wx.ID_UP, + wx.ID_HELP, + wx.ID_HOME, + wx.ID_INDENT, + wx.ID_INDEX, + wx.ID_ITALIC, + wx.ID_JUSTIFY_CENTER, + wx.ID_JUSTIFY_FILL, + wx.ID_JUSTIFY_LEFT, + wx.ID_JUSTIFY_RIGHT, + wx.ID_NEW, + wx.ID_NO, + wx.ID_OK, + wx.ID_OPEN, + wx.ID_PASTE, + wx.ID_PREFERENCES, + wx.ID_PRINT, + wx.ID_PREVIEW, + wx.ID_PROPERTIES, + wx.ID_EXIT, + wx.ID_REDO, + wx.ID_REFRESH, + wx.ID_REMOVE, + wx.ID_REVERT_TO_SAVED, + wx.ID_SAVE, + wx.ID_SAVEAS, + wx.ID_SELECTALL, + wx.ID_STOP, + wx.ID_UNDELETE, + wx.ID_UNDERLINE, + wx.ID_UNDO, + wx.ID_UNINDENT, + wx.ID_YES, + wx.ID_ZOOM_100, + wx.ID_ZOOM_FIT, + wx.ID_ZOOM_IN, + wx.ID_ZOOM_OUT, + + ] + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + sizer = wx.FlexGridSizer(cols=5, hgap=4, vgap=4) + for ID in stockIDs: + b = wx.Button(self, ID) + sizer.Add(b) + + self.SetSizer(sizer) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Stock Buttons

+ +It is now possible to create \"stock\" buttons. Basically this means +that you only have to provide one of the stock IDs (and an empty +label) when creating the button and wxWidgets will choose the stock +label to go with it automatically. Additionally on the platforms that +have a native concept of a stock button (currently only GTK2) then the +native stock button will be used. + +

This sample shows buttons for all of the currenlty available stock +IDs. Notice that when the button is created that no label is given, +and compare that with the button that is created. + + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/StyledTextCtrl_1.py b/demo/StyledTextCtrl_1.py new file mode 100644 index 00000000..c0c19a59 --- /dev/null +++ b/demo/StyledTextCtrl_1.py @@ -0,0 +1,320 @@ +# +# 11/21/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o wx.TheClipboard.Flush() generates a warning on program exit. +# + +import wx +import wx.stc as stc + +import images + +#---------------------------------------------------------------------- + +debug = 1 + + +demoText = """\ +This editor is provided by a class named wx.StyledTextCtrl. As +the name suggests, you can define styles that can be applied to +sections of text. This will typically be used for things like +syntax highlighting code editors, but I'm sure that there are other +applications as well. A style is a combination of font, point size, +foreground and background colours. The editor can handle +proportional fonts just as easily as monospaced fonts, and various +styles can use different sized fonts. + +There are a few canned language lexers and colourizers included, +(see the next demo) or you can handle the colourization yourself. +If you do you can simply register an event handler and the editor +will let you know when the visible portion of the text needs +styling. + +wx.StyledTextCtrl also supports setting markers in the margin... + + + + +...and indicators within the text. You can use these for whatever +you want in your application. Cut, Copy, Paste, Drag and Drop of +text works, as well as virtually unlimited Undo and Redo +capabilities, (right click to try it out.) +""" + +if wx.Platform == '__WXMSW__': + face1 = 'Arial' + face2 = 'Times New Roman' + face3 = 'Courier New' + pb = 10 +else: + face1 = 'Helvetica' + face2 = 'Times' + face3 = 'Courier' + pb = 12 + + +#---------------------------------------------------------------------- +# This shows how to catch the Modified event from the wx.StyledTextCtrl + +class MySTC(stc.StyledTextCtrl): + def __init__(self, parent, ID, log): + stc.StyledTextCtrl.__init__(self, parent, ID) + self.log = log + + self.Bind(stc.EVT_STC_DO_DROP, self.OnDoDrop) + self.Bind(stc.EVT_STC_DRAG_OVER, self.OnDragOver) + self.Bind(stc.EVT_STC_START_DRAG, self.OnStartDrag) + self.Bind(stc.EVT_STC_MODIFIED, self.OnModified) + + self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) + + def OnDestroy(self, evt): + # This is how the clipboard contents can be preserved after + # the app has exited. + wx.TheClipboard.Flush() + evt.Skip() + + + def OnStartDrag(self, evt): + self.log.write("OnStartDrag: %d, %s\n" + % (evt.GetDragAllowMove(), evt.GetDragText())) + + if debug and evt.GetPosition() < 250: + evt.SetDragAllowMove(False) # you can prevent moving of text (only copy) + evt.SetDragText("DRAGGED TEXT") # you can change what is dragged + #evt.SetDragText("") # or prevent the drag with empty text + + + def OnDragOver(self, evt): + self.log.write( + "OnDragOver: x,y=(%d, %d) pos: %d DragResult: %d\n" + % (evt.GetX(), evt.GetY(), evt.GetPosition(), evt.GetDragResult()) + ) + + if debug and evt.GetPosition() < 250: + evt.SetDragResult(wx.DragNone) # prevent dropping at the beginning of the buffer + + + def OnDoDrop(self, evt): + self.log.write("OnDoDrop: x,y=(%d, %d) pos: %d DragResult: %d\n" + "\ttext: %s\n" + % (evt.GetX(), evt.GetY(), evt.GetPosition(), evt.GetDragResult(), + evt.GetDragText())) + + if debug and evt.GetPosition() < 500: + evt.SetDragText("DROPPED TEXT") # Can change text if needed + #evt.SetDragResult(wx.DragNone) # Can also change the drag operation, but it + # is probably better to do it in OnDragOver so + # there is visual feedback + + #evt.SetPosition(25) # Can also change position, but I'm not sure why + # you would want to... + + + + + def OnModified(self, evt): + self.log.write("""OnModified + Mod type: %s + At position: %d + Lines added: %d + Text Length: %d + Text: %s\n""" % ( self.transModType(evt.GetModificationType()), + evt.GetPosition(), + evt.GetLinesAdded(), + evt.GetLength(), + repr(evt.GetText()) )) + + + def transModType(self, modType): + st = "" + table = [(stc.STC_MOD_INSERTTEXT, "InsertText"), + (stc.STC_MOD_DELETETEXT, "DeleteText"), + (stc.STC_MOD_CHANGESTYLE, "ChangeStyle"), + (stc.STC_MOD_CHANGEFOLD, "ChangeFold"), + (stc.STC_PERFORMED_USER, "UserFlag"), + (stc.STC_PERFORMED_UNDO, "Undo"), + (stc.STC_PERFORMED_REDO, "Redo"), + (stc.STC_LASTSTEPINUNDOREDO, "Last-Undo/Redo"), + (stc.STC_MOD_CHANGEMARKER, "ChangeMarker"), + (stc.STC_MOD_BEFOREINSERT, "B4-Insert"), + (stc.STC_MOD_BEFOREDELETE, "B4-Delete") + ] + + for flag,text in table: + if flag & modType: + st = st + text + " " + + if not st: + st = 'UNKNOWN' + + return st + + + + +#---------------------------------------------------------------------- + +_USE_PANEL = 1 + +def runTest(frame, nb, log): + if not _USE_PANEL: + ed = p = MySTC(nb, -1, log) + + else: + p = wx.Panel(nb, -1, style=wx.NO_FULL_REPAINT_ON_RESIZE) + ed = MySTC(p, -1, log) + s = wx.BoxSizer(wx.HORIZONTAL) + s.Add(ed, 1, wx.EXPAND) + p.SetSizer(s) + p.SetAutoLayout(True) + + + #ed.SetBufferedDraw(False) + #ed.StyleClearAll() + #ed.SetScrollWidth(800) + #ed.SetWrapMode(True) + #ed.SetUseAntiAliasing(False) + #ed.SetViewEOL(True) + + #ed.CmdKeyClear(stc.STC_KEY_BACK, + # stc.STC_SCMOD_CTRL) + #ed.CmdKeyAssign(stc.STC_KEY_BACK, + # stc.STC_SCMOD_CTRL, + # stc.STC_CMD_DELWORDLEFT) + + ed.SetText(demoText) + + if wx.USE_UNICODE: + import codecs + decode = codecs.lookup("utf-8")[1] + + ed.GotoPos(ed.GetLength()) + ed.AddText("\n\nwx.StyledTextCtrl can also do Unicode:\n") + uniline = ed.GetCurrentLine() + unitext, l = decode('\xd0\x9f\xd0\xb8\xd1\x82\xd0\xbe\xd0\xbd - ' + '\xd0\xbb\xd1\x83\xd1\x87\xd1\x88\xd0\xb8\xd0\xb9 ' + '\xd1\x8f\xd0\xb7\xd1\x8b\xd0\xba \xd0\xbf\xd1\x80\xd0\xbe\xd0\xb3\xd1\x80\xd0\xb0\xd0\xbc\xd0\xbc\xd0\xb8\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb0\xd0\xbd\xd0\xb8\xd1\x8f!\n\n') + ed.AddText('\tRussian: ') + ed.AddText(unitext) + ed.GotoPos(0) + #else: + # #ed.StyleSetFontEncoding(stc.STC_STYLE_DEFAULT, wx.FONTENCODING_KOI8) + # #text = u'\u041f\u0438\u0442\u043e\u043d - \u043b\u0443\u0447\u0448\u0438\u0439 \u044f\u0437\u044b\u043a \n\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f!' + # #text = text.encode('koi8-r') + # #ed.StyleSetFontEncoding(stc.STC_STYLE_DEFAULT, wx.FONTENCODING_BIG5) + # #text = u'Python \u662f\u6700\u597d\u7684\u7de8\u7a0b\u8a9e\u8a00\uff01' + # #text = text.encode('big5') + # ed.GotoPos(ed.GetLength()) + # ed.AddText('\n\n' + text) + + ed.EmptyUndoBuffer() + + # make some styles + ed.StyleSetSpec(stc.STC_STYLE_DEFAULT, "size:%d,face:%s" % (pb, face3)) + ed.StyleClearAll() + ed.StyleSetSpec(1, "size:%d,bold,face:%s,fore:#0000FF" % (pb, face1)) + ed.StyleSetSpec(2, "face:%s,italic,fore:#FF0000,size:%d" % (face2, pb)) + ed.StyleSetSpec(3, "face:%s,bold,size:%d" % (face2, pb)) + ed.StyleSetSpec(4, "face:%s,size:%d" % (face1, pb-1)) + ed.StyleSetSpec(5, "back:#FFF0F0") + + # Now set some text to those styles... Normally this would be + # done in an event handler that happens when text needs displayed. + ed.StartStyling(98, 0xff) + ed.SetStyling(6, 1) # set style for 6 characters using style 1 + + ed.StartStyling(190, 0xff) + ed.SetStyling(20, 2) + + ed.StartStyling(310, 0xff) + ed.SetStyling(4, 3) + ed.SetStyling(2, 0) + ed.SetStyling(10, 4) + + + # line numbers in the margin + ed.SetMarginType(0, stc.STC_MARGIN_NUMBER) + ed.SetMarginWidth(0, 22) + ed.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "size:%d,face:%s" % (pb-2, face1)) + + # setup some markers + ed.SetMarginType(1, stc.STC_MARGIN_SYMBOL) + ed.MarkerDefine(0, stc.STC_MARK_ROUNDRECT, "#CCFF00", "RED") + ed.MarkerDefine(1, stc.STC_MARK_CIRCLE, "FOREST GREEN", "SIENNA") + ed.MarkerDefine(2, stc.STC_MARK_SHORTARROW, "blue", "blue") + ed.MarkerDefine(3, stc.STC_MARK_ARROW, "#00FF00", "#00FF00") + + # put some markers on some lines + ed.MarkerAdd(17, 0) + ed.MarkerAdd(18, 1) + ed.MarkerAdd(19, 2) + ed.MarkerAdd(20, 3) + ed.MarkerAdd(20, 0) + + + # and an indicator or two + ed.IndicatorSetStyle(0, stc.STC_INDIC_SQUIGGLE) + ed.IndicatorSetForeground(0, wx.RED) + ed.IndicatorSetStyle(1, stc.STC_INDIC_DIAGONAL) + ed.IndicatorSetForeground(1, wx.BLUE) + ed.IndicatorSetStyle(2, stc.STC_INDIC_STRIKE) + ed.IndicatorSetForeground(2, wx.RED) + + ed.StartStyling(836, stc.STC_INDICS_MASK) + ed.SetStyling(10, stc.STC_INDIC0_MASK) + ed.SetStyling(8, stc.STC_INDIC1_MASK) + ed.SetStyling(10, stc.STC_INDIC2_MASK | stc.STC_INDIC1_MASK) + + # add some annotations + ed.AnnotationSetText(23, "\nThis is an annotaion, it is not part of \nthe document's text.\n") + ed.AnnotationSetVisible(stc.STC_ANNOTATION_BOXED) + ed.AnnotationSetStyle(23, 5) # line number, style number + + # some test stuff... + if debug: + print "GetTextLength(): ", ed.GetTextLength(), len(ed.GetText()) + print "GetText(): ", repr(ed.GetText()) + print + print "GetStyledText(98, 104): ", repr(ed.GetStyledText(98, 104)), len(ed.GetStyledText(98, 104)) + print + print "GetCurLine(): ", repr(ed.GetCurLine()) + ed.GotoPos(5) + print "GetCurLine(): ", repr(ed.GetCurLine()) + print + print "GetLine(1): ", repr(ed.GetLine(1)) + print + ed.SetSelection(25, 35) + print "GetSelectedText(): ", repr(ed.GetSelectedText()) + print "GetTextRange(25, 35): ", repr(ed.GetTextRange(25, 35)) + print "FindText(0, max, 'indicators'): ", + print ed.FindText(0, ed.GetTextLength(), "indicators") + if wx.USE_UNICODE: + end = ed.GetLength() + start = ed.PositionFromLine(uniline) + print "GetTextRange(%d, %d): " % (start, end), + print repr(ed.GetTextRange(start, end)) + + + wx.CallAfter(ed.GotoPos, 0) + return p + + + +#---------------------------------------------------------------------- + + +overview = """\ + +Once again, no docs yet. Sorry. But this +and this should +be helpful. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/StyledTextCtrl_2.py b/demo/StyledTextCtrl_2.py new file mode 100644 index 00000000..7926e07c --- /dev/null +++ b/demo/StyledTextCtrl_2.py @@ -0,0 +1,409 @@ + +import keyword + +import wx +import wx.stc as stc + +import images + +#---------------------------------------------------------------------- + +demoText = """\ +## This version of the editor has been set up to edit Python source +## code. Here is a copy of wxPython/demo/Main.py to play with. + + +""" + +#---------------------------------------------------------------------- + + +if wx.Platform == '__WXMSW__': + faces = { 'times': 'Times New Roman', + 'mono' : 'Courier New', + 'helv' : 'Arial', + 'other': 'Comic Sans MS', + 'size' : 10, + 'size2': 8, + } +elif wx.Platform == '__WXMAC__': + faces = { 'times': 'Times New Roman', + 'mono' : 'Monaco', + 'helv' : 'Arial', + 'other': 'Comic Sans MS', + 'size' : 12, + 'size2': 10, + } +else: + faces = { 'times': 'Times', + 'mono' : 'Courier', + 'helv' : 'Helvetica', + 'other': 'new century schoolbook', + 'size' : 12, + 'size2': 10, + } + + +#---------------------------------------------------------------------- + +class PythonSTC(stc.StyledTextCtrl): + + fold_symbols = 2 + + def __init__(self, parent, ID, + pos=wx.DefaultPosition, size=wx.DefaultSize, + style=0): + stc.StyledTextCtrl.__init__(self, parent, ID, pos, size, style) + + self.CmdKeyAssign(ord('B'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMIN) + self.CmdKeyAssign(ord('N'), stc.STC_SCMOD_CTRL, stc.STC_CMD_ZOOMOUT) + + self.SetLexer(stc.STC_LEX_PYTHON) + self.SetKeyWords(0, " ".join(keyword.kwlist)) + + self.SetProperty("fold", "1") + self.SetProperty("tab.timmy.whinge.level", "1") + self.SetMargins(0,0) + + self.SetViewWhiteSpace(False) + #self.SetBufferedDraw(False) + #self.SetViewEOL(True) + #self.SetEOLMode(stc.STC_EOL_CRLF) + #self.SetUseAntiAliasing(True) + + self.SetEdgeMode(stc.STC_EDGE_BACKGROUND) + self.SetEdgeColumn(78) + + # Setup a margin to hold fold markers + #self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER? + self.SetMarginType(2, stc.STC_MARGIN_SYMBOL) + self.SetMarginMask(2, stc.STC_MASK_FOLDERS) + self.SetMarginSensitive(2, True) + self.SetMarginWidth(2, 12) + + if self.fold_symbols == 0: + # Arrow pointing right for contracted folders, arrow pointing down for expanded + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_ARROWDOWN, "black", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_ARROW, "black", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "black", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "black", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") + + elif self.fold_symbols == 1: + # Plus for contracted folders, minus for expanded + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_MINUS, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_PLUS, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_EMPTY, "white", "black") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_EMPTY, "white", "black") + + elif self.fold_symbols == 2: + # Like a flattened tree control using circular headers and curved joins + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_CIRCLEMINUS, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_CIRCLEPLUS, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNERCURVE, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_CIRCLEPLUSCONNECTED, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_CIRCLEMINUSCONNECTED, "white", "#404040") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNERCURVE, "white", "#404040") + + elif self.fold_symbols == 3: + # Like a flattened tree control using square headers + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPEN, stc.STC_MARK_BOXMINUS, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDER, stc.STC_MARK_BOXPLUS, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERSUB, stc.STC_MARK_VLINE, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERTAIL, stc.STC_MARK_LCORNER, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEREND, stc.STC_MARK_BOXPLUSCONNECTED, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDEROPENMID, stc.STC_MARK_BOXMINUSCONNECTED, "white", "#808080") + self.MarkerDefine(stc.STC_MARKNUM_FOLDERMIDTAIL, stc.STC_MARK_TCORNER, "white", "#808080") + + + self.Bind(stc.EVT_STC_UPDATEUI, self.OnUpdateUI) + self.Bind(stc.EVT_STC_MARGINCLICK, self.OnMarginClick) + self.Bind(wx.EVT_KEY_DOWN, self.OnKeyPressed) + + # Make some styles, The lexer defines what each style is used for, we + # just have to define what each style looks like. This set is adapted from + # Scintilla sample property files. + + # Global default styles for all languages + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces) + self.StyleClearAll() # Reset all to be like the default + + # Global default styles for all languages + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces) + self.StyleSetSpec(stc.STC_STYLE_LINENUMBER, "back:#C0C0C0,face:%(helv)s,size:%(size2)d" % faces) + self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces) + self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold") + self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") + + # Python styles + # Default + self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces) + # Comments + self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces) + # Number + self.StyleSetSpec(stc.STC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces) + # String + self.StyleSetSpec(stc.STC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces) + # Single quoted string + self.StyleSetSpec(stc.STC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces) + # Keyword + self.StyleSetSpec(stc.STC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces) + # Triple quotes + self.StyleSetSpec(stc.STC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces) + # Triple double quotes + self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces) + # Class name definition + self.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces) + # Function or method name definition + self.StyleSetSpec(stc.STC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces) + # Operators + self.StyleSetSpec(stc.STC_P_OPERATOR, "bold,size:%(size)d" % faces) + # Identifiers + self.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces) + # Comment-blocks + self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces) + # End of line where string is not closed + self.StyleSetSpec(stc.STC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces) + + self.SetCaretForeground("BLUE") + + + # register some images for use in the AutoComplete box. + self.RegisterImage(1, images.Smiles.GetBitmap()) + self.RegisterImage(2, + wx.ArtProvider.GetBitmap(wx.ART_NEW, size=(16,16))) + self.RegisterImage(3, + wx.ArtProvider.GetBitmap(wx.ART_COPY, size=(16,16))) + + + def OnKeyPressed(self, event): + if self.CallTipActive(): + self.CallTipCancel() + key = event.GetKeyCode() + + if key == 32 and event.ControlDown(): + pos = self.GetCurrentPos() + + # Tips + if event.ShiftDown(): + self.CallTipSetBackground("yellow") + self.CallTipShow(pos, 'lots of of text: blah, blah, blah\n\n' + 'show some suff, maybe parameters..\n\n' + 'fubar(param1, param2)') + # Code completion + else: + #lst = [] + #for x in range(50000): + # lst.append('%05d' % x) + #st = " ".join(lst) + #print len(st) + #self.AutoCompShow(0, st) + + kw = keyword.kwlist[:] + kw.append("zzzzzz?2") + kw.append("aaaaa?2") + kw.append("__init__?3") + kw.append("zzaaaaa?2") + kw.append("zzbaaaa?2") + kw.append("this_is_a_longer_value") + #kw.append("this_is_a_much_much_much_much_much_much_much_longer_value") + + kw.sort() # Python sorts are case sensitive + self.AutoCompSetIgnoreCase(False) # so this needs to match + + # Images are specified with a appended "?type" + for i in range(len(kw)): + if kw[i] in keyword.kwlist: + kw[i] = kw[i] + "?1" + + self.AutoCompShow(0, " ".join(kw)) + else: + event.Skip() + + + def OnUpdateUI(self, evt): + # check for matching braces + braceAtCaret = -1 + braceOpposite = -1 + charBefore = None + caretPos = self.GetCurrentPos() + + if caretPos > 0: + charBefore = self.GetCharAt(caretPos - 1) + styleBefore = self.GetStyleAt(caretPos - 1) + + # check before + if charBefore and chr(charBefore) in "[]{}()" and styleBefore == stc.STC_P_OPERATOR: + braceAtCaret = caretPos - 1 + + # check after + if braceAtCaret < 0: + charAfter = self.GetCharAt(caretPos) + styleAfter = self.GetStyleAt(caretPos) + + if charAfter and chr(charAfter) in "[]{}()" and styleAfter == stc.STC_P_OPERATOR: + braceAtCaret = caretPos + + if braceAtCaret >= 0: + braceOpposite = self.BraceMatch(braceAtCaret) + + if braceAtCaret != -1 and braceOpposite == -1: + self.BraceBadLight(braceAtCaret) + else: + self.BraceHighlight(braceAtCaret, braceOpposite) + #pt = self.PointFromPosition(braceOpposite) + #self.Refresh(True, wxRect(pt.x, pt.y, 5,5)) + #print pt + #self.Refresh(False) + + + def OnMarginClick(self, evt): + # fold and unfold as needed + if evt.GetMargin() == 2: + if evt.GetShift() and evt.GetControl(): + self.FoldAll() + else: + lineClicked = self.LineFromPosition(evt.GetPosition()) + + if self.GetFoldLevel(lineClicked) & stc.STC_FOLDLEVELHEADERFLAG: + if evt.GetShift(): + self.SetFoldExpanded(lineClicked, True) + self.Expand(lineClicked, True, True, 1) + elif evt.GetControl(): + if self.GetFoldExpanded(lineClicked): + self.SetFoldExpanded(lineClicked, False) + self.Expand(lineClicked, False, True, 0) + else: + self.SetFoldExpanded(lineClicked, True) + self.Expand(lineClicked, True, True, 100) + else: + self.ToggleFold(lineClicked) + + + def FoldAll(self): + lineCount = self.GetLineCount() + expanding = True + + # find out if we are folding or unfolding + for lineNum in range(lineCount): + if self.GetFoldLevel(lineNum) & stc.STC_FOLDLEVELHEADERFLAG: + expanding = not self.GetFoldExpanded(lineNum) + break + + lineNum = 0 + + while lineNum < lineCount: + level = self.GetFoldLevel(lineNum) + if level & stc.STC_FOLDLEVELHEADERFLAG and \ + (level & stc.STC_FOLDLEVELNUMBERMASK) == stc.STC_FOLDLEVELBASE: + + if expanding: + self.SetFoldExpanded(lineNum, True) + lineNum = self.Expand(lineNum, True) + lineNum = lineNum - 1 + else: + lastChild = self.GetLastChild(lineNum, -1) + self.SetFoldExpanded(lineNum, False) + + if lastChild > lineNum: + self.HideLines(lineNum+1, lastChild) + + lineNum = lineNum + 1 + + + + def Expand(self, line, doExpand, force=False, visLevels=0, level=-1): + lastChild = self.GetLastChild(line, level) + line = line + 1 + + while line <= lastChild: + if force: + if visLevels > 0: + self.ShowLines(line, line) + else: + self.HideLines(line, line) + else: + if doExpand: + self.ShowLines(line, line) + + if level == -1: + level = self.GetFoldLevel(line) + + if level & stc.STC_FOLDLEVELHEADERFLAG: + if force: + if visLevels > 1: + self.SetFoldExpanded(line, True) + else: + self.SetFoldExpanded(line, False) + + line = self.Expand(line, doExpand, force, visLevels-1) + + else: + if doExpand and self.GetFoldExpanded(line): + line = self.Expand(line, True, force, visLevels-1) + else: + line = self.Expand(line, False, force, visLevels-1) + else: + line = line + 1 + + return line + + +#---------------------------------------------------------------------- + +_USE_PANEL = 1 + +def runTest(frame, nb, log): + if not _USE_PANEL: + ed = p = PythonSTC(nb, -1) + else: + p = wx.Panel(nb, -1, style = wx.NO_FULL_REPAINT_ON_RESIZE) + ed = PythonSTC(p, -1) + s = wx.BoxSizer(wx.HORIZONTAL) + s.Add(ed, 1, wx.EXPAND) + p.SetSizer(s) + p.SetAutoLayout(True) + + + ed.SetText(demoText + open('Main.py').read()) + ed.EmptyUndoBuffer() + ed.Colourise(0, -1) + + # line numbers in the margin + ed.SetMarginType(1, stc.STC_MARGIN_NUMBER) + ed.SetMarginWidth(1, 25) + + return p + + + +#---------------------------------------------------------------------- + + +overview = """\ + +Once again, no docs yet. Sorry. But this +and this should +be helpful. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + + + +#---------------------------------------------------------------------- +#---------------------------------------------------------------------- + diff --git a/demo/SystemSettings.py b/demo/SystemSettings.py new file mode 100644 index 00000000..d3861bb4 --- /dev/null +++ b/demo/SystemSettings.py @@ -0,0 +1,325 @@ +############################################################################### +# Name: SystemSettingsDemo.py # +# Purpose: SystemSettings Test and Demo File # +# Author: Cody Precord # +# Copyright: (c) 2009 Cody Precord # +# Licence: wxWindows Licence # +############################################################################### + +""" +wx.SystemSettings: + +

Allows the application to ask for details about the system.

+ +

This can include settings such as standard colours, fonts, and user interface +element sizes.

+ +""" + +__author__ = "Cody Precord " +__svnid__ = "$Id$" +__revision__ = "$Revision$" + +#-----------------------------------------------------------------------------# +# Imports +import os +import sys +import wx +import wx.lib.scrolledpanel as scrolled + +#-----------------------------------------------------------------------------# + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent) + + # Attributes + self.log = log + self._nb = wx.Notebook(self) + + # Setup + panel1 = ScrolledWrapper(self._nb, SysColorPanel, self.log) + self._nb.AddPage(panel1, "System Colors") + panel2 = ScrolledWrapper(self._nb, SysFontPanel, self.log) + self._nb.AddPage(panel2, "System Fonts") + panel3 = ScrolledWrapper(self._nb, SysMetricPanel, self.log) + self._nb.AddPage(panel3, "System Metrics") + panel4 = ScrolledWrapper(self._nb, SysFeaturePanel, self.log) + self._nb.AddPage(panel4, "System Features") + + # Layout + self.__DoLayout() + + def __DoLayout(self): + """Layout the panel""" + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self._nb, 1, wx.EXPAND) + self.SetSizer(sizer) + self.SetAutoLayout(True) + +#---------------------------------------------------------------------- + +class SysPanelBase(wx.PyPanel): + def __init__(self, parent, log): + wx.PyPanel.__init__(self, parent)#, size=(500, 500)) + + # Attributes + self.log = log + self._vals = list() + + ## Event Handlers + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_SCROLLWIN, self.OnScroll) + + + def DoGetBestSize(self): + """Return the best size for this panel""" + maxw = 0 + for vals in self._vals: + extent = self.GetTextExtent(vals)[0] + if extent > maxw: + maxw = extent + + self._maxw = maxw + maxw += 75 + maxh = (len(self._vals) + 1) * 22 + return (maxw, maxh) + + def SetupPaintDC(self, dc): + """Paint the screen + @param dc: paint DC + + """ + dc.SetFont(self.GetFont()) + dc.SetBrush(wx.WHITE_BRUSH) + dc.Clear() + dc.DrawRectangleRect(self.GetClientRect()) + + dc.SetPen(wx.BLACK_PEN) + dc.SetTextForeground(wx.BLACK) + + def OnPaint(self, evt): + dc = wx.PaintDC(self) + evt.Skip() + + def OnSize(self, evt): + self.Refresh() + evt.Skip() + + def OnScroll(self, evt): + self.Refresh() + evt.Skip() + + def OnErase(self, evt): + pass + +#---------------------------------------------------------------------- + +class SysColorPanel(SysPanelBase): + def __init__(self, parent, log): + SysPanelBase.__init__(self, parent, log) + + # Attributes: + self._box = (50, 15) # Color box dimensions + self._maxw = 0 + self._vals = [ color for color in dir(wx) + if color.startswith('SYS_COLOUR_') ] + + def OnPaint(self, evt): + dc = wx.AutoBufferedPaintDCFactory(self) + self.SetupPaintDC(dc) + + # Draw a sample box for each system color + nextx = 10 + nexty = 10 + column = 0 + row_count = 0 + for val in self._vals: + syscolor = wx.SystemSettings.GetColour(getattr(wx, val)) + dc.SetBrush(wx.Brush(syscolor)) + + # Draw label + dc.DrawText(val, nextx, nexty) + + # Calculate box position + nextx += self._maxw + 8 + dc.DrawRectangle(nextx, nexty, self._box[0], self._box[1]) + + nextx = 10 + nexty += 20 + +#---------------------------------------------------------------------- + +class SysFontPanel(SysPanelBase): + def __init__(self, parent, log): + SysPanelBase.__init__(self, parent, log) + + # Attributes: + self._maxw = 0 + self._vals = ['SYS_ANSI_FIXED_FONT', 'SYS_ANSI_VAR_FONT', + 'SYS_DEFAULT_GUI_FONT', 'SYS_DEVICE_DEFAULT_FONT', + 'SYS_ICONTITLE_FONT', 'SYS_OEM_FIXED_FONT', + 'SYS_SYSTEM_FIXED_FONT', 'SYS_SYSTEM_FONT'] + + + def OnPaint(self, evt): + dc = wx.AutoBufferedPaintDCFactory(self) + self.SetupPaintDC(dc) + + # Draw a sample box for each system color + nextx = 10 + nexty = 10 + column = 0 + row_count = 0 + for val in self._vals: + dc.SetFont(self.GetFont()) + sysfont = wx.SystemSettings.GetFont(getattr(wx, val)) + + # Draw label + dc.DrawText(val, nextx, nexty) + + # Calculate box position + nextx += self._maxw + 8 + dc.SetFont(sysfont) + dc.DrawText(sysfont.GetFaceName(), nextx, nexty) + + nextx = 10 + nexty += 20 + +#---------------------------------------------------------------------- + +class SysMetricPanel(SysPanelBase): + def __init__(self, parent, log): + SysPanelBase.__init__(self, parent, log) + + # Attributes: + self._maxw = 0 + self._vals = ['SYS_BORDER_X', 'SYS_BORDER_Y', 'SYS_CAPTION_Y', + 'SYS_CURSOR_X', 'SYS_CURSOR_Y', 'SYS_DCLICK_X', + 'SYS_DCLICK_Y', 'SYS_DRAG_X', 'SYS_DRAG_Y', + 'SYS_EDGE_X', 'SYS_EDGE_Y', 'SYS_FRAMESIZE_X', + 'SYS_FRAMESIZE_Y', 'SYS_HSCROLL_ARROW_X', + 'SYS_HSCROLL_ARROW_Y', 'SYS_HSCROLL_Y', 'SYS_HTHUMB_X', + 'SYS_ICONSPACING_X', 'SYS_ICONSPACING_Y', 'SYS_ICON_X', + 'SYS_ICON_Y', 'SYS_MENU_Y', 'SYS_SCREEN_X', + 'SYS_SCREEN_Y', 'SYS_SMALLICON_X', 'SYS_SMALLICON_Y', + 'SYS_VSCROLL_ARROW_X', 'SYS_VSCROLL_ARROW_Y', + 'SYS_VSCROLL_X', 'SYS_VTHUMB_Y', 'SYS_WINDOWMIN_X', + 'SYS_WINDOWMIN_Y', 'SYS_MOUSE_BUTTONS', + 'SYS_NETWORK_PRESENT', 'SYS_PENWINDOWS_PRESENT', + 'SYS_SHOW_SOUNDS', 'SYS_SWAP_BUTTONS'] + self._vals.sort() + + + def OnPaint(self, evt): + dc = wx.AutoBufferedPaintDCFactory(self) + self.SetupPaintDC(dc) + + # Draw a sample box for each system color + nextx = 10 + nexty = 10 + column = 0 + row_count = 0 + for val in self._vals: + sysmetric = wx.SystemSettings.GetMetric(getattr(wx, val)) + + # Draw label + dc.DrawText(val, nextx, nexty) + + # Calculate box position + nextx += self._maxw + 8 + dc.DrawText(repr(sysmetric), nextx, nexty) + + nextx = 10 + nexty += 20 + +#---------------------------------------------------------------------- + +class SysFeaturePanel(SysPanelBase): + def __init__(self, parent, log): + SysPanelBase.__init__(self, parent, log) + + # Attributes: + self._maxw = 0 + self._vals = ['SYS_CAN_DRAW_FRAME_DECORATIONS', + 'SYS_CAN_ICONIZE_FRAME', + 'SYS_TABLET_PRESENT' ] + + + def OnPaint(self, evt): + dc = wx.AutoBufferedPaintDCFactory(self) + self.SetupPaintDC(dc) + + # Draw a sample box for each system color + nextx = 10 + nexty = 10 + column = 0 + row_count = 0 + for val in self._vals: + sysfeature = wx.SystemSettings.HasFeature(getattr(wx, val)) + + # Draw label + dc.DrawText(val, nextx, nexty) + + # Calculate box position + nextx += self._maxw + 8 + dc.DrawText(repr(sysfeature), nextx, nexty) + + nextx = 10 + nexty += 20 + +#---------------------------------------------------------------------- + +class ScrolledWrapper(scrolled.ScrolledPanel): + def __init__(self, parent, ctor, log): + """Wrap the given window in a scrolled panel""" + scrolled.ScrolledPanel.__init__(self, parent) + + # Attributes + self._panel = ctor(self, log) + + # Layout + sizer = wx.BoxSizer(wx.VERTICAL) + + sizer.Add(self._panel, 1, wx.EXPAND) + self.SetSizer(sizer) + self.SetAutoLayout(True) + + # Setup + self.SetupScrolling() + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +class TestLog: + def __init__(self): + pass + + def write(self, msg): + print msg + +#---------------------------------------------------------------------- + +overview = __doc__ + +#-----------------------------------------------------------------------------# +if __name__ == '__main__': + try: + import sys + import run + except ImportError: + app = wx.PySimpleApp(False) + frame = wx.Frame(None, title="SystemSettings Demo", size=(500, 500)) + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(TestPanel(frame, TestLog()), 1, wx.EXPAND) + frame.CreateStatusBar() + frame.SetSizer(sizer) + frame.Show() + app.MainLoop() + else: + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/TablePrint.py b/demo/TablePrint.py new file mode 100644 index 00000000..73818dda --- /dev/null +++ b/demo/TablePrint.py @@ -0,0 +1,222 @@ + +import os +import wx +import wx.lib.printout as printout + +#--------------------------------------------------------------------------- + +buttonDefs = { + 814 : ('PreviewWide', 'Preview print of a wide table'), + 815 : ('PreviewNarrow', 'Preview print of a narrow table with color highlights'), + 816 : ('PreviewText', 'Preview print of a text file'), + 818 : ('OnPreviewMatrix', 'Preview print of a narrow column grid without a table header'), + 817 : ('PreviewLine', 'Preview print to demonstrate the use of line breaks'), + 819 : ('PrintWide', 'Direct print (no preview) of a wide table'), + } + + +class TablePanel(wx.Panel): + def __init__(self, parent, log, frame): + wx.Panel.__init__(self, parent, -1) + self.log = log + self.frame = frame + + box = wx.BoxSizer(wx.VERTICAL) + box.Add((20, 30)) + keys = buttonDefs.keys() + keys.sort() + + for k in keys: + text = buttonDefs[k][1] + btn = wx.Button(self, k, text) + box.Add(btn, 0, wx.ALIGN_CENTER|wx.ALL, 15) + self.Bind(wx.EVT_BUTTON, self.OnButton, btn) + + self.SetAutoLayout(True) + self.SetSizer(box) + + def OnButton(self, evt): + funct = buttonDefs[evt.GetId()][0] + code = 'self.' + funct + '()' + eval(code) + + def ReadData(self): + test_file = "./data/testtable.txt" + file = open(test_file,'r',1) + i = 0 + + data = [] + while 1: + text = file.readline() + text = text.strip() + if not text: + break + + list_val = text.split('\t') + data.append(list_val) + file.close() + + self.header = data[0] + self.data = data[1:] + + def PreviewWide(self): + self.ReadData() + prt = printout.PrintTable(self.frame) + prt.data = self.data + prt.left_margin = 0.5 + prt.set_column = [1.0, 1.0, 1.0, 1.5, 1.0, 3.0] + prt.label = self.header + prt.SetLandscape() + + prt.SetColumnLineSize(2, 3) + prt.SetColumnLineColour(3, wx.NamedColour('RED')) + + prt.SetRowLineSize(1, 3) + prt.SetRowLineColour(5, wx.NamedColour('RED')) + + prt.SetHeader("wx.Windows Applications") + prt.SetFooter() + prt.SetFooter("Date: ", type = "Date", align=wx.ALIGN_RIGHT, indent = -1, colour = wx.NamedColour('RED')) + prt.Preview() + + def PreviewNarrow(self): + self.ReadData() + new_data = [] + for val in self.data: + new_data.append([val[0], val[1], val[2], val[4], val[5]]) + + val = self.header + new_header = [val[0], val[1], val[2], val[4], val[5]] + + prt = printout.PrintTable(self.frame) + prt.data = new_data + prt.set_column = [ 1, 1, 1, 1, 2] + prt.label = new_header + prt.SetColAlignment(1, wx.ALIGN_CENTRE) + prt.SetColBackgroundColour(0, wx.NamedColour('RED')) + prt.SetColTextColour(0, wx.NamedColour('WHITE')) + prt.SetCellColour(4, 0, wx.NamedColour('LIGHT BLUE')) + prt.SetCellColour(4, 1, wx.NamedColour('LIGHT BLUE')) + prt.SetCellColour(17, 1, wx.NamedColour('LIGHT BLUE')) + + prt.SetColBackgroundColour(2, wx.NamedColour('LIGHT BLUE')) + prt.SetCellText(4, 2, wx.NamedColour('RED')) + + prt.SetColTextColour(3, wx.NamedColour('RED')) + prt.label_font_colour = wx.NamedColour('WHITE') + prt.SetHeader("wxWindows Applications", colour = wx.NamedColour('RED')) + + prt.SetHeader("Printed: ", type = "Date & Time", align=wx.ALIGN_RIGHT, indent = -1, colour = wx.NamedColour('BLUE')) + prt.SetFooter("Page No", colour = wx.NamedColour('RED'), type ="Num") + prt.Preview() + + def OnPreviewMatrix(self): + total_col = 45 + total_row = 10 + hsize = 0.2 + vsize = 0.2 + + data = [] + startx = 1.0 + columns = [] + for val in range(total_col): + columns.append(hsize) + + prt = printout.PrintTable(self.frame) + + for row in range(total_row): + value = [] + for col in range(total_col): + value.append(str(col)) + data.append(value) + + for col in range(total_col): + prt.SetColAlignment(col, wx.ALIGN_CENTRE) + + prt.SetLandscape() + prt.text_font_size = 8 + prt.cell_left_margin = 0 + + prt.data = data + prt.set_column = columns + prt.SetHeader("Test of Small Grid Size") + prt.Preview() + + def PreviewLine(self): + prt = printout.PrintTable(self.frame) + prt.label = ["Header 1", "Header 2", "Header 3"] + prt.set_column = [] + prt.data = [["Row 1", "1", "2"], ["Row 2", "3", "4\nNew Line to see if it also can wrap around the cell region properly\nAnother new line"]] + prt.SetFooter() + prt.Preview() + + def PreviewText(self): + prt = printout.PrintTable(self.frame) + prt.SetHeader("PROCLAMATION") + file = open('data/proclamation.txt') + data = [] + for txt in file: + data.append(txt.strip()) + file.close() + prt.data = data + prt.Preview() + + def PrintWide(self): + self.ReadData() + prt = printout.PrintTable(self.frame) + prt.data = self.data + + prt.left_margin = 0.5 + prt.set_columns = [ 1, 1, 1, 1, 2, 1, 3 ] + prt.label = self.header + prt.SetLandscape() + prt.Print() + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TablePanel(nb, log, frame) + return win + +#--------------------------------------------------------------------------- + + + + + +overview = """\ + +

Table Printing

+ +This demo shows various ways of using the new + PrintOut class. To understand the class you need to examine the demo examples +and the library printout.py module classes. +

+The initial class primarily contains a Table preview/printing class. There is a lot of flexibility +in manipulating the placement, sizing, colours, alignment of the table text and cell background colors. +There are also a number of options for printing Header and Footer information on the page. +

+There is also a class to extract the parameters from a wxGrid and easily recreate a Table printout. +

+The data is printed from a list object containing the column and row values. The label or table header +can be defined and will be repeated for all pages. +

+The correct "Total Page" does get calculated and used in the print out Footer. +

+There is still problems with the print framework to properly get the total pages in the preview unless +the program knows it before trying to parse through the available pages. This will be fixed +when the framework allows for it. + + +""" % os.path.join(os.path.dirname(printout.__file__), "printout.py") + + + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/TestTable.txt b/demo/TestTable.txt new file mode 100644 index 00000000..beaccdef --- /dev/null +++ b/demo/TestTable.txt @@ -0,0 +1,38 @@ +Name Type Platform Location Availability Description +WebReuser Development Windows 95, Windows NT, HPUX 9.05 and 10.2, Solaris 2.4 and 2.5 http://www.stablesoft.com Evaluation WebReuser is a re-use tool from Hitachi Europe Limited. WebReuser is a tool that simplifies software reuse. Its ability to track, schematize and search documents makes it the ideal way to understand C++ code. These features also make WebReuser an ideal tool to classify any Web resource. WebReuser can even be used for more general documentation management tasks. +MacAnova Development Windows, Motif, Mac http://www.stat.umn.edu/~gary/macanova/macanova.home.html Free A large statistical application from the School of Statistics, University of Minnesota. It is based on a modified version of wxWindows 1.65. +Hardy Development Win 3.1, WIN32, Motif (Sun only) http://www.aiai.ed.ac.uk/~hardy/ Freeware for personal and academic use A hypertext-based diagramming and knowledge-based system development tool, with NASA's CLIPS built-in. It is a superset of wxCLIPS. +wxCLIPS Development Win 3.1, WIN32, Motif, XView http://web.ukonline.co.uk/julian.smart/wxclips Freeware A GUI development environment for CLIPS applications. +wxPython Development wxWindows 2 for the new version http://alldunn.com/wxPython/ Freeware Python/wxWindows combination by Robin Dunn and Harri Pasanen. Python is an elegant object-oriented, interpreted language that runs on many platforms. +MrEd Development Win 3.1, WIN32, Motif, XView http://www.cs.rice.edu/CS/PLT/packages/mred/ Freeware MrEd is a combined editor and Scheme development environment by Matthew Flatt. +WXLisp Development Win 3.1, WIN32, Motif, XView http://www.cadlab.de/~lipuser/wxlisp/wxlisp.html Freeware A combination of wxWindows and XLisp. +Scriptum Development Motif http://www.isoft.com.ar/eng/products/system/scriptum.html Freeware Graphical editor with visual highlighting, navigation/browsing, undo, class browser for C++ and Java, source code management, file locking, remote editing using ftp, configurable. +WipeOut Development XView/Linux http://www.softwarebuero.de/wipeout-eng.html Giftware WipeOut is an integrated development environment for C++ projects, available for Linux/XView. The authors are working on versions for SunOS/Solaris. Source is available for porting to other platforms. +OPL Development Win 3.1, WIN32, Motif, XView http://www.ozemail.com.au/~adavison/ Freeware Object Prolog is a portable implementation of Prolog by Andrew Davison, with object-oriented extensions, entirely written in C++. In the initial version, a binding to wxWindows is available. In the revamped version, this binding has not been written yet. +Dataplore Graphics and sound Windows, other? http://www.datan.de/dataplore Commercial Data visualisation tool, from Datan +VCG Tool Graphics and sound Win 3.1, WIN32, Motif, XView http://www.cs.uni-sb.de:80/RW/users/sander/html/gsvcg1.html Freeware A graph layout tool similar to GraphPlace, but with extensions. Very nice indeed! +Y.E.S. Graphics and sound Win 3.1, WIN32, XView (Linux) ftp://ftp.musik.uni-essen.de/pub/EsAC/program/ Shareware Monophonic notation program. +JAZZ Graphics and sound XView (Linux) http://rokke.aug.hiagder.no/per/jazz.html Freeware A MIDI sequencer for Linux. +ISP Graphics and sound Win 3.1, WIN32, Motif, XView ftp://www.remstar.com/pub/wxwin/contrib/isp-100/ Freeware Image and sound player educational tool. +ClockWorks Graphics and sound Win 3.1, WIN32, Motif, XView http://web.ukonline.co.uk/Members/julian.smart/freesoft.html#clockworks Freeware A configurable analogue clock, with a collection of 'fine art' faces. By Julian Smart. +M Miscellaneous Windows 95, Windows NT, Linux http://www.phy.hw.ac.uk/~karsten/M/index.html GPL M is a cross-platform e-mail application. It will be available for X11/Unix and Windows platforms, supporting a wide range of e-mail transfer protocols as well as including full MIME support. M's wealth of features and ease of use make it one of the most powerful MUAs available, providing a consistent and intuitive interface across all platforms. +Boolean Miscellaneous Windows 95, Windows NT, Solaris http://www.xs4all.nl/~kholwerd/bool.html Freeware A GDSII CAD file format viewer, and program to perform boolean operations on sets of 2D polygons. By Klaas Holwerda. +TimeMan Miscellaneous wxGTK, Unix http://www.bgif.no/neureka/TimeMan/ Freeware A time manager, written using wxGTK +Forty Thieves Miscellaneous Motif, Windows apps/forty/forty.htm Freeware A fiendish patience game, by Chris Breeze. A nice demo of what's possible with wxWindows. +Lean Integration Platform Miscellaneous Windows NT, various flavours of UNIX http://www.c-lab.de/~lipuser/lip To be decided LIP is a workflow-oriented tool integration system which uses wxLisp (and thus wxWindows) as an implementation basis. Lisp combined with the wxWindows bindings make up the compatible extension language platform of the system. +wxWeb Miscellaneous Win 3.1, WIN32, Motif ftp://www.remstar.com/pub/wxwin/contrib/wxweb Freeware Andrew Davison's Web browser, with SimSock portable socket library and wxHtml canvas. Includes an http server for UNIX and Windows. +SANTIS Miscellaneous Win 3.1, Windows 95, Linux, Solaris OpenLook and Motif, Silicon Graphics http://www.physiology.rwth-aachen.de/bs/santis/ Free for non-commercial use SANTIS is a software tool designed for the analysis of signals and time series data of any kind, in particular for scientific purposes. It was developed at the Laboratory of Biomedical Systems Analysis, Institute of Physiology at the University of Aachen, Germany. +Xbaies Miscellaneous Win 3.1, WIN32, Motif, XView xbaies.htm Freeware A shell for building Bayesian network models, by Robert Cowell. +wxTinyBB Miscellaneous Win 3.1, WIN32, Motif, XView ftp://www.remstar.com/pub/wxwin/contrib/wxtinybb Freeware/commercial A tiny blackboard shell demo showing an embedded (commercial) Prolog engine. Demo written by Arvindra Sehmi. A good example of a nice interface using wxWindows. +Gambit Miscellaneous Win 3.1, WIN32, Motif, XView http://www.hss.caltech.edu/~gambit/Gambit.html Freeware A large wxWindows application with source, and features such as a table control with printing. +Tex2RTF Miscellaneous Win 3.1, WIN32, Motif, XView http://web.ukonline.co.uk/julian.smart/tex2rtf Freeware Converts subset of LaTeX syntax to WinHelp, wordprocessor RTF, HTML, and wxHelp. As used for wxWindows documentation. +wxPoem Miscellaneous Win 3.1, WIN32, Motif, XView none.htm Freeware A poetry display program for wxWindows. Included as a sample in the wxWindows distribution. +Sonar tracking software Miscellaneous See Web site http://www.desertstar.com Demonstration Miscellaneous sonar tracking software from Desert Star Systems, who use wxWindows for all their Windows-based software. +Name Research software Platform Location Availability Description +DisCo Research software N/A http://www.cs.tut.fi/laitos/DisCo/tool.fm.html N/A A tool for specification of reactive systems. +CAFE Research software N/A cafe.htm N/A Cellular Analysis of Fire and Extinction +CODA Research software See Web site http://www.ozemail.com.au/~mbedward/coda/coda.html See Web site CODA assists in the design of networks of nature reserves or protected areas. It has been used for major reserve planning studies, as a teaching resource and for research into conservation planning methods.  +EGRESS Research software N/A http://www.aiai.ed.ac.uk/~jimd/Egress2/projInfo_contents.html N/A An evacuation decision model. +ACT Research software N/A none.htm N/A A general process and tracker and automator being built at NASA. +Rectangular nesting program Research software N/A http://www.elec-eng.leeds.ac.uk/een5mpd/research.html N/A Optimized layout of rectangles on a page. +Finite element post processor Research software N/A http://www.ime.auc.dk/afd3/odessy/manuals/index.htm N/A Finite element postprocessor, produced at Aalborg University in Denmark by John Rasmussen and Erik Lund. diff --git a/demo/TextCtrl.py b/demo/TextCtrl.py new file mode 100644 index 00000000..6b19578c --- /dev/null +++ b/demo/TextCtrl.py @@ -0,0 +1,178 @@ + +import sys +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + # def OnSetFocus(self, evt): + # print "OnSetFocus" + # evt.Skip() + # def OnKillFocus(self, evt): + # print "OnKillFocus" + # evt.Skip() + # def OnWindowDestroy(self, evt): + # print "OnWindowDestroy" + # evt.Skip() + + + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + l1 = wx.StaticText(self, -1, "wx.TextCtrl") + t1 = wx.TextCtrl(self, -1, "Test it out and see", size=(125, -1)) + wx.CallAfter(t1.SetInsertionPoint, 0) + self.tc1 = t1 + + self.Bind(wx.EVT_TEXT, self.EvtText, t1) + t1.Bind(wx.EVT_CHAR, self.EvtChar) + # t1.Bind(wx.EVT_SET_FOCUS, self.OnSetFocus) + # t1.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) + # t1.Bind(wx.EVT_WINDOW_DESTROY, self.OnWindowDestroy) + + l2 = wx.StaticText(self, -1, "Password") + t2 = wx.TextCtrl(self, -1, "", size=(125, -1), style=wx.TE_PASSWORD) + self.Bind(wx.EVT_TEXT, self.EvtText, t2) + + l3 = wx.StaticText(self, -1, "Multi-line") + t3 = wx.TextCtrl(self, -1, + "Here is a looooooooooooooong line of text set in the control.\n\n" + "The quick brown fox jumped over the lazy dog...", + size=(200, 100), style=wx.TE_MULTILINE|wx.TE_PROCESS_ENTER) + + t3.SetInsertionPoint(0) + self.Bind(wx.EVT_TEXT, self.EvtText, t3) + self.Bind(wx.EVT_TEXT_ENTER, self.EvtTextEnter, t3) + + b = wx.Button(self, -1, "Test Replace") + self.Bind(wx.EVT_BUTTON, self.OnTestReplace, b) + b2 = wx.Button(self, -1, "Test GetSelection") + self.Bind(wx.EVT_BUTTON, self.OnTestGetSelection, b2) + b3 = wx.Button(self, -1, "Test WriteText") + self.Bind(wx.EVT_BUTTON, self.OnTestWriteText, b3) + self.tc = t3 + + + l4 = wx.StaticText(self, -1, "Rich Text") + t4 = wx.TextCtrl(self, -1, "If supported by the native control, this is red, and this is a different font.", + size=(200, 100), style=wx.TE_MULTILINE|wx.TE_RICH2) + t4.SetInsertionPoint(0) + t4.SetStyle(44, 47, wx.TextAttr("RED", "YELLOW")) + points = t4.GetFont().GetPointSize() # get the current size + f = wx.Font(points+3, wx.ROMAN, wx.ITALIC, wx.BOLD, True) + t4.SetStyle(63, 77, wx.TextAttr("BLUE", wx.NullColour, f)) + + l5 = wx.StaticText(self, -1, "Test Positions") + t5 = wx.TextCtrl(self, -1, "0123456789\n" * 5, size=(200, 100), + style = wx.TE_MULTILINE + #| wx.TE_RICH + | wx.TE_RICH2 + ) + t5.Bind(wx.EVT_LEFT_DOWN, self.OnT5LeftDown) + self.t5 = t5 + + space = 6 + bsizer = wx.BoxSizer(wx.VERTICAL) + bsizer.Add(b, 0, wx.GROW|wx.ALL, space) + bsizer.Add(b2, 0, wx.GROW|wx.ALL, space) + bsizer.Add(b3, 0, wx.GROW|wx.ALL, space) + + sizer = wx.FlexGridSizer(cols=3, hgap=space, vgap=space) + sizer.AddMany([ l1, t1, (0,0), + l2, t2, (0,0), + l3, t3, bsizer, + l4, t4, (0,0), + l5, t5, (0,0), + ]) + border = wx.BoxSizer(wx.VERTICAL) + border.Add(sizer, 0, wx.ALL, 25) + self.SetSizer(border) + self.SetAutoLayout(True) + + + def EvtText(self, event): + self.log.WriteText('EvtText: %s\n' % event.GetString()) + + def EvtTextEnter(self, event): + self.log.WriteText('EvtTextEnter\n') + event.Skip() + + def EvtChar(self, event): + self.log.WriteText('EvtChar: %d\n' % event.GetKeyCode()) + event.Skip() + + + def OnTestReplace(self, evt): + self.tc.Replace(5, 9, "IS A") + #self.tc.Remove(5, 9) + + def OnTestWriteText(self, evt): + self.tc.WriteText("TEXT") + + def OnTestGetSelection(self, evt): + start, end = self.tc.GetSelection() + text = self.tc.GetValue() + if wx.Platform == "__WXMSW__": # This is why GetStringSelection was added + text = text.replace('\n', '\r\n') + + self.log.write("multi-line GetSelection(): (%d, %d)\n" + "\tGetStringSelection(): %s\n" + "\tSelectedText: %s\n" % + (start, end, + self.tc.GetStringSelection(), + repr(text[start:end]))) + + start, end = self.tc1.GetSelection() + text = self.tc1.GetValue() + + if wx.Platform == "__WXMSW__": # This is why GetStringSelection was added + text = text.replace('\n', '\r\n') + + self.log.write("single-line GetSelection(): (%d, %d)\n" + "\tGetStringSelection(): %s\n" + "\tSelectedText: %s\n" % + (start, end, + self.tc1.GetStringSelection(), + repr(text[start:end]))) + + + def OnT5LeftDown(self, evt): + evt.Skip() + wx.CallAfter(self.LogT5Position, evt) + + def LogT5Position(self, evt): + text = self.t5.GetValue() + ip = self.t5.GetInsertionPoint() + lp = self.t5.GetLastPosition() + self.log.write("LogT5Position:\n" + "\tGetInsertionPoint:\t%d\n" + "\ttext[insertionpoint]:\t%s\n" + "\tGetLastPosition:\t%d\n" + "\tlen(text):\t\t%d\n" + % (ip, text[ip], lp, len(text))) + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ +A TextCtrl allows text to be displayed and (possibly) edited. It may be single +line or multi-line, support styles or not, be read-only or not, and even supports +text masking for such things as passwords. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/TextEntryDialog.py b/demo/TextEntryDialog.py new file mode 100644 index 00000000..568095aa --- /dev/null +++ b/demo/TextEntryDialog.py @@ -0,0 +1,56 @@ + +import wx + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Create and Show a TextEntryDialog", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + dlg = wx.TextEntryDialog( + self, 'What is your favorite programming language?', + 'Eh??', 'Python') + + dlg.SetValue("Python is the best!") + + if dlg.ShowModal() == wx.ID_OK: + self.log.WriteText('You entered: %s\n' % dlg.GetValue()) + + dlg.Destroy() + + + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + + +overview = """\ +This class represents a dialog that requests a one-line text string from the user. +It is implemented as a generic wxWindows dialog. Along with the usual wx.Dialog +style flags, all of the wx.TextCtrl TE_* style flags are accepted, so, for example, +wx.TE_PASSWORD could be used to create a password dialog. + +As with other dialogs of this type, the user input must be retrieved prior to +destroying the dialog. + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/Threads.py b/demo/Threads.py new file mode 100644 index 00000000..11c6a34d --- /dev/null +++ b/demo/Threads.py @@ -0,0 +1,263 @@ + +import random +import time +import thread + +import wx +import wx.lib.newevent + +#---------------------------------------------------------------------- + +# This creates a new Event class and a EVT binder function +(UpdateBarEvent, EVT_UPDATE_BARGRAPH) = wx.lib.newevent.NewEvent() + + +#---------------------------------------------------------------------- + +class CalcBarThread: + def __init__(self, win, barNum, val): + self.win = win + self.barNum = barNum + self.val = val + + def Start(self): + self.keepGoing = self.running = True + thread.start_new_thread(self.Run, ()) + + def Stop(self): + self.keepGoing = False + + def IsRunning(self): + return self.running + + def Run(self): + while self.keepGoing: + # We communicate with the UI by sending events to it. There can be + # no manipulation of UI objects from the worker thread. + evt = UpdateBarEvent(barNum = self.barNum, value = int(self.val)) + wx.PostEvent(self.win, evt) + + sleeptime = (random.random() * 2) + 0.5 + time.sleep(sleeptime/4) + + sleeptime = sleeptime * 5 + if int(random.random() * 2): + self.val = self.val + sleeptime + else: + self.val = self.val - sleeptime + + if self.val < 0: self.val = 0 + if self.val > 300: self.val = 300 + + self.running = False + +#---------------------------------------------------------------------- + + +class GraphWindow(wx.Window): + def __init__(self, parent, labels): + wx.Window.__init__(self, parent, -1) + + self.values = [] + for label in labels: + self.values.append((label, 0)) + + font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD) + self.SetFont(font) + + self.colors = [ wx.RED, wx.GREEN, wx.BLUE, wx.CYAN, + "Yellow", "Navy" ] + + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + self.Bind(wx.EVT_PAINT, self.OnPaint) + + + def SetValue(self, index, value): + assert index < len(self.values) + cur = self.values[index] + self.values[index:index+1] = [(cur[0], value)] + + + def SetFont(self, font): + wx.Window.SetFont(self, font) + wmax = hmax = 0 + for label, val in self.values: + w,h = self.GetTextExtent(label) + if w > wmax: wmax = w + if h > hmax: hmax = h + self.linePos = wmax + 10 + self.barHeight = hmax + + + def GetBestHeight(self): + return 2 * (self.barHeight + 1) * len(self.values) + + + def Draw(self, dc, size): + dc.SetFont(self.GetFont()) + dc.SetTextForeground(wx.BLUE) + dc.SetBackground(wx.Brush(self.GetBackgroundColour())) + dc.Clear() + dc.SetPen(wx.Pen(wx.BLACK, 3, wx.SOLID)) + dc.DrawLine(self.linePos, 0, self.linePos, size.height-10) + + bh = ypos = self.barHeight + for x in range(len(self.values)): + label, val = self.values[x] + dc.DrawText(label, 5, ypos) + + if val: + color = self.colors[ x % len(self.colors) ] + dc.SetPen(wx.Pen(color)) + dc.SetBrush(wx.Brush(color)) + dc.DrawRectangle(self.linePos+3, ypos, val, bh) + + ypos = ypos + 2*bh + if ypos > size[1]-10: + break + + + def OnPaint(self, evt): + dc = wx.BufferedPaintDC(self) + self.Draw(dc, self.GetSize()) + + + def OnEraseBackground(self, evt): + pass + + + + +#---------------------------------------------------------------------- + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, "Thread Test", size=(450,300)) + self.log = log + + #self.CenterOnParent() + + panel = wx.Panel(self, -1) + panel.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD)) + wx.StaticText(panel, -1, + "This demo shows multiple threads interacting with this\n" + "window by sending events to it, one thread for each bar.", + (5,5)) + panel.Fit() + + self.graph = GraphWindow(self, ['Zero', 'One', 'Two', 'Three', 'Four', + 'Five', 'Six', 'Seven']) + self.graph.SetMinSize((450, self.graph.GetBestHeight())) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(panel, 0, wx.EXPAND) + sizer.Add(self.graph, 1, wx.EXPAND) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + sizer.Fit(self) + + self.Bind(EVT_UPDATE_BARGRAPH, self.OnUpdate) + + self.threads = [] + self.threads.append(CalcBarThread(self, 0, 50)) + self.threads.append(CalcBarThread(self, 1, 75)) + self.threads.append(CalcBarThread(self, 2, 100)) + self.threads.append(CalcBarThread(self, 3, 150)) + self.threads.append(CalcBarThread(self, 4, 225)) + self.threads.append(CalcBarThread(self, 5, 300)) + self.threads.append(CalcBarThread(self, 6, 250)) + self.threads.append(CalcBarThread(self, 7, 175)) + + for t in self.threads: + t.Start() + + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + + def OnUpdate(self, evt): + self.graph.SetValue(evt.barNum, evt.value) + self.graph.Refresh(False) + + + def OnCloseWindow(self, evt): + busy = wx.BusyInfo("One moment please, waiting for threads to die...") + wx.Yield() + + for t in self.threads: + t.Stop() + + running = 1 + + while running: + running = 0 + + for t in self.threads: + running = running + t.IsRunning() + + time.sleep(0.1) + + self.Destroy() + + + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show Threads sample", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = TestFrame(self, self.log) + self.win.Show(True) + + + def ShutdownDemo(self): + if hasattr(self, 'win') and self.win: + self.win.Close() + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + + + +overview = """\ +The main issue with multi-threaded GUI programming is the thread safty +of the GUI itself. On most platforms the GUI is not thread safe and +so any cross platform GUI Toolkit and applications written with it +need to take that into account. + +The solution is to only allow interaction with the GUI from a single +thread, but this often severely limits what can be done in an +application and makes it difficult to use additional threads at all. + +Since wxPython already makes extensive use of event handlers, it is a +logical extension to allow events to be sent to GUI objects from +alternate threads. A function called wx.PostEvent allows you to do +this. It accepts an event and an event handler (window) and instead +of sending the event immediately in the current context like +ProcessEvent does, it processes it later from the context of the GUI +thread. + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Throbber.py b/demo/Throbber.py new file mode 100644 index 00000000..1d9400fd --- /dev/null +++ b/demo/Throbber.py @@ -0,0 +1,248 @@ + +import wx +import wx.lib.throbber as throb + +import throbImages + +from wx.lib.throbber import __doc__ as docString + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + # create the throbbers + self.throbbers = { + 'plain': { 'throbber': None, + 'text': "Plain throbber." }, + 'reverse': { 'throbber': None, + 'text': "This throbber runs in reverse and faster." }, + 'autoreverse': { 'throbber': None, + 'text': "This throbber switches direction." }, + 'label': { 'throbber': None, + 'text': "With a label." }, + 'overlay': { 'throbber': None, + 'text': "With an overlayed image." }, + 'overlay+text': { 'throbber': None, + 'text': "With a label and an overlayed image." }, + } + + images = [throbImages.catalog[i].GetBitmap() + for i in throbImages.index + if i not in ['eclouds', 'logo']] + + self.throbbers['plain']['throbber'] = \ + throb.Throbber(self, -1, images, size=(36, 36),frameDelay = 0.1) + + self.throbbers['reverse']['throbber'] = \ + throb.Throbber(self, -1, images, frameDelay = 0.07) + + self.throbbers['reverse']['throbber'].Reverse() + + self.throbbers['autoreverse']['throbber'] = \ + throb.Throbber(self, -1, images, frameDelay = 0.1, reverse = True) + + self.throbbers['autoreverse']['throbber'].sequence.append(0) + + self.throbbers['label']['throbber'] = \ + throb.Throbber(self, -1, images, frameDelay = 0.1, label = 'Label') + + self.throbbers['label']['throbber'].SetFont(wx.Font( + pointSize = 10, family = wx.DEFAULT, style = wx.NORMAL, weight = wx.BOLD + )) + + self.throbbers['overlay']['throbber'] = \ + throb.Throbber( + self, -1, images, frameDelay = 0.1, + overlay = throbImages.catalog['logo'].GetBitmap() + ) + + self.throbbers['overlay+text']['throbber'] = \ + throb.Throbber( + self, -1, images, frameDelay = 0.1, + overlay = throbImages.catalog['logo'].GetBitmap(), label = "Python!" + ) + + self.throbbers['overlay+text']['throbber'].SetFont(wx.Font( + pointSize = 8, family = wx.DEFAULT, style = wx.NORMAL, weight = wx.BOLD + )) + + self.customThrobber = \ + throb.Throbber(self, -1, images, size=(36, 36), + frameDelay = 0.1, + rest = 4, + sequence = [ 1, 5, 2, 7, 3, 6, 4, 4, 4, 4, 7, 2, 2, 0 ] + ) + + box = wx.BoxSizer(wx.VERTICAL) + sizer = wx.GridBagSizer() + box.Add(sizer, 1, wx.EXPAND|wx.ALL, 5) + + row = 2 + + # use a list so we can keep our order + for t in ['plain', 'reverse', 'autoreverse', 'label', 'overlay', 'overlay+text']: + sizer.Add( + self.throbbers[t]['throbber'], (row, 0), (1, 1), + flag = wx.ALIGN_CENTER|wx.ALL, border=2 + ) + + sizer.Add( + wx.StaticText(self, -1, self.throbbers[t]['text']), + (row, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT + ) + + row += 1 + + # Add custom throbber to sizer. + row += 2 + sizer.Add( + self.customThrobber, (row, 0), (1, 1), + flag = wx.ALIGN_CENTER|wx.ALL, border=2 + ) + + sizer.Add( + wx.StaticText(self, -1, 'with custom & manual sequences'), + (row, 1), flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT + ) + + sizer.AddGrowableCol(1) + + # start and stop buttons + startButton = wx.Button(self, -1, "Start") + self.Bind(wx.EVT_BUTTON, self.OnStartAnimation, startButton) + + stopButton = wx.Button(self, -1, "Stop") + self.Bind(wx.EVT_BUTTON, self.OnStopAnimation, stopButton) + + buttonBox = wx.BoxSizer(wx.HORIZONTAL) + buttonBox.AddMany([ + (startButton, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5), + (stopButton, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5), + ]) + + sizer.Add( + buttonBox, (len(self.throbbers) + 2, 0), (1, 3), flag = wx.ALIGN_CENTER + ) + + # Buttoms for the custom throbber. + nextButton = wx.Button(self, -1, "Next") + self.Bind(wx.EVT_BUTTON, self.OnNext, nextButton) + + prevButton = wx.Button(self, -1, "Previous") + self.Bind(wx.EVT_BUTTON, self.OnPrevious, prevButton) + + incButton = wx.Button(self, -1, "Increment") + self.Bind(wx.EVT_BUTTON, self.OnIncrement, incButton) + + decButton = wx.Button(self, -1, "Decrement") + self.Bind(wx.EVT_BUTTON, self.OnDecrement, decButton) + + revButton = wx.Button(self, -1, "Reverse") + self.Bind(wx.EVT_BUTTON, self.OnReverse, revButton) + + restButton = wx.Button(self, -1, "Rest") + self.Bind(wx.EVT_BUTTON, self.OnRest, restButton) + + startButton = wx.Button(self, -1, "Start") + self.Bind(wx.EVT_BUTTON, self.OnStart, startButton) + + stopButton = wx.Button(self, -1, "Stop") + self.Bind(wx.EVT_BUTTON, self.OnStop, stopButton) + + customBox1 = wx.BoxSizer(wx.HORIZONTAL) + customBox1.AddMany([ + (nextButton, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5), + (prevButton, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5), + (incButton, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5), + (decButton, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5), + (revButton, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5), + ]) + + customBox2 = wx.BoxSizer(wx.HORIZONTAL) + customBox2.AddMany([ + (restButton, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5), + (startButton, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5), + (stopButton, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 5), + ]) + + sizer.Add( customBox1, (len(self.throbbers) + 5, 0), (1, 3), flag = wx.ALIGN_CENTER ) + sizer.Add( customBox2, (len(self.throbbers) + 6, 0), (1, 3), flag = wx.ALIGN_CENTER ) + + # Layout. + self.SetSizer(box) + self.SetAutoLayout(True) + self.Layout() + sizer.SetSizeHints(self) + sizer.Fit(self) + + for t in self.throbbers.keys(): + self.throbbers[t]['throbber'].Start() + + self.Bind(wx.EVT_WINDOW_DESTROY, self.OnDestroy) + + def OnDestroy(self, event): + self.log.write("got destroy event") + event.Skip() + + def OnStartAnimation(self, event): + for t in self.throbbers.keys(): + self.throbbers[t]['throbber'].Start() + + def OnStopAnimation(self, event): + for t in self.throbbers.keys(): + self.throbbers[t]['throbber'].Rest() + + def OnNext(self, event): + self.customThrobber.Next() + + def OnPrevious(self, event): + self.customThrobber.Previous() + + def OnIncrement(self, event): + self.customThrobber.Increment() + + def OnDecrement(self, event): + self.customThrobber.Decrement() + + def OnReverse(self, event): + self.customThrobber.Reverse() + + def OnRest(self, event): + self.customThrobber.Rest() + + def OnStart(self, event): + self.customThrobber.Start() + + def OnStop(self, event): + self.customThrobber.Stop() + + def ShutdownDemo(self): + for t in self.throbbers.keys(): + self.throbbers[t]['throbber'].Rest() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Throbber

+

%s

+ +""" % docString + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/Ticker.py b/demo/Ticker.py new file mode 100644 index 00000000..8eb01f78 --- /dev/null +++ b/demo/Ticker.py @@ -0,0 +1,151 @@ + +import wx +from wx.lib.ticker import Ticker +import wx.lib.colourselect as csel #for easy color selection + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + self.ticker = Ticker(self) + + # Controls for ...controlling... the ticker. + self.txt = wx.TextCtrl(self, value="I am a scrolling ticker!!!!", size=(200,-1)) + wx.CallAfter(self.txt.SetInsertionPoint, 0) + txtl = wx.StaticText(self, label="Ticker text:") + fgb = csel.ColourSelect(self, -1, colour=self.ticker.GetForegroundColour()) + fgl = wx.StaticText(self, label="Foreground Color:") + bgb = csel.ColourSelect(self, -1, colour=self.ticker.GetBackgroundColour()) + bgl = wx.StaticText(self, label="Background Color:") + fontb = wx.Button(self, label="Change") + self.fontl = wx.StaticText(self) + dirb = wx.Button(self, label="Switch") + self.dirl = wx.StaticText(self) + fpsl = wx.StaticText(self, label="Frames per Second:") + fps = wx.Slider(self, value=self.ticker.GetFPS(), minValue=1, maxValue=100, + size=(150,-1), + style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS) + fps.SetTickFreq(5) + ppfl = wx.StaticText(self, label="Pixels per frame:") + ppf = wx.Slider(self, value=self.ticker.GetPPF(), minValue=1, maxValue=10, + size=(150,-1), + style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS) + + # Do layout + sz = wx.FlexGridSizer(cols=2, hgap=4, vgap=4) + + sz.Add(txtl, flag=wx.ALIGN_CENTER_VERTICAL) + sz.Add(self.txt, flag=wx.ALIGN_CENTER_VERTICAL) + + sz.Add(fgl, flag=wx.ALIGN_CENTER_VERTICAL) + sz.Add(fgb, flag=wx.ALIGN_CENTER_VERTICAL) + + sz.Add(bgl, flag=wx.ALIGN_CENTER_VERTICAL) + sz.Add(bgb, flag=wx.ALIGN_CENTER_VERTICAL) + + sz.Add(self.fontl, flag=wx.ALIGN_CENTER_VERTICAL) + sz.Add(fontb, flag=wx.ALIGN_CENTER_VERTICAL) + + sz.Add(self.dirl, flag=wx.ALIGN_CENTER_VERTICAL) + sz.Add(dirb, flag=wx.ALIGN_CENTER_VERTICAL) + + sz.Add(fpsl, flag=wx.ALIGN_CENTER_VERTICAL) + sz.Add(fps, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) + + sz.Add(ppfl, flag=wx.ALIGN_CENTER_VERTICAL) + sz.Add(ppf, flag=wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_LEFT) + + sz2 = wx.BoxSizer(wx.VERTICAL) + sz2.Add(self.ticker, flag=wx.EXPAND|wx.ALL, border=5) + sz2.Add(sz, flag=wx.EXPAND|wx.ALL, proportion=1, border=25) + self.SetSizer(sz2) + sz2.SetSizeHints(self) + + # Bind events + self.Bind(wx.EVT_BUTTON, self.OnChangeTickDirection, dirb) + self.Bind(wx.EVT_BUTTON, self.OnChangeTickFont, fontb) + self.Bind(wx.EVT_TEXT, self.OnText, self.txt) + self.Bind(csel.EVT_COLOURSELECT, self.ChangeTickFGColor, fgb) + self.Bind(csel.EVT_COLOURSELECT, self.ChangeTickBGColor, bgb) + self.Bind(wx.EVT_SCROLL, self.ChangeFPS, fps) + self.Bind(wx.EVT_SCROLL, self.ChangePPF, ppf) + + # Set defaults + self.SetTickDirection("rtl") + self.SetTickFont(self.ticker.GetFont()) + self.ticker.SetText(self.txt.GetValue()) + + + def SetTickFont(self, font): + """Sets ticker font, updates label""" + self.ticker.SetFont(font) + self.fontl.SetLabel("Font: %s"%(self.ticker.GetFont().GetFaceName())) + self.Layout() + + + def OnChangeTickFont(self, evt): + fd = wx.FontData() + fd.EnableEffects(False) + fd.SetInitialFont(self.ticker.GetFont()) + dlg = wx.FontDialog(wx.GetTopLevelParent(self), fd) + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetFontData() + self.SetTickFont(data.GetChosenFont()) + + + def SetTickDirection(self, dir): + """Sets tick direction, updates label""" + self.ticker.SetDirection(dir) + self.dirl.SetLabel("Direction: %s"%(self.ticker.GetDirection())) + + + def OnChangeTickDirection(self, dir): + if self.ticker.GetDirection() == "rtl": + self.SetTickDirection("ltr") + else: + self.SetTickDirection("rtl") + + + def OnText(self, evt): + """Live update of the ticker text""" + self.ticker.SetText(self.txt.GetValue()) + + def ChangeTickFGColor(self, evt): + self.ticker.SetForegroundColour(evt.GetValue()) + + def ChangeTickBGColor(self, evt): + self.ticker.SetBackgroundColour(evt.GetValue()) + + def ChangeFPS(self, evt): + self.ticker.SetFPS(evt.GetPosition()) + + def ChangePPF(self, evt): + self.ticker.SetPPF(evt.GetPosition()) + + + def ShutdownDemo(self): + self.ticker.Stop() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = wx.lib.ticker.__doc__ + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/TimeCtrl.py b/demo/TimeCtrl.py new file mode 100644 index 00000000..a94bd24d --- /dev/null +++ b/demo/TimeCtrl.py @@ -0,0 +1,239 @@ +# +# 11/21/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o presense of spin control causing probs (see spin ctrl demo for details) +# + +import wx +import wx.lib.scrolledpanel as scrolled +import wx.lib.masked as masked + +#---------------------------------------------------------------------- + +class TestPanel( scrolled.ScrolledPanel ): + def __init__( self, parent, log ): + + scrolled.ScrolledPanel.__init__( self, parent, -1 ) + self.log = log + + box_label = wx.StaticBox( self, -1, "Change Controls through API" ) + buttonbox = wx.StaticBoxSizer( box_label, wx.HORIZONTAL ) + + text1 = wx.StaticText( self, -1, "12-hour format:") + self.time12 = masked.TimeCtrl( self, -1, name="12 hour control" ) + h = self.time12.GetSize().height + spin1 = wx.SpinButton( self, -1, wx.DefaultPosition, (-1,h), wx.SP_VERTICAL ) + self.time12.BindSpinButton( spin1 ) + + text2 = wx.StaticText( self, -1, "24-hour format:") + spin2 = wx.SpinButton( self, -1, wx.DefaultPosition, (-1,h), wx.SP_VERTICAL ) + self.time24 = masked.TimeCtrl( + self, -1, name="24 hour control", fmt24hr=True, + spinButton = spin2 + ) + + text3 = wx.StaticText( self, -1, "No seconds\nor spin button:") + self.spinless_ctrl = masked.TimeCtrl( + self, -1, name="spinless control", + display_seconds = False + ) + + grid = wx.FlexGridSizer( cols=2, hgap=10, vgap=5 ) + grid.Add( text1, 0, wx.ALIGN_RIGHT ) + hbox1 = wx.BoxSizer( wx.HORIZONTAL ) + hbox1.Add( self.time12, 0, wx.ALIGN_CENTRE ) + hbox1.Add( spin1, 0, wx.ALIGN_CENTRE ) + grid.Add( hbox1, 0, wx.LEFT ) + + grid.Add( text2, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM ) + hbox2 = wx.BoxSizer( wx.HORIZONTAL ) + hbox2.Add( self.time24, 0, wx.ALIGN_CENTRE ) + hbox2.Add( spin2, 0, wx.ALIGN_CENTRE ) + grid.Add( hbox2, 0, wx.LEFT ) + + grid.Add( text3, 0, wx.ALIGN_RIGHT|wx.TOP|wx.BOTTOM ) + grid.Add( self.spinless_ctrl, 0, wx.LEFT ) + + + buttonChange = wx.Button( self, -1, "Change Controls") + self.radio12to24 = wx.RadioButton( + self, -1, "Copy 12-hour time to 24-hour control", + wx.DefaultPosition, wx.DefaultSize, wx.RB_GROUP + ) + + self.radio24to12 = wx.RadioButton( + self, -1, "Copy 24-hour time to 12-hour control" + ) + + self.radioWx = wx.RadioButton( self, -1, "Set controls to 'now' using wxDateTime") + self.radioMx = wx.RadioButton( self, -1, "Set controls to 'now' using mxDateTime") + + radio_vbox = wx.BoxSizer( wx.VERTICAL ) + radio_vbox.Add( self.radio12to24, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + radio_vbox.Add( self.radio24to12, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + radio_vbox.Add( self.radioWx, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + radio_vbox.Add( self.radioMx, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + + buttonbox.Add( buttonChange, 0, wx.ALIGN_CENTRE|wx.ALL, 5 ) + buttonbox.Add( radio_vbox, 0, wx.ALIGN_CENTRE|wx.ALL, 5 ) + + hbox = wx.BoxSizer( wx.HORIZONTAL ) + hbox.Add( grid, 0, wx.ALIGN_LEFT|wx.ALL, 15 ) + hbox.Add( buttonbox, 0, wx.ALIGN_RIGHT|wx.BOTTOM, 20 ) + + + box_label = wx.StaticBox( self, -1, "Bounds Control" ) + boundsbox = wx.StaticBoxSizer( box_label, wx.HORIZONTAL ) + self.set_bounds = wx.CheckBox( self, -1, "Set time bounds:" ) + + minlabel = wx.StaticText( self, -1, "minimum time:" ) + self.min = masked.TimeCtrl( self, -1, name="min", display_seconds = False ) + self.min.Enable( False ) + + maxlabel = wx.StaticText( self, -1, "maximum time:" ) + self.max = masked.TimeCtrl( self, -1, name="max", display_seconds = False ) + self.max.Enable( False ) + + self.limit_check = wx.CheckBox( self, -1, "Limit control" ) + + label = wx.StaticText( self, -1, "Resulting time control:" ) + self.target_ctrl = masked.TimeCtrl( self, -1, name="new" ) + + grid2 = wx.FlexGridSizer( cols=2 ) + grid2.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid2.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + grid2.Add( self.set_bounds, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid3 = wx.FlexGridSizer( cols=2, hgap=5, vgap=5 ) + grid3.Add(minlabel, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL ) + grid3.Add( self.min, 0, wx.ALIGN_LEFT ) + grid3.Add(maxlabel, 0, wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL ) + grid3.Add( self.max, 0, wx.ALIGN_LEFT ) + grid2.Add(grid3, 0, wx.ALIGN_LEFT ) + + grid2.Add( self.limit_check, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid2.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + grid2.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid2.Add( (20, 0), 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + grid2.Add( label, 0, wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5 ) + grid2.Add( self.target_ctrl, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + boundsbox.Add(grid2, 0, wx.ALIGN_CENTER|wx.EXPAND|wx.ALL, 5) + + vbox = wx.BoxSizer( wx.VERTICAL ) + vbox.Add( (20, 20) ) + vbox.Add( hbox, 0, wx.ALIGN_LEFT|wx.ALL, 5) + vbox.Add( boundsbox, 0, wx.ALIGN_LEFT|wx.ALL, 5 ) + + + outer_box = wx.BoxSizer( wx.VERTICAL ) + outer_box.Add( vbox, 0, wx.ALIGN_LEFT|wx.ALL, 5) + + + # Turn on mxDateTime option only if we can import the module: + try: + from mx import DateTime + except ImportError: + self.radioMx.Enable( False ) + + + self.SetAutoLayout( True ) + self.SetSizer( outer_box ) + outer_box.Fit( self ) + self.SetupScrolling() + + self.Bind(wx.EVT_BUTTON, self.OnButtonClick, buttonChange ) + self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.time12 ) + self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.time24 ) + self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.spinless_ctrl ) + self.Bind(wx.EVT_CHECKBOX, self.OnBoundsCheck, self.set_bounds ) + self.Bind(wx.EVT_CHECKBOX, self.SetTargetMinMax, self.limit_check ) + self.Bind(masked.EVT_TIMEUPDATE, self.SetTargetMinMax, self.min ) + self.Bind(masked.EVT_TIMEUPDATE, self.SetTargetMinMax, self.max ) + self.Bind(masked.EVT_TIMEUPDATE, self.OnTimeChange, self.target_ctrl ) + + + def OnTimeChange( self, event ): + timectrl = self.FindWindowById( event.GetId() ) + ib_str = [ " (out of bounds)", "" ] + + self.log.write('%s time = %s%s\n' % ( timectrl.GetName(), timectrl.GetValue(), ib_str[ timectrl.IsInBounds() ] ) ) + + + def OnButtonClick( self, event ): + if self.radio12to24.GetValue(): + self.time24.SetValue( self.time12.GetValue() ) + + elif self.radio24to12.GetValue(): + self.time12.SetValue( self.time24.GetValue() ) + + elif self.radioWx.GetValue(): + now = wx.DateTime_Now() + self.time12.SetValue( now ) + # (demonstrates that G/SetValue returns/takes a wx.DateTime) + self.time24.SetValue( self.time12.GetValue(as_wxDateTime=True) ) + + # (demonstrates that G/SetValue returns/takes a wx.TimeSpan) + self.spinless_ctrl.SetValue( self.time12.GetValue(as_wxTimeSpan=True) ) + + elif self.radioMx.GetValue(): + from mx import DateTime + now = DateTime.now() + self.time12.SetValue( now ) + + # (demonstrates that G/SetValue returns/takes a DateTime) + self.time24.SetValue( self.time12.GetValue(as_mxDateTime=True) ) + + # (demonstrates that G/SetValue returns/takes a DateTimeDelta) + self.spinless_ctrl.SetValue( self.time12.GetValue(as_mxDateTimeDelta=True) ) + + + def OnBoundsCheck( self, event ): + self.min.Enable( self.set_bounds.GetValue() ) + self.max.Enable( self.set_bounds.GetValue() ) + self.SetTargetMinMax() + + + def SetTargetMinMax( self, event=None ): + min = None + max = None + + if self.set_bounds.GetValue(): + min = self.min.GetWxDateTime() + max = self.max.GetWxDateTime() + else: + min, max = None, None + + cur_min, cur_max = self.target_ctrl.GetBounds() + print cur_min, min + if min and (min != cur_min): self.target_ctrl.SetMin( min ) + if max and (max != cur_max): self.target_ctrl.SetMax( max ) + + self.target_ctrl.SetLimited( self.limit_check.GetValue() ) + + if min != cur_min or max != cur_max: + new_min, new_max = self.target_ctrl.GetBounds() + + if new_min and new_max: + self.log.write( "current min, max: (%s, %s)\n" % ( new_min.FormatTime(), new_max.FormatTime() ) ) + else: + self.log.write( "current min, max: (None, None)\n" ) + +#---------------------------------------------------------------------- + +def runTest( frame, nb, log ): + win = TestPanel( nb, log ) + return win + +#---------------------------------------------------------------------- +import wx.lib.masked.timectrl as timectl +overview = """ +

+""" + timectl.__doc__ + """
+
""" + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])]) + diff --git a/demo/Timer.py b/demo/Timer.py new file mode 100644 index 00000000..4ed40872 --- /dev/null +++ b/demo/Timer.py @@ -0,0 +1,267 @@ +import time +import wx +import wx.lib.scrolledpanel as sp + +#---------------------------------------------------------------------- + + +header = """\ +This demo shows the various ways that wx.Timers can be used in your code. Just +select one of the buttons in the left column to start a timer in the indicated way, +and watch the log window below for messages printed when the timer event or callback +happens. Clicking the corresponding button on the right will stop that timer. Since +timers are not owned by any other wx object you should hold on to a reference to the +timer until you are completely finished with it. """ + +doc1 = """\ +Binding an event handler to the wx.EVT_TIMER event is the +prefered way to use the wx.Timer class directly. It makes +handling timer events work just like normal window events. You +just need to specify the window that is to receive the event in +the wx.Timer constructor. If that window needs to be able to +receive events from more than one timer then you can optionally +specify an ID for the timer and the event binding. +""" + + +doc2 = """\ +wx.CallLater is a convenience class for wx.Timer. You just +specify the timeout in milliseconds and a callable object, along +with any args or keyword args you would like to be passed to your +callable, and wx.CallLater takes care of the rest. If you don't +need to get the return value of the callable or to restart the +timer then there is no need to hold a reference to this object. +""" + + +doc3 = """\ +If you derive a class from wx.Timer and give it a Notify method +then it will be called when the timer expires. +""" + + +doc4 = """\ +wx.PyTimer is the old way (a kludge that goes back all the way to +the first version of wxPython) to bind a timer directly to a +callable. You should migrate any code that uses this method to +use EVT_TIMER instead as this may be deprecated in the future. +""" + + +class TestPanel(sp.ScrolledPanel): + def __init__(self, parent, log): + self.log = log + sp.ScrolledPanel.__init__(self, parent, -1) + + outsideSizer = wx.BoxSizer(wx.VERTICAL) + + text = wx.StaticText(self, -1, "wx.Timer", style=wx.ALIGN_CENTRE) + text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + text.SetSize(text.GetBestSize()) + text.SetForegroundColour(wx.BLUE) + outsideSizer.Add(text, 0, wx.EXPAND|wx.ALL, 5) + outsideSizer.Add(wx.StaticText(self, -1, header), 0, wx.ALIGN_CENTER|wx.ALL, 5) + outsideSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) + outsideSizer.Add((20,20)) + + + t1b1 = wx.Button(self, -1, "EVT_TIMER") + t1b2 = wx.Button(self, -1, "stop timer") + t1st = wx.StaticText(self, -1, doc1) + t1b2.Disable() + self.Bind(wx.EVT_BUTTON, self.OnTest1Start, t1b1) + self.Bind(wx.EVT_BUTTON, self.OnTest1Stop, t1b2) + + # Bind all EVT_TIMER events to self.OnTest1Timer + self.Bind(wx.EVT_TIMER, self.OnTest1Timer) + + + t2b1 = wx.Button(self, -1, "wx.CallLater") + t2b2 = wx.Button(self, -1, "stop timer") + t2st = wx.StaticText(self, -1, doc2) + t2b2.Disable() + self.Bind(wx.EVT_BUTTON, self.OnTest2Start, t2b1) + self.Bind(wx.EVT_BUTTON, self.OnTest2Stop, t2b2) + + t3b1 = wx.Button(self, -1, "self.Notify") + t3b2 = wx.Button(self, -1, "stop timer") + t3st = wx.StaticText(self, -1, doc3) + t3b2.Disable() + self.Bind(wx.EVT_BUTTON, self.OnTest3Start, t3b1) + self.Bind(wx.EVT_BUTTON, self.OnTest3Stop, t3b2) + + t4b1 = wx.Button(self, -1, "wx.PyTimer") + t4b2 = wx.Button(self, -1, "stop timer") + t4st = wx.StaticText(self, -1, doc4) + t4b2.Disable() + self.Bind(wx.EVT_BUTTON, self.OnTest4Start, t4b1) + self.Bind(wx.EVT_BUTTON, self.OnTest4Stop, t4b2) + + + self.t1b2 = t1b2 + self.t2b2 = t2b2 + self.t3b2 = t3b2 + self.t4b2 = t4b2 + + fgs = wx.FlexGridSizer(cols=3, hgap=10, vgap=10) + fgs.Add(t1b1) + fgs.Add(t1b2) + fgs.Add(t1st) + + fgs.Add(t2b1) + fgs.Add(t2b2) + fgs.Add(t2st) + + fgs.Add(t3b1) + fgs.Add(t3b2) + fgs.Add(t3st) + + fgs.Add(t4b1) + fgs.Add(t4b2) + fgs.Add(t4st) + + outsideSizer.Add(fgs, 0, wx.ALIGN_CENTER|wx.ALL, 10) + self.SetSizer(outsideSizer) + self.SetupScrolling() + + + # Test 1 shows how to use a timer to generate EVT_TIMER + # events, by passing self to the wx.Timer constructor. The + # event is bound above to the OnTest1Timer method. + + def OnTest1Start(self, evt): + self.t1 = wx.Timer(self) + self.t1.Start(1000) + self.log.write("EVT_TIMER timer started\n") + self.t1b2.Enable() + + def OnTest1Stop(self, evt): + self.t1.Stop() + self.log.write("EVT_TIMER timer stoped\n") + del self.t1 + self.t1b2.Disable() + + def OnTest1Timer(self, evt): + self.log.write("got EVT_TIMER event\n") + + + + # Test 2 shows how to use the wx.CallLater class. + + def OnTest2Start(self, evt): + # Call OnTest2Timer one second in the future, passing some + # optional arbitrary args. There is no need to hold a + # reference to this one, unless we want to manipulate or query + # it later like we do in the two methods below + self.t2 = wx.CallLater(1000, self.OnTest2Timer, + 'a', 'b', 'c', one=1, two=2) + self.log.write("CallLater scheduled\n") + self.t2b2.Enable() + + def OnTest2Stop(self, evt): + self.t2.Stop() + self.log.write("CallLater stopped, last return value was: %s\n" % + repr(self.t2.GetResult())) + del self.t2 + self.t2b2.Disable() + + def OnTest2Timer(self, *args, **kw): + self.log.write("CallLater called with args=%s, kwargs=%s\n" % (args, kw)) + + # Normally a FutureCall is one-shot, but we can make it + # recurring just by calling Restart. We can even use a + # different timeout or pass differnt args this time. + self.t2.Restart(1500, "restarted") + + # The return value of this function is saved and can be + # retrived later. See OnTest2Stop above. + return "This is my return value" + + + + # Test 3 shows how to use a class derived from wx.Timer. See + # also the NotifyTimer class below. + + def OnTest3Start(self, evt): + self.t3 = NotifyTimer(self.log) + self.t3.Start(1000) + self.log.write("NotifyTimer timer started\n") + self.t3b2.Enable() + + def OnTest3Stop(self, evt): + self.t3.Stop() + self.log.write("NotifyTimer timer stoped\n") + del self.t3 + self.t3b2.Disable() + + + + # Test 4 shows the old way (a kludge that goes back all the + # way to the first version of wxPython) to bind a timer + # directly to a callable. You should migrate any code that + # uses this method to use EVT_TIMER instead as this may be + # deprecated in the future. + def OnTest4Start(self, evt): + self.t4 = wx.PyTimer(self.OnTest4Timer) + self.t4.Start(1000) + self.log.write("wx.PyTimer timer started\n") + self.t4b2.Enable() + + def OnTest4Stop(self, evt): + self.t4.Stop() + self.log.write("wx.PyTimer timer stoped\n") + del self.t4 + self.t4b2.Disable() + + def OnTest4Timer(self): + self.log.write("got wx.PyTimer event\n") + + + +#---------------------------------------------------------------------- + + +# When deriving from wx.Timer you must provide a Notify method +# that will be called when the timer expires. +class NotifyTimer(wx.Timer): + def __init__(self, log): + wx.Timer.__init__(self) + self.log = log + + def Notify(self): + self.log.write("got NotifyTimer event\n") + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#---------------------------------------------------------------------- + +overview = """ +

wx.Timer

+ +The wx.Timer class allows you to execute code at specified intervals +from within the wxPython event loop. Timers can be one-shot or +repeating. This demo shows the principle method of using a timer +(with events) as well as the convenient wx.FutureCall class. Also +there are two other usage patterns shown here that have been preserved +for backwards compatibility. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + + diff --git a/demo/ToggleButton.py b/demo/ToggleButton.py new file mode 100644 index 00000000..50073863 --- /dev/null +++ b/demo/ToggleButton.py @@ -0,0 +1,53 @@ + +import wx +import images + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + panel = wx.Panel(self, -1) + buttons = wx.BoxSizer(wx.HORIZONTAL) + + for word in "These are toggle buttons".split(): + b = wx.ToggleButton(panel, -1, word) + self.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggle, b) + buttons.Add(b, flag=wx.ALL, border=5) + + panel.SetAutoLayout(True) + panel.SetSizer(buttons) + buttons.Fit(panel) + panel.Move((50,50)) + + b = wx.ToggleButton(self, -1, "can have bitmaps too", pos=(50,125)) + b.SetBitmap(images.Mondrian.Bitmap) + b.SetInitialSize() # adjust default size for the bitmap + self.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggle, b) + + def OnToggle(self, evt): + self.log.write("Button %d toggled\n" % evt.GetId()) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#---------------------------------------------------------------------- + + +overview = """\ +wx.ToggleButton is a button that stays pressed when clicked by the user. +In other words, it is similar to wxCheckBox in functionality but looks like a +wxButton. +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/ToolBar.py b/demo/ToolBar.py new file mode 100644 index 00000000..28f38905 --- /dev/null +++ b/demo/ToolBar.py @@ -0,0 +1,252 @@ + +import wx +import images + +FRAMETB = True +TBFLAGS = ( wx.TB_HORIZONTAL + | wx.NO_BORDER + | wx.TB_FLAT + #| wx.TB_TEXT + #| wx.TB_HORZ_LAYOUT + ) + +#--------------------------------------------------------------------------- + +class TestSearchCtrl(wx.SearchCtrl): + maxSearches = 5 + + def __init__(self, parent, id=-1, value="", + pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, + doSearch=None): + style |= wx.TE_PROCESS_ENTER + wx.SearchCtrl.__init__(self, parent, id, value, pos, size, style) + self.Bind(wx.EVT_TEXT_ENTER, self.OnTextEntered) + self.Bind(wx.EVT_MENU_RANGE, self.OnMenuItem, id=1, id2=self.maxSearches) + self.doSearch = doSearch + self.searches = [] + + def OnTextEntered(self, evt): + text = self.GetValue() + if self.doSearch(text): + self.searches.append(text) + if len(self.searches) > self.maxSearches: + del self.searches[0] + self.SetMenu(self.MakeMenu()) + self.SetValue("") + + def OnMenuItem(self, evt): + text = self.searches[evt.GetId()-1] + self.doSearch(text) + + def MakeMenu(self): + menu = wx.Menu() + item = menu.Append(-1, "Recent Searches") + item.Enable(False) + for idx, txt in enumerate(self.searches): + menu.Append(1+idx, txt) + return menu + + + +class TestToolBar(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, 'Test ToolBar', size=(600, 400)) + self.log = log + self.timer = None + self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) + + client = wx.Panel(self) + client.SetBackgroundColour(wx.NamedColour("WHITE")) + + if FRAMETB: + # Use the wxFrame internals to create the toolbar and + # associate it all in one tidy method call. By using + # CreateToolBar or SetToolBar the "client area" of the + # frame will be adjusted to exclude the toolbar. + tb = self.CreateToolBar( TBFLAGS ) + + # Here's a 'simple' toolbar example, and how to bind it using SetToolBar() + #tb = wx.ToolBarSimple(self, -1, wx.DefaultPosition, wx.DefaultSize, + # wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT) + #self.SetToolBar(tb) + # But we're doing it a different way here. + + else: + # The toolbar can also be a child of another widget, and + # be managed by a sizer, although there may be some + # implications of doing this on some platforms. + tb = wx.ToolBar(client, style=TBFLAGS) + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(tb, 0, wx.EXPAND) + client.SetSizer(sizer) + + + log.write("Default toolbar tool size: %s\n" % tb.GetToolBitmapSize()) + + self.CreateStatusBar() + + tsize = (24,24) + new_bmp = wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_TOOLBAR, tsize) + open_bmp = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR, tsize) + copy_bmp = wx.ArtProvider.GetBitmap(wx.ART_COPY, wx.ART_TOOLBAR, tsize) + paste_bmp= wx.ArtProvider.GetBitmap(wx.ART_PASTE, wx.ART_TOOLBAR, tsize) + + tb.SetToolBitmapSize(tsize) + + #tb.AddSimpleTool(10, new_bmp, "New", "Long help for 'New'") + tb.AddLabelTool(10, "New", new_bmp, shortHelp="New", longHelp="Long help for 'New'") + self.Bind(wx.EVT_TOOL, self.OnToolClick, id=10) + self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=10) + + #tb.AddSimpleTool(20, open_bmp, "Open", "Long help for 'Open'") + tb.AddLabelTool(20, "Open", open_bmp, shortHelp="Open", longHelp="Long help for 'Open'") + self.Bind(wx.EVT_TOOL, self.OnToolClick, id=20) + self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=20) + + tb.AddSeparator() + tb.AddSimpleTool(30, copy_bmp, "Copy", "Long help for 'Copy'") + self.Bind(wx.EVT_TOOL, self.OnToolClick, id=30) + self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=30) + + tb.AddSimpleTool(40, paste_bmp, "Paste", "Long help for 'Paste'") + self.Bind(wx.EVT_TOOL, self.OnToolClick, id=40) + self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick, id=40) + + tb.AddSeparator() + + #tool = tb.AddCheckTool(50, images.Tog1.GetBitmap(), shortHelp="Toggle this") + tool = tb.AddCheckLabelTool(50, "Checkable", images.Tog1.GetBitmap(), + shortHelp="Toggle this") + self.Bind(wx.EVT_TOOL, self.OnToolClick, id=50) + + self.Bind(wx.EVT_TOOL_ENTER, self.OnToolEnter) + self.Bind(wx.EVT_TOOL_RCLICKED, self.OnToolRClick) # Match all + self.Bind(wx.EVT_TIMER, self.OnClearSB) + + tb.AddSeparator() + cbID = wx.NewId() + + tb.AddControl( + wx.ComboBox( + tb, cbID, "", choices=["", "This", "is a", "wx.ComboBox"], + size=(150,-1), style=wx.CB_DROPDOWN + )) + self.Bind(wx.EVT_COMBOBOX, self.OnCombo, id=cbID) + + tb.AddStretchableSpace() + search = TestSearchCtrl(tb, size=(150,-1), doSearch=self.DoSearch) + tb.AddControl(search) + + # Final thing to do for a toolbar is call the Realize() method. This + # causes it to render (more or less, that is). + tb.Realize() + + + def DoSearch(self, text): + # called by TestSearchCtrl + self.log.WriteText("DoSearch: %s\n" % text) + # return true to tell the search ctrl to remember the text + return True + + + def OnToolClick(self, event): + self.log.WriteText("tool %s clicked\n" % event.GetId()) + #tb = self.GetToolBar() + tb = event.GetEventObject() + tb.EnableTool(10, not tb.GetToolEnabled(10)) + + def OnToolRClick(self, event): + self.log.WriteText("tool %s right-clicked\n" % event.GetId()) + + def OnCombo(self, event): + self.log.WriteText("combobox item selected: %s\n" % event.GetString()) + + def OnToolEnter(self, event): + self.log.WriteText('OnToolEnter: %s, %s\n' % (event.GetId(), event.GetInt())) + + if self.timer is None: + self.timer = wx.Timer(self) + + if self.timer.IsRunning(): + self.timer.Stop() + + self.timer.Start(2000) + event.Skip() + + + def OnClearSB(self, event): # called for the timer event handler + self.SetStatusText("") + self.timer.Stop() + self.timer = None + + + def OnCloseWindow(self, event): + if self.timer is not None: + self.timer.Stop() + self.timer = None + self.Destroy() + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show the ToolBar sample", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = TestToolBar(self, self.log) + win.Show(True) + self.frame = win + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + + + +overview = """\ +wx.ToolBar is a narrow strip of icons on one side of a frame (top, bottom, sides) +that acts much like a menu does, except it is always visible. Additionally, actual +wxWindows controls, such as wx.TextCtrl or wx.ComboBox, can be added to the toolbar +and used from within it. + +Toolbar creation is a two-step process. First, the toolbar is defined using the +various Add* methods of wx.ToolBar. Once all is set up, then wx.Toolbar.Realize() +must be called to render it. + +wx.Toolbar events are also propogated as Menu events; this is especially handy when +you have a menu bar that contains items that carry out the same function. For example, +it is not uncommon to have a little 'floppy' toolbar icon to 'save' the current file +(whatever it is) as well as a FILE/SAVE menu item that does the same thing. In this +case, both events can be captured and acted upon using the same event handler +with no ill effects. + +If there are cases where a toolbar icon should *not* be associated with a menu item, +use a unique ID to trap it. + +There are a number of ways to create a toolbar for a wx.Frame. wx.Frame.CreateToolBar() +does all the work except it adds no buttons at all unless you override the virtual method +OnCreateToolBar(). On the other hand, you can just subclass wx.ToolBar and then use +wx.Frame.SetToolBar() instead. + +Note that wx.TB_DOCKABLE is only supported under GTK. An attempt to alleviate this +is provided in wx.lib.floatbar, but it is not formally supported. +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Toolbook.py b/demo/Toolbook.py new file mode 100644 index 00000000..61dd9acf --- /dev/null +++ b/demo/Toolbook.py @@ -0,0 +1,110 @@ + +import wx + +import ColorPanel +import images + +colourList = [ "Aquamarine", "Grey", "Blue", "Blue Violet", "Brown", "Cadet Blue", + "Coral", "Wheat", #"Cyan", "Dark Grey", "Dark Green", + #"Steel Blue", + ] + +#---------------------------------------------------------------------------- + +def getNextImageID(count): + imID = 0 + while True: + yield imID + imID += 1 + if imID == count: + imID = 0 + + +class TestTB(wx.Toolbook): + def __init__(self, parent, id, log): + wx.Toolbook.__init__(self, parent, id, style= + wx.BK_DEFAULT + #wx.BK_TOP + #wx.BK_BOTTOM + #wx.BK_LEFT + #wx.BK_RIGHT + ) + self.log = log + + # make an image list using the LBXX images + il = wx.ImageList(32, 32) + for x in range(12): + obj = getattr(images, 'LB%02d' % (x+1)) + bmp = obj.GetBitmap() + il.Add(bmp) + self.AssignImageList(il) + imageIdGenerator = getNextImageID(il.GetImageCount()) + + # Now make a bunch of panels for the list book + first = True + for colour in colourList: + win = self.makeColorPanel(colour) + self.AddPage(win, colour, imageId=imageIdGenerator.next()) + if first: + st = wx.StaticText(win.win, -1, + "You can put nearly any type of window here,\n" + "and the toolbar can be on either side of the Toolbook", + wx.Point(10, 10)) + first = False + + self.Bind(wx.EVT_TOOLBOOK_PAGE_CHANGED, self.OnPageChanged) + self.Bind(wx.EVT_TOOLBOOK_PAGE_CHANGING, self.OnPageChanging) + + + def makeColorPanel(self, color): + p = wx.Panel(self, -1) + win = ColorPanel.ColoredPanel(p, color) + p.win = win + def OnCPSize(evt, win=win): + win.SetPosition((0,0)) + win.SetSize(evt.GetSize()) + p.Bind(wx.EVT_SIZE, OnCPSize) + return p + + + def OnPageChanged(self, event): + old = event.GetOldSelection() + new = event.GetSelection() + sel = self.GetSelection() + self.log.write('OnPageChanged, old:%d, new:%d, sel:%d\n' % (old, new, sel)) + event.Skip() + + def OnPageChanging(self, event): + old = event.GetOldSelection() + new = event.GetSelection() + sel = self.GetSelection() + self.log.write('OnPageChanging, old:%d, new:%d, sel:%d\n' % (old, new, sel)) + event.Skip() + +#---------------------------------------------------------------------------- + +def runTest(frame, nb, log): + testWin = TestTB(nb, -1, log) + return testWin + +#---------------------------------------------------------------------------- + + +overview = """\ + +

wx.Toolbook

+

+This class is a control similar to a notebook control, but with a +wx.Toolbar instead of a set of tabs. + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + diff --git a/demo/TreeCtrl.py b/demo/TreeCtrl.py new file mode 100644 index 00000000..b00d22de --- /dev/null +++ b/demo/TreeCtrl.py @@ -0,0 +1,211 @@ + +import string +import wx +import images + +#--------------------------------------------------------------------------- + +class MyTreeCtrl(wx.TreeCtrl): + def __init__(self, parent, id, pos, size, style, log): + wx.TreeCtrl.__init__(self, parent, id, pos, size, style) + self.log = log + + def OnCompareItems(self, item1, item2): + t1 = self.GetItemText(item1) + t2 = self.GetItemText(item2) + self.log.WriteText('compare: ' + t1 + ' <> ' + t2 + '\n') + if t1 < t2: return -1 + if t1 == t2: return 0 + return 1 + +#--------------------------------------------------------------------------- + +class TestTreeCtrlPanel(wx.Panel): + def __init__(self, parent, log): + # Use the WANTS_CHARS style so the panel doesn't eat the Return key. + wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS) + self.Bind(wx.EVT_SIZE, self.OnSize) + + self.log = log + tID = wx.NewId() + + self.tree = MyTreeCtrl(self, tID, wx.DefaultPosition, wx.DefaultSize, + wx.TR_HAS_BUTTONS + | wx.TR_EDIT_LABELS + #| wx.TR_MULTIPLE + #| wx.TR_HIDE_ROOT + , self.log) + + isz = (16,16) + il = wx.ImageList(isz[0], isz[1]) + fldridx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, isz)) + fldropenidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_OTHER, isz)) + fileidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, isz)) + smileidx = il.Add(images.Smiles.GetBitmap()) + + self.tree.SetImageList(il) + self.il = il + + # NOTE: For some reason tree items have to have a data object in + # order to be sorted. Since our compare just uses the labels + # we don't need any real data, so we'll just use None below for + # the item data. + + self.root = self.tree.AddRoot("The Root Item") + self.tree.SetPyData(self.root, None) + self.tree.SetItemImage(self.root, fldridx, wx.TreeItemIcon_Normal) + self.tree.SetItemImage(self.root, fldropenidx, wx.TreeItemIcon_Expanded) + + + for x in range(15): + child = self.tree.AppendItem(self.root, "Item %d" % x) + self.tree.SetPyData(child, None) + self.tree.SetItemImage(child, fldridx, wx.TreeItemIcon_Normal) + self.tree.SetItemImage(child, fldropenidx, wx.TreeItemIcon_Expanded) + + for y in range(5): + last = self.tree.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y))) + self.tree.SetPyData(last, None) + self.tree.SetItemImage(last, fldridx, wx.TreeItemIcon_Normal) + self.tree.SetItemImage(last, fldropenidx, wx.TreeItemIcon_Expanded) + + for z in range(5): + item = self.tree.AppendItem(last, "item %d-%s-%d" % (x, chr(ord("a")+y), z)) + self.tree.SetPyData(item, None) + self.tree.SetItemImage(item, fileidx, wx.TreeItemIcon_Normal) + self.tree.SetItemImage(item, smileidx, wx.TreeItemIcon_Selected) + + self.tree.Expand(self.root) + self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded, self.tree) + self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, self.tree) + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, self.tree) + self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.tree) + self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnEndEdit, self.tree) + self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate, self.tree) + + self.tree.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick) + self.tree.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) + self.tree.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) + + + def OnRightDown(self, event): + pt = event.GetPosition(); + item, flags = self.tree.HitTest(pt) + if item: + self.log.WriteText("OnRightClick: %s, %s, %s\n" % + (self.tree.GetItemText(item), type(item), item.__class__)) + self.tree.SelectItem(item) + + + def OnRightUp(self, event): + pt = event.GetPosition(); + item, flags = self.tree.HitTest(pt) + if item: + self.log.WriteText("OnRightUp: %s (manually starting label edit)\n" + % self.tree.GetItemText(item)) + self.tree.EditLabel(item) + + + + def OnBeginEdit(self, event): + self.log.WriteText("OnBeginEdit\n") + # show how to prevent edit... + item = event.GetItem() + if item and self.tree.GetItemText(item) == "The Root Item": + wx.Bell() + self.log.WriteText("You can't edit this one...\n") + + # Lets just see what's visible of its children + cookie = 0 + root = event.GetItem() + (child, cookie) = self.tree.GetFirstChild(root) + + while child.IsOk(): + self.log.WriteText("Child [%s] visible = %d" % + (self.tree.GetItemText(child), + self.tree.IsVisible(child))) + (child, cookie) = self.tree.GetNextChild(root, cookie) + + event.Veto() + + + def OnEndEdit(self, event): + self.log.WriteText("OnEndEdit: %s %s\n" % + (event.IsEditCancelled(), event.GetLabel()) ) + # show how to reject edit, we'll not allow any digits + for x in event.GetLabel(): + if x in string.digits: + self.log.WriteText("You can't enter digits...\n") + event.Veto() + return + + + def OnLeftDClick(self, event): + pt = event.GetPosition(); + item, flags = self.tree.HitTest(pt) + if item: + self.log.WriteText("OnLeftDClick: %s\n" % self.tree.GetItemText(item)) + parent = self.tree.GetItemParent(item) + if parent.IsOk(): + self.tree.SortChildren(parent) + event.Skip() + + + def OnSize(self, event): + w,h = self.GetClientSizeTuple() + self.tree.SetDimensions(0, 0, w, h) + + + def OnItemExpanded(self, event): + item = event.GetItem() + if item: + self.log.WriteText("OnItemExpanded: %s\n" % self.tree.GetItemText(item)) + + def OnItemCollapsed(self, event): + item = event.GetItem() + if item: + self.log.WriteText("OnItemCollapsed: %s\n" % self.tree.GetItemText(item)) + + def OnSelChanged(self, event): + self.item = event.GetItem() + if self.item: + self.log.WriteText("OnSelChanged: %s\n" % self.tree.GetItemText(self.item)) + if wx.Platform == '__WXMSW__': + self.log.WriteText("BoundingRect: %s\n" % + self.tree.GetBoundingRect(self.item, True)) + #items = self.tree.GetSelections() + #print map(self.tree.GetItemText, items) + event.Skip() + + + def OnActivate(self, event): + if self.item: + self.log.WriteText("OnActivate: %s\n" % self.tree.GetItemText(self.item)) + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestTreeCtrlPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + + + + +overview = """\ +A TreeCtrl presents information as a hierarchy, with items that may be +expanded to show further items. Items in a tree control are referenced by +wx.TreeItemId handles. + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/TreeListCtrl.py b/demo/TreeListCtrl.py new file mode 100644 index 00000000..2518b2a2 --- /dev/null +++ b/demo/TreeListCtrl.py @@ -0,0 +1,121 @@ + +import wx +import wx.gizmos as gizmos + +import images + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + self.Bind(wx.EVT_SIZE, self.OnSize) + + self.tree = gizmos.TreeListCtrl(self, -1, style = + wx.TR_DEFAULT_STYLE + #| wx.TR_HAS_BUTTONS + #| wx.TR_TWIST_BUTTONS + #| wx.TR_ROW_LINES + #| wx.TR_COLUMN_LINES + #| wx.TR_NO_LINES + | wx.TR_FULL_ROW_HIGHLIGHT + ) + + isz = (16,16) + il = wx.ImageList(isz[0], isz[1]) + fldridx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, isz)) + fldropenidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, isz)) + fileidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, isz)) + smileidx = il.Add(images.Smiles.GetBitmap()) + + self.tree.SetImageList(il) + self.il = il + + # create some columns + self.tree.AddColumn("Main column") + self.tree.AddColumn("Column 1") + self.tree.AddColumn("Column 2") + self.tree.SetMainColumn(0) # the one with the tree in it... + self.tree.SetColumnWidth(0, 175) + + + self.root = self.tree.AddRoot("The Root Item") + self.tree.SetItemText(self.root, "col 1 root", 1) + self.tree.SetItemText(self.root, "col 2 root", 2) + self.tree.SetItemImage(self.root, fldridx, which = wx.TreeItemIcon_Normal) + self.tree.SetItemImage(self.root, fldropenidx, which = wx.TreeItemIcon_Expanded) + + + for x in range(15): + txt = "Item %d" % x + child = self.tree.AppendItem(self.root, txt) + self.tree.SetItemText(child, txt + "(c1)", 1) + self.tree.SetItemText(child, txt + "(c2)", 2) + self.tree.SetItemImage(child, fldridx, which = wx.TreeItemIcon_Normal) + self.tree.SetItemImage(child, fldropenidx, which = wx.TreeItemIcon_Expanded) + + for y in range(5): + txt = "item %d-%s" % (x, chr(ord("a")+y)) + last = self.tree.AppendItem(child, txt) + self.tree.SetItemText(last, txt + "(c1)", 1) + self.tree.SetItemText(last, txt + "(c2)", 2) + self.tree.SetItemImage(last, fldridx, which = wx.TreeItemIcon_Normal) + self.tree.SetItemImage(last, fldropenidx, which = wx.TreeItemIcon_Expanded) + + for z in range(5): + txt = "item %d-%s-%d" % (x, chr(ord("a")+y), z) + item = self.tree.AppendItem(last, txt) + self.tree.SetItemText(item, txt + "(c1)", 1) + self.tree.SetItemText(item, txt + "(c2)", 2) + self.tree.SetItemImage(item, fileidx, which = wx.TreeItemIcon_Normal) + self.tree.SetItemImage(item, smileidx, which = wx.TreeItemIcon_Selected) + + + self.tree.Expand(self.root) + + self.tree.GetMainWindow().Bind(wx.EVT_RIGHT_UP, self.OnRightUp) + self.tree.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnActivate) + + + def OnActivate(self, evt): + self.log.write('OnActivate: %s' % self.tree.GetItemText(evt.GetItem())) + + + def OnRightUp(self, evt): + pos = evt.GetPosition() + item, flags, col = self.tree.HitTest(pos) + if item: + self.log.write('Flags: %s, Col:%s, Text: %s' % + (flags, col, self.tree.GetItemText(item, col))) + + def OnSize(self, evt): + self.tree.SetSize(self.GetSize()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

TreeListCtrl

+ +The TreeListCtrl is essentially a wx.TreeCtrl with extra columns, +such that the look is similar to a wx.ListCtrl. + + +""" + + +if __name__ == '__main__': + #raw_input("Press enter...") + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/TreeMixin.py b/demo/TreeMixin.py new file mode 100644 index 00000000..059ddd61 --- /dev/null +++ b/demo/TreeMixin.py @@ -0,0 +1,265 @@ +import wx, wx.lib.customtreectrl, wx.gizmos +try: + import treemixin +except ImportError: + from wx.lib.mixins import treemixin + +overview = treemixin.__doc__ + +class TreeModel(object): + ''' TreeModel holds the domain objects that are shown in the different + tree controls. Each domain object is simply a two-tuple consisting of + a label and a list of child tuples, i.e. (label, [list of child tuples]). + ''' + def __init__(self, *args, **kwargs): + self.items = [] + self.itemCounter = 0 + super(TreeModel, self).__init__(*args, **kwargs) + + def GetItem(self, indices): + text, children = 'Hidden root', self.items + for index in indices: + text, children = children[index] + return text, children + + def GetText(self, indices): + return self.GetItem(indices)[0] + + def GetChildren(self, indices): + return self.GetItem(indices)[1] + + def GetChildrenCount(self, indices): + return len(self.GetChildren(indices)) + + def SetChildrenCount(self, indices, count): + children = self.GetChildren(indices) + while len(children) > count: + children.pop() + while len(children) < count: + children.append(('item %d'%self.itemCounter, [])) + self.itemCounter += 1 + + def MoveItem(self, itemToMoveIndex, newParentIndex): + itemToMove = self.GetItem(itemToMoveIndex) + newParentChildren = self.GetChildren(newParentIndex) + newParentChildren.append(itemToMove) + oldParentChildren = self.GetChildren(itemToMoveIndex[:-1]) + oldParentChildren.remove(itemToMove) + + +class DemoTreeMixin(treemixin.VirtualTree, treemixin.DragAndDrop, + treemixin.ExpansionState): + def __init__(self, *args, **kwargs): + self.model = kwargs.pop('treemodel') + self.log = kwargs.pop('log') + super(DemoTreeMixin, self).__init__(*args, **kwargs) + self.CreateImageList() + + def CreateImageList(self): + size = (16, 16) + self.imageList = wx.ImageList(*size) + for art in wx.ART_FOLDER, wx.ART_FILE_OPEN, wx.ART_NORMAL_FILE: + self.imageList.Add(wx.ArtProvider.GetBitmap(art, wx.ART_OTHER, + size)) + self.AssignImageList(self.imageList) + + def OnGetItemText(self, indices): + return self.model.GetText(indices) + + def OnGetChildrenCount(self, indices): + return self.model.GetChildrenCount(indices) + + def OnGetItemFont(self, indices): + # Show how to change the item font. Here we use a small font for + # items that have children and the default font otherwise. + if self.model.GetChildrenCount(indices) > 0: + return wx.SMALL_FONT + else: + return super(DemoTreeMixin, self).OnGetItemFont(indices) + + def OnGetItemTextColour(self, indices): + # Show how to change the item text colour. In this case second level + # items are coloured red and third level items are blue. All other + # items have the default text colour. + if len(indices) % 2 == 0: + return wx.RED + elif len(indices) % 3 == 0: + return wx.BLUE + else: + return super(DemoTreeMixin, self).OnGetItemTextColour(indices) + + def OnGetItemBackgroundColour(self, indices): + # Show how to change the item background colour. In this case the + # background colour of each third item is green. + if indices[-1] == 2: + return wx.GREEN + else: + return super(DemoTreeMixin, + self).OnGetItemBackgroundColour(indices) + + def OnGetItemImage(self, indices, which): + # Return the right icon depending on whether the item has children. + if which in [wx.TreeItemIcon_Normal, wx.TreeItemIcon_Selected]: + if self.model.GetChildrenCount(indices): + return 0 + else: + return 2 + else: + return 1 + + def OnDrop(self, dropTarget, dragItem): + dropIndex = self.GetIndexOfItem(dropTarget) + dropText = self.model.GetText(dropIndex) + dragIndex = self.GetIndexOfItem(dragItem) + dragText = self.model.GetText(dragIndex) + self.log.write('drop %s %s on %s %s'%(dragText, dragIndex, + dropText, dropIndex)) + self.model.MoveItem(dragIndex, dropIndex) + self.GetParent().RefreshItems() + + +class VirtualTreeCtrl(DemoTreeMixin, wx.TreeCtrl): + pass + + +class VirtualTreeListCtrl(DemoTreeMixin, wx.gizmos.TreeListCtrl): + def __init__(self, *args, **kwargs): + kwargs['style'] = wx.TR_DEFAULT_STYLE | wx.TR_FULL_ROW_HIGHLIGHT + super(VirtualTreeListCtrl, self).__init__(*args, **kwargs) + self.AddColumn('Column 0') + self.AddColumn('Column 1') + for art in wx.ART_TIP, wx.ART_WARNING: + self.imageList.Add(wx.ArtProvider.GetBitmap(art, wx.ART_OTHER, + (16, 16))) + + def OnGetItemText(self, indices, column=0): + # Return a different label depending on column. + return '%s, column %d'%\ + (super(VirtualTreeListCtrl, self).OnGetItemText(indices), column) + + def OnGetItemImage(self, indices, which, column=0): + # Also change the image of the other columns when the item has + # children. + if column == 0: + return super(VirtualTreeListCtrl, self).OnGetItemImage(indices, + which) + elif self.OnGetChildrenCount(indices): + return 4 + else: + return 3 + + +class VirtualCustomTreeCtrl(DemoTreeMixin, + wx.lib.customtreectrl.CustomTreeCtrl): + def __init__(self, *args, **kwargs): + self.checked = {} + kwargs['style'] = wx.TR_HIDE_ROOT | \ + wx.TR_HAS_BUTTONS | wx.TR_FULL_ROW_HIGHLIGHT + super(VirtualCustomTreeCtrl, self).__init__(*args, **kwargs) + self.Bind(wx.lib.customtreectrl.EVT_TREE_ITEM_CHECKED, + self.OnItemChecked) + + def OnGetItemType(self, indices): + if len(indices) == 1: + return 1 + elif len(indices) == 2: + return 2 + else: + return 0 + + def OnGetItemChecked(self, indices): + return self.checked.get(indices, False) + + def OnItemChecked(self, event): + item = event.GetItem() + itemIndex = self.GetIndexOfItem(item) + if self.GetItemType(item) == 2: + # It's a radio item; reset other items on the same level + for nr in range(self.GetChildrenCount(self.GetItemParent(item))): + self.checked[itemIndex[:-1]+(nr,)] = False + self.checked[itemIndex] = True + + + +class TreeNotebook(wx.Notebook): + def __init__(self, *args, **kwargs): + treemodel = kwargs.pop('treemodel') + log = kwargs.pop('log') + super(TreeNotebook, self).__init__(*args, **kwargs) + self.trees = [] + for class_, title in [(VirtualTreeCtrl, 'TreeCtrl'), + (VirtualTreeListCtrl, 'TreeListCtrl'), + (VirtualCustomTreeCtrl, 'CustomTreeCtrl')]: + tree = class_(self, treemodel=treemodel, log=log) + self.trees.append(tree) + self.AddPage(tree, title) + self.Bind(wx.EVT_NOTEBOOK_PAGE_CHANGED, self.OnPageChanged) + + def OnPageChanged(self, event): + oldTree = self.GetPage(event.OldSelection) + newTree = self.GetPage(event.Selection) + newTree.RefreshItems() + newTree.SetExpansionState(oldTree.GetExpansionState()) + event.Skip() + + def GetIndicesOfSelectedItems(self): + tree = self.trees[self.GetSelection()] + if tree.GetSelections(): + return [tree.GetIndexOfItem(item) for item in tree.GetSelections()] + else: + return [()] + + def RefreshItems(self): + tree = self.trees[self.GetSelection()] + tree.RefreshItems() + tree.UnselectAll() + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + super(TestPanel, self).__init__(parent) + self.treemodel = TreeModel() + self.CreateControls() + self.LayoutControls() + + def CreateControls(self): + self.notebook = TreeNotebook(self, treemodel=self.treemodel, + log=self.log) + self.label = wx.StaticText(self, label='Number of children: ') + self.childrenCountCtrl = wx.SpinCtrl(self, value='0', max=10000) + self.button = wx.Button(self, label='Update children') + self.button.Bind(wx.EVT_BUTTON, self.OnEnter) + + def LayoutControls(self): + hSizer = wx.BoxSizer(wx.HORIZONTAL) + options = dict(flag=wx.ALIGN_CENTER_VERTICAL|wx.ALL, border=2) + hSizer.Add(self.label, **options) + hSizer.Add(self.childrenCountCtrl, 2, **options) + hSizer.Add(self.button, **options) + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(self.notebook, 1, wx.EXPAND) + sizer.Add(hSizer, 0, wx.EXPAND) + self.SetSizer(sizer) + + def OnEnter(self, event): + indicesList = self.notebook.GetIndicesOfSelectedItems() + newChildrenCount = self.childrenCountCtrl.GetValue() + for indices in indicesList: + text = self.treemodel.GetText(indices) + oldChildrenCount = self.treemodel.GetChildrenCount(indices) + self.log.write('%s %s now has %d children (was %d)'%(text, indices, + newChildrenCount, oldChildrenCount)) + self.treemodel.SetChildrenCount(indices, newChildrenCount) + self.notebook.RefreshItems() + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +if __name__ == '__main__': + import sys, os, run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Treebook.py b/demo/Treebook.py new file mode 100644 index 00000000..5d96cf4a --- /dev/null +++ b/demo/Treebook.py @@ -0,0 +1,124 @@ + +import wx + +import ColorPanel +import images + +colourList = [ "Aquamarine", "Grey", "Blue", "Blue Violet", "Brown", "Cadet Blue", + "Coral", "Wheat", "Cyan", "Dark Grey", "Dark Green", + "Steel Blue", + ] + +#---------------------------------------------------------------------------- + +def getNextImageID(count): + imID = 0 + while True: + yield imID + imID += 1 + if imID == count: + imID = 0 + + +class TestTB(wx.Treebook): + def __init__(self, parent, id, log): + wx.Treebook.__init__(self, parent, id, style= + wx.BK_DEFAULT + #wx.BK_TOP + #wx.BK_BOTTOM + #wx.BK_LEFT + #wx.BK_RIGHT + ) + self.log = log + + # make an image list using the LBXX images + il = wx.ImageList(32, 32) + for x in range(12): + obj = getattr(images, 'LB%02d' % (x+1)) + bmp = obj.GetBitmap() + il.Add(bmp) + self.AssignImageList(il) + imageIdGenerator = getNextImageID(il.GetImageCount()) + + # Now make a bunch of panels for the list book + first = True + for colour in colourList: + win = self.makeColorPanel(colour) + self.AddPage(win, colour, imageId=imageIdGenerator.next()) + if first: + st = wx.StaticText(win.win, -1, + "You can put nearly any type of window here,\n" + "and the wx.TreeCtrl can be on either side of the\n" + "Treebook", + wx.Point(10, 10)) + first = False + + win = self.makeColorPanel(colour) + st = wx.StaticText(win.win, -1, "this is a sub-page", (10,10)) + self.AddSubPage(win, 'a sub-page', imageId=imageIdGenerator.next()) + + self.Bind(wx.EVT_TREEBOOK_PAGE_CHANGED, self.OnPageChanged) + self.Bind(wx.EVT_TREEBOOK_PAGE_CHANGING, self.OnPageChanging) + + # This is a workaround for a sizing bug on Mac... + wx.FutureCall(100, self.AdjustSize) + + def AdjustSize(self): + #print self.GetTreeCtrl().GetBestSize() + self.GetTreeCtrl().InvalidateBestSize() + self.SendSizeEvent() + #print self.GetTreeCtrl().GetBestSize() + + + def makeColorPanel(self, color): + p = wx.Panel(self, -1) + win = ColorPanel.ColoredPanel(p, color) + p.win = win + def OnCPSize(evt, win=win): + win.SetPosition((0,0)) + win.SetSize(evt.GetSize()) + p.Bind(wx.EVT_SIZE, OnCPSize) + return p + + + def OnPageChanged(self, event): + old = event.GetOldSelection() + new = event.GetSelection() + sel = self.GetSelection() + self.log.write('OnPageChanged, old:%d, new:%d, sel:%d\n' % (old, new, sel)) + event.Skip() + + def OnPageChanging(self, event): + old = event.GetOldSelection() + new = event.GetSelection() + sel = self.GetSelection() + self.log.write('OnPageChanging, old:%d, new:%d, sel:%d\n' % (old, new, sel)) + event.Skip() + +#---------------------------------------------------------------------------- + +def runTest(frame, nb, log): + testWin = TestTB(nb, -1, log) + return testWin + +#---------------------------------------------------------------------------- + + +overview = """\ + +

wx.Treebook

+

+This class is a control similar to a notebook control, but with a +wx.TreeCtrl instead of a set of tabs. + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + diff --git a/demo/UIActionSimulator.py b/demo/UIActionSimulator.py new file mode 100644 index 00000000..55987977 --- /dev/null +++ b/demo/UIActionSimulator.py @@ -0,0 +1,150 @@ + +import wx +import wx.lib.buttons as buttons + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + self.recordingKeys = False + self.stopwatchKeys = wx.StopWatch() + self.uisim = wx.UIActionSimulator() + + + # create widgets and bind events + keyLabel = wx.StaticText(self, -1, "Key Events") + keyLabel.SetFont(wx.FFont(18, wx.SWISS, wx.FONTFLAG_BOLD)) + + self.txt = wx.TextCtrl(self, size=(300,-1)) + self.txt.Bind(wx.EVT_KEY_DOWN, self.OnTxtKeyDown) + self.txt.Bind(wx.EVT_KEY_UP, self.OnTxtKeyUp) + + self.recordBtn = buttons.GenToggleButton(self, -1, "Record") + self.Bind(wx.EVT_BUTTON, self.OnToggleRecordKeys, self.recordBtn) + self.recordBtn.SetToolTipString( + "Click this button and then type some keys in the\n" + "textctrl. Click here again when done.") + + self.playbackKeysBtn = buttons.GenButton(self, -1, "Playback") + self.Bind(wx.EVT_BUTTON, self.OnPlaybackKeys, self.playbackKeysBtn) + self.playbackKeysBtn.SetToolTipString( + "Record some key events and then click here to\n" + "replay the recorded events.") + self.playbackKeysBtn.Disable() + + + # create the layout + gbs = wx.GridBagSizer(10,10) + gbs.Add(keyLabel, (0,0), span=(1,2)) + gbs.Add(self.txt, (1,1), span=(1,2)) + btnsizer = wx.BoxSizer(wx.HORIZONTAL) + btnsizer.Add(self.recordBtn) + btnsizer.Add((10,10)) + btnsizer.Add(self.playbackKeysBtn) + gbs.Add(btnsizer, (2,1), span=(1,2)) + + self.Sizer = wx.BoxSizer() + self.Sizer.Add(gbs, 1, wx.EXPAND|wx.ALL, 20) + + + def OnToggleRecordKeys(self, evt): + self.recordingKeys = not self.recordingKeys + if self.recordingKeys: + self.recordBtn.SetLabel('Recording') + self.keyEvents = list() + self.stopwatchKeys.Start() + self.playbackKeysBtn.Disable() + self.txt.Clear() + self.txt.SetFocus() + else: + self.playbackKeysBtn.Enable() + self.recordBtn.SetLabel('Record') + + + def OnPlaybackKeys(self, evt): + self._playbackEvents = self.keyEvents[:] # make a copy so we can pop() + if self._playbackEvents: + self.playbackKeysBtn.Disable() + self.txt.Clear() + self.txt.SetFocus() + self._setNextKeyEvent() + + + def _playbackKey(self, evtType, key, modifiers): + if evtType == 'down': + self.uisim.KeyDown(key, modifiers) + elif evtType == 'up': + self.uisim.KeyUp(key, modifiers) + + if self._playbackEvents: + self._setNextKeyEvent() + else: + self.playbackKeysBtn.Enable() + + + def _setNextKeyEvent(self): + evtType, key, modifiers, milli = self._playbackEvents.pop(0) + milli = max(milli/2, 1) # play back faster than it was recorded + print (evtType, key, modifiers, milli) + wx.CallLater(milli, self._playbackKey, evtType, key, modifiers) + + + def _onKeyEvent(self, evt, evtType): + evt.Skip() + if not self.recordingKeys: + return + evtInfo = ( evtType, + evt.KeyCode, + evt.Modifiers, + self.stopwatchKeys.Time(), + ) + self.keyEvents.append(evtInfo) + self.stopwatchKeys.Start() + + + def OnTxtKeyDown(self, evt): + self._onKeyEvent(evt, 'down') + + def OnTxtKeyUp(self, evt): + self._onKeyEvent(evt, 'up') + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + try: + uisim = wx.UIActionSimulator() + win = TestPanel(nb, log) + return win + except NotImplementedError: + from wx.lib.msgpanel import MessagePanel + win = MessagePanel(nb, + "This build of wxWidgets does not include the \n" + "wx.UIActionSimulator implementation.", + "Sorry", wx.ICON_WARNING) + return win + + +#---------------------------------------------------------------------- + + + +overview = """ +

UIActionSimulator

+ +wx.UIActionSimulator is a class that facilitates the injection of +mouse or keyboard events into the application's message queue. + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/URLDragAndDrop.py b/demo/URLDragAndDrop.py new file mode 100644 index 00000000..68795f66 --- /dev/null +++ b/demo/URLDragAndDrop.py @@ -0,0 +1,130 @@ + +import wx + +#---------------------------------------------------------------------- + +class MyURLDropTarget(wx.PyDropTarget): + def __init__(self, window): + wx.PyDropTarget.__init__(self) + self.window = window + + self.data = wx.URLDataObject(); + self.SetDataObject(self.data) + + def OnDragOver(self, x, y, d): + return wx.DragLink + + def OnData(self, x, y, d): + if not self.GetData(): + return wx.DragNone + + url = self.data.GetURL() + self.window.AppendText(url + "\n") + + return d + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + + self.SetAutoLayout(True) + outsideSizer = wx.BoxSizer(wx.VERTICAL) + + msg = "Drag-And-Drop of URLs" + text = wx.StaticText(self, -1, "", style=wx.ALIGN_CENTRE) + text.SetFont(wx.Font(24, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + text.SetLabel(msg) + w,h = text.GetTextExtent(msg) + text.SetSize(wx.Size(w,h+1)) + text.SetForegroundColour(wx.BLUE) + outsideSizer.Add(text, 0, wx.EXPAND|wx.ALL, 5) + outsideSizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) + outsideSizer.Add((20,20)) + + self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + + inSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5) + inSizer.AddGrowableCol(0) + + inSizer.Add((20,20)) + inSizer.Add((20,20)) + inSizer.Add(wx.StaticText(self, -1, + "Drag URLs from your browser to\nthis window:", + style = wx.ALIGN_RIGHT), + 0, wx.ALIGN_RIGHT ) + self.dropText = wx.TextCtrl(self, -1, "", size=(380, 180), + style=wx.TE_MULTILINE|wx.TE_READONLY) + inSizer.Add(self.dropText, 0, wx.EXPAND) + + + inSizer.Add(wx.StaticText(self, -1, + "Drag this URL to your browser:", + style = wx.ALIGN_RIGHT), + 0, wx.ALIGN_RIGHT ) + self.dragText = wx.TextCtrl(self, -1, "http://wxPython.org/") + inSizer.Add(self.dragText, 0, wx.EXPAND) + self.dragText.Bind(wx.EVT_MOTION, self.OnStartDrag) + + +## inSizer.Add(wx.StaticText(self, -1, +## "Drag this TEXT to your browser:", +## style = wx.ALIGN_RIGHT), +## 0, wx.ALIGN_RIGHT ) +## self.dragText2 = wx.TextCtrl(self, -1, "http://wxPython.org/") +## inSizer.Add(self.dragText2, 0, wx.EXPAND) +## self.dragText2.Bind(EVT_MOTION, self.OnStartDrag2) + + + outsideSizer.Add(inSizer, 1, wx.EXPAND) + self.SetSizer(outsideSizer) + + self.dropText.SetDropTarget(MyURLDropTarget(self.dropText)) + + + def OnStartDrag(self, evt): + if evt.Dragging(): + url = self.dragText.GetValue() + data = wx.URLDataObject() + data.SetURL(url) + + dropSource = wx.DropSource(self.dragText) + dropSource.SetData(data) + result = dropSource.DoDragDrop() + + + def OnStartDrag2(self, evt): + if evt.Dragging(): + url = self.dragText2.GetValue() + data = wx.TextDataObject() + data.SetText(url) + + dropSource = wx.DropSource(self.dragText2) + dropSource.SetData(data) + result = dropSource.DoDragDrop() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + + +overview = """\ +""" + + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Unicode.py b/demo/Unicode.py new file mode 100644 index 00000000..aa7373d5 --- /dev/null +++ b/demo/Unicode.py @@ -0,0 +1,153 @@ + +import wx + +#---------------------------------------------------------------------- + +# Some unicode strings +chi_uni = (u'Python \u662f\u6700\u597d\u7684\u7de8\u7a0b\u8a9e\u8a00\uff01', + 'Python is the best\nprogramming language!') + +lt1_uni = (u'Pythonas yra \u017eaviausia \u0161neka', + 'Python is the best') +lt2_uni = (u'A\u0161 m\u0117gstu \u0161okolad\u0105', + 'I like chocolate') + +kor_uni = (u'\ud30c\uc774\uc36c\uc740 \ucd5c\uace0\uc758 \ud504\ub85c\uadf8\ub798\ubc0d \uc5b8\uc5b4\uc774\ub2e4!', + 'Python is the best\nprogramming language!') + +bul_uni = (u'\u041f\u0438\u0442\u043e\u043d \u0435 \u043d\u0430\u0439-\u0434\u043e\u0431\u0440\u0438\u044f \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u0435\u043d \u0435\u0437\u0438\u043a!', + 'Python is the best\nprogramming language!') +rus_uni = (u'\u041f\u0438\u0442\u043e\u043d - \u043b\u0443\u0447\u0448\u0438\u0439 \u044f\u0437\u044b\u043a \n\u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f!', + 'Python is the best\nprogramming language!') + + +# Equivalents in UTF-8. Should I demo these somehow??? +chi_utf8 = ('Python \xe6\x98\xaf\xe6\x9c\x80\xe5\xa5\xbd\xe7\x9a\x84\xe7\xb7\xa8\xe7\xa8\x8b\xe8\xaa\x9e\xe8\xa8\x80\xef\xbc\x81', + 'Python is the best programming language') + +lt1_utf8 = ('Pythonas yra \xc5\xbeaviausia \xc5\xa1neka', + 'Python is the best') +lt2_utf8 = ('A\xc5\xa1 m\xc4\x97gstu \xc5\xa1okolad\xc4\x85', + 'I like chocolate') + +kor_utf8 = ('\xed\x8c\x8c\xec\x9d\xb4\xec\x8d\xac\xec\x9d\x80 \xec\xb5\x9c\xea\xb3\xa0\xec\x9d\x98 \xed\x94\x84\xeb\xa1\x9c\xea\xb7\xb8\xeb\x9e\x98\xeb\xb0\x8d \xec\x96\xb8\xec\x96\xb4\xec\x9d\xb4\xeb\x8b\xa4!', + 'Python is the best programming language!') + +bul_utf8 = ('\xd0\x9f\xd0\xb8\xd1\x82\xd0\xbe\xd0\xbd \xd0\xb5 \xd0\xbd\xd0\xb0\xd0\xb9-\xd0\xb4\xd0\xbe\xd0\xb1\xd1\x80\xd0\xb8\xd1\x8f \xd0\xbf\xd1\x80\xd0\xbe\xd0\xb3\xd1\x80\xd0\xb0\xd0\xbc\xd0\xb5\xd0\xbd \xd0\xb5\xd0\xb7\xd0\xb8\xd0\xba!', + 'Python is the best programming language!') +rus_utf8 = ('\xd0\x9f\xd0\xb8\xd1\x82\xd0\xbe\xd0\xbd - \xd0\xbb\xd1\x83\xd1\x87\xd1\x88\xd0\xb8\xd0\xb9 \xd1\x8f\xd0\xb7\xd1\x8b\xd0\xba \xd0\xbf\xd1\x80\xd0\xbe\xd0\xb3\xd1\x80\xd0\xb0\xd0\xbc\xd0\xbc\xd0\xb8\xd1\x80\xd0\xbe\xd0\xb2\xd0\xb0\xd0\xbd\xd0\xb8\xd1\x8f!', + 'Python is the best programming language!') + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + box = wx.BoxSizer(wx.VERTICAL) + + if not wx.USE_UNICODE: + self.AddLine(box) + self.AddText(box, "Sorry, this wxPython was not built with Unicode support.", + font = wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)) + self.AddLine(box) + + else: + font = self.GetFont() + font.SetPointSize(14) + font.SetWeight(wx.BOLD) + + self.AddLine(box) + self.AddText(box, chi_uni[0], chi_uni[1], 'Chinese:', font) + self.AddLine(box) + + self.AddText(box, lt1_uni[0], lt1_uni[1], 'Lithuanian:', font) + self.AddLine(box) + self.AddText(box, lt2_uni[0], lt2_uni[1], 'Lithuanian:', font) + self.AddLine(box) + + self.AddText(box, kor_uni[0], kor_uni[1], 'Korean:', font) + self.AddLine(box) + + self.AddText(box, bul_uni[0], bul_uni[1], 'Bulgarian:', font) + self.AddLine(box) + self.AddText(box, rus_uni[0], rus_uni[1], 'Russian:', font) + self.AddLine(box) + + + border = wx.BoxSizer(wx.VERTICAL) + border.Add(box, 1, wx.EXPAND|wx.ALL, 10) + self.SetAutoLayout(True) + self.SetSizer(border) + + + def AddLine(self, sizer): + sizer.Add(wx.StaticLine(self, -1), 0, wx.EXPAND) + + def AddText(self, sizer, text1, text2='', lang='', font=None): + # create some controls + lang = wx.StaticText(self, -1, lang) + text1 = wx.StaticText(self, -1, text1) + text2 = wx.StaticText(self, -1, text2, style=wx.ALIGN_RIGHT) + if font is not None: + text1.SetFont(font) + + # put them in a sizer + row = wx.BoxSizer(wx.HORIZONTAL) + row.Add(lang) + row.Add((15,10)) + row.Add(text1, 1, wx.EXPAND) + row.Add(text2) + + # put the row in the main sizer + sizer.Add(row, 0, wx.EXPAND|wx.ALL, 5) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wxPython Unicode Support

+ +

+wxWidgets and wxPython can be built to use either ANSI or Unicode strings. +This demo shows how Unicode can be used to support text in many different +languages using one locale when Unicode is enabled.

+ +

So what is the difference between the ANSI and Unicode builds?

+ +

If ANSI is used, Python strings (bytes) are always used, and you can only +display strings that use either the ASCII encoding, or the system's default +encoding. Any attempt to display other strings will result in garbled +characters.

+ +

When unicode is enabled, then all functions and methods in wxPython +that return a wxString will return an Python unicode object, and parameters +that expect a wxString can accept either a Python string or unicode object. (NOTE: If you aren't familiar with the difference between Python +strings and Unicode objects, you should view this Python Unicode Object introduction.) +If a string object is passed then it will be decoded into unicode using the +converter pointed to by wxConvCurrent, which will use the default +system encoding. If you need to use string in some other encoding +then you should convert it to unicode using the Python codecs first +and then pass the unicode to the wxPython method. + + + +""" + + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/VListBox.py b/demo/VListBox.py new file mode 100644 index 00000000..e0ef9a1f --- /dev/null +++ b/demo/VListBox.py @@ -0,0 +1,175 @@ + +import wx +from wx import html + +#---------------------------------------------------------------------- + +# The wx.VListBox is much like a regular wx.ListBox except you draw the +# items yourself and the items can vary in height. +class MyVListBox(wx.VListBox): + + # This method must be overridden. When called it should draw the + # n'th item on the dc within the rect. How it is drawn, and what + # is drawn is entirely up to you. + def OnDrawItem(self, dc, rect, n): + if self.GetSelection() == n: + c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT) + else: + c = self.GetForegroundColour() + dc.SetFont(self.GetFont()) + dc.SetTextForeground(c) + dc.DrawLabel(self._getItemText(n), rect, + wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL) + + # This method must be overridden. It should return the height + # required to draw the n'th item. + def OnMeasureItem(self, n): + height = 0 + for line in self._getItemText(n).split('\n'): + w, h = self.GetTextExtent(line) + height += h + return height + 5 + + + # These are also overridable: + # + # OnDrawSeparator(dc, rect, n) + # Draw a separator between items. Note that rect may be reduced + # in size if desired so OnDrawItem gets a smaller rect. + # + # OnDrawBackground(dc, rect, n) + # Draw the background and maybe a border if desired. + + + def _getItemText(self, item): + if item % 2 == 0: + return "This is item# %d" % item + else: + return "This is item# %d\n with an extra line" % item + +#---------------------------------------------------------------------- + +# The wx.HtmlListBox derives from wx.VListBox, but draws each item +# itself as a wx.HtmlCell. +class MyHtmlListBox(wx.HtmlListBox): + + def __init__(self, *args, **kw): + self.log = kw.pop('log') + wx.HtmlListBox.__init__(self, *args, **kw) + + def OnGetItem(self, n): + if n == 1: + return """ + + + + + +
col 1Lorem ipsum dolor + sit amet, consectetuer adipiscing elit.foobar
""" + if n % 2 == 0: + return "This is item# %d" % n + else: + return "This is item# %d
Any HTML is okay." % n + + def OnLinkClicked(self, n, linkinfo): + self.log.WriteText('OnLinkClicked: %s\n' % linkinfo.GetHref()) + #there's a bug in the wxPython wrapper as of 2.8.7.1 + #super(MyHtmlListBox, self).OnLinkClicked(n, linkinfo) + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + spacer = 50 + + vlb = MyVListBox(self, -1, size=(150, 250), style=wx.BORDER_SUNKEN) + vlb.SetItemCount(50) + vlb.SetSelection(0) + vlb.SetFocus() + vlbSizer = wx.BoxSizer(wx.VERTICAL) + vlbSizer.Add((spacer, spacer)) + vlbSizer.Add(wx.StaticText(self, -1, "wx.VListBox"), 0, 5, wx.ALL) + vlbSizer.Add(vlb) + + hlb = MyHtmlListBox(self, -1, size=(150, 250), style=wx.BORDER_SUNKEN, + log=log) + hlb.SetItemCount(50) + hlb.SetSelection(0) + hlbSizer = wx.BoxSizer(wx.VERTICAL) + hlbSizer.Add((spacer, spacer)) + hlbSizer.Add(wx.StaticText(self, -1, "wx.HtmlListBox"), 0, 5, wx.ALL) + hlbSizer.Add(hlb) + + self.Bind(html.EVT_HTML_CELL_CLICKED, self.OnCellClicked, hlb ) + self.Bind(html.EVT_HTML_CELL_HOVER, self.OnCellMouseHover, hlb ) + #there's a bug in the wxPython wrapper as of 2.8.7.1 + #self.Bind(html.EVT_HTML_LINK_CLICKED, self.OnLinkClicked, hlb ) + + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add((spacer, spacer)) + sizer.Add(vlbSizer) + sizer.Add((spacer, spacer)) + sizer.Add((spacer, spacer)) + sizer.Add(hlbSizer) + + self.SetSizer(sizer) + + #there's a bug in the wxPython wrapper as of 2.8.7.1 + #def OnLinkClicked(self, event): + # linkinfo = event.GetLinkInfo() + # self.log.WriteText('OnLinkClicked: %s\n' % linkinfo.GetHref()) + # + def OnCellMouseHover(self, event): + cell = event.GetCell() + self.log.WriteText('OnCellMouseHover: %s\n' % (cell)) + if isinstance(cell, html.HtmlWordCell): + sel = html.HtmlSelection() + self.log.WriteText(' %s\n' % cell.ConvertToText(sel)) + event.Skip() + + def OnCellClicked(self, event): + cell = event.GetCell() + self.log.WriteText('OnCellClicked: %s\n' % (cell)) + if isinstance(cell, html.HtmlWordCell): + sel = html.HtmlSelection() + self.log.WriteText(' %s\n' % cell.ConvertToText(sel)) + event.Skip() + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.VListBox and wx.HtmlListBox

+
+ +The "V" in wxVListBox stands for both "virtual" because it can have an +unlimited number of items since it doesn't store them itself, and +"variable" since items can vary in height. It has much the same +interface as wxListBox and also emits the same events so you can use +the same EVT_LISTBOX function to connect a handler. +

+ +The wx.HtmlListBox derives from wx.VListBox, but draws each item itself +as a wx.HtmlCell. This means that you just need to provide a snippet +of HTML for each item when requested. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/Validator.py b/demo/Validator.py new file mode 100644 index 00000000..9faf3f72 --- /dev/null +++ b/demo/Validator.py @@ -0,0 +1,240 @@ + +import string +import wx + +#---------------------------------------------------------------------- + +ALPHA_ONLY = 1 +DIGIT_ONLY = 2 + +class MyValidator(wx.PyValidator): + def __init__(self, flag=None, pyVar=None): + wx.PyValidator.__init__(self) + self.flag = flag + self.Bind(wx.EVT_CHAR, self.OnChar) + + def Clone(self): + return MyValidator(self.flag) + + def Validate(self, win): + tc = self.GetWindow() + val = tc.GetValue() + + if self.flag == ALPHA_ONLY: + for x in val: + if x not in string.letters: + return False + + elif self.flag == DIGIT_ONLY: + for x in val: + if x not in string.digits: + return False + + return True + + + def OnChar(self, event): + key = event.GetKeyCode() + + if key < wx.WXK_SPACE or key == wx.WXK_DELETE or key > 255: + event.Skip() + return + + if self.flag == ALPHA_ONLY and chr(key) in string.letters: + event.Skip() + return + + if self.flag == DIGIT_ONLY and chr(key) in string.digits: + event.Skip() + return + + if not wx.Validator_IsSilent(): + wx.Bell() + + # Returning without calling even.Skip eats the event before it + # gets to the text control + return + +#---------------------------------------------------------------------- + +class TestValidatorPanel(wx.Panel): + def __init__(self, parent): + wx.Panel.__init__(self, parent, -1) + self.SetAutoLayout(True) + VSPACE = 10 + + fgs = wx.FlexGridSizer(cols=2) + + fgs.Add((1,1)) + fgs.Add(wx.StaticText(self, -1, "These controls have validators that limit\n" + "the type of characters that can be entered.")) + + fgs.Add((1,VSPACE)); fgs.Add((1,VSPACE)) + + label = wx.StaticText(self, -1, "Alpha Only: ") + fgs.Add(label, 0, wx.ALIGN_RIGHT|wx.CENTER) + + fgs.Add(wx.TextCtrl(self, -1, "", validator = MyValidator(ALPHA_ONLY))) + + fgs.Add((1,VSPACE)); fgs.Add((1,VSPACE)) + + label = wx.StaticText(self, -1, "Digits Only: ") + fgs.Add(label, 0, wx.ALIGN_RIGHT|wx.CENTER) + fgs.Add(wx.TextCtrl(self, -1, "", validator = MyValidator(DIGIT_ONLY))) + + fgs.Add((1,VSPACE)); fgs.Add((1,VSPACE)) + fgs.Add((1,VSPACE)); fgs.Add((1,VSPACE)) + fgs.Add((0,0)) + b = wx.Button(self, -1, "Test Dialog Validation") + self.Bind(wx.EVT_BUTTON, self.OnDoDialog, b) + fgs.Add(b) + + border = wx.BoxSizer() + border.Add(fgs, 1, wx.GROW|wx.ALL, 25) + self.SetSizer(border) + self.Layout() + + def OnDoDialog(self, evt): + dlg = TestValidateDialog(self) + dlg.ShowModal() + dlg.Destroy() + + +#---------------------------------------------------------------------- + +class TextObjectValidator(wx.PyValidator): + """ This validator is used to ensure that the user has entered something + into the text object editor dialog's text field. + """ + def __init__(self): + """ Standard constructor. + """ + wx.PyValidator.__init__(self) + + + + def Clone(self): + """ Standard cloner. + + Note that every validator must implement the Clone() method. + """ + return TextObjectValidator() + + + def Validate(self, win): + """ Validate the contents of the given text control. + """ + textCtrl = self.GetWindow() + text = textCtrl.GetValue() + + if len(text) == 0: + wx.MessageBox("A text object must contain some text!", "Error") + textCtrl.SetBackgroundColour("pink") + textCtrl.SetFocus() + textCtrl.Refresh() + return False + else: + textCtrl.SetBackgroundColour( + wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW)) + textCtrl.Refresh() + return True + + + def TransferToWindow(self): + """ Transfer data from validator to window. + + The default implementation returns False, indicating that an error + occurred. We simply return True, as we don't do any data transfer. + """ + return True # Prevent wxDialog from complaining. + + + def TransferFromWindow(self): + """ Transfer data from window to validator. + + The default implementation returns False, indicating that an error + occurred. We simply return True, as we don't do any data transfer. + """ + return True # Prevent wxDialog from complaining. + +#---------------------------------------------------------------------- + +class TestValidateDialog(wx.Dialog): + def __init__(self, parent): + wx.Dialog.__init__(self, parent, -1, "Validated Dialog") + + self.SetAutoLayout(True) + VSPACE = 10 + + fgs = wx.FlexGridSizer(cols=2) + + fgs.Add((1,1)); + fgs.Add(wx.StaticText(self, -1, + "These controls must have text entered into them. Each\n" + "one has a validator that is checked when the Ok\n" + "button is clicked.")) + + fgs.Add((1,VSPACE)); fgs.Add((1,VSPACE)) + + label = wx.StaticText(self, -1, "First: ") + fgs.Add(label, 0, wx.ALIGN_RIGHT|wx.CENTER) + + fgs.Add(wx.TextCtrl(self, -1, "", validator = TextObjectValidator())) + + fgs.Add((1,VSPACE)); fgs.Add((1,VSPACE)) + + label = wx.StaticText(self, -1, "Second: ") + fgs.Add(label, 0, wx.ALIGN_RIGHT|wx.CENTER) + fgs.Add(wx.TextCtrl(self, -1, "", validator = TextObjectValidator())) + + + buttons = wx.StdDialogButtonSizer() #wx.BoxSizer(wx.HORIZONTAL) + b = wx.Button(self, wx.ID_OK, "OK") + b.SetDefault() + buttons.AddButton(b) + buttons.AddButton(wx.Button(self, wx.ID_CANCEL, "Cancel")) + buttons.Realize() + + border = wx.BoxSizer(wx.VERTICAL) + border.Add(fgs, 1, wx.GROW|wx.ALL, 25) + border.Add(buttons, 0, wx.GROW|wx.BOTTOM, 5) + self.SetSizer(border) + border.Fit(self) + self.Layout() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestValidatorPanel(nb) + return win + +#---------------------------------------------------------------------- + + + +overview = """\ + + +wx.Validator is the base class for a family of validator classes that mediate +between a class of control, and application data. + +

A validator has three major roles: + +

    +
  1. to transfer data from a C++ variable or own storage to and from a control; +
  2. to validate data in a control, and show an appropriate error message; +
  3. to filter events (such as keystrokes), thereby changing the behaviour of the associated control. +
+

Validators can be plugged into controls dynamically. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/Wizard.py b/demo/Wizard.py new file mode 100644 index 00000000..eceba135 --- /dev/null +++ b/demo/Wizard.py @@ -0,0 +1,246 @@ + +import wx +import wx.wizard as wiz +import images + +#---------------------------------------------------------------------- + +def makePageTitle(wizPg, title): + sizer = wx.BoxSizer(wx.VERTICAL) + wizPg.SetSizer(sizer) + title = wx.StaticText(wizPg, -1, title) + title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)) + sizer.Add(title, 0, wx.ALIGN_CENTRE|wx.ALL, 5) + sizer.Add(wx.StaticLine(wizPg, -1), 0, wx.EXPAND|wx.ALL, 5) + return sizer + +#---------------------------------------------------------------------- + +class TitledPage(wiz.WizardPageSimple): + def __init__(self, parent, title): + wiz.WizardPageSimple.__init__(self, parent) + self.sizer = makePageTitle(self, title) + + +#---------------------------------------------------------------------- + +class SkipNextPage(wiz.PyWizardPage): + def __init__(self, parent, title): + wiz.PyWizardPage.__init__(self, parent) + self.next = self.prev = None + self.sizer = makePageTitle(self, title) + + self.cb = wx.CheckBox(self, -1, "Skip next page") + self.sizer.Add(self.cb, 0, wx.ALL, 5) + + def SetNext(self, next): + self.next = next + + def SetPrev(self, prev): + self.prev = prev + + + # Classes derived from wxPyWizardPanel must override + # GetNext and GetPrev, and may also override GetBitmap + # as well as all those methods overridable by + # wx.PyWindow. + + def GetNext(self): + """If the checkbox is set then return the next page's next page""" + if self.cb.GetValue(): + self.next.GetNext().SetPrev(self) + return self.next.GetNext() + else: + self.next.GetNext().SetPrev(self.next) + return self.next + + def GetPrev(self): + return self.prev + +#---------------------------------------------------------------------- + +class UseAltBitmapPage(wiz.PyWizardPage): + def __init__(self, parent, title): + wiz.PyWizardPage.__init__(self, parent) + self.next = self.prev = None + self.sizer = makePageTitle(self, title) + + self.sizer.Add(wx.StaticText(self, -1, "This page uses a different bitmap"), + 0, wx.ALL, 5) + + def SetNext(self, next): + self.next = next + + def SetPrev(self, prev): + self.prev = prev + + def GetNext(self): + return self.next + + def GetPrev(self): + return self.prev + + def GetBitmap(self): + # You usually wouldn't need to override this method + # since you can set a non-default bitmap in the + # wxWizardPageSimple constructor, but if you need to + # dynamically change the bitmap based on the + # contents of the wizard, or need to also change the + # next/prev order then it can be done by overriding + # GetBitmap. + return images.WizTest2.GetBitmap() + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Run Simple Wizard", pos=(50, 50)) + self.Bind(wx.EVT_BUTTON, self.OnRunSimpleWizard, b) + + b = wx.Button(self, -1, "Run Dynamic Wizard", pos=(50, 100)) + self.Bind(wx.EVT_BUTTON, self.OnRunDynamicWizard, b) + + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGED, self.OnWizPageChanged) + self.Bind(wiz.EVT_WIZARD_PAGE_CHANGING, self.OnWizPageChanging) + self.Bind(wiz.EVT_WIZARD_CANCEL, self.OnWizCancel) + + + def OnWizPageChanged(self, evt): + if evt.GetDirection(): + dir = "forward" + else: + dir = "backward" + + page = evt.GetPage() + self.log.write("OnWizPageChanged: %s, %s\n" % (dir, page.__class__)) + + + def OnWizPageChanging(self, evt): + if evt.GetDirection(): + dir = "forward" + else: + dir = "backward" + + page = evt.GetPage() + self.log.write("OnWizPageChanging: %s, %s\n" % (dir, page.__class__)) + + + def OnWizCancel(self, evt): + page = evt.GetPage() + self.log.write("OnWizCancel: %s\n" % page.__class__) + + # Show how to prevent cancelling of the wizard. The + # other events can be Veto'd too. + if page is self.page1: + wx.MessageBox("Cancelling on the first page has been prevented.", "Sorry") + evt.Veto() + + + def OnWizFinished(self, evt): + self.log.write("OnWizFinished\n") + + + def OnRunSimpleWizard(self, evt): + # Create the wizard and the pages + wizard = wiz.Wizard(self, -1, "Simple Wizard", images.WizTest1.GetBitmap()) + page1 = TitledPage(wizard, "Page 1") + page2 = TitledPage(wizard, "Page 2") + page3 = TitledPage(wizard, "Page 3") + page4 = TitledPage(wizard, "Page 4") + self.page1 = page1 + + page1.sizer.Add(wx.StaticText(page1, -1, """ +This wizard is totally useless, but is meant to show how to +chain simple wizard pages together in a non-dynamic manner. +IOW, the order of the pages never changes, and so the +wxWizardPageSimple class can easily be used for the pages.""")) + wizard.FitToPage(page1) + page4.sizer.Add(wx.StaticText(page4, -1, "\nThis is the last page.")) + + # Use the convenience Chain function to connect the pages + wiz.WizardPageSimple.Chain(page1, page2) + wiz.WizardPageSimple.Chain(page2, page3) + wiz.WizardPageSimple.Chain(page3, page4) + + wizard.GetPageAreaSizer().Add(page1) + if wizard.RunWizard(page1): + wx.MessageBox("Wizard completed successfully", "That's all folks!") + else: + wx.MessageBox("Wizard was cancelled", "That's all folks!") + + + + def OnRunDynamicWizard(self, evt): + # Create the wizard and the pages + #wizard = wx.PreWizard() + #wizard.SetExtraStyle(wx.WIZARD_EX_HELPBUTTON) + #wizard.Create(self, self.ID_wiz, "Simple Wizard", + # images.WizTest1.GetBitmap()) + wizard = wiz.Wizard(self, -1, "Dynamic Wizard", images.WizTest1.GetBitmap()) + + page1 = TitledPage(wizard, "Page 1") + page2 = SkipNextPage(wizard, "Page 2") + page3 = TitledPage(wizard, "Page 3") + page4 = UseAltBitmapPage(wizard, "Page 4") + page5 = TitledPage(wizard, "Page 5") + self.page1 = page1 + + page1.sizer.Add(wx.StaticText(page1, -1, """ +This wizard shows the ability to choose at runtime the order +of the pages and also which bitmap is shown. +""")) + wizard.FitToPage(page1) + page5.sizer.Add(wx.StaticText(page5, -1, "\nThis is the last page.")) + + # Set the initial order of the pages + page1.SetNext(page2) + page2.SetPrev(page1) + page2.SetNext(page3) + page3.SetPrev(page2) + page3.SetNext(page4) + page4.SetPrev(page3) + page4.SetNext(page5) + page5.SetPrev(page4) + + + wizard.GetPageAreaSizer().Add(page1) + if wizard.RunWizard(page1): + wx.MessageBox("Wizard completed successfully", "That's all folks!") + else: + wx.MessageBox("Wizard was cancelled", "That's all folks!") + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wxWizard

+ +wxWizard is the central class for implementing 'wizard-like' +dialogs. These dialogs are mostly familiar to Windows users and are +nothing else but a sequence of 'pages' each of them displayed inside a +dialog which has the buttons to pass to the next (and previous) pages. +

+The wizards are typically used to decompose a complex dialog into +several simple steps and are mainly useful to the novice users, hence +it is important to keep them as simple as possible. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/WrapSizer.py b/demo/WrapSizer.py new file mode 100644 index 00000000..08d83200 --- /dev/null +++ b/demo/WrapSizer.py @@ -0,0 +1,92 @@ + +import wx +from wx.lib.buttons import GenButton + +import random + +#---------------------------------------------------------------------- + +class WrapSizerTest(wx.Frame): + def __init__(self, *args, **kw): + wx.Frame.__init__(self, *args, **kw) + + # Make a title area and sizer for the upper part of the panel + pnl = wx.Panel(self) + stx = wx.StaticText(pnl, -1, "wx.WrapSizer Layout") + stx.SetFont(wx.FFont(28, wx.SWISS)) + sln = wx.StaticLine(pnl) + upper = wx.BoxSizer(wx.VERTICAL) + upper.Add(stx, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.TOP, 8) + upper.Add(sln, 0, wx.EXPAND|wx.ALL, 8) + + # In the lower part of the panel we'll put a bunch of buttons + # in a WrapSizer + def _makeButtons(words): + sizer = wx.WrapSizer() + for word in words: + btn = GenButton(pnl, -1, word, style=wx.BU_EXACTFIT) + sizer.Add(btn, 0, wx.ALL, 4) + + # Add a little color to make it interesting + r = random.randint(128, 255) + g = random.randint(128, 255) + b = random.randint(128, 255) + btn.SetBackgroundColour(wx.Colour(r,g,b)) + btn.Refresh() + + return sizer + + lower1 = _makeButtons(sampleText.split()) + lower2 = _makeButtons("Try resizing this Frame to see how it works.".split()) + + pnl.Sizer = wx.BoxSizer(wx.VERTICAL) + pnl.Sizer.Add(upper, 0, wx.EXPAND) + pnl.Sizer.Add(lower1, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 8) + pnl.Sizer.Add((16,16)) + pnl.Sizer.Add(lower2, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 8) + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Demonstrate wx.WrapSizer", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + win = WrapSizerTest(self, -1, "wx.WrapSizer Demo", size=(640, 480)) + win.Show(True) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + +sampleText = """\ +The wx.WrapSizer implements a commonly requested layout mechanism where +however many items will fit on a "line" are positioned next to each other, and +then the location of the next item in the sizer is on the next logical line of +the parent's layout. """ + +overview = """ +

WrapSizer

+""" + \ +sampleText + \ +""" + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/XMLtreeview.py b/demo/XMLtreeview.py new file mode 100644 index 00000000..36dc81f6 --- /dev/null +++ b/demo/XMLtreeview.py @@ -0,0 +1,108 @@ + +import sys +import wx + +from xml.parsers import expat + +#---------------------------------------------------------------------- + +class XMLTree(wx.TreeCtrl): + def __init__(self, parent, ID): + wx.TreeCtrl.__init__(self, parent, ID) + self._root = self.AddRoot("Root") + self.nodeStack = [self._root] + + # Trees need an image list to do DnD... + self.il = wx.ImageList(16,16) + self.SetImageList(self.il) + + # event handlers for DnD + self.Bind(wx.EVT_TREE_BEGIN_DRAG, self.OnBeginDrag) + self.Bind(wx.EVT_TREE_END_DRAG, self.OnEndDrag) + + + def OnBeginDrag(self, event): + item = event.GetItem() + + if item != self.GetRootItem(): + self.draggingItem = item + event.Allow() # if DnD of this item is okay Allow it. + + def IsDescendant(self, firstItem, secondItem): + "Recursive check if firstItem is a descendant of a secondItem." + if firstItem == self._root: + return False + parentItem = self.GetItemParent(firstItem) + if parentItem == secondItem: + return True + else: + return self.IsDescendant(parentItem, secondItem) + + def OnEndDrag(self, evt): + itemSrc = self.draggingItem + itemDst = evt.GetItem() + self.draggingItem = None + + if not itemDst.IsOk(): + print "Can't drag to here..." + return + + if self.IsDescendant(itemDst, itemSrc): + print "Can't move item to its descendant" + return + + # For this simple example just take the text of the source item + # and append it to the destination item. In real life you would + # possibly want to copy subtrees... + text = self.GetItemText(itemSrc) + self.AppendItem(itemDst, text) + self.Delete(itemSrc) + + + # Define a handler for start element events + def StartElement(self, name, attrs ): + name = name.encode() + + id = self.AppendItem(self.nodeStack[-1], name) + self.nodeStack.append(id) + + def EndElement(self, name ): + self.nodeStack = self.nodeStack[:-1] + + def CharacterData(self, data ): + if data.strip(): + data = data.encode() + + self.AppendItem(self.nodeStack[-1], data) + + + def LoadTree(self, filename): + # Create a parser + Parser = expat.ParserCreate() + + # Tell the parser what the start element handler is + Parser.StartElementHandler = self.StartElement + Parser.EndElementHandler = self.EndElement + Parser.CharacterDataHandler = self.CharacterData + + # Parse the XML File + ParserStatus = Parser.Parse(open(filename,'r').read(), 1) + + +def runTest(frame, nb, log): + win = XMLTree(nb, -1) + win.LoadTree("paper.xml") + return win + +#---------------------------------------------------------------------- + + + +overview = """\ +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/XmlResource.py b/demo/XmlResource.py new file mode 100644 index 00000000..5d241b1d --- /dev/null +++ b/demo/XmlResource.py @@ -0,0 +1,76 @@ + +import wx +import wx.xrc as xrc + +from Main import opj + +#---------------------------------------------------------------------- + +RESFILE = opj("data/resource_wdr.xrc") + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1) + self.log = log + + # make the components + label = wx.StaticText(self, -1, "The lower panel was built from this XML:") + label.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)) + + resourceText = open(RESFILE).read() + text = wx.TextCtrl(self, -1, resourceText, + style=wx.TE_READONLY|wx.TE_MULTILINE) + text.SetInsertionPoint(0) + + line = wx.StaticLine(self, -1) + + # This shows a few different ways to load XML Resources + if 0: + # XML Resources can be loaded from a file like this: + res = xrc.XmlResource(RESFILE) + + elif 1: + # or from a Virtual FileSystem: + wx.FileSystem_AddHandler(wx.MemoryFSHandler()) + wx.MemoryFSHandler_AddFile("XRC_Resources/data_file", resourceText) + res = xrc.XmlResource("memory:XRC_Resources/data_file") + + else: + # or from a string, like this: + res = xrc.EmptyXmlResource() + res.LoadFromString(resourceText) + + + # Now create a panel from the resource data + panel = res.LoadPanel(self, "MyPanel") + + # and do the layout + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(label, 0, wx.EXPAND|wx.TOP|wx.LEFT, 5) + sizer.Add(text, 1, wx.EXPAND|wx.ALL, 5) + sizer.Add(line, 0, wx.EXPAND) + sizer.Add(panel, 1, wx.EXPAND|wx.ALL, 5) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/XmlResourceHandler.py b/demo/XmlResourceHandler.py new file mode 100644 index 00000000..ef0c3a07 --- /dev/null +++ b/demo/XmlResourceHandler.py @@ -0,0 +1,202 @@ + +import wx +import wx.xrc as xrc + +#---------------------------------------------------------------------- + +resourceText = r''' + + + + + + 200,100 + + + 10,10 + + + +''' + +#---------------------------------------------------------------------- + +class MyCustomPanel(wx.Panel): + def __init__(self, parent, id, pos, size, style, name): + wx.Panel.__init__(self, parent, id, pos, size, style, name) + + # This is the little bit of customization that we do for this + # silly example. + self.Bind(wx.EVT_SIZE, self.OnSize) + t = wx.StaticText(self, -1, "MyCustomPanel") + f = t.GetFont() + f.SetWeight(wx.BOLD) + f.SetPointSize(f.GetPointSize()+2) + t.SetFont(f) + self.t = t + + def OnSize(self, evt): + sz = self.GetSize() + w, h = self.t.GetTextExtent(self.t.GetLabel()) + self.t.SetPosition(((sz.width-w)/2, (sz.height-h)/2)) + + +# To do it the more complex way, (see below) we need to write the +# class a little differently... This could obviously be done with a +# single class, but I wanted to make separate ones to make clear what +# the different requirements are. +class PreMyCustomPanel(wx.Panel): + def __init__(self): + p = wx.PrePanel() + self.PostCreate(p) + + def Create(self, parent, id, pos, size, style, name): + wx.Panel.Create(self, parent, id, pos, size, style, name) + self.Bind(wx.EVT_SIZE, self.OnSize) + t = wx.StaticText(self, -1, "MyCustomPanel") + f = t.GetFont() + f.SetWeight(wx.BOLD) + f.SetPointSize(f.GetPointSize()+2) + t.SetFont(f) + self.t = t + + def OnSize(self, evt): + sz = self.GetSize() + w, h = self.t.GetTextExtent(self.t.GetLabel()) + self.t.SetPosition(((sz.width-w)/2, (sz.height-h)/2)) + +#---------------------------------------------------------------------- + +class MyCustomPanelXmlHandler(xrc.XmlResourceHandler): + def __init__(self): + xrc.XmlResourceHandler.__init__(self) + # Specify the styles recognized by objects of this type + self.AddStyle("wxTAB_TRAVERSAL", wx.TAB_TRAVERSAL) + self.AddStyle("wxWS_EX_VALIDATE_RECURSIVELY", wx.WS_EX_VALIDATE_RECURSIVELY) + self.AddStyle("wxCLIP_CHILDREN", wx.CLIP_CHILDREN) + self.AddWindowStyles() + + # This method and the next one are required for XmlResourceHandlers + def CanHandle(self, node): + return self.IsOfClass(node, "MyCustomPanel") + + def DoCreateResource(self): + # NOTE: wxWindows can be created in either a single-phase or + # in a two-phase way. Single phase is what you normally do, + # and two-phase creates the instnace first, and then later + # creates the actual window when the Create method is called. + # (In wxPython the first phase is done using the wxPre* + # function, for example, wxPreFrame, wxPrePanel, etc.) + # + # wxXmlResource supports either method, a premade instance can + # be created and populated by xrc using the appropriate + # LoadOn* method (such as LoadOnPanel) or xrc can create the + # instance too, using the Load* method. However this makes + # the handlers a bit more complex. If you can be sure that a + # particular class will never be loaded using a pre-existing + # instance, then you can make the handle much simpler. I'll + # show both methods below. + + if 1: + # The simple method assumes that there is no existing + # instance. Be sure of that with an assert. + assert self.GetInstance() is None + + # Now create the object + panel = MyCustomPanel(self.GetParentAsWindow(), + self.GetID(), + self.GetPosition(), + self.GetSize(), + self.GetStyle("style", wx.TAB_TRAVERSAL), + self.GetName() + ) + else: + # When using the more complex (but more flexible) method + # the instance may already have been created, check for it + panel = self.GetInstance() + if panel is None: + # if not, then create the instance (but not the window) + panel = PreMyCustomPanel() + + # Now call the panel's Create method to actually create the window + panel.Create(self.GetParentAsWindow(), + self.GetID(), + self.GetPosition(), + self.GetSize(), + self.GetStyle("style", wx.TAB_TRAVERSAL), + self.GetName() + ) + + # These two things should be done in either case: + # Set standard window attributes + self.SetupWindow(panel) + # Create any child windows of this node + self.CreateChildren(panel) + + return panel + + +#---------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + # make the components + label = wx.StaticText(self, -1, "The lower panel was built from this XML:") + label.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)) + + text = wx.TextCtrl(self, -1, resourceText, + style=wx.TE_READONLY|wx.TE_MULTILINE) + text.SetInsertionPoint(0) + + line = wx.StaticLine(self, -1) + + # Load the resource + res = xrc.EmptyXmlResource() + res.InsertHandler(MyCustomPanelXmlHandler()) + res.LoadFromString(resourceText) + + # Now create a panel from the resource data + panel = res.LoadObject(self, "MyPanel", "MyCustomPanel") + + # and do the layout + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(label, 0, wx.EXPAND|wx.TOP|wx.LEFT, 5) + sizer.Add(text, 1, wx.EXPAND|wx.ALL, 5) + sizer.Add(line, 0, wx.EXPAND) + sizer.Add(panel, 1, wx.EXPAND|wx.ALL, 5) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.XmlResourceHandler

+ +Deriving a class from wx.XmlResourceHandler allows you to specify your +own classes in XRC resources, and your handler class will then be used +to create instances of that class when the resource is loaded. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/XmlResourceSubclass.py b/demo/XmlResourceSubclass.py new file mode 100644 index 00000000..4cda2a45 --- /dev/null +++ b/demo/XmlResourceSubclass.py @@ -0,0 +1,120 @@ + +import wx +import wx.xrc as xrc + +#---------------------------------------------------------------------- + +resourceText = r''' + + + + + + 200,100 + + + 10,10 + + + +''' + +#---------------------------------------------------------------------- + +class MyCustomPanel(wx.Panel): + def __init__(self): + p = wx.PrePanel() + # the Create step is done by XRC. + self.PostCreate(p) + self.Bind(wx.EVT_WINDOW_CREATE, self.OnCreate) + self.Bind(wx.EVT_SIZE, self.OnSize) + + + def OnCreate(self, evt): + # This is the little bit of customization that we do for this + # silly example. It could just as easily have been done in + # the resource. We do it in the EVT_WINDOW_CREATE handler + # because the window doesn't really exist yet in the __init__. + if self is evt.GetEventObject(): + t = wx.StaticText(self, -1, "MyCustomPanel") + f = t.GetFont() + f.SetWeight(wx.BOLD) + f.SetPointSize(f.GetPointSize()+2) + t.SetFont(f) + self.t = t + # On OSX the EVT_SIZE happens before EVT_WINDOW_CREATE !?! + # so give it another kick + wx.CallAfter(self.OnSize, None) + evt.Skip() + + def OnSize(self, evt): + if hasattr(self, 't'): + sz = self.GetSize() + w, h = self.t.GetTextExtent(self.t.GetLabel()) + self.t.SetPosition(((sz.width-w)/2, (sz.height-h)/2)) + +#---------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + # make the components + label = wx.StaticText(self, -1, "The lower panel was built from this XML:") + label.SetFont(wx.Font(12, wx.SWISS, wx.NORMAL, wx.BOLD)) + + text = wx.TextCtrl(self, -1, resourceText, + style=wx.TE_READONLY|wx.TE_MULTILINE) + text.SetInsertionPoint(0) + + line = wx.StaticLine(self, -1) + + # Load the resource + res = xrc.EmptyXmlResource() + res.LoadFromString(resourceText) + + # Now create a panel from the resource data + panel = res.LoadPanel(self, "MyPanel") + + # and do the layout + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(label, 0, wx.EXPAND|wx.TOP|wx.LEFT, 5) + sizer.Add(text, 1, wx.EXPAND|wx.ALL, 5) + sizer.Add(line, 0, wx.EXPAND) + sizer.Add(panel, 1, wx.EXPAND|wx.ALL, 5) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.XmlResourceSubclass

+ +Sometimes it is necessary to use custom classes, but you still want +them to be created from XRC. The subclass XRC attribute allows you to +do that. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/AGWInfoBar.py b/demo/agw/AGWInfoBar.py new file mode 100644 index 00000000..46e1b6bc --- /dev/null +++ b/demo/agw/AGWInfoBar.py @@ -0,0 +1,174 @@ +import wx +import random + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + import agw.infobar as IB +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.infobar as IB + +from images import catalog + +#---------------------------------------------------------------------- + +def GetValidImages(): + + keys = catalog.keys() + valid_images = [] + counter = 0 + + for key in keys: + bmp = catalog[key].GetBitmap() + if bmp.GetWidth() == 16 and bmp.GetHeight() == 16: + valid_images.append(bmp) + + return valid_images + +#---------------------------------------------------------------------- + +flags = [ (wx.ICON_NONE, "ICON_NONE"), + (wx.ICON_INFORMATION, "ICON_INFORMATION"), + (wx.ICON_QUESTION, "ICON_QUESTION"), + (wx.ICON_WARNING, "ICON_WARNING"), + (wx.ICON_ERROR, "ICON_ERROR") + ] + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + # Create the InfoBar. It starts out in a hidden state so it + # won't be visible until we need it. + self.info = IB.InfoBar(self) + + panel = wx.Panel(self) + + self.message = wx.TextCtrl(panel, -1, "Hello World", size=(250,-1)) + self.flags = wx.Choice(panel, choices=[f[1] for f in flags]) + self.flags.SetSelection(1) # wx.ICON_INFORMATION is the default + + self.checkBitmap = wx.CheckBox(panel, -1, 'With Bitmap') + + smBtn = wx.Button(panel, -1, "Show Message") + dmBtn = wx.Button(panel, -1, "Dismiss") + addBtn = wx.Button(panel, -1, "Add Button") + + fgs = wx.FlexGridSizer(cols=3, vgap=10, hgap=10) + fgs.Add(wx.StaticText(panel, -1, "Message:"), 0, + wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT) + fgs.Add(self.message) + fgs.Add(self.flags) + fgs.AddSpacer(5) + + hbox = wx.BoxSizer(wx.HORIZONTAL) + hbox.Add(smBtn, 0, wx.RIGHT, 5) + hbox.Add(dmBtn) + fgs.Add(hbox) + fgs.AddSpacer(5) + fgs.AddSpacer(5) + + hbox2 = wx.BoxSizer(wx.HORIZONTAL) + + hbox2.Add(addBtn, 0, wx.RIGHT, 10) + hbox2.Add(self.checkBitmap, 0, wx.ALIGN_CENTER) + fgs.Add(hbox2) + + panel.Sizer = wx.BoxSizer(wx.VERTICAL) + text = """\ +An info bar is a transient window shown at top or bottom of its parent window +to display non-critical information to the user.""" + panel.Sizer.Add(wx.StaticText(panel, -1, text), 0, wx.TOP|wx.LEFT, 25) + panel.Sizer.Add(fgs, 1, wx.EXPAND|wx.ALL, 25) + + self.Sizer = wx.BoxSizer(wx.VERTICAL) + self.Sizer.Add(self.info, 0, wx.EXPAND) + self.Sizer.Add(panel, 1, wx.EXPAND) + + self.Bind(wx.EVT_BUTTON, self.OnShowMessage, smBtn) + self.Bind(wx.EVT_BUTTON, self.OnDismiss, dmBtn) + self.Bind(wx.EVT_BUTTON, self.OnAddButton, addBtn) + + self.valid_images = GetValidImages() + + + def OnShowMessage(self, event): + msg = self.message.GetValue() + flag = flags[self.flags.GetSelection()][0] + self.info.ShowMessage(msg, flag) + + + def OnDismiss(self, event): + self.info.Dismiss() + + + def OnAddButton(self, event): + btnId = wx.NewId() + + if self.checkBitmap.GetValue(): + bitmap = random.choice(self.valid_images) + else: + bitmap = wx.NullBitmap + + self.info.AddButton(btnId, "New Button", bitmap) + self.info.Bind(wx.EVT_BUTTON, self.OnButtonClicked, id=btnId) + + + def OnButtonClicked(self, event): + wx.MessageBox("New Button clicked") + # Calling event.Skip() will allow the default handler to run + # which will dismiss the info bar. If you don't want it to be + # dismissed for a particular button then then don't call + # Skip(). + event.Skip() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

wx.InfoBar

+ +An info bar is a transient window shown at top or bottom of its parent +window to display non-critical information to the user. + +

This class provides another way to show messages to the user, +intermediate between message boxes and status bar messages. The +message boxes are modal and thus interrupt the users work flow and +should be used sparingly for this reason. However status bar messages +are often too easy not to notice at all. An info bar provides a way to +present the messages which has a much higher chance to be noticed by +the user but without being annoying. + +

Info bar may show an icon (on the left), text message and, optionally, +buttons allowing the user to react to the information presented. It +always has a close button at the right allowing the user to dismiss it +so it isn't necessary to provide a button just to close it. + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/AUI.py b/demo/agw/AUI.py new file mode 100644 index 00000000..2c9f45de --- /dev/null +++ b/demo/agw/AUI.py @@ -0,0 +1,3060 @@ +import wx +import wx.html +import wx.grid + +import os +import sys +import time + +from wx.lib.embeddedimage import PyEmbeddedImage + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import aui + from agw.aui import aui_switcherdialog as ASD +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.aui as aui + from wx.lib.agw.aui import aui_switcherdialog as ASD + +import random +import images + +ArtIDs = [ "wx.ART_ADD_BOOKMARK", + "wx.ART_DEL_BOOKMARK", + "wx.ART_HELP_SIDE_PANEL", + "wx.ART_HELP_SETTINGS", + "wx.ART_HELP_BOOK", + "wx.ART_HELP_FOLDER", + "wx.ART_HELP_PAGE", + "wx.ART_GO_BACK", + "wx.ART_GO_FORWARD", + "wx.ART_GO_UP", + "wx.ART_GO_DOWN", + "wx.ART_GO_TO_PARENT", + "wx.ART_GO_HOME", + "wx.ART_FILE_OPEN", + "wx.ART_PRINT", + "wx.ART_HELP", + "wx.ART_TIP", + "wx.ART_REPORT_VIEW", + "wx.ART_LIST_VIEW", + "wx.ART_NEW_DIR", + "wx.ART_HARDDISK", + "wx.ART_FLOPPY", + "wx.ART_CDROM", + "wx.ART_REMOVABLE", + "wx.ART_FOLDER", + "wx.ART_FOLDER_OPEN", + "wx.ART_GO_DIR_UP", + "wx.ART_EXECUTABLE_FILE", + "wx.ART_NORMAL_FILE", + "wx.ART_TICK_MARK", + "wx.ART_CROSS_MARK", + "wx.ART_ERROR", + "wx.ART_QUESTION", + "wx.ART_WARNING", + "wx.ART_INFORMATION", + "wx.ART_MISSING_IMAGE", + ] + +# Custom pane button bitmaps +#---------------------------------------------------------------------- +close = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAABHNCSVQICAgIfAhkiAAAAh9J" + "REFUKJFl0s1LFGEAx/HvMzO7M9vmrrSuThJIhslmaSZqFgZLdSqKjr147VB/Qn9Af0GXTiIU" + "vVAQdRAKqkuColaiiyiKr7FKL7u6OzM78zxPh6igfvcvv8tHCMMEoHAxr/35AlpK/p0wTZz2" + "HLlXbwWABTBzrk83DnSRvjWE4Tj/Rcr3KU1/Zsav6GNvxoU1cSGvmwZ7SZ3Oo5MpIiuGrvl/" + "X+IOIgpJndmPNONM2Elt7KyuU9/djySCbBNGo4ssriA3FlHfNjAaXchkiSKf+u5+ykvLGHLP" + "XlQiSS0SqLoMosHF6DwJdfWIXC+iwUWls4TaQtkJQtPC8gIPo1pldvQlanGNnqs3iLktyOwB" + "TNMk9AMmnzzEmHjHiVOD7AQBVjUI0JUdDqaTzLwfZS6VovPSFUytQUrmXjynfO8uR9MWyrEJ" + "/QCrFkrU9leM5QVysoa044jSD9AAmoxjk6GKtbqNaukglAojCHyi8Q8Ec7PsO3sZt/UQ3uYG" + "3+cLeF82cdsOk719hyjlIis+Na0wlJRExSJe23EitwW5VWRqZJjHQ9eYGhlGbhWJmlvxOvqp" + "lXeRSmM57TnWSx4/ltZZsR5hOAlKz57St1tmbWSYscou0vNIfJwlyGRIHOlACMPkwUCPzsmQ" + "aswi8Hza/ICYgFDDgmMTd2ySkaRgxrg+NinEb3v3z+f15qdpQt/DQvwREaGJOQmau7q5+fqX" + "vZ+3DPNuDe9/tAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +close_inactive = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAABHNCSVQICAgIfAhkiAAAAh5J" + "REFUKJFl0stLVFEAgPHv3Htn7lzNGW1GZzSNtJI0fFZjQkQPqV0U0SJmnZugP6B9/0O4cZNE" + "ZFAQUdBrlZBYoJmGOYSPSUvRRp25r3NOi8iN3/7b/YQwTAAuDn7VM3kXqdiTaUBbS4w3Q+0C" + "QAjDpD83qfuPNdDZEicWMfZMbqCYzBcZmy0wNtIprIFb4/pUa4bzfXHiVRAxFWVP7w6OLQgk" + "NDTFsWOKyopxbSyubpPtShB6mroaQTolWFiQzM9LCsuadEpQWw1uSZHtSpBfKmLscySVFRpM" + "j+R+SaZWcLrXoDoBJ7shUydIJRVW1MeJaSwzxHLLJUqu4PnLaZYKity1Hg42RjhQb2CaAs/z" + "efjsM+/GDM6e6cErF7Hc8g5bO5rKqmZevJ8iXjXL1csdaC2QoeDpq1nu3S8SiXZgJxWe72NJ" + "6bO+rZhbNvDDdqKOZHMHtBYARJ0UrkyysGRyfEuhVIDhej4fpkO+5H2uXKqm5VCawi+fbz82" + "+fnb4+jhNHdvp8jUh7ihRMkAQ0rF6oaku73EwfqQlbWQ4dEJbt55xPDoBCtrIc2NIX3dZbbd" + "AK0k4lzugS5HT7C+vkG2tYxjmzx++4eiaiJuLHLjQoKSKxmfc0gma3D8iX8istdHtG+3YVHC" + "dX28yBEQEdABdvAd244iRQVRb4aPT3JC/Lc3kBvSn6YKlL0AYVi7IrQKcewIvR0NvB4ZFAB/" + "Aa4X7YpTOtu/AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +maximize = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAABHNCSVQICAgIfAhkiAAAAJZJ" + "REFUKJG9kj0OwjAMRp8D6hDUExDmrr0dEkOHXgXuAMfIBl1yCwaMMAyoIJQWqUu/yZa/5x/J" + "Im7BVLnJBLDsg2vbPC3G8e51zapp5QeyGLHzBYbWtcfwJFlv8Nsdrqpypuu4HfY5hHPgPVKW" + "+STv3/XeOnrEH80HfW9SxVIaNFlKoJpDEgL30xGKIqdUkRA+qcz2Ri8+yyNzplbFQwAAAABJ" + "RU5ErkJggg==") + +#---------------------------------------------------------------------- +maximize_inactive = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAABHNCSVQICAgIfAhkiAAAAJhJ" + "REFUKJFjZGRiZiAVMJGsg4GBgQXGaGz7+v/CxX84FRroMzHUV3Ezomi6cPEfw/Vb/xiYsbj2" + "718cNsnKMDJUlnAwqKthuvjmrX8MS1b8xtTEyMTAwMXFyMDLw4ihiYuLkYERySyyAoJ+muB+" + "+v2bgeHeA+xBfu/BP4bfiHBAaJKWYmTYsfsPAysrpqbfvyHyMMBIt2QEAFPtI359ud6yAAAA" + "AElFTkSuQmCC") + +#---------------------------------------------------------------------- +minimize = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAABHNCSVQICAgIfAhkiAAAAMlJ" + "REFUKJGdkrsNwkAQRN/eWohPByYkQaIKSqAJhBAF0AdExGRUQwoioAREAth3S2BjWzLIwER7" + "oxntzOpEnPIrotcQ1lvjeIbbHXjkpAczkAf0OjAc4GZTQZwiTrHNzhoxX5g4xRU7U9+c654A" + "VEzY150qpuQLedY1qvFJCqrgX3ENQp5C7IMp9eAEQsjEIWQXVC3UpckSWK5gfwCRnKv0nIwL" + "vrLJQDzomytGEXRb5bOYLhfotyEeASk1xfUEcT+r9s83cs2SOp6D2FytkDyOCgAAAABJRU5E" + "rkJggg==") + +#---------------------------------------------------------------------- +minimize_inactive = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAABHNCSVQICAgIfAhkiAAAANRJ" + "REFUKJGdkj1OgkEQhp/ZJSCF0VBYmUBPixfwAtzRS2DvCShMvAGRUJCQkMjOjwV8CwT1C77V" + "zGaevO9MViRlrlWnKd7el7HaKGpgpQDg7ng4rkY3Bw/3PZ4nI6lQzpnp0+BPh5fXDwBS8+DR" + "HquonUNEOxWHmaOTWSvk6sDJIRqZO0kEO8nrAUmEiN8gC8iCHyBvYqdU01RIizKbr1msy4/R" + "xo/9uvbRKYIIJewSSgIderWv0PZrRzcrw9tAVeulwvd7fC62DO5uAJD/fKPUPnKpbzVEY0DN" + "U2N1AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +restore = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAABHNCSVQICAgIfAhkiAAAAUlJ" + "REFUKJGd0j9LW1EYBvDfvUkM1iaGkohaKJRQv0XJ5FCKg1PnoogUHCwOjnVTx67d2n6Cgq2O" + "7oXupdKhUIOQqMRSE733djiXNkoXPcvhvO/z530fThTFBTc9RUjfvM2020zeC5VS3i3kiBg/" + "ulQa4oXnUREcd9nZ5fAnvQ5nHaKEYkY14w4eNHm6+M9JfTwQHs5w2WdjHSkRBj2W5uge8Ghi" + "iBQl/O6RXDA9gUvWXnJ8xIdPYdQIpXiIVMJpm433tB4H0OcvLMwHxyzoSIeCUEB5QJywvUm/" + "T6vFk2dUavxC5Vp6RlDLya+3ODnBK4p3ebfC4D+RK2AM/TP29slSqjVerPJxJ/RG/6LzK00p" + "Y2UuqF7gHD2Mo5ELX3H62uZ+k85BWDbJF6/nIZUx1eR7d4hUnWR2mZn61eHztEQp344oN8Lz" + "Nn/vD5FAXWAC04u0AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +restore_inactive = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAA0AAAANCAYAAABy6+R8AAAABHNCSVQICAgIfAhkiAAAAYxJ" + "REFUKJGdkr2PTGEUh5/z3ntndmYXIyODiI8oVyGRLTUitpToNCRCJdv7B2gkOrV6Q4hWp6JV" + "jXILhWKHeMfcmXvfj3MUk7jbcqrTPPk9J+cn4gr+dUqAz9OFzWth0CtJCiEaWUHNiMnIahQ0" + "TEYF16+OpARYto6v35SZj/gaZnNj2UIblZlX6lXg8thzf/dYl7RRFfyYK2fHjskI9m6XZIWs" + "4Gtj72VkerAk5SEADiBEWKwEVeHEphASvPoQefq65fRJAdaqmHVQG43vP5XdawX3blZcueh4" + "/qjPqeMQsxEUytKoSu30YjZmXlkFeP8p0URj+0LBrZ2KrYGjpiBlR1bpoDYYhz6Ts7H/MTJv" + "4O4NWIhj/03AZ0hBCNl1UMjCrxr80nj2oI8qbA2FJ28j774oMQnWGqpH/qQ5s2paHr6IbPSg" + "KoTWCYfZcMGhvqHQjGAd5Ehsn/FMD35Ti6NXClnWOiFCkRI7lxKD/pGbzk96PL4zJoUhhvyt" + "S7L1bmpUpXBusgmA/E/3/gASuMtl4Uj5YAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- + +fullscreen = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAActJ" + "REFUOI2dk09I02EYx7/v+/7+DDRRYg4EWWYUKAjDSxBhJKuEUUJslwi8BXoaEaIdhpchddgt" + "CKIgCIbeYmXaTHboEigZ5GENdCCKfyZKTrf5+72Pp7nf9Lcf4gPP5fl+3i9feJ8HcKrghPD4" + "X9c5IdxJvHq4PFKvy3dOjKgltN4f71QU/lGo4kZD250/u5nZtB3H7IY9PRElW6f/ApgPAIiw" + "YZpax+rM8x2nNBeqSoLghMBkyIzFYptSSrcdzDnfCofDzd3db9X5+WdHAKAAQEt/9LKaz3zI" + "Ag+llG7f7UeQks4YLP787AaAnGdn2PsgupD9NvpVaeuLXmeGMkcwm8rg2tYe4tOLVY+D/i5L" + "EtYoQQlvIDqoEKgfoGbGmVEGHt/tQOBWe5WBrut4k05VTAQHA4b4ytTLVyAMSML/smgYBorF" + "YlUbxok/TEkmZ/zHfkHc5ACw/GX4E0B+q4GmaVVtNYBEPOPL39v4/iJ/Zg/O8wvWme0iIRLh" + "3t9osI6u7GI/lRozTqP2t7DUyVjJlWQlV46VXDl+5FpIX4Jmm8rWYDJkEmNPhSoKqqYUJKcn" + "64mxAzu05jHt/UtuN17rJSL6u5IYeV+LOwbQBrHjq9vsKwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +reload = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAApFJ" + "REFUOI11k72LXFUUwH/n3vvmvbzZnZnNl7sWI0mIISaIIKYJ2AmbznQWKezSiOm0NaXpAjZu" + "kQTMHyBC0JBOCwmyWBrXHaMmuopLdt7Ox3vz3r33WMyyCJscOBwOnPPjfAovEFWEr2kBcIla" + "BH1enBxI/Golb7ZGb/kZb6vXkyCI4VeX8G3iFn+Qq1vTFwL0886pcqofNSXvgh41qEGEqBJR" + "tl3Gl2ZBbhy6ujs4ACjXuidiET7zDauuhRFnidky0gwxfkz0gq+JJuEbl9kPDn1YPAYwAHqT" + "VEfhmq9ZdS4aJBIWThNeuUQ4fpEgbbAGk3dMbMxqqMI1vUkK4AAa8vN+ppdj96ypj59DJv+g" + "+TJiFtDuq2iIUO1A1sM8/c7Epr48Nd0voFifAxpzAQ0rdPuEi5/M+6rHaLkDf3yPWzqLOAfT" + "f8G20KZeCT5cANaNKoJKX4RExluIr5B8CXp9aCrsbHvuJ2201SGaNiKaaJS+KmJE0KjRIwZm" + "BZTP5gvXiHRWiJ3+vFObQdqD7AiIQIxeBHUAorqh1lWiIWP3TyiHkPXgpdfg5Dv4jXvY0S9g" + "LGoyRGyFbzb2hxiCfWgdA2M5J5v3sVRodpQg78GRU5B2MX89BT9Bmm1i1MFM7cP9NXZmo83Q" + "hNvEokzKAdZaEuNxjx8gj+6RDB9h8iWME/DDMlbh9jFGm/sAuU7UkbsVxuM1KX+fGgokzUlS" + "S1o9wbUMRgvYHUxDsbsmtbsl14kHTvnZx0td0vqKW2y/b7vLZ6R9LAfQyfY0DLd+nhWTO9a3" + "7h7+dKd43i8I0Hp5kYUrr7vTbyzzZq8tJwB2xvrbj09Yv/uT3/x7zBiYwcEKBEiBfM/aPQUI" + "ewk1MPk/4D/OAyg6YvZkywAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +remove = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAApVJ" + "REFUOI2lkUtIVHEUxr//vf9778x4J8d8DDaODjo+mBzLKFJJJbVWFdmiVaEtehBYi2hVENXK" + "XS0iC6JNFkbkInwVQeoiiLAHtlAhW6TjTPnA9DreO/d/WjjOIkiDDnxwFuc7fOd3gP8s+bmD" + "118+UPGmiagsNL88UJqb62gLhTrP1tVdmY5G334zjOiGG574XF00/IjmHt6lO+mujvvb/J1L" + "3d1k9vRQk9fbsWkCX9ya/DIxUdVQ2+gt9Obt3lG1N6ykp+NGe/vnl5OT15aEiGx6x03g4GBl" + "IEGX2ojaLlBXeflKXWbm/n9i8BTILivgV4vkuXC0/x0W3n9C3tYMnsjOXpmyrMEfhmFutIC7" + "s3C9Jpw4vjAO3Ha6zS2Ki11cNZXz+fnnXkUiMbuy8l6OrreYpikxxgVRQmKMyaqa9mJo6PUH" + "PhTc6Q9gDvM1u1BxuFVxKRK+9/UhOjaOiCzL24uLHzcfOlLvcGoAGDRNgSxz9PcPnIrHf9Xy" + "r6FqHm85gXBFCNUeDwMAo7EB77uewdHxIBLI85c3HzsKp9MJxhgYYwCAmZmZwOjoWBp3EbJz" + "SoPQPR5YpglbCLhcaQgEg/Do6XsWF1elkZGPUFUVkiRB0zTouo7p6Rh03bOPBwKBUIbbDQAg" + "AIwxmKYJb1YWTp9pPckkSYrFfoKIUgKAkpIgDMO6xX0+n+R0OSGESJG1LAv5BX4UBQulRCIB" + "y7Jg2zaEsGHbAkQCmqZifn7JwYlk+vM1jDEIIWAYBoQQSbNIiYggxCqEYDZXFDVlWge03v9N" + "azMEzjm4qqp83STLUvJGAmMEYM1AxFLpkgggSYCiaDKPRhenenuHddNM0BokgMhODq+DQyo6" + "QLBtgiwzNju7svwbnlAlxKIQCyQAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +sort = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAMdJ" + "REFUOI2VklEOgyAMhv+iR1jmdfQWHt1dQXA+dI9K97BpaIFE/4SQAv36UwC5BukAROxaOl7T" + "pPYdbmpZVxUrgMRNyLUkcZMqIIQ64IpCWMqAo6qdrbyfVdymAbmWLDAH+LKDq6oC0uql+FDw" + "uonnFWLcM8vONRkkLBWATSgBAeBt/gH9fp9WjLvY6t3zIZIiCZjnQFkTS8kA0PcDmBn8YTAz" + "hn7IHdSSD0lyLfqfOx3Y5FIPxnFUs3Jw9RUk7kLJerGJd/QF7eJxBTVIT38AAAAASUVORK5C" + "YII=") + +#---------------------------------------------------------------------- +superscript = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAYFJ" + "REFUOI3VkTtPAlEQhUfW4INCxMpigcTEVhMbCxO2NDZgg6UUJpSIzZZS+AO201gYaa1MbEy2" + "EAosbCQxxFdUsKLjIffOndl1sTBYiEFjYzzVmWTmy8wZgH+voZ82ru0+RfWpkeOJUV/04lpY" + "J+ZMDgDA91NAwD9s3T9Q4vyqZS3Mjm//Ytl3pfZr5Y2D52qvHu4Z0zQLrusCEQEzAxGllFKH" + "iAiICLZtGzGzkhPoQvUWE725jxMcx7GYeV4pFSOicj6fr0opC1LKKjOnlrYqCZ8G0bvHtsHk" + "BOfWL6MAn0JMp9OGUuqMmaHT6WSVUgnbtg0AgJWdm4I+PRZzX7vwIl9bR5szwT4AAEAymbQc" + "x8kIIYCIJovFYnNQJn1fIKKcEAI8z4N2u537LtQ+gJTyWAiRRUTodruZSCRiDAJoPROPx4O6" + "ru8hYqFUKlmBQGDS7/cvNpvNVU3TTomoPhAQDodPETEopVShUKgupUw1Go0aM9eZeRkAyp7n" + "fQn5W70BAIHMJSEYEtgAAAAASUVORK5CYII=") +#---------------------------------------------------------------------- + +# Custom pane bitmaps reference +# bitmap button id active maximize +CUSTOM_PANE_BITMAPS = [(close, aui.AUI_BUTTON_CLOSE, True, False), + (close_inactive, aui.AUI_BUTTON_CLOSE, False, False), + (minimize, aui.AUI_BUTTON_MINIMIZE, True, False), + (minimize_inactive, aui.AUI_BUTTON_MINIMIZE, False, False), + (maximize, aui.AUI_BUTTON_MAXIMIZE_RESTORE, True, True), + (maximize_inactive, aui.AUI_BUTTON_MAXIMIZE_RESTORE, False, True), + (restore, aui.AUI_BUTTON_MAXIMIZE_RESTORE, True, False), + (restore_inactive, aui.AUI_BUTTON_MAXIMIZE_RESTORE, False, False)] + +#---------------------------------------------------------------------- +# Custom buttons in tab area +# +CUSTOM_TAB_BUTTONS = {"Left": [(sort, aui.AUI_BUTTON_CUSTOM1), + (superscript, aui.AUI_BUTTON_CUSTOM2)], + "Right": [(fullscreen, aui.AUI_BUTTON_CUSTOM3), + (remove, aui.AUI_BUTTON_CUSTOM4), + (reload, aui.AUI_BUTTON_CUSTOM5)] + } + +#---------------------------------------------------------------------- + +# Define a translation function +_ = wx.GetTranslation + + +ID_CreateTree = wx.ID_HIGHEST + 1 +ID_CreateGrid = ID_CreateTree + 1 +ID_CreateText = ID_CreateTree + 2 +ID_CreateHTML = ID_CreateTree + 3 +ID_CreateNotebook = ID_CreateTree + 4 +ID_CreateSizeReport = ID_CreateTree + 5 +ID_GridContent = ID_CreateTree + 6 +ID_TextContent = ID_CreateTree + 7 +ID_TreeContent = ID_CreateTree + 8 +ID_HTMLContent = ID_CreateTree + 9 +ID_NotebookContent = ID_CreateTree + 10 +ID_SizeReportContent = ID_CreateTree + 11 +ID_SwitchPane = ID_CreateTree + 12 +ID_CreatePerspective = ID_CreateTree + 13 +ID_CopyPerspectiveCode = ID_CreateTree + 14 +ID_CreateNBPerspective = ID_CreateTree + 15 +ID_CopyNBPerspectiveCode = ID_CreateTree + 16 +ID_AllowFloating = ID_CreateTree + 17 +ID_AllowActivePane = ID_CreateTree + 18 +ID_TransparentHint = ID_CreateTree + 19 +ID_VenetianBlindsHint = ID_CreateTree + 20 +ID_RectangleHint = ID_CreateTree + 21 +ID_NoHint = ID_CreateTree + 22 +ID_HintFade = ID_CreateTree + 23 +ID_NoVenetianFade = ID_CreateTree + 24 +ID_TransparentDrag = ID_CreateTree + 25 +ID_NoGradient = ID_CreateTree + 26 +ID_VerticalGradient = ID_CreateTree + 27 +ID_HorizontalGradient = ID_CreateTree + 28 +ID_LiveUpdate = ID_CreateTree + 29 +ID_AnimateFrames = ID_CreateTree + 30 +ID_PaneIcons = ID_CreateTree + 31 +ID_TransparentPane = ID_CreateTree + 32 +ID_DefaultDockArt = ID_CreateTree + 33 +ID_ModernDockArt = ID_CreateTree + 34 +ID_SnapToScreen = ID_CreateTree + 35 +ID_SnapPanes = ID_CreateTree + 36 +ID_FlyOut = ID_CreateTree + 37 +ID_CustomPaneButtons = ID_CreateTree + 38 +ID_Settings = ID_CreateTree + 39 +ID_CustomizeToolbar = ID_CreateTree + 40 +ID_DropDownToolbarItem = ID_CreateTree + 41 +ID_MinimizePosSmart = ID_CreateTree + 42 +ID_MinimizePosTop = ID_CreateTree + 43 +ID_MinimizePosLeft = ID_CreateTree + 44 +ID_MinimizePosRight = ID_CreateTree + 45 +ID_MinimizePosBottom = ID_CreateTree + 46 +ID_MinimizeCaptSmart = ID_CreateTree + 47 +ID_MinimizeCaptHorz = ID_CreateTree + 48 +ID_MinimizeCaptHide = ID_CreateTree + 49 +ID_NotebookNoCloseButton = ID_CreateTree + 50 +ID_NotebookCloseButton = ID_CreateTree + 51 +ID_NotebookCloseButtonAll = ID_CreateTree + 52 +ID_NotebookCloseButtonActive = ID_CreateTree + 53 +ID_NotebookCloseOnLeft = ID_CreateTree + 54 +ID_NotebookAllowTabMove = ID_CreateTree + 55 +ID_NotebookAllowTabExternalMove = ID_CreateTree + 56 +ID_NotebookAllowTabSplit = ID_CreateTree + 57 +ID_NotebookTabFloat = ID_CreateTree + 58 +ID_NotebookTabDrawDnd = ID_CreateTree + 59 +ID_NotebookDclickUnsplit = ID_CreateTree + 60 +ID_NotebookWindowList = ID_CreateTree + 61 +ID_NotebookScrollButtons = ID_CreateTree + 62 +ID_NotebookTabFixedWidth = ID_CreateTree + 63 +ID_NotebookArtGloss = ID_CreateTree + 64 +ID_NotebookArtSimple = ID_CreateTree + 65 +ID_NotebookArtVC71 = ID_CreateTree + 66 +ID_NotebookArtFF2 = ID_CreateTree + 67 +ID_NotebookArtVC8 = ID_CreateTree + 68 +ID_NotebookArtChrome = ID_CreateTree + 69 +ID_NotebookAlignTop = ID_CreateTree + 70 +ID_NotebookAlignBottom = ID_CreateTree + 71 +ID_NotebookHideSingle = ID_CreateTree + 72 +ID_NotebookSmartTab = ID_CreateTree + 73 +ID_NotebookUseImagesDropDown = ID_CreateTree + 74 +ID_NotebookCustomButtons = ID_CreateTree + 75 +ID_NotebookMinMaxWidth = ID_CreateTree + 76 + +ID_SampleItem = ID_CreateTree + 77 +ID_StandardGuides = ID_CreateTree + 78 +ID_AeroGuides = ID_CreateTree + 79 +ID_WhidbeyGuides = ID_CreateTree + 80 +ID_NotebookPreview = ID_CreateTree + 81 +ID_PreviewMinimized = ID_CreateTree + 82 + +ID_SmoothDocking = ID_CreateTree + 83 +ID_NativeMiniframes = ID_CreateTree + 84 + +ID_FirstPerspective = ID_CreatePerspective + 1000 +ID_FirstNBPerspective = ID_CreateNBPerspective + 10000 + +ID_PaneBorderSize = ID_SampleItem + 100 +ID_SashSize = ID_PaneBorderSize + 2 +ID_CaptionSize = ID_PaneBorderSize + 3 +ID_BackgroundColour = ID_PaneBorderSize + 4 +ID_SashColour = ID_PaneBorderSize + 5 +ID_InactiveCaptionColour = ID_PaneBorderSize + 6 +ID_InactiveCaptionGradientColour = ID_PaneBorderSize + 7 +ID_InactiveCaptionTextColour = ID_PaneBorderSize + 8 +ID_ActiveCaptionColour = ID_PaneBorderSize + 9 +ID_ActiveCaptionGradientColour = ID_PaneBorderSize + 10 +ID_ActiveCaptionTextColour = ID_PaneBorderSize + 11 +ID_BorderColour = ID_PaneBorderSize + 12 +ID_GripperColour = ID_PaneBorderSize + 13 +ID_SashGrip = ID_PaneBorderSize + 14 +ID_HintColour = ID_PaneBorderSize + 15 + +ID_VetoTree = ID_PaneBorderSize + 16 +ID_VetoText = ID_PaneBorderSize + 17 +ID_NotebookMultiLine = ID_PaneBorderSize + 18 + +# -- SizeReportCtrl -- +# (a utility control that always reports it's client size) + +class SizeReportCtrl(wx.PyControl): + + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, + size=wx.DefaultSize, mgr=None): + + wx.PyControl.__init__(self, parent, id, pos, size, style=wx.NO_BORDER) + self._mgr = mgr + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + self.Bind(wx.EVT_SIZE, self.OnSize) + + + def OnPaint(self, event): + + dc = wx.PaintDC(self) + size = self.GetClientSize() + + s = "Size: %d x %d"%(size.x, size.y) + + dc.SetFont(wx.NORMAL_FONT) + w, height = dc.GetTextExtent(s) + height += 3 + dc.SetBrush(wx.WHITE_BRUSH) + dc.SetPen(wx.WHITE_PEN) + dc.DrawRectangle(0, 0, size.x, size.y) + dc.SetPen(wx.LIGHT_GREY_PEN) + dc.DrawLine(0, 0, size.x, size.y) + dc.DrawLine(0, size.y, size.x, 0) + dc.DrawText(s, (size.x-w)/2, (size.y-height*5)/2) + + if self._mgr: + + pi = self._mgr.GetPane(self) + + s = "Layer: %d"%pi.dock_layer + w, h = dc.GetTextExtent(s) + dc.DrawText(s, (size.x-w)/2, ((size.y-(height*5))/2)+(height*1)) + + s = "Dock: %d Row: %d"%(pi.dock_direction, pi.dock_row) + w, h = dc.GetTextExtent(s) + dc.DrawText(s, (size.x-w)/2, ((size.y-(height*5))/2)+(height*2)) + + s = "Position: %d"%pi.dock_pos + w, h = dc.GetTextExtent(s) + dc.DrawText(s, (size.x-w)/2, ((size.y-(height*5))/2)+(height*3)) + + s = "Proportion: %d"%pi.dock_proportion + w, h = dc.GetTextExtent(s) + dc.DrawText(s, (size.x-w)/2, ((size.y-(height*5))/2)+(height*4)) + + + def OnEraseBackground(self, event): + + pass + + + def OnSize(self, event): + + self.Refresh() + + +class SettingsPanel(wx.Panel): + + def __init__(self, parent, frame): + + wx.Panel.__init__(self, parent) + self._frame = frame + + s1 = wx.BoxSizer(wx.HORIZONTAL) + self._border_size = wx.SpinCtrl(self, ID_PaneBorderSize, "%d"%frame.GetDockArt().GetMetric(aui.AUI_DOCKART_PANE_BORDER_SIZE), + wx.DefaultPosition, wx.Size(50, 20), wx.SP_ARROW_KEYS, 0, 100, + frame.GetDockArt().GetMetric(aui.AUI_DOCKART_PANE_BORDER_SIZE)) + s1.Add((1, 1), 1, wx.EXPAND) + s1.Add(wx.StaticText(self, -1, "Pane Border Size:")) + s1.Add(self._border_size) + s1.Add((1, 1), 1, wx.EXPAND) + s1.SetItemMinSize(1, (180, 20)) + + s2 = wx.BoxSizer(wx.HORIZONTAL) + self._sash_size = wx.SpinCtrl(self, ID_SashSize, "%d"%frame.GetDockArt().GetMetric(aui.AUI_DOCKART_SASH_SIZE), wx.DefaultPosition, + wx.Size(50, 20), wx.SP_ARROW_KEYS, 0, 100, frame.GetDockArt().GetMetric(aui.AUI_DOCKART_SASH_SIZE)) + s2.Add((1, 1), 1, wx.EXPAND) + s2.Add(wx.StaticText(self, -1, "Sash Size:")) + s2.Add(self._sash_size) + s2.Add((1, 1), 1, wx.EXPAND) + s2.SetItemMinSize(1, (180, 20)) + + s3 = wx.BoxSizer(wx.HORIZONTAL) + self._caption_size = wx.SpinCtrl(self, ID_CaptionSize, "%d"%frame.GetDockArt().GetMetric(aui.AUI_DOCKART_CAPTION_SIZE), + wx.DefaultPosition, wx.Size(50, 20), wx.SP_ARROW_KEYS, 0, 100, frame.GetDockArt().GetMetric(aui.AUI_DOCKART_CAPTION_SIZE)) + s3.Add((1, 1), 1, wx.EXPAND) + s3.Add(wx.StaticText(self, -1, "Caption Size:")) + s3.Add(self._caption_size) + s3.Add((1, 1), 1, wx.EXPAND) + s3.SetItemMinSize(1, (180, 20)) + + b = self.CreateColourBitmap(wx.BLACK) + + s4 = wx.BoxSizer(wx.HORIZONTAL) + self._background_colour = wx.BitmapButton(self, ID_BackgroundColour, b, wx.DefaultPosition, wx.Size(50, 25)) + s4.Add((1, 1), 1, wx.EXPAND) + s4.Add(wx.StaticText(self, -1, "Background Colour:")) + s4.Add(self._background_colour) + s4.Add((1, 1), 1, wx.EXPAND) + s4.SetItemMinSize(1, (180, 20)) + + s5 = wx.BoxSizer(wx.HORIZONTAL) + self._sash_colour = wx.BitmapButton(self, ID_SashColour, b, wx.DefaultPosition, wx.Size(50, 25)) + s5.Add((1, 1), 1, wx.EXPAND) + s5.Add(wx.StaticText(self, -1, "Sash Colour:")) + s5.Add(self._sash_colour) + s5.Add((1, 1), 1, wx.EXPAND) + s5.SetItemMinSize(1, (180, 20)) + + s6 = wx.BoxSizer(wx.HORIZONTAL) + self._inactive_caption_colour = wx.BitmapButton(self, ID_InactiveCaptionColour, b, wx.DefaultPosition, wx.Size(50, 25)) + s6.Add((1, 1), 1, wx.EXPAND) + s6.Add(wx.StaticText(self, -1, "Normal Caption:")) + s6.Add(self._inactive_caption_colour) + s6.Add((1, 1), 1, wx.EXPAND) + s6.SetItemMinSize(1, (180, 20)) + + s7 = wx.BoxSizer(wx.HORIZONTAL) + self._inactive_caption_gradient_colour = wx.BitmapButton(self, ID_InactiveCaptionGradientColour, b, wx.DefaultPosition, wx.Size(50, 25)) + s7.Add((1, 1), 1, wx.EXPAND) + s7.Add(wx.StaticText(self, -1, "Normal Caption Gradient:")) + s7.Add(self._inactive_caption_gradient_colour) + s7.Add((1, 1), 1, wx.EXPAND) + s7.SetItemMinSize(1, (180, 20)) + + s8 = wx.BoxSizer(wx.HORIZONTAL) + self._inactive_caption_text_colour = wx.BitmapButton(self, ID_InactiveCaptionTextColour, b, wx.DefaultPosition, wx.Size(50, 25)) + s8.Add((1, 1), 1, wx.EXPAND) + s8.Add(wx.StaticText(self, -1, "Normal Caption Text:")) + s8.Add(self._inactive_caption_text_colour) + s8.Add((1, 1), 1, wx.EXPAND) + s8.SetItemMinSize(1, (180, 20)) + + s9 = wx.BoxSizer(wx.HORIZONTAL) + self._active_caption_colour = wx.BitmapButton(self, ID_ActiveCaptionColour, b, wx.DefaultPosition, wx.Size(50, 25)) + s9.Add((1, 1), 1, wx.EXPAND) + s9.Add(wx.StaticText(self, -1, "Active Caption:")) + s9.Add(self._active_caption_colour) + s9.Add((1, 1), 1, wx.EXPAND) + s9.SetItemMinSize(1, (180, 20)) + + s10 = wx.BoxSizer(wx.HORIZONTAL) + self._active_caption_gradient_colour = wx.BitmapButton(self, ID_ActiveCaptionGradientColour, b, wx.DefaultPosition, wx.Size(50, 25)) + s10.Add((1, 1), 1, wx.EXPAND) + s10.Add(wx.StaticText(self, -1, "Active Caption Gradient:")) + s10.Add(self._active_caption_gradient_colour) + s10.Add((1, 1), 1, wx.EXPAND) + s10.SetItemMinSize(1, (180, 20)) + + s11 = wx.BoxSizer(wx.HORIZONTAL) + self._active_caption_text_colour = wx.BitmapButton(self, ID_ActiveCaptionTextColour, b, wx.DefaultPosition, wx.Size(50, 25)) + s11.Add((1, 1), 1, wx.EXPAND) + s11.Add(wx.StaticText(self, -1, "Active Caption Text:")) + s11.Add(self._active_caption_text_colour) + s11.Add((1, 1), 1, wx.EXPAND) + s11.SetItemMinSize(1, (180, 20)) + + s12 = wx.BoxSizer(wx.HORIZONTAL) + self._border_colour = wx.BitmapButton(self, ID_BorderColour, b, wx.DefaultPosition, wx.Size(50, 25)) + s12.Add((1, 1), 1, wx.EXPAND) + s12.Add(wx.StaticText(self, -1, "Border Colour:")) + s12.Add(self._border_colour) + s12.Add((1, 1), 1, wx.EXPAND) + s12.SetItemMinSize(1, (180, 20)) + + s13 = wx.BoxSizer(wx.HORIZONTAL) + self._gripper_colour = wx.BitmapButton(self, ID_GripperColour, b, wx.DefaultPosition, wx.Size(50,25)) + s13.Add((1, 1), 1, wx.EXPAND) + s13.Add(wx.StaticText(self, -1, "Gripper Colour:")) + s13.Add(self._gripper_colour) + s13.Add((1, 1), 1, wx.EXPAND) + s13.SetItemMinSize(1, (180, 20)) + + s14 = wx.BoxSizer(wx.HORIZONTAL) + self._sash_grip = wx.CheckBox(self, ID_SashGrip, "", wx.DefaultPosition, wx.Size(50,20)) + s14.Add((1, 1), 1, wx.EXPAND) + s14.Add(wx.StaticText(self, -1, "Draw Sash Grip:")) + s14.Add(self._sash_grip) + s14.Add((1, 1), 1, wx.EXPAND) + s14.SetItemMinSize(1, (180, 20)) + + s15 = wx.BoxSizer(wx.HORIZONTAL) + self._hint_colour = wx.BitmapButton(self, ID_HintColour, b, wx.DefaultPosition, wx.Size(50,25)) + s15.Add((1, 1), 1, wx.EXPAND) + s15.Add(wx.StaticText(self, -1, "Hint Window Colour:")) + s15.Add(self._hint_colour) + s15.Add((1, 1), 1, wx.EXPAND) + s15.SetItemMinSize(1, (180, 20)) + + grid_sizer = wx.GridSizer(0, 2) + grid_sizer.SetHGap(5) + grid_sizer.Add(s1) + grid_sizer.Add(s4) + grid_sizer.Add(s2) + grid_sizer.Add(s5) + grid_sizer.Add(s3) + grid_sizer.Add(s13) + grid_sizer.Add(s14) + grid_sizer.Add((1, 1)) + grid_sizer.Add(s12) + grid_sizer.Add(s6) + grid_sizer.Add(s9) + grid_sizer.Add(s7) + grid_sizer.Add(s10) + grid_sizer.Add(s8) + grid_sizer.Add(s11) + grid_sizer.Add(s15) + + cont_sizer = wx.BoxSizer(wx.VERTICAL) + cont_sizer.Add(grid_sizer, 1, wx.EXPAND | wx.ALL, 5) + self.SetSizer(cont_sizer) + self.GetSizer().SetSizeHints(self) + + self._border_size.SetValue(frame.GetDockArt().GetMetric(aui.AUI_DOCKART_PANE_BORDER_SIZE)) + self._sash_size.SetValue(frame.GetDockArt().GetMetric(aui.AUI_DOCKART_SASH_SIZE)) + self._caption_size.SetValue(frame.GetDockArt().GetMetric(aui.AUI_DOCKART_CAPTION_SIZE)) + self._sash_grip.SetValue(frame.GetDockArt().GetMetric(aui.AUI_DOCKART_DRAW_SASH_GRIP)) + + self.UpdateColours() + + self.Bind(wx.EVT_SPINCTRL, self.OnPaneBorderSize, id=ID_PaneBorderSize) + self.Bind(wx.EVT_SPINCTRL, self.OnSashSize, id=ID_SashSize) + self.Bind(wx.EVT_SPINCTRL, self.OnCaptionSize, id=ID_CaptionSize) + self.Bind(wx.EVT_CHECKBOX, self.OnDrawSashGrip, id=ID_SashGrip) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_BackgroundColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_SashColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_InactiveCaptionColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_InactiveCaptionGradientColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_InactiveCaptionTextColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_ActiveCaptionColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_ActiveCaptionGradientColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_ActiveCaptionTextColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_BorderColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_GripperColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_HintColour) + + + def CreateColourBitmap(self, c): + + image = wx.EmptyImage(25, 14) + for x in xrange(25): + for y in xrange(14): + pixcol = c + if x == 0 or x == 24 or y == 0 or y == 13: + pixcol = wx.BLACK + + image.SetRGB(x, y, pixcol.Red(), pixcol.Green(), pixcol.Blue()) + + return image.ConvertToBitmap() + + + def UpdateColours(self): + + bk = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_BACKGROUND_COLOUR) + self._background_colour.SetBitmapLabel(self.CreateColourBitmap(bk)) + + cap = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_INACTIVE_CAPTION_COLOUR) + self._inactive_caption_colour.SetBitmapLabel(self.CreateColourBitmap(cap)) + + capgrad = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR) + self._inactive_caption_gradient_colour.SetBitmapLabel(self.CreateColourBitmap(capgrad)) + + captxt = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR) + self._inactive_caption_text_colour.SetBitmapLabel(self.CreateColourBitmap(captxt)) + + acap = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_ACTIVE_CAPTION_COLOUR) + self._active_caption_colour.SetBitmapLabel(self.CreateColourBitmap(acap)) + + acapgrad = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR) + self._active_caption_gradient_colour.SetBitmapLabel(self.CreateColourBitmap(acapgrad)) + + acaptxt = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR) + self._active_caption_text_colour.SetBitmapLabel(self.CreateColourBitmap(acaptxt)) + + sash = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_SASH_COLOUR) + self._sash_colour.SetBitmapLabel(self.CreateColourBitmap(sash)) + + border = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_BORDER_COLOUR) + self._border_colour.SetBitmapLabel(self.CreateColourBitmap(border)) + + gripper = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_GRIPPER_COLOUR) + self._gripper_colour.SetBitmapLabel(self.CreateColourBitmap(gripper)) + + hint = self._frame.GetDockArt().GetColour(aui.AUI_DOCKART_HINT_WINDOW_COLOUR) + self._hint_colour.SetBitmapLabel(self.CreateColourBitmap(hint)) + + + def OnPaneBorderSize(self, event): + + self._frame.GetDockArt().SetMetric(aui.AUI_DOCKART_PANE_BORDER_SIZE, + event.GetInt()) + self._frame.DoUpdate() + + + def OnSashSize(self, event): + + self._frame.GetDockArt().SetMetric(aui.AUI_DOCKART_SASH_SIZE, + event.GetInt()) + self._frame.DoUpdate() + + + def OnCaptionSize(self, event): + + self._frame.GetDockArt().SetMetric(aui.AUI_DOCKART_CAPTION_SIZE, + event.GetInt()) + self._frame.DoUpdate() + + + def OnDrawSashGrip(self, event): + + self._frame.GetDockArt().SetMetric(aui.AUI_DOCKART_DRAW_SASH_GRIP, + event.GetInt()) + self._frame.DoUpdate() + + + def OnSetColour(self, event): + + dlg = wx.ColourDialog(self._frame) + dlg.SetTitle("Colour Picker") + + if dlg.ShowModal() != wx.ID_OK: + return + + evId = event.GetId() + if evId == ID_BackgroundColour: + var = aui.AUI_DOCKART_BACKGROUND_COLOUR + elif evId == ID_SashColour: + var = aui.AUI_DOCKART_SASH_COLOUR + elif evId == ID_InactiveCaptionColour: + var = aui.AUI_DOCKART_INACTIVE_CAPTION_COLOUR + elif evId == ID_InactiveCaptionGradientColour: + var = aui.AUI_DOCKART_INACTIVE_CAPTION_GRADIENT_COLOUR + elif evId == ID_InactiveCaptionTextColour: + var = aui.AUI_DOCKART_INACTIVE_CAPTION_TEXT_COLOUR + elif evId == ID_ActiveCaptionColour: + var = aui.AUI_DOCKART_ACTIVE_CAPTION_COLOUR + elif evId == ID_ActiveCaptionGradientColour: + var = aui.AUI_DOCKART_ACTIVE_CAPTION_GRADIENT_COLOUR + elif evId == ID_ActiveCaptionTextColour: + var = aui.AUI_DOCKART_ACTIVE_CAPTION_TEXT_COLOUR + elif evId == ID_BorderColour: + var = aui.AUI_DOCKART_BORDER_COLOUR + elif evId == ID_GripperColour: + var = aui.AUI_DOCKART_GRIPPER_COLOUR + elif evId == ID_HintColour: + var = aui.AUI_DOCKART_HINT_WINDOW_COLOUR + else: + return + + self._frame.GetDockArt().SetColour(var, dlg.GetColourData().GetColour()) + self._frame.DoUpdate() + self.UpdateColours() + + +# ---------------------------------------------------------------------------- # +# Class ProgressGauge +# ---------------------------------------------------------------------------- # + +class ProgressGauge(wx.PyWindow): + """ This class provides a visual alternative for wx.Gauge.""" + + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=(-1,30)): + """ Default class constructor. """ + + wx.PyWindow.__init__(self, parent, id, pos, size, style=wx.BORDER_NONE) + + self._value = 0 + self._steps = 16 + self._pos = 0 + self._current = 0 + self._gaugeproportion = 0.4 + self._startTime = time.time() + + self._bottomStartColour = wx.GREEN + rgba = self._bottomStartColour.Red(), self._bottomStartColour.Green(), \ + self._bottomStartColour.Blue(), self._bottomStartColour.Alpha() + self._bottomEndColour = self.LightColour(self._bottomStartColour, 30) + self._topStartColour = self.LightColour(self._bottomStartColour, 80) + self._topEndColour = self.LightColour(self._bottomStartColour, 40) + + self._background = wx.Brush(wx.WHITE, wx.SOLID) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + + + def OnEraseBackground(self, event): + """ Handles the wx.EVT_ERASE_BACKGROUND event for ProgressGauge. """ + + pass + + + def OnPaint(self, event): + """ Handles the wx.EVT_PAINT event for ProgressGauge. """ + + dc = wx.BufferedPaintDC(self) + dc.SetBackground(self._background) + dc.SetBackground(wx.WHITE_BRUSH) + dc.Clear() + + xsize, ysize = self.GetClientSize() + interval = xsize/float(self._steps) + + self._pos = interval*self._value + + status = self._current/(self._steps - int((self._gaugeproportion*xsize/interval))) + + if status%2 == 0: + increment = 1 + else: + increment = -1 + + self._value = self._value + increment + self._current = self._current + 1 + + self.DrawProgress(dc, xsize, ysize, increment) + + dc.SetBrush(wx.TRANSPARENT_BRUSH) + dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRADIENTINACTIVECAPTION))) + dc.DrawRectangleRect(self.GetClientRect()) + + + def LightColour(self, colour, percent): + """ + Return light contrast of colour. The colour returned is from the scale of + colour -> white. The percent determines how light the colour will be. + Percent = 100 return white, percent = 0 returns colour. + """ + + end_colour = wx.WHITE + rd = end_colour.Red() - colour.Red() + gd = end_colour.Green() - colour.Green() + bd = end_colour.Blue() - colour.Blue() + high = 100 + + # We take the percent way of the colour from colour -> white + i = percent + r = colour.Red() + ((i*rd*100)/high)/100 + g = colour.Green() + ((i*gd*100)/high)/100 + b = colour.Blue() + ((i*bd*100)/high)/100 + + return wx.Colour(r, g, b) + + + def DrawProgress(self, dc, xsize, ysize, increment): + """ Actually draws the sliding bar. """ + + interval = self._gaugeproportion*xsize + gc = wx.GraphicsContext.Create(dc) + + clientRect = self.GetClientRect() + gradientRect = wx.Rect(*clientRect) + + x, y, width, height = clientRect + x, width = self._pos, interval + + gradientRect.SetHeight(gradientRect.GetHeight()/2) + topStart, topEnd = self._topStartColour, self._topEndColour + + rc1 = wx.Rect(x, y, width, height/2) + path1 = self.GetPath(gc, rc1, 8) + br1 = gc.CreateLinearGradientBrush(x, y, x, y+height/2, topStart, topEnd) + gc.SetBrush(br1) + gc.FillPath(path1) #draw main + + path4 = gc.CreatePath() + path4.AddRectangle(x, y+height/2-8, width, 8) + path4.CloseSubpath() + gc.SetBrush(br1) + gc.FillPath(path4) + + gradientRect.Offset((0, gradientRect.GetHeight())) + + bottomStart, bottomEnd = self._bottomStartColour, self._bottomEndColour + + rc3 = wx.Rect(x, y+height/2, width, height/2) + path3 = self.GetPath(gc, rc3, 8) + br3 = gc.CreateLinearGradientBrush(x, y+height/2, x, y+height, bottomStart, bottomEnd) + gc.SetBrush(br3) + gc.FillPath(path3) #draw main + + path4 = gc.CreatePath() + path4.AddRectangle(x, y+height/2, width, 8) + path4.CloseSubpath() + gc.SetBrush(br3) + gc.FillPath(path4) + + + def GetPath(self, gc, rc, r): + """ Returns a rounded GraphicsPath. """ + + x, y, w, h = rc + path = gc.CreatePath() + path.AddRoundedRectangle(x, y, w, h, r) + path.CloseSubpath() + return path + + + + def Pulse(self): + """ Updates the gauge with a new value. """ + + self.Refresh() + + +class AuiFrame(wx.Frame): + + def __init__(self, parent, id=wx.ID_ANY, title="", pos= wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE|wx.SUNKEN_BORDER, log=None): + + wx.Frame.__init__(self, parent, id, title, pos, size, style) + + self._mgr = aui.AuiManager() + + # tell AuiManager to manage this frame + self._mgr.SetManagedWindow(self) + + # set frame icon + self.SetIcon(images.Mondrian.GetIcon()) + + # set up default notebook style + self._notebook_style = aui.AUI_NB_DEFAULT_STYLE | aui.AUI_NB_TAB_EXTERNAL_MOVE | wx.NO_BORDER + self._notebook_theme = 0 + # Attributes + self._textCount = 1 + self._transparency = 255 + self._snapped = False + self._custom_pane_buttons = False + self._custom_tab_buttons = False + self._pane_icons = False + self._veto_tree = self._veto_text = False + + self.log = log + + self.CreateStatusBar() + self.GetStatusBar().SetStatusText("Ready") + + self.BuildPanes() + self.CreateMenuBar() + self.BindEvents() + + + def CreateMenuBar(self): + + # create menu + mb = wx.MenuBar() + + file_menu = wx.Menu() + file_menu.Append(wx.ID_EXIT, "Exit") + + view_menu = wx.Menu() + view_menu.Append(ID_CreateText, "Create Text Control") + view_menu.Append(ID_CreateHTML, "Create HTML Control") + view_menu.Append(ID_CreateTree, "Create Tree") + view_menu.Append(ID_CreateGrid, "Create Grid") + view_menu.Append(ID_CreateNotebook, "Create Notebook") + view_menu.Append(ID_CreateSizeReport, "Create Size Reporter") + view_menu.AppendSeparator() + view_menu.Append(ID_GridContent, "Use a Grid for the Content Pane") + view_menu.Append(ID_TextContent, "Use a Text Control for the Content Pane") + view_menu.Append(ID_HTMLContent, "Use an HTML Control for the Content Pane") + view_menu.Append(ID_TreeContent, "Use a Tree Control for the Content Pane") + view_menu.Append(ID_NotebookContent, "Use a AuiNotebook control for the Content Pane") + view_menu.Append(ID_SizeReportContent, "Use a Size Reporter for the Content Pane") + view_menu.AppendSeparator() + +## if wx.Platform == "__WXMAC__": +## switcherAccel = "Alt+Tab" +## elif wx.Platform == "__WXGTK__": +## switcherAccel = "Ctrl+/" +## else: +## switcherAccel = "Ctrl+Tab" +## +## view_menu.Append(ID_SwitchPane, _("S&witch Window...") + "\t" + switcherAccel) + + options_menu = wx.Menu() + options_menu.AppendRadioItem(ID_TransparentHint, "Transparent Hint") + options_menu.AppendRadioItem(ID_VenetianBlindsHint, "Venetian Blinds Hint") + options_menu.AppendRadioItem(ID_RectangleHint, "Rectangle Hint") + options_menu.AppendRadioItem(ID_NoHint, "No Hint") + options_menu.AppendSeparator() + options_menu.AppendCheckItem(ID_HintFade, "Hint Fade-in") + options_menu.AppendCheckItem(ID_AllowFloating, "Allow Floating") + options_menu.AppendCheckItem(ID_NoVenetianFade, "Disable Venetian Blinds Hint Fade-in") + options_menu.AppendCheckItem(ID_TransparentDrag, "Transparent Drag") + options_menu.AppendCheckItem(ID_AllowActivePane, "Allow Active Pane") + options_menu.AppendCheckItem(ID_LiveUpdate, "Live Resize Update") + options_menu.AppendCheckItem(ID_NativeMiniframes, "Use Native wx.MiniFrames") + options_menu.AppendSeparator() + options_menu.AppendRadioItem(ID_MinimizePosSmart, "Minimize in Smart mode").Check() + options_menu.AppendRadioItem(ID_MinimizePosTop, "Minimize on Top") + options_menu.AppendRadioItem(ID_MinimizePosLeft, "Minimize on the Left") + options_menu.AppendRadioItem(ID_MinimizePosRight, "Minimize on the Right") + options_menu.AppendRadioItem(ID_MinimizePosBottom, "Minimize at the Bottom") + options_menu.AppendSeparator() + options_menu.AppendRadioItem(ID_MinimizeCaptSmart, "Smart Minimized Caption") + options_menu.AppendRadioItem(ID_MinimizeCaptHorz, "Horizontal Minimized Caption") + options_menu.AppendRadioItem(ID_MinimizeCaptHide, "Hidden Minimized Caption").Check() + options_menu.AppendSeparator() + options_menu.AppendCheckItem(ID_PaneIcons, "Set Icons On Panes") + options_menu.AppendCheckItem(ID_AnimateFrames, "Animate Dock/Close/Minimize Of Floating Panes") + options_menu.AppendCheckItem(ID_SmoothDocking, "Smooth Docking Effects (PyQT Style)") + options_menu.AppendSeparator() + options_menu.Append(ID_TransparentPane, "Set Floating Panes Transparency") + options_menu.AppendSeparator() + options_menu.AppendRadioItem(ID_DefaultDockArt, "Default DockArt") + options_menu.AppendRadioItem(ID_ModernDockArt, "Modern Dock Art") + options_menu.AppendSeparator() + options_menu.Append(ID_SnapToScreen, "Snap To Screen") + options_menu.AppendCheckItem(ID_SnapPanes, "Snap Panes To Managed Window") + options_menu.AppendCheckItem(ID_FlyOut, "Use Fly-Out Floating Panes") + options_menu.AppendSeparator() + options_menu.AppendCheckItem(ID_CustomPaneButtons, "Set Custom Pane Button Bitmaps") + options_menu.AppendSeparator() + options_menu.AppendRadioItem(ID_NoGradient, "No Caption Gradient") + options_menu.AppendRadioItem(ID_VerticalGradient, "Vertical Caption Gradient") + options_menu.AppendRadioItem(ID_HorizontalGradient, "Horizontal Caption Gradient") + options_menu.AppendSeparator() + options_menu.AppendCheckItem(ID_PreviewMinimized, "Preview Minimized Panes") + options_menu.AppendSeparator() + options_menu.Append(ID_Settings, "Settings Pane") + + notebook_menu = wx.Menu() + notebook_menu.AppendRadioItem(ID_NotebookArtGloss, "Glossy Theme (Default)") + notebook_menu.AppendRadioItem(ID_NotebookArtSimple, "Simple Theme") + notebook_menu.AppendRadioItem(ID_NotebookArtVC71, "VC71 Theme") + notebook_menu.AppendRadioItem(ID_NotebookArtFF2, "Firefox 2 Theme") + notebook_menu.AppendRadioItem(ID_NotebookArtVC8, "VC8 Theme") + notebook_menu.AppendRadioItem(ID_NotebookArtChrome, "Chrome Theme") + notebook_menu.AppendSeparator() + notebook_menu.AppendRadioItem(ID_NotebookNoCloseButton, "No Close Button") + notebook_menu.AppendRadioItem(ID_NotebookCloseButton, "Close Button At Right") + notebook_menu.AppendRadioItem(ID_NotebookCloseButtonAll, "Close Button On All Tabs") + notebook_menu.AppendRadioItem(ID_NotebookCloseButtonActive, "Close Button On Active Tab") + notebook_menu.AppendSeparator() + notebook_menu.AppendCheckItem(ID_NotebookCloseOnLeft, "Close Button On The Left Of Tabs") + notebook_menu.AppendSeparator() + notebook_menu.AppendRadioItem(ID_NotebookAlignTop, "Tab Top Alignment") + notebook_menu.AppendRadioItem(ID_NotebookAlignBottom, "Tab Bottom Alignment") + notebook_menu.AppendSeparator() + notebook_menu.AppendCheckItem(ID_NotebookAllowTabMove, "Allow Tab Move") + notebook_menu.AppendCheckItem(ID_NotebookAllowTabExternalMove, "Allow External Tab Move") + notebook_menu.AppendCheckItem(ID_NotebookAllowTabSplit, "Allow Notebook Split") + notebook_menu.AppendCheckItem(ID_NotebookTabFloat, "Allow Single Tab Floating") + notebook_menu.AppendSeparator() + notebook_menu.AppendCheckItem(ID_NotebookDclickUnsplit, "Unsplit On Sash Double-Click") + notebook_menu.AppendCheckItem(ID_NotebookTabDrawDnd, "Draw Tab Image On Drag 'n' Drop") + notebook_menu.AppendSeparator() + notebook_menu.AppendCheckItem(ID_NotebookScrollButtons, "Scroll Buttons Visible") + notebook_menu.AppendCheckItem(ID_NotebookWindowList, "Window List Button Visible") + notebook_menu.AppendCheckItem(ID_NotebookTabFixedWidth, "Fixed-Width Tabs") + notebook_menu.AppendSeparator() + notebook_menu.AppendCheckItem(ID_NotebookHideSingle, "Hide On Single Tab") + notebook_menu.AppendCheckItem(ID_NotebookSmartTab, "Use Smart Tabbing") + notebook_menu.AppendCheckItem(ID_NotebookUseImagesDropDown, "Use Tab Images In Dropdown Menu") + notebook_menu.AppendCheckItem(ID_NotebookCustomButtons, "Show Custom Buttons In Tab Area") + notebook_menu.AppendSeparator() + notebook_menu.Append(ID_NotebookMinMaxWidth, "Set Min/Max Tab Widths") + notebook_menu.Append(ID_NotebookMultiLine, "Add A Multi-Line Label Tab") + notebook_menu.AppendSeparator() + notebook_menu.Append(ID_NotebookPreview, "Preview Of All Notebook Pages") + + perspectives_menu = wx.Menu() + + self._perspectives_menu = wx.Menu() + self._perspectives_menu.Append(ID_CreatePerspective, "Create Perspective") + self._perspectives_menu.Append(ID_CopyPerspectiveCode, "Copy Perspective Data To Clipboard") + self._perspectives_menu.AppendSeparator() + self._perspectives_menu.Append(ID_FirstPerspective+0, "Default Startup") + self._perspectives_menu.Append(ID_FirstPerspective+1, "All Panes") + + self._nb_perspectives_menu = wx.Menu() + self._nb_perspectives_menu.Append(ID_CreateNBPerspective, "Create Perspective") + self._nb_perspectives_menu.Append(ID_CopyNBPerspectiveCode, "Copy Perspective Data To Clipboard") + self._nb_perspectives_menu.AppendSeparator() + self._nb_perspectives_menu.Append(ID_FirstNBPerspective+0, "Default Startup") + + guides_menu = wx.Menu() + guides_menu.AppendRadioItem(ID_StandardGuides, "Standard Docking Guides") + guides_menu.AppendRadioItem(ID_AeroGuides, "Aero-Style Docking Guides") + guides_menu.AppendRadioItem(ID_WhidbeyGuides, "Whidbey-Style Docking Guides") + + perspectives_menu.AppendMenu(wx.ID_ANY, "Frame Perspectives", self._perspectives_menu) + perspectives_menu.AppendMenu(wx.ID_ANY, "AuiNotebook Perspectives", self._nb_perspectives_menu) + perspectives_menu.AppendSeparator() + perspectives_menu.AppendMenu(wx.ID_ANY, "Docking Guides", guides_menu) + + action_menu = wx.Menu() + action_menu.AppendCheckItem(ID_VetoTree, "Veto Floating Of Tree Pane") + action_menu.AppendCheckItem(ID_VetoText, "Veto Docking Of Fixed Pane") + action_menu.AppendSeparator() + + attention_menu = wx.Menu() + + self._requestPanes = {} + for indx, pane in enumerate(self._mgr.GetAllPanes()): + if pane.IsToolbar(): + continue + if not pane.caption or not pane.name: + continue + ids = wx.ID_HIGHEST + 12345 + indx + self._requestPanes[ids] = pane.name + attention_menu.Append(ids, pane.caption) + + action_menu.AppendMenu(wx.ID_ANY, "Request User Attention For", attention_menu) + + help_menu = wx.Menu() + help_menu.Append(wx.ID_ABOUT, "About...") + + mb.Append(file_menu, "&File") + mb.Append(view_menu, "&View") + mb.Append(perspectives_menu, "&Perspectives") + mb.Append(options_menu, "&Options") + mb.Append(notebook_menu, "&Notebook") + mb.Append(action_menu, "&Actions") + mb.Append(help_menu, "&Help") + + self.SetMenuBar(mb) + + + def BuildPanes(self): + + # min size for the frame itself isn't completely done. + # see the end up AuiManager.Update() for the test + # code. For now, just hard code a frame minimum size + self.SetMinSize(wx.Size(400, 300)) + + # prepare a few custom overflow elements for the toolbars' overflow buttons + + prepend_items, append_items = [], [] + item = aui.AuiToolBarItem() + + item.SetKind(wx.ITEM_SEPARATOR) + append_items.append(item) + + item = aui.AuiToolBarItem() + item.SetKind(wx.ITEM_NORMAL) + item.SetId(ID_CustomizeToolbar) + item.SetLabel("Customize...") + append_items.append(item) + + + # create some toolbars + tb1 = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + agwStyle=aui.AUI_TB_DEFAULT_STYLE | aui.AUI_TB_OVERFLOW) + tb1.SetToolBitmapSize(wx.Size(48, 48)) + tb1.AddSimpleTool(ID_SampleItem+1, "Test", wx.ArtProvider.GetBitmap(wx.ART_ERROR)) + tb1.AddSeparator() + tb1.AddSimpleTool(ID_SampleItem+2, "Test", wx.ArtProvider.GetBitmap(wx.ART_QUESTION)) + tb1.AddSimpleTool(ID_SampleItem+3, "Test", wx.ArtProvider.GetBitmap(wx.ART_INFORMATION)) + tb1.AddSimpleTool(ID_SampleItem+4, "Test", wx.ArtProvider.GetBitmap(wx.ART_WARNING)) + tb1.AddSimpleTool(ID_SampleItem+5, "Test", wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE)) + tb1.SetCustomOverflowItems(prepend_items, append_items) + tb1.Realize() + + tb2 = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + agwStyle=aui.AUI_TB_DEFAULT_STYLE | aui.AUI_TB_OVERFLOW) + tb2.SetToolBitmapSize(wx.Size(16, 16)) + + tb2_bmp1 = wx.ArtProvider.GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, wx.Size(16, 16)) + tb2.AddSimpleTool(ID_SampleItem+6, "Test", tb2_bmp1) + tb2.AddSimpleTool(ID_SampleItem+7, "Test", tb2_bmp1) + tb2.AddSimpleTool(ID_SampleItem+8, "Test", tb2_bmp1) + tb2.AddSimpleTool(ID_SampleItem+9, "Test", tb2_bmp1) + tb2.AddSeparator() + tb2.AddSimpleTool(ID_SampleItem+10, "Test", tb2_bmp1) + tb2.AddSimpleTool(ID_SampleItem+11, "Test", tb2_bmp1) + tb2.AddSeparator() + tb2.AddSimpleTool(ID_SampleItem+12, "Test", tb2_bmp1) + tb2.AddSimpleTool(ID_SampleItem+13, "Test", tb2_bmp1) + tb2.AddSimpleTool(ID_SampleItem+14, "Test", tb2_bmp1) + tb2.AddSimpleTool(ID_SampleItem+15, "Test", tb2_bmp1) + tb2.SetCustomOverflowItems(prepend_items, append_items) + tb2.Realize() + + tb3 = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + agwStyle=aui.AUI_TB_DEFAULT_STYLE | aui.AUI_TB_OVERFLOW) + tb3.SetToolBitmapSize(wx.Size(16, 16)) + tb3_bmp1 = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, wx.Size(16, 16)) + tb3.AddSimpleTool(ID_SampleItem+16, "Check 1", tb3_bmp1, "Check 1", aui.ITEM_CHECK) + tb3.AddSimpleTool(ID_SampleItem+17, "Check 2", tb3_bmp1, "Check 2", aui.ITEM_CHECK) + tb3.AddSimpleTool(ID_SampleItem+18, "Check 3", tb3_bmp1, "Check 3", aui.ITEM_CHECK) + tb3.AddSimpleTool(ID_SampleItem+19, "Check 4", tb3_bmp1, "Check 4", aui.ITEM_CHECK) + tb3.AddSeparator() + tb3.AddSimpleTool(ID_SampleItem+20, "Radio 1", tb3_bmp1, "Radio 1", aui.ITEM_RADIO) + tb3.AddSimpleTool(ID_SampleItem+21, "Radio 2", tb3_bmp1, "Radio 2", aui.ITEM_RADIO) + tb3.AddSimpleTool(ID_SampleItem+22, "Radio 3", tb3_bmp1, "Radio 3", aui.ITEM_RADIO) + tb3.AddSeparator() + tb3.AddSimpleTool(ID_SampleItem+23, "Radio 1 (Group 2)", tb3_bmp1, "Radio 1 (Group 2)", aui.ITEM_RADIO) + tb3.AddSimpleTool(ID_SampleItem+24, "Radio 2 (Group 2)", tb3_bmp1, "Radio 2 (Group 2)", aui.ITEM_RADIO) + tb3.AddSimpleTool(ID_SampleItem+25, "Radio 3 (Group 2)", tb3_bmp1, "Radio 3 (Group 2)", aui.ITEM_RADIO) + + tb3.SetCustomOverflowItems(prepend_items, append_items) + tb3.Realize() + + tb4 = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + agwStyle=aui.AUI_TB_OVERFLOW | aui.AUI_TB_TEXT | aui.AUI_TB_HORZ_TEXT) + tb4.SetToolBitmapSize(wx.Size(16, 16)) + tb4_bmp1 = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16)) + tb4.AddSimpleTool(ID_DropDownToolbarItem, "Item 1", tb4_bmp1) + tb4.AddSimpleTool(ID_SampleItem+23, "Item 2", tb4_bmp1) + tb4.AddSimpleTool(ID_SampleItem+24, "Item 3", tb4_bmp1) + tb4.AddSimpleTool(ID_SampleItem+25, "Item 4", tb4_bmp1) + tb4.AddSeparator() + tb4.AddSimpleTool(ID_SampleItem+26, "Item 5", tb4_bmp1) + tb4.AddSimpleTool(ID_SampleItem+27, "Item 6", tb4_bmp1) + tb4.AddSimpleTool(ID_SampleItem+28, "Item 7", tb4_bmp1) + tb4.AddSimpleTool(ID_SampleItem+29, "Item 8", tb4_bmp1) + + choice = wx.Choice(tb4, -1, choices=["One choice", "Another choice"]) + tb4.AddControl(choice) + + tb4.SetToolDropDown(ID_DropDownToolbarItem, True) + tb4.Realize() + + tb5 = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + agwStyle=aui.AUI_TB_OVERFLOW | aui.AUI_TB_VERTICAL) + + tb5.SetToolBitmapSize(wx.Size(48, 48)) + tb5.AddSimpleTool(ID_SampleItem+30, "Test", wx.ArtProvider.GetBitmap(wx.ART_ERROR)) + tb5.AddSeparator() + tb5.AddSimpleTool(ID_SampleItem+31, "Test", wx.ArtProvider.GetBitmap(wx.ART_QUESTION)) + tb5.AddSimpleTool(ID_SampleItem+32, "Test", wx.ArtProvider.GetBitmap(wx.ART_INFORMATION)) + tb5.AddSimpleTool(ID_SampleItem+33, "Test", wx.ArtProvider.GetBitmap(wx.ART_WARNING)) + tb5.AddSimpleTool(ID_SampleItem+34, "Test", wx.ArtProvider.GetBitmap(wx.ART_MISSING_IMAGE)) + tb5.SetCustomOverflowItems(prepend_items, append_items) + tb5.Realize() + + tb6 = aui.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, + agwStyle=aui.AUI_TB_OVERFLOW | aui.AUI_TB_VERT_TEXT) + tb6.SetToolBitmapSize(wx.Size(48, 48)) + tb6.AddSimpleTool(ID_SampleItem+35, "Clockwise 1", wx.ArtProvider.GetBitmap(wx.ART_ERROR, wx.ART_OTHER, wx.Size(16, 16))) + tb6.AddSeparator() + tb6.AddSimpleTool(ID_SampleItem+36, "Clockwise 2", wx.ArtProvider.GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, wx.Size(16, 16))) + tb6.AddSimpleTool(ID_DropDownToolbarItem, "Clockwise 3", wx.ArtProvider.GetBitmap(wx.ART_WARNING, wx.ART_OTHER, wx.Size(16, 16))) + tb6.SetCustomOverflowItems(prepend_items, append_items) + tb6.SetToolDropDown(ID_DropDownToolbarItem, True) + tb6.Realize() + + # add a bunch of panes + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo(). + Name("test1").Caption("Pane Caption").Top().MinimizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo(). + Name("test2").Caption("Client Size Reporter"). + Bottom().Position(1).CloseButton(True).MaximizeButton(True). + MinimizeButton(True).CaptionVisible(True, left=True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo(). + Name("test3").Caption("Client Size Reporter"). + Bottom().CloseButton(True).MaximizeButton(True).MinimizeButton(True). + CaptionVisible(True, left=True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo(). + Name("test4").Caption("Pane Caption").Left()) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo(). + Name("test5").Caption("No Close Button").Right().CloseButton(False)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo(). + Name("test6").Caption("Client Size Reporter").Right().Row(1). + CloseButton(True).MaximizeButton(True).MinimizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo(). + Name("test7").Caption("Client Size Reporter").Left().Layer(1). + CloseButton(True).MaximizeButton(True).MinimizeButton(True)) + + self._mgr.AddPane(self.CreateTreeCtrl(), aui.AuiPaneInfo().Name("test8").Caption("Tree Pane"). + Left().Layer(1).Position(1).CloseButton(True).MaximizeButton(True). + MinimizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo(). + Name("test9").Caption("Min Size 200x100"). + BestSize(wx.Size(200,100)).MinSize(wx.Size(200,100)).Bottom().Layer(1). + CloseButton(True).MaximizeButton(True).MinimizeButton(True)) + + self._mgr.AddPane(self.CreateTreeCtrl(), aui.AuiPaneInfo(). + Name("autonotebook").Caption("Auto NB"). + Bottom().Layer(1).Position(1).MinimizeButton(True)) + + wnd10 = self.CreateTextCtrl("This pane will prompt the user before hiding.") + self._mgr.AddPane(wnd10, aui.AuiPaneInfo(). + Name("test10").Caption("Text Pane with Hide Prompt"). + Bottom().MinimizeButton(True), target=self._mgr.GetPane("autonotebook")) + + self._mgr.AddPane(self.CreateTreeCtrl(), aui.AuiPaneInfo(). + Name("thirdauto").Caption("A Third Auto-NB Pane"). + Bottom().MinimizeButton(True), target=self._mgr.GetPane("autonotebook")) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo(). + Name("test11").Caption("Fixed Pane"). + Bottom().Layer(1).Position(2).Fixed().MinimizeButton(True)) + + self._mgr.AddPane(SettingsPanel(self,self), aui.AuiPaneInfo(). + Name("settings").Caption("Dock Manager Settings"). + Dockable(False).Float().Hide().MinimizeButton(True)) + + # create some center panes + + self._mgr.AddPane(self.CreateGrid(), aui.AuiPaneInfo().Name("grid_content"). + CenterPane().Hide().MinimizeButton(True)) + + self._mgr.AddPane(self.CreateTreeCtrl(), aui.AuiPaneInfo().Name("tree_content"). + CenterPane().Hide().MinimizeButton(True)) + + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo().Name("sizereport_content"). + CenterPane().Hide().MinimizeButton(True)) + + self._mgr.AddPane(self.CreateTextCtrl(), aui.AuiPaneInfo().Name("text_content"). + CenterPane().Hide().MinimizeButton(True)) + + self._mgr.AddPane(self.CreateHTMLCtrl(), aui.AuiPaneInfo().Name("html_content"). + CenterPane().Hide().MinimizeButton(True)) + + self._mgr.AddPane(self.CreateNotebook(), aui.AuiPaneInfo().Name("notebook_content"). + CenterPane().PaneBorder(False)) + + # add the toolbars to the manager + self._mgr.AddPane(tb1, aui.AuiPaneInfo().Name("tb1").Caption("Big Toolbar"). + ToolbarPane().Top()) + + self._mgr.AddPane(tb2, aui.AuiPaneInfo().Name("tb2").Caption("Toolbar 2"). + ToolbarPane().Top().Row(1)) + + self._mgr.AddPane(tb3, aui.AuiPaneInfo().Name("tb3").Caption("Toolbar 3"). + ToolbarPane().Top().Row(1).Position(1)) + + self._mgr.AddPane(tb4, aui.AuiPaneInfo().Name("tb4").Caption("Sample Bookmark Toolbar"). + ToolbarPane().Top().Row(2)) + + self._mgr.AddPane(tb5, aui.AuiPaneInfo().Name("tb5").Caption("Sample Vertical Toolbar"). + ToolbarPane().Left().GripperTop()) + + self._mgr.AddPane(tb6, aui.AuiPaneInfo(). + Name("tb6").Caption("Sample Vertical Clockwise Rotated Toolbar"). + ToolbarPane().Right().GripperTop().TopDockable(False).BottomDockable(False)); + + self._mgr.AddPane(wx.Button(self, -1, "Test Button"), + aui.AuiPaneInfo().Name("tb7").ToolbarPane().Top().Row(2).Position(1)) + + # Show how to add a control inside a tab + notebook = self._mgr.GetPane("notebook_content").window + self.gauge = ProgressGauge(notebook, size=(55, 15)) + notebook.AddControlToPage(4, self.gauge) + + self._main_notebook = notebook + + # make some default perspectives + perspective_all = self._mgr.SavePerspective() + + all_panes = self._mgr.GetAllPanes() + for pane in all_panes: + if not pane.IsToolbar(): + pane.Hide() + + self._mgr.GetPane("tb1").Hide() + self._mgr.GetPane("tb7").Hide() + + self._mgr.GetPane("test8").Show().Left().Layer(0).Row(0).Position(0) + self._mgr.GetPane("__notebook_%d"%self._mgr.GetPane("test10").notebook_id).Show().Bottom().Layer(0).Row(0).Position(0) + self._mgr.GetPane("autonotebook").Show() + self._mgr.GetPane("thirdauto").Show() + self._mgr.GetPane("test10").Show() + self._mgr.GetPane("notebook_content").Show() + + perspective_default = self._mgr.SavePerspective() + + self._perspectives = [] + self._perspectives.append(perspective_default) + self._perspectives.append(perspective_all) + + self._nb_perspectives = [] + auibook = self._mgr.GetPane("notebook_content").window + nb_perspective_default = auibook.SavePerspective() + self._nb_perspectives.append(nb_perspective_default) + + self._mgr.LoadPerspective(perspective_default) + + # Show how to get a custom minimizing behaviour, i.e., to minimize a pane + # inside an existing AuiToolBar + tree = self._mgr.GetPane("test8") + tree.MinimizeMode(aui.AUI_MINIMIZE_POS_TOOLBAR) + toolbarPane = self._mgr.GetPane(tb4) + tree.MinimizeTarget(toolbarPane) + + # "commit" all changes made to AuiManager + self._mgr.Update() + + + def BindEvents(self): + + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_MENU, self.OnCreateTree, id=ID_CreateTree) + self.Bind(wx.EVT_MENU, self.OnCreateGrid, id=ID_CreateGrid) + self.Bind(wx.EVT_MENU, self.OnCreateText, id=ID_CreateText) + self.Bind(wx.EVT_MENU, self.OnCreateHTML, id=ID_CreateHTML) + self.Bind(wx.EVT_MENU, self.OnCreateSizeReport, id=ID_CreateSizeReport) + self.Bind(wx.EVT_MENU, self.OnCreateNotebook, id=ID_CreateNotebook) +## self.Bind(wx.EVT_MENU, self.OnSwitchPane, id=ID_SwitchPane) + self.Bind(wx.EVT_MENU, self.OnCreatePerspective, id=ID_CreatePerspective) + self.Bind(wx.EVT_MENU, self.OnCopyPerspectiveCode, id=ID_CopyPerspectiveCode) + self.Bind(wx.EVT_MENU, self.OnCreateNBPerspective, id=ID_CreateNBPerspective) + self.Bind(wx.EVT_MENU, self.OnCopyNBPerspectiveCode, id=ID_CopyNBPerspectiveCode) + self.Bind(wx.EVT_MENU, self.OnGuides, id=ID_StandardGuides) + self.Bind(wx.EVT_MENU, self.OnGuides, id=ID_AeroGuides) + self.Bind(wx.EVT_MENU, self.OnGuides, id=ID_WhidbeyGuides) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_AllowFloating) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_TransparentHint) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_VenetianBlindsHint) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_RectangleHint) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_NoHint) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_HintFade) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_NoVenetianFade) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_TransparentDrag) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_LiveUpdate) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_SmoothDocking) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_NativeMiniframes) + self.Bind(wx.EVT_MENU, self.OnMinimizePosition, id=ID_MinimizePosSmart) + self.Bind(wx.EVT_MENU, self.OnMinimizePosition, id=ID_MinimizePosTop) + self.Bind(wx.EVT_MENU, self.OnMinimizePosition, id=ID_MinimizePosLeft) + self.Bind(wx.EVT_MENU, self.OnMinimizePosition, id=ID_MinimizePosRight) + self.Bind(wx.EVT_MENU, self.OnMinimizePosition, id=ID_MinimizePosBottom) + self.Bind(wx.EVT_MENU, self.OnMinimizeCaption, id=ID_MinimizeCaptSmart) + self.Bind(wx.EVT_MENU, self.OnMinimizeCaption, id=ID_MinimizeCaptHorz) + self.Bind(wx.EVT_MENU, self.OnMinimizeCaption, id=ID_MinimizeCaptHide) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_AnimateFrames) + self.Bind(wx.EVT_MENU, self.OnSetIconsOnPanes, id=ID_PaneIcons) + self.Bind(wx.EVT_MENU, self.OnTransparentPane, id=ID_TransparentPane) + self.Bind(wx.EVT_MENU, self.OnDockArt, id=ID_DefaultDockArt) + self.Bind(wx.EVT_MENU, self.OnDockArt, id=ID_ModernDockArt) + self.Bind(wx.EVT_MENU, self.OnSnapToScreen, id=ID_SnapToScreen) + self.Bind(wx.EVT_MENU, self.OnSnapPanes, id=ID_SnapPanes) + self.Bind(wx.EVT_MENU, self.OnFlyOut, id=ID_FlyOut) + self.Bind(wx.EVT_MENU, self.OnCustomPaneButtons, id=ID_CustomPaneButtons) + self.Bind(wx.EVT_MENU, self.OnManagerFlag, id=ID_AllowActivePane) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookTabFixedWidth) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookNoCloseButton) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookCloseButton) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookCloseButtonAll) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookCloseButtonActive) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookAllowTabMove) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookAllowTabExternalMove) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookAllowTabSplit) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookTabFloat) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookDclickUnsplit) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookTabDrawDnd) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookScrollButtons) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookWindowList) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookArtGloss) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookArtSimple) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookArtVC71) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookArtFF2) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookArtVC8) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookArtChrome) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookHideSingle) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookSmartTab) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookUseImagesDropDown) + self.Bind(wx.EVT_MENU, self.OnNotebookFlag, id=ID_NotebookCloseOnLeft) + self.Bind(wx.EVT_MENU, self.OnTabAlignment, id=ID_NotebookAlignTop) + self.Bind(wx.EVT_MENU, self.OnTabAlignment, id=ID_NotebookAlignBottom) + self.Bind(wx.EVT_MENU, self.OnCustomTabButtons, id=ID_NotebookCustomButtons) + self.Bind(wx.EVT_MENU, self.OnMinMaxTabWidth, id=ID_NotebookMinMaxWidth) + self.Bind(wx.EVT_MENU, self.OnPreview, id=ID_NotebookPreview) + self.Bind(wx.EVT_MENU, self.OnAddMultiLine, id=ID_NotebookMultiLine) + + self.Bind(wx.EVT_MENU, self.OnGradient, id=ID_NoGradient) + self.Bind(wx.EVT_MENU, self.OnGradient, id=ID_VerticalGradient) + self.Bind(wx.EVT_MENU, self.OnGradient, id=ID_HorizontalGradient) + self.Bind(wx.EVT_MENU, self.OnSettings, id=ID_Settings) + self.Bind(wx.EVT_MENU, self.OnPreviewMinimized, id=ID_PreviewMinimized) + self.Bind(wx.EVT_MENU, self.OnCustomizeToolbar, id=ID_CustomizeToolbar) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_GridContent) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_TreeContent) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_TextContent) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_SizeReportContent) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_HTMLContent) + self.Bind(wx.EVT_MENU, self.OnChangeContentPane, id=ID_NotebookContent) + self.Bind(wx.EVT_MENU, self.OnVetoTree, id=ID_VetoTree) + self.Bind(wx.EVT_MENU, self.OnVetoText, id=ID_VetoText) + + for ids in self._requestPanes: + self.Bind(wx.EVT_MENU, self.OnRequestUserAttention, id=ids) + + self.Bind(wx.EVT_MENU, self.OnExit, id=wx.ID_EXIT) + self.Bind(wx.EVT_MENU, self.OnAbout, id=wx.ID_ABOUT) + + self.Bind(wx.EVT_MENU_RANGE, self.OnRestorePerspective, id=ID_FirstPerspective, + id2=ID_FirstPerspective+1000) + self.Bind(wx.EVT_MENU_RANGE, self.OnRestoreNBPerspective, id=ID_FirstNBPerspective, + id2=ID_FirstNBPerspective+1000) + + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_AllowFloating) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_TransparentHint) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_HintFade) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_TransparentDrag) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NoGradient) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_VerticalGradient) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_HorizontalGradient) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_VenetianBlindsHint) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_RectangleHint) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NoHint) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NoVenetianFade) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_LiveUpdate) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_PaneIcons) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_AnimateFrames) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_DefaultDockArt) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_ModernDockArt) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_SnapPanes) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_FlyOut) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_CustomPaneButtons) + + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookTabFixedWidth) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookNoCloseButton) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookCloseButton) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookCloseButtonAll) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookCloseButtonActive) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookAllowTabMove) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookAllowTabExternalMove) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookAllowTabSplit) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookTabFloat) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookDclickUnsplit) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookTabDrawDnd) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookScrollButtons) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookWindowList) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookHideSingle) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookSmartTab) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookUseImagesDropDown) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_NotebookCustomButtons) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_VetoTree) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_VetoText) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_StandardGuides) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_AeroGuides) + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ID_WhidbeyGuides) + + for ids in self._requestPanes: + self.Bind(wx.EVT_UPDATE_UI, self.OnUpdateUI, id=ids) + + self.Bind(aui.EVT_AUITOOLBAR_TOOL_DROPDOWN, self.OnDropDownToolbarItem, id=ID_DropDownToolbarItem) + self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPaneClose) + self.Bind(aui.EVT_AUINOTEBOOK_ALLOW_DND, self.OnAllowNotebookDnD) + self.Bind(aui.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnNotebookPageClose) + + self.Bind(aui.EVT_AUI_PANE_FLOATING, self.OnFloatDock) + self.Bind(aui.EVT_AUI_PANE_FLOATED, self.OnFloatDock) + self.Bind(aui.EVT_AUI_PANE_DOCKING, self.OnFloatDock) + self.Bind(aui.EVT_AUI_PANE_DOCKED, self.OnFloatDock) + + self.Bind(wx.EVT_CLOSE, self.OnClose) + + self.Bind(wx.EVT_TIMER, self.TimerHandler) + self.timer = wx.Timer(self) + self.timer.Start(100) + + + def __del__(self): + + self.timer.Stop() + + + def OnClose(self, event): + + self.timer.Stop() + self._mgr.UnInit() + event.Skip() + + + def TimerHandler(self, event): + + try: + self.gauge.Pulse() + except wx.PyDeadObjectError: + self.timer.Stop() + + + def GetDockArt(self): + + return self._mgr.GetArtProvider() + + + def DoUpdate(self): + + self._mgr.Update() + self.Refresh() + + + def OnEraseBackground(self, event): + + event.Skip() + + + def OnSize(self, event): + + event.Skip() + + + def OnSettings(self, event): + + # show the settings pane, and float it + floating_pane = self._mgr.GetPane("settings").Float().Show() + + if floating_pane.floating_pos == wx.DefaultPosition: + floating_pane.FloatingPosition(self.GetStartPosition()) + + self._mgr.Update() + + + def OnPreviewMinimized(self, event): + + checked = event.IsChecked() + agwFlags = self._mgr.GetAGWFlags() + + if event.IsChecked(): + agwFlags ^= aui.AUI_MGR_PREVIEW_MINIMIZED_PANES + else: + agwFlags &= ~aui.AUI_MGR_PREVIEW_MINIMIZED_PANES + + self._mgr.SetAGWFlags(agwFlags) + + + def OnSetIconsOnPanes(self, event): + + panes = self._mgr.GetAllPanes() + checked = event.IsChecked() + self._pane_icons = checked + + for pane in panes: + if checked: + randimage = random.randint(0, len(ArtIDs) - 1) + bmp = wx.ArtProvider_GetBitmap(eval(ArtIDs[randimage]), wx.ART_OTHER, (16, 16)) + else: + bmp = None + + pane.Icon(bmp) + + self._mgr.Update() + + + def OnTransparentPane(self, event): + + dlg = wx.TextEntryDialog(self, "Enter a transparency value (0-255):", "Pane transparency") + + dlg.SetValue("%d"%self._transparency) + if dlg.ShowModal() != wx.ID_OK: + return + + transparency = int(dlg.GetValue()) + dlg.Destroy() + try: + transparency = int(transparency) + except: + dlg = wx.MessageDialog(self, 'Invalid transparency value. Transparency' \ + ' should be an integer between 0 and 255.', + 'Error', + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + + if transparency < 0 or transparency > 255: + dlg = wx.MessageDialog(self, 'Invalid transparency value. Transparency' \ + ' should be an integer between 0 and 255.', + 'Error', + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + + self._transparency = transparency + panes = self._mgr.GetAllPanes() + for pane in panes: + pane.Transparent(self._transparency) + + self._mgr.Update() + + + def OnDockArt(self, event): + + if event.GetId() == ID_DefaultDockArt: + self._mgr.SetArtProvider(aui.AuiDefaultDockArt()) + else: + if self._mgr.CanUseModernDockArt(): + self._mgr.SetArtProvider(aui.ModernDockArt(self)) + + self._mgr.Update() + self.Refresh() + + + def OnSnapToScreen(self, event): + + self._mgr.SnapToScreen(True, monitor=0, hAlign=wx.RIGHT, vAlign=wx.TOP) + + + def OnSnapPanes(self, event): + + allPanes = self._mgr.GetAllPanes() + + if not self._snapped: + self._captions = {} + for pane in allPanes: + self._captions[pane.name] = pane.caption + + toSnap = not self._snapped + + if toSnap: + for pane in allPanes: + if pane.IsToolbar() or isinstance(pane.window, aui.AuiNotebook): + continue + + snap = random.randint(0, 4) + if snap == 0: + # Snap everywhere + pane.Caption(pane.caption + " (Snap Everywhere)") + pane.Snappable(True) + elif snap == 1: + # Snap left + pane.Caption(pane.caption + " (Snap Left)") + pane.LeftSnappable(True) + elif snap == 2: + # Snap right + pane.Caption(pane.caption + " (Snap Right)") + pane.RightSnappable(True) + elif snap == 3: + # Snap top + pane.Caption(pane.caption + " (Snap Top)") + pane.TopSnappable(True) + elif snap == 4: + # Snap bottom + pane.Caption(pane.caption + " (Snap Bottom)") + pane.BottomSnappable(True) + + else: + + for pane in allPanes: + if pane.IsToolbar() or isinstance(pane.window, aui.AuiNotebook): + continue + + pane.Caption(self._captions[pane.name]) + pane.Snappable(False) + + self._snapped = toSnap + self._mgr.Update() + self.Refresh() + + + def OnFlyOut(self, event): + + checked = event.IsChecked() + pane = self._mgr.GetPane("test8") + + if checked: + dlg = wx.MessageDialog(self, 'The tree pane will have fly-out' \ + ' behaviour when floating.', + 'Message', + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + pane.FlyOut(True) + else: + pane.FlyOut(False) + + self._mgr.Update() + + + def OnCustomPaneButtons(self, event): + + self._custom_pane_buttons = checked = event.IsChecked() + art = self._mgr.GetArtProvider() + + if not checked: + art.SetDefaultPaneBitmaps(wx.Platform == "__WXMAC__") + else: + for bmp, button, active, maximize in CUSTOM_PANE_BITMAPS: + art.SetCustomPaneBitmap(bmp.GetBitmap(), button, active, maximize) + + self._mgr.Update() + self.Refresh() + + + def OnCustomizeToolbar(self, event): + + wx.MessageBox("Customize Toolbar clicked", "AUI Test") + + + def OnGradient(self, event): + + evId = event.GetId() + if evId == ID_NoGradient: + gradient = aui.AUI_GRADIENT_NONE + elif evId == ID_VerticalGradient: + gradient = aui.AUI_GRADIENT_VERTICAL + elif evId == ID_HorizontalGradient: + gradient = aui.AUI_GRADIENT_HORIZONTAL + + self._mgr.GetArtProvider().SetMetric(aui.AUI_DOCKART_GRADIENT_TYPE, gradient) + self._mgr.Update() + + + def OnManagerFlag(self, event): + + flag = 0 + evId = event.GetId() + + if evId in [ID_TransparentHint, ID_VenetianBlindsHint, ID_RectangleHint, ID_NoHint]: + + agwFlags = self._mgr.GetAGWFlags() + agwFlags &= ~aui.AUI_MGR_TRANSPARENT_HINT + agwFlags &= ~aui.AUI_MGR_VENETIAN_BLINDS_HINT + agwFlags &= ~aui.AUI_MGR_RECTANGLE_HINT + self._mgr.SetAGWFlags(agwFlags) + + if evId == ID_AllowFloating: + flag = aui.AUI_MGR_ALLOW_FLOATING + elif evId == ID_TransparentDrag: + flag = aui.AUI_MGR_TRANSPARENT_DRAG + elif evId == ID_HintFade: + flag = aui.AUI_MGR_HINT_FADE + elif evId == ID_NoVenetianFade: + flag = aui.AUI_MGR_NO_VENETIAN_BLINDS_FADE + elif evId == ID_AllowActivePane: + flag = aui.AUI_MGR_ALLOW_ACTIVE_PANE + elif evId == ID_TransparentHint: + flag = aui.AUI_MGR_TRANSPARENT_HINT + elif evId == ID_VenetianBlindsHint: + flag = aui.AUI_MGR_VENETIAN_BLINDS_HINT + elif evId == ID_RectangleHint: + flag = aui.AUI_MGR_RECTANGLE_HINT + elif evId == ID_LiveUpdate: + flag = aui.AUI_MGR_LIVE_RESIZE + elif evId == ID_AnimateFrames: + flag = aui.AUI_MGR_ANIMATE_FRAMES + elif evId == ID_SmoothDocking: + flag = aui.AUI_MGR_SMOOTH_DOCKING + elif evId == ID_NativeMiniframes: + flag = aui.AUI_MGR_USE_NATIVE_MINIFRAMES + + if flag: + self._mgr.SetAGWFlags(self._mgr.GetAGWFlags() ^ flag) + + self._mgr.Update() + + + def OnMinimizePosition(self, event): + + minize_mode = 0 + evId = event.GetId() + + if evId == ID_MinimizePosSmart: + minize_mode |= aui.AUI_MINIMIZE_POS_SMART + elif evId == ID_MinimizePosTop: + minize_mode |= aui.AUI_MINIMIZE_POS_TOP + elif evId == ID_MinimizePosLeft: + minize_mode |= aui.AUI_MINIMIZE_POS_LEFT + elif evId == ID_MinimizePosRight: + minize_mode |= aui.AUI_MINIMIZE_POS_RIGHT + elif evId == ID_MinimizePosBottom: + minize_mode |= aui.AUI_MINIMIZE_POS_BOTTOM + + all_panes = self._mgr.GetAllPanes() + for pane in all_panes: + if pane.name != "test8": + pane.MinimizeMode(minize_mode | (pane.GetMinimizeMode() & aui.AUI_MINIMIZE_CAPT_MASK)) + + + def OnMinimizeCaption(self, event): + + minize_mode = 0 + evId = event.GetId() + + if evId == ID_MinimizeCaptSmart: + minize_mode |= aui.AUI_MINIMIZE_CAPT_SMART + elif evId == ID_MinimizeCaptHorz: + minize_mode |= aui.AUI_MINIMIZE_CAPT_HORZ + elif evId == ID_MinimizeCaptHide: + minize_mode |= aui.AUI_MINIMIZE_CAPT_HIDE + + all_panes = self._mgr.GetAllPanes() + for pane in all_panes: + pane.MinimizeMode(minize_mode | (pane.GetMinimizeMode() & aui.AUI_MINIMIZE_POS_MASK)) + + + def OnNotebookFlag(self, event): + + evId = event.GetId() + unsplit = None + + if evId in [ID_NotebookNoCloseButton, ID_NotebookCloseButton, ID_NotebookCloseButtonAll, \ + ID_NotebookCloseButtonActive]: + + self._notebook_style &= ~(aui.AUI_NB_CLOSE_BUTTON | + aui.AUI_NB_CLOSE_ON_ACTIVE_TAB | + aui.AUI_NB_CLOSE_ON_ALL_TABS) + + if evId == ID_NotebookCloseButton: + self._notebook_style ^= aui.AUI_NB_CLOSE_BUTTON + elif evId == ID_NotebookCloseButtonAll: + self._notebook_style ^= aui.AUI_NB_CLOSE_ON_ALL_TABS + elif evId == ID_NotebookCloseButtonActive: + self._notebook_style ^= aui.AUI_NB_CLOSE_ON_ACTIVE_TAB + + if evId == ID_NotebookAllowTabMove: + self._notebook_style ^= aui.AUI_NB_TAB_MOVE + + if evId == ID_NotebookAllowTabExternalMove: + self._notebook_style ^= aui.AUI_NB_TAB_EXTERNAL_MOVE + + elif evId == ID_NotebookAllowTabSplit: + self._notebook_style ^= aui.AUI_NB_TAB_SPLIT + + elif evId == ID_NotebookTabFloat: + self._notebook_style ^= aui.AUI_NB_TAB_FLOAT + + elif evId == ID_NotebookTabDrawDnd: + self._notebook_style ^= aui.AUI_NB_DRAW_DND_TAB + + elif evId == ID_NotebookWindowList: + self._notebook_style ^= aui.AUI_NB_WINDOWLIST_BUTTON + + elif evId == ID_NotebookScrollButtons: + self._notebook_style ^= aui.AUI_NB_SCROLL_BUTTONS + + elif evId == ID_NotebookTabFixedWidth: + self._notebook_style ^= aui.AUI_NB_TAB_FIXED_WIDTH + + elif evId == ID_NotebookHideSingle: + self._notebook_style ^= aui.AUI_NB_HIDE_ON_SINGLE_TAB + + elif evId == ID_NotebookSmartTab: + self._notebook_style ^= aui.AUI_NB_SMART_TABS + + elif evId == ID_NotebookUseImagesDropDown: + self._notebook_style ^= aui.AUI_NB_USE_IMAGES_DROPDOWN + + elif evId == ID_NotebookCloseOnLeft: + self._notebook_style ^= aui.AUI_NB_CLOSE_ON_TAB_LEFT + + all_panes = self._mgr.GetAllPanes() + + for pane in all_panes: + + if isinstance(pane.window, aui.AuiNotebook): + nb = pane.window + + if evId == ID_NotebookArtGloss: + + nb.SetArtProvider(aui.AuiDefaultTabArt()) + self._notebook_theme = 0 + + elif evId == ID_NotebookArtSimple: + nb.SetArtProvider(aui.AuiSimpleTabArt()) + self._notebook_theme = 1 + + elif evId == ID_NotebookArtVC71: + nb.SetArtProvider(aui.VC71TabArt()) + self._notebook_theme = 2 + + elif evId == ID_NotebookArtFF2: + nb.SetArtProvider(aui.FF2TabArt()) + self._notebook_theme = 3 + + elif evId == ID_NotebookArtVC8: + nb.SetArtProvider(aui.VC8TabArt()) + self._notebook_theme = 4 + + elif evId == ID_NotebookArtChrome: + nb.SetArtProvider(aui.ChromeTabArt()) + self._notebook_theme = 5 + + if nb.GetAGWWindowStyleFlag() & aui.AUI_NB_BOTTOM == 0: + nb.SetAGWWindowStyleFlag(self._notebook_style) + + if evId == ID_NotebookCloseButtonAll: + # Demonstrate how to remove a close button from a tab + nb.SetCloseButton(2, False) + elif evId == ID_NotebookDclickUnsplit: + nb.SetSashDClickUnsplit(event.IsChecked()) + + nb.Refresh() + nb.Update() + + + def OnUpdateUI(self, event): + + agwFlags = self._mgr.GetAGWFlags() + evId = event.GetId() + + if evId == ID_NoGradient: + event.Check(self._mgr.GetArtProvider().GetMetric(aui.AUI_DOCKART_GRADIENT_TYPE) == aui.AUI_GRADIENT_NONE) + + elif evId == ID_VerticalGradient: + event.Check(self._mgr.GetArtProvider().GetMetric(aui.AUI_DOCKART_GRADIENT_TYPE) == aui.AUI_GRADIENT_VERTICAL) + + elif evId == ID_HorizontalGradient: + event.Check(self._mgr.GetArtProvider().GetMetric(aui.AUI_DOCKART_GRADIENT_TYPE) == aui.AUI_GRADIENT_HORIZONTAL) + + elif evId == ID_AllowFloating: + event.Check((agwFlags & aui.AUI_MGR_ALLOW_FLOATING) != 0) + + elif evId == ID_TransparentDrag: + event.Check((agwFlags & aui.AUI_MGR_TRANSPARENT_DRAG) != 0) + + elif evId == ID_TransparentHint: + event.Check((agwFlags & aui.AUI_MGR_TRANSPARENT_HINT) != 0) + + elif evId == ID_LiveUpdate: + event.Check(aui.AuiManager_HasLiveResize(self._mgr)) + + elif evId == ID_VenetianBlindsHint: + event.Check((agwFlags & aui.AUI_MGR_VENETIAN_BLINDS_HINT) != 0) + + elif evId == ID_RectangleHint: + event.Check((agwFlags & aui.AUI_MGR_RECTANGLE_HINT) != 0) + + elif evId == ID_NoHint: + event.Check(((aui.AUI_MGR_TRANSPARENT_HINT | + aui.AUI_MGR_VENETIAN_BLINDS_HINT | + aui.AUI_MGR_RECTANGLE_HINT) & agwFlags) == 0) + + elif evId == ID_HintFade: + event.Check((agwFlags & aui.AUI_MGR_HINT_FADE) != 0) + + elif evId == ID_NoVenetianFade: + event.Check((agwFlags & aui.AUI_MGR_NO_VENETIAN_BLINDS_FADE) != 0) + + elif evId == ID_NativeMiniframes: + event.Check(aui.AuiManager_UseNativeMiniframes(self._mgr)) + + elif evId == ID_PaneIcons: + event.Check(self._pane_icons) + + elif evId == ID_SmoothDocking: + event.Check((agwFlags & aui.AUI_MGR_SMOOTH_DOCKING) != 0) + + elif evId == ID_AnimateFrames: + event.Check((agwFlags & aui.AUI_MGR_ANIMATE_FRAMES) != 0) + + elif evId == ID_DefaultDockArt: + event.Check(isinstance(self._mgr.GetArtProvider(), aui.AuiDefaultDockArt)) + + elif evId == ID_ModernDockArt: + event.Check(isinstance(self._mgr.GetArtProvider(), aui.ModernDockArt)) + + elif evId == ID_SnapPanes: + event.Check(self._snapped) + + elif evId == ID_FlyOut: + pane = self._mgr.GetPane("test8") + event.Check(pane.IsFlyOut()) + + elif evId == ID_AeroGuides: + event.Check(agwFlags & aui.AUI_MGR_AERO_DOCKING_GUIDES != 0) + + elif evId == ID_WhidbeyGuides: + event.Check(agwFlags & aui.AUI_MGR_WHIDBEY_DOCKING_GUIDES != 0) + + elif evId == ID_StandardGuides: + event.Check((agwFlags & aui.AUI_MGR_AERO_DOCKING_GUIDES == 0) and (agwFlags & aui.AUI_MGR_WHIDBEY_DOCKING_GUIDES == 0)) + + elif evId == ID_CustomPaneButtons: + event.Check(self._custom_pane_buttons) + + elif evId == ID_PreviewMinimized: + event.Check(agwFlags & aui.AUI_MGR_PREVIEW_MINIMIZED_PANES) + + elif evId == ID_NotebookNoCloseButton: + event.Check((self._notebook_style & (aui.AUI_NB_CLOSE_BUTTON|aui.AUI_NB_CLOSE_ON_ALL_TABS|aui.AUI_NB_CLOSE_ON_ACTIVE_TAB)) != 0) + + elif evId == ID_NotebookCloseButton: + event.Check((self._notebook_style & aui.AUI_NB_CLOSE_BUTTON) != 0) + + elif evId == ID_NotebookCloseButtonAll: + event.Check((self._notebook_style & aui.AUI_NB_CLOSE_ON_ALL_TABS) != 0) + + elif evId == ID_NotebookCloseButtonActive: + event.Check((self._notebook_style & aui.AUI_NB_CLOSE_ON_ACTIVE_TAB) != 0) + + elif evId == ID_NotebookAllowTabSplit: + event.Check((self._notebook_style & aui.AUI_NB_TAB_SPLIT) != 0) + + elif evId == ID_NotebookTabFloat: + event.Check((self._notebook_style & aui.AUI_NB_TAB_FLOAT) != 0) + + elif evId == ID_NotebookDclickUnsplit: + event.Check(self._main_notebook.GetSashDClickUnsplit()) + + elif evId == ID_NotebookTabDrawDnd: + event.Check((self._notebook_style & aui.AUI_NB_DRAW_DND_TAB) != 0) + + elif evId == ID_NotebookAllowTabMove: + event.Check((self._notebook_style & aui.AUI_NB_TAB_MOVE) != 0) + + elif evId == ID_NotebookAllowTabExternalMove: + event.Check((self._notebook_style & aui.AUI_NB_TAB_EXTERNAL_MOVE) != 0) + + elif evId == ID_NotebookScrollButtons: + event.Check((self._notebook_style & aui.AUI_NB_SCROLL_BUTTONS) != 0) + + elif evId == ID_NotebookWindowList: + event.Check((self._notebook_style & aui.AUI_NB_WINDOWLIST_BUTTON) != 0) + + elif evId == ID_NotebookTabFixedWidth: + event.Check((self._notebook_style & aui.AUI_NB_TAB_FIXED_WIDTH) != 0) + + elif evId == ID_NotebookHideSingle: + event.Check((self._notebook_style & aui.AUI_NB_HIDE_ON_SINGLE_TAB) != 0) + + elif evId == ID_NotebookSmartTab: + event.Check((self._notebook_style & aui.AUI_NB_SMART_TABS) != 0) + + elif evId == ID_NotebookUseImagesDropDown: + event.Check((self._notebook_style & aui.AUI_NB_USE_IMAGES_DROPDOWN) != 0) + + elif evId == ID_NotebookCloseOnLeft: + event.Check((self._notebook_style & aui.AUI_NB_CLOSE_ON_TAB_LEFT) != 0) + + elif evId == ID_NotebookCustomButtons: + event.Check(self._custom_tab_buttons) + + elif evId == ID_NotebookArtGloss: + event.Check(self._notebook_theme == 0) + + elif evId == ID_NotebookArtSimple: + event.Check(self._notebook_theme == 1) + + elif evId == ID_NotebookArtVC71: + event.Check(self._notebook_theme == 2) + + elif evId == ID_NotebookArtFF2: + event.Check(self._notebook_theme == 3) + + elif evId == ID_NotebookArtVC8: + event.Check(self._notebook_theme == 4) + + elif evId == ID_NotebookArtChrome: + event.Check(self._notebook_theme == 5) + + elif evId == ID_VetoTree: + event.Check(self._veto_tree) + + elif evId == ID_VetoText: + event.Check(self._veto_text) + + else: + for ids in self._requestPanes: + if evId == ids: + paneName = self._requestPanes[ids] + pane = self._mgr.GetPane(paneName) + event.Enable(pane.IsShown()) + + + def OnPaneClose(self, event): + + if event.pane.name == "test10": + + msg = "Are you sure you want to " + if event.GetEventType() == aui.wxEVT_AUI_PANE_MINIMIZE: + msg += "minimize " + else: + msg += "close/hide " + + res = wx.MessageBox(msg + "this pane?", "AUI", wx.YES_NO, self) + if res != wx.YES: + event.Veto() + + + def OnCreatePerspective(self, event): + + dlg = wx.TextEntryDialog(self, "Enter a name for the new perspective:", "AUI Test") + + dlg.SetValue("Perspective %u"%(len(self._perspectives) + 1)) + if dlg.ShowModal() != wx.ID_OK: + return + + if len(self._perspectives) == 0: + self._perspectives_menu.AppendSeparator() + + self._perspectives_menu.Append(ID_FirstPerspective + len(self._perspectives), dlg.GetValue()) + self._perspectives.append(self._mgr.SavePerspective()) + + + def OnCopyPerspectiveCode(self, event): + + s = self._mgr.SavePerspective() + + if wx.TheClipboard.Open(): + + wx.TheClipboard.SetData(wx.TextDataObject(s)) + wx.TheClipboard.Close() + + + def OnRestorePerspective(self, event): + + self._mgr.LoadPerspective(self._perspectives[event.GetId() - ID_FirstPerspective]) + + + def OnCreateNBPerspective(self, event): + + dlg = wx.TextEntryDialog(self, "Enter a name for the new perspective:", "AUI Test") + + dlg.SetValue("Perspective %u"%(len(self._nb_perspectives) + 1)) + if dlg.ShowModal() != wx.ID_OK: + return + + if len(self._nb_perspectives) == 0: + self._nb_perspectives_menu.AppendSeparator() + + auibook = self._mgr.GetPane("notebook_content").window + self._nb_perspectives_menu.Append(ID_FirstNBPerspective + len(self._nb_perspectives), dlg.GetValue()) + self._nb_perspectives.append(auibook.SavePerspective()) + + + def OnCopyNBPerspectiveCode(self, event): + + auibook = self._mgr.GetPane("notebook_content").window + s = auibook.SavePerspective() + + if wx.TheClipboard.Open(): + + wx.TheClipboard.SetData(wx.TextDataObject(s)) + wx.TheClipboard.Close() + + + def OnRestoreNBPerspective(self, event): + + auibook = self._mgr.GetPane("notebook_content").window + auibook.LoadPerspective(self._nb_perspectives[event.GetId() - ID_FirstNBPerspective]) + + self.gauge = ProgressGauge(auibook, size=(55, 15)) + auibook.AddControlToPage(4, self.gauge) + + + def OnGuides(self, event): + + useAero = event.GetId() == ID_AeroGuides + useWhidbey = event.GetId() == ID_WhidbeyGuides + agwFlags = self._mgr.GetAGWFlags() + + if useAero: + agwFlags ^= aui.AUI_MGR_AERO_DOCKING_GUIDES + agwFlags &= ~aui.AUI_MGR_WHIDBEY_DOCKING_GUIDES + elif useWhidbey: + agwFlags ^= aui.AUI_MGR_WHIDBEY_DOCKING_GUIDES + agwFlags &= ~aui.AUI_MGR_AERO_DOCKING_GUIDES + else: + agwFlags &= ~aui.AUI_MGR_AERO_DOCKING_GUIDES + agwFlags &= ~aui.AUI_MGR_WHIDBEY_DOCKING_GUIDES + + self._mgr.SetAGWFlags(agwFlags) + + + def OnNotebookPageClose(self, event): + + ctrl = event.GetEventObject() + if isinstance(ctrl.GetPage(event.GetSelection()), wx.html.HtmlWindow): + + res = wx.MessageBox("Are you sure you want to close/hide this notebook page?", + "AUI", wx.YES_NO, self) + if res != wx.YES: + event.Veto() + + + def OnAllowNotebookDnD(self, event): + + # for the purpose of this test application, explicitly + # allow all noteboko drag and drop events + event.Allow() + + + def GetStartPosition(self): + + x = 20 + pt = self.ClientToScreen(wx.Point(0, 0)) + return wx.Point(pt.x + x, pt.y + x) + + + def OnCreateTree(self, event): + + self._mgr.AddPane(self.CreateTreeCtrl(), aui.AuiPaneInfo(). + Caption("Tree Control"). + Float().FloatingPosition(self.GetStartPosition()). + FloatingSize(wx.Size(150, 300)).MinimizeButton(True)) + self._mgr.Update() + + + def OnCreateGrid(self, event): + + self._mgr.AddPane(self.CreateGrid(), aui.AuiPaneInfo(). + Caption("Grid"). + Float().FloatingPosition(self.GetStartPosition()). + FloatingSize(wx.Size(300, 200)).MinimizeButton(True)) + self._mgr.Update() + + + def OnCreateHTML(self, event): + + self._mgr.AddPane(self.CreateHTMLCtrl(), aui.AuiPaneInfo(). + Caption("HTML Control"). + Float().FloatingPosition(self.GetStartPosition()). + FloatingSize(wx.Size(300, 200)).MinimizeButton(True)) + self._mgr.Update() + + + def OnCreateNotebook(self, event): + + self._mgr.AddPane(self.CreateNotebook(), aui.AuiPaneInfo(). + Caption("Notebook"). + Float().FloatingPosition(self.GetStartPosition()). + CloseButton(True).MaximizeButton(True).MinimizeButton(True)) + self._mgr.Update() + + + def OnCreateText(self, event): + + self._mgr.AddPane(self.CreateTextCtrl(), aui.AuiPaneInfo(). + Caption("Text Control"). + Float().FloatingPosition(self.GetStartPosition()). + MinimizeButton(True)) + self._mgr.Update() + + + def OnCreateSizeReport(self, event): + + self._mgr.AddPane(self.CreateSizeReportCtrl(), aui.AuiPaneInfo(). + Caption("Client Size Reporter"). + Float().FloatingPosition(self.GetStartPosition()). + CloseButton(True).MaximizeButton(True).MinimizeButton(True)) + self._mgr.Update() + + + def OnChangeContentPane(self, event): + + self._mgr.GetPane("grid_content").Show(event.GetId() == ID_GridContent) + self._mgr.GetPane("text_content").Show(event.GetId() == ID_TextContent) + self._mgr.GetPane("tree_content").Show(event.GetId() == ID_TreeContent) + self._mgr.GetPane("sizereport_content").Show(event.GetId() == ID_SizeReportContent) + self._mgr.GetPane("html_content").Show(event.GetId() == ID_HTMLContent) + self._mgr.GetPane("notebook_content").Show(event.GetId() == ID_NotebookContent) + self._mgr.Update() + + + def OnVetoTree(self, event): + + self._veto_tree = event.IsChecked() + + + def OnVetoText(self, event): + + self._veto_text = event.IsChecked() + + + def OnRequestUserAttention(self, event): + + ids = event.GetId() + if ids not in self._requestPanes: + return + + paneName = self._requestPanes[ids] + pane = self._mgr.GetPane(paneName) + self._mgr.RequestUserAttention(pane.window) + + + def OnDropDownToolbarItem(self, event): + + if event.IsDropDownClicked(): + + tb = event.GetEventObject() + tb.SetToolSticky(event.GetId(), True) + + # create the popup menu + menuPopup = wx.Menu() + bmp = wx.ArtProvider.GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, wx.Size(16, 16)) + + m1 = wx.MenuItem(menuPopup, 10001, "Drop Down Item 1") + m1.SetBitmap(bmp) + menuPopup.AppendItem(m1) + + m2 = wx.MenuItem(menuPopup, 10002, "Drop Down Item 2") + m2.SetBitmap(bmp) + menuPopup.AppendItem(m2) + + m3 = wx.MenuItem(menuPopup, 10003, "Drop Down Item 3") + m3.SetBitmap(bmp) + menuPopup.AppendItem(m3) + + m4 = wx.MenuItem(menuPopup, 10004, "Drop Down Item 4") + m4.SetBitmap(bmp) + menuPopup.AppendItem(m4) + + # line up our menu with the button + rect = tb.GetToolRect(event.GetId()) + pt = tb.ClientToScreen(rect.GetBottomLeft()) + pt = self.ScreenToClient(pt) + + self.PopupMenu(menuPopup, pt) + + # make sure the button is "un-stuck" + tb.SetToolSticky(event.GetId(), False) + + + def OnTabAlignment(self, event): + + for pane in self._mgr.GetAllPanes(): + + if isinstance(pane.window, aui.AuiNotebook): + + nb = pane.window + style = nb.GetAGWWindowStyleFlag() + + if event.GetId() == ID_NotebookAlignTop: + style &= ~aui.AUI_NB_BOTTOM + style ^= aui.AUI_NB_TOP + nb.SetAGWWindowStyleFlag(style) + elif event.GetId() == ID_NotebookAlignBottom: + style &= ~aui.AUI_NB_TOP + style ^= aui.AUI_NB_BOTTOM + nb.SetAGWWindowStyleFlag(style) + + self._notebook_style = style + nb.Update() + nb.Refresh() + + + def OnCustomTabButtons(self, event): + + checked = event.IsChecked() + self._custom_tab_buttons = checked + auibook = self._mgr.GetPane("notebook_content").window + + left = CUSTOM_TAB_BUTTONS["Left"] + for btn, ids in left: + if checked: + auibook.AddTabAreaButton(ids, wx.LEFT, btn.GetBitmap()) + else: + auibook.RemoveTabAreaButton(ids) + + right = CUSTOM_TAB_BUTTONS["Right"] + for btn, ids in right: + if checked: + auibook.AddTabAreaButton(ids, wx.RIGHT, btn.GetBitmap()) + else: + auibook.RemoveTabAreaButton(ids) + + auibook.Refresh() + auibook.Update() + + + def OnMinMaxTabWidth(self, event): + + auibook = self._mgr.GetPane("notebook_content").window + minTabWidth, maxTabWidth = auibook.GetMinMaxTabWidth() + + dlg = wx.TextEntryDialog(self, "Enter the minimum and maximum tab widths, separated by a comma:", + "AuiNotebook Tab Widths") + + dlg.SetValue("%d,%d"%(minTabWidth, maxTabWidth)) + if dlg.ShowModal() != wx.ID_OK: + return + + value = dlg.GetValue() + dlg.Destroy() + + try: + minTabWidth, maxTabWidth = value.split(",") + minTabWidth, maxTabWidth = int(minTabWidth), int(maxTabWidth) + except: + dlg = wx.MessageDialog(self, 'Invalid minimum/maximum tab width. Tab widths should be' \ + ' 2 integers separated by a comma.', + 'Error', + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + + if minTabWidth > maxTabWidth: + dlg = wx.MessageDialog(self, 'Invalid minimum/maximum tab width. Minimum tab width' \ + ' should be less of equal than maximum tab width.', + 'Error', + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + + auibook.SetMinMaxTabWidth(minTabWidth, maxTabWidth) + auibook.Refresh() + auibook.Update() + + + def OnPreview(self, event): + + auibook = self._mgr.GetPane("notebook_content").window + auibook.NotebookPreview() + + + def OnAddMultiLine(self, event): + + auibook = self._mgr.GetPane("notebook_content").window + + auibook.InsertPage(1, wx.TextCtrl(auibook, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "Multi-Line\nTab Labels", True) + + auibook.SetPageTextColour(1, wx.BLUE) + + + def OnFloatDock(self, event): + + paneLabel = event.pane.caption + etype = event.GetEventType() + + strs = "Pane %s "%paneLabel + if etype == aui.wxEVT_AUI_PANE_FLOATING: + strs += "is about to be floated" + + if event.pane.name == "test8" and self._veto_tree: + event.Veto() + strs += "... Event vetoed by user selection!" + self.log.write(strs + "\n") + return + + elif etype == aui.wxEVT_AUI_PANE_FLOATED: + strs += "has been floated" + elif etype == aui.wxEVT_AUI_PANE_DOCKING: + strs += "is about to be docked" + + if event.pane.name == "test11" and self._veto_text: + event.Veto() + strs += "... Event vetoed by user selection!" + self.log.write(strs + "\n") + return + + elif etype == aui.wxEVT_AUI_PANE_DOCKED: + strs += "has been docked" + + self.log.write(strs + "\n") + + + def OnExit(self, event): + + self.Close(True) + + + def OnAbout(self, event): + + msg = "This Is The About Dialog Of The Pure Python Version Of AUI.\n\n" + \ + "Author: Andrea Gavana @ 23 Dec 2005\n\n" + \ + "Please Report Any Bug/Requests Of Improvements\n" + \ + "To Me At The Following Adresses:\n\n" + \ + "andrea.gavana@maerskoil.com\n" + "andrea.gavana@gmail.com\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "AUI Demo", + wx.OK | wx.ICON_INFORMATION) + + if wx.Platform != '__WXMAC__': + dlg.SetFont(wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, False)) + + dlg.ShowModal() + dlg.Destroy() + + + def CreateTextCtrl(self, ctrl_text=""): + + if ctrl_text.strip(): + text = ctrl_text + else: + text = "This is text box %d"%self._textCount + self._textCount += 1 + + return wx.TextCtrl(self,-1, text, wx.Point(0, 0), wx.Size(150, 90), + wx.NO_BORDER | wx.TE_MULTILINE) + + + def CreateGrid(self): + + grid = wx.grid.Grid(self, -1, wx.Point(0, 0), wx.Size(150, 250), + wx.NO_BORDER | wx.WANTS_CHARS) + grid.CreateGrid(50, 20) + return grid + + + def CreateTreeCtrl(self): + + tree = wx.TreeCtrl(self, -1, wx.Point(0, 0), wx.Size(160, 250), + wx.TR_DEFAULT_STYLE | wx.NO_BORDER) + + imglist = wx.ImageList(16, 16, True, 2) + imglist.Add(wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, wx.Size(16, 16))) + imglist.Add(wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16))) + tree.AssignImageList(imglist) + + root = tree.AddRoot("AUI Project", 0) + items = [] + + items.append(tree.AppendItem(root, "Item 1", 0)) + items.append(tree.AppendItem(root, "Item 2", 0)) + items.append(tree.AppendItem(root, "Item 3", 0)) + items.append(tree.AppendItem(root, "Item 4", 0)) + items.append(tree.AppendItem(root, "Item 5", 0)) + + for item in items: + tree.AppendItem(item, "Subitem 1", 1) + tree.AppendItem(item, "Subitem 2", 1) + tree.AppendItem(item, "Subitem 3", 1) + tree.AppendItem(item, "Subitem 4", 1) + tree.AppendItem(item, "Subitem 5", 1) + + tree.Expand(root) + + return tree + + + def CreateSizeReportCtrl(self, width=80, height=80): + + ctrl = SizeReportCtrl(self, -1, wx.DefaultPosition, wx.Size(width, height), self._mgr) + return ctrl + + + def CreateHTMLCtrl(self, parent=None): + + if not parent: + parent = self + + ctrl = wx.html.HtmlWindow(parent, -1, wx.DefaultPosition, wx.Size(400, 300)) + ctrl.SetPage(GetIntroText()) + return ctrl + + + def CreateNotebook(self): + + # create the notebook off-window to avoid flicker + client_size = self.GetClientSize() + ctrl = aui.AuiNotebook(self, -1, wx.Point(client_size.x, client_size.y), + wx.Size(430, 200), agwStyle=self._notebook_style) + + arts = [aui.AuiDefaultTabArt, aui.AuiSimpleTabArt, aui.VC71TabArt, aui.FF2TabArt, + aui.VC8TabArt, aui.ChromeTabArt] + + art = arts[self._notebook_theme]() + ctrl.SetArtProvider(art) + + page_bmp = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16)) + ctrl.AddPage(self.CreateHTMLCtrl(ctrl), "Welcome to AUI", False, page_bmp) + + panel = wx.Panel(ctrl, -1) + flex = wx.FlexGridSizer(0, 2) + flex.Add((5, 5)) + flex.Add((5, 5)) + flex.Add(wx.StaticText(panel, -1, "wxTextCtrl:"), 0, wx.ALL|wx.ALIGN_CENTRE, 5) + flex.Add(wx.TextCtrl(panel, -1, "", wx.DefaultPosition, wx.Size(100, -1)), + 1, wx.ALL|wx.ALIGN_CENTRE, 5) + flex.Add(wx.StaticText(panel, -1, "wxSpinCtrl:"), 0, wx.ALL|wx.ALIGN_CENTRE, 5) + flex.Add(wx.SpinCtrl(panel, -1, "5", wx.DefaultPosition, wx.Size(100, -1), + wx.SP_ARROW_KEYS, 5, 50, 5), 0, wx.ALL|wx.ALIGN_CENTRE, 5) + flex.Add((5, 5)) + flex.Add((5, 5)) + flex.AddGrowableRow(0) + flex.AddGrowableRow(3) + flex.AddGrowableCol(1) + panel.SetSizer(flex) + ctrl.AddPage(panel, "Disabled", False, page_bmp) + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "DClick Edit!", False, page_bmp) + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "Blue Tab") + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "A Control") + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "wxTextCtrl 4") + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "wxTextCtrl 5") + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "wxTextCtrl 6") + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "wxTextCtrl 7 (longer title)") + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "wxTextCtrl 8") + + # Demonstrate how to disable a tab + ctrl.EnableTab(1, False) + + ctrl.SetPageTextColour(2, wx.RED) + ctrl.SetPageTextColour(3, wx.BLUE) + ctrl.SetRenamable(2, True) + + return ctrl + + + def OnSwitchPane(self, event): + + items = ASD.SwitcherItems() + items.SetRowCount(12) + + # Add the main windows and toolbars, in two separate columns + # We'll use the item 'id' to store the notebook selection, or -1 if not a page + + for k in xrange(2): + if k == 0: + items.AddGroup(_("Main Windows"), "mainwindows") + else: + items.AddGroup(_("Toolbars"), "toolbars").BreakColumn() + + for pane in self._mgr.GetAllPanes(): + name = pane.name + caption = pane.caption + if not caption: + continue + + toolBar = isinstance(pane.window, wx.ToolBar) or isinstance(pane.window, aui.AuiToolBar) + bitmap = (pane.icon.IsOk() and [pane.icon] or [wx.NullBitmap])[0] + + if (toolBar and k == 1) or (not toolBar and k == 0): + items.AddItem(caption, name, -1, bitmap).SetWindow(pane.window) + + # Now add the wxAuiNotebook pages + items.AddGroup(_("Notebook Pages"), "pages").BreakColumn() + + for pane in self._mgr.GetAllPanes(): + nb = pane.window + if isinstance(nb, aui.AuiNotebook): + for j in xrange(nb.GetPageCount()): + + name = nb.GetPageText(j) + win = nb.GetPage(j) + + items.AddItem(name, name, j, nb.GetPageBitmap(j)).SetWindow(win) + + # Select the focused window + + idx = items.GetIndexForFocus() + if idx != wx.NOT_FOUND: + items.SetSelection(idx) + + if wx.Platform == "__WXMAC__": + items.SetBackgroundColour(wx.WHITE) + + # Show the switcher dialog + + dlg = ASD.SwitcherDialog(items, self, self._mgr) + + # In GTK+ we can't use Ctrl+Tab; we use Ctrl+/ instead and tell the switcher + # to treat / in the same was as tab (i.e. cycle through the names) + + if wx.Platform == "__WXGTK__": + dlg.SetExtraNavigationKey('/') + + if wx.Platform == "__WXMAC__": + dlg.SetBackgroundColour(wx.WHITE) + dlg.SetModifierKey(wx.WXK_ALT) + + ans = dlg.ShowModal() + + if ans == wx.ID_OK and dlg.GetSelection() != -1: + item = items.GetItem(dlg.GetSelection()) + + if item.GetId() == -1: + info = self._mgr.GetPane(item.GetName()) + info.Show() + self._mgr.Update() + info.window.SetFocus() + + else: + nb = item.GetWindow().GetParent() + win = item.GetWindow() + if isinstance(nb, aui.AuiNotebook): + nb.SetSelection(item.GetId()) + win.SetFocus() + + +def GetIntroText(): + + text = \ + "" \ + "

Welcome to AUI

" \ + "
Overview
" \ + "

AUI is an Advanced User Interface library for the wxPython toolkit " \ + "that allows developers to create high-quality, cross-platform user " \ + "interfaces quickly and easily.

" \ + "

Features

" \ + "

With AUI, developers can create application frameworks with:

" \ + "
    " \ + "
  • Native, dockable floating frames
  • " \ + "
  • Perspective saving and loading
  • " \ + "
  • Native toolbars incorporating real-time, 'spring-loaded' dragging
  • " \ + "
  • Customizable floating/docking behavior
  • " \ + "
  • Completely customizable look-and-feel
  • " \ + "
  • Optional transparent window effects (while dragging or docking)
  • " \ + "
  • Splittable notebook control
  • " \ + "
" \ + "

What's new in AUI?

" \ + "

Current wxAUI Version Tracked: wxWidgets 2.9.4 (SVN HEAD)" \ + "

The wxPython AUI version fixes the following bugs or implement the following" \ + " missing features (the list is not exhaustive): " \ + "

" \ + "

Plus the following features:" \ + "

    " \ + "
  • AuiManager:
  • " \ + "
      " \ + "
    • Implementation of a simple minimize pane system: Clicking on this minimize button causes a new " \ + "AuiToolBar to be created and added to the frame manager, (currently the implementation is such " \ + "that panes at West will have a toolbar at the right, panes at South will have toolbars at the " \ + "bottom etc...) and the pane is hidden in the manager. " \ + "Clicking on the restore button on the newly created toolbar will result in the toolbar being " \ + "removed and the original pane being restored;
    • " \ + "
    • Panes can be docked on top of each other to form AuiNotebooks; AuiNotebooks tabs can be torn " \ + "off to create floating panes;
    • " \ + "
    • On Windows XP, use the nice sash drawing provided by XP while dragging the sash;
    • " \ + "
    • Possibility to set an icon on docked panes;
    • " \ + "
    • Possibility to draw a sash visual grip, for enhanced visualization of sashes;
    • " \ + "
    • Implementation of a native docking art (ModernDockArt). Windows XP only, requires Mark Hammond's " \ + "pywin32 package (winxptheme);
    • " \ + "
    • Possibility to set a transparency for floating panes (a la Paint .NET);
    • " \ + "
    • Snapping the main frame to the screen in any positin specified by horizontal and vertical " \ + "alignments;
    • " \ + "
    • Snapping floating panes on left/right/top/bottom or any combination of directions, a la Winamp;
    • " \ + "
    • 'Fly-out' floating panes, i.e. panes which show themselves only when the mouse hover them;
    • " \ + "
    • Ability to set custom bitmaps for pane buttons (close, maximize, etc...);
    • " \ + "
    • Implementation of the style AUI_MGR_ANIMATE_FRAMES, which fade-out floating panes when " \ + "they are closed (all platforms which support frames transparency) and show a moving rectangle " \ + "when they are docked and minimized (Windows excluding Vista and GTK only);
    • " \ + "
    • A pane switcher dialog is available to cycle through existing AUI panes;
    • " \ + "
    • Some flags which allow to choose the orientation and the position of the minimized panes;
    • " \ + "
    • The functions [Get]MinimizeMode() in AuiPaneInfo which allow to set/get the flags described above;
    • " \ + "
    • Events like EVT_AUI_PANE_DOCKING, EVT_AUI_PANE_DOCKED, EVT_AUI_PANE_FLOATING "\ + "and EVT_AUI_PANE_FLOATED are "\ + "available for all panes except toolbar panes;
    • " \ + "
    • Implementation of the RequestUserAttention method for panes;
    • " \ + "
    • Ability to show the caption bar of docked panes on the left instead of on the top (with caption " \ + "text rotated by 90 degrees then). This is similar to what wxDockIt did. To enable this feature on any " \ + "given pane, simply call CaptionVisible(True, left=True);
    • " \ + "
    • New Aero-style docking guides: you can enable them by using the AuiManager style AUI_MGR_AERO_DOCKING_GUIDES;
    • " \ + "
    • New Whidbey-style docking guides: you can enable them by using the AuiManager style AUI_MGR_WHIDBEY_DOCKING_GUIDES;
    • " \ + "
    • A slide-in/slide-out preview of minimized panes can be seen by enabling the AuiManager style" \ + "AUI_MGR_PREVIEW_MINIMIZED_PANES and by hovering with the mouse on the minimized pane toolbar tool;
    • " \ + "
    • Native of custom-drawn mini frames can be used as floating panes, depending on the AUI_MGR_USE_NATIVE_MINIFRAMES style;
    • " \ + "
    • A 'smooth docking effect' can be obtained by using the AUI_MGR_SMOOTH_DOCKING style (similar to PyQT docking style);
    • " \ + '
    • Implementation of "Movable" panes, i.e. a pane that is set as `Movable()` but not `Floatable()` can be dragged and docked into a new location but will not form a floating window in between.
    • ' \ + "

    " \ + "

  • AuiNotebook:
  • " \ + "
      " \ + "
    • Implementation of the style AUI_NB_HIDE_ON_SINGLE_TAB, a la wx.lib.agw.flatnotebook;
    • " \ + "
    • Implementation of the style AUI_NB_SMART_TABS, a la wx.lib.agw.flatnotebook;
    • " \ + "
    • Implementation of the style AUI_NB_USE_IMAGES_DROPDOWN, which allows to show tab images " \ + "on the tab dropdown menu instead of bare check menu items (a la wx.lib.agw.flatnotebook);
    • " \ + "
    • 6 different tab arts are available, namely:
    • " \ + "
        " \ + "
      • Default 'glossy' theme (as in wx.aui.AuiNotebook)
      • " \ + "
      • Simple theme (as in wx.aui.AuiNotebook)
      • " \ + "
      • Firefox 2 theme
      • " \ + "
      • Visual Studio 2003 theme (VC71)
      • " \ + "
      • Visual Studio 2005 theme (VC81)
      • " \ + "
      • Google Chrome theme
      • " \ + "
      " \ + "
    • Enabling/disabling tabs;
    • " \ + "
    • Setting the colour of the tab's text;
    • " \ + "
    • Implementation of the style AUI_NB_CLOSE_ON_TAB_LEFT, which draws the tab close button on " \ + "the left instead of on the right (a la Camino browser);
    • " \ + "
    • Ability to save and load perspectives in wx.aui.AuiNotebook (experimental);
    • " \ + "
    • Possibility to add custom buttons in the wx.aui.AuiNotebook tab area;
    • " \ + "
    • Implementation of the style AUI_NB_TAB_FLOAT, which allows the floating of single tabs. " \ + "Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far " \ + "enough outside of the notebook to become floating pages.
    • " \ + "
    • Implementation of the style AUI_NB_DRAW_DND_TAB (on by default), which draws an image " \ + "representation of a tab while dragging;
    • " \ + "
    • Implementation of the AuiNotebook unsplit functionality, which unsplit a splitted AuiNotebook " \ + "when double-clicking on a sash (Use SetSashDClickUnsplit);
    • " \ + "
    • Possibility to hide all the tabs by calling HideAllTAbs;
    • " \ + "
    • wxPython controls can now be added inside page tabs by calling AddControlToPage, and they can be " \ + "removed by calling RemoveControlFromPage;
    • " \ + "
    • Possibility to preview all the pages in a AuiNotebook (as thumbnails) by using the NotebookPreview " \ + "method of AuiNotebook
    • ;" \ + "
    • Tab labels can be edited by calling the SetRenamable method on a AuiNotebook page;
    • " \ + "
    • Support for multi-lines tab labels in AuiNotebook;
    • " \ + "
    • Support for setting minimum and maximum tab widths for fixed width tabs;
    • "\ + "
    • Implementation of the style AUI_NB_ORDER_BY_ACCESS, which orders the tabs by last access time inside the "\ + "Tab Navigator dialog
    • ;" \ + "
    • Implementation of the style AUI_NB_NO_TAB_FOCUS, allowing the developer not to draw the tab " \ + "focus rectangle on tne AuiNotebook tabs.
    • "\ + "

    " \ + "

  • AuiToolBar:
  • " \ + "
      " \ + "
    • AUI_TB_PLAIN_BACKGROUND style that allows to easy setup a plain background to the AUI toolbar, " \ + "without the need to override drawing methods. This style contrasts with the default behaviour " \ + "of the wx.aui.AuiToolBar that draws a background gradient and this break the window design when " \ + "putting it within a control that has margin between the borders and the toolbar (example: put " \ + "wx.aui.AuiToolBar within a wx.StaticBoxSizer that has a plain background);
    • " \ + "
    • AuiToolBar allow item alignment: " \ + "http://trac.wxwidgets.org/ticket/10174;
    • " \ + "
    • AUIToolBar DrawButton() improvement: " \ + "http://trac.wxwidgets.org/ticket/10303;
    • " \ + "
    • AuiToolBar automatically assign new id for tools: " \ + "http://trac.wxwidgets.org/ticket/10173;
    • " \ + "
    • AuiToolBar Allow right-click on any kind of button: " \ + "http://trac.wxwidgets.org/ticket/10079;
    • " \ + "
    • AuiToolBar idle update only when visible: " \ + "http://trac.wxwidgets.org/ticket/10075;
    • " \ + "
    • Ability of creating AuiToolBar tools with [counter]clockwise rotation. This allows to propose a " \ + "variant of the minimizing functionality with a rotated button which keeps the caption of the pane as label;
    • " \ + "
    • Allow setting the alignment of all tools in a toolbar that is expanded.
    • " \ + "
    • Implementation of the AUI_MINIMIZE_POS_TOOLBAR flag, which allows to minimize a pane inside " \ + "an existing toolbar. Limitation: if the minimized icon in the toolbar ends up in the overflowing " \ + "items (i.e., a menu is needed to show the icon), this style will not work.
    • " \ + "
    " \ + "

" \ + "

" \ + "" + + return text + + +#---------------------------------------------------------------------- + +class ParentFrame(aui.AuiMDIParentFrame): + + def __init__(self, parent): + + aui.AuiMDIParentFrame.__init__(self, parent, -1, title="AGW AuiMDIParentFrame", + size=(640,480), style=wx.DEFAULT_FRAME_STYLE) + self.count = 0 + + # set frame icon + self.SetIcon(images.Mondrian.GetIcon()) + + mb = self.MakeMenuBar() + self.SetMenuBar(mb) + self.CreateStatusBar() + + + def MakeMenuBar(self): + + mb = wx.MenuBar() + menu = wx.Menu() + item = menu.Append(-1, "New child window\tCtrl-N") + self.Bind(wx.EVT_MENU, self.OnNewChild, item) + item = menu.Append(-1, "Close parent") + self.Bind(wx.EVT_MENU, self.OnDoClose, item) + mb.Append(menu, "&File") + return mb + + + def OnNewChild(self, evt): + + self.count += 1 + child = ChildFrame(self, self.count) + child.Show() + + + def OnDoClose(self, evt): + self.Close() + + +#---------------------------------------------------------------------- + +class ChildFrame(aui.AuiMDIChildFrame): + + def __init__(self, parent, count): + + aui.AuiMDIChildFrame.__init__(self, parent, -1, title="Child: %d" % count) + mb = parent.MakeMenuBar() + menu = wx.Menu() + item = menu.Append(-1, "This is child %d's menu" % count) + mb.Append(menu, "&Child") + self.SetMenuBar(mb) + + p = wx.Panel(self) + wx.StaticText(p, -1, "This is child %d" % count, (10,10)) + p.SetBackgroundColour('light blue') + + sizer = wx.BoxSizer() + sizer.Add(p, 1, wx.EXPAND) + self.SetSizer(sizer) + + wx.CallAfter(self.Layout) + + +#--------------------------------------------------------------------------- + +def MainAUI(parent, log): + + frame = AuiFrame(parent, -1, "AUI Test Frame", size=(800, 600), log=log) + frame.CenterOnScreen() + frame.Show() + + +#--------------------------------------------------------------------------- + +def MDIAUI(parent, log): + + frame = ParentFrame(parent) + frame.CenterOnScreen() + frame.Show() + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b1 = wx.Button(self, -1, " AGW AUI Docking Library ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton1, b1) + +## b2 = wx.Button(self, -1, " AGW AuiMDIs ", (50, 80)) +## self.Bind(wx.EVT_BUTTON, self.OnButton2, b2) + + + def OnButton1(self, event): + self.win = MainAUI(self, self.log) + + + def OnButton2(self, event): + self.win = MDIAUI(self, self.log) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = GetIntroText() + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/agw/AdvancedSplash.py b/demo/agw/AdvancedSplash.py new file mode 100644 index 00000000..9f804fad --- /dev/null +++ b/demo/agw/AdvancedSplash.py @@ -0,0 +1,57 @@ +import wx +import wx.lib.buttons + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +bitmapDir = os.path.join(dirName, 'bitmaps') +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import advancedsplash as AS +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.advancedsplash as AS + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test AdvancedSplash ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + pn = os.path.normpath(os.path.join(bitmapDir, "advancedsplash.png")) + bitmap = wx.Bitmap(pn, wx.BITMAP_TYPE_PNG) + shadow = wx.WHITE + + frame = AS.AdvancedSplash(self, bitmap=bitmap, timeout=5000, + agwStyle=AS.AS_TIMEOUT | + AS.AS_CENTER_ON_PARENT | + AS.AS_SHADOW_BITMAP, + shadowcolour=shadow) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = AS.__doc__ + + +if __name__ == '__main__': + import sys, os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/agw/AquaButton.py b/demo/agw/AquaButton.py new file mode 100644 index 00000000..a5e7cc69 --- /dev/null +++ b/demo/agw/AquaButton.py @@ -0,0 +1,141 @@ +import wx + +if wx.VERSION < (2, 8, 9, 0): + raise Exception("This demo requires wxPython version greater than 2.8.9.0") + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +bitmapDir = os.path.join(dirName, 'bitmaps') +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import aquabutton as AB +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.aquabutton as AB + + +class AquaButtonDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + self.log = log + + self.mainPanel = wx.Panel(self) + self.mainPanel.SetBackgroundColour(wx.WHITE) + + # Initialize AquaButton 1 (with image) + bitmap = wx.Bitmap( + os.path.normpath(os.path.join(bitmapDir, "aquabutton.png")), + wx.BITMAP_TYPE_PNG) + self.btn1 = AB.AquaButton(self.mainPanel, -1, bitmap, "AquaButton") + # Initialize AquaButton 2 (no image) + self.btn2 = AB.AquaButton(self.mainPanel, -1, None, "Hello World!") + + self.backColour = wx.ColourPickerCtrl(self.mainPanel, col=self.btn2.GetBackgroundColour()) + self.hoverColour = wx.ColourPickerCtrl(self.mainPanel, col=self.btn2.GetHoverColour()) + self.textColour = wx.ColourPickerCtrl(self.mainPanel, col=self.btn2.GetForegroundColour()) + self.pulseCheck = wx.CheckBox(self.mainPanel, -1, "Pulse On Focus") + + self.DoLayout() + self.BindEvents() + + + def DoLayout(self): + + frameSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.FlexGridSizer(2, 2, 15, 15) + + colourSizer = wx.FlexGridSizer(2, 3, 1, 10) + + btnSizer.Add(self.btn1, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL) + btnSizer.Add(self.pulseCheck, 0, wx.ALIGN_CENTER_VERTICAL) + + btnSizer.Add(self.btn2, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL) + + labelBack = wx.StaticText(self.mainPanel, -1, "Background Colour") + labelHover = wx.StaticText(self.mainPanel, -1, "Hover Colour") + labelText = wx.StaticText(self.mainPanel, -1, "Text Colour") + + colourSizer.Add(labelBack) + colourSizer.Add(labelHover) + colourSizer.Add(labelText) + + colourSizer.Add(self.backColour, 0, wx.EXPAND) + colourSizer.Add(self.hoverColour, 0, wx.EXPAND) + colourSizer.Add(self.textColour, 0, wx.EXPAND) + + btnSizer.Add(colourSizer, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL) + label1 = wx.StaticText(self.mainPanel, -1, "Welcome to the AquaButton demo for wxPython!") + + mainSizer.Add(label1, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10) + mainSizer.Add(btnSizer, 1, wx.EXPAND|wx.ALL, 30) + + boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + boldFont.SetWeight(wx.BOLD) + + for child in self.mainPanel.GetChildren(): + if isinstance(child, wx.StaticText): + child.SetFont(boldFont) + + self.mainPanel.SetSizer(mainSizer) + mainSizer.Layout() + frameSizer.Add(self.mainPanel, 1, wx.EXPAND) + self.SetSizer(frameSizer) + frameSizer.Layout() + + + def BindEvents(self): + + self.Bind(wx.EVT_CHECKBOX, self.OnPulse, self.pulseCheck) + self.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnPickColour) + self.Bind(wx.EVT_BUTTON, self.OnButton, self.btn1) + self.Bind(wx.EVT_BUTTON, self.OnButton, self.btn2) + + + def OnPulse(self, event): + + self.btn1.SetPulseOnFocus(event.IsChecked()) + + + def OnPickColour(self, event): + + obj = event.GetEventObject() + colour = event.GetColour() + if obj == self.backColour: + self.btn2.SetBackgroundColour(colour) + elif obj == self.hoverColour: + self.btn2.SetHoverColour(colour) + else: + self.btn2.SetForegroundColour(colour) + + + def OnButton(self, event): + + obj = event.GetEventObject() + self.log.write("You clicked %s\n"%obj.GetLabel()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = AquaButtonDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = AB.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/agw/BalloonTip.py b/demo/agw/BalloonTip.py new file mode 100644 index 00000000..c61d500b --- /dev/null +++ b/demo/agw/BalloonTip.py @@ -0,0 +1,374 @@ +# ---------------------------------------------------------------------------- +# BalloonTip Demo Implementation +# +# This Demo Shows How To Use The BalloonTip Control, With Different Styles +# And Behaviors. +# ---------------------------------------------------------------------------- + + +import wx +from wx.lib.stattext import GenStaticText as StaticText +from wx.lib.buttons import GenBitmapButton as BitmapButton + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import balloontip as BT +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.balloontip as BT + +import images + +ArtIDs = [ "wx.ART_HELP_PAGE", + "wx.ART_GO_FORWARD", + "wx.ART_FILE_OPEN", + "wx.ART_HELP", + "wx.ART_ERROR", + "wx.ART_QUESTION", + "wx.ART_WARNING", + "wx.ART_INFORMATION", + "wx.ART_HELP", + ] + + +# ---------------------------------------------------------------------------- +# Beginning Of BalloonTip Demo +# ---------------------------------------------------------------------------- + +class BalloonTipDemo(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent, title="BalloonTip wxPython Demo ;-)") + + self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + self.statusbar.SetStatusWidths([-2, -1]) + # statusbar fields + statusbar_fields = [("Welcome To WxPython " + wx.VERSION_STRING), + ("BalloonTip Demo")] + + for i in range(len(statusbar_fields)): + self.statusbar.SetStatusText(statusbar_fields[i], i) + + self.SetIcon(images.Mondrian.GetIcon()) + self.SetMenuBar(self.CreateMenuBar()) + + panel = wx.Panel(self, -1) + + mainsizer = wx.FlexGridSizer(3, 4, hgap=2, vgap=2) + + # Add A Button + button = wx.Button(panel, -1, "Press Me!") + # Add A TextCtrl + textctrl = wx.TextCtrl(panel, -1, "I Am A TextCtrl") + # Add A CheckBox + checkbox = wx.CheckBox(panel, -1, "3-State Checkbox", + style=wx.CHK_3STATE | wx.CHK_ALLOW_3RD_STATE_FOR_USER) + samplelist=['One', 'Two', 'Three', 'Four', 'Kick', 'The', 'Demo', 'Out', + 'The', 'Door', ';-)'] + # Add A Choice + choice = wx.Choice(panel, -1, choices = samplelist) + # Add A Gauge + gauge = wx.Gauge(panel, -1, 50, style=wx.GA_SMOOTH) + # Add A ListBox + listbox = wx.ListBox(panel, -1, choices=samplelist, style=wx.LB_SINGLE) + # Add A TreeCtrl + isz = (16,16) + treecontrol = wx.TreeCtrl(panel, -1) + il = wx.ImageList(isz[0], isz[1]) + fldridx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, isz)) + fldropenidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, isz)) + fileidx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_REPORT_VIEW, wx.ART_OTHER, isz)) + treecontrol.SetImageList(il) + self.il = il + root = treecontrol.AddRoot("ROOT") + treecontrol.SetPyData(root, None) + treecontrol.SetItemImage(root, fldridx, wx.TreeItemIcon_Normal) + treecontrol.SetItemImage(root, fldropenidx, wx.TreeItemIcon_Expanded) + for ii in range(11): + child = treecontrol.AppendItem(root, samplelist[ii]) + treecontrol.SetPyData(child, None) + treecontrol.SetItemImage(child, fldridx, wx.TreeItemIcon_Normal) + treecontrol.SetItemImage(child, fldropenidx, wx.TreeItemIcon_Selected) + + # Add A Slider + slider = wx.Slider(panel, -1, 25, 1, 100, + style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS)# | wx.SL_LABELS) + slider.SetTickFreq(5, 1) + # Add Another TextCtrl + textctrl2 = wx.TextCtrl(panel, -1, "Another TextCtrl") + # Add A GenStaticText + statictext = StaticText(panel, -1, "Hello World!") + statictext.SetFont(wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + bmp = wx.ArtProvider_GetBitmap(wx.ART_INFORMATION, + wx.ART_TOOLBAR, (16,16)) + # Add A GenBitmapButton + bitmapbutton = BitmapButton(panel, -1, bmp) + button2 = wx.Button(panel, -1, "Disable BalloonTip") + + tbicon = wx.TaskBarIcon() + tbicon.SetIcon(images.Mondrian.GetIcon()) + + controls = list(panel.GetChildren()) + controls.append(tbicon) + self.tbicon = tbicon + + # Add The Controls To The Main FlexGridSizer + mainsizer.Add(button, 0, wx.EXPAND | wx.ALL, 10) + mainsizer.Add(textctrl, 0, wx.EXPAND | wx.ALL, 10) + mainsizer.Add(checkbox, 0, wx.EXPAND | wx.ALL, 10) + mainsizer.Add(choice, 0, wx.EXPAND | wx.ALL, 10) + mainsizer.Add(gauge, 0, wx.ALL, 10) + mainsizer.Add(listbox, 0, wx.EXPAND | wx.ALL, 10) + mainsizer.Add(treecontrol, 0, wx.EXPAND, wx.ALL, 10) + mainsizer.Add(slider, 0, wx.ALL, 10) + mainsizer.Add(textctrl2, 0, wx.ALL, 10) + mainsizer.Add(statictext, 0, wx.EXPAND | wx.ALIGN_CENTER | wx.ALL, 10) + mainsizer.Add(bitmapbutton, 0, wx.ALL, 10) + mainsizer.Add(button2, 0, wx.ALL, 10) + + panel.SetSizer(mainsizer) + mainsizer.Layout() + + # Declare The BalloonTip Background Colours + bgcolours = [None, wx.WHITE, wx.GREEN, wx.BLUE, wx.CYAN, wx.RED, None, None, + wx.LIGHT_GREY, None, wx.WHITE, None, None] + + # Declare The BalloonTip Top-Left Icons + icons = [] + for ii in xrange(4): + bmp = wx.ArtProvider_GetBitmap(eval(ArtIDs[ii]), wx.ART_TOOLBAR, (16,16)) + icons.append(bmp) + + icons.extend([None]*5) + + for ii in xrange(4, 9): + bmp = wx.ArtProvider_GetBitmap(eval(ArtIDs[ii]), wx.ART_TOOLBAR, (16,16)) + icons.append(bmp) + + # Declare The BalloonTip Top Titles + titles = ["Button Help", "Texctrl Help", "CheckBox Help", "Choice Help", + "Gauge Help", "", "", "Read Me Carefully!", "SpinCtrl Help", + "StaticText Help", "BitmapButton Help", "Button Help", "Taskbar Help"] + + fontone = wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, True) + fonttwo = wx.Font(14, wx.SCRIPT, wx.NORMAL, wx.BOLD, False) + fontthree = wx.Font(9, wx.SWISS, wx.ITALIC, wx.NORMAL, False) + fontfour = wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD, True) + + # Declare The BalloonTip Top Titles Fonts + titlefonts = [None, None, fontone, None, fonttwo, fontthree, None, None, + None, fontfour, fontthree, None, None] + + # Declare The BalloonTip Top Titles Colours + titlecolours = [None, None, wx.WHITE, wx.NamedColour("YELLOW"), None, wx.WHITE, + wx.BLUE, wx.RED, None, None, wx.LIGHT_GREY, None, None] + + # Declare The BalloonTip Messages + msg1 = "This Is The Default BalloonTip Window\nYou Can Customize It! "\ + "Look At The Demo!" + msg2 = "You Can Change The Background Colour\n Of The Balloon Window." + msg3 = "You Can Also Change The Font And The\nColour For The Title." + msg4 = "I Have Nothing Special To Suggest!\n\nWelcome To wxPython " + \ + wx.VERSION_STRING + " !" + msg5 = "What About If I Don't Want The Icon?\nNo Problem!" + msg6 = "I Don't Have The Icon Nor The Title.\n\nDo You Love Me Anyway?" + msg7 = "Some Comments On The Window Shape:\n\n- BT_ROUNDED: Creates A "\ + "Rounded Rectangle;\n- BT_RECTANGLE: Creates A Rectangle.\n" + msg8 = "Some Comments On The BalloonTip Style:\n\n"\ + "BT_LEAVE: The BalloonTip Is Destroyed When\nThe Mouse Leaves"\ + "The Target Widget;\n\nBT_CLICK: The BalloonTip Is Destroyed When\n"\ + "You Click Any Region Of The BalloonTip;\n\nBT_BUTTON: The BalloonTip"\ + " Is Destroyed When\nYou Click On The Top-Right Small Button." + msg9 = "Some Comments On Delay Time:\n\nBy Default, The Delay Time After Which\n"\ + "The BalloonTip Is Destroyed Is Very Long.\nYou Can Change It By Using"\ + " The\nSetEndDelay() Method." + msg10 = "I Have Nothing Special To Suggest!\n\nRead Me FAST, You Have Only 3 "\ + "Seconds!" + msg11 = "I Hope You Will Enjoy BalloonTip!\nIf This Is The Case, Please\n"\ + "Post Some Comments On wxPython\nMailing List!" + msg12 = "This Button Enable/Disable Globally\nThe BalloonTip On Your Application." + msg13 = "This Is A BalloonTip For The\nTaskBar Icon Of Your Application.\n"\ + "All The Styles For BalloonTip Work." + + messages = [msg1, msg2, msg3, msg4, msg5, msg6, msg7, msg8, msg9, msg10, + msg11, msg12, msg13] + + # Declare The BalloonTip Tip Messages Colours + messagecolours = [None, None, None, wx.WHITE, wx.BLUE, + None, wx.BLUE, None, None, wx.RED, wx.GREEN, + wx.BLUE, None] + + fontone = wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, True) + fonttwo = wx.Font(8, wx.SWISS, wx.ITALIC, wx.NORMAL, False) + fontthree = wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD, True) + + # Declare The BalloonTip Tip Messages Fonts + messagefonts = [None, None, None, fontone, None, None, fonttwo, None, + fontthree, None, None, None, None] + + # Declare The BalloonTip Frame Shapes + windowshapes = [BT.BT_ROUNDED, BT.BT_RECTANGLE, BT.BT_ROUNDED, BT.BT_RECTANGLE, + BT.BT_ROUNDED, BT.BT_RECTANGLE, BT.BT_ROUNDED, BT.BT_ROUNDED, + BT.BT_ROUNDED, BT.BT_RECTANGLE, BT.BT_ROUNDED, BT.BT_RECTANGLE, BT.BT_RECTANGLE] + + # Declare The BalloonTip Destruction Style + tipstyles = [BT.BT_LEAVE, BT.BT_CLICK, BT.BT_BUTTON, BT.BT_LEAVE, BT.BT_CLICK, + BT.BT_LEAVE, BT.BT_CLICK, BT.BT_BUTTON, BT.BT_BUTTON, BT.BT_CLICK, + BT.BT_LEAVE, BT.BT_LEAVE, BT.BT_BUTTON] + + # Set The Targets/Styles For The BalloonTip + for ii, widget in enumerate(controls): + tipballoon = BT.BalloonTip(topicon=icons[ii], toptitle=titles[ii], + message=messages[ii], shape=windowshapes[ii], + tipstyle=tipstyles[ii]) + # Set The Target + tipballoon.SetTarget(widget) + # Set The Balloon Colour + tipballoon.SetBalloonColour(bgcolours[ii]) + # Set The Font For The Top Title + tipballoon.SetTitleFont(titlefonts[ii]) + # Set The Colour For The Top Title + tipballoon.SetTitleColour(titlecolours[ii]) + # Set The Font For The Tip Message + tipballoon.SetMessageFont(messagefonts[ii]) + # Set The Colour For The Tip Message + tipballoon.SetMessageColour(messagecolours[ii]) + # Set The Delay After Which The BalloonTip Is Created + tipballoon.SetStartDelay(1000) + if ii == 9: + # Set The Delay After Which The BalloonTip Is Destroyed + tipballoon.SetEndDelay(3000) + + # Store The Last BalloonTip Reference To Enable/Disable Globall The + # BalloonTip. You Can Store Any Of Them, Not Necessarily The Last One. + self.lasttip = tipballoon + self.gauge = gauge + self.count = 0 + + button2.Bind(wx.EVT_BUTTON, self.OnActivateBalloon) + self.Bind(wx.EVT_IDLE, self.IdleHandler) + + frameSizer = wx.BoxSizer(wx.VERTICAL) + frameSizer.Add(panel, 1, wx.EXPAND) + self.SetSizer(frameSizer) + frameSizer.Layout() + self.Fit() + + self.CenterOnParent() + + + def IdleHandler(self, event): + + self.count = self.count + 1 + + if self.count >= 50: + self.count = 0 + + self.gauge.SetValue(self.count) + + + def CreateMenuBar(self): + + # Make a menubar + file_menu = wx.Menu() + help_menu = wx.Menu() + + TEST_QUIT = wx.NewId() + TEST_ABOUT = wx.NewId() + + file_menu.Append(TEST_QUIT, "&Exit") + help_menu.Append(TEST_ABOUT, "&About") + + menu_bar = wx.MenuBar() + + menu_bar.Append(file_menu, "&File") + menu_bar.Append(help_menu, "&Help") + + self.Bind(wx.EVT_MENU, self.OnAbout, id=TEST_ABOUT) + self.Bind(wx.EVT_MENU, self.OnQuit, id=TEST_QUIT) + self.Bind(wx.EVT_CLOSE, self.OnQuit) + + return menu_bar + + + def OnQuit(self, event): + + self.tbicon.RemoveIcon() + self.tbicon.Destroy() + self.Destroy() + + + def OnAbout(self, event): + + msg = "This is the about dialog of the BalloonTip demo.\n\n" + \ + "Author: Andrea Gavana @ 29 May 2005\n\n" + \ + "Please report any bug/requests or improvements\n" + \ + "to me at the following adresses:\n\n" + \ + "andrea.gavana@agip.it\n" + "andrea_gavana@tin.it\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "BalloonTip Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.SetFont(wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, False, "Verdana")) + dlg.ShowModal() + dlg.Destroy() + + + def OnActivateBalloon(self, event): + + button = event.GetEventObject() + label = button.GetLabel() + tips = self.lasttip + + if label == "Disable BalloonTip": + button.SetLabel("Enable BalloonTip") + tips.EnableTip(False) + else: + button.SetLabel("Disable BalloonTip") + tips.EnableTip(True) + + event.Skip() + + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test BalloonTip ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = BalloonTipDemo(self, self.log) + self.win.Show(True) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = BT.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/ButtonPanel.py b/demo/agw/ButtonPanel.py new file mode 100644 index 00000000..7e51a733 --- /dev/null +++ b/demo/agw/ButtonPanel.py @@ -0,0 +1,891 @@ +import wx +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import buttonpanel as bp +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.buttonpanel as bp + +import images +import random + +#---------------------------------------------------------------------- + +ID_BackgroundColour = wx.NewId() +ID_GradientFrom = wx.NewId() +ID_GradientTo = wx.NewId() +ID_BorderColour = wx.NewId() +ID_CaptionColour = wx.NewId() +ID_ButtonTextColour = wx.NewId() +ID_SelectionBrush = wx.NewId() +ID_SelectionPen = wx.NewId() +ID_SeparatorColour = wx.NewId() + + +#---------------------------------------------------------------------- + +class SettingsPanel(wx.MiniFrame): + + def __init__(self, parent, id=wx.ID_ANY, title="Settings Panel", pos=wx.DefaultPosition, + size=wx.DefaultSize, + style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.FRAME_NO_TASKBAR + | wx.FRAME_FLOAT_ON_PARENT | wx.CLIP_CHILDREN): + + wx.MiniFrame.__init__(self, parent, id, title, pos, size, style) + + self.targetTitleBar = parent.titleBar + self.parent = parent + self.panel = wx.Panel(self, -1) + + self.coloursizer_staticbox = wx.StaticBox(self.panel, -1, "Colour Options") + self.bottomsizer_staticbox = wx.StaticBox(self.panel, -1, "Size Options") + self.stylesizer_staticbox = wx.StaticBox(self.panel, -1, "ButtonPanel Styles") + self.defaultstyle = wx.RadioButton(self.panel, -1, "Default Style", style=wx.RB_GROUP) + self.gradientstyle = wx.RadioButton(self.panel, -1, "Gradient Style") + self.verticalgradient = wx.RadioButton(self.panel, -1, "Vertical Gradient", style=wx.RB_GROUP) + self.horizontalgradient = wx.RadioButton(self.panel, -1, "Horizontal Gradient") + + b = self.CreateColourBitmap(wx.BLACK) + + self.bakbrush = wx.BitmapButton(self.panel, ID_BackgroundColour, b, size=wx.Size(50,25)) + self.gradientfrom = wx.BitmapButton(self.panel, ID_GradientFrom, b, size=wx.Size(50,25)) + self.gradientto = wx.BitmapButton(self.panel, ID_GradientTo, b, size=wx.Size(50,25)) + self.bordercolour = wx.BitmapButton(self.panel, ID_BorderColour, b, size=wx.Size(50,25)) + self.captioncolour = wx.BitmapButton(self.panel, ID_CaptionColour, b, size=wx.Size(50,25)) + self.textbuttoncolour = wx.BitmapButton(self.panel, ID_ButtonTextColour, b, size=wx.Size(50,25)) + self.selectionbrush = wx.BitmapButton(self.panel, ID_SelectionBrush, b, size=wx.Size(50,25)) + self.selectionpen = wx.BitmapButton(self.panel, ID_SelectionPen, b, size=wx.Size(50,25)) + self.separatorcolour = wx.BitmapButton(self.panel, ID_SeparatorColour, b, size=wx.Size(50,25)) + + self.separatorspin = wx.SpinCtrl(self.panel, -1, "7", min=3, max=20, + style=wx.SP_ARROW_KEYS) + self.marginspin = wx.SpinCtrl(self.panel, -1, "6", min=3, max=20, + style=wx.SP_ARROW_KEYS) + self.paddingspin = wx.SpinCtrl(self.panel, -1, "6", min=3, max=20, + style=wx.SP_ARROW_KEYS) + self.borderspin = wx.SpinCtrl(self.panel, -1, "3", min=3, max=7, + style=wx.SP_ARROW_KEYS) + + self.__set_properties() + self.__do_layout() + + self.Bind(wx.EVT_RADIOBUTTON, self.OnDefaultStyle, self.defaultstyle) + self.Bind(wx.EVT_RADIOBUTTON, self.OnGradientStyle, self.gradientstyle) + self.Bind(wx.EVT_RADIOBUTTON, self.OnVerticalGradient, self.verticalgradient) + self.Bind(wx.EVT_RADIOBUTTON, self.OnHorizontalGradient, self.horizontalgradient) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_BackgroundColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_GradientFrom) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_GradientTo) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_BorderColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_CaptionColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_ButtonTextColour) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_SelectionBrush) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_SelectionPen) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_SeparatorColour) + + self.Bind(wx.EVT_SPINCTRL, self.OnSeparator, self.separatorspin) + self.Bind(wx.EVT_SPINCTRL, self.OnMargins, self.marginspin) + self.Bind(wx.EVT_SPINCTRL, self.OnPadding, self.paddingspin) + self.Bind(wx.EVT_SPINCTRL, self.OnBorder, self.borderspin) + + self.Bind(wx.EVT_CLOSE, self.OnClose) + + + def __set_properties(self): + + self.defaultstyle.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + self.defaultstyle.SetValue(1) + self.gradientstyle.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + self.verticalgradient.SetValue(1) + + if self.targetTitleBar.GetStyle() & bp.BP_DEFAULT_STYLE: + self.verticalgradient.Enable(False) + self.horizontalgradient.Enable(False) + self.defaultstyle.SetValue(1) + else: + self.gradientstyle.SetValue(1) + + self.borderspin.SetValue(self.targetTitleBar.GetBPArt().GetMetric(bp.BP_BORDER_SIZE)) + self.separatorspin.SetValue(self.targetTitleBar.GetBPArt().GetMetric(bp.BP_SEPARATOR_SIZE)) + self.marginspin.SetValue(self.targetTitleBar.GetBPArt().GetMetric(bp.BP_MARGINS_SIZE).x) + self.paddingspin.SetValue(self.targetTitleBar.GetBPArt().GetMetric(bp.BP_PADDING_SIZE).x) + + self.UpdateColours() + + + def __do_layout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + buttonsizer = wx.BoxSizer(wx.HORIZONTAL) + bottomsizer = wx.StaticBoxSizer(self.bottomsizer_staticbox, wx.VERTICAL) + sizer_13 = wx.BoxSizer(wx.HORIZONTAL) + sizer_12 = wx.BoxSizer(wx.HORIZONTAL) + sizer_11 = wx.BoxSizer(wx.HORIZONTAL) + sizer_10 = wx.BoxSizer(wx.HORIZONTAL) + coloursizer = wx.StaticBoxSizer(self.coloursizer_staticbox, wx.HORIZONTAL) + rightsizer = wx.BoxSizer(wx.VERTICAL) + sizer_9 = wx.BoxSizer(wx.HORIZONTAL) + sizer_8 = wx.BoxSizer(wx.HORIZONTAL) + sizer_7 = wx.BoxSizer(wx.HORIZONTAL) + sizer_6 = wx.BoxSizer(wx.HORIZONTAL) + leftsizer = wx.BoxSizer(wx.VERTICAL) + sizer_5 = wx.BoxSizer(wx.HORIZONTAL) + sizer_4 = wx.BoxSizer(wx.HORIZONTAL) + sizer_3 = wx.BoxSizer(wx.HORIZONTAL) + sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + stylesizer = wx.StaticBoxSizer(self.stylesizer_staticbox, wx.VERTICAL) + tophsizer = wx.BoxSizer(wx.HORIZONTAL) + tophsizer2 = wx.BoxSizer(wx.VERTICAL) + + stylesizer.Add(self.defaultstyle, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 5) + + tophsizer.Add(self.gradientstyle, 0, wx.LEFT|wx.RIGHT|wx.EXPAND| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + + tophsizer2.Add(self.verticalgradient, 0, wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + tophsizer2.Add(self.horizontalgradient, 0, wx.ADJUST_MINSIZE, 0) + + tophsizer.Add(tophsizer2, 1, wx.LEFT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 10) + + stylesizer.Add(tophsizer, 1, wx.EXPAND, 0) + + mainsizer.Add(stylesizer, 0, wx.ALL|wx.EXPAND, 5) + + label_1 = wx.StaticText(self.panel, -1, "Background Brush Colour:") + sizer_1.Add(label_1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_1.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_1.Add(self.bakbrush, 0, wx.ADJUST_MINSIZE, 0) + + leftsizer.Add(sizer_1, 1, wx.EXPAND, 0) + + label_2 = wx.StaticText(self.panel, -1, "Gradient Colour From:") + sizer_2.Add(label_2, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_2.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_2.Add(self.gradientfrom, 0, wx.ADJUST_MINSIZE, 0) + + leftsizer.Add(sizer_2, 1, wx.EXPAND, 0) + + label_3 = wx.StaticText(self.panel, -1, "Gradient Colour To:") + sizer_3.Add(label_3, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_3.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_3.Add(self.gradientto, 0, wx.ADJUST_MINSIZE, 0) + + leftsizer.Add(sizer_3, 1, wx.EXPAND, 0) + + label_4 = wx.StaticText(self.panel, -1, "Border Colour:") + sizer_4.Add(label_4, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_4.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_4.Add(self.bordercolour, 0, wx.ADJUST_MINSIZE, 0) + + leftsizer.Add(sizer_4, 1, wx.EXPAND, 0) + + label_5 = wx.StaticText(self.panel, -1, "Main Caption Colour:") + sizer_5.Add(label_5, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_5.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_5.Add(self.captioncolour, 0, wx.ADJUST_MINSIZE, 0) + + leftsizer.Add(sizer_5, 1, wx.EXPAND, 0) + + coloursizer.Add(leftsizer, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + coloursizer.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + + label_6 = wx.StaticText(self.panel, -1, "Text Button Colour:") + sizer_6.Add(label_6, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_6.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_6.Add(self.textbuttoncolour, 0, wx.ADJUST_MINSIZE, 0) + + rightsizer.Add(sizer_6, 1, wx.EXPAND, 0) + + label_7 = wx.StaticText(self.panel, -1, "Selection Brush Colour:") + sizer_7.Add(label_7, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_7.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_7.Add(self.selectionbrush, 0, wx.ADJUST_MINSIZE, 0) + + rightsizer.Add(sizer_7, 1, wx.EXPAND, 0) + + label_8 = wx.StaticText(self.panel, -1, "Selection Pen Colour:") + sizer_8.Add(label_8, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_8.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_8.Add(self.selectionpen, 0, wx.ADJUST_MINSIZE, 0) + + rightsizer.Add(sizer_8, 1, wx.EXPAND, 0) + + label_9 = wx.StaticText(self.panel, -1, "Separator Colour:") + sizer_9.Add(label_9, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_9.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_9.Add(self.separatorcolour, 0, wx.ADJUST_MINSIZE, 0) + + rightsizer.Add(sizer_9, 1, wx.EXPAND, 0) + + coloursizer.Add(rightsizer, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + + mainsizer.Add(coloursizer, 0, wx.ALL|wx.EXPAND, 5) + + label_10 = wx.StaticText(self.panel, -1, "Separator Size:") + sizer_10.Add(label_10, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_10.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_10.Add(self.separatorspin, 0, wx.ALL|wx.ADJUST_MINSIZE, 5) + + bottomsizer.Add(sizer_10, 1, wx.EXPAND, 0) + + label_11 = wx.StaticText(self.panel, -1, "Margins Size:") + sizer_11.Add(label_11, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_11.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_11.Add(self.marginspin, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ADJUST_MINSIZE, 5) + + bottomsizer.Add(sizer_11, 1, wx.EXPAND, 0) + + label_12 = wx.StaticText(self.panel, -1, "Padding Size:") + sizer_12.Add(label_12, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_12.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_12.Add(self.paddingspin, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ADJUST_MINSIZE, 5) + + bottomsizer.Add(sizer_12, 1, wx.EXPAND, 0) + + label_13 = wx.StaticText(self.panel, -1, "Border Size:") + sizer_13.Add(label_13, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + sizer_13.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_13.Add(self.borderspin, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ADJUST_MINSIZE, 5) + + bottomsizer.Add(sizer_13, 1, wx.EXPAND, 0) + + mainsizer.Add(bottomsizer, 0, wx.ALL|wx.EXPAND, 5) + + self.panel.SetSizer(mainsizer) + sizer = wx.BoxSizer() + sizer.Add(self.panel, 1, wx.EXPAND) + self.SetSizer(sizer) + self.Fit() + + + def CreateColourBitmap(self, c): + + image = wx.EmptyImage(25, 14) + + for x in xrange(25): + for y in xrange(14): + pixcol = c + if x == 0 or x == 24 or y == 0 or y == 13: + pixcol = wx.BLACK + + image.SetRGB(x, y, pixcol.Red(), pixcol.Green(), pixcol.Blue()) + + return image.ConvertToBitmap() + + + def UpdateColours(self): + + bk = self.targetTitleBar.GetBPArt().GetColour(bp.BP_BACKGROUND_COLOUR) + self.bakbrush.SetBitmapLabel(self.CreateColourBitmap(bk)) + + capfrom = self.targetTitleBar.GetBPArt().GetColour(bp.BP_GRADIENT_COLOUR_FROM) + self.gradientfrom.SetBitmapLabel(self.CreateColourBitmap(capfrom)) + + capto = self.targetTitleBar.GetBPArt().GetColour(bp.BP_GRADIENT_COLOUR_TO) + self.gradientto.SetBitmapLabel(self.CreateColourBitmap(capto)) + + captxt = self.targetTitleBar.GetBPArt().GetColour(bp.BP_TEXT_COLOUR) + self.captioncolour.SetBitmapLabel(self.CreateColourBitmap(captxt)) + + bor = self.targetTitleBar.GetBPArt().GetColour(bp.BP_BORDER_COLOUR) + self.bordercolour.SetBitmapLabel(self.CreateColourBitmap(bor)) + + btntext = self.targetTitleBar.GetBPArt().GetColour(bp.BP_BUTTONTEXT_COLOUR) + self.textbuttoncolour.SetBitmapLabel(self.CreateColourBitmap(btntext)) + + selb = self.targetTitleBar.GetBPArt().GetColour(bp.BP_SELECTION_BRUSH_COLOUR) + self.selectionbrush.SetBitmapLabel(self.CreateColourBitmap(selb)) + + selp = self.targetTitleBar.GetBPArt().GetColour(bp.BP_SELECTION_PEN_COLOUR) + self.selectionpen.SetBitmapLabel(self.CreateColourBitmap(selp)) + + sepc = self.targetTitleBar.GetBPArt().GetColour(bp.BP_SEPARATOR_COLOUR) + self.separatorcolour.SetBitmapLabel(self.CreateColourBitmap(sepc)) + + + def OnDefaultStyle(self, event): + + self.verticalgradient.Enable(False) + self.horizontalgradient.Enable(False) + self.targetTitleBar.SetStyle(bp.BP_DEFAULT_STYLE) + + self.targetTitleBar.Refresh() + + event.Skip() + + + def OnGradientStyle(self, event): + + self.verticalgradient.Enable(True) + self.horizontalgradient.Enable(True) + self.targetTitleBar.SetStyle(bp.BP_USE_GRADIENT) + self.targetTitleBar.Refresh() + + event.Skip() + + + def OnVerticalGradient(self, event): + + self.targetTitleBar.GetBPArt().SetGradientType(bp.BP_GRADIENT_VERTICAL) + self.targetTitleBar.SetStyle(bp.BP_USE_GRADIENT) + self.targetTitleBar.Refresh() + + event.Skip() + + + def OnHorizontalGradient(self, event): + + self.targetTitleBar.GetBPArt().SetGradientType(bp.BP_GRADIENT_HORIZONTAL) + self.targetTitleBar.SetStyle(bp.BP_USE_GRADIENT) + self.targetTitleBar.Refresh() + + event.Skip() + + + def OnSetColour(self, event): + + dlg = wx.ColourDialog(self.parent) + + dlg.SetTitle("Colour Picker") + + if dlg.ShowModal() != wx.ID_OK: + return + + var = 0 + if event.GetId() == ID_BackgroundColour: + var = bp.BP_BACKGROUND_COLOUR + elif event.GetId() == ID_GradientFrom: + var = bp.BP_GRADIENT_COLOUR_FROM + elif event.GetId() == ID_GradientTo: + var = bp.BP_GRADIENT_COLOUR_TO + elif event.GetId() == ID_BorderColour: + var = bp.BP_BORDER_COLOUR + elif event.GetId() == ID_CaptionColour: + var = bp.BP_TEXT_COLOUR + elif event.GetId() == ID_ButtonTextColour: + var = bp.BP_BUTTONTEXT_COLOUR + elif event.GetId() == ID_SelectionBrush: + var = bp.BP_SELECTION_BRUSH_COLOUR + elif event.GetId() == ID_SelectionPen: + var = bp.BP_SELECTION_PEN_COLOUR + elif event.GetId() == ID_SeparatorColour: + var = bp.BP_SEPARATOR_COLOUR + else: + return + + self.targetTitleBar.GetBPArt().SetColour(var, dlg.GetColourData().GetColour()) + self.targetTitleBar.Refresh() + self.UpdateColours() + + self.parent.useredited = True + + + def OnSeparator(self, event): + + self.targetTitleBar.GetBPArt().SetMetric(bp.BP_SEPARATOR_SIZE, + event.GetInt()) + + self.targetTitleBar.DoLayout() + self.parent.mainPanel.Layout() + self.parent.useredited = True + + event.Skip() + + + def OnMargins(self, event): + + self.targetTitleBar.GetBPArt().SetMetric(bp.BP_MARGINS_SIZE, + wx.Size(event.GetInt(), event.GetInt())) + + self.targetTitleBar.DoLayout() + self.parent.mainPanel.Layout() + + self.parent.useredited = True + + event.Skip() + + + def OnPadding(self, event): + + self.targetTitleBar.GetBPArt().SetMetric(bp.BP_PADDING_SIZE, + wx.Size(event.GetInt(), event.GetInt())) + + self.targetTitleBar.DoLayout() + self.parent.mainPanel.Layout() + self.parent.useredited = True + + event.Skip() + + + def OnBorder(self, event): + + self.targetTitleBar.GetBPArt().SetMetric(bp.BP_BORDER_SIZE, + event.GetInt()) + + self.targetTitleBar.DoLayout() + self.parent.mainPanel.Layout() + + self.parent.useredited = True + + event.Skip() + + + def OnClose(self, event): + + self.parent.hassettingpanel = False + self.Destroy() + + +#---------------------------------------------------------------------- + +class ButtonPanelDemo(wx.Frame): + + def __init__(self, parent, id=wx.ID_ANY, title="ButtonPanel wxPython Demo ;-)", + pos=wx.DefaultPosition, size=(640, 400), style=wx.DEFAULT_FRAME_STYLE): + + wx.Frame.__init__(self, parent, id, title, pos, size, style) + + self.useredited = False + self.hassettingpanel = False + + self.SetIcon(images.Mondrian.GetIcon()) + self.CreateMenuBar() + + self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + self.statusbar.SetStatusWidths([-2, -1]) + # statusbar fields + statusbar_fields = [("ButtonPanel wxPython Demo, Andrea Gavana @ 02 Oct 2006"), + ("Welcome To wxPython!")] + + for i in range(len(statusbar_fields)): + self.statusbar.SetStatusText(statusbar_fields[i], i) + + self.mainPanel = wx.Panel(self, -1) + self.logtext = wx.TextCtrl(self.mainPanel, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY) + + vSizer = wx.BoxSizer(wx.VERTICAL) + self.mainPanel.SetSizer(vSizer) + + self.alignments = [bp.BP_ALIGN_LEFT, bp.BP_ALIGN_RIGHT, bp.BP_ALIGN_TOP, bp.BP_ALIGN_BOTTOM] + + self.alignment = bp.BP_ALIGN_LEFT + self.agwStyle = bp.BP_USE_GRADIENT + + self.titleBar = bp.ButtonPanel(self.mainPanel, -1, "A Simple Test & Demo", + agwStyle=self.agwStyle, alignment=self.alignment) + + self.created = False + self.pngs = [ (images._bp_btn1.GetBitmap(), 'label1'), + (images._bp_btn2.GetBitmap(), 'label2'), + (images._bp_btn3.GetBitmap(), 'label3'), + (images._bp_btn4.GetBitmap(), 'label4'), + ] + self.CreateButtons() + self.SetProperties() + + + def CreateMenuBar(self): + + mb = wx.MenuBar() + + file_menu = wx.Menu() + + item = wx.MenuItem(file_menu, wx.ID_ANY, "&Quit") + file_menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnClose, item) + + edit_menu = wx.Menu() + + item = wx.MenuItem(edit_menu, wx.ID_ANY, "Set Bar Text") + edit_menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnSetBarText, item) + + edit_menu.AppendSeparator() + + submenu = wx.Menu() + + item = wx.MenuItem(submenu, wx.ID_ANY, "BP_ALIGN_LEFT", kind=wx.ITEM_RADIO) + submenu.AppendItem(item) + item.Check(True) + self.Bind(wx.EVT_MENU, self.OnAlignment, item) + + item = wx.MenuItem(submenu, wx.ID_ANY, "BP_ALIGN_RIGHT", kind=wx.ITEM_RADIO) + submenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnAlignment, item) + + item = wx.MenuItem(submenu, wx.ID_ANY, "BP_ALIGN_TOP", kind=wx.ITEM_RADIO) + submenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnAlignment, item) + + item = wx.MenuItem(submenu, wx.ID_ANY, "BP_ALIGN_BOTTOM", kind=wx.ITEM_RADIO) + submenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnAlignment, item) + + edit_menu.AppendMenu(wx.ID_ANY, "&Alignment", submenu) + + submenu = wx.Menu() + + item = wx.MenuItem(submenu, wx.ID_ANY, "Default Style", kind=wx.ITEM_RADIO) + submenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnDefaultStyle, item) + + item = wx.MenuItem(submenu, wx.ID_ANY, "Gradient Style", kind=wx.ITEM_RADIO) + submenu.AppendItem(item) + item.Check(True) + self.Bind(wx.EVT_MENU, self.OnGradientStyle, item) + + edit_menu.AppendMenu(wx.ID_ANY, "&Styles", submenu) + + edit_menu.AppendSeparator() + + item = wx.MenuItem(submenu, wx.ID_ANY, "Settings Panel") + edit_menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnSettingsPanel, item) + + demo_menu = wx.Menu() + + item = wx.MenuItem(demo_menu, wx.ID_ANY, "Default Demo", kind=wx.ITEM_RADIO) + demo_menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnDefaultDemo, item) + + item = wx.MenuItem(demo_menu, wx.ID_ANY, "Button Only Demo", kind=wx.ITEM_RADIO) + demo_menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnButtonOnly, item) + + help_menu = wx.Menu() + + item = wx.MenuItem(help_menu, wx.ID_ANY, "&About...") + help_menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnAbout, item) + + mb.Append(file_menu, "&File") + mb.Append(edit_menu, "&Edit") + mb.Append(demo_menu, "&Demo") + mb.Append(help_menu, "&Help") + + self.SetMenuBar(mb) + + + def CreateButtons(self): + + # Here we (re)create the buttons for the default startup demo + self.Freeze() + + if self.created: + sizer = self.mainPanel.GetSizer() + sizer.Detach(0) + self.titleBar.Hide() + wx.CallAfter(self.titleBar.Destroy) + self.titleBar = bp.ButtonPanel(self.mainPanel, -1, "A Simple Test & Demo", + agwStyle=self.agwStyle, alignment=self.alignment) + self.SetProperties() + + self.indices = [] + + for count, png in enumerate(self.pngs): + + shortHelp = "Button %d"%(count+1) + + if count < 2: + # First 2 buttons are togglebuttons + kind = wx.ITEM_CHECK + longHelp = "ButtonPanel Toggle Button No %d"%(count+1) + else: + kind = wx.ITEM_NORMAL + longHelp = "Simple Button without label No %d"%(count+1) + + btn = bp.ButtonInfo(self.titleBar, wx.NewId(), + png[0], kind=kind, + shortHelp=shortHelp, longHelp=longHelp) + + self.titleBar.AddButton(btn) + self.Bind(wx.EVT_BUTTON, self.OnButton, id=btn.GetId()) + + self.indices.append(btn.GetId()) + + if count < 2: + # First 2 buttons have also a text + btn.SetText(png[1]) + + if count == 2: + # Append a separator after the second button + self.titleBar.AddSeparator() + + if count == 1: + # Add a wx.TextCtrl to ButtonPanel + self.titleBar.AddControl(wx.TextCtrl(self.titleBar, -1, "Hello wxPython!")) + btn.SetTextAlignment(bp.BP_BUTTONTEXT_ALIGN_RIGHT) + + # Add a wx.Choice to ButtonPanel + self.titleBar.AddControl(wx.Choice(self.titleBar, -1, + choices=["Hello", "From", "wxPython!"])) + + self.strings = ["First", "Second", "Third", "Fourth"] + + self.ChangeLayout() + self.Thaw() + self.titleBar.DoLayout() + + self.created = True + + + def ButtonOnly(self): + + # Here we (re)create the buttons for the button-only demo + self.Freeze() + + if self.created: + sizer = self.mainPanel.GetSizer() + sizer.Detach(0) + self.titleBar.Hide() + wx.CallAfter(self.titleBar.Destroy) + self.titleBar = bp.ButtonPanel(self.mainPanel, -1, "A Simple Test & Demo", + agwStyle=self.agwStyle, alignment=self.alignment) + self.SetProperties() + + # Buttons are created completely random, with random images, toggle behavior + # and text + + self.indices = [] + + for count in xrange(8): + + itemImage = random.randint(0, 3) + hasText = random.randint(0, 1) + itemKind = random.randint(0, 1) + + btn = bp.ButtonInfo(self.titleBar, wx.NewId(), self.pngs[itemImage][0], + kind=itemKind) + + if hasText: + btn.SetText(self.pngs[itemImage][1]) + rightText = random.randint(0, 1) + if rightText: + btn.SetTextAlignment(bp.BP_BUTTONTEXT_ALIGN_RIGHT) + + self.titleBar.AddButton(btn) + self.Bind(wx.EVT_BUTTON, self.OnButton, id=btn.GetId()) + + self.indices.append(btn.GetId()) + + if count in [0, 3, 5]: + self.titleBar.AddSeparator() + + self.strings = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth"] + + self.ChangeLayout() + self.Thaw() + self.titleBar.DoLayout() + + + def ChangeLayout(self): + + # Change the layout after a switch in ButtonPanel alignment + self.Freeze() + + if self.alignment in [bp.BP_ALIGN_LEFT, bp.BP_ALIGN_RIGHT]: + vSizer = wx.BoxSizer(wx.VERTICAL) + else: + vSizer = wx.BoxSizer(wx.HORIZONTAL) + + self.mainPanel.SetSizer(vSizer) + + vSizer.Add(self.titleBar, 0, wx.EXPAND) + vSizer.Add((20, 20)) + vSizer.Add(self.logtext, 1, wx.EXPAND|wx.ALL, 5) + + vSizer.Layout() + self.mainPanel.Layout() + self.Thaw() + + + def SetProperties(self): + + # No resetting if the user is using the Settings Panel + if self.useredited: + return + + # Sets the colours for the two demos: called only if the user didn't + # modify the colours and sizes using the Settings Panel + bpArt = self.titleBar.GetBPArt() + + if self.agwStyle & bp.BP_USE_GRADIENT: + # set the colour the text is drawn with + bpArt.SetColour(bp.BP_TEXT_COLOUR, wx.WHITE) + + # These default to white and whatever is set in the system + # settings for the wx.SYS_COLOUR_ACTIVECAPTION. We'll use + # some specific settings to ensure a consistent look for the + # demo. + bpArt.SetColour(bp.BP_BORDER_COLOUR, wx.Colour(120,23,224)) + bpArt.SetColour(bp.BP_GRADIENT_COLOUR_FROM, wx.Colour(60,11,112)) + bpArt.SetColour(bp.BP_GRADIENT_COLOUR_TO, wx.Colour(120,23,224)) + bpArt.SetColour(bp.BP_BUTTONTEXT_COLOUR, wx.Colour(70,143,255)) + bpArt.SetColour(bp.BP_SEPARATOR_COLOUR, + bp.BrightenColour(wx.Colour(60, 11, 112), 0.85)) + bpArt.SetColour(bp.BP_SELECTION_BRUSH_COLOUR, wx.Colour(225, 225, 255)) + bpArt.SetColour(bp.BP_SELECTION_PEN_COLOUR, wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)) + + else: + + background = self.titleBar.GetBackgroundColour() + bpArt.SetColour(bp.BP_TEXT_COLOUR, wx.BLUE) + bpArt.SetColour(bp.BP_BORDER_COLOUR, + bp.BrightenColour(background, 0.85)) + bpArt.SetColour(bp.BP_SEPARATOR_COLOUR, + bp.BrightenColour(background, 0.85)) + bpArt.SetColour(bp.BP_BUTTONTEXT_COLOUR, wx.BLACK) + bpArt.SetColour(bp.BP_SELECTION_BRUSH_COLOUR, wx.Colour(242, 242, 235)) + bpArt.SetColour(bp.BP_SELECTION_PEN_COLOUR, wx.Colour(206, 206, 195)) + + self.titleBar.SetStyle(self.agwStyle) + + + def OnAlignment(self, event): + + # Here we change the alignment property of ButtonPanel + current = event.GetId() + item = self.GetMenuBar().FindItemById(current) + alignment = getattr(bp, item.GetLabel()) + self.alignment = alignment + + self.ChangeLayout() + self.titleBar.SetAlignment(alignment) + self.mainPanel.Layout() + + event.Skip() + + + def OnDefaultStyle(self, event): + + # Restore the ButtonPanel default style (no gradient) + self.agwStyle = bp.BP_DEFAULT_STYLE + self.SetProperties() + + event.Skip() + + + def OnGradientStyle(self, event): + + # Use gradients to paint ButtonPanel background + self.agwStyle = bp.BP_USE_GRADIENT + self.SetProperties() + + event.Skip() + + + def OnDefaultDemo(self, event): + + # Reload the default startup demo + self.CreateButtons() + event.Skip() + + + def OnButtonOnly(self, event): + + # Reload the button-only demo + self.ButtonOnly() + event.Skip() + + + def OnButton(self, event): + + btn = event.GetId() + indx = self.indices.index(btn) + + self.logtext.AppendText("Event Fired From " + self.strings[indx] + " Button\n") + event.Skip() + + + def OnSetBarText(self, event): + + dlg = wx.TextEntryDialog(self, "Enter The Text You Wish To Display On The Bar (Clear If No Text):", + "Set Text", self.titleBar.GetBarText()) + + if dlg.ShowModal() == wx.ID_OK: + + val = dlg.GetValue() + self.titleBar.SetBarText(val) + self.titleBar.DoLayout() + self.mainPanel.Layout() + + + def OnSettingsPanel(self, event): + + if self.hassettingpanel: + self.settingspanel.Raise() + return + + self.settingspanel = SettingsPanel(self, -1) + self.settingspanel.Show() + self.hassettingpanel = True + + + def OnClose(self, event): + + self.Destroy() + event.Skip() + + + def OnAbout(self, event): + + msg = "This Is The About Dialog Of The ButtonPanel Demo.\n\n" + \ + "Author: Andrea Gavana @ 02 Oct 2006\n\n" + \ + "Please Report Any Bug/Requests Of Improvements\n" + \ + "To Me At The Following Adresses:\n\n" + \ + "andrea.gavana@gmail.com\n" + "andrea.gavana@maerskoil.com\n\n" + \ + "Based On Eran C++ Implementation (wxWidgets Forum).\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "ButtonPanel wxPython Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test ButtonPanel ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = ButtonPanelDemo(self) + self.win.Show(True) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = bp.__doc__ + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + diff --git a/demo/agw/CubeColourDialog.py b/demo/agw/CubeColourDialog.py new file mode 100644 index 00000000..a615818a --- /dev/null +++ b/demo/agw/CubeColourDialog.py @@ -0,0 +1,81 @@ +import wx + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import cubecolourdialog as CCD +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.cubecolourdialog as CCD + + +class CubeColourDialogDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent, -1) + + static = wx.StaticText(self, -1, "Notice the panel background colour!", (50, 50)) + b = wx.Button(self, -1, "Create and Show a CubeColourDialog", (50, 70)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + self.log = log + + + def OnButton(self, evt): + + if not hasattr(self, "colourData"): + self.colourData = wx.ColourData() + + self.colourData.SetColour(self.GetBackgroundColour()) + + dlg = CCD.CubeColourDialog(self, self.colourData) + + if dlg.ShowModal() == wx.ID_OK: + + # If the user selected OK, then the dialog's wx.ColourData will + # contain valid information. Fetch the data ... + self.colourData = dlg.GetColourData() + h, s, v, a = dlg.GetHSVAColour() + + # ... then do something with it. The actual colour data will be + # returned as a three-tuple (r, g, b) in this particular case. + colour = self.colourData.GetColour() + self.log.WriteText('You selected: %s: %d, %s: %d, %s: %d, %s: %d\n' % ("Red", colour.Red(), + "Green", colour.Green(), + "Blue", colour.Blue(), + "Alpha", colour.Alpha())) + self.log.WriteText('HSVA Components: %s: %d, %s: %d, %s: %d, %s: %d\n\n' % ("Hue", h, + "Saturation", s, + "Brightness", v, + "Alpha", a)) + self.SetBackgroundColour(self.colourData.GetColour()) + self.Refresh() + + # Once the dialog is destroyed, Mr. wx.ColourData is no longer your + # friend. Don't use it again! + dlg.Destroy() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = CubeColourDialogDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = CCD.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/CustomTreeCtrl.py b/demo/agw/CustomTreeCtrl.py new file mode 100644 index 00000000..67a0b27a --- /dev/null +++ b/demo/agw/CustomTreeCtrl.py @@ -0,0 +1,2037 @@ +import wx +import string +import os +import sys +import random + +import wx.lib.colourselect as csel + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +bitmapDir = os.path.join(dirName, 'bitmaps') +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import customtreectrl as CT +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.customtreectrl as CT + +import images + +#--------------------------------------------------------------------------- + + +penstyle = ["wx.SOLID", "wx.TRANSPARENT", "wx.DOT", "wx.LONG_DASH", "wx.DOT_DASH", "wx.USER_DASH", + "wx.BDIAGONAL_HATCH", "wx.CROSSDIAG_HATCH", "wx.FDIAGONAL_HATCH", "wx.CROSS_HATCH", + "wx.HORIZONTAL_HATCH", "wx.VERTICAL_HATCH"] + +ArtIDs = [ "None", + "wx.ART_ADD_BOOKMARK", + "wx.ART_DEL_BOOKMARK", + "wx.ART_HELP_SIDE_PANEL", + "wx.ART_HELP_SETTINGS", + "wx.ART_HELP_BOOK", + "wx.ART_HELP_FOLDER", + "wx.ART_HELP_PAGE", + "wx.ART_GO_BACK", + "wx.ART_GO_FORWARD", + "wx.ART_GO_UP", + "wx.ART_GO_DOWN", + "wx.ART_GO_TO_PARENT", + "wx.ART_GO_HOME", + "wx.ART_FILE_OPEN", + "wx.ART_PRINT", + "wx.ART_HELP", + "wx.ART_TIP", + "wx.ART_REPORT_VIEW", + "wx.ART_LIST_VIEW", + "wx.ART_NEW_DIR", + "wx.ART_HARDDISK", + "wx.ART_FLOPPY", + "wx.ART_CDROM", + "wx.ART_REMOVABLE", + "wx.ART_FOLDER", + "wx.ART_FOLDER_OPEN", + "wx.ART_GO_DIR_UP", + "wx.ART_EXECUTABLE_FILE", + "wx.ART_NORMAL_FILE", + "wx.ART_TICK_MARK", + "wx.ART_CROSS_MARK", + "wx.ART_ERROR", + "wx.ART_QUESTION", + "wx.ART_WARNING", + "wx.ART_INFORMATION", + "wx.ART_MISSING_IMAGE", + "SmileBitmap" + ] + +keyMap = { + wx.WXK_BACK : "WXK_BACK", + wx.WXK_TAB : "WXK_TAB", + wx.WXK_RETURN : "WXK_RETURN", + wx.WXK_ESCAPE : "WXK_ESCAPE", + wx.WXK_SPACE : "WXK_SPACE", + wx.WXK_DELETE : "WXK_DELETE", + wx.WXK_START : "WXK_START", + wx.WXK_LBUTTON : "WXK_LBUTTON", + wx.WXK_RBUTTON : "WXK_RBUTTON", + wx.WXK_CANCEL : "WXK_CANCEL", + wx.WXK_MBUTTON : "WXK_MBUTTON", + wx.WXK_CLEAR : "WXK_CLEAR", + wx.WXK_SHIFT : "WXK_SHIFT", + wx.WXK_ALT : "WXK_ALT", + wx.WXK_CONTROL : "WXK_CONTROL", + wx.WXK_MENU : "WXK_MENU", + wx.WXK_PAUSE : "WXK_PAUSE", + wx.WXK_CAPITAL : "WXK_CAPITAL", + wx.WXK_PRIOR : "WXK_PRIOR", + wx.WXK_NEXT : "WXK_NEXT", + wx.WXK_END : "WXK_END", + wx.WXK_HOME : "WXK_HOME", + wx.WXK_LEFT : "WXK_LEFT", + wx.WXK_UP : "WXK_UP", + wx.WXK_RIGHT : "WXK_RIGHT", + wx.WXK_DOWN : "WXK_DOWN", + wx.WXK_SELECT : "WXK_SELECT", + wx.WXK_PRINT : "WXK_PRINT", + wx.WXK_EXECUTE : "WXK_EXECUTE", + wx.WXK_SNAPSHOT : "WXK_SNAPSHOT", + wx.WXK_INSERT : "WXK_INSERT", + wx.WXK_HELP : "WXK_HELP", + wx.WXK_NUMPAD0 : "WXK_NUMPAD0", + wx.WXK_NUMPAD1 : "WXK_NUMPAD1", + wx.WXK_NUMPAD2 : "WXK_NUMPAD2", + wx.WXK_NUMPAD3 : "WXK_NUMPAD3", + wx.WXK_NUMPAD4 : "WXK_NUMPAD4", + wx.WXK_NUMPAD5 : "WXK_NUMPAD5", + wx.WXK_NUMPAD6 : "WXK_NUMPAD6", + wx.WXK_NUMPAD7 : "WXK_NUMPAD7", + wx.WXK_NUMPAD8 : "WXK_NUMPAD8", + wx.WXK_NUMPAD9 : "WXK_NUMPAD9", + wx.WXK_MULTIPLY : "WXK_MULTIPLY", + wx.WXK_ADD : "WXK_ADD", + wx.WXK_SEPARATOR : "WXK_SEPARATOR", + wx.WXK_SUBTRACT : "WXK_SUBTRACT", + wx.WXK_DECIMAL : "WXK_DECIMAL", + wx.WXK_DIVIDE : "WXK_DIVIDE", + wx.WXK_F1 : "WXK_F1", + wx.WXK_F2 : "WXK_F2", + wx.WXK_F3 : "WXK_F3", + wx.WXK_F4 : "WXK_F4", + wx.WXK_F5 : "WXK_F5", + wx.WXK_F6 : "WXK_F6", + wx.WXK_F7 : "WXK_F7", + wx.WXK_F8 : "WXK_F8", + wx.WXK_F9 : "WXK_F9", + wx.WXK_F10 : "WXK_F10", + wx.WXK_F11 : "WXK_F11", + wx.WXK_F12 : "WXK_F12", + wx.WXK_F13 : "WXK_F13", + wx.WXK_F14 : "WXK_F14", + wx.WXK_F15 : "WXK_F15", + wx.WXK_F16 : "WXK_F16", + wx.WXK_F17 : "WXK_F17", + wx.WXK_F18 : "WXK_F18", + wx.WXK_F19 : "WXK_F19", + wx.WXK_F20 : "WXK_F20", + wx.WXK_F21 : "WXK_F21", + wx.WXK_F22 : "WXK_F22", + wx.WXK_F23 : "WXK_F23", + wx.WXK_F24 : "WXK_F24", + wx.WXK_NUMLOCK : "WXK_NUMLOCK", + wx.WXK_SCROLL : "WXK_SCROLL", + wx.WXK_PAGEUP : "WXK_PAGEUP", + wx.WXK_PAGEDOWN : "WXK_PAGEDOWN", + wx.WXK_NUMPAD_SPACE : "WXK_NUMPAD_SPACE", + wx.WXK_NUMPAD_TAB : "WXK_NUMPAD_TAB", + wx.WXK_NUMPAD_ENTER : "WXK_NUMPAD_ENTER", + wx.WXK_NUMPAD_F1 : "WXK_NUMPAD_F1", + wx.WXK_NUMPAD_F2 : "WXK_NUMPAD_F2", + wx.WXK_NUMPAD_F3 : "WXK_NUMPAD_F3", + wx.WXK_NUMPAD_F4 : "WXK_NUMPAD_F4", + wx.WXK_NUMPAD_HOME : "WXK_NUMPAD_HOME", + wx.WXK_NUMPAD_LEFT : "WXK_NUMPAD_LEFT", + wx.WXK_NUMPAD_UP : "WXK_NUMPAD_UP", + wx.WXK_NUMPAD_RIGHT : "WXK_NUMPAD_RIGHT", + wx.WXK_NUMPAD_DOWN : "WXK_NUMPAD_DOWN", + wx.WXK_NUMPAD_PRIOR : "WXK_NUMPAD_PRIOR", + wx.WXK_NUMPAD_PAGEUP : "WXK_NUMPAD_PAGEUP", + wx.WXK_NUMPAD_NEXT : "WXK_NUMPAD_NEXT", + wx.WXK_NUMPAD_PAGEDOWN : "WXK_NUMPAD_PAGEDOWN", + wx.WXK_NUMPAD_END : "WXK_NUMPAD_END", + wx.WXK_NUMPAD_BEGIN : "WXK_NUMPAD_BEGIN", + wx.WXK_NUMPAD_INSERT : "WXK_NUMPAD_INSERT", + wx.WXK_NUMPAD_DELETE : "WXK_NUMPAD_DELETE", + wx.WXK_NUMPAD_EQUAL : "WXK_NUMPAD_EQUAL", + wx.WXK_NUMPAD_MULTIPLY : "WXK_NUMPAD_MULTIPLY", + wx.WXK_NUMPAD_ADD : "WXK_NUMPAD_ADD", + wx.WXK_NUMPAD_SEPARATOR : "WXK_NUMPAD_SEPARATOR", + wx.WXK_NUMPAD_SUBTRACT : "WXK_NUMPAD_SUBTRACT", + wx.WXK_NUMPAD_DECIMAL : "WXK_NUMPAD_DECIMAL", + wx.WXK_NUMPAD_DIVIDE : "WXK_NUMPAD_DIVIDE" + } + + + +#--------------------------------------------------------------------------- +# Just A Dialog To Select Pen Styles +#--------------------------------------------------------------------------- +class PenDialog(wx.Dialog): + + def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, oldpen=None, + pentype=0): + + wx.Dialog.__init__(self, parent, id, title, pos, size, style) + + self.colourbutton = csel.ColourSelect(self) + self.spinwidth = wx.SpinCtrl(self, -1, "1", min=1, max=3, style=wx.SP_ARROW_KEYS) + + self.combostyle = wx.ComboBox(self, -1, choices=penstyle, style=wx.CB_DROPDOWN|wx.CB_READONLY) + + choices = ["[1, 1]", "[2, 2]", "[3, 3]", "[4, 4]"] + self.combodash = wx.ComboBox(self, -1, choices=choices, style=wx.CB_DROPDOWN|wx.CB_READONLY) + + self.okbutton = wx.Button(self, wx.ID_OK) + self.cancelbutton = wx.Button(self, wx.ID_CANCEL) + + self.oldpen = oldpen + self.parent = parent + self.pentype = pentype + + self.SetProperties() + self.DoLayout() + + self.Bind(wx.EVT_COMBOBOX, self.OnStyle, self.combostyle) + self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton) + self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton) + + + def SetProperties(self): + + self.SetTitle("Pen Dialog Selector") + self.colourbutton.SetMinSize((25, 25)) + self.colourbutton.SetColour(self.oldpen.GetColour()) + + style = self.oldpen.GetStyle() + for count, st in enumerate(penstyle): + if eval(st) == style: + self.combostyle.SetSelection(count) + if count == 5: + self.combodash.Enable(True) + else: + self.combodash.Enable(False) + break + + if self.combodash.IsEnabled(): + dashes = repr(self.oldpen.GetDashes()) + self.combodash.SetValue(dashes) + + self.spinwidth.SetValue(self.oldpen.GetWidth()) + self.okbutton.SetDefault() + + if self.pentype == 1: + self.spinwidth.Enable(False) + + + def DoLayout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + bottomsizer = wx.BoxSizer(wx.HORIZONTAL) + middlesizer = wx.BoxSizer(wx.VERTICAL) + stylesizer = wx.BoxSizer(wx.HORIZONTAL) + widthsizer = wx.BoxSizer(wx.HORIZONTAL) + coloursizer = wx.BoxSizer(wx.HORIZONTAL) + label_1 = wx.StaticText(self, -1, "Please Choose The Pen Settings:") + label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10) + label_2 = wx.StaticText(self, -1, "Pen Colour") + coloursizer.Add(label_2, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + coloursizer.Add((5, 5), 1, wx.ADJUST_MINSIZE, 0) + coloursizer.Add(self.colourbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 5) + middlesizer.Add(coloursizer, 0, wx.EXPAND, 0) + label_3 = wx.StaticText(self, -1, "Pen Width") + widthsizer.Add(label_3, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + widthsizer.Add((5, 5), 1, wx.ADJUST_MINSIZE, 0) + widthsizer.Add(self.spinwidth, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + middlesizer.Add(widthsizer, 0, wx.EXPAND, 0) + label_4 = wx.StaticText(self, -1, "Pen Style") + stylesizer.Add(label_4, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + stylesizer.Add((5, 5), 1, wx.ADJUST_MINSIZE, 0) + stylesizer.Add(self.combostyle, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + stylesizer.Add(self.combodash, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + middlesizer.Add(stylesizer, 0, wx.BOTTOM|wx.EXPAND, 5) + mainsizer.Add(middlesizer, 1, wx.EXPAND, 0) + bottomsizer.Add(self.okbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20) + bottomsizer.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + bottomsizer.Add(self.cancelbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20) + mainsizer.Add(bottomsizer, 0, wx.EXPAND, 0) + self.SetAutoLayout(True) + self.SetSizer(mainsizer) + mainsizer.Fit(self) + mainsizer.SetSizeHints(self) + self.Layout() + self.Centre() + + + def OnStyle(self, event): + + choice = event.GetEventObject().GetValue() + self.combodash.Enable(choice==5) + event.Skip() + + + def OnOk(self, event): + + colour = self.colourbutton.GetColour() + style = eval(self.combostyle.GetValue()) + width = int(self.spinwidth.GetValue()) + + dashes = None + if self.combostyle.GetSelection() == 5: + dashes = eval(self.combodash.GetValue()) + + pen = wx.Pen(colour, width, style) + + if dashes: + pen.SetDashes(dashes) + + pen.SetCap(wx.CAP_BUTT) + + if self.pentype == 0: + self.parent.SetConnectionPen(pen) + else: + self.parent.SetBorderPen(pen) + + self.Destroy() + event.Skip() + + + def OnCancel(self, event): + + self.Destroy() + event.Skip() + + +#--------------------------------------------------------------------------- +# Just A Dialog To Select Tree Buttons Icons +#--------------------------------------------------------------------------- +class TreeButtonsDialog(wx.Dialog): + + def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, oldicons=None): + + wx.Dialog.__init__(self, parent, id, title, pos, size, style) + + self.listicons = wx.ListBox(self, -1, choices=["Set 1", "Set 2", "Set 3", "Set 4", "Set 5"], style=wx.LB_SINGLE) + + bitmap_plus = os.path.normpath(os.path.join(bitmapDir, "plus" + str(oldicons+1) + ".ico")) + bitmap_minus = os.path.normpath(os.path.join(bitmapDir, "minus" + str(oldicons+1) + ".ico")) + + bitmap_plus = wx.Image(bitmap_plus, wx.BITMAP_TYPE_ICO) + bitmap_plus.Rescale(24, 24) + bitmap_plus = bitmap_plus.ConvertToBitmap() + bitmap_minus = wx.Image(bitmap_minus, wx.BITMAP_TYPE_ICO) + bitmap_minus.Rescale(24, 24) + bitmap_minus = bitmap_minus.ConvertToBitmap() + + self.bitmap_plus = wx.StaticBitmap(self, -1, bitmap_plus) + self.bitmap_minus = wx.StaticBitmap(self, -1, bitmap_minus) + + self.okbutton = wx.Button(self, wx.ID_OK) + self.cancelbutton = wx.Button(self, wx.ID_CANCEL) + + self.parent = parent + + self.SetProperties() + self.DoLayout() + + self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton) + self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton) + self.Bind(wx.EVT_LISTBOX, self.OnListBox, self.listicons) + + + def SetProperties(self): + + self.SetTitle("Tree Buttons Selector") + self.listicons.SetSelection(0) + self.okbutton.SetDefault() + + + def DoLayout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + bottomsizer = wx.BoxSizer(wx.HORIZONTAL) + topsizer = wx.BoxSizer(wx.HORIZONTAL) + rightsizer = wx.BoxSizer(wx.VERTICAL) + sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + label_1 = wx.StaticText(self, -1, "Please Choose One Of These Sets Of Icons:") + label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10) + topsizer.Add(self.listicons, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 5) + label_2 = wx.StaticText(self, -1, "Collapsed") + sizer_1.Add(label_2, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_1.Add((20, 20), 1, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0) + sizer_1.Add(self.bitmap_plus, 1, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_1, 0, wx.EXPAND, 0) + label_3 = wx.StaticText(self, -1, "Expanded") + sizer_2.Add(label_3, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_2.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + sizer_2.Add(self.bitmap_minus, 1, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_2, 0, wx.EXPAND, 0) + topsizer.Add(rightsizer, 0, wx.ALL|wx.EXPAND, 5) + mainsizer.Add(topsizer, 1, wx.EXPAND, 0) + bottomsizer.Add(self.okbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20) + bottomsizer.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + bottomsizer.Add(self.cancelbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20) + mainsizer.Add(bottomsizer, 0, wx.EXPAND, 0) + self.SetAutoLayout(True) + self.SetSizer(mainsizer) + mainsizer.Fit(self) + mainsizer.SetSizeHints(self) + self.Layout() + + + def OnListBox(self, event): + + selection = self.listicons.GetSelection() + bitmap_plus = os.path.normpath(os.path.join(bitmapDir, "plus" + str(selection+1) + ".ico")) + bitmap_minus = os.path.normpath(os.path.join(bitmapDir, "minus" + str(selection+1) + ".ico")) + + bitmap_plus = wx.Image(bitmap_plus, wx.BITMAP_TYPE_ICO) + bitmap_plus.Rescale(24, 24) + bitmap_plus = bitmap_plus.ConvertToBitmap() + bitmap_minus = wx.Image(bitmap_minus, wx.BITMAP_TYPE_ICO) + bitmap_minus.Rescale(24, 24) + bitmap_minus = bitmap_minus.ConvertToBitmap() + + self.bitmap_plus.SetBitmap(bitmap_plus) + self.bitmap_minus.SetBitmap(bitmap_minus) + + self.bitmap_plus.Refresh() + self.bitmap_minus.Refresh() + event.Skip() + + + def OnOk(self, event): + + selection = self.listicons.GetSelection() + self.parent.SetTreeButtons(selection) + self.Destroy() + event.Skip() + + + def OnCancel(self, event): + + self.Destroy() + event.Skip() + + +#--------------------------------------------------------------------------- +# Just A Dialog To Select Tree Check/Radio Item Icons +#--------------------------------------------------------------------------- +class CheckDialog(wx.Dialog): + + def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE): + + wx.Dialog.__init__(self, parent, id, title, pos, size, style) + + self.listicons = wx.ListBox(self, -1, choices=["Set 1", "Set 2"], style=wx.LB_SINGLE) + + bitmap_check = wx.Bitmap(os.path.normpath(os.path.join(bitmapDir, "checked.ico")), wx.BITMAP_TYPE_ICO) + bitmap_uncheck = wx.Bitmap(os.path.normpath(os.path.join(bitmapDir, "notchecked.ico")), wx.BITMAP_TYPE_ICO) + bitmap_flag = wx.Bitmap(os.path.normpath(os.path.join(bitmapDir, "flagged.ico")), wx.BITMAP_TYPE_ICO) + bitmap_unflag = wx.Bitmap(os.path.normpath(os.path.join(bitmapDir, "notflagged.ico")), wx.BITMAP_TYPE_ICO) + + self.bitmap_check = wx.StaticBitmap(self, -1, bitmap_check) + self.bitmap_uncheck = wx.StaticBitmap(self, -1, bitmap_uncheck) + self.bitmap_flag = wx.StaticBitmap(self, -1, bitmap_flag) + self.bitmap_unflag = wx.StaticBitmap(self, -1, bitmap_unflag) + + self.okbutton = wx.Button(self, wx.ID_OK) + self.cancelbutton = wx.Button(self, wx.ID_CANCEL) + + self.parent = parent + + self.SetProperties() + self.DoLayout() + + self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton) + self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton) + self.Bind(wx.EVT_LISTBOX, self.OnListBox, self.listicons) + + + def SetProperties(self): + + self.SetTitle("Check/Radio Icon Selector") + self.listicons.SetSelection(0) + self.okbutton.SetDefault() + + + def DoLayout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + bottomsizer = wx.BoxSizer(wx.HORIZONTAL) + topsizer = wx.BoxSizer(wx.HORIZONTAL) + rightsizer = wx.BoxSizer(wx.VERTICAL) + sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + sizer_3 = wx.BoxSizer(wx.HORIZONTAL) + sizer_4 = wx.BoxSizer(wx.HORIZONTAL) + label_1 = wx.StaticText(self, -1, "Please Choose One Of These Sets Of Icons:") + label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10) + topsizer.Add(self.listicons, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 5) + label_2 = wx.StaticText(self, -1, "Checked") + sizer_1.Add(label_2, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_1.Add((20, 20), 1, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0) + sizer_1.Add(self.bitmap_check, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_1, 0, wx.EXPAND, 0) + label_3 = wx.StaticText(self, -1, "Not Checked") + sizer_2.Add(label_3, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_2.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + sizer_2.Add(self.bitmap_uncheck, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_2, 0, wx.EXPAND, 0) + label_4 = wx.StaticText(self, -1, "Flagged") + sizer_3.Add(label_4, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_3.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + sizer_3.Add(self.bitmap_flag, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_3, 0, wx.EXPAND, 0) + label_5 = wx.StaticText(self, -1, "Not Flagged") + sizer_4.Add(label_5, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_4.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + sizer_4.Add(self.bitmap_unflag, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_4, 0, wx.EXPAND, 0) + + topsizer.Add(rightsizer, 0, wx.ALL|wx.EXPAND, 5) + mainsizer.Add(topsizer, 1, wx.EXPAND, 0) + bottomsizer.Add(self.okbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20) + bottomsizer.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + bottomsizer.Add(self.cancelbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20) + mainsizer.Add(bottomsizer, 0, wx.EXPAND, 0) + self.SetAutoLayout(True) + self.SetSizer(mainsizer) + mainsizer.Fit(self) + mainsizer.SetSizeHints(self) + self.Layout() + + + def OnListBox(self, event): + + selection = self.listicons.GetSelection() + + if selection == 0: + bitmap_check = os.path.normpath(os.path.join(bitmapDir, "checked.ico")) + bitmap_uncheck = os.path.normpath(os.path.join(bitmapDir, "notchecked.ico")) + bitmap_flag = os.path.normpath(os.path.join(bitmapDir, "flagged.ico")) + bitmap_unflag = os.path.normpath(os.path.join(bitmapDir, "notflagged.ico")) + else: + bitmap_check = os.path.normpath(os.path.join(bitmapDir, "aquachecked.ico")) + bitmap_uncheck = os.path.normpath(os.path.join(bitmapDir, "aquanotchecked.ico")) + bitmap_flag = os.path.normpath(os.path.join(bitmapDir, "aquaflagged.ico")) + bitmap_unflag = os.path.normpath(os.path.join(bitmapDir, "aquanotflagged.ico")) + + bitmap_check = wx.Bitmap(bitmap_check, wx.BITMAP_TYPE_ICO) + bitmap_uncheck = wx.Bitmap(bitmap_uncheck, wx.BITMAP_TYPE_ICO) + bitmap_flag = wx.Bitmap(bitmap_flag, wx.BITMAP_TYPE_ICO) + bitmap_unflag = wx.Bitmap(bitmap_unflag, wx.BITMAP_TYPE_ICO) + + self.bitmap_uncheck.SetBitmap(bitmap_uncheck) + self.bitmap_check.SetBitmap(bitmap_check) + self.bitmap_unflag.SetBitmap(bitmap_unflag) + self.bitmap_flag.SetBitmap(bitmap_flag) + + self.bitmap_check.Refresh() + self.bitmap_uncheck.Refresh() + self.bitmap_flag.Refresh() + self.bitmap_unflag.Refresh() + + event.Skip() + + + def OnOk(self, event): + + selection = self.listicons.GetSelection() + self.parent.SetCheckRadio(selection) + self.Destroy() + event.Skip() + + + def OnCancel(self, event): + + self.Destroy() + event.Skip() + + +#--------------------------------------------------------------------------- +# Just A Dialog To Select Tree Items Icons +#--------------------------------------------------------------------------- +class TreeIcons(wx.Dialog): + + def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, oldpen=None, + bitmaps=None): + + wx.Dialog.__init__(self, parent, id, title, pos, size, style) + + self.bitmaps = [None, None, None, None] + empty = wx.EmptyBitmap(16, 16) + self.parent = parent + + self.bitmaps[0] = wx.StaticBitmap(self, -1, empty) + self.combonormal = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.bitmaps[1] = wx.StaticBitmap(self, -1, empty) + self.comboselected = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.bitmaps[2] = wx.StaticBitmap(self, -1, empty) + self.comboexpanded = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.bitmaps[3] = wx.StaticBitmap(self, -1, empty) + self.comboselectedexpanded = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.okbutton = wx.Button(self, wx.ID_OK) + self.cancelbutton = wx.Button(self, wx.ID_CANCEL) + + self.combonormal.SetSelection(bitmaps[0] >= 0 and bitmaps[0]+1 or 0) + self.comboselected.SetSelection(bitmaps[1] >= 0 and bitmaps[1]+1 or 0) + self.comboexpanded.SetSelection(bitmaps[2] >= 0 and bitmaps[2]+1 or 0) + self.comboselectedexpanded.SetSelection(bitmaps[3] >= 0 and bitmaps[3]+1 or 0) + + self.GetBitmaps(bitmaps) + + self.SetProperties() + self.DoLayout() + + self.Bind(wx.EVT_COMBOBOX, self.OnComboNormal, self.combonormal) + self.Bind(wx.EVT_COMBOBOX, self.OnComboSelected, self.comboselected) + self.Bind(wx.EVT_COMBOBOX, self.OnComboExpanded, self.comboexpanded) + self.Bind(wx.EVT_COMBOBOX, self.OnComboSelectedExpanded, self.comboselectedexpanded) + self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton) + self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton) + + + def SetProperties(self): + + self.SetTitle("Item Icon Selector") + self.okbutton.SetDefault() + + + def DoLayout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + gridsizer = wx.FlexGridSizer(4, 3, 5, 5) + label_1 = wx.StaticText(self, -1, "Please Choose The Icons For This Item (All Are Optional):") + label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10) + label_2 = wx.StaticText(self, -1, "TreeIcon_Normal:") + gridsizer.Add(label_2, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.bitmaps[0], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.combonormal, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + label_3 = wx.StaticText(self, -1, "TreeIcon_Selected:") + gridsizer.Add(label_3, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.bitmaps[1], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.comboselected, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + label_4 = wx.StaticText(self, -1, "TreeIcon_Expanded:") + gridsizer.Add(label_4, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.bitmaps[2], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.comboexpanded, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + label_5 = wx.StaticText(self, -1, "TreeIcon_SelectedExpanded:") + gridsizer.Add(label_5, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.bitmaps[3], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.comboselectedexpanded, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + gridsizer.AddGrowableCol(0) + gridsizer.AddGrowableCol(1) + gridsizer.AddGrowableCol(2) + mainsizer.Add(gridsizer, 0, wx.ALL|wx.EXPAND, 5) + sizer_2.Add(self.okbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20) + sizer_2.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + sizer_2.Add(self.cancelbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20) + mainsizer.Add(sizer_2, 1, wx.EXPAND, 0) + self.SetAutoLayout(True) + self.SetSizer(mainsizer) + mainsizer.Fit(self) + mainsizer.SetSizeHints(self) + self.Layout() + self.Centre() + + + def OnComboNormal(self, event): + + input = event.GetSelection() + self.GetBitmap(input, 0) + event.Skip() + + + def OnComboSelected(self, event): + + input = event.GetSelection() + self.GetBitmap(input, 1) + event.Skip() + + + def OnComboExpanded(self, event): + + input = event.GetSelection() + self.GetBitmap(input, 2) + event.Skip() + + + def OnComboSelectedExpanded(self, event): + + input = event.GetSelection() + self.GetBitmap(input, 3) + event.Skip() + + + def OnOk(self, event): + + bitmaps = [-1, -1, -1, -1] + normal = self.combonormal.GetSelection() + selected = self.comboselected.GetSelection() + expanded = self.comboexpanded.GetSelection() + selexp = self.comboselectedexpanded.GetSelection() + + bitmaps = [(normal > 0 and normal or -1), (selected > 0 and selected or -1), + (expanded > 0 and expanded or -1), (selexp > 0 and selexp or -1)] + + newbitmaps = [] + + for bmp in bitmaps: + if bmp > 0: + newbitmaps.append(bmp-1) + else: + newbitmaps.append(bmp) + + self.parent.SetNewIcons(newbitmaps) + + self.Destroy() + event.Skip() + + + def OnCancel(self, event): + + self.Destroy() + event.Skip() + + + def GetBitmap(self, input, which): + + if input == 0: + bmp = wx.EmptyBitmap(16,16) + self.ClearBmp(bmp) + elif input > 36: + bmp = images.Smiles.GetBitmap() + else: + bmp = wx.ArtProvider_GetBitmap(eval(ArtIDs[input]), wx.ART_OTHER, (16,16)) + if not bmp.Ok(): + bmp = wx.EmptyBitmap(16,16) + self.ClearBmp(bmp) + + self.bitmaps[which].SetBitmap(bmp) + self.bitmaps[which].Refresh() + + + def GetBitmaps(self, bitmaps): + + output = [] + + for count, input in enumerate(bitmaps): + if input < 0: + bmp = wx.EmptyBitmap(16,16) + self.ClearBmp(bmp) + elif input > 35: + bmp = images.Smiles.GetBitmap() + else: + bmp = wx.ArtProvider_GetBitmap(eval(ArtIDs[input+1]), wx.ART_OTHER, (16,16)) + if not bmp.Ok(): + bmp = wx.EmptyBitmap(16,16) + self.ClearBmp(bmp) + + self.bitmaps[count].SetBitmap(bmp) + + + def ClearBmp(self, bmp): + + dc = wx.MemoryDC() + dc.SelectObject(bmp) + dc.SetBackground(wx.Brush("white")) + dc.Clear() + + +#--------------------------------------------------------------------------- +# CustomTreeCtrl Demo Implementation +#--------------------------------------------------------------------------- +class CustomTreeCtrlDemo(wx.Panel): + + def __init__(self, parent, log): + wx.Panel.__init__(self, parent) + + self.log = log + self.oldicons = 0 + + splitter = wx.SplitterWindow(self, -1, style=wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D) + + # Create the CustomTreeCtrl, using a derived class defined below + self.tree = CustomTreeCtrl(splitter, -1, log=self.log, + style=wx.SUNKEN_BORDER, + agwStyle=CT.TR_HAS_BUTTONS | CT.TR_HAS_VARIABLE_ROW_HEIGHT) + + self.leftpanel = wx.ScrolledWindow(splitter, -1, style=wx.SUNKEN_BORDER) + self.leftpanel.SetScrollRate(20,20) + width = self.PopulateLeftPanel(self.tree.styles, self.tree.events) + + # add the windows to the splitter and split it. + splitter.SplitVertically(self.leftpanel, self.tree, 300) + splitter.SetMinimumPaneSize(width+5) + + sizer = wx.BoxSizer() + sizer.Add(splitter, 1, wx.EXPAND) + self.SetSizer(sizer) + + self.leftimagelist = wx.ImageList(12, 12) + for ids in xrange(1, len(ArtIDs)-1): + bmp = wx.ArtProvider_GetBitmap(eval(ArtIDs[ids]), wx.ART_OTHER, (12, 12)) + self.leftimagelist.Add(bmp) + + + def PopulateLeftPanel(self, styles, events): + + pnl = wx.Panel(self.leftpanel) + mainsizer = wx.BoxSizer(wx.VERTICAL) + recreatetree = wx.Button(pnl, -1, "Recreate CustomTreeCtrl") + mainsizer.Add(recreatetree, 0, wx.ALL|wx.ALIGN_CENTER, 10) + recreatetree.Bind(wx.EVT_BUTTON, self.OnRecreateTree) + + staticboxstyles = wx.StaticBox(pnl, -1, "CustomTreeCtrl Styles") + stylesizer = wx.StaticBoxSizer(staticboxstyles, wx.VERTICAL) + staticboxevents = wx.StaticBox(pnl, -1, "CustomTreeCtrl Events") + eventssizer = wx.StaticBoxSizer(staticboxevents, wx.VERTICAL) + staticboxcolours = wx.StaticBox(pnl, -1, "CustomTreeCtrl Images/Colours") + colourssizer = wx.StaticBoxSizer(staticboxcolours, wx.VERTICAL) + staticboxthemes = wx.StaticBox(pnl, -1, "CustomTreeCtrl Themes/Gradients") + themessizer = wx.StaticBoxSizer(staticboxthemes, wx.VERTICAL) + + self.treestyles = [] + self.treeevents = [] + + for count, style in enumerate(styles): + + if count == 0: + tags = wx.ALL + else: + tags = wx.LEFT|wx.RIGHT|wx.BOTTOM + + if style != "TR_DEFAULT_STYLE": + check = wx.CheckBox(pnl, -1, style) + stylesizer.Add(check, 0, tags, 3) + + if style in ["TR_HAS_BUTTONS", "TR_HAS_VARIABLE_ROW_HEIGHT"]: + check.SetValue(1) + + if style == "TR_HAS_VARIABLE_ROW_HEIGHT": + check.Enable(False) + + check.Bind(wx.EVT_CHECKBOX, self.OnCheckStyle) + self.treestyles.append(check) + + for count, event in enumerate(events): + + if count == 0: + tags = wx.ALL + else: + tags = wx.LEFT|wx.RIGHT|wx.BOTTOM + + if count not in [6, 17, 22, 23]: + check = wx.CheckBox(pnl, -1, event) + eventssizer.Add(check, 0, tags, 3) + + if event in ["EVT_TREE_ITEM_EXPANDED", "EVT_TREE_ITEM_COLLAPSED", + "EVT_TREE_SEL_CHANGED", "EVT_TREE_SEL_CHANGING"]: + + check.SetValue(1) + + check.Bind(wx.EVT_CHECKBOX, self.OnCheckEvent) + self.treeevents.append(check) + + sizer1 = wx.BoxSizer(wx.HORIZONTAL) + label = wx.StaticText(pnl, -1, "Connection Pen") + font = label.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + label.SetFont(font) + buttonconnection = wx.Button(pnl, -1, "Choose...") + buttonconnection.Bind(wx.EVT_BUTTON, self.OnButtonConnection) + sizer1.Add(label, 0, wx.ALL|wx.ALIGN_CENTER, 5) + sizer1.Add((1,0), 1, wx.EXPAND) + sizer1.Add(buttonconnection, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5) + + sizer2 = wx.BoxSizer(wx.HORIZONTAL) + label = wx.StaticText(pnl, -1, "Border Pen") + font = label.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + label.SetFont(font) + buttonborder = wx.Button(pnl, -1, "Choose...") + buttonborder.Bind(wx.EVT_BUTTON, self.OnButtonBorder) + sizer2.Add(label, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5) + sizer2.Add((1,0), 1, wx.EXPAND) + sizer2.Add(buttonborder, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5) + + sizer3 = wx.BoxSizer(wx.HORIZONTAL) + label = wx.StaticText(pnl, -1, "Tree Buttons") + font = label.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + label.SetFont(font) + buttontree = wx.Button(pnl, -1, "Choose...") + buttontree.Bind(wx.EVT_BUTTON, self.OnButtonTree) + sizer3.Add(label, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5) + sizer3.Add((1,0), 1, wx.EXPAND) + sizer3.Add(buttontree, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5) + + sizer4 = wx.BoxSizer(wx.HORIZONTAL) + label = wx.StaticText(pnl, -1, "Check/Radio Buttons") + font = label.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + label.SetFont(font) + buttoncr = wx.Button(pnl, -1, "Choose...") + buttoncr.Bind(wx.EVT_BUTTON, self.OnButtonCheckRadio) + sizer4.Add(label, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5) + sizer4.Add((1,0), 1, wx.EXPAND) + sizer4.Add(buttoncr, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5) + + sizer5 = wx.BoxSizer(wx.HORIZONTAL) + radioimage = wx.RadioButton(pnl, -1, "Image Background", style=wx.RB_GROUP) + radioimage.Bind(wx.EVT_RADIOBUTTON, self.OnBackgroundImage) + self.imagebutton = wx.Button(pnl, -1, "Choose...") + self.imagebutton.Bind(wx.EVT_BUTTON, self.OnChooseImage) + sizer5.Add(radioimage, 0, wx.ALL|wx.ALIGN_CENTER, 5) + sizer5.Add((1,0), 1, wx.EXPAND) + sizer5.Add(self.imagebutton, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5) + + sizer6 = wx.BoxSizer(wx.HORIZONTAL) + radiobackground = wx.RadioButton(pnl, -1, "Background Colour") + radiobackground.Bind(wx.EVT_RADIOBUTTON, self.OnBackgroundColour) + self.backbutton = csel.ColourSelect(pnl, -1, "Choose...", wx.WHITE) + self.backbutton.Bind(csel.EVT_COLOURSELECT, self.OnChooseBackground) + sizer6.Add(radiobackground, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5) + sizer6.Add((1,0), 1, wx.EXPAND) + sizer6.Add(self.backbutton, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5) + + leftimagelist = wx.CheckBox(pnl, -1, "Use Left ImageList") + leftimagelist.Bind(wx.EVT_CHECKBOX, self.OnLeftImageList) + + colourssizer.Add(sizer1, 0, wx.EXPAND) + colourssizer.Add(sizer2, 0, wx.EXPAND) + colourssizer.Add(sizer3, 0, wx.EXPAND) + colourssizer.Add(sizer4, 0, wx.EXPAND) + colourssizer.Add(sizer5, 0, wx.EXPAND) + colourssizer.Add(sizer6, 0, wx.EXPAND) + colourssizer.Add(leftimagelist, 0, wx.ALL, 5) + + sizera = wx.BoxSizer(wx.HORIZONTAL) + self.checknormal = wx.CheckBox(pnl, -1, "Standard Colours") + self.focus = csel.ColourSelect(pnl, -1, "Focus", + self.tree.GetHilightFocusColour()) + self.unfocus = csel.ColourSelect(pnl, -1, "Non-Focus", + self.tree.GetHilightNonFocusColour()) + self.checknormal.Bind(wx.EVT_CHECKBOX, self.OnCheckNormal) + self.focus.Bind(csel.EVT_COLOURSELECT, self.OnFocusColour) + self.unfocus.Bind(csel.EVT_COLOURSELECT, self.OnNonFocusColour) + sizera1 = wx.BoxSizer(wx.VERTICAL) + sizera1.Add(self.focus, 0, wx.BOTTOM, 2) + sizera1.Add(self.unfocus, 0) + sizera.Add(self.checknormal, 0, wx.ALL, 3) + sizera.Add((1, 0), 1, wx.EXPAND) + sizera.Add(sizera1, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, 3) + + sizerb = wx.BoxSizer(wx.VERTICAL) + self.checkgradient = wx.CheckBox(pnl, -1, "Gradient Theme") + self.checkgradient.Bind(wx.EVT_CHECKBOX, self.OnCheckGradient) + sizerb1 = wx.BoxSizer(wx.HORIZONTAL) + sizerb1.Add((10, 0)) + self.radiohorizontal = wx.RadioButton(pnl, -1, "Horizontal", style=wx.RB_GROUP) + self.radiohorizontal.Bind(wx.EVT_RADIOBUTTON, self.OnHorizontal) + sizerb1.Add(self.radiohorizontal, 0, wx.TOP|wx.BOTTOM, 3) + sizerb2 = wx.BoxSizer(wx.HORIZONTAL) + sizerb2.Add((10, 0)) + self.radiovertical = wx.RadioButton(pnl, -1, "Vertical") + self.radiovertical.Bind(wx.EVT_RADIOBUTTON, self.OnVertical) + sizerb2.Add(self.radiovertical, 0, wx.BOTTOM, 3) + sizerb3 = wx.BoxSizer(wx.HORIZONTAL) + self.firstcolour = csel.ColourSelect(pnl, -1, "First Colour", + self.tree.GetFirstGradientColour()) + self.secondcolour = csel.ColourSelect(pnl, -1, "Second Colour", + self.tree.GetSecondGradientColour()) + self.firstcolour.Bind(csel.EVT_COLOURSELECT, self.OnFirstColour) + self.secondcolour.Bind(csel.EVT_COLOURSELECT, self.OnSecondColour) + sizerb3.Add(self.firstcolour, 0, wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, 3) + sizerb3.Add(self.secondcolour, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, 3) + sizerb.Add(self.checkgradient, 0, wx.ALL, 3) + sizerb.Add(sizerb1, 0) + sizerb.Add(sizerb2, 0) + sizerb.Add(sizerb3, 0, wx.ALIGN_CENTER) + + self.checkvista = wx.CheckBox(pnl, -1, "Windows Vista Theme") + self.checkvista.Bind(wx.EVT_CHECKBOX, self.OnVista) + + themessizer.Add(sizera, 0, wx.EXPAND) + themessizer.Add(sizerb, 0, wx.EXPAND) + themessizer.Add((0, 5)) + themessizer.Add(self.checkvista, 0, wx.EXPAND|wx.ALL, 3) + + mainsizer.Add(stylesizer, 0, wx.EXPAND|wx.ALL, 5) + mainsizer.Add(colourssizer, 0, wx.EXPAND|wx.ALL, 5) + mainsizer.Add(themessizer, 0, wx.EXPAND|wx.ALL, 5) + mainsizer.Add(eventssizer, 0, wx.EXPAND|wx.ALL, 5) + + pnl.SetSizer(mainsizer) + pnl.Fit() + + swsizer = wx.BoxSizer(wx.VERTICAL) + swsizer.Add(pnl, 0, wx.EXPAND) + self.leftpanel.SetSizer(swsizer) + swsizer.Layout() + + radiobackground.SetValue(1) + self.checknormal.SetValue(1) + self.radiohorizontal.Enable(False) + self.radiovertical.Enable(False) + self.firstcolour.Enable(False) + self.secondcolour.Enable(False) + self.imagebutton.Enable(False) + + return mainsizer.CalcMin().width + wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X) + + + def OnRecreateTree(self, event): + + splitter = self.tree.GetParent() + newtree = CustomTreeCtrl(splitter, -1, log=self.log) + splitter.ReplaceWindow(self.tree, newtree) + self.tree.Destroy() + self.tree = newtree + # Todo: The settings in the leftpanel should be reset too + + + def OnCheckStyle(self, event): + + self.tree.ChangeStyle(self.treestyles) + event.Skip() + + + def OnCheckEvent(self, event): + + obj = event.GetEventObject() + self.tree.BindEvents(obj) + + event.Skip() + + + def OnButtonConnection(self, event): + + pen = self.tree.GetConnectionPen() + dlg = PenDialog(self, -1, oldpen=pen, pentype=0) + + dlg.ShowModal() + + event.Skip() + + + def SetConnectionPen(self, pen): + + self.tree.SetConnectionPen(pen) + + + def OnButtonBorder(self, event): + + pen = self.tree.GetBorderPen() + dlg = PenDialog(self, -1, oldpen=pen, pentype=1) + + dlg.ShowModal() + event.Skip() + + + def SetBorderPen(self, pen): + + self.tree.SetBorderPen(pen) + + + def OnButtonTree(self, event): + + dlg = TreeButtonsDialog(self, -1, oldicons=self.oldicons) + dlg.ShowModal() + + event.Skip() + + + def OnButtonCheckRadio(self, event): + + dlg = CheckDialog(self, -1) + dlg.ShowModal() + + event.Skip() + + + def SetTreeButtons(self, selection): + + bitmap_plus = os.path.normpath(os.path.join(bitmapDir, "plus" + str(selection+1) + ".ico")) + bitmap_minus = os.path.normpath(os.path.join(bitmapDir, "minus" + str(selection+1) + ".ico")) + + bitmap = wx.Bitmap(bitmap_plus, wx.BITMAP_TYPE_ICO) + width = bitmap.GetWidth() + + il = wx.ImageList(width, width) + + il.Add(wx.Bitmap(bitmap_plus, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_plus, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_minus, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_minus, wx.BITMAP_TYPE_ICO)) + + self.il = il + self.tree.SetButtonsImageList(il) + + + def SetCheckRadio(self, selection): + + if selection == 0: + self.tree.SetImageListCheck(13, 13) + else: + bitmap_check = os.path.normpath(os.path.join(bitmapDir, "aquachecked.ico")) + bitmap_uncheck = os.path.normpath(os.path.join(bitmapDir, "aquanotchecked.ico")) + bitmap_flag = os.path.normpath(os.path.join(bitmapDir, "aquaflagged.ico")) + bitmap_unflag = os.path.normpath(os.path.join(bitmapDir, "aquanotflagged.ico")) + + il = wx.ImageList(16, 16) + + il.Add(wx.Bitmap(bitmap_check, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_uncheck, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_flag, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_unflag, wx.BITMAP_TYPE_ICO)) + self.tree.SetImageListCheck(16, 16, il) + + + def OnBackgroundImage(self, event): + + if hasattr(self, "backgroundimage"): + self.tree.SetBackgroundImage(self.backgroundimage) + + self.backbutton.Enable(False) + self.imagebutton.Enable(True) + + event.Skip() + + + def OnChooseImage(self, event): + + wildcard = "JPEG Files (*.jpg)|*.jpg|" \ + "Bitmap Files (*.bmp)|*.bmp|" \ + "PNG Files (*.png)|*.png|" \ + "Icon Files (*.ico)|*.ico|" \ + "GIF Files (*.gif)|*.gif|" \ + "All files (*.*)|*.*" + + dlg = wx.FileDialog(self, "Choose An Image File", ".", "", wildcard, wx.OPEN) + + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + else: + dlg.Destroy() + return + + dlg.Destroy() + bitmap = wx.Bitmap(path, wx.BITMAP_TYPE_ANY) + self.tree.SetBackgroundImage(bitmap) + self.backgroundimage = bitmap + + event.Skip() + + + def OnBackgroundColour(self, event): + + self.imagebutton.Enable(False) + self.backbutton.Enable(True) + self.tree.SetBackgroundImage(None) + + event.Skip() + + + def OnChooseBackground(self, event): + + col1 = event.GetValue() + self.tree.SetBackgroundColour(col1) + event.Skip() + + + def OnLeftImageList(self, event): + + checked = event.IsChecked() + if checked: + self.tree.SetLeftImageList(self.leftimagelist) + else: + self.tree.SetLeftImageList(None) + + self.tree.CalculateLineHeight() + self.tree.Refresh() + + + def OnCheckNormal(self, event): + + self.radiohorizontal.Enable(False) + self.radiovertical.Enable(False) + self.firstcolour.Enable(False) + self.secondcolour.Enable(False) + self.focus.Enable(True) + self.unfocus.Enable(True) + self.checkgradient.SetValue(0) + self.checkvista.SetValue(0) + self.tree.EnableSelectionGradient(False) + self.tree.EnableSelectionVista(False) + event.Skip() + + + def OnFocusColour(self, event): + + col1 = event.GetValue() + self.tree.SetHilightFocusColour(col1) + event.Skip() + + + def OnNonFocusColour(self, event): + + col1 = event.GetValue() + self.tree.SetHilightNonFocusColour(col1) + event.Skip() + + + def OnCheckGradient(self, event): + + self.radiohorizontal.Enable(True) + self.radiovertical.Enable(True) + self.firstcolour.Enable(True) + self.secondcolour.Enable(True) + self.checknormal.SetValue(0) + self.checkvista.SetValue(0) + self.focus.Enable(False) + self.unfocus.Enable(False) + self.tree.SetGradientStyle(self.radiovertical.GetValue()) + self.tree.EnableSelectionVista(False) + self.tree.EnableSelectionGradient(True) + + event.Skip() + + + def OnHorizontal(self, event): + + self.tree.SetGradientStyle(self.radiovertical.GetValue()) + event.Skip() + + + def OnVertical(self, event): + + self.tree.SetGradientStyle(self.radiovertical.GetValue()) + event.Skip() + + + def OnFirstColour(self, event): + + col1 = event.GetValue() + self.tree.SetFirstGradientColour(wx.Colour(col1[0], col1[1], col1[2])) + event.Skip() + + + def OnSecondColour(self, event): + + col1 = event.GetValue() + self.tree.SetSecondGradientColour(wx.Colour(col1[0], col1[1], col1[2])) + event.Skip() + + + def OnVista(self, event): + + self.radiohorizontal.Enable(False) + self.radiovertical.Enable(False) + self.firstcolour.Enable(False) + self.secondcolour.Enable(False) + self.checknormal.SetValue(0) + self.checkgradient.SetValue(0) + self.focus.Enable(False) + self.unfocus.Enable(False) + self.tree.EnableSelectionGradient(False) + self.tree.EnableSelectionVista(True) + + event.Skip() + + +#--------------------------------------------------------------------------- +# CustomTreeCtrl Demo Implementation +#--------------------------------------------------------------------------- +class CustomTreeCtrl(CT.CustomTreeCtrl): + + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, + size=wx.DefaultSize, + style=wx.SUNKEN_BORDER|wx.WANTS_CHARS, + agwStyle=CT.TR_HAS_BUTTONS|CT.TR_HAS_VARIABLE_ROW_HEIGHT, + log=None): + + CT.CustomTreeCtrl.__init__(self, parent, id, pos, size, style, agwStyle) + + self.SetBackgroundColour(wx.WHITE) + + alldata = dir(CT) + + treestyles = [] + events = [] + for data in alldata: + if data.startswith("TR_"): + treestyles.append(data) + elif data.startswith("EVT_"): + events.append(data) + + self.events = events + self.styles = treestyles + self.item = None + + il = wx.ImageList(16, 16) + + for items in ArtIDs[1:-1]: + bmp = wx.ArtProvider_GetBitmap(eval(items), wx.ART_TOOLBAR, (16, 16)) + il.Add(bmp) + + smileidx = il.Add(images.Smiles.GetBitmap()) + numicons = il.GetImageCount() + + self.AssignImageList(il) + self.count = 0 + self.log = log + + # NOTE: For some reason tree items have to have a data object in + # order to be sorted. Since our compare just uses the labels + # we don't need any real data, so we'll just use None below for + # the item data. + + self.root = self.AddRoot("The Root Item") + + if not(self.GetAGWWindowStyleFlag() & CT.TR_HIDE_ROOT): + self.SetPyData(self.root, None) + self.SetItemImage(self.root, 24, CT.TreeItemIcon_Normal) + self.SetItemImage(self.root, 13, CT.TreeItemIcon_Expanded) + + textctrl = wx.TextCtrl(self, -1, "I Am A Simple\nMultiline wx.TexCtrl", style=wx.TE_MULTILINE) + self.gauge = wx.Gauge(self, -1, 50, style=wx.GA_HORIZONTAL|wx.GA_SMOOTH) + self.gauge.SetValue(0) + combobox = wx.ComboBox(self, -1, choices=["That", "Was", "A", "Nice", "Holyday!"], style=wx.CB_READONLY|wx.CB_DROPDOWN) + + textctrl.Bind(wx.EVT_CHAR, self.OnTextCtrl) + combobox.Bind(wx.EVT_COMBOBOX, self.OnComboBox) + lenArtIds = len(ArtIDs) - 2 + + for x in range(15): + if x == 1: + child = self.AppendItem(self.root, "Item %d" % x + "\nHello World\nHappy wxPython-ing!") + self.SetItemBold(child, True) + else: + child = self.AppendItem(self.root, "Item %d" % x) + self.SetPyData(child, None) + self.SetItemImage(child, 24, CT.TreeItemIcon_Normal) + self.SetItemImage(child, 13, CT.TreeItemIcon_Expanded) + + if random.randint(0, 3) == 0: + self.SetItemLeftImage(child, random.randint(0, lenArtIds)) + + if random.randint(0, 5) == 0: + self.AppendSeparator(self.root) + + for y in range(5): + if y == 0 and x == 1: + last = self.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y)), ct_type=2, wnd=self.gauge) + elif y == 1 and x == 2: + last = self.AppendItem(child, "Item %d-%s" % (x, chr(ord("a")+y)), ct_type=1, wnd=textctrl) + if random.randint(0, 3) == 1: + self.SetItem3State(last, True) + + elif 2 < y < 4: + last = self.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y))) + elif y == 4 and x == 1: + last = self.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y)), wnd=combobox) + else: + last = self.AppendItem(child, "item %d-%s" % (x, chr(ord("a")+y)), ct_type=2) + + self.SetPyData(last, None) + self.SetItemImage(last, 24, CT.TreeItemIcon_Normal) + self.SetItemImage(last, 13, CT.TreeItemIcon_Expanded) + + if random.randint(0, 3) == 0: + self.SetItemLeftImage(last, random.randint(0, lenArtIds)) + + if random.randint(0, 5) == 0: + self.AppendSeparator(child) + + for z in range(5): + if z > 2: + item = self.AppendItem(last, "item %d-%s-%d" % (x, chr(ord("a")+y), z), ct_type=1) + if random.randint(0, 3) == 1: + self.SetItem3State(item, True) + elif 0 < z <= 2: + item = self.AppendItem(last, "item %d-%s-%d" % (x, chr(ord("a")+y), z), ct_type=2) + elif z == 0: + item = self.AppendItem(last, "item %d-%s-%d" % (x, chr(ord("a")+y), z)) + self.SetItemHyperText(item, True) + self.SetPyData(item, None) + self.SetItemImage(item, 28, CT.TreeItemIcon_Normal) + self.SetItemImage(item, numicons-1, CT.TreeItemIcon_Selected) + + if random.randint(0, 3) == 0: + self.SetItemLeftImage(item, random.randint(0, lenArtIds)) + + if random.randint(0, 5) == 0: + self.AppendSeparator(last) + + self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick) + self.Bind(wx.EVT_IDLE, self.OnIdle) + + self.eventdict = {'EVT_TREE_BEGIN_DRAG': self.OnBeginDrag, 'EVT_TREE_BEGIN_LABEL_EDIT': self.OnBeginEdit, + 'EVT_TREE_BEGIN_RDRAG': self.OnBeginRDrag, 'EVT_TREE_DELETE_ITEM': self.OnDeleteItem, + 'EVT_TREE_END_DRAG': self.OnEndDrag, 'EVT_TREE_END_LABEL_EDIT': self.OnEndEdit, + 'EVT_TREE_ITEM_ACTIVATED': self.OnActivate, 'EVT_TREE_ITEM_CHECKED': self.OnItemCheck, + 'EVT_TREE_ITEM_CHECKING': self.OnItemChecking, 'EVT_TREE_ITEM_COLLAPSED': self.OnItemCollapsed, + 'EVT_TREE_ITEM_COLLAPSING': self.OnItemCollapsing, 'EVT_TREE_ITEM_EXPANDED': self.OnItemExpanded, + 'EVT_TREE_ITEM_EXPANDING': self.OnItemExpanding, 'EVT_TREE_ITEM_GETTOOLTIP': self.OnToolTip, + 'EVT_TREE_ITEM_MENU': self.OnItemMenu, 'EVT_TREE_ITEM_RIGHT_CLICK': self.OnRightDown, + 'EVT_TREE_KEY_DOWN': self.OnKey, 'EVT_TREE_SEL_CHANGED': self.OnSelChanged, + 'EVT_TREE_SEL_CHANGING': self.OnSelChanging, "EVT_TREE_ITEM_HYPERLINK": self.OnHyperLink} + + mainframe = wx.GetTopLevelParent(self) + + if not hasattr(mainframe, "leftpanel"): + self.Bind(CT.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded) + self.Bind(CT.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed) + self.Bind(CT.EVT_TREE_SEL_CHANGED, self.OnSelChanged) + self.Bind(CT.EVT_TREE_SEL_CHANGING, self.OnSelChanging) + self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) + self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) + else: + for combos in mainframe.treeevents: + self.BindEvents(combos) + + if hasattr(mainframe, "leftpanel"): + self.ChangeStyle(mainframe.treestyles) + + if not(self.GetAGWWindowStyleFlag() & CT.TR_HIDE_ROOT): + self.SelectItem(self.root) + self.Expand(self.root) + + + def BindEvents(self, choice, recreate=False): + + value = choice.GetValue() + text = choice.GetLabel() + + evt = "CT." + text + binder = self.eventdict[text] + + if value == 1: + if evt == "CT.EVT_TREE_BEGIN_RDRAG": + self.Bind(wx.EVT_RIGHT_DOWN, None) + self.Bind(wx.EVT_RIGHT_UP, None) + self.Bind(eval(evt), binder) + else: + self.Bind(eval(evt), None) + if evt == "CT.EVT_TREE_BEGIN_RDRAG": + self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) + self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) + + + def ChangeStyle(self, combos): + + style = 0 + for combo in combos: + if combo.GetValue() == 1: + style = style | eval("CT." + combo.GetLabel()) + + if self.GetAGWWindowStyleFlag() != style: + self.SetAGWWindowStyleFlag(style) + + + def OnCompareItems(self, item1, item2): + + t1 = self.GetItemText(item1) + t2 = self.GetItemText(item2) + + self.log.write('compare: ' + t1 + ' <> ' + t2 + "\n") + + if t1 < t2: + return -1 + if t1 == t2: + return 0 + + return 1 + + + def OnIdle(self, event): + + if self.gauge: + try: + if self.gauge.IsEnabled() and self.gauge.IsShown(): + self.count = self.count + 1 + + if self.count >= 50: + self.count = 0 + + self.gauge.SetValue(self.count) + + except: + self.gauge = None + + event.Skip() + + + def OnRightDown(self, event): + + pt = event.GetPosition() + item, flags = self.HitTest(pt) + + if item: + self.item = item + self.log.write("OnRightClick: %s, %s, %s" % (self.GetItemText(item), type(item), item.__class__) + "\n") + self.SelectItem(item) + + + def OnRightUp(self, event): + + item = self.item + + if not item: + event.Skip() + return + + if not self.IsItemEnabled(item): + event.Skip() + return + + # Item Text Appearance + ishtml = self.IsItemHyperText(item) + back = self.GetItemBackgroundColour(item) + fore = self.GetItemTextColour(item) + isbold = self.IsBold(item) + font = self.GetItemFont(item) + + # Icons On Item + normal = self.GetItemImage(item, CT.TreeItemIcon_Normal) + selected = self.GetItemImage(item, CT.TreeItemIcon_Selected) + expanded = self.GetItemImage(item, CT.TreeItemIcon_Expanded) + selexp = self.GetItemImage(item, CT.TreeItemIcon_SelectedExpanded) + + # Enabling/Disabling Windows Associated To An Item + haswin = self.GetItemWindow(item) + + # Enabling/Disabling Items + enabled = self.IsItemEnabled(item) + + # Generic Item's Info + children = self.GetChildrenCount(item) + itemtype = self.GetItemType(item) + text = self.GetItemText(item) + pydata = self.GetPyData(item) + separator = self.IsItemSeparator(item) + + self.current = item + self.itemdict = {"ishtml": ishtml, "back": back, "fore": fore, "isbold": isbold, + "font": font, "normal": normal, "selected": selected, "expanded": expanded, + "selexp": selexp, "haswin": haswin, "children": children, + "itemtype": itemtype, "text": text, "pydata": pydata, "enabled": enabled, + "separator": separator} + + menu = wx.Menu() + + item1 = menu.Append(wx.ID_ANY, "Change item background colour") + item2 = menu.Append(wx.ID_ANY, "Modify item text colour") + menu.AppendSeparator() + + if isbold: + strs = "Make item text not bold" + else: + strs = "Make item text bold" + + item3 = menu.Append(wx.ID_ANY, strs) + item4 = menu.Append(wx.ID_ANY, "Change item font") + menu.AppendSeparator() + + if ishtml: + strs = "Set item as non-hyperlink" + else: + strs = "Set item as hyperlink" + + item5 = menu.Append(wx.ID_ANY, strs) + menu.AppendSeparator() + + item13 = menu.Append(wx.ID_ANY, "Insert separator") + menu.AppendSeparator() + + if haswin: + enabled = self.GetItemWindowEnabled(item) + if enabled: + strs = "Disable associated widget" + else: + strs = "Enable associated widget" + else: + strs = "Enable associated widget" + + item6 = menu.Append(wx.ID_ANY, strs) + + if not haswin: + item6.Enable(False) + + item7 = menu.Append(wx.ID_ANY, "Disable item") + + menu.AppendSeparator() + item8 = menu.Append(wx.ID_ANY, "Change item icons") + menu.AppendSeparator() + item9 = menu.Append(wx.ID_ANY, "Get other information for this item") + menu.AppendSeparator() + + item10 = menu.Append(wx.ID_ANY, "Delete item") + if item == self.GetRootItem(): + item10.Enable(False) + item13.Enable(False) + + item11 = menu.Append(wx.ID_ANY, "Prepend an item") + item12 = menu.Append(wx.ID_ANY, "Append an item") + + self.Bind(wx.EVT_MENU, self.OnItemBackground, item1) + self.Bind(wx.EVT_MENU, self.OnItemForeground, item2) + self.Bind(wx.EVT_MENU, self.OnItemBold, item3) + self.Bind(wx.EVT_MENU, self.OnItemFont, item4) + self.Bind(wx.EVT_MENU, self.OnItemHyperText, item5) + self.Bind(wx.EVT_MENU, self.OnEnableWindow, item6) + self.Bind(wx.EVT_MENU, self.OnDisableItem, item7) + self.Bind(wx.EVT_MENU, self.OnItemIcons, item8) + self.Bind(wx.EVT_MENU, self.OnItemInfo, item9) + self.Bind(wx.EVT_MENU, self.OnItemDelete, item10) + self.Bind(wx.EVT_MENU, self.OnItemPrepend, item11) + self.Bind(wx.EVT_MENU, self.OnItemAppend, item12) + self.Bind(wx.EVT_MENU, self.OnSeparatorInsert, item13) + + self.PopupMenu(menu) + menu.Destroy() + + + def OnItemBackground(self, event): + + colourdata = wx.ColourData() + colourdata.SetColour(self.itemdict["back"]) + dlg = wx.ColourDialog(self, colourdata) + + dlg.GetColourData().SetChooseFull(True) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetColourData() + col1 = data.GetColour().Get() + self.SetItemBackgroundColour(self.current, col1) + dlg.Destroy() + + + def OnItemForeground(self, event): + + colourdata = wx.ColourData() + colourdata.SetColour(self.itemdict["fore"]) + dlg = wx.ColourDialog(self, colourdata) + + dlg.GetColourData().SetChooseFull(True) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetColourData() + col1 = data.GetColour().Get() + self.SetItemTextColour(self.current, col1) + dlg.Destroy() + + + def OnItemBold(self, event): + + self.SetItemBold(self.current, not self.itemdict["isbold"]) + + + def OnItemFont(self, event): + + data = wx.FontData() + font = self.itemdict["font"] + + if font is None: + font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + + data.SetInitialFont(font) + + dlg = wx.FontDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetFontData() + font = data.GetChosenFont() + self.SetItemFont(self.current, font) + + dlg.Destroy() + + + def OnItemHyperText(self, event): + + self.SetItemHyperText(self.current, not self.itemdict["ishtml"]) + + + def OnEnableWindow(self, event): + + enable = self.GetItemWindowEnabled(self.current) + self.SetItemWindowEnabled(self.current, not enable) + + + def OnDisableItem(self, event): + + self.EnableItem(self.current, False) + + + def OnItemIcons(self, event): + + bitmaps = [self.itemdict["normal"], self.itemdict["selected"], + self.itemdict["expanded"], self.itemdict["selexp"]] + + wx.BeginBusyCursor() + dlg = TreeIcons(self, -1, bitmaps=bitmaps) + wx.EndBusyCursor() + dlg.ShowModal() + + + def SetNewIcons(self, bitmaps): + + self.SetItemImage(self.current, bitmaps[0], CT.TreeItemIcon_Normal) + self.SetItemImage(self.current, bitmaps[1], CT.TreeItemIcon_Selected) + self.SetItemImage(self.current, bitmaps[2], CT.TreeItemIcon_Expanded) + self.SetItemImage(self.current, bitmaps[3], CT.TreeItemIcon_SelectedExpanded) + + + def OnItemInfo(self, event): + + itemtext = self.itemdict["text"] + numchildren = str(self.itemdict["children"]) + itemtype = self.itemdict["itemtype"] + pydata = repr(type(self.itemdict["pydata"])) + + if itemtype == 0: + itemtype = "Normal" + elif itemtype == 1: + itemtype = "CheckBox" + else: + itemtype = "RadioButton" + + strs = "Information On Selected Item:\n\n" + "Text: " + itemtext + "\n" \ + "Number Of Children: " + numchildren + "\n" \ + "Item Type: " + itemtype + "\n" \ + "Item Data Type: " + pydata + "\n" + + dlg = wx.MessageDialog(self, strs, "CustomTreeCtrlDemo Info", wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + + + def OnItemDelete(self, event): + + strs = "Are You Sure You Want To Delete Item " + self.GetItemText(self.current) + "?" + dlg = wx.MessageDialog(None, strs, 'Deleting Item', wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_QUESTION) + + if dlg.ShowModal() in [wx.ID_NO, wx.ID_CANCEL]: + dlg.Destroy() + return + + dlg.Destroy() + + self.DeleteChildren(self.current) + self.Delete(self.current) + self.current = None + + + + def OnItemPrepend(self, event): + + dlg = wx.TextEntryDialog(self, "Please Enter The New Item Name", 'Item Naming', 'Python') + + if dlg.ShowModal() == wx.ID_OK: + newname = dlg.GetValue() + newitem = self.PrependItem(self.current, newname) + self.EnsureVisible(newitem) + + dlg.Destroy() + + + def OnItemAppend(self, event): + + dlg = wx.TextEntryDialog(self, "Please Enter The New Item Name", 'Item Naming', 'Python') + + if dlg.ShowModal() == wx.ID_OK: + newname = dlg.GetValue() + newitem = self.AppendItem(self.current, newname) + self.EnsureVisible(newitem) + + dlg.Destroy() + + + def OnSeparatorInsert(self, event): + + newitem = self.InsertSeparator(self.GetItemParent(self.current), self.current) + self.EnsureVisible(newitem) + + + def OnBeginEdit(self, event): + + self.log.write("OnBeginEdit" + "\n") + # show how to prevent edit... + item = event.GetItem() + if item and self.GetItemText(item) == "The Root Item": + wx.Bell() + self.log.write("You can't edit this one..." + "\n") + + # Lets just see what's visible of its children + cookie = 0 + root = event.GetItem() + (child, cookie) = self.GetFirstChild(root) + + while child: + self.log.write("Child [%s] visible = %d" % (self.GetItemText(child), self.IsVisible(child)) + "\n") + (child, cookie) = self.GetNextChild(root, cookie) + + event.Veto() + + + def OnEndEdit(self, event): + + self.log.write("OnEndEdit: %s %s" %(event.IsEditCancelled(), event.GetLabel())) + # show how to reject edit, we'll not allow any digits + for x in event.GetLabel(): + if x in string.digits: + self.log.write(", You can't enter digits..." + "\n") + event.Veto() + return + + self.log.write("\n") + + + def OnLeftDClick(self, event): + + pt = event.GetPosition() + item, flags = self.HitTest(pt) + if item and (flags & CT.TREE_HITTEST_ONITEMLABEL): + if self.GetAGWWindowStyleFlag() & CT.TR_EDIT_LABELS: + self.log.write("OnLeftDClick: %s (manually starting label edit)"% self.GetItemText(item) + "\n") + self.EditLabel(item) + else: + self.log.write("OnLeftDClick: Cannot Start Manual Editing, Missing Style TR_EDIT_LABELS\n") + + event.Skip() + + + def OnItemExpanded(self, event): + + item = event.GetItem() + if item: + self.log.write("OnItemExpanded: %s" % self.GetItemText(item) + "\n") + + + def OnItemExpanding(self, event): + + item = event.GetItem() + if item: + self.log.write("OnItemExpanding: %s" % self.GetItemText(item) + "\n") + + event.Skip() + + + def OnItemCollapsed(self, event): + + item = event.GetItem() + if item: + self.log.write("OnItemCollapsed: %s" % self.GetItemText(item) + "\n") + + + def OnItemCollapsing(self, event): + + item = event.GetItem() + if item: + self.log.write("OnItemCollapsing: %s" % self.GetItemText(item) + "\n") + + event.Skip() + + + def OnSelChanged(self, event): + + self.item = event.GetItem() + if self.item: + self.log.write("OnSelChanged: %s" % self.GetItemText(self.item)) + if wx.Platform == '__WXMSW__': + self.log.write(", BoundingRect: %s" % self.GetBoundingRect(self.item, True) + "\n") + else: + self.log.write("\n") + + event.Skip() + + + def OnSelChanging(self, event): + + item = event.GetItem() + olditem = event.GetOldItem() + + if item: + if not olditem: + olditemtext = "None" + else: + olditemtext = self.GetItemText(olditem) + self.log.write("OnSelChanging: From %s" % olditemtext + " To %s" % self.GetItemText(item) + "\n") + + event.Skip() + + + def OnBeginDrag(self, event): + + self.item = event.GetItem() + if self.item: + self.log.write("Beginning Drag..." + "\n") + + event.Allow() + + + def OnBeginRDrag(self, event): + + self.item = event.GetItem() + if self.item: + self.log.write("Beginning Right Drag..." + "\n") + + event.Allow() + + + def OnEndDrag(self, event): + + self.item = event.GetItem() + if self.item: + self.log.write("Ending Drag!" + "\n") + + event.Skip() + + + def OnDeleteItem(self, event): + + item = event.GetItem() + + if not item: + return + + self.log.write("Deleting Item: %s" % self.GetItemText(item) + "\n") + event.Skip() + + + def OnItemCheck(self, event): + + item = event.GetItem() + self.log.write("Item " + self.GetItemText(item) + " Has Been Checked!\n") + event.Skip() + + + def OnItemChecking(self, event): + + item = event.GetItem() + self.log.write("Item " + self.GetItemText(item) + " Is Being Checked...\n") + event.Skip() + + + def OnToolTip(self, event): + + item = event.GetItem() + if item: + event.SetToolTip(wx.ToolTip(self.GetItemText(item))) + + + def OnItemMenu(self, event): + + item = event.GetItem() + if item: + self.log.write("OnItemMenu: %s" % self.GetItemText(item) + "\n") + + event.Skip() + + + def OnKey(self, event): + + keycode = event.GetKeyCode() + keyname = keyMap.get(keycode, None) + + if keycode == wx.WXK_BACK: + self.log.write("OnKeyDown: HAHAHAHA! I Vetoed Your Backspace! HAHAHAHA\n") + return + + if keyname is None: + if "unicode" in wx.PlatformInfo: + keycode = event.GetUnicodeKey() + if keycode <= 127: + keycode = event.GetKeyCode() + keyname = "\"" + unichr(event.GetUnicodeKey()) + "\"" + if keycode < 27: + keyname = "Ctrl-%s" % chr(ord('A') + keycode-1) + + elif keycode < 256: + if keycode == 0: + keyname = "NUL" + elif keycode < 27: + keyname = "Ctrl-%s" % chr(ord('A') + keycode-1) + else: + keyname = "\"%s\"" % chr(keycode) + else: + keyname = "unknown (%s)" % keycode + + self.log.write("OnKeyDown: You Pressed '" + keyname + "'\n") + + event.Skip() + + + def OnActivate(self, event): + + if self.item: + self.log.write("OnActivate: %s" % self.GetItemText(self.item) + "\n") + + event.Skip() + + + def OnHyperLink(self, event): + + item = event.GetItem() + if item: + self.log.write("OnHyperLink: %s" % self.GetItemText(self.item) + "\n") + + + def OnTextCtrl(self, event): + + char = chr(event.GetKeyCode()) + self.log.write("EDITING THE TEXTCTRL: You Wrote '" + char + \ + "' (KeyCode = " + str(event.GetKeyCode()) + ")\n") + event.Skip() + + + def OnComboBox(self, event): + + selection = event.GetEventObject().GetValue() + self.log.write("CHOICE FROM COMBOBOX: You Chose '" + selection + "'\n") + event.Skip() + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = CustomTreeCtrlDemo(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = CT.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/agw/FlatMenu.py b/demo/agw/FlatMenu.py new file mode 100644 index 00000000..e3d044a5 --- /dev/null +++ b/demo/agw/FlatMenu.py @@ -0,0 +1,874 @@ +import wx +import math +import random +import os + +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +bitmapDir = os.path.join(dirName, 'bitmaps') +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import flatmenu as FM + from agw.artmanager import ArtManager, RendererBase, DCSaver + from agw.fmresources import ControlFocus, ControlPressed + from agw.fmresources import FM_OPT_SHOW_CUSTOMIZE, FM_OPT_SHOW_TOOLBAR, FM_OPT_MINIBAR +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.flatmenu as FM + from wx.lib.agw.artmanager import ArtManager, RendererBase, DCSaver + from wx.lib.agw.fmresources import ControlFocus, ControlPressed + from wx.lib.agw.fmresources import FM_OPT_SHOW_CUSTOMIZE, FM_OPT_SHOW_TOOLBAR, FM_OPT_MINIBAR + +import images + +if wx.VERSION >= (2,7,0,0): + import wx.aui as AUI + AuiPaneInfo = AUI.AuiPaneInfo + AuiManager = AUI.AuiManager + _hasAUI = True +else: + try: + import PyAUI as AUI + _hasAUI = True + AuiPaneInfo = AUI.PaneInfo + AuiManager = AUI.FrameManager + except: + _hasAUI = False + +#---------------------------------------------------------------------- + +#------------------------------- +# Menu items IDs +#------------------------------- + +MENU_STYLE_DEFAULT = wx.NewId() +MENU_STYLE_XP = wx.NewId() +MENU_STYLE_2007 = wx.NewId() +MENU_STYLE_VISTA = wx.NewId() +MENU_STYLE_MY = wx.NewId() +MENU_USE_CUSTOM = wx.NewId() +MENU_LCD_MONITOR = wx.NewId() +MENU_HELP = wx.NewId() + +MENU_DISABLE_MENU_ITEM = wx.NewId() +MENU_REMOVE_MENU = wx.NewId() +MENU_TRANSPARENCY = wx.NewId() + +MENU_NEW_FILE = 10005 +MENU_SAVE = 10006 +MENU_OPEN_FILE = 10007 +MENU_NEW_FOLDER = 10008 +MENU_COPY = 10009 +MENU_CUT = 10010 +MENU_PASTE = 10011 + + +def switchRGBtoBGR(colour): + + return wx.Colour(colour.Blue(), colour.Green(), colour.Red()) + + +def CreateBackgroundBitmap(): + + mem_dc = wx.MemoryDC() + bmp = wx.EmptyBitmap(200, 300) + mem_dc.SelectObject(bmp) + + mem_dc.Clear() + + # colour the menu face with background colour + top = wx.NamedColour("blue") + bottom = wx.NamedColour("light blue") + filRect = wx.Rect(0, 0, 200, 300) + mem_dc.GradientFillConcentric(filRect, top, bottom, wx.Point(100, 150)) + + mem_dc.SelectObject(wx.NullBitmap) + return bmp + +#------------------------------------------------------------ +# A custom renderer class for FlatMenu +#------------------------------------------------------------ + +class FM_MyRenderer(FM.FMRenderer): + """ My custom style. """ + + def __init__(self): + + FM.FMRenderer.__init__(self) + + + def DrawMenuButton(self, dc, rect, state): + """Draws the highlight on a FlatMenu""" + + self.DrawButton(dc, rect, state) + + + def DrawMenuBarButton(self, dc, rect, state): + """Draws the highlight on a FlatMenuBar""" + + self.DrawButton(dc, rect, state) + + + def DrawButton(self, dc, rect, state, colour=None): + + if state == ControlFocus: + penColour = switchRGBtoBGR(ArtManager.Get().FrameColour()) + brushColour = switchRGBtoBGR(ArtManager.Get().BackgroundColour()) + elif state == ControlPressed: + penColour = switchRGBtoBGR(ArtManager.Get().FrameColour()) + brushColour = switchRGBtoBGR(ArtManager.Get().HighlightBackgroundColour()) + else: # ControlNormal, ControlDisabled, default + penColour = switchRGBtoBGR(ArtManager.Get().FrameColour()) + brushColour = switchRGBtoBGR(ArtManager.Get().BackgroundColour()) + + # Draw the button borders + dc.SetPen(wx.Pen(penColour)) + dc.SetBrush(wx.Brush(brushColour)) + dc.DrawRoundedRectangle(rect.x, rect.y, rect.width, rect.height,4) + + + def DrawMenuBarBackground(self, dc, rect): + + # For office style, we simple draw a rectangle with a gradient colouring + vertical = ArtManager.Get().GetMBVerticalGradient() + + dcsaver = DCSaver(dc) + + # fill with gradient + startColour = self.menuBarFaceColour + endColour = ArtManager.Get().LightColour(startColour, 90) + + dc.SetPen(wx.Pen(endColour)) + dc.SetBrush(wx.Brush(endColour)) + dc.DrawRectangleRect(rect) + + + def DrawToolBarBg(self, dc, rect): + + if not ArtManager.Get().GetRaiseToolbar(): + return + + # fill with gradient + startColour = self.menuBarFaceColour() + dc.SetPen(wx.Pen(startColour)) + dc.SetBrush(wx.Brush(startColour)) + dc.DrawRectangle(0, 0, rect.GetWidth(), rect.GetHeight()) + + +#------------------------------------------------------------ +# Declare our main frame +#------------------------------------------------------------ + +class FlatMenuDemo(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent, size=(700, 500), style=wx.DEFAULT_FRAME_STYLE | + wx.NO_FULL_REPAINT_ON_RESIZE) + + self.SetIcon(images.Mondrian.GetIcon()) + wx.SystemOptions_SetOption("msw.remap", "0") + self.SetTitle("FlatMenu wxPython Demo ;-D") + + if _hasAUI: + self._mgr = AuiManager() + self._mgr.SetManagedWindow(self) + + self._popUpMenu = None + + mainSizer = wx.BoxSizer(wx.VERTICAL) + + # Create a main panel and place some controls on it + mainPanel = wx.Panel(self, wx.ID_ANY) + + panelSizer = wx.BoxSizer(wx.VERTICAL) + mainPanel.SetSizer(panelSizer) + + # Create minibar Preview Panel + minibarPanel= wx.Panel(self, wx.ID_ANY) + self.CreateMinibar(minibarPanel) + miniSizer = wx.BoxSizer(wx.VERTICAL) + miniSizer.Add(self._mtb, 0, wx.EXPAND) + minibarPanel.SetSizer(miniSizer) + + # Add log window + self.log = log + + hs = wx.BoxSizer(wx.HORIZONTAL) + btn = wx.Button(mainPanel, wx.ID_ANY, "Press me for pop up menu!") + hs.Add(btn, 0, wx.ALL, 5) + + # Connect a button + btn.Bind(wx.EVT_BUTTON, self.OnButtonClicked) + + btn = wx.Button(mainPanel, wx.ID_ANY, "Press me for a long menu!") + hs.Add(btn, 0, wx.ALL, 5) + + panelSizer.Add(hs, 0, wx.ALL, 5) + + # Connect a button + btn.Bind(wx.EVT_BUTTON, self.OnLongButtonClicked) + + statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + statusbar.SetStatusWidths([-2, -1]) + # statusbar fields + statusbar_fields = [("FlatMenu wxPython Demo, Andrea Gavana @ 01 Nov 2006"), + ("Welcome To wxPython!")] + + for i in range(len(statusbar_fields)): + statusbar.SetStatusText(statusbar_fields[i], i) + + self.CreateMenu() + self.ConnectEvents() + + mainSizer.Add(self._mb, 0, wx.EXPAND) + mainSizer.Add(mainPanel, 1, wx.EXPAND) + self.SetSizer(mainSizer) + mainSizer.Layout() + + if _hasAUI: + # AUI support + self._mgr.AddPane(mainPanel, AuiPaneInfo().Name("main_panel"). + CenterPane()) + + self._mgr.AddPane(minibarPanel, AuiPaneInfo().Name("minibar_panel"). + Caption("Minibar Preview").Right(). + MinSize(wx.Size(150, 200))) + + self._mb.PositionAUI(self._mgr) + self._mgr.Update() + + ArtManager.Get().SetMBVerticalGradient(True) + ArtManager.Get().SetRaiseToolbar(False) + + self._mb.Refresh() + self._mtb.Refresh() + + self.CenterOnScreen() + + + def CreateMinibar(self, parent): + # create mini toolbar + self._mtb = FM.FlatMenuBar(parent, wx.ID_ANY, 16, 6, options = FM_OPT_SHOW_TOOLBAR|FM_OPT_MINIBAR) + + checkCancelBmp = wx.Bitmap(os.path.join(bitmapDir, "ok-16.png"), wx.BITMAP_TYPE_PNG) + viewMagBmp = wx.Bitmap(os.path.join(bitmapDir, "viewmag-16.png"), wx.BITMAP_TYPE_PNG) + viewMagFitBmp = wx.Bitmap(os.path.join(bitmapDir, "viewmagfit-16.png"), wx.BITMAP_TYPE_PNG) + viewMagZoomBmp = wx.Bitmap(os.path.join(bitmapDir, "viewmag-p-16.png"), wx.BITMAP_TYPE_PNG) + viewMagZoomOutBmp = wx.Bitmap(os.path.join(bitmapDir, "viewmag-m-16.png"), wx.BITMAP_TYPE_PNG) + + self._mtb.AddCheckTool(wx.ID_ANY, "Check Settings Item", checkCancelBmp) + self._mtb.AddCheckTool(wx.ID_ANY, "Check Info Item", checkCancelBmp) + self._mtb.AddSeparator() + self._mtb.AddRadioTool(wx.ID_ANY, "Magnifier", viewMagBmp) + self._mtb.AddRadioTool(wx.ID_ANY, "Fit", viewMagFitBmp) + self._mtb.AddRadioTool(wx.ID_ANY, "Zoom In", viewMagZoomBmp) + self._mtb.AddRadioTool(wx.ID_ANY, "Zoom Out", viewMagZoomOutBmp) + + + def CreateMenu(self): + + # Create the menubar + self._mb = FM.FlatMenuBar(self, wx.ID_ANY, 32, 5, options = FM_OPT_SHOW_TOOLBAR | FM_OPT_SHOW_CUSTOMIZE) + + fileMenu = FM.FlatMenu() + styleMenu = FM.FlatMenu() + editMenu = FM.FlatMenu() + multipleMenu = FM.FlatMenu() + historyMenu = FM.FlatMenu() + subMenu = FM.FlatMenu() + helpMenu = FM.FlatMenu() + subMenu1 = FM.FlatMenu() + subMenuExit = FM.FlatMenu() + + self.newMyTheme = self._mb.GetRendererManager().AddRenderer(FM_MyRenderer()) + + # Load toolbar icons (32x32) + copy_bmp = wx.Bitmap(os.path.join(bitmapDir, "editcopy.png"), wx.BITMAP_TYPE_PNG) + cut_bmp = wx.Bitmap(os.path.join(bitmapDir, "editcut.png"), wx.BITMAP_TYPE_PNG) + paste_bmp = wx.Bitmap(os.path.join(bitmapDir, "editpaste.png"), wx.BITMAP_TYPE_PNG) + open_folder_bmp = wx.Bitmap(os.path.join(bitmapDir, "fileopen.png"), wx.BITMAP_TYPE_PNG) + new_file_bmp = wx.Bitmap(os.path.join(bitmapDir, "filenew.png"), wx.BITMAP_TYPE_PNG) + new_folder_bmp = wx.Bitmap(os.path.join(bitmapDir, "folder_new.png"), wx.BITMAP_TYPE_PNG) + save_bmp = wx.Bitmap(os.path.join(bitmapDir, "filesave.png"), wx.BITMAP_TYPE_PNG) + context_bmp = wx.Bitmap(os.path.join(bitmapDir, "contexthelp-16.png"), wx.BITMAP_TYPE_PNG) + colBmp = wx.Bitmap(os.path.join(bitmapDir, "month-16.png"), wx.BITMAP_TYPE_PNG) + view1Bmp = wx.Bitmap(os.path.join(bitmapDir, "view_choose.png"), wx.BITMAP_TYPE_PNG) + view2Bmp = wx.Bitmap(os.path.join(bitmapDir, "view_detailed.png"), wx.BITMAP_TYPE_PNG) + view3Bmp = wx.Bitmap(os.path.join(bitmapDir, "view_icon.png"), wx.BITMAP_TYPE_PNG) + view4Bmp = wx.Bitmap(os.path.join(bitmapDir, "view_multicolumn.png"), wx.BITMAP_TYPE_PNG) + + # Set an icon to the exit/help/transparency menu item + exitImg = wx.Bitmap(os.path.join(bitmapDir, "exit-16.png"), wx.BITMAP_TYPE_PNG) + helpImg = wx.Bitmap(os.path.join(bitmapDir, "help-16.png"), wx.BITMAP_TYPE_PNG) + ghostBmp = wx.Bitmap(os.path.join(bitmapDir, "field-16.png"), wx.BITMAP_TYPE_PNG) + + # Create a context menu + context_menu = FM.FlatMenu() + + # Create the menu items + menuItem = FM.FlatMenuItem(context_menu, wx.ID_ANY, "Test Item", "", wx.ITEM_NORMAL, None, context_bmp) + context_menu.AppendItem(menuItem) + + item = FM.FlatMenuItem(fileMenu, MENU_NEW_FILE, "&New File\tCtrl+N", "New File", wx.ITEM_NORMAL) + fileMenu.AppendItem(item) + item.SetContextMenu(context_menu) + + self._mb.AddTool(MENU_NEW_FILE, "New File", new_file_bmp) + + item = FM.FlatMenuItem(fileMenu, MENU_SAVE, "&Save File\tCtrl+S", "Save File", wx.ITEM_NORMAL) + fileMenu.AppendItem(item) + self._mb.AddTool(MENU_SAVE, "Save File", save_bmp) + + item = FM.FlatMenuItem(fileMenu, MENU_OPEN_FILE, "&Open File\tCtrl+O", "Open File", wx.ITEM_NORMAL) + fileMenu.AppendItem(item) + self._mb.AddTool(MENU_OPEN_FILE, "Open File", open_folder_bmp) + self._mb.AddSeparator() # Toolbar separator + + item = FM.FlatMenuItem(fileMenu, MENU_NEW_FOLDER, "N&ew Folder\tCtrl+E", "New Folder", wx.ITEM_NORMAL) + fileMenu.AppendItem(item) + + self._mb.AddTool(MENU_NEW_FOLDER, "New Folder",new_folder_bmp) + self._mb.AddSeparator() # Toobar separator + + item = FM.FlatMenuItem(fileMenu, MENU_COPY, "&Copy\tCtrl+C", "Copy", wx.ITEM_NORMAL) + fileMenu.AppendItem(item) + self._mb.AddTool(MENU_COPY, "Copy", copy_bmp) + + item = FM.FlatMenuItem(fileMenu, MENU_CUT, "Cut\tCtrl+X", "Cut", wx.ITEM_NORMAL) + fileMenu.AppendItem(item) + self._mb.AddTool(MENU_CUT, "Cut", cut_bmp) + + item = FM.FlatMenuItem(fileMenu, MENU_PASTE, "Paste\tCtrl+V", "Paste", wx.ITEM_NORMAL, subMenuExit) + fileMenu.AppendItem(item) + self._mb.AddTool(MENU_PASTE, "Paste", paste_bmp) + + self._mb.AddSeparator() # Separator + + # Add a wx.ComboBox to FlatToolbar + combo = wx.ComboBox(self._mb, -1, choices=["Hello", "World", "wxPython"]) + self._mb.AddControl(combo) + + self._mb.AddSeparator() # Separator + + stext = wx.StaticText(self._mb, -1, "Hello") + #stext.SetBackgroundStyle(wx.BG_STYLE_CUSTOM ) + + self._mb.AddControl(stext) + + self._mb.AddSeparator() # Separator + + # Add another couple of bitmaps + self._mb.AddRadioTool(wx.ID_ANY, "View Column", view1Bmp) + self._mb.AddRadioTool(wx.ID_ANY, "View Icons", view2Bmp) + self._mb.AddRadioTool(wx.ID_ANY, "View Details", view3Bmp) + self._mb.AddRadioTool(wx.ID_ANY, "View Multicolumn", view4Bmp) + + # Add non-toolbar item + item = FM.FlatMenuItem(subMenuExit, wx.ID_EXIT, "E&xit\tAlt+X", "Exit demo", wx.ITEM_NORMAL, None, exitImg) + subMenuExit.AppendItem(item) + fileMenu.AppendSeparator() + item = FM.FlatMenuItem(subMenuExit, wx.ID_EXIT, "E&xit\tAlt+Q", "Exit demo", wx.ITEM_NORMAL, None, exitImg) + fileMenu.AppendItem(item) + + # Second menu + item = FM.FlatMenuItem(styleMenu, MENU_STYLE_DEFAULT, "Menu style Default\tAlt+N", "Menu style Default", wx.ITEM_RADIO) + styleMenu.AppendItem(item) + item.Check(True) + + item = FM.FlatMenuItem(styleMenu, MENU_STYLE_MY, "Menu style Custom \tAlt+C", "Menu style Custom", wx.ITEM_RADIO) + styleMenu.AppendItem(item) + + item = FM.FlatMenuItem(styleMenu, MENU_STYLE_XP, "Menu style XP\tAlt+P", "Menu style XP", wx.ITEM_RADIO) + styleMenu.AppendItem(item) + + item = FM.FlatMenuItem(styleMenu, MENU_STYLE_2007, "Menu style 2007\tAlt+O", "Menu style 2007", wx.ITEM_RADIO) + styleMenu.AppendItem(item) + + item = FM.FlatMenuItem(styleMenu, MENU_STYLE_VISTA, "Menu style Vista\tAlt+V", "Menu style Vista", wx.ITEM_RADIO) + styleMenu.AppendItem(item) + + styleMenu.AppendSeparator() + item = FM.FlatMenuItem(styleMenu, MENU_USE_CUSTOM, "Show Customize DropDown", "Shows the customize drop down arrow", wx.ITEM_CHECK) + + # Demonstrate how to set custom font and text colour to a FlatMenuItem + item.SetFont(wx.Font(10, wx.SWISS, wx.ITALIC, wx.BOLD, False, "Courier New")) + item.SetTextColour(wx.RED) + + item.Check(True) + styleMenu.AppendItem(item) + + styleMenu.AppendSeparator() + item = FM.FlatMenuItem(styleMenu, MENU_LCD_MONITOR, "Use LCD monitors option", "Instructs FlatMenu to use LCD drawings", wx.ITEM_CHECK) + styleMenu.AppendItem(item) + + # Add some radio items + styleMenu.AppendSeparator() + # Add sub-menu to main menu + item = FM.FlatMenuItem(styleMenu, wx.ID_ANY, "Sub-&menu radio items", "", wx.ITEM_NORMAL, subMenu1) + styleMenu.AppendItem(item) + item.SetContextMenu(context_menu) + + item = FM.FlatMenuItem(subMenu1, wx.ID_ANY, "Radio Item 1", "Radio Item 1", wx.ITEM_RADIO) + subMenu1.AppendItem(item) + + item = FM.FlatMenuItem(subMenu1, wx.ID_ANY, "Radio Item 2", "Radio Item 2", wx.ITEM_RADIO) + subMenu1.AppendItem(item) + item.Check(True) + + item = FM.FlatMenuItem(subMenu1, wx.ID_ANY, "Radio Item 3", "Radio Item 3", wx.ITEM_RADIO) + subMenu1.AppendItem(item) + + item = FM.FlatMenuItem(editMenu, MENU_REMOVE_MENU, "Remove menu", "Remove menu", wx.ITEM_NORMAL) + editMenu.AppendItem(item) + + item = FM.FlatMenuItem(editMenu, MENU_DISABLE_MENU_ITEM, "Disable Menu Item ...", "Disable Menu Item", wx.ITEM_NORMAL) + editMenu.AppendItem(item) + + editMenu.AppendSeparator() + + item = FM.FlatMenuItem(editMenu, MENU_TRANSPARENCY, "Set FlatMenu transparency...", "Sets the FlatMenu transparency", + wx.ITEM_NORMAL, None, ghostBmp) + + editMenu.AppendItem(item) + + # Add some dummy entries to the sub menu + # Add sub-menu to main menu + item = FM.FlatMenuItem(editMenu, 9001, "Sub-&menu items", "", wx.ITEM_NORMAL, subMenu) + editMenu.AppendItem(item) + + # Create the submenu items and add them + item = FM.FlatMenuItem(subMenu, 9002, "&Sub-menu Item 1", "", wx.ITEM_NORMAL) + subMenu.AppendItem(item) + + item = FM.FlatMenuItem(subMenu, 9003, "Su&b-menu Item 2", "", wx.ITEM_NORMAL) + subMenu.AppendItem(item) + + item = FM.FlatMenuItem(subMenu, 9004, "Sub-menu Item 3", "", wx.ITEM_NORMAL) + subMenu.AppendItem(item) + + item = FM.FlatMenuItem(subMenu, 9005, "Sub-menu Item 4", "", wx.ITEM_NORMAL) + subMenu.AppendItem(item) + + maxItems = 17 + numCols = 2 + switch = int(math.ceil(maxItems/float(numCols))) + + fnt = wx.Font(9, wx.SWISS, wx.ITALIC, wx.BOLD, False, "Courier New") + colours = [wx.RED, wx.GREEN, wx.BLUE] + for i in xrange(17): + row, col = i%switch, i/switch + result = random.randint(0, 1) == 1 + bmp = (result and [colBmp] or [wx.NullBitmap])[0] + item = FM.FlatMenuItem(multipleMenu, wx.ID_ANY, "Row %d, Col %d"%((row+1, col+1)), "", wx.ITEM_NORMAL, None, bmp) + if result == 0: + # Demonstrate how to set custom font and text colour to a FlatMenuItem + col = random.randint(0, 2) + item.SetFont(fnt) + item.SetTextColour(colours[col]) + + multipleMenu.AppendItem(item) + + multipleMenu.SetNumberColumns(2) + + historyMenu.Append(wx.ID_OPEN, "&Open...") + self.historyMenu = historyMenu + self.filehistory = FM.FileHistory() + self.filehistory.UseMenu(self.historyMenu) + + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnFileOpenDialog, id=wx.ID_OPEN) + + item = FM.FlatMenuItem(helpMenu, MENU_HELP, "&About\tCtrl+A", "About...", wx.ITEM_NORMAL, None, helpImg) + helpMenu.AppendItem(item) + + fileMenu.SetBackgroundBitmap(CreateBackgroundBitmap()) + + # Add menu to the menu bar + self._mb.Append(fileMenu, "&File") + self._mb.Append(styleMenu, "&Style") + self._mb.Append(editMenu, "&Edit") + self._mb.Append(multipleMenu, "&Multiple Columns") + self._mb.Append(historyMenu, "File Histor&y") + self._mb.Append(helpMenu, "&Help") + + + def ConnectEvents(self): + + # Attach menu events to some handlers + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnQuit, id=wx.ID_EXIT) + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnEdit, id=MENU_DISABLE_MENU_ITEM, id2=MENU_REMOVE_MENU) + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnStyle, id=MENU_STYLE_XP, id2=MENU_STYLE_VISTA) + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnFlatMenuCmd, id=MENU_NEW_FILE, id2=20013) + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnAbout, id=MENU_HELP) + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnStyle, id=MENU_STYLE_MY) + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnStyle, id=MENU_STYLE_DEFAULT) + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnShowCustom, id=MENU_USE_CUSTOM) + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnLCDMonitor, id=MENU_LCD_MONITOR) + self.Bind(FM.EVT_FLAT_MENU_SELECTED, self.OnTransparency, id=MENU_TRANSPARENCY) + + self.Bind(FM.EVT_FLAT_MENU_ITEM_MOUSE_OVER, self.OnMouseOver, id=MENU_NEW_FILE) + self.Bind(FM.EVT_FLAT_MENU_ITEM_MOUSE_OUT, self.OnMouseOut, id=MENU_NEW_FILE) + + self.Bind(wx.EVT_UPDATE_UI, self.OnFlatMenuCmdUI, id=20001, id2=20013) + if "__WXMAC__" in wx.Platform: + self.Bind(wx.EVT_SIZE, self.OnSize) + + self.Bind(FM.EVT_FLAT_MENU_RANGE, self.OnFileHistory, id=wx.ID_FILE1, id2=wx.ID_FILE9+1) + + + def OnSize(self, event): + + self._mgr.Update() + self.Layout() + + + def OnQuit(self, event): + + if _hasAUI: + self._mgr.UnInit() + + self.Destroy() + + + def OnButtonClicked(self, event): + + # Demonstrate using the wxFlatMenu without a menu bar + btn = event.GetEventObject() + + # Create the popup menu + self.CreatePopupMenu() + + # Position the menu: + # The menu should be positioned at the bottom left corner of the button. + btnSize = btn.GetSize() + btnPt = btn.GetPosition() + + # Since the btnPt (button position) is in client coordinates, + # and the menu coordinates is relative to screen we convert + # the coords + btnPt = btn.GetParent().ClientToScreen(btnPt) + + # A nice feature with the Popup menu, is the ability to provide an + # object that we wish to handle the menu events, in this case we + # pass 'self' + # if we wish the menu to appear under the button, we provide its height + self._popUpMenu.SetOwnerHeight(btnSize.y) + self._popUpMenu.Popup(wx.Point(btnPt.x, btnPt.y), self) + + + def OnLongButtonClicked(self, event): + + # Demonstrate using the wxFlatMenu without a menu bar + btn = event.GetEventObject() + + # Create the popup menu + self.CreateLongPopupMenu() + + # Postion the menu: + # The menu should be positioned at the bottom left corner of the button. + btnSize = btn.GetSize() + + # btnPt is returned relative to its parent + # so, we need to convert it to screen + btnPt = btn.GetPosition() + btnPt = btn.GetParent().ClientToScreen(btnPt) + + # if we wish the menu to appear under the button, we provide its height + self._longPopUpMenu.SetOwnerHeight(btnSize.y) + self._longPopUpMenu.Popup(wx.Point(btnPt.x, btnPt.y), self) + + + def CreatePopupMenu(self): + + if not self._popUpMenu: + + self._popUpMenu = FM.FlatMenu() + #----------------------------------------------- + # Flat Menu test + #----------------------------------------------- + + # First we create the sub-menu item + subMenu = FM.FlatMenu() + subSubMenu = FM.FlatMenu() + + # Create the menu items + menuItem = FM.FlatMenuItem(self._popUpMenu, 20001, "First Menu Item", "", wx.ITEM_CHECK) + self._popUpMenu.AppendItem(menuItem) + + menuItem = FM.FlatMenuItem(self._popUpMenu, 20002, "Sec&ond Menu Item", "", wx.ITEM_CHECK) + self._popUpMenu.AppendItem(menuItem) + + menuItem = FM.FlatMenuItem(self._popUpMenu, wx.ID_ANY, "Checkable-Disabled Item", "", wx.ITEM_CHECK) + menuItem.Enable(False) + self._popUpMenu.AppendItem(menuItem) + + menuItem = FM.FlatMenuItem(self._popUpMenu, 20003, "Third Menu Item", "", wx.ITEM_CHECK) + self._popUpMenu.AppendItem(menuItem) + + self._popUpMenu.AppendSeparator() + + # Add sub-menu to main menu + menuItem = FM.FlatMenuItem(self._popUpMenu, 20004, "Sub-&menu item", "", wx.ITEM_NORMAL, subMenu) + self._popUpMenu.AppendItem(menuItem) + + # Create the submenu items and add them + menuItem = FM.FlatMenuItem(subMenu, 20005, "&Sub-menu Item 1", "", wx.ITEM_NORMAL) + subMenu.AppendItem(menuItem) + + menuItem = FM.FlatMenuItem(subMenu, 20006, "Su&b-menu Item 2", "", wx.ITEM_NORMAL) + subMenu.AppendItem(menuItem) + + menuItem = FM.FlatMenuItem(subMenu, 20007, "Sub-menu Item 3", "", wx.ITEM_NORMAL) + subMenu.AppendItem(menuItem) + + menuItem = FM.FlatMenuItem(subMenu, 20008, "Sub-menu Item 4", "", wx.ITEM_NORMAL) + subMenu.AppendItem(menuItem) + + # Create the submenu items and add them + menuItem = FM.FlatMenuItem(subSubMenu, 20009, "Sub-menu Item 1", "", wx.ITEM_NORMAL) + subSubMenu.AppendItem(menuItem) + + menuItem = FM.FlatMenuItem(subSubMenu, 20010, "Sub-menu Item 2", "", wx.ITEM_NORMAL) + subSubMenu.AppendItem(menuItem) + + menuItem = FM.FlatMenuItem(subSubMenu, 20011, "Sub-menu Item 3", "", wx.ITEM_NORMAL) + subSubMenu.AppendItem(menuItem) + + menuItem = FM.FlatMenuItem(subSubMenu, 20012, "Sub-menu Item 4", "", wx.ITEM_NORMAL) + subSubMenu.AppendItem(menuItem) + + # Add sub-menu to submenu menu + menuItem = FM.FlatMenuItem(subMenu, 20013, "Sub-menu item", "", wx.ITEM_NORMAL, subSubMenu) + subMenu.AppendItem(menuItem) + + + def CreateLongPopupMenu(self): + + if hasattr(self, "_longPopUpMenu"): + return + + self._longPopUpMenu = FM.FlatMenu() + sub = FM.FlatMenu() + + #----------------------------------------------- + # Flat Menu test + #----------------------------------------------- + + for ii in xrange(30): + if ii == 0: + menuItem = FM.FlatMenuItem(self._longPopUpMenu, wx.ID_ANY, "Menu Item #%ld"%(ii+1), "", wx.ITEM_NORMAL, sub) + self._longPopUpMenu.AppendItem(menuItem) + + for k in xrange(5): + + menuItem = FM.FlatMenuItem(sub, wx.ID_ANY, "Sub Menu Item #%ld"%(k+1)) + sub.AppendItem(menuItem) + + else: + + menuItem = FM.FlatMenuItem(self._longPopUpMenu, wx.ID_ANY, "Menu Item #%ld"%(ii+1)) + self._longPopUpMenu.AppendItem(menuItem) + +# ------------------------------------------ +# Event handlers +# ------------------------------------------ + + def OnStyle(self, event): + + eventId = event.GetId() + + if eventId == MENU_STYLE_DEFAULT: + self._mb.GetRendererManager().SetTheme(FM.StyleDefault) + elif eventId == MENU_STYLE_2007: + self._mb.GetRendererManager().SetTheme(FM.Style2007) + elif eventId == MENU_STYLE_XP: + self._mb.GetRendererManager().SetTheme(FM.StyleXP) + elif eventId == MENU_STYLE_VISTA: + self._mb.GetRendererManager().SetTheme(FM.StyleVista) + elif eventId == MENU_STYLE_MY: + self._mb.GetRendererManager().SetTheme(self.newMyTheme) + + self._mb.ClearBitmaps() + + self._mb.Refresh() + self._mtb.Refresh() + self.Update() + + + def OnShowCustom(self, event): + + self._mb.ShowCustomize(event.IsChecked()) + + + def OnLCDMonitor(self, event): + + self._mb.SetLCDMonitor(event.IsChecked()) + + + def OnTransparency(self, event): + + transparency = ArtManager.Get().GetTransparency() + dlg = wx.TextEntryDialog(self, 'Please enter a value for menu transparency', + 'FlatMenu Transparency', str(transparency)) + + if dlg.ShowModal() != wx.ID_OK: + dlg.Destroy() + return + + value = dlg.GetValue() + dlg.Destroy() + + try: + value = int(value) + except: + dlg = wx.MessageDialog(self, "Invalid transparency value!", "Error", + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + + if value < 0 or value > 255: + dlg = wx.MessageDialog(self, "Invalid transparency value!", "Error", + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + + ArtManager.Get().SetTransparency(value) + + + def OnMouseOver(self, event): + + self.log.write("Received Flat menu mouse enter ID: %d\n"%(event.GetId())) + + + def OnMouseOut(self, event): + + self.log.write("Received Flat menu mouse leave ID: %d\n"%(event.GetId())) + + + def OnFlatMenuCmd(self, event): + + self.log.write("Received Flat menu command event ID: %d\n"%(event.GetId())) + + + def OnFlatMenuCmdUI(self, event): + + self.log.write("Received Flat menu update UI event ID: %d\n"%(event.GetId())) + + + def GetStringFromUser(self, msg): + + dlg = wx.TextEntryDialog(self, msg, "Enter Text") + + userString = "" + if dlg.ShowModal() == wx.ID_OK: + userString = dlg.GetValue() + + dlg.Destroy() + + return userString + + + def OnFileOpenDialog(self, evt): + dlg = wx.FileDialog(self, defaultDir = os.getcwd(), + wildcard = "All Files|*", style = wx.OPEN | wx.CHANGE_DIR) + + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + self.log.write("You selected %s\n" % path) + + # add it to the history + self.filehistory.AddFileToHistory(path) + + dlg.Destroy() + + + def OnFileHistory(self, evt): + # get the file based on the menu ID + fileNum = evt.GetId() - wx.ID_FILE1 + path = self.filehistory.GetHistoryFile(fileNum) + self.log.write("You selected %s\n" % path) + + # add it back to the history so it will be moved up the list + self.filehistory.AddFileToHistory(path) + + + def OnEdit(self, event): + + if event.GetId() == MENU_REMOVE_MENU: + + idxStr = self.GetStringFromUser("Insert menu index to remove:") + if idxStr.strip() != "": + + idx = int(idxStr) + self._mb.Remove(idx) + + elif event.GetId() == MENU_DISABLE_MENU_ITEM: + + idxStr = self.GetStringFromUser("Insert menu item ID to be disabled (10005 - 10011):") + if idxStr.strip() != "": + + idx = int(idxStr) + mi = self._mb.FindMenuItem(idx) + if mi: + mi.Enable(False) + + + def OnAbout(self, event): + + msg = "This is the About Dialog of the FlatMenu demo.\n\n" + \ + "Author: Andrea Gavana @ 03 Nov 2006\n\n" + \ + "Please report any bug/requests or improvements\n" + \ + "to Andrea Gavana at the following email addresses:\n\n" + \ + "andrea.gavana@gmail.com\nandrea.gavana@maerskoil.com\n\n" + \ + "Welcome to wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "FlatMenu wxPython Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test FlatMenu ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = FlatMenuDemo(self, self.log) + self.win.Show(True) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + if wx.Platform != '__WXMAC__': + win = TestPanel(nb, log) + return win + else: + from Main import MessagePanel + win = MessagePanel(nb, 'This demo only works on MSW and GTK.', + 'Sorry', wx.ICON_WARNING) + return win + +#---------------------------------------------------------------------- + + +overview = FM.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/FlatNotebook.py b/demo/agw/FlatNotebook.py new file mode 100644 index 00000000..8ce497f7 --- /dev/null +++ b/demo/agw/FlatNotebook.py @@ -0,0 +1,992 @@ +import wx + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + import agw.flatnotebook as FNB +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.flatnotebook as FNB + +import random +import images + + +#---------------------------------------------------------------------- + + +MENU_EDIT_DELETE_ALL = wx.NewId() +MENU_EDIT_ADD_PAGE = wx.NewId() +MENU_EDIT_DELETE_PAGE = wx.NewId() +MENU_EDIT_SET_SELECTION = wx.NewId() +MENU_EDIT_ADVANCE_SELECTION_FWD = wx.NewId() +MENU_EDIT_ADVANCE_SELECTION_BACK = wx.NewId() +MENU_SET_ALL_TABS_SHAPE_ANGLE = wx.NewId() +MENU_SHOW_IMAGES = wx.NewId() +MENU_USE_VC71_STYLE = wx.NewId() +MENU_USE_DEFAULT_STYLE = wx.NewId() +MENU_USE_FANCY_STYLE = wx.NewId() +MENU_USE_RIBBON_STYLE = wx.NewId() +MENU_SELECT_GRADIENT_COLOUR_FROM = wx.NewId() +MENU_SELECT_GRADIENT_COLOUR_TO = wx.NewId() +MENU_SELECT_GRADIENT_COLOUR_BORDER = wx.NewId() +MENU_SET_PAGE_IMAGE_INDEX = wx.NewId() +MENU_HIDE_X = wx.NewId() +MENU_HIDE_NAV_BUTTONS = wx.NewId() +MENU_USE_MOUSE_MIDDLE_BTN = wx.NewId() +MENU_DRAW_BORDER = wx.NewId() +MENU_USE_BOTTOM_TABS = wx.NewId() +MENU_ENABLE_TAB = wx.NewId() +MENU_DISABLE_TAB = wx.NewId() +MENU_ENABLE_DRAG_N_DROP = wx.NewId() +MENU_DCLICK_CLOSES_TAB = wx.NewId() +MENU_USE_VC8_STYLE = wx.NewId() +MENU_USE_FF2_STYLE = wx.NewId() +MENU_HIDE_ON_SINGLE_TAB = wx.NewId() +MENU_HIDE_TABS = wx.NewId() +MENU_NO_TABS_FOCUS = wx.NewId() + +MENU_SET_ACTIVE_TEXT_COLOUR = wx.NewId() +MENU_DRAW_TAB_X = wx.NewId() +MENU_SET_ACTIVE_TAB_COLOUR = wx.NewId() +MENU_SET_TAB_AREA_COLOUR = wx.NewId() +MENU_SELECT_NONACTIVE_TEXT_COLOUR = wx.NewId() +MENU_GRADIENT_BACKGROUND = wx.NewId() +MENU_COLOURFUL_TABS = wx.NewId() +MENU_SMART_TABS = wx.NewId() +MENU_USE_DROP_ARROW_BUTTON = wx.NewId() +MENU_ALLOW_FOREIGN_DND = wx.NewId() + +MENU_TILE_HORIZONTALLY = wx.NewId() +MENU_TILE_VERTICALLY = wx.NewId() +MENU_TILE_NONE = wx.NewId() + + +class FlatNotebookDemo(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent, title="FlatNotebook Demo", size=(800,600)) + self.log = log + + self._bShowImages = False + self._bVCStyle = False + self._newPageCounter = 0 + + self._ImageList = wx.ImageList(16, 16) + self._ImageList.Add(images._book_red.GetBitmap()) + self._ImageList.Add(images._book_green.GetBitmap()) + self._ImageList.Add(images._book_blue.GetBitmap()) + + self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + self.statusbar.SetStatusWidths([-2, -1]) + # statusbar fields + statusbar_fields = [("FlatNotebook wxPython Demo, Andrea Gavana @ 02 Oct 2006"), + ("Welcome To wxPython!")] + + for i in range(len(statusbar_fields)): + self.statusbar.SetStatusText(statusbar_fields[i], i) + + self.SetIcon(images.Mondrian.GetIcon()) + self.CreateMenuBar() + self.CreateRightClickMenu() + self.LayoutItems() + + self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CHANGING, self.OnPageChanging) + self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged) + self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_CLOSING, self.OnPageClosing) + self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_DROPPED_FOREIGN, self.OnForeignDrop) + self.Bind(FNB.EVT_FLATNOTEBOOK_PAGE_DROPPED, self.OnDrop) + + self.Bind(wx.EVT_UPDATE_UI, self.OnDropDownArrowUI, id=MENU_USE_DROP_ARROW_BUTTON) + self.Bind(wx.EVT_UPDATE_UI, self.OnHideNavigationButtonsUI, id=MENU_HIDE_NAV_BUTTONS) + self.Bind(wx.EVT_UPDATE_UI, self.OnAllowForeignDndUI, id=MENU_ALLOW_FOREIGN_DND) + + + def CreateMenuBar(self): + + self._menuBar = wx.MenuBar(wx.MB_DOCKABLE) + self._fileMenu = wx.Menu() + self._editMenu = wx.Menu() + self._visualMenu = wx.Menu() + + item = wx.MenuItem(self._fileMenu, wx.ID_ANY, "&Close\tCtrl-Q", "Close demo window") + self.Bind(wx.EVT_MENU, self.OnQuit, item) + self._fileMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_EDIT_ADD_PAGE, "New Page\tCtrl+N", "Add New Page") + self.Bind(wx.EVT_MENU, self.OnAddPage, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_EDIT_DELETE_PAGE, "Delete Page\tCtrl+F4", "Delete Page") + self.Bind(wx.EVT_MENU, self.OnDeletePage, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_EDIT_DELETE_ALL, "Delete All Pages", "Delete All Pages") + self.Bind(wx.EVT_MENU, self.OnDeleteAll, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_EDIT_SET_SELECTION, "Set Selection", "Set Selection") + self.Bind(wx.EVT_MENU, self.OnSetSelection, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_EDIT_ADVANCE_SELECTION_FWD, "Advance Selection Forward", + "Advance Selection Forward") + self.Bind(wx.EVT_MENU, self.OnAdvanceSelectionFwd, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_EDIT_ADVANCE_SELECTION_BACK, "Advance Selection Backward", + "Advance Selection Backward") + self.Bind(wx.EVT_MENU, self.OnAdvanceSelectionBack, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_SET_ALL_TABS_SHAPE_ANGLE, "Set an inclination of tab header borders", + "Set the shape of tab header") + self.Bind(wx.EVT_MENU, self.OnSetAllPagesShapeAngle, item) + self._visualMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_SET_PAGE_IMAGE_INDEX, "Set image index of selected page", + "Set image index") + self.Bind(wx.EVT_MENU, self.OnSetPageImage, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_SHOW_IMAGES, "Show Images", "Show Images", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnShowImages, item) + self._editMenu.AppendItem(item) + + styleMenu = wx.Menu() + item = wx.MenuItem(styleMenu, MENU_USE_DEFAULT_STYLE, "Use Default Style", "Use VC71 Style", wx.ITEM_RADIO) + self.Bind(wx.EVT_MENU, self.OnDefaultStyle, item) + styleMenu.AppendItem(item) + + item = wx.MenuItem(styleMenu, MENU_USE_VC71_STYLE, "Use VC71 Style", "Use VC71 Style", wx.ITEM_RADIO) + self.Bind(wx.EVT_MENU, self.OnVC71Style, item) + styleMenu.AppendItem(item) + + item = wx.MenuItem(styleMenu, MENU_USE_VC8_STYLE, "Use VC8 Style", "Use VC8 Style", wx.ITEM_RADIO) + self.Bind(wx.EVT_MENU, self.OnVC8Style, item) + styleMenu.AppendItem(item) + + item = wx.MenuItem(styleMenu, MENU_USE_FANCY_STYLE, "Use Fancy Style", "Use Fancy Style", wx.ITEM_RADIO) + self.Bind(wx.EVT_MENU, self.OnFancyStyle, item) + styleMenu.AppendItem(item) + + item = wx.MenuItem(styleMenu, MENU_USE_FF2_STYLE, "Use Firefox 2 Style", "Use Firefox 2 Style", wx.ITEM_RADIO) + self.Bind(wx.EVT_MENU, self.OnFF2Style, item) + styleMenu.AppendItem(item) + + item = wx.MenuItem(styleMenu, MENU_USE_RIBBON_STYLE, "Use Ribbon Style", "Use Ribbon Style", wx.ITEM_RADIO) + self.Bind(wx.EVT_MENU, self.OnRibbonStyle, item) + styleMenu.AppendItem(item) + + self._visualMenu.AppendMenu(wx.ID_ANY, "Tabs Style", styleMenu) + + item = wx.MenuItem(self._visualMenu, MENU_SELECT_GRADIENT_COLOUR_FROM, "Select fancy tab style 'from' colour", + "Select fancy tab style 'from' colour") + self._visualMenu.AppendItem(item) + + item = wx.MenuItem(self._visualMenu, MENU_SELECT_GRADIENT_COLOUR_TO, "Select fancy tab style 'to' colour", + "Select fancy tab style 'to' colour") + self._visualMenu.AppendItem(item) + + item = wx.MenuItem(self._visualMenu, MENU_SELECT_GRADIENT_COLOUR_BORDER, "Select fancy tab style 'border' colour", + "Select fancy tab style 'border' colour") + self._visualMenu.AppendItem(item) + + self._editMenu.AppendSeparator() + + self.Bind(wx.EVT_MENU_RANGE, self.OnSelectColour, id=MENU_SELECT_GRADIENT_COLOUR_FROM, + id2=MENU_SELECT_GRADIENT_COLOUR_BORDER) + + item = wx.MenuItem(self._editMenu, MENU_HIDE_ON_SINGLE_TAB, "Hide Page Container when only one Tab", + "Hide Page Container when only one Tab", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnStyle, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_HIDE_TABS, "Hide Tabs", + "Hide Page Container allowing only keyboard navigation", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnStyle, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_NO_TABS_FOCUS, "No focus on notebook tabs", + "No focus on notebook tabs, only pages", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnStyle, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_HIDE_NAV_BUTTONS, "Hide Navigation Buttons", + "Hide Navigation Buttons", wx.ITEM_CHECK) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_HIDE_X, "Hide X Button", "Hide X Button", wx.ITEM_CHECK) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_SMART_TABS, "Smart tabbing", "Smart tabbing", wx.ITEM_CHECK) + self._editMenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnSmartTabs, item) + item.Check(False) + + item = wx.MenuItem(self._editMenu, MENU_USE_DROP_ARROW_BUTTON, "Use drop down button for tab navigation", + "Use drop down arrow for quick tab navigation", wx.ITEM_CHECK) + self._editMenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnDropDownArrow, item) + item.Check(False) + self._editMenu.AppendSeparator() + + item = wx.MenuItem(self._editMenu, MENU_TILE_HORIZONTALLY, "Tile pages horizontally", + "Tile all the panels in an horizontal sizer", wx.ITEM_RADIO) + self._editMenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnTile, item) + + item = wx.MenuItem(self._editMenu, MENU_TILE_VERTICALLY, "Tile pages vertically", + "Tile all the panels in a vertical sizer", wx.ITEM_RADIO) + self._editMenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnTile, item) + + item = wx.MenuItem(self._editMenu, MENU_TILE_NONE, "No tiling", + "No tiling, standard FlatNotebook behaviour", wx.ITEM_RADIO) + self._editMenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnTile, item) + + item.Check(True) + + self._editMenu.AppendSeparator() + + item = wx.MenuItem(self._editMenu, wx.ID_ANY, "Use custom page", + "Shows a custom page when the main notebook has no pages left", wx.ITEM_CHECK) + self._editMenu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnCustomPanel, item) + + self._editMenu.AppendSeparator() + + item = wx.MenuItem(self._editMenu, MENU_USE_MOUSE_MIDDLE_BTN, "Use Mouse Middle Button as 'X' button", + "Use Mouse Middle Button as 'X' button", wx.ITEM_CHECK) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_DCLICK_CLOSES_TAB, "Mouse double click closes tab", + "Mouse double click closes tab", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnDClickCloseTab, item) + self._editMenu.AppendItem(item) + item.Check(False) + + self._editMenu.AppendSeparator() + + item = wx.MenuItem(self._editMenu, MENU_USE_BOTTOM_TABS, "Use Bottoms Tabs", "Use Bottoms Tabs", + wx.ITEM_CHECK) + self._editMenu.AppendItem(item) + + self.Bind(wx.EVT_MENU_RANGE, self.OnStyle, id=MENU_HIDE_X, id2=MENU_USE_BOTTOM_TABS) + + item = wx.MenuItem(self._editMenu, MENU_ENABLE_TAB, "Enable Tab", "Enable Tab") + self.Bind(wx.EVT_MENU, self.OnEnableTab, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_DISABLE_TAB, "Disable Tab", "Disable Tab") + self.Bind(wx.EVT_MENU, self.OnDisableTab, item) + self._editMenu.AppendItem(item) + + item = wx.MenuItem(self._editMenu, MENU_ENABLE_DRAG_N_DROP, "Enable Drag And Drop of Tabs", + "Enable Drag And Drop of Tabs", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnEnableDrag, item) + self._editMenu.AppendItem(item) + item.Check(False) + + item = wx.MenuItem(self._editMenu, MENU_ALLOW_FOREIGN_DND, "Enable Drag And Drop of Tabs from foreign notebooks", + "Enable Drag And Drop of Tabs from foreign notebooks", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnAllowForeignDnd, item) + self._editMenu.AppendItem(item) + item.Check(False); + + item = wx.MenuItem(self._visualMenu, MENU_DRAW_BORDER, "Draw Border around tab area", + "Draw Border around tab area", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnStyle, item) + self._visualMenu.AppendItem(item) + item.Check(True) + + item = wx.MenuItem(self._visualMenu, MENU_DRAW_TAB_X, "Draw X button On Active Tab", + "Draw X button On Active Tab", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnDrawTabX, item) + self._visualMenu.AppendItem(item) + + item = wx.MenuItem(self._visualMenu, MENU_SET_ACTIVE_TAB_COLOUR, "Select Active Tab Colour", + "Select Active Tab Colour") + self.Bind(wx.EVT_MENU, self.OnSelectColour, item) + self._visualMenu.AppendItem(item) + + item = wx.MenuItem(self._visualMenu, MENU_SET_TAB_AREA_COLOUR, "Select Tab Area Colour", + "Select Tab Area Colour") + self.Bind(wx.EVT_MENU, self.OnSelectColour, item) + self._visualMenu.AppendItem(item) + + item = wx.MenuItem(self._visualMenu, MENU_SET_ACTIVE_TEXT_COLOUR, "Select active tab text colour", + "Select active tab text colour") + self.Bind(wx.EVT_MENU, self.OnSelectColour, item) + self._visualMenu.AppendItem(item) + + item = wx.MenuItem(self._visualMenu, MENU_SELECT_NONACTIVE_TEXT_COLOUR, + "Select NON-active tab text colour", "Select NON-active tab text colour") + self.Bind(wx.EVT_MENU, self.OnSelectColour, item) + self._visualMenu.AppendItem(item) + + item = wx.MenuItem(self._visualMenu, MENU_GRADIENT_BACKGROUND, "Use Gradient Colouring for tab area", + "Use Gradient Colouring for tab area", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnGradientBack, item) + self._visualMenu.AppendItem(item) + item.Check(False) + + item = wx.MenuItem(self._visualMenu, MENU_COLOURFUL_TABS, "Colourful tabs", "Colourful tabs", wx.ITEM_CHECK) + self.Bind(wx.EVT_MENU, self.OnColourfulTabs, item) + self._visualMenu.AppendItem(item) + item.Check(False) + + help_menu = wx.Menu() + item = wx.MenuItem(help_menu, wx.ID_ANY, "About...", "Shows The About Dialog") + self.Bind(wx.EVT_MENU, self.OnAbout, item) + help_menu.AppendItem(item) + + self._menuBar.Append(self._fileMenu, "&File") + self._menuBar.Append(self._editMenu, "&Edit") + self._menuBar.Append(self._visualMenu, "&Tab Appearance") + + self._menuBar.Append(help_menu, "&Help") + + self.SetMenuBar(self._menuBar) + + + def CreateRightClickMenu(self): + + self._rmenu = wx.Menu() + item = wx.MenuItem(self._rmenu, MENU_EDIT_DELETE_PAGE, "Close Tab\tCtrl+F4", "Close Tab") + self._rmenu.AppendItem(item) + + + def LayoutItems(self): + + mainSizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(mainSizer) + + bookStyle = FNB.FNB_NODRAG + + self.book = FNB.FlatNotebook(self, wx.ID_ANY, agwStyle=bookStyle) + + bookStyle &= ~(FNB.FNB_NODRAG) + bookStyle |= FNB.FNB_ALLOW_FOREIGN_DND + self.secondBook = FNB.FlatNotebook(self, wx.ID_ANY, agwStyle=bookStyle) + + # Set right click menu to the notebook + self.book.SetRightClickMenu(self._rmenu) + + # Set the image list + self.book.SetImageList(self._ImageList) + mainSizer.Add(self.book, 6, wx.EXPAND) + + # Add spacer between the books + spacer = wx.Panel(self, -1) + spacer.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)) + mainSizer.Add(spacer, 0, wx.ALL | wx.EXPAND) + + mainSizer.Add(self.secondBook, 2, wx.EXPAND) + + # Add some pages to the second notebook + self.Freeze() + + text = wx.TextCtrl(self.secondBook, -1, "Second Book Page 1\n", style=wx.TE_MULTILINE|wx.TE_READONLY) + self.secondBook.AddPage(text, "Second Book Page 1") + + text = wx.TextCtrl(self.secondBook, -1, "Second Book Page 2\n", style=wx.TE_MULTILINE|wx.TE_READONLY) + self.secondBook.AddPage(text, "Second Book Page 2") + + self.Thaw() + + mainSizer.Layout() + self.SendSizeEvent() + + + def OnStyle(self, event): + + style = self.book.GetAGWWindowStyleFlag() + eventid = event.GetId() + + if eventid == MENU_HIDE_NAV_BUTTONS: + if event.IsChecked(): + # Hide the navigation buttons + style |= FNB.FNB_NO_NAV_BUTTONS + else: + style &= ~FNB.FNB_NO_NAV_BUTTONS + style &= ~FNB.FNB_DROPDOWN_TABS_LIST + + self.book.SetAGWWindowStyleFlag(style) + + elif eventid == MENU_HIDE_ON_SINGLE_TAB: + if event.IsChecked(): + # Hide the navigation buttons + style |= FNB.FNB_HIDE_ON_SINGLE_TAB + else: + style &= ~(FNB.FNB_HIDE_ON_SINGLE_TAB) + + self.book.SetAGWWindowStyleFlag(style) + + elif eventid == MENU_HIDE_TABS: + if event.IsChecked(): + # Hide the tabs + style |= FNB.FNB_HIDE_TABS + else: + style &= ~(FNB.FNB_HIDE_TABS) + + self.book.SetAGWWindowStyleFlag(style) + + elif eventid == MENU_HIDE_X: + if event.IsChecked(): + # Hide the X button + style |= FNB.FNB_NO_X_BUTTON + else: + if style & FNB.FNB_NO_X_BUTTON: + style ^= FNB.FNB_NO_X_BUTTON + + self.book.SetAGWWindowStyleFlag(style) + + elif eventid == MENU_DRAW_BORDER: + if event.IsChecked(): + style |= FNB.FNB_TABS_BORDER_SIMPLE + else: + if style & FNB.FNB_TABS_BORDER_SIMPLE: + style ^= FNB.FNB_TABS_BORDER_SIMPLE + + self.book.SetAGWWindowStyleFlag(style) + + elif eventid == MENU_USE_MOUSE_MIDDLE_BTN: + if event.IsChecked(): + style |= FNB.FNB_MOUSE_MIDDLE_CLOSES_TABS + else: + if style & FNB.FNB_MOUSE_MIDDLE_CLOSES_TABS: + style ^= FNB.FNB_MOUSE_MIDDLE_CLOSES_TABS + + self.book.SetAGWWindowStyleFlag(style) + + elif eventid == MENU_USE_BOTTOM_TABS: + if event.IsChecked(): + style |= FNB.FNB_BOTTOM + else: + if style & FNB.FNB_BOTTOM: + style ^= FNB.FNB_BOTTOM + + self.book.SetAGWWindowStyleFlag(style) + self.book.Refresh() + + elif eventid == MENU_NO_TABS_FOCUS: + if event.IsChecked(): + # Hide the navigation buttons + style |= FNB.FNB_NO_TAB_FOCUS + else: + style &= ~(FNB.FNB_NO_TAB_FOCUS) + + self.book.SetAGWWindowStyleFlag(style) + + + def OnQuit(self, event): + + self.Destroy() + + + def OnDeleteAll(self, event): + + self.book.DeleteAllPages() + + + def OnShowImages(self, event): + + self._bShowImages = event.IsChecked() + + + def OnForeignDrop(self, event): + + self.log.write('Foreign drop received\n') + self.log.write('new NB: %s || old NB: %s\n' % (event.GetNotebook(), event.GetOldNotebook())) + self.log.write('new tab: %s || old tab: %s\n' % (event.GetSelection(), event.GetOldSelection())) + + + def OnDrop(self, event): + + self.log.write('Drop received - same notebook\n') + self.log.write('new: %s old: %s\n' % (event.GetSelection(), event.GetOldSelection())) + + + def OnFF2Style(self, event): + + style = self.book.GetAGWWindowStyleFlag() + + # remove old tabs style + mirror = ~(FNB.FNB_VC71 | FNB.FNB_VC8 | FNB.FNB_FANCY_TABS | FNB.FNB_FF2 | FNB.FNB_RIBBON_TABS) + style &= mirror + + style |= FNB.FNB_FF2 + + self.book.SetAGWWindowStyleFlag(style) + + + def OnVC71Style(self, event): + + style = self.book.GetAGWWindowStyleFlag() + + # remove old tabs style + mirror = ~(FNB.FNB_VC71 | FNB.FNB_VC8 | FNB.FNB_FANCY_TABS | FNB.FNB_FF2 | FNB.FNB_RIBBON_TABS) + style &= mirror + + style |= FNB.FNB_VC71 + + self.book.SetAGWWindowStyleFlag(style) + + + def OnVC8Style(self, event): + + style = self.book.GetAGWWindowStyleFlag() + + # remove old tabs style + mirror = ~(FNB.FNB_VC71 | FNB.FNB_VC8 | FNB.FNB_FANCY_TABS | FNB.FNB_FF2 | FNB.FNB_RIBBON_TABS) + style &= mirror + + # set new style + style |= FNB.FNB_VC8 + + self.book.SetAGWWindowStyleFlag(style) + + def OnRibbonStyle(self, event): + + style = self.book.GetAGWWindowStyleFlag() + + # remove old tabs style + mirror = ~(FNB.FNB_VC71 | FNB.FNB_VC8 | FNB.FNB_FANCY_TABS | FNB.FNB_FF2 | FNB.FNB_RIBBON_TABS) + style &= mirror + + # set new style + style |= FNB.FNB_RIBBON_TABS + + self.book.SetAGWWindowStyleFlag(style) + + + def OnDefaultStyle(self, event): + + style = self.book.GetAGWWindowStyleFlag() + + # remove old tabs style + mirror = ~(FNB.FNB_VC71 | FNB.FNB_VC8 | FNB.FNB_FANCY_TABS | FNB.FNB_FF2 | FNB.FNB_RIBBON_TABS) + style &= mirror + + self.book.SetAGWWindowStyleFlag(style) + + + def OnFancyStyle(self, event): + + style = self.book.GetAGWWindowStyleFlag() + + # remove old tabs style + mirror = ~(FNB.FNB_VC71 | FNB.FNB_VC8 | FNB.FNB_FANCY_TABS | FNB.FNB_FF2 | FNB.FNB_RIBBON_TABS) + style &= mirror + + style |= FNB.FNB_FANCY_TABS + self.book.SetAGWWindowStyleFlag(style) + + + def OnSelectColour(self, event): + + eventid = event.GetId() + + # Open a colour dialog + data = wx.ColourData() + + dlg = wx.ColourDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + + if eventid == MENU_SELECT_GRADIENT_COLOUR_BORDER: + self.book.SetGradientColourBorder(dlg.GetColourData().GetColour()) + elif eventid == MENU_SELECT_GRADIENT_COLOUR_FROM: + self.book.SetGradientColourFrom(dlg.GetColourData().GetColour()) + elif eventid == MENU_SELECT_GRADIENT_COLOUR_TO: + self.book.SetGradientColourTo(dlg.GetColourData().GetColour()) + elif eventid == MENU_SET_ACTIVE_TEXT_COLOUR: + self.book.SetActiveTabTextColour(dlg.GetColourData().GetColour()) + elif eventid == MENU_SELECT_NONACTIVE_TEXT_COLOUR: + self.book.SetNonActiveTabTextColour(dlg.GetColourData().GetColour()) + elif eventid == MENU_SET_ACTIVE_TAB_COLOUR: + self.book.SetActiveTabColour(dlg.GetColourData().GetColour()) + elif eventid == MENU_SET_TAB_AREA_COLOUR: + self.book.SetTabAreaColour(dlg.GetColourData().GetColour()) + + self.book.Refresh() + + + def OnAddPage(self, event): + + caption = "New Page Added #" + str(self._newPageCounter) + + self.Freeze() + + image = -1 + if self._bShowImages: + image = random.randint(0, self._ImageList.GetImageCount()-1) + + self.book.AddPage(self.CreatePage(caption), caption, True, image) + self.Thaw() + self._newPageCounter = self._newPageCounter + 1 + + + def CreatePage(self, caption): + + p = wx.Panel(self.book, style=wx.SUNKEN_BORDER|wx.TAB_TRAVERSAL) + wx.StaticText(p, -1, caption, (20,20)) + wx.TextCtrl(p, -1, "", (20,40), (150,-1)) + return p + + + def OnDeletePage(self, event): + + self.book.DeletePage(self.book.GetSelection()) + + + def OnSetSelection(self, event): + + dlg = wx.TextEntryDialog(self, "Enter Tab Number to select:", "Set Selection") + + if dlg.ShowModal() == wx.ID_OK: + + val = dlg.GetValue() + self.book.SetSelection(int(val)) + + + def OnEnableTab(self, event): + + dlg = wx.TextEntryDialog(self, "Enter Tab Number to enable:", "Enable Tab") + + if dlg.ShowModal() == wx.ID_OK: + + val = dlg.GetValue() + self.book.EnableTab(int(val)) + + + def OnDisableTab(self, event): + + dlg = wx.TextEntryDialog(self, "Enter Tab Number to disable:", "Disable Tab") + + if dlg.ShowModal() == wx.ID_OK: + + val = dlg.GetValue() + self.book.EnableTab(int(val), False) + + + def OnEnableDrag(self, event): + + style = self.book.GetAGWWindowStyleFlag() + style2 = self.secondBook.GetAGWWindowStyleFlag() + + if event.IsChecked(): + if style & FNB.FNB_NODRAG: + style ^= FNB.FNB_NODRAG + if style2 & FNB.FNB_NODRAG: + style2 ^= FNB.FNB_NODRAG + else: + style |= FNB.FNB_NODRAG + style2 |= FNB.FNB_NODRAG + + self.book.SetAGWWindowStyleFlag(style) + self.secondBook.SetAGWWindowStyleFlag(style2) + + + def OnAllowForeignDnd(self, event): + + style = self.book.GetAGWWindowStyleFlag() + if event.IsChecked(): + style |= FNB.FNB_ALLOW_FOREIGN_DND + else: + style &= ~(FNB.FNB_ALLOW_FOREIGN_DND) + + self.book.SetAGWWindowStyleFlag(style) + self.book.Refresh() + + + def OnSetAllPagesShapeAngle(self, event): + + + dlg = wx.TextEntryDialog(self, "Enter an inclination of header borders (0-15):", "Set Angle") + if dlg.ShowModal() == wx.ID_OK: + + val = dlg.GetValue() + self.book.SetAllPagesShapeAngle(int(val)) + + + def OnSetPageImage(self, event): + + dlg = wx.TextEntryDialog(self, "Enter an image index (0-%i):"%(self.book.GetImageList().GetImageCount()-1), "Set Image Index") + if dlg.ShowModal() == wx.ID_OK: + val = dlg.GetValue() + self.book.SetPageImage(self.book.GetSelection(), int(val)) + + + def OnAdvanceSelectionFwd(self, event): + + self.book.AdvanceSelection(True) + + + def OnAdvanceSelectionBack(self, event): + + self.book.AdvanceSelection(False) + + + def OnPageChanging(self, event): + + self.log.write("Page Changing From %d To %d" % (event.GetOldSelection(), event.GetSelection())) + event.Skip() + + + def OnPageChanged(self, event): + + self.log.write("Page Changed To %d" % event.GetSelection()) + event.Skip() + + + def OnPageClosing(self, event): + + self.log.write("Page Closing, Selection: %d" % event.GetSelection()) + event.Skip() + + + def OnDrawTabX(self, event): + + style = self.book.GetAGWWindowStyleFlag() + if event.IsChecked(): + style |= FNB.FNB_X_ON_TAB + else: + if style & FNB.FNB_X_ON_TAB: + style ^= FNB.FNB_X_ON_TAB + + self.book.SetAGWWindowStyleFlag(style) + + + def OnDClickCloseTab(self, event): + + style = self.book.GetAGWWindowStyleFlag() + if event.IsChecked(): + style |= FNB.FNB_DCLICK_CLOSES_TABS + else: + style &= ~(FNB.FNB_DCLICK_CLOSES_TABS) + + self.book.SetAGWWindowStyleFlag(style) + + + def OnGradientBack(self, event): + + style = self.book.GetAGWWindowStyleFlag() + if event.IsChecked(): + style |= FNB.FNB_BACKGROUND_GRADIENT + else: + style &= ~(FNB.FNB_BACKGROUND_GRADIENT) + + self.book.SetAGWWindowStyleFlag(style) + self.book.Refresh() + + + def OnColourfulTabs(self, event): + + style = self.book.GetAGWWindowStyleFlag() + if event.IsChecked(): + style |= FNB.FNB_COLOURFUL_TABS + else: + style &= ~(FNB.FNB_COLOURFUL_TABS) + + self.book.SetAGWWindowStyleFlag(style) + self.book.Refresh() + + + def OnSmartTabs(self, event): + + style = self.book.GetAGWWindowStyleFlag() + if event.IsChecked(): + style |= FNB.FNB_SMART_TABS + else: + style &= ~FNB.FNB_SMART_TABS + + self.book.SetAGWWindowStyleFlag(style) + self.book.Refresh() + + + def OnDropDownArrow(self, event): + + style = self.book.GetAGWWindowStyleFlag() + + if event.IsChecked(): + + style |= FNB.FNB_DROPDOWN_TABS_LIST + style |= FNB.FNB_NO_NAV_BUTTONS + + else: + + style &= ~FNB.FNB_DROPDOWN_TABS_LIST + style &= ~FNB.FNB_NO_NAV_BUTTONS + + self.book.SetAGWWindowStyleFlag(style) + self.book.Refresh() + + + def OnTile(self, event): + + evId = event.GetId() + if evId == MENU_TILE_HORIZONTALLY: + self.book.Tile(wx.HORIZONTAL) + elif evId == MENU_TILE_VERTICALLY: + self.book.Tile(wx.VERTICAL) + else: + self.book.Tile(None) + + + def OnCustomPanel(self, event): + + if event.IsChecked(): + custom = LogoPanel(self.book, -1) + self.book.SetCustomPage(custom) + else: + self.book.SetCustomPage(None) + + + def OnHideNavigationButtonsUI(self, event): + + style = self.book.GetAGWWindowStyleFlag() + event.Check((style & FNB.FNB_NO_NAV_BUTTONS and [True] or [False])[0]) + + + def OnDropDownArrowUI(self, event): + + style = self.book.GetAGWWindowStyleFlag() + event.Check((style & FNB.FNB_DROPDOWN_TABS_LIST and [True] or [False])[0]) + + + def OnAllowForeignDndUI(self, event): + + style = self.book.GetAGWWindowStyleFlag() + event.Enable((style & FNB.FNB_NODRAG and [False] or [True])[0]) + + + def OnAbout(self, event): + + msg = "This Is The About Dialog Of The FlatNotebook Demo.\n\n" + \ + "Author: Andrea Gavana @ 02 Oct 2006\n\n" + \ + "Please Report Any Bug/Requests Of Improvements\n" + \ + "To Me At The Following Adresses:\n\n" + \ + "andrea.gavana@gmail.com\n" + "andrea.gavana@maerskoil.com\n\n" + \ + "Based On Eran C++ Implementation (wxWidgets Forum).\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "FlatNotebook wxPython Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +class LogoPanel(wx.Panel): + + def __init__(self, parent, id=-1, pos=wx.DefaultPosition, size=wx.DefaultSize, + style=wx.CLIP_CHILDREN): + + wx.Panel.__init__(self, parent, id, pos, size, style) + + self.SetBackgroundColour(wx.WHITE) + self.bmp = images.Vippi.GetBitmap() + + self.bigfont = wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD, False) + self.normalfont = wx.Font(14, wx.SWISS, wx.NORMAL, wx.BOLD, True) + + self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM) + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnSize) + + + def OnSize(self, event): + + event.Skip() + self.Refresh() + + + def OnPaint(self, event): + + dc = wx.AutoBufferedPaintDC(self) + self.DoDrawing(dc) + + + def DoDrawing(self, dc): + + dc.SetBackground(wx.WHITE_BRUSH) + dc.Clear() + + w, h = self.GetClientSize() + bmpW, bmpH = self.bmp.GetWidth(), self.bmp.GetHeight() + + xpos, ypos = int((w - bmpW)/2), int((h - bmpH)/2) + + dc.DrawBitmap(self.bmp, xpos, ypos, True) + + dc.SetFont(self.bigfont) + dc.SetTextForeground(wx.BLUE) + dc.SetBrush(wx.TRANSPARENT_BRUSH) + dc.SetPen(wx.Pen(wx.BLUE, 2)) + + tw, th = dc.GetTextExtent("FlatNotebook") + xpos = int((w - tw)/2) + ypos = int(h/3) + + dc.DrawRoundedRectangle(xpos-5, ypos-3, tw+10, th+6, 3) + dc.DrawText("FlatNotebook", xpos, ypos) + + dc.SetFont(self.normalfont) + dc.SetTextForeground(wx.RED) + tw, th = dc.GetTextExtent("Andrea Gavana") + xpos = int((w - tw)/2) + ypos = int(2*h/3) + dc.DrawText("Andrea Gavana", xpos, ypos) + tw, th = dc.GetTextExtent("02 Oct 2006") + + xpos = int((w - tw)/2) + ypos = int(2*h/3 + 3*th/2) + + dc.DrawText("02 Oct 2006", xpos, ypos) + + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test FlatNotebook ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = FlatNotebookDemo(self, self.log) + self.win.Show(True) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = FNB.__doc__ + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/FloatSpin.py b/demo/agw/FloatSpin.py new file mode 100644 index 00000000..eac6ff0e --- /dev/null +++ b/demo/agw/FloatSpin.py @@ -0,0 +1,473 @@ +import wx + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import floatspin as FS +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.floatspin as FS + + +#---------------------------------------------------------------------- + + +class FloatSpinDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + self.log = log + + self.mainpanel = wx.Panel(self, -1) + self.sizer_5_staticbox = wx.StaticBox(self.mainpanel, -1, "Example 2") + self.sizer_7_staticbox = wx.StaticBox(self.mainpanel, -1, "Example 3") + self.sizer_8_staticbox = wx.StaticBox(self.mainpanel, -1, "Example 4") + self.sizer_4_staticbox = wx.StaticBox(self.mainpanel, -1, "Example 1") + self.helptext = wx.StaticText(self.mainpanel, -1, "Welcome to the FloatSpin Demo") + + self.floatspin1 = FS.FloatSpin(self.mainpanel, -1, min_val=0, max_val=1, + increment=0.01, value=0.1, agwStyle=FS.FS_LEFT) + self.floatspin1.SetFormat("%f") + self.floatspin1.SetDigits(2) + + self.setvalue1 = wx.Button(self.mainpanel, -1, "Set Value") + self.textctrlvalue1 = wx.TextCtrl(self.mainpanel, -1, "0.0") + self.setdigits1 = wx.Button(self.mainpanel, -1, "Set Digits") + self.textctrldigits1 = wx.TextCtrl(self.mainpanel, -1, "2") + self.radioformat1 = wx.RadioBox(self.mainpanel, -1, "Set Format", + choices=["%f", "%F", "%e", "%E", "%g", "%G"], + majorDimension=2, style=wx.RA_SPECIFY_COLS) + self.setincrement1 = wx.Button(self.mainpanel, -1, "Set Increment") + self.textctrlincr1 = wx.TextCtrl(self.mainpanel, -1, "0.01") + self.setfont1 = wx.Button(self.mainpanel, -1, "Set Font") + + self.floatspin2 = FS.FloatSpin(self.mainpanel, -1, min_val=-10, max_val=100, + increment=0.1, agwStyle=FS.FS_RIGHT) + self.floatspin2.SetFormat("%e") + self.floatspin2.SetDigits(4) + + self.setvalue2 = wx.Button(self.mainpanel, -1, "Set Value") + self.textctrlvalue2 = wx.TextCtrl(self.mainpanel, -1, "0.0") + self.setdigits2 = wx.Button(self.mainpanel, -1, "Set Digits") + self.textctrldigits2 = wx.TextCtrl(self.mainpanel, -1, "4") + self.radioformat2 = wx.RadioBox(self.mainpanel, -1, "Set Format", + choices=["%f", "%F", "%e", "%E", "%g", "%G"], + majorDimension=2, style=wx.RA_SPECIFY_COLS) + self.setincrement2 = wx.Button(self.mainpanel, -1, "Set Increment") + self.textctrlincr2 = wx.TextCtrl(self.mainpanel, -1, "0.1") + self.setfont2 = wx.Button(self.mainpanel, -1, "Set Font") + + self.floatspin3 = FS.FloatSpin(self.mainpanel, -1, min_val=0.01, max_val=0.05, + increment=0.0001, agwStyle=FS.FS_CENTRE) + self.floatspin3.SetFormat("%f") + self.floatspin3.SetDigits(5) + + self.setvalue3 = wx.Button(self.mainpanel, -1, "Set Value") + self.textctrlvalue3 = wx.TextCtrl(self.mainpanel, -1, "0.01") + self.setdigits3 = wx.Button(self.mainpanel, -1, "Set Digits") + self.textctrldigits3 = wx.TextCtrl(self.mainpanel, -1, "5") + self.radioformat3 = wx.RadioBox(self.mainpanel, -1, "Set Format", + choices=["%f", "%F", "%e", "%E", "%g", "%G"], + majorDimension=2, style=wx.RA_SPECIFY_COLS) + self.setincrement3 = wx.Button(self.mainpanel, -1, "Set Increment") + self.textctrlincr3 = wx.TextCtrl(self.mainpanel, -1, "0.0001") + self.setfont3 = wx.Button(self.mainpanel, -1, "Set Font") + + self.floatspin4 = FS.FloatSpin(self.mainpanel, -1, min_val=-2, max_val=20000, + increment=0.1, agwStyle=FS.FS_READONLY) + self.floatspin4.SetFormat("%G") + self.floatspin4.SetDigits(3) + + self.setvalue4 = wx.Button(self.mainpanel, -1, "Set Value") + self.textctrlvalue4 = wx.TextCtrl(self.mainpanel, -1, "0.0") + self.setdigits4 = wx.Button(self.mainpanel, -1, "Set Digits") + self.textctrldigits4 = wx.TextCtrl(self.mainpanel, -1, "3") + self.radioformat4 = wx.RadioBox(self.mainpanel, -1, "Set Format", + choices=["%f", "%F", "%e", "%E", "%g", "%G"], + majorDimension=2, style=wx.RA_SPECIFY_COLS) + self.setincrement4 = wx.Button(self.mainpanel, -1, "Set Increment") + self.textctrlincr4 = wx.TextCtrl(self.mainpanel, -1, "0.1") + self.setfont4 = wx.Button(self.mainpanel, -1, "Set Font") + + self.valuebuttons = [self.setvalue1, self.setvalue2, self.setvalue3, + self.setvalue4] + self.digitbuttons = [self.setdigits1, self.setdigits2, self.setdigits3, + self.setdigits4] + self.radioboxes = [self.radioformat1, self.radioformat2, self.radioformat3, + self.radioformat4] + self.incrbuttons = [self.setincrement1, self.setincrement2, self.setincrement3, + self.setincrement4] + self.fontbuttons = [self.setfont1, self.setfont2, self.setfont3, self.setfont4] + self.textvalues = [self.textctrlvalue1, self.textctrlvalue2, self.textctrlvalue3, + self.textctrlvalue4] + self.textdigits = [self.textctrldigits1, self.textctrldigits2, self.textctrldigits3, + self.textctrldigits4] + self.textincr = [self.textctrlincr1, self.textctrlincr2, self.textctrlincr3, + self.textctrlincr4] + self.floatspins = [self.floatspin1, self.floatspin2, self.floatspin3, + self.floatspin4] + + self.SetProperties() + self.DoLayout() + self.BindEvents() + + + def SetProperties(self): + + self.helptext.SetFont(wx.Font(10, wx.MODERN, wx.NORMAL, wx.BOLD, 0, "Verdana")) + self.radioformat1.SetSelection(0) + self.radioformat2.SetSelection(2) + self.radioformat3.SetSelection(0) + self.radioformat4.SetSelection(5) + + + def DoLayout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + panelsizer = wx.BoxSizer(wx.VERTICAL) + sizer_6 = wx.BoxSizer(wx.HORIZONTAL) + sizer_8 = wx.StaticBoxSizer(self.sizer_8_staticbox, wx.HORIZONTAL) + right4 = wx.BoxSizer(wx.VERTICAL) + subright43 = wx.BoxSizer(wx.HORIZONTAL) + subright42 = wx.BoxSizer(wx.HORIZONTAL) + subright41 = wx.BoxSizer(wx.HORIZONTAL) + bottomright2 = wx.BoxSizer(wx.VERTICAL) + sizer_7 = wx.StaticBoxSizer(self.sizer_7_staticbox, wx.HORIZONTAL) + right3 = wx.BoxSizer(wx.VERTICAL) + subright33 = wx.BoxSizer(wx.HORIZONTAL) + subright32 = wx.BoxSizer(wx.HORIZONTAL) + subright31 = wx.BoxSizer(wx.HORIZONTAL) + bottomleft2 = wx.BoxSizer(wx.VERTICAL) + sizer_3 = wx.BoxSizer(wx.HORIZONTAL) + sizer_5 = wx.StaticBoxSizer(self.sizer_5_staticbox, wx.HORIZONTAL) + right2 = wx.BoxSizer(wx.VERTICAL) + subright23 = wx.BoxSizer(wx.HORIZONTAL) + subright22 = wx.BoxSizer(wx.HORIZONTAL) + subright21 = wx.BoxSizer(wx.HORIZONTAL) + topright2 = wx.BoxSizer(wx.VERTICAL) + sizer_4 = wx.StaticBoxSizer(self.sizer_4_staticbox, wx.HORIZONTAL) + right1 = wx.BoxSizer(wx.VERTICAL) + subright13 = wx.BoxSizer(wx.HORIZONTAL) + subright12 = wx.BoxSizer(wx.HORIZONTAL) + subright11 = wx.BoxSizer(wx.HORIZONTAL) + topleft2 = wx.BoxSizer(wx.VERTICAL) + panelsizer.Add(self.helptext, 0, wx.ALL|wx.ADJUST_MINSIZE, 10) + topleft2.Add((0, 1), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + label_1 = wx.StaticText(self.mainpanel, -1, "FS_LEFT") + topleft2.Add(label_1, 0, wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + topleft2.Add(self.floatspin1, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + topleft2.Add((0, 1), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_4.Add(topleft2, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 5) + subright11.Add(self.setvalue1, 0, wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL| + wx.ADJUST_MINSIZE | wx.BOTTOM, 3) + subright11.Add(self.textctrlvalue1, 1, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right1.Add((0,1), 1, wx.EXPAND) + right1.Add(subright11, 0, wx.EXPAND, 0) + subright12.Add(self.setdigits1, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + subright12.Add(self.textctrldigits1, 1, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right1.Add(subright12, 0, wx.EXPAND, 0) + right1.Add(self.radioformat1, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 3) + right1.Add((0, 5), 0, wx.ADJUST_MINSIZE, 0) + subright13.Add(self.setincrement1, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + subright13.Add(self.textctrlincr1, 1, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right1.Add(subright13, 0, wx.EXPAND, 0) + right1.Add((0, 5), 0, wx.ADJUST_MINSIZE, 0) + right1.Add(self.setfont1, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + right1.Add((0,1), 1, wx.EXPAND) + sizer_4.Add(right1, 1, wx.EXPAND, 0) + sizer_3.Add(sizer_4, 1, wx.ALL|wx.EXPAND, 5) + topright2.Add((0, 1), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + label_2 = wx.StaticText(self.mainpanel, -1, "FS_RIGHT") + topright2.Add(label_2, 0, wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + topright2.Add(self.floatspin2, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + topright2.Add((0, 1), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_5.Add(topright2, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 5) + subright21.Add(self.setvalue2, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE | wx.BOTTOM, 3) + subright21.Add(self.textctrlvalue2, 1, wx.LEFT|wx.RIGHT|wx.BOTTOM| + wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right2.Add((0,1), 1, wx.EXPAND) + right2.Add(subright21, 0, wx.EXPAND, 0) + subright22.Add(self.setdigits2, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + subright22.Add(self.textctrldigits2, 1, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right2.Add(subright22, 0, wx.EXPAND, 0) + right2.Add(self.radioformat2, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 3) + right2.Add((0, 5), 0, wx.ADJUST_MINSIZE, 0) + subright23.Add(self.setincrement2, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + subright23.Add(self.textctrlincr2, 1, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right2.Add(subright23, 0, wx.EXPAND, 0) + right2.Add((0, 5), 0, wx.ADJUST_MINSIZE, 0) + right2.Add(self.setfont2, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + right2.Add((0,1), 1, wx.EXPAND) + sizer_5.Add(right2, 1, wx.EXPAND, 0) + sizer_3.Add(sizer_5, 1, wx.ALL|wx.EXPAND, 5) + panelsizer.Add(sizer_3, 1, wx.EXPAND, 0) + bottomleft2.Add((0, 1), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + label_3 = wx.StaticText(self.mainpanel, -1, "FS_CENTER") + bottomleft2.Add(label_3, 0, wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + bottomleft2.Add(self.floatspin3, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + bottomleft2.Add((0, 1), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_7.Add(bottomleft2, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 5) + subright31.Add(self.setvalue3, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE | wx.BOTTOM, 3) + subright31.Add(self.textctrlvalue3, 1, wx.LEFT|wx.RIGHT|wx.BOTTOM| + wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right3.Add(subright31, 0, wx.EXPAND, 0) + subright32.Add(self.setdigits3, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + subright32.Add(self.textctrldigits3, 1, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right3.Add((0,1), 1, wx.EXPAND) + right3.Add(subright32, 0, wx.EXPAND, 0) + right3.Add(self.radioformat3, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 3) + right3.Add((0, 5), 0, wx.ADJUST_MINSIZE, 0) + subright33.Add(self.setincrement3, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + subright33.Add(self.textctrlincr3, 1, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right3.Add(subright33, 0, wx.EXPAND, 0) + right3.Add((0, 5), 0, wx.ADJUST_MINSIZE, 0) + right3.Add(self.setfont3, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + right3.Add((0,1), 1, wx.EXPAND) + sizer_7.Add(right3, 1, wx.EXPAND, 0) + sizer_6.Add(sizer_7, 1, wx.ALL|wx.EXPAND, 5) + bottomright2.Add((0, 1), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + label_4 = wx.StaticText(self.mainpanel, -1, "FS_READONLY") + bottomright2.Add(label_4, 0, wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + bottomright2.Add(self.floatspin4, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + bottomright2.Add((0, 1), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0) + sizer_8.Add(bottomright2, 0, wx.LEFT|wx.RIGHT|wx.EXPAND, 5) + subright41.Add(self.setvalue4, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE | wx.BOTTOM, 3) + subright41.Add(self.textctrlvalue4, 1, wx.LEFT|wx.RIGHT|wx.BOTTOM| + wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL| + wx.ADJUST_MINSIZE, 3) + right4.Add((0,1), 1, wx.EXPAND) + right4.Add(subright41, 0, wx.EXPAND, 0) + subright42.Add(self.setdigits4, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + subright42.Add(self.textctrldigits4, 1, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right4.Add(subright42, 0, wx.EXPAND, 0) + right4.Add(self.radioformat4, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 3) + right4.Add((0, 5), 0, wx.ADJUST_MINSIZE, 0) + subright43.Add(self.setincrement4, 0, wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + subright43.Add(self.textctrlincr4, 1, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_HORIZONTAL| + wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + right4.Add(subright43, 0, wx.EXPAND, 0) + right4.Add((0, 5), 0, wx.ADJUST_MINSIZE, 0) + right4.Add(self.setfont4, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + right4.Add((0,1), 1, wx.EXPAND) + sizer_8.Add(right4, 1, wx.EXPAND, 0) + sizer_6.Add(sizer_8, 1, wx.ALL|wx.EXPAND, 5) + panelsizer.Add(sizer_6, 1, wx.EXPAND, 0) + self.mainpanel.SetAutoLayout(True) + self.mainpanel.SetSizer(panelsizer) + panelsizer.Fit(self.mainpanel) + panelsizer.SetSizeHints(self.mainpanel) + mainsizer.Add(self.mainpanel, 1, wx.EXPAND, 0) + self.SetSizer(mainsizer) + mainsizer.Layout() + + + def BindEvents(self): + + self.Bind(wx.EVT_BUTTON, self.OnSetValue, self.setvalue1) + self.Bind(wx.EVT_BUTTON, self.OnSetDigits, self.setdigits1) + self.Bind(wx.EVT_RADIOBOX, self.OnChangeFormat, self.radioformat1) + self.Bind(wx.EVT_BUTTON, self.OnSetIncrement, self.setincrement1) + self.Bind(wx.EVT_BUTTON, self.OnSetFont, self.setfont1) + self.Bind(wx.EVT_BUTTON, self.OnSetValue, self.setvalue2) + self.Bind(wx.EVT_BUTTON, self.OnSetDigits, self.setdigits2) + self.Bind(wx.EVT_RADIOBOX, self.OnChangeFormat, self.radioformat2) + self.Bind(wx.EVT_BUTTON, self.OnSetIncrement, self.setincrement2) + self.Bind(wx.EVT_BUTTON, self.OnSetFont, self.setfont2) + self.Bind(wx.EVT_BUTTON, self.OnSetValue, self.setvalue3) + self.Bind(wx.EVT_BUTTON, self.OnSetDigits, self.setdigits3) + self.Bind(wx.EVT_RADIOBOX, self.OnChangeFormat, self.radioformat3) + self.Bind(wx.EVT_BUTTON, self.OnSetIncrement, self.setincrement3) + self.Bind(wx.EVT_BUTTON, self.OnSetFont, self.setfont3) + self.Bind(wx.EVT_BUTTON, self.OnSetValue, self.setvalue4) + self.Bind(wx.EVT_BUTTON, self.OnSetDigits, self.setdigits4) + self.Bind(wx.EVT_RADIOBOX, self.OnChangeFormat, self.radioformat4) + self.Bind(wx.EVT_BUTTON, self.OnSetIncrement, self.setincrement4) + self.Bind(wx.EVT_BUTTON, self.OnSetFont, self.setfont4) + + self.floatspin1.Bind(FS.EVT_FLOATSPIN, self.OnFloatSpin) + self.floatspin2.Bind(FS.EVT_FLOATSPIN, self.OnFloatSpin) + self.floatspin3.Bind(FS.EVT_FLOATSPIN, self.OnFloatSpin) + self.floatspin4.Bind(FS.EVT_FLOATSPIN, self.OnFloatSpin) + + + def OnSetValue(self, event): + + btn = event.GetEventObject() + indx = self.valuebuttons.index(btn) + textctrl = self.textvalues[indx] + floatspin = self.floatspins[indx] + + try: + value = float(textctrl.GetValue().strip()) + except: + errstr = "Error: Non Floating Value For The Text Control! " + dlg = wx.MessageDialog(self, errstr, "FloatSpinDemo Error", + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + + floatspin.SetValue(value) + + event.Skip() + + + def OnSetDigits(self, event): + + btn = event.GetEventObject() + indx = self.digitbuttons.index(btn) + textctrl = self.textdigits[indx] + floatspin = self.floatspins[indx] + + try: + value = int(textctrl.GetValue().strip()) + except: + errstr = "Error: Non Integer Value For The Text Control! " + dlg = wx.MessageDialog(self, errstr, "FloatSpinDemo Error", + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + + floatspin.SetDigits(value) + + event.Skip() + + + def OnChangeFormat(self, event): + + radio = event.GetEventObject() + indx = self.radioboxes.index(radio) + floatspin = self.floatspins[indx] + + fmt = radio.GetStringSelection() + floatspin.SetFormat(fmt) + + event.Skip() + + + def OnSetIncrement(self, event): + + btn = event.GetEventObject() + indx = self.incrbuttons.index(btn) + textctrl = self.textincr[indx] + floatspin = self.floatspins[indx] + + try: + value = float(textctrl.GetValue().strip()) + except: + errstr = "Error: Non Floating Value For The Text Control! " + dlg = wx.MessageDialog(self, errstr, "FloatSpinDemo Error", + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + + try: + floatspin.SetIncrement(value) + except: + textctrl.DiscardEdits() + strs = sys.exc_info() + dlg = wx.MessageDialog(self, strs[0], "FloatSpinDemo Error", + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + + event.Skip() + + + def OnSetFont(self, event): + + btn = event.GetEventObject() + indx = self.fontbuttons.index(btn) + floatspin = self.floatspins[indx] + + data = wx.FontData() + data.EnableEffects(True) + data.SetInitialFont(floatspin.GetFont()) + + dlg = wx.FontDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetFontData() + font = data.GetChosenFont() + colour = data.GetColour() + floatspin.SetFont(font) + floatspin.GetTextCtrl().SetForegroundColour(colour) + floatspin.Refresh() + + # Don't destroy the dialog until you get everything you need from the + # dialog! + dlg.Destroy() + + + def OnFloatSpin(self, event): + + floatspin = event.GetEventObject() + self.log.write("FloatSpin event: Value = %s\n"%floatspin.GetValue()) + + indx = self.floatspins.index(floatspin) + + fmt = floatspin.GetFormat() + dgt = floatspin.GetDigits() + currenttext = self.textvalues[indx] + + strs = ("%100." + str(dgt) + fmt[1])%floatspin.GetValue() + + currenttext.SetValue(strs.strip()) + currenttext.Refresh() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = FloatSpinDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = FS.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/FoldPanelBar.py b/demo/agw/FoldPanelBar.py new file mode 100644 index 00000000..28377965 --- /dev/null +++ b/demo/agw/FoldPanelBar.py @@ -0,0 +1,951 @@ +import wx + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import foldpanelbar as fpb +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.foldpanelbar as fpb + + +# ---------------------------------------------------------------------------- +# Extended Demo Implementation +# +# This demo shows how to use custom CaptionBar styles and custom icons for +# the caption bars. here i used the standard Windows XP icons for the +# collapsed and expanded state. +# ---------------------------------------------------------------------------- + +#---------------------------------------------------------------------- +# different icons for the collapsed/expanded states. +# Taken from standard Windows XP collapsed/expanded states. +#---------------------------------------------------------------------- + +def GetCollapsedIconData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ +\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ +\x00\x01\x8eIDAT8\x8d\xa5\x93-n\xe4@\x10\x85?g\x03\n6lh)\xc4\xd2\x12\xc3\x81\ +\xd6\xa2I\x90\x154\xb9\x81\x8f1G\xc8\x11\x16\x86\xcd\xa0\x99F\xb3A\x91\xa1\ +\xc9J&\x96L"5lX\xcc\x0bl\xf7v\xb2\x7fZ\xa5\x98\xebU\xbdz\xf5\\\x9deW\x9f\xf8\ +H\\\xbfO|{y\x9dT\x15P\x04\x01\x01UPUD\x84\xdb/7YZ\x9f\xa5\n\xce\x97aRU\x8a\ +\xdc`\xacA\x00\x04P\xf0!0\xf6\x81\xa0\xf0p\xff9\xfb\x85\xe0|\x19&T)K\x8b\x18\ +\xf9\xa3\xe4\xbe\xf3\x8c^#\xc9\xd5\n\xa8*\xc5?\x9a\x01\x8a\xd2b\r\x1cN\xc3\ +\x14\t\xce\x97a\xb2F0Ks\xd58\xaa\xc6\xc5\xa6\xf7\xdfya\xe7\xbdR\x13M2\xf9\ +\xf9qKQ\x1fi\xf6-\x00~T\xfac\x1dq#\x82,\xe5q\x05\x91D\xba@\xefj\xba1\xf0\xdc\ +zzW\xcff&\xb8,\x89\xa8@Q\xd6\xaaf\xdfRm,\xee\xb1BDxr#\xae\xf5|\xddo\xd6\xe2H\ +\x18\x15\x84\xa0q@]\xe54\x8d\xa3\xedf\x05M\xe3\xd8Uy\xc4\x15\x8d\xf5\xd7\x8b\ +~\x82\x0fh\x0e"\xb0\xad,\xee\xb8c\xbb\x18\xe7\x8e;6\xa5\x89\x04\xde\xff\x1c\ +\x16\xef\xe0p\xfa>\x19\x11\xca\x8d\x8d\xe0\x93\x1b\x01\xd8m\xf3(;x\xa5\xef=\ +\xb7w\xf3\x1d$\x7f\xc1\xe0\xbd\xa7\xeb\xa0(,"Kc\x12\xc1+\xfd\xe8\tI\xee\xed)\ +\xbf\xbcN\xc1{D\x04k\x05#\x12\xfd\xf2a\xde[\x81\x87\xbb\xdf\x9cr\x1a\x87\xd3\ +0)\xba>\x83\xd5\xb97o\xe0\xaf\x04\xff\x13?\x00\xd2\xfb\xa9`z\xac\x80w\x00\ +\x00\x00\x00IEND\xaeB`\x82' + +def GetCollapsedIconBitmap(): + return wx.BitmapFromImage(GetCollapsedIconImage()) + +def GetCollapsedIconImage(): + import cStringIO + stream = cStringIO.StringIO(GetCollapsedIconData()) + return wx.ImageFromStream(stream) + +#---------------------------------------------------------------------- +def GetExpandedIconData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ +\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ +\x00\x01\x9fIDAT8\x8d\x95\x93\xa1\x8e\xdc0\x14EO\xb2\xc4\xd0\xd2\x12\xb7(mI\ +\xa4%V\xd1lQT4[4-\x9a\xfe\xc1\xc2|\xc6\xc2~BY\x83:A3E\xd3\xa0*\xa4\xd2\x90H!\ +\x95\x0c\r\r\x1fK\x81g\xb2\x99\x84\xb4\x0fY\xd6\xbb\xc7\xf7>=\'Iz\xc3\xbcv\ +\xfbn\xb8\x9c\x15 \xe7\xf3\xc7\x0fw\xc9\xbc7\x99\x03\x0e\xfbn0\x99F+\x85R\ +\x80RH\x10\x82\x08\xde\x05\x1ef\x90+\xc0\xe1\xd8\ryn\xd0Z-\\A\xb4\xd2\xf7\ +\x9e\xfbwoF\xc8\x088\x1c\xbbae\xb3\xe8y&\x9a\xdf\xf5\xbd\xe7\xfem\x84\xa4\ +\x97\xccYf\x16\x8d\xdb\xb2a]\xfeX\x18\xc9s\xc3\xe1\x18\xe7\x94\x12cb\xcc\xb5\ +\xfa\xb1l8\xf5\x01\xe7\x84\xc7\xb2Y@\xb2\xcc0\x02\xb4\x9a\x88%\xbe\xdc\xb4\ +\x9e\xb6Zs\xaa74\xadg[6\x88<\xb7]\xc6\x14\x1dL\x86\xe6\x83\xa0\x81\xba\xda\ +\x10\x02x/\xd4\xd5\x06\r\x840!\x9c\x1fM\x92\xf4\x86\x9f\xbf\xfe\x0c\xd6\x9ae\ +\xd6u\x8d \xf4\xf5\x165\x9b\x8f\x04\xe1\xc5\xcb\xdb$\x05\x90\xa97@\x04lQas\ +\xcd*7\x14\xdb\x9aY\xcb\xb8\\\xe9E\x10|\xbc\xf2^\xb0E\x85\xc95_\x9f\n\xaa/\ +\x05\x10\x81\xce\xc9\xa8\xf6>\x13\xc0n\xff{PJ\xc5\xfdP\x11""<\xbc\ +\xff\x87\xdf\xf8\xbf\xf5\x17FF\xaf\x8f\x8b\xd3\xe6K\x00\x00\x00\x00IEND\xaeB\ +`\x82' + +def GetExpandedIconBitmap(): + return wx.BitmapFromImage(GetExpandedIconImage()) + +def GetExpandedIconImage(): + import cStringIO + stream = cStringIO.StringIO(GetExpandedIconData()) + return wx.ImageFromStream(stream) + +#---------------------------------------------------------------------- +def GetMondrianData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ +\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\ +ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\ +o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\ +\xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\ +\x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\ +\x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82' + +def GetMondrianBitmap(): + return wx.BitmapFromImage(GetMondrianImage()) + +def GetMondrianImage(): + import cStringIO + stream = cStringIO.StringIO(GetMondrianData()) + return wx.ImageFromStream(stream) + +def GetMondrianIcon(): + icon = wx.EmptyIcon() + icon.CopyFromBitmap(GetMondrianBitmap()) + return icon + +# ---------------------------------------------------------------------------- +# Beginning Of Extended Demo +# ---------------------------------------------------------------------------- + +class Extended(wx.Frame): + + def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, + size=(700,650), style=wx.DEFAULT_FRAME_STYLE): + + wx.Frame.__init__(self, parent, id, title, pos, size, style) + + self._flags = 0 + + self.SetIcon(GetMondrianIcon()) + self.SetMenuBar(self.CreateMenuBar()) + + self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + self.statusbar.SetStatusWidths([-4, -3]) + self.statusbar.SetStatusText("Andrea Gavana @ 23 Mar 2005", 0) + self.statusbar.SetStatusText("Welcome to wxPython!", 1) + + self._leftWindow1 = wx.SashLayoutWindow(self, 101, wx.DefaultPosition, + wx.Size(200, 1000), wx.NO_BORDER | + wx.SW_3D | wx.CLIP_CHILDREN) + + self._leftWindow1.SetDefaultSize(wx.Size(220, 1000)) + self._leftWindow1.SetOrientation(wx.LAYOUT_VERTICAL) + self._leftWindow1.SetAlignment(wx.LAYOUT_LEFT) + self._leftWindow1.SetSashVisible(wx.SASH_RIGHT, True) + self._leftWindow1.SetExtraBorderSize(10) + + self._pnl = 0 + + # will occupy the space not used by the Layout Algorithm + self.remainingSpace = wx.Panel(self, -1, style=wx.SUNKEN_BORDER) + wx.StaticText(self.remainingSpace, -1, + "Use your imagination for what kinds of things to put in this window...", + (15,30)) + + self.ID_WINDOW_TOP = 100 + self.ID_WINDOW_LEFT1 = 101 + self.ID_WINDOW_RIGHT1 = 102 + self.ID_WINDOW_BOTTOM = 103 + + self._leftWindow1.Bind(wx.EVT_SASH_DRAGGED_RANGE, self.OnFoldPanelBarDrag, + id=100, id2=103) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_SCROLL, self.OnSlideColour) + + self.ReCreateFoldPanel(0) + + + def OnSize(self, event): + + wx.LayoutAlgorithm().LayoutWindow(self, self.remainingSpace) + event.Skip() + + + def OnQuit(self, event): + + self.Destroy() + + + def OnAbout(self, event): + + msg = "This is the about dialog of the FoldPanelBar demo.\n\n" + \ + "Author: Andrea Gavana @ 23 Mar 2005\n\n" + \ + "Please report any bug/requests or improvements\n" + \ + "To me at the following adresses:\n\n" + \ + "andrea.gavana@agip.it\n" + "andrea_gavana@tin.it\n\n" + \ + "Based On Jorgen Bodde C++ demo implementation.\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "FoldPanelBar Extended Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.SetFont(wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, False, "Verdana")) + dlg.ShowModal() + dlg.Destroy() + + + def OnToggleWindow(self, event): + + self._leftWindow1.Show(not self._leftWindow1.IsShown()) + # Leaves bits of itself behind sometimes + wx.LayoutAlgorithm().LayoutWindow(self, self.remainingSpace) + self.remainingSpace.Refresh() + + event.Skip() + + + def OnFoldPanelBarDrag(self, event): + + if event.GetDragStatus() == wx.SASH_STATUS_OUT_OF_RANGE: + return + + if event.GetId() == self.ID_WINDOW_LEFT1: + self._leftWindow1.SetDefaultSize(wx.Size(event.GetDragRect().width, 1000)) + + + # Leaves bits of itself behind sometimes + wx.LayoutAlgorithm().LayoutWindow(self, self.remainingSpace) + self.remainingSpace.Refresh() + + event.Skip() + + + def ReCreateFoldPanel(self, fpb_flags): + + # delete earlier panel + self._leftWindow1.DestroyChildren() + + # recreate the foldpanelbar + + self._pnl = fpb.FoldPanelBar(self._leftWindow1, -1, wx.DefaultPosition, + wx.Size(-1,-1), agwStyle=fpb_flags) + + Images = wx.ImageList(16,16) + Images.Add(GetExpandedIconBitmap()) + Images.Add(GetCollapsedIconBitmap()) + + item = self._pnl.AddFoldPanel("Caption Colours", collapsed=False, + foldIcons=Images) + + self._pnl.AddFoldPanelWindow(item, wx.StaticText(item, -1, "Adjust The First Colour"), + fpb.FPB_ALIGN_WIDTH, 5, 20) + + # RED colour spin control + self._rslider1 = wx.Slider(item, -1, 0, 0, 255) + self._pnl.AddFoldPanelWindow(item, self._rslider1, fpb.FPB_ALIGN_WIDTH, 2, 20) + + # GREEN colour spin control + self._gslider1 = wx.Slider(item, -1, 0, 0, 255) + self._pnl.AddFoldPanelWindow(item, self._gslider1, fpb.FPB_ALIGN_WIDTH, 0, 20) + + # BLUE colour spin control + self._bslider1 = wx.Slider(item, -1, 0, 0, 255) + self._pnl.AddFoldPanelWindow(item, self._bslider1, fpb.FPB_ALIGN_WIDTH, 0, 20) + + self._pnl.AddFoldPanelSeparator(item) + + self._pnl.AddFoldPanelWindow(item, wx.StaticText(item, -1, "Adjust The Second Colour"), + fpb.FPB_ALIGN_WIDTH, 5, 20) + + # RED colour spin control + self._rslider2 = wx.Slider(item, -1, 0, 0, 255) + self._pnl.AddFoldPanelWindow(item, self._rslider2, fpb.FPB_ALIGN_WIDTH, 2, 20) + + # GREEN colour spin control + self._gslider2 = wx.Slider(item, -1, 0, 0, 255) + self._pnl.AddFoldPanelWindow(item, self._gslider2, fpb.FPB_ALIGN_WIDTH, 0, 20) + + # BLUE colour spin control + self._bslider2 = wx.Slider(item, -1, 0, 0, 255) + self._pnl.AddFoldPanelWindow(item, self._bslider2, fpb.FPB_ALIGN_WIDTH, 0, 20) + + self._pnl.AddFoldPanelSeparator(item) + + button1 = wx.Button(item, wx.ID_ANY, "Apply To All") + button1.Bind(wx.EVT_BUTTON, self.OnExpandMe) + self._pnl.AddFoldPanelWindow(item, button1) + + # read back current gradients and set the sliders + # for the colour which is now taken as default + + style = self._pnl.GetCaptionStyle(item) + col = style.GetFirstColour() + + self._rslider1.SetValue(col.Red()) + self._gslider1.SetValue(col.Green()) + self._bslider1.SetValue(col.Blue()) + + col = style.GetSecondColour() + self._rslider2.SetValue(col.Red()) + self._gslider2.SetValue(col.Green()) + self._bslider2.SetValue(col.Blue()) + + # put down some caption styles from which the user can + # select to show how the current or all caption bars will look like + + item = self._pnl.AddFoldPanel("Caption Style", False, foldIcons=Images) + + self.ID_USE_VGRADIENT = wx.NewId() + self.ID_USE_HGRADIENT = wx.NewId() + self.ID_USE_SINGLE = wx.NewId() + self.ID_USE_RECTANGLE = wx.NewId() + self.ID_USE_FILLED_RECTANGLE = wx.NewId() + + currStyle = wx.RadioButton(item, self.ID_USE_VGRADIENT, "&Vertical Gradient") + self._pnl.AddFoldPanelWindow(item, currStyle, fpb.FPB_ALIGN_WIDTH, + fpb.FPB_DEFAULT_SPACING, 10) + + currStyle.SetValue(True) + + radio1 = wx.RadioButton(item, self.ID_USE_HGRADIENT, "&Horizontal Gradient") + radio2 = wx.RadioButton(item, self.ID_USE_SINGLE, "&Single Colour") + radio3 = wx.RadioButton(item, self.ID_USE_RECTANGLE, "&Rectangle Box") + radio4 = wx.RadioButton(item, self.ID_USE_FILLED_RECTANGLE, "&Filled Rectangle Box") + + currStyle.Bind(wx.EVT_RADIOBUTTON, self.OnStyleChange) + radio1.Bind(wx.EVT_RADIOBUTTON, self.OnStyleChange) + radio2.Bind(wx.EVT_RADIOBUTTON, self.OnStyleChange) + radio3.Bind(wx.EVT_RADIOBUTTON, self.OnStyleChange) + radio4.Bind(wx.EVT_RADIOBUTTON, self.OnStyleChange) + + self._pnl.AddFoldPanelWindow(item, radio1, fpb.FPB_ALIGN_WIDTH, fpb.FPB_DEFAULT_SPACING, 10) + self._pnl.AddFoldPanelWindow(item, radio2, fpb.FPB_ALIGN_WIDTH, fpb.FPB_DEFAULT_SPACING, 10) + self._pnl.AddFoldPanelWindow(item, radio3, fpb.FPB_ALIGN_WIDTH, fpb.FPB_DEFAULT_SPACING, 10) + self._pnl.AddFoldPanelWindow(item, radio4, fpb.FPB_ALIGN_WIDTH, fpb.FPB_DEFAULT_SPACING, 10) + + self._pnl.AddFoldPanelSeparator(item) + + self._single = wx.CheckBox(item, -1, "&Only This Caption") + self._pnl.AddFoldPanelWindow(item, self._single, fpb.FPB_ALIGN_WIDTH, + fpb.FPB_DEFAULT_SPACING, 10) + + # one more panel to finish it + + cs = fpb.CaptionBarStyle() + cs.SetCaptionStyle(fpb.CAPTIONBAR_RECTANGLE) + + item = self._pnl.AddFoldPanel("Misc Stuff", collapsed=True, foldIcons=Images, + cbstyle=cs) + + button2 = wx.Button(item, wx.NewId(), "Collapse All") + self._pnl.AddFoldPanelWindow(item, button2) + self._pnl.AddFoldPanelWindow(item, wx.StaticText(item, -1, "Enter Some Comments"), + fpb.FPB_ALIGN_WIDTH, 5, 20) + self._pnl.AddFoldPanelWindow(item, wx.TextCtrl(item, -1, "Comments"), + fpb.FPB_ALIGN_WIDTH, fpb.FPB_DEFAULT_SPACING, 10) + + button2.Bind(wx.EVT_BUTTON, self.OnCollapseMe) + self.radiocontrols = [currStyle, radio1, radio2, radio3, radio4] + + self._leftWindow1.SizeWindows() + + + def OnCreateBottomStyle(self, event): + + # recreate with style collapse to bottom, which means + # all panels that are collapsed are placed at the bottom, + # or normal + + if event.IsChecked(): + self.GetMenuBar().Check(self._singlestyle, False) + self.GetMenuBar().Check(self._exclusivestyle, False) + self._flags = self._flags & ~fpb.FPB_SINGLE_FOLD + self._flags = self._flags & ~fpb.FPB_EXCLUSIVE_FOLD + self._flags = self._flags | fpb.FPB_COLLAPSE_TO_BOTTOM + else: + self._flags = self._flags & ~fpb.FPB_COLLAPSE_TO_BOTTOM + + self.ReCreateFoldPanel(self._flags) + + + def OnCreateNormalStyle(self, event): + + # recreate with style where only one panel at the time is + # allowed to be opened + + if event.IsChecked(): + self.GetMenuBar().Check(self._bottomstyle, False) + self.GetMenuBar().Check(self._exclusivestyle, False) + self._flags = self._flags & ~fpb.FPB_EXCLUSIVE_FOLD + self._flags = self._flags & ~fpb.FPB_COLLAPSE_TO_BOTTOM + self._flags = self._flags | fpb.FPB_SINGLE_FOLD + else: + self._flags = self._flags & ~fpb.FPB_SINGLE_FOLD + + self.ReCreateFoldPanel(self._flags) + + + def OnCreateExclusiveStyle(self, event): + + # recreate with style where only one panel at the time is + # allowed to be opened and the others are collapsed to bottom + + if event.IsChecked(): + self.GetMenuBar().Check(self._singlestyle, False) + self.GetMenuBar().Check(self._bottomstyle, False) + self._flags = self._flags & ~fpb.FPB_SINGLE_FOLD + self._flags = self._flags & ~fpb.FPB_COLLAPSE_TO_BOTTOM + self._flags = self._flags | fpb.FPB_EXCLUSIVE_FOLD + else: + self._flags = self._flags & ~fpb.FPB_EXCLUSIVE_FOLD + + self.ReCreateFoldPanel(self._flags) + + + def OnCollapseMe(self, event): + + for i in range(0, self._pnl.GetCount()): + item = self._pnl.GetFoldPanel(i) + self._pnl.Collapse(item) + + + def OnExpandMe(self, event): + + col1 = wx.Colour(self._rslider1.GetValue(), self._gslider1.GetValue(), + self._bslider1.GetValue()) + col2 = wx.Colour(self._rslider2.GetValue(), self._gslider2.GetValue(), + self._bslider2.GetValue()) + + style = fpb.CaptionBarStyle() + + style.SetFirstColour(col1) + style.SetSecondColour(col2) + + counter = 0 + for items in self.radiocontrols: + if items.GetValue(): + break + counter = counter + 1 + + if counter == 0: + mystyle = fpb.CAPTIONBAR_GRADIENT_V + elif counter == 1: + mystyle = fpb.CAPTIONBAR_GRADIENT_H + elif counter == 2: + mystyle = fpb.CAPTIONBAR_SINGLE + elif counter == 3: + mystyle = fpb.CAPTIONBAR_RECTANGLE + else: + mystyle = fpb.CAPTIONBAR_FILLED_RECTANGLE + + style.SetCaptionStyle(mystyle) + self._pnl.ApplyCaptionStyleAll(style) + + + def OnSlideColour(self, event): + + col1 = wx.Colour(self._rslider1.GetValue(), self._gslider1.GetValue(), + self._bslider1.GetValue()) + col2 = wx.Colour(self._rslider2.GetValue(), self._gslider2.GetValue(), + self._bslider2.GetValue()) + + style = fpb.CaptionBarStyle() + + counter = 0 + for items in self.radiocontrols: + if items.GetValue(): + break + + counter = counter + 1 + + if counter == 0: + mystyle = fpb.CAPTIONBAR_GRADIENT_V + elif counter == 1: + mystyle = fpb.CAPTIONBAR_GRADIENT_H + elif counter == 2: + mystyle = fpb.CAPTIONBAR_SINGLE + elif counter == 3: + mystyle = fpb.CAPTIONBAR_RECTANGLE + else: + mystyle = fpb.CAPTIONBAR_FILLED_RECTANGLE + + style.SetFirstColour(col1) + style.SetSecondColour(col2) + style.SetCaptionStyle(mystyle) + + item = self._pnl.GetFoldPanel(0) + self._pnl.ApplyCaptionStyle(item, style) + + + def OnStyleChange(self, event): + + style = fpb.CaptionBarStyle() + + eventid = event.GetId() + + if eventid == self.ID_USE_HGRADIENT: + style.SetCaptionStyle(fpb.CAPTIONBAR_GRADIENT_H) + + elif eventid == self.ID_USE_VGRADIENT: + style.SetCaptionStyle(fpb.CAPTIONBAR_GRADIENT_V) + + elif eventid == self.ID_USE_SINGLE: + style.SetCaptionStyle(fpb.CAPTIONBAR_SINGLE) + + elif eventid == self.ID_USE_RECTANGLE: + style.SetCaptionStyle(fpb.CAPTIONBAR_RECTANGLE) + + elif eventid == self.ID_USE_FILLED_RECTANGLE: + style.SetCaptionStyle(fpb.CAPTIONBAR_FILLED_RECTANGLE) + + else: + raise "ERROR: Undefined Style Selected For CaptionBar: " + repr(eventid) + + col1 = wx.Colour(self._rslider1.GetValue(), self._gslider1.GetValue(), + self._bslider1.GetValue()) + col2 = wx.Colour(self._rslider2.GetValue(), self._gslider2.GetValue(), + self._bslider2.GetValue()) + + style.SetFirstColour(col1) + style.SetSecondColour(col2) + + if self._single.GetValue(): + item = self._pnl.GetFoldPanel(1) + self._pnl.ApplyCaptionStyle(item, style) + else: + self._pnl.ApplyCaptionStyleAll(style) + + + def CreateMenuBar(self, with_window=False): + + # Make a menubar + file_menu = wx.Menu() + + FPBTEST_QUIT = wx.NewId() + FPBTEST_REFRESH = wx.NewId() + FPB_BOTTOM_FOLD = wx.NewId() + FPB_SINGLE_FOLD = wx.NewId() + FPB_EXCLUSIVE_FOLD = wx.NewId() + FPBTEST_TOGGLE_WINDOW = wx.NewId() + FPBTEST_ABOUT = wx.NewId() + + file_menu.Append(FPBTEST_QUIT, "&Exit") + + option_menu = None + + if with_window: + # Dummy option + option_menu = wx.Menu() + option_menu.Append(FPBTEST_REFRESH, "&Refresh picture") + + # make fold panel menu + + fpb_menu = wx.Menu() + fpb_menu.AppendCheckItem(FPB_BOTTOM_FOLD, "Create with &fpb.FPB_COLLAPSE_TO_BOTTOM") + + # Now Implemented! + fpb_menu.AppendCheckItem(FPB_SINGLE_FOLD, "Create with &fpb.FPB_SINGLE_FOLD") + + # Now Implemented! + fpb_menu.AppendCheckItem(FPB_EXCLUSIVE_FOLD, "Create with &fpb.FPB_EXCLUSIVE_FOLD") + + fpb_menu.AppendSeparator() + fpb_menu.Append(FPBTEST_TOGGLE_WINDOW, "&Toggle FoldPanelBar") + + help_menu = wx.Menu() + help_menu.Append(FPBTEST_ABOUT, "&About") + + menu_bar = wx.MenuBar() + + menu_bar.Append(file_menu, "&File") + menu_bar.Append(fpb_menu, "&FoldPanel") + + if option_menu: + menu_bar.Append(option_menu, "&Options") + + menu_bar.Append(help_menu, "&Help") + + self.Bind(wx.EVT_MENU, self.OnAbout, id=FPBTEST_ABOUT) + self.Bind(wx.EVT_MENU, self.OnQuit, id=FPBTEST_QUIT) + self.Bind(wx.EVT_MENU, self.OnToggleWindow, id=FPBTEST_TOGGLE_WINDOW) + self.Bind(wx.EVT_MENU, self.OnCreateBottomStyle, id=FPB_BOTTOM_FOLD) + self.Bind(wx.EVT_MENU, self.OnCreateNormalStyle, id=FPB_SINGLE_FOLD) + self.Bind(wx.EVT_MENU, self.OnCreateExclusiveStyle, id=FPB_EXCLUSIVE_FOLD) + + self._bottomstyle = FPB_BOTTOM_FOLD + self._singlestyle = FPB_SINGLE_FOLD + self._exclusivestyle = FPB_EXCLUSIVE_FOLD + + return menu_bar + + +# ---------------------------------------------------------------------------- +# Collapsed Demo Implementation +# ---------------------------------------------------------------------------- + +class FoldTestPanel(wx.Panel): + + def __init__(self, parent, id, pos=wx.DefaultPosition, size=wx.DefaultSize, + style=wx.NO_BORDER | wx.TAB_TRAVERSAL): + + wx.Panel.__init__(self, parent, id, pos, size, style) + + self.CreateControls() + self.GetSizer().Fit(self) + self.GetSizer().SetSizeHints(self) + self.GetSizer().Layout() + + self.Bind(fpb.EVT_CAPTIONBAR, self.OnPressCaption) + + + def OnPressCaption(self, event): + event.Skip() + + def CreateControls(self): + + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(sizer) + + subpanel = wx.Panel(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, + wx.NO_BORDER | wx.TAB_TRAVERSAL) + sizer.Add(subpanel, 1, wx.GROW | wx.ADJUST_MINSIZE, 5) + + subsizer = wx.BoxSizer(wx.VERTICAL) + subpanel.SetSizer(subsizer) + itemstrings = ["One", "Two", "Three"] + + item5 = wx.Choice(subpanel, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, + itemstrings, 0) + + subsizer.Add(item5, 0, wx.GROW | wx.ALL, 5) + + item6 = wx.TextCtrl(subpanel, wx.ID_ANY, "", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE) + subsizer.Add(item6, 1, wx.GROW | wx.ALL, 5) + + item7 = wx.RadioButton(subpanel, wx.ID_ANY, "I Like This", wx.DefaultPosition, + wx.DefaultSize, 0) + item7.SetValue(True) + subsizer.Add(item7, 0, wx.ALIGN_LEFT | wx.ALL, 5) + + item8 = wx.RadioButton(subpanel, wx.ID_ANY, "I Hate It", wx.DefaultPosition, + wx.DefaultSize, 0) + item8.SetValue(False) + subsizer.Add(item8, 0, wx.ALIGN_LEFT | wx.ALL, 5) + + +# ---------------------------------------------------------------------------- + +class Collapsed(wx.Frame): + + def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, + size=(400,300), style=wx.DEFAULT_FRAME_STYLE): + + wx.Frame.__init__(self, parent, id, title, pos, size, style) + + self.SetIcon(GetMondrianIcon()) + self.SetMenuBar(self.CreateMenuBar()) + + self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + self.statusbar.SetStatusWidths([-4, -3]) + self.statusbar.SetStatusText("Andrea Gavana @ 23 Mar 2005", 0) + self.statusbar.SetStatusText("Welcome to wxPython!", 1) + + self.CreateFoldBar() + + + def CreateFoldBar(self, vertical=True): + + if vertical: + self.SetSize((500,600)) + else: + self.SetSize((700,300)) + + newstyle = (vertical and [fpb.FPB_VERTICAL] or [fpb.FPB_HORIZONTAL])[0] + + bar = fpb.FoldPanelBar(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, + agwStyle=fpb.FPB_COLLAPSE_TO_BOTTOM|newstyle) + + item = bar.AddFoldPanel("Test me", collapsed=False) + button1 = wx.Button(item, wx.ID_ANY, "Collapse Me") + button1.Bind(wx.EVT_BUTTON, self.OnCollapseMe) + + bar.AddFoldPanelWindow(item, button1, fpb.FPB_ALIGN_LEFT) + + item = bar.AddFoldPanel("Test me too!", collapsed=True) + + button2 = wx.Button(item, wx.ID_ANY, "Expand First One") + button2.Bind(wx.EVT_BUTTON, self.OnExpandMe) + + bar.AddFoldPanelWindow(item, button2) + bar.AddFoldPanelSeparator(item) + + newfoldpanel = FoldTestPanel(item, wx.ID_ANY) + bar.AddFoldPanelWindow(item, newfoldpanel) + + bar.AddFoldPanelSeparator(item) + + bar.AddFoldPanelWindow(item, wx.TextCtrl(item, wx.ID_ANY, "Comment"), + fpb.FPB_ALIGN_LEFT, fpb.FPB_DEFAULT_SPACING, 20) + + item = bar.AddFoldPanel("Some Opinions ...", collapsed=False) + bar.AddFoldPanelWindow(item, wx.CheckBox(item, wx.ID_ANY, "I Like This")) + + if vertical: + # do not add this for horizontal for better presentation + bar.AddFoldPanelWindow(item, wx.CheckBox(item, wx.ID_ANY, "And also this")) + bar.AddFoldPanelWindow(item, wx.CheckBox(item, wx.ID_ANY, "And gimme this too")) + + bar.AddFoldPanelSeparator(item) + + bar.AddFoldPanelWindow(item, wx.CheckBox(item, wx.ID_ANY, "Check this too if you like")) + + if vertical: + # do not add this for horizontal for better presentation + bar.AddFoldPanelWindow(item, wx.CheckBox(item, wx.ID_ANY, "What about this")) + + item = bar.AddFoldPanel("Choose one ...", collapsed=False) + bar.AddFoldPanelWindow(item, wx.StaticText(item, wx.ID_ANY, "Enter your comment")) + bar.AddFoldPanelWindow(item, wx.TextCtrl(item, wx.ID_ANY, "Comment"), + fpb.FPB_ALIGN_WIDTH, fpb.FPB_DEFAULT_SPACING, 20) + + if hasattr(self, "pnl"): + self.pnl.Destroy() + + self.pnl = bar + + size = self.GetClientSize() + self.pnl.SetDimensions(0, 0, size.GetWidth(), size.GetHeight()) + + + def CreateMenuBar(self): + + FoldPanelBarTest_Quit = wx.NewId() + FoldPanelBarTest_About = wx.NewId() + FoldPanelBarTest_Horizontal = wx.NewId() + FoldPanelBarTest_Vertical = wx.NewId() + + menuFile = wx.Menu() + menuFile.Append(FoldPanelBarTest_Horizontal, "&Horizontal\tAlt-H") + menuFile.Append(FoldPanelBarTest_Vertical, "&Vertical\tAlt-V") + menuFile.AppendSeparator() + menuFile.Append(FoldPanelBarTest_Quit, "E&xit\tAlt-X", "Quit This Program") + + helpMenu = wx.Menu() + helpMenu.Append(FoldPanelBarTest_About, "&About...\tF1", "Show About Dialog") + + self.FoldPanelBarTest_Vertical = FoldPanelBarTest_Vertical + self.FoldPanelBarTest_Horizontal = FoldPanelBarTest_Horizontal + + self.Bind(wx.EVT_MENU, self.OnQuit, id=FoldPanelBarTest_Quit) + self.Bind(wx.EVT_MENU, self.OnAbout, id=FoldPanelBarTest_About) + self.Bind(wx.EVT_MENU, self.OnOrientation, id=FoldPanelBarTest_Horizontal) + self.Bind(wx.EVT_MENU, self.OnOrientation, id=FoldPanelBarTest_Vertical) + + value = wx.MenuBar() + value.Append(menuFile, "&File") + value.Append(helpMenu, "&Help") + + return value + + + def OnOrientation(self, event): + self.CreateFoldBar(event.GetId() == self.FoldPanelBarTest_Vertical) + + + def OnQuit(self, event): + # True is to force the frame to close + self.Close(True) + + + def OnAbout(self, event): + + msg = "This is the about dialog of the FoldPanelBarTest application.\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + dlg = wx.MessageDialog(self, msg, "About FoldPanelBarTest", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + + def OnCollapseMe(self, event): + + item = self.pnl.GetFoldPanel(0) + self.pnl.Collapse(item) + + def OnExpandMe(self, event): + + self.pnl.Expand(self.pnl.GetFoldPanel(0)) + self.pnl.Collapse(self.pnl.GetFoldPanel(1)) + + + +# ---------------------------------------------------------------------------- +# NotCollapsed Implementation +# ---------------------------------------------------------------------------- + +class NotCollapsed(wx.Frame): + def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, + size=(400,300), style=wx.DEFAULT_FRAME_STYLE): + + wx.Frame.__init__(self, parent, id, title, pos, size, style) + + self.SetIcon(GetMondrianIcon()) + self.SetMenuBar(self.CreateMenuBar()) + + self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + self.statusbar.SetStatusWidths([-4, -3]) + self.statusbar.SetStatusText("Andrea Gavana @ 23 Mar 2005", 0) + self.statusbar.SetStatusText("Welcome to wxPython!", 1) + + pnl = fpb.FoldPanelBar(self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, + agwStyle=fpb.FPB_VERTICAL) + + item = pnl.AddFoldPanel("Test Me", collapsed=False) + + button1 = wx.Button(item, wx.ID_ANY, "Collapse Me") + + pnl.AddFoldPanelWindow(item, button1, fpb.FPB_ALIGN_LEFT) + pnl.AddFoldPanelSeparator(item) + + button1.Bind(wx.EVT_BUTTON, self.OnCollapseMe) + + item = pnl.AddFoldPanel("Test Me Too!", collapsed=True) + button2 = wx.Button(item, wx.ID_ANY, "Expand First One") + pnl.AddFoldPanelWindow(item, button2, fpb.FPB_ALIGN_LEFT) + pnl.AddFoldPanelSeparator(item) + + button2.Bind(wx.EVT_BUTTON, self.OnExpandMe) + + newfoldpanel = FoldTestPanel(item, wx.ID_ANY) + pnl.AddFoldPanelWindow(item, newfoldpanel) + + pnl.AddFoldPanelSeparator(item) + + pnl.AddFoldPanelWindow(item, wx.TextCtrl(item, wx.ID_ANY, "Comment"), + fpb.FPB_ALIGN_LEFT, fpb.FPB_DEFAULT_SPACING, 20) + + item = pnl.AddFoldPanel("Some Opinions ...", collapsed=False) + pnl.AddFoldPanelWindow(item, wx.CheckBox(item, wx.ID_ANY, "I Like This")) + pnl.AddFoldPanelWindow(item, wx.CheckBox(item, wx.ID_ANY, "And Also This")) + pnl.AddFoldPanelWindow(item, wx.CheckBox(item, wx.ID_ANY, "And Gimme This Too")) + + pnl.AddFoldPanelSeparator(item) + + pnl.AddFoldPanelWindow(item, wx.CheckBox(item, wx.ID_ANY, "Check This Too If You Like")) + pnl.AddFoldPanelWindow(item, wx.CheckBox(item, wx.ID_ANY, "What About This")) + + item = pnl.AddFoldPanel("Choose One ...", collapsed=False) + pnl.AddFoldPanelWindow(item, wx.StaticText(item, wx.ID_ANY, "Enter Your Comment")) + pnl.AddFoldPanelWindow(item, wx.TextCtrl(item, wx.ID_ANY, "Comment"), + fpb.FPB_ALIGN_WIDTH, fpb.FPB_DEFAULT_SPACING, 20, 20) + self.pnl = pnl + + + def CreateMenuBar(self): + + FoldPanelBarTest_Quit = wx.NewId() + FoldPanelBarTest_About = wx.NewId() + + menuFile = wx.Menu() + menuFile.Append(FoldPanelBarTest_Quit, "E&xit\tAlt-X", "Quit This Program") + + helpMenu = wx.Menu() + helpMenu.Append(FoldPanelBarTest_About, "&About...\tF1", "Show About Dialog") + + self.Bind(wx.EVT_MENU, self.OnQuit, id=FoldPanelBarTest_Quit) + self.Bind(wx.EVT_MENU, self.OnAbout, id=FoldPanelBarTest_About) + + value = wx.MenuBar() + value.Append(menuFile, "&File") + value.Append(helpMenu, "&Help") + + return value + + + # Event Handlers + + def OnQuit(self, event): + + # True is to force the frame to close + self.Close(True) + + + def OnAbout(self, event): + + msg = "This is the about dialog of the FoldPanelBarTest application.\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + dlg = wx.MessageDialog(self, msg, "About FoldPanelBarTest", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + + def OnCollapseMe(self, event): + + item = self.pnl.GetFoldPanel(0) + self.pnl.Collapse(item) + + def OnExpandMe(self, event): + + self.pnl.Expand(self.pnl.GetFoldPanel(0)) + self.pnl.Collapse(self.pnl.GetFoldPanel(1)) + + +#--------------------------------------------------------------------------- +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + vsizer = wx.BoxSizer(wx.VERTICAL) + b = wx.Button(self, -1, "FoldPanelBar Extended Demo") + vsizer.Add(b, 0, wx.ALL, 5) + self.Bind(wx.EVT_BUTTON, self.OnButton1, b) + + b = wx.Button(self, -1, "FoldPanelBar Collapsed Demo") + vsizer.Add(b, 0, wx.ALL, 5) + self.Bind(wx.EVT_BUTTON, self.OnButton2, b) + + b = wx.Button(self, -1, "FoldPanelBar NotCollapsed Demo") + vsizer.Add(b, 0, wx.ALL, 5) + self.Bind(wx.EVT_BUTTON, self.OnButton3, b) + + bdr = wx.BoxSizer() + bdr.Add(vsizer, 0, wx.ALL, 50) + self.SetSizer(bdr) + + def OnButton1(self, evt): + frame = Extended(self, title="FoldPanelBar Extended Demo") + frame.Show() + + def OnButton2(self, evt): + frame = Collapsed(self, title="FoldPanelBar Collapsed Demo") + frame.Show() + + def OnButton3(self, evt): + frame = NotCollapsed(self, title="FoldPanelBar NotCollapsed Demo") + frame.Show() + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = fpb.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/FourWaySplitter.py b/demo/agw/FourWaySplitter.py new file mode 100644 index 00000000..b80d1696 --- /dev/null +++ b/demo/agw/FourWaySplitter.py @@ -0,0 +1,298 @@ +import wx + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import fourwaysplitter as FWS +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.fourwaysplitter as FWS + +import images + +#---------------------------------------------------------------------- +class SamplePane(wx.Panel): + """ + Just a simple test window to put into the splitter. + """ + def __init__(self, parent, colour, label): + wx.Panel.__init__(self, parent, style=wx.BORDER_SUNKEN) + self.SetBackgroundColour(colour) + wx.StaticText(self, -1, label, (5,5)) + + def SetOtherLabel(self, label): + wx.StaticText(self, -1, label, (5, 30)) + + + +class ControlPane(wx.Panel): + + def __init__(self, parent): + + wx.Panel.__init__(self, parent) + + luCheck = wx.CheckBox(self, -1, "Live Update") + luCheck.SetValue(True) + self.Bind(wx.EVT_CHECKBOX, self.OnSetLiveUpdate, luCheck) + + btn1 = wx.Button(self, -1, "Swap 2 && 4") + self.Bind(wx.EVT_BUTTON, self.OnSwapButton24, btn1) + + btn2 = wx.Button(self, -1, "Swap 1 && 3") + self.Bind(wx.EVT_BUTTON, self.OnSwapButton13, btn2) + + static = wx.StaticText(self, -1, "Expand A Window") + combo = wx.ComboBox(self, -1, choices=["None", "1", "2", "3", "4"], + style=wx.CB_READONLY|wx.CB_DROPDOWN) + combo.SetStringSelection("None") + + self.Bind(wx.EVT_COMBOBOX, self.OnExpandWindow) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(luCheck, 0, wx.TOP, 5) + sizer.Add(btn1, 0, wx.TOP, 5) + sizer.Add(btn2, 0, wx.TOP, 5) + sizer.Add(static, 0, wx.TOP, 10) + sizer.Add(combo, 0, wx.EXPAND|wx.RIGHT|wx.TOP, 2) + + border = wx.BoxSizer() + border.Add(sizer, 1, wx.EXPAND|wx.ALL, 5) + self.SetSizer(border) + + + def OnSetLiveUpdate(self, evt): + + check = evt.GetEventObject() + self.GetParent().SetLiveUpdate(check.GetValue()) + + + def OnSwapButton24(self, evt): + + self.GetParent().Swap2and4() + + + def OnSwapButton13(self, evt): + + self.GetParent().Swap1and3() + + + def OnExpandWindow(self, event): + + self.GetParent().ExpandWindow(event.GetSelection()) + + +class FWSPanel(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent, -1) + self.log = log + + cp = ControlPane(self) + splitter = FWS.FourWaySplitter(self, agwStyle=wx.SP_LIVE_UPDATE) + self.splitter = splitter + self.log = log + + sizer = wx.BoxSizer(wx.HORIZONTAL) + sizer.Add(cp) + sizer.Add(splitter, 1, wx.EXPAND) + self.SetSizer(sizer) + + p1 = SamplePane(splitter, "pink", "Panel One") + p1.SetOtherLabel( + "There are three ways\n" + "to drag sashes. Try\n" + "dragging the horizontal\n" + "sash, the vertical sash\n" + "or position the mouse at\n" + "the intersection of the\n" + "two sashes." + ) + splitter.AppendWindow(p1) + + p2 = SamplePane(splitter, "sky blue", "Panel Two") + p2.SetOtherLabel("Hello From wxPython!") + p2.SetMinSize(p2.GetBestSize()) + splitter.AppendWindow(p2) + + p3 = SamplePane(splitter, "yellow", "Panel Three") + splitter.AppendWindow(p3) + + p4 = SamplePane(splitter, "Lime Green", "Panel Four") + splitter.AppendWindow(p4) + + self.log.write("Welcome to the FourWaySplitterDemo!\n") + + self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnChanged) + self.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnChanging) + + + def GetSashIdx(self, event): + + if event.GetSashIdx() == wx.HORIZONTAL: + idx = "Horizontal" + elif event.GetSashIdx() == wx.VERTICAL: + idx = "Vertical" + else: + idx = "Horizontal & Vertical" + + return idx + + + def OnChanging(self, event): + + idx = self.GetSashIdx(event) + self.log.write("Changing sash: %s %s\n" %(idx, event.GetSashPosition())) + + # This is one way to control the sash limits + #if event.GetSashPosition().x < 50: + # event.Veto() + + event.Skip() + + + def OnChanged(self, event): + + idx = self.GetSashIdx(event) + self.log.write("Changed sash: %s %s\n" %(idx, event.GetSashPosition())) + + event.Skip() + + + def SetLiveUpdate(self, enable): + + if enable: + self.splitter.SetAGWWindowStyleFlag(wx.SP_LIVE_UPDATE) + else: + self.splitter.SetAGWWindowStyleFlag(0) + + + def Swap2and4(self): + + win2 = self.splitter.GetWindow(1) + win4 = self.splitter.GetWindow(3) + self.splitter.ExchangeWindows(win2, win4) + + + def Swap1and3(self): + + win1 = self.splitter.GetWindow(0) + win3 = self.splitter.GetWindow(2) + self.splitter.ExchangeWindows(win1, win3) + + + def ExpandWindow(self, selection): + + self.splitter.SetExpanded(selection-1) + + +class FourWaySplitterDemo(wx.Frame): + + def __init__(self, parent, log, id=wx.ID_ANY, title="FourWaySplitter Demo", + size=(700, 500)): + + wx.Frame.__init__(self, parent, id, title, size=size) + + self.log = log + panel = FWSPanel(self, log) + + sizer = wx.BoxSizer(wx.VERTICAL) + sizer.Add(panel, 1, wx.EXPAND) + self.SetSizer(sizer) + sizer.Layout() + + statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + statusbar.SetStatusWidths([-2, -1]) + # statusbar fields + statusbar_fields = [("FourWaySplitter wxPython Demo, Andrea Gavana @ 03 Nov 2006"), + ("Welcome To wxPython!")] + + for i in range(len(statusbar_fields)): + statusbar.SetStatusText(statusbar_fields[i], i) + + self.CreateMenu() + + self.SetIcon(images.Mondrian.GetIcon()) + self.CenterOnScreen() + + + def CreateMenu(self): + + menuBar = wx.MenuBar(wx.MB_DOCKABLE) + fileMenu = wx.Menu() + helpMenu = wx.Menu() + + item = wx.MenuItem(fileMenu, wx.ID_ANY, "E&xit") + self.Bind(wx.EVT_MENU, self.OnQuit, item) + fileMenu.AppendItem(item) + + item = wx.MenuItem(helpMenu, wx.ID_ANY, "About") + self.Bind(wx.EVT_MENU, self.OnAbout, item) + helpMenu.AppendItem(item) + + menuBar.Append(fileMenu, "&File") + menuBar.Append(helpMenu, "&Help") + + self.SetMenuBar(menuBar) + + + def OnQuit(self, event): + + self.Destroy() + + + def OnAbout(self, event): + + msg = "This Is The About Dialog Of The FourWaySplitter Demo.\n\n" + \ + "Author: Andrea Gavana @ 03 Nov 2006\n\n" + \ + "Please Report Any Bug/Requests Of Improvements\n" + \ + "To Me At The Following Adresses:\n\n" + \ + "andrea.gavana@gmail.com\n" + "andrea.gavana@maerskoil.com\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "FourWaySplitter wxPython Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test FourWaySplitter ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = FourWaySplitterDemo(self, self.log) + self.win.Show(True) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = FWS.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/GenericMessageDialog.py b/demo/agw/GenericMessageDialog.py new file mode 100644 index 00000000..002ea5ed --- /dev/null +++ b/demo/agw/GenericMessageDialog.py @@ -0,0 +1,205 @@ +import wx + +import os +import sys +import random + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import genericmessagedialog as GMD +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.genericmessagedialog as GMD + +import images + + +_msg = "This is the about dialog of GenericMessageDialog demo.\n\n" + \ + "Author: Andrea Gavana @ 07 Oct 2008\n\n" + \ + "Please report any bugs/requests of improvements\n" + \ + "to me at the following addresses:\n\n" + \ + "andrea.gavana@gmail.com\n" + "andrea.gavana@maerskoil.com\n\n" + \ + "Welcome to wxPython " + wx.VERSION_STRING + "!!" + + +ART_ICONS = [] +for d in dir(wx): + if d.startswith('ART_'): + if not eval('wx.%s'%d).endswith('_C'): + ART_ICONS.append(eval('wx.%s'%d)) + + +class GenericMessageDialogDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + + self.log = log + + self.mainPanel = wx.Panel(self) + self.buttonSizer_staticbox = wx.StaticBox(self.mainPanel, -1, "Buttons Styles") + self.ok = wx.CheckBox(self.mainPanel, -1, "wx.OK") + self.yes_no = wx.CheckBox(self.mainPanel, -1, "wx.YES_NO") + self.cancel = wx.CheckBox(self.mainPanel, -1, "wx.CANCEL") + self.yes = wx.CheckBox(self.mainPanel, -1, "wx.YES") + self.no = wx.CheckBox(self.mainPanel, -1, "wx.NO") + self.no_default = wx.CheckBox(self.mainPanel, -1, "wx.NO_DEFAULT") + self.help = wx.CheckBox(self.mainPanel, -1, "wx.HELP") + self.dialogStyles = wx.RadioBox(self.mainPanel, -1, "Dialog Styles", + choices=["wx.ICON_INFORMATION", "wx.ICON_WARNING", + "wx.ICON_EXCLAMATION", "wx.ICON_ERROR", + "wx.ICON_QUESTION"], + majorDimension=5, style=wx.RA_SPECIFY_ROWS) + self.buttonKinds = wx.RadioBox(self.mainPanel, -1, "Button Kind", + choices=["Themed buttons", "AquaButtons", + "GradientButtons"], + majorDimension=3, style=wx.RA_SPECIFY_ROWS) + + self.useExtended = wx.CheckBox(self.mainPanel, -1, "Add extended message") + self.customIcons = wx.CheckBox(self.mainPanel, -1, "Use custom icons") + + self.showDialog = wx.Button(self.mainPanel, -1, "Show GenericMessageDialog") + + self.SetProperties() + self.DoLayout() + + self.Bind(wx.EVT_BUTTON, self.OnShowDialog, self.showDialog) + self.Bind(wx.EVT_CHECKBOX, self.OnCheckBox) + + + def SetProperties(self): + + self.ok.SetValue(1) + self.dialogStyles.SetSelection(0) + self.showDialog.SetDefault() + + + def DoLayout(self): + + frameSizer = wx.BoxSizer(wx.VERTICAL) + panelSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer = wx.BoxSizer(wx.HORIZONTAL) + buttonSizer = wx.StaticBoxSizer(self.buttonSizer_staticbox, wx.VERTICAL) + + buttonSizer.Add(self.ok, 0, wx.LEFT|wx.RIGHT|wx.TOP, 5) + buttonSizer.Add((0, 2), 0, 0, 0) + buttonSizer.Add(self.yes_no, 0, wx.LEFT|wx.RIGHT, 5) + buttonSizer.Add((0, 2), 0, 0, 0) + buttonSizer.Add(self.cancel, 0, wx.LEFT|wx.RIGHT, 5) + buttonSizer.Add((0, 2), 0, 0, 0) + buttonSizer.Add(self.yes, 0, wx.LEFT|wx.RIGHT, 5) + buttonSizer.Add((0, 2), 0, 0, 0) + buttonSizer.Add(self.no, 0, wx.LEFT|wx.RIGHT, 5) + buttonSizer.Add((0, 2), 0, 0, 0) + buttonSizer.Add(self.no_default, 0, wx.LEFT|wx.RIGHT, 5) + buttonSizer.Add((0, 2), 0, 0, 0) + buttonSizer.Add(self.help, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, 5) + mainSizer.Add(buttonSizer, 0, wx.ALL, 5) + mainSizer.Add(self.buttonKinds, 0, wx.ALL, 5) + mainSizer.Add(self.dialogStyles, 0, wx.ALL, 5) + mainSizer.Add((10, 0), 0, 0, 0) + mainSizer.Add(self.showDialog, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 10) + mainSizer.Add((10, 0), 0, 0, 0) + + panelSizer.Add(mainSizer, 1, wx.EXPAND) + panelSizer.Add(self.useExtended, 0, wx.ALL, 15) + panelSizer.Add(self.customIcons, 0, wx.LEFT|wx.RIGHT, 15) + panelSizer.Add((0, 0), 1, wx.ALL, 10) + + self.mainPanel.SetSizer(panelSizer) + + frameSizer.Add(self.mainPanel, 1, wx.EXPAND) + self.SetSizer(frameSizer) + frameSizer.Layout() + + + def OnCheckBox(self, event): + + obj = event.GetEventObject() + + if obj in [self.useExtended, self.customIcons]: + event.Skip() + return + + widgets = [self.yes, self.yes_no, self.no, self.no_default] + if not event.IsChecked(): + return + + if obj == self.ok: + for checks in widgets: + checks.SetValue(0) + elif obj in widgets: + self.ok.SetValue(0) + + + def OnShowDialog(self, event): + + btnStyle = 0 + for child in self.mainPanel.GetChildren(): + if isinstance(child, wx.CheckBox) and child not in [self.useExtended, self.customIcons]: + if child.GetValue(): + btnStyle |= eval(child.GetLabel()) + + dlgStyle = eval(self.dialogStyles.GetStringSelection()) + buttonKind = self.buttonKinds.GetSelection() + + if buttonKind == 1: + # Aquabuttons + dlgStyle += GMD.GMD_USE_AQUABUTTONS + elif buttonKind == 2: + # GradientButtons + dlgStyle += GMD.GMD_USE_GRADIENTBUTTONS + + if self.useExtended: + extended = _msg + message = "This is the main message!" + else: + extended = "" + message = _msg + + dlg = GMD.GenericMessageDialog(self, message, + "A Nice Message Box", + btnStyle | dlgStyle) + + if self.customIcons.GetValue(): + b1, b2, b3 = [random.randint(0, len(ART_ICONS)-1) for i in xrange(3)] + b4, b5 = [random.randint(0, len(ART_ICONS)-1) for i in xrange(2)] + + yes = wx.ArtProvider.GetBitmap(ART_ICONS[b1], wx.ART_OTHER, (16, 16)) + no = wx.ArtProvider.GetBitmap(ART_ICONS[b2], wx.ART_OTHER, (16, 16)) + cancel = wx.ArtProvider.GetBitmap(ART_ICONS[b3], wx.ART_OTHER, (16, 16)) + ok = wx.ArtProvider.GetBitmap(ART_ICONS[b4], wx.ART_OTHER, (16, 16)) + help = wx.ArtProvider.GetBitmap(ART_ICONS[b5], wx.ART_OTHER, (16, 16)) + + dlg.SetYesNoCancelBitmaps(yes, no, cancel) + dlg.SetOKBitmap(ok) + dlg.SetHelpBitmap(help) + + dlg.SetExtendedMessage(extended) + dlg.SetIcon(images.Mondrian.GetIcon()) + dlg.ShowModal() + dlg.Destroy() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = GenericMessageDialogDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = GMD.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/agw/GradientButton.py b/demo/agw/GradientButton.py new file mode 100644 index 00000000..2d65df01 --- /dev/null +++ b/demo/agw/GradientButton.py @@ -0,0 +1,154 @@ +import wx + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import gradientbutton as GB + bitmapDir = "bitmaps/" +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.gradientbutton as GB + bitmapDir = "agw/bitmaps/" + + +class GradientButtonDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + + self.log = log + self.mainPanel = wx.Panel(self) + self.mainPanel.SetBackgroundColour(wx.WHITE) + # Initialize GradientButton 1 (no image) + self.btn1 = GB.GradientButton(self.mainPanel, -1, None, "Hello World!") + # Initialize GradientButton 2 (with image) + bitmap = wx.Bitmap(os.path.normpath(bitmapDir+"gradientbutton.png"), wx.BITMAP_TYPE_PNG) + self.btn2 = GB.GradientButton(self.mainPanel, -1, bitmap, "GradientButton") + + self.topStartColour = wx.ColourPickerCtrl(self.mainPanel, col=self.btn2.GetTopStartColour(), + name="Top Start") + self.topEndColour = wx.ColourPickerCtrl(self.mainPanel, col=self.btn2.GetTopEndColour(), + name="Top End") + self.bottomStartColour = wx.ColourPickerCtrl(self.mainPanel, col=self.btn2.GetBottomStartColour(), + name="Bottom Start") + self.bottomEndColour = wx.ColourPickerCtrl(self.mainPanel, col=self.btn2.GetBottomEndColour(), + name="Bottom End") + self.pressedTopColour = wx.ColourPickerCtrl(self.mainPanel, col=self.btn2.GetPressedTopColour(), + name="Pressed Top") + self.pressedBottomColour = wx.ColourPickerCtrl(self.mainPanel, col=self.btn2.GetPressedBottomColour(), + name="Pressed Bottom") + self.textColour = wx.ColourPickerCtrl(self.mainPanel, col=self.btn2.GetForegroundColour(), + name="Text Colour") + + self.DoLayout() + self.BindEvents() + + + def DoLayout(self): + + frameSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer = wx.BoxSizer(wx.VERTICAL) + btnSizer = wx.BoxSizer(wx.HORIZONTAL) + colourSizer = wx.FlexGridSizer(4, 4, 1, 10) + + label1 = wx.StaticText(self.mainPanel, -1, "Welcome to the GradientButton demo for wxPython!") + mainSizer.Add(label1, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10) + + mainSizer.Add(self.btn1, 0, wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT|wx.TOP, 15) + btnSizer.Add(self.btn2, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5) + btnSizer.Add((20, 0)) + + firstStrings = ["Top Start", "Bottom Start", "Pressed Top", "Text Colour"] + secondStrings = ["Top End", "Bottom End", "Pressed Bottom", ""] + + for strings in firstStrings: + label = wx.StaticText(self.mainPanel, -1, strings) + colourSizer.Add(label, 0, wx.ALIGN_CENTER|wx.EXPAND) + for strings in firstStrings: + colourSizer.Add(self.FindWindowByName(strings), 0, wx.ALIGN_CENTER|wx.BOTTOM|wx.EXPAND, 10) + + for strings in secondStrings: + label = wx.StaticText(self.mainPanel, -1, strings) + colourSizer.Add(label, 0, wx.ALIGN_CENTER|wx.EXPAND) + for strings in secondStrings[:-1]: + colourSizer.Add(self.FindWindowByName(strings), 0, wx.ALIGN_CENTER|wx.EXPAND, 10) + + btnSizer.Add(colourSizer, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL) + btnSizer.Add((10, 0)) + mainSizer.Add(btnSizer, 0, wx.EXPAND|wx.ALL, 10) + + boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + boldFont.SetWeight(wx.BOLD) + + for child in self.mainPanel.GetChildren(): + if isinstance(child, wx.StaticText): + child.SetFont(boldFont) + + buttonFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + buttonFont.SetWeight(wx.BOLD) + try: + buttonFont.SetFaceName("Tahoma") + self.btn1.SetFont(buttonFont) + self.btn2.SetFont(buttonFont) + except: + self.btn1.SetFont(boldFont) + self.btn2.SetFont(boldFont) + + self.mainPanel.SetSizer(mainSizer) + mainSizer.Layout() + frameSizer.Add(self.mainPanel, 1, wx.EXPAND) + self.SetSizer(frameSizer) + frameSizer.Layout() + + + def BindEvents(self): + + self.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnPickColour) + self.Bind(wx.EVT_BUTTON, self.OnButton, self.btn1) + self.Bind(wx.EVT_BUTTON, self.OnButton, self.btn2) + + + def OnPickColour(self, event): + + obj = event.GetEventObject() + colour = event.GetColour() + name = obj.GetName() + + if obj == self.textColour: + self.btn2.SetForegroundColour(colour) + else: + method = "Set%sColour"%(name.replace(" ", "")) + method = getattr(self.btn2, method) + method(colour) + + + def OnButton(self, event): + + obj = event.GetEventObject() + self.log.write("You clicked %s\n"%obj.GetLabel()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = GradientButtonDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = GB.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/agw/HyperLinkCtrl.py b/demo/agw/HyperLinkCtrl.py new file mode 100644 index 00000000..0f28438b --- /dev/null +++ b/demo/agw/HyperLinkCtrl.py @@ -0,0 +1,142 @@ +import wx + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import hyperlink as hl +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.hyperlink as hl + + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + self.SetFont(wx.Font(10, wx.SWISS, wx.NORMAL, wx.NORMAL, False)) + + sizer = wx.BoxSizer(wx.VERTICAL) + self.SetSizer(sizer) + + # Creator credits + text1 = wx.StaticText(self, -1, "HyperLinkCtrl Example By Andrea Gavana") + text1.SetFont(wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, False, 'Verdana')) + + sizer.Add((0,10)) + sizer.Add(text1, 0, wx.LEFT | wx.TOP | wx.BOTTOM, 10) + + text2 = wx.StaticText(self, -1, "Latest Revision: 11 May 2005") + text2.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, False, 'Verdana')) + sizer.Add(text2, 0, wx.LEFT, 10) + + sizer.Add((0,25)) + + # Default Web links: + self._hyper1 = hl.HyperLinkCtrl(self, wx.ID_ANY, "wxPython Main Page", + URL="http://www.wxpython.org/") + sizer.Add(self._hyper1, 0, wx.ALL, 10) + + + # Web link with underline rollovers, opens in window + self._hyper2 = hl.HyperLinkCtrl(self, wx.ID_ANY, "My Home Page", + URL="http://xoomer.virgilio.it/infinity77/") + sizer.Add(self._hyper2, 0, wx.ALL, 10) + self._hyper2.Bind(hl.EVT_HYPERLINK_MIDDLE, self.OnMiddleLink) + self._hyper2.AutoBrowse(False) + self._hyper2.SetColours("BLUE", "BLUE", "BLUE") + self._hyper2.EnableRollover(True) + self._hyper2.SetUnderlines(False, False, True) + self._hyper2.SetBold(True) + self._hyper2.OpenInSameWindow(True) # middle click to open in window + self._hyper2.SetToolTip(wx.ToolTip("Middle-click to open in browser window")) + self._hyper2.UpdateLink() + + + # Intense link examples.. + self._hyper3 = hl.HyperLinkCtrl(self, wx.ID_ANY, "wxPython Mail Archive", + URL="http://lists.wxwidgets.org/") + sizer.Add(self._hyper3, 0, wx.ALL, 10) + self._hyper3.Bind(hl.EVT_HYPERLINK_RIGHT, self.OnRightLink) + + self._hyper3.SetLinkCursor(wx.CURSOR_QUESTION_ARROW) + self._hyper3.SetColours("DARK GREEN", "RED", "NAVY") + self._hyper3.SetUnderlines(False, False, False) + self._hyper3.EnableRollover(True) + self._hyper3.SetBold(True) + self._hyper3.DoPopup(False) + self._hyper3.UpdateLink() + + + self._hyper4 = hl.HyperLinkCtrl(self, wx.ID_ANY, + "Open Google In Current Browser Window?", + URL="http://www.google.com") + sizer.Add(self._hyper4, 0, wx.ALL, 10) + self._hyper4.Bind(hl.EVT_HYPERLINK_LEFT, self.OnLink) + self._hyper4.SetToolTip(wx.ToolTip("Click link for yes, no, cancel dialog")) + self._hyper4.AutoBrowse(False) + + + + + + def OnLink(self, event): + # Goto URL, demonstrates attempt to open link in current window: + strs = "Open Google In Current Browser Window " + strs = strs + "(NO Opens Google In Another Browser Window)?" + nResult = wx.MessageBox(strs, "HyperLinkCtrl", wx.YES_NO | + wx.CANCEL | wx.ICON_QUESTION, self) + + if nResult == wx.YES: + self._hyper4.GotoURL("http://www.google.com", True, True) + elif nResult == wx.NO: + self._hyper4.GotoURL("http://www.google.com", True, False) + + + + def OnRightLink(self, event): + pos = self._hyper3.GetPosition() + event.GetPosition() + menuPopUp = wx.Menu("Having a nice day?") + ID_MENU_YES = wx.NewId() + ID_MENU_NO = wx.NewId() + menuPopUp.Append(ID_MENU_YES, "Yes, absolutely!") + menuPopUp.Append(ID_MENU_NO, "I've had better") + self.PopupMenu(menuPopUp) + menuPopUp.Destroy() + + + + def OnMiddleLink(self, event): + self._hyper2.GotoURL("http://xoomer.virgilio.it/infinity77/", + True, True) + + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = hl.__doc__ + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/agw/HyperTreeList.py b/demo/agw/HyperTreeList.py new file mode 100644 index 00000000..9d0d00de --- /dev/null +++ b/demo/agw/HyperTreeList.py @@ -0,0 +1,2535 @@ +import os +import string +import random + +import wx +import wx.lib.colourselect as csel +import wx.lib.colourutils as cutils + +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import hypertreelist as HTL + bitmapDir = "bitmaps/" +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.hypertreelist as HTL + bitmapDir = "agw/bitmaps/" + +import ListCtrl +import images + + +penstyle = ["wx.SOLID", "wx.TRANSPARENT", "wx.DOT", "wx.LONG_DASH", "wx.DOT_DASH", "wx.USER_DASH", + "wx.BDIAGONAL_HATCH", "wx.CROSSDIAG_HATCH", "wx.FDIAGONAL_HATCH", "wx.CROSS_HATCH", + "wx.HORIZONTAL_HATCH", "wx.VERTICAL_HATCH"] + +ArtIDs = [ "None", + "wx.ART_ADD_BOOKMARK", + "wx.ART_DEL_BOOKMARK", + "wx.ART_HELP_SIDE_PANEL", + "wx.ART_HELP_SETTINGS", + "wx.ART_HELP_BOOK", + "wx.ART_HELP_FOLDER", + "wx.ART_HELP_PAGE", + "wx.ART_GO_BACK", + "wx.ART_GO_FORWARD", + "wx.ART_GO_UP", + "wx.ART_GO_DOWN", + "wx.ART_GO_TO_PARENT", + "wx.ART_GO_HOME", + "wx.ART_FILE_OPEN", + "wx.ART_PRINT", + "wx.ART_HELP", + "wx.ART_TIP", + "wx.ART_REPORT_VIEW", + "wx.ART_LIST_VIEW", + "wx.ART_NEW_DIR", + "wx.ART_HARDDISK", + "wx.ART_FLOPPY", + "wx.ART_CDROM", + "wx.ART_REMOVABLE", + "wx.ART_FOLDER", + "wx.ART_FOLDER_OPEN", + "wx.ART_GO_DIR_UP", + "wx.ART_EXECUTABLE_FILE", + "wx.ART_NORMAL_FILE", + "wx.ART_TICK_MARK", + "wx.ART_CROSS_MARK", + "wx.ART_ERROR", + "wx.ART_QUESTION", + "wx.ART_WARNING", + "wx.ART_INFORMATION", + "wx.ART_MISSING_IMAGE", + "SmileBitmap" + ] + +keyMap = { + wx.WXK_BACK : "WXK_BACK", + wx.WXK_TAB : "WXK_TAB", + wx.WXK_RETURN : "WXK_RETURN", + wx.WXK_ESCAPE : "WXK_ESCAPE", + wx.WXK_SPACE : "WXK_SPACE", + wx.WXK_DELETE : "WXK_DELETE", + wx.WXK_START : "WXK_START", + wx.WXK_LBUTTON : "WXK_LBUTTON", + wx.WXK_RBUTTON : "WXK_RBUTTON", + wx.WXK_CANCEL : "WXK_CANCEL", + wx.WXK_MBUTTON : "WXK_MBUTTON", + wx.WXK_CLEAR : "WXK_CLEAR", + wx.WXK_SHIFT : "WXK_SHIFT", + wx.WXK_ALT : "WXK_ALT", + wx.WXK_CONTROL : "WXK_CONTROL", + wx.WXK_MENU : "WXK_MENU", + wx.WXK_PAUSE : "WXK_PAUSE", + wx.WXK_CAPITAL : "WXK_CAPITAL", + wx.WXK_PRIOR : "WXK_PRIOR", + wx.WXK_NEXT : "WXK_NEXT", + wx.WXK_END : "WXK_END", + wx.WXK_HOME : "WXK_HOME", + wx.WXK_LEFT : "WXK_LEFT", + wx.WXK_UP : "WXK_UP", + wx.WXK_RIGHT : "WXK_RIGHT", + wx.WXK_DOWN : "WXK_DOWN", + wx.WXK_SELECT : "WXK_SELECT", + wx.WXK_PRINT : "WXK_PRINT", + wx.WXK_EXECUTE : "WXK_EXECUTE", + wx.WXK_SNAPSHOT : "WXK_SNAPSHOT", + wx.WXK_INSERT : "WXK_INSERT", + wx.WXK_HELP : "WXK_HELP", + wx.WXK_NUMPAD0 : "WXK_NUMPAD0", + wx.WXK_NUMPAD1 : "WXK_NUMPAD1", + wx.WXK_NUMPAD2 : "WXK_NUMPAD2", + wx.WXK_NUMPAD3 : "WXK_NUMPAD3", + wx.WXK_NUMPAD4 : "WXK_NUMPAD4", + wx.WXK_NUMPAD5 : "WXK_NUMPAD5", + wx.WXK_NUMPAD6 : "WXK_NUMPAD6", + wx.WXK_NUMPAD7 : "WXK_NUMPAD7", + wx.WXK_NUMPAD8 : "WXK_NUMPAD8", + wx.WXK_NUMPAD9 : "WXK_NUMPAD9", + wx.WXK_MULTIPLY : "WXK_MULTIPLY", + wx.WXK_ADD : "WXK_ADD", + wx.WXK_SEPARATOR : "WXK_SEPARATOR", + wx.WXK_SUBTRACT : "WXK_SUBTRACT", + wx.WXK_DECIMAL : "WXK_DECIMAL", + wx.WXK_DIVIDE : "WXK_DIVIDE", + wx.WXK_F1 : "WXK_F1", + wx.WXK_F2 : "WXK_F2", + wx.WXK_F3 : "WXK_F3", + wx.WXK_F4 : "WXK_F4", + wx.WXK_F5 : "WXK_F5", + wx.WXK_F6 : "WXK_F6", + wx.WXK_F7 : "WXK_F7", + wx.WXK_F8 : "WXK_F8", + wx.WXK_F9 : "WXK_F9", + wx.WXK_F10 : "WXK_F10", + wx.WXK_F11 : "WXK_F11", + wx.WXK_F12 : "WXK_F12", + wx.WXK_F13 : "WXK_F13", + wx.WXK_F14 : "WXK_F14", + wx.WXK_F15 : "WXK_F15", + wx.WXK_F16 : "WXK_F16", + wx.WXK_F17 : "WXK_F17", + wx.WXK_F18 : "WXK_F18", + wx.WXK_F19 : "WXK_F19", + wx.WXK_F20 : "WXK_F20", + wx.WXK_F21 : "WXK_F21", + wx.WXK_F22 : "WXK_F22", + wx.WXK_F23 : "WXK_F23", + wx.WXK_F24 : "WXK_F24", + wx.WXK_NUMLOCK : "WXK_NUMLOCK", + wx.WXK_SCROLL : "WXK_SCROLL", + wx.WXK_PAGEUP : "WXK_PAGEUP", + wx.WXK_PAGEDOWN : "WXK_PAGEDOWN", + wx.WXK_NUMPAD_SPACE : "WXK_NUMPAD_SPACE", + wx.WXK_NUMPAD_TAB : "WXK_NUMPAD_TAB", + wx.WXK_NUMPAD_ENTER : "WXK_NUMPAD_ENTER", + wx.WXK_NUMPAD_F1 : "WXK_NUMPAD_F1", + wx.WXK_NUMPAD_F2 : "WXK_NUMPAD_F2", + wx.WXK_NUMPAD_F3 : "WXK_NUMPAD_F3", + wx.WXK_NUMPAD_F4 : "WXK_NUMPAD_F4", + wx.WXK_NUMPAD_HOME : "WXK_NUMPAD_HOME", + wx.WXK_NUMPAD_LEFT : "WXK_NUMPAD_LEFT", + wx.WXK_NUMPAD_UP : "WXK_NUMPAD_UP", + wx.WXK_NUMPAD_RIGHT : "WXK_NUMPAD_RIGHT", + wx.WXK_NUMPAD_DOWN : "WXK_NUMPAD_DOWN", + wx.WXK_NUMPAD_PRIOR : "WXK_NUMPAD_PRIOR", + wx.WXK_NUMPAD_PAGEUP : "WXK_NUMPAD_PAGEUP", + wx.WXK_NUMPAD_NEXT : "WXK_NUMPAD_NEXT", + wx.WXK_NUMPAD_PAGEDOWN : "WXK_NUMPAD_PAGEDOWN", + wx.WXK_NUMPAD_END : "WXK_NUMPAD_END", + wx.WXK_NUMPAD_BEGIN : "WXK_NUMPAD_BEGIN", + wx.WXK_NUMPAD_INSERT : "WXK_NUMPAD_INSERT", + wx.WXK_NUMPAD_DELETE : "WXK_NUMPAD_DELETE", + wx.WXK_NUMPAD_EQUAL : "WXK_NUMPAD_EQUAL", + wx.WXK_NUMPAD_MULTIPLY : "WXK_NUMPAD_MULTIPLY", + wx.WXK_NUMPAD_ADD : "WXK_NUMPAD_ADD", + wx.WXK_NUMPAD_SEPARATOR : "WXK_NUMPAD_SEPARATOR", + wx.WXK_NUMPAD_SUBTRACT : "WXK_NUMPAD_SUBTRACT", + wx.WXK_NUMPAD_DECIMAL : "WXK_NUMPAD_DECIMAL", + wx.WXK_NUMPAD_DIVIDE : "WXK_NUMPAD_DIVIDE" + } + + +#---------------------------------------------------------------------- +def GetMondrianData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\ +\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\ +ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\ +o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\ +\xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\ +\x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\ +\x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82' + +def GetMondrianBitmap(): + return wx.BitmapFromImage(GetMondrianImage()) + +def GetMondrianImage(): + import cStringIO + stream = cStringIO.StringIO(GetMondrianData()) + return wx.ImageFromStream(stream) + +def GetMondrianIcon(): + icon = wx.EmptyIcon() + icon.CopyFromBitmap(GetMondrianBitmap()) + return icon + + +#---------------------------------------------------------------------- +def GetSmilesData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x10\x08\x06\ +\x00\x00\x00\x1f\xf3\xffa\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\ +\x00\x02\x89IDAT8\x8dm\x93\xddK\x93a\x18\xc6\x7f\xef\xc7\xb3\xa6\xc3 aV\xcc\ +\xad\x99\x8d\\\x08\x11AAd\x91\x95\x85F\'\x9dD\x8d\xa8\xe9\xb6X\x87\xe1\x7f\ +\xd0A\xe2y\'\xe6I\x7f@\'!T\x96\'A\x10A\xf4!\xcc\xd1\xb7&DP \xba\xe5\xde\xd7\ +\xed\xea\xc0\xcdF\xf9\xc0u\xf2<\xcf\xc5}\xdf\xd7u\xddX\xb6\xc3\xbfH\xa5.)\ +\x1e\xdf)\xd7\xb5d\x8c\xadD"\xaa\\.\xa3\xcd\xfe\xda4\x9dl&\xad\xceHP\xbd\xbd\ +\x9fx\xf0\xe0\x08\xe5\xf2eJ\xa5\x8b\xdc\xbf\xbf\x9f\xae\xaeGtFj\xcaf\xae\xa9\ +\x99cY\xb6\x03\xc0\xe9S\xc7\x14\x8b\xfd\xe4\xce\x9d\xf3\x18\xe3\x01%`\x05\ +\xa8\x02\x15\xe0#\xbe_ \x9f\xf7\x98\x9f?\xc2\xf4\x93\xe7\x16\xb0\xdeA6\x93V,\ +\x06\x13\x13\xb71&\t\x84\xea\xc4F\xb1U\xa0\x8c1\x16\x13\x13[\x88\xc5\x9e\x91\ +\xcd\\]\x7f\xb4l\x87h\xb4]\x9eW\x90\xf4E\xd2c\x8d\x8e\x8e\n\x90\x94\x92\x94\ +\x12\xa0p8,\xa9UR\x8b<\x0fE;\x91e;\xb8\xd9LZ]]k\x18\xd3\x028@\x8d\xf1\xf1\ +\xf1\xa6)\x97\xe8\xe9\xe9ann\x0eh\x05\xd50\x04\xb9q\xbd\xca\xe7\xf9\x94\xec\ +\x99\x99\x87\x0c\rE\x80E\xe0#\xf0\xba\x89\\\x01\x16YXXh\xba\xabA\xa5\x95\xa1\ +\x93m\xcc\xccLa\x19c\xabT\xba\x891m\xc0*\xc3\xc3\xdf\x99\x9c\xf46\x84\x83\ +\x85\xba\xa0ur\xb5\nK\x1d\xf8\xab\x0e\xa1]\xf3\r\x1b\xbd\xba\xe2\xcbLN\xfa\ +\xc0\x12\xf0\x0e(6\x91\x05Zcwg\x10\xfc\x16\xf0\x83\x00\xd8\xf1x\x84b\xf1\x1b\ +\xf0\x03(\x92L\xbe\x04^\xd4+\xeb/\x19\x1f\xaa6\x9f\xbf/C\xb9\x8d\xe2\x9cE|W\ +\x18\xb7\xbf\xff\x0cSS\xf7\xe8\xed\r\x00\xa2P\x80PH\x94\x1a\x85\xa9\x01kP\ +\xb58\xb8\xaf\r}\x89@y+S\x8f\x7f\xd1\x7f\xfcd\xc3FK\x9e\xd7R\xb7i\xdd*\x05\ +\x83\n\x04\x02r]G\xa1\xa0\xab\xfd\xdd\xed\xd2\xe2^\xa9\xd0\'\xef\xd5\tEw\x04\ +\xb4\x11\xe5\xc1\xc14\xf9\xfc\xeaz\x9b\r\xfc\xf6\xa9\xf8>\xbecq8\xd9\xc1\xeb\ +\xa7QX\x0e\xc3Z\x80\xfc\xad"\x83g\xce\xb1\x11$\xcbv\x18\x18\xe8\xd3\xc8\x08\ +\xf2<$\xd5Q\xb5\xa5\x95m\xd2\xb7\xa4\xf4\xe1\x90\xbc7G5ra\x87\x06\x8e\x1f\ +\xd0\x7f\xcb4\xfd\xe4\xb9\xe58\xc3tw\xc3\xd8\x18\xcc\xce\x82_q\xf0+6\xb3\xef\ +W\x18\xbb\xfb\x95\xee\xb3/p\xb6\xf61\xfd\xec\xad\xb5\x11\x8b\xcdV4\x97K+\x91\ +\xd8.\xe3"\xe3\xa2\xc4\x9e\x0e\xe52W6]\xe7?\xc6#-\xf1\x056\x98<\x00\x00\x00\ +\x00IEND\xaeB`\x82' + +def GetSmilesBitmap(): + return wx.BitmapFromImage(GetSmilesImage()) + +def GetSmilesImage(): + import cStringIO + stream = cStringIO.StringIO(GetSmilesData()) + return wx.ImageFromStream(stream) + + +#----------------------------------------------------------------------------- +# PATH & FILE FILLING (OS INDEPENDENT) +#----------------------------------------------------------------------------- + +def opj(path): + """Convert paths to the platform-specific separator""" + str = apply(os.path.join, tuple(path.split('/'))) + # HACK: on Linux, a leading / gets lost... + if path.startswith('/'): + str = '/' + str + return str + +#----------------------------------------------------------------------------- + +#--------------------------------------------------------------------------- +# Just A Dialog To Select Pen Styles +#--------------------------------------------------------------------------- +class PenDialog(wx.Dialog): + + def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, oldpen=None, + pentype=0): + + wx.Dialog.__init__(self, parent, id, title, pos, size, style) + + self.colourbutton = wx.Button(self, -1, "") + self.spinwidth = wx.SpinCtrl(self, -1, "1", min=1, max=3, style=wx.SP_ARROW_KEYS) + + self.combostyle = wx.ComboBox(self, -1, choices=penstyle, style=wx.CB_DROPDOWN|wx.CB_READONLY) + + choices = ["[1, 1]", "[2, 2]", "[3, 3]", "[4, 4]"] + self.combodash = wx.ComboBox(self, -1, choices=choices, style=wx.CB_DROPDOWN|wx.CB_READONLY) + + self.okbutton = wx.Button(self, -1, "Ok") + self.cancelbutton = wx.Button(self, -1, "Cancel") + + self.oldpen = oldpen + self.parent = parent + self.pentype = pentype + + self.__set_properties() + self.__do_layout() + + self.Bind(wx.EVT_BUTTON, self.OnColour, self.colourbutton) + self.Bind(wx.EVT_COMBOBOX, self.OnStyle, self.combostyle) + self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton) + self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton) + + + def __set_properties(self): + + self.SetTitle("Pen Dialog Selector") + self.colourbutton.SetMinSize((25, 25)) + self.colourbutton.SetBackgroundColour(self.oldpen.GetColour()) + + style = self.oldpen.GetStyle() + for count, st in enumerate(penstyle): + if eval(st) == style: + self.combostyle.SetSelection(count) + if count == 5: + self.combodash.Enable(True) + else: + self.combodash.Enable(False) + break + + if self.combodash.IsEnabled(): + dashes = repr(self.oldpen.GetDashes()) + self.combodash.SetValue(dashes) + + self.spinwidth.SetValue(self.oldpen.GetWidth()) + self.okbutton.SetDefault() + + if self.pentype == 1: + self.spinwidth.Enable(False) + + + def __do_layout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + bottomsizer = wx.BoxSizer(wx.HORIZONTAL) + middlesizer = wx.BoxSizer(wx.VERTICAL) + stylesizer = wx.BoxSizer(wx.HORIZONTAL) + widthsizer = wx.BoxSizer(wx.HORIZONTAL) + coloursizer = wx.BoxSizer(wx.HORIZONTAL) + label_1 = wx.StaticText(self, -1, "Please Choose The Pen Settings:") + label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10) + label_2 = wx.StaticText(self, -1, "Pen Colour") + coloursizer.Add(label_2, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + coloursizer.Add((5, 5), 1, wx.ADJUST_MINSIZE, 0) + coloursizer.Add(self.colourbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 5) + middlesizer.Add(coloursizer, 0, wx.EXPAND, 0) + label_3 = wx.StaticText(self, -1, "Pen Width") + widthsizer.Add(label_3, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + widthsizer.Add((5, 5), 1, wx.ADJUST_MINSIZE, 0) + widthsizer.Add(self.spinwidth, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + middlesizer.Add(widthsizer, 0, wx.EXPAND, 0) + label_4 = wx.StaticText(self, -1, "Pen Style") + stylesizer.Add(label_4, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + stylesizer.Add((5, 5), 1, wx.ADJUST_MINSIZE, 0) + stylesizer.Add(self.combostyle, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + stylesizer.Add(self.combodash, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + middlesizer.Add(stylesizer, 0, wx.BOTTOM|wx.EXPAND, 5) + mainsizer.Add(middlesizer, 1, wx.EXPAND, 0) + bottomsizer.Add(self.okbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20) + bottomsizer.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + bottomsizer.Add(self.cancelbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20) + mainsizer.Add(bottomsizer, 0, wx.EXPAND, 0) + self.SetAutoLayout(True) + self.SetSizer(mainsizer) + mainsizer.Fit(self) + mainsizer.SetSizeHints(self) + self.Layout() + self.Centre() + + + def OnColour(self, event): + + obj = event.GetEventObject() + old = obj.GetBackgroundColour() + colourdata = wx.ColourData() + colourdata.SetColour(old) + dlg = wx.ColourDialog(self, colourdata) + + dlg.GetColourData().SetChooseFull(True) + + if dlg.ShowModal() == wx.ID_OK: + + # If the user selected OK, then the dialog's wx.ColourData will + # contain valid information. Fetch the data ... + data = dlg.GetColourData() + + # ... then do something with it. The actual colour data will be + # returned as a three-tuple (r, g, b) in this particular case. + col1 = data.GetColour().Get() + obj.SetBackgroundColour(col1) + # Once the dialog is destroyed, Mr. wx.ColourData is no longer your + # friend. Don't use it again! + dlg.Destroy() + + event.Skip() + + + def OnStyle(self, event): + + choice = event.GetEventObject().GetValue() + self.combodash.Enable(choice==5) + event.Skip() + + + def OnOk(self, event): + + colour = self.colourbutton.GetBackgroundColour() + style = eval(self.combostyle.GetValue()) + width = int(self.spinwidth.GetValue()) + + dashes = None + if self.combostyle.GetSelection() == 5: + dashes = eval(self.combodash.GetValue()) + + pen = wx.Pen(colour, width, style) + + if dashes: + pen.SetDashes(dashes) + + pen.SetCap(wx.CAP_BUTT) + + if self.pentype == 0: + self.parent.SetConnectionPen(pen) + else: + self.parent.SetBorderPen(pen) + + self.Destroy() + event.Skip() + + + def OnCancel(self, event): + + self.Destroy() + event.Skip() + + +#--------------------------------------------------------------------------- +# Just A Dialog To Select Tree Buttons Icons +#--------------------------------------------------------------------------- +class TreeDialog(wx.Dialog): + + def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, oldicons=None): + + wx.Dialog.__init__(self, parent, id, title, pos, size, style) + + self.listicons = wx.ListBox(self, -1, choices=["Set 1", "Set 2", "Set 3", "Set 4", "Set 5"], style=wx.LB_SINGLE) + + bitmap_plus = opj(bitmapDir + "plus" + str(oldicons+1) + ".ico") + bitmap_minus = opj(bitmapDir+ "minus" + str(oldicons+1) + ".ico") + + bitmap_plus = wx.Image(bitmap_plus, wx.BITMAP_TYPE_ICO) + bitmap_plus.Rescale(24, 24) + bitmap_plus = bitmap_plus.ConvertToBitmap() + bitmap_minus = wx.Image(bitmap_minus, wx.BITMAP_TYPE_ICO) + bitmap_minus.Rescale(24, 24) + bitmap_minus = bitmap_minus.ConvertToBitmap() + + self.bitmap_plus = wx.StaticBitmap(self, -1, bitmap_plus) + self.bitmap_minus = wx.StaticBitmap(self, -1, bitmap_minus) + + self.okbutton = wx.Button(self, -1, "Ok") + self.cancelbutton = wx.Button(self, -1, "Cancel") + + self.parent = parent + + self.__set_properties() + self.__do_layout() + + self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton) + self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton) + self.Bind(wx.EVT_LISTBOX, self.OnListBox, self.listicons) + + + def __set_properties(self): + + self.SetTitle("Tree Buttons Selector") + self.listicons.SetSelection(0) + self.okbutton.SetDefault() + + + def __do_layout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + bottomsizer = wx.BoxSizer(wx.HORIZONTAL) + topsizer = wx.BoxSizer(wx.HORIZONTAL) + rightsizer = wx.BoxSizer(wx.VERTICAL) + sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + label_1 = wx.StaticText(self, -1, "Please Choose One Of These Sets Of Icons:") + label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10) + topsizer.Add(self.listicons, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 5) + label_2 = wx.StaticText(self, -1, "Collapsed") + sizer_1.Add(label_2, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_1.Add((20, 20), 1, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0) + sizer_1.Add(self.bitmap_plus, 1, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_1, 0, wx.EXPAND, 0) + label_3 = wx.StaticText(self, -1, "Expanded") + sizer_2.Add(label_3, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_2.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + sizer_2.Add(self.bitmap_minus, 1, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_2, 0, wx.EXPAND, 0) + topsizer.Add(rightsizer, 0, wx.ALL|wx.EXPAND, 5) + mainsizer.Add(topsizer, 1, wx.EXPAND, 0) + bottomsizer.Add(self.okbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20) + bottomsizer.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + bottomsizer.Add(self.cancelbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20) + mainsizer.Add(bottomsizer, 0, wx.EXPAND, 0) + self.SetAutoLayout(True) + self.SetSizer(mainsizer) + mainsizer.Fit(self) + mainsizer.SetSizeHints(self) + self.Layout() + + + def OnListBox(self, event): + + selection = self.listicons.GetSelection() + bitmap_plus = opj(bitmapDir + "plus" + str(selection+1) + ".ico") + bitmap_minus = opj(bitmapDir+ "minus" + str(selection+1) + ".ico") + + bitmap_plus = wx.Image(bitmap_plus, wx.BITMAP_TYPE_ICO) + bitmap_plus.Rescale(24, 24) + bitmap_plus = bitmap_plus.ConvertToBitmap() + bitmap_minus = wx.Image(bitmap_minus, wx.BITMAP_TYPE_ICO) + bitmap_minus.Rescale(24, 24) + bitmap_minus = bitmap_minus.ConvertToBitmap() + + self.bitmap_plus.SetBitmap(bitmap_plus) + self.bitmap_minus.SetBitmap(bitmap_minus) + + self.bitmap_plus.Refresh() + self.bitmap_minus.Refresh() + event.Skip() + + + def OnOk(self, event): + + selection = self.listicons.GetSelection() + self.parent.SetTreeButtons(selection) + self.Destroy() + event.Skip() + + + def OnCancel(self, event): + + self.Destroy() + event.Skip() + + +#--------------------------------------------------------------------------- +# Just A Dialog To Select Tree Cehck/Radio Item Icons +#--------------------------------------------------------------------------- +class CheckDialog(wx.Dialog): + + def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE): + + wx.Dialog.__init__(self, parent, id, title, pos, size, style) + + self.listicons = wx.ListBox(self, -1, choices=["Set 1", "Set 2"], style=wx.LB_SINGLE) + + bitmap_check = wx.Bitmap(opj(bitmapDir+ "checked.ico"), wx.BITMAP_TYPE_ICO) + bitmap_uncheck = wx.Bitmap(opj(bitmapDir+ "notchecked.ico"), wx.BITMAP_TYPE_ICO) + bitmap_flag = wx.Bitmap(opj(bitmapDir+ "flagged.ico"), wx.BITMAP_TYPE_ICO) + bitmap_unflag = wx.Bitmap(opj(bitmapDir+ "notflagged.ico"), wx.BITMAP_TYPE_ICO) + + self.bitmap_check = wx.StaticBitmap(self, -1, bitmap_check) + self.bitmap_uncheck = wx.StaticBitmap(self, -1, bitmap_uncheck) + self.bitmap_flag = wx.StaticBitmap(self, -1, bitmap_flag) + self.bitmap_unflag = wx.StaticBitmap(self, -1, bitmap_unflag) + + self.okbutton = wx.Button(self, -1, "Ok") + self.cancelbutton = wx.Button(self, -1, "Cancel") + + self.parent = parent + + self.__set_properties() + self.__do_layout() + + self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton) + self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton) + self.Bind(wx.EVT_LISTBOX, self.OnListBox, self.listicons) + + + def __set_properties(self): + + self.SetTitle("Check/Radio Icon Selector") + self.listicons.SetSelection(0) + self.okbutton.SetDefault() + + + def __do_layout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + bottomsizer = wx.BoxSizer(wx.HORIZONTAL) + topsizer = wx.BoxSizer(wx.HORIZONTAL) + rightsizer = wx.BoxSizer(wx.VERTICAL) + sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + sizer_1 = wx.BoxSizer(wx.HORIZONTAL) + sizer_3 = wx.BoxSizer(wx.HORIZONTAL) + sizer_4 = wx.BoxSizer(wx.HORIZONTAL) + label_1 = wx.StaticText(self, -1, "Please Choose One Of These Sets Of Icons:") + label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10) + topsizer.Add(self.listicons, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 5) + label_2 = wx.StaticText(self, -1, "Checked") + sizer_1.Add(label_2, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_1.Add((20, 20), 1, wx.ALIGN_RIGHT|wx.ADJUST_MINSIZE, 0) + sizer_1.Add(self.bitmap_check, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_1, 0, wx.EXPAND, 0) + label_3 = wx.StaticText(self, -1, "Not Checked") + sizer_2.Add(label_3, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_2.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + sizer_2.Add(self.bitmap_uncheck, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_2, 0, wx.EXPAND, 0) + label_4 = wx.StaticText(self, -1, "Flagged") + sizer_3.Add(label_4, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_3.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + sizer_3.Add(self.bitmap_flag, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_3, 0, wx.EXPAND, 0) + label_5 = wx.StaticText(self, -1, "Not Flagged") + sizer_4.Add(label_5, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + sizer_4.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + sizer_4.Add(self.bitmap_unflag, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 10) + rightsizer.Add(sizer_4, 0, wx.EXPAND, 0) + + topsizer.Add(rightsizer, 0, wx.ALL|wx.EXPAND, 5) + mainsizer.Add(topsizer, 1, wx.EXPAND, 0) + bottomsizer.Add(self.okbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20) + bottomsizer.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + bottomsizer.Add(self.cancelbutton, 0, wx.ALL|wx.ADJUST_MINSIZE, 20) + mainsizer.Add(bottomsizer, 0, wx.EXPAND, 0) + self.SetAutoLayout(True) + self.SetSizer(mainsizer) + mainsizer.Fit(self) + mainsizer.SetSizeHints(self) + self.Layout() + + + def OnListBox(self, event): + + selection = self.listicons.GetSelection() + + if selection == 0: + bitmap_check = opj(bitmapDir + "checked.ico") + bitmap_uncheck = opj(bitmapDir + "notchecked.ico") + bitmap_flag = opj(bitmapDir + "flagged.ico") + bitmap_unflag = opj(bitmapDir + "notflagged.ico") + else: + bitmap_check = opj(bitmapDir + "aquachecked.ico") + bitmap_uncheck = opj(bitmapDir + "aquanotchecked.ico") + bitmap_flag = opj(bitmapDir + "aquaflagged.ico") + bitmap_unflag = opj(bitmapDir + "aquanotflagged.ico") + + bitmap_check = wx.Bitmap(bitmap_check, wx.BITMAP_TYPE_ICO) + bitmap_uncheck = wx.Bitmap(bitmap_uncheck, wx.BITMAP_TYPE_ICO) + bitmap_flag = wx.Bitmap(bitmap_flag, wx.BITMAP_TYPE_ICO) + bitmap_unflag = wx.Bitmap(bitmap_unflag, wx.BITMAP_TYPE_ICO) + + self.bitmap_uncheck.SetBitmap(bitmap_uncheck) + self.bitmap_check.SetBitmap(bitmap_check) + self.bitmap_unflag.SetBitmap(bitmap_unflag) + self.bitmap_flag.SetBitmap(bitmap_flag) + + self.bitmap_check.Refresh() + self.bitmap_uncheck.Refresh() + self.bitmap_flag.Refresh() + self.bitmap_unflag.Refresh() + + event.Skip() + + + def OnOk(self, event): + + selection = self.listicons.GetSelection() + self.parent.SetCheckRadio(selection) + self.Destroy() + event.Skip() + + + def OnCancel(self, event): + + self.Destroy() + event.Skip() + + +#--------------------------------------------------------------------------- +# Just A Dialog To Select Tree Items Icons +#--------------------------------------------------------------------------- +class TreeIcons(wx.Dialog): + + def __init__(self, parent=None, id=-1, title="", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_DIALOG_STYLE, oldpen=None, + bitmaps=None): + + wx.Dialog.__init__(self, parent, id, title, pos, size, style) + + self.bitmaps = [None, None, None, None] + empty = wx.EmptyBitmap(16, 16) + self.parent = parent + + self.bitmaps[0] = wx.StaticBitmap(self, -1, empty) + self.combonormal = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.bitmaps[1] = wx.StaticBitmap(self, -1, empty) + self.comboselected = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.bitmaps[2] = wx.StaticBitmap(self, -1, empty) + self.comboexpanded = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.bitmaps[3] = wx.StaticBitmap(self, -1, empty) + self.comboselectedexpanded = wx.ComboBox(self, -1, choices=ArtIDs, style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.okbutton = wx.Button(self, -1, "Ok") + self.cancelbutton = wx.Button(self, -1, "Cancel") + + self.combonormal.SetSelection(bitmaps[0] >= 0 and bitmaps[0]+1 or 0) + self.comboselected.SetSelection(bitmaps[1] >= 0 and bitmaps[1]+1 or 0) + self.comboexpanded.SetSelection(bitmaps[2] >= 0 and bitmaps[2]+1 or 0) + self.comboselectedexpanded.SetSelection(bitmaps[3] >= 0 and bitmaps[3]+1 or 0) + + self.GetBitmaps(bitmaps) + + self.__set_properties() + self.__do_layout() + + self.Bind(wx.EVT_COMBOBOX, self.OnComboNormal, self.combonormal) + self.Bind(wx.EVT_COMBOBOX, self.OnComboSelected, self.comboselected) + self.Bind(wx.EVT_COMBOBOX, self.OnComboExpanded, self.comboexpanded) + self.Bind(wx.EVT_COMBOBOX, self.OnComboSelectedExpanded, self.comboselectedexpanded) + self.Bind(wx.EVT_BUTTON, self.OnOk, self.okbutton) + self.Bind(wx.EVT_BUTTON, self.OnCancel, self.cancelbutton) + + + def __set_properties(self): + + self.SetTitle("Item Icon Selector") + self.okbutton.SetDefault() + + + def __do_layout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + sizer_2 = wx.BoxSizer(wx.HORIZONTAL) + gridsizer = wx.FlexGridSizer(cols=3, hgap=5, vgap=5) + label_1 = wx.StaticText(self, -1, "Please Choose The Icons For This Item (All Are Optional):") + label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + mainsizer.Add(label_1, 0, wx.ALL|wx.ADJUST_MINSIZE, 10) + label_2 = wx.StaticText(self, -1, "TreeIcon_Normal:") + gridsizer.Add(label_2, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.bitmaps[0], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.combonormal, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + label_3 = wx.StaticText(self, -1, "TreeIcon_Selected:") + gridsizer.Add(label_3, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.bitmaps[1], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.comboselected, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + label_4 = wx.StaticText(self, -1, "TreeIcon_Expanded:") + gridsizer.Add(label_4, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.bitmaps[2], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.comboexpanded, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + label_5 = wx.StaticText(self, -1, "TreeIcon_SelectedExpanded:") + gridsizer.Add(label_5, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.bitmaps[3], 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.comboselectedexpanded, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 0) + gridsizer.AddGrowableCol(0) + gridsizer.AddGrowableCol(1) + gridsizer.AddGrowableCol(2) + mainsizer.Add(gridsizer, 0, wx.ALL|wx.EXPAND, 5) + sizer_2.Add(self.okbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20) + sizer_2.Add((20, 20), 1, wx.ADJUST_MINSIZE, 0) + sizer_2.Add(self.cancelbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 20) + mainsizer.Add(sizer_2, 1, wx.EXPAND, 0) + self.SetAutoLayout(True) + self.SetSizer(mainsizer) + mainsizer.Fit(self) + mainsizer.SetSizeHints(self) + self.Layout() + self.Centre() + + + def OnComboNormal(self, event): + + input = event.GetSelection() + self.GetBitmap(input, 0) + event.Skip() + + + def OnComboSelected(self, event): + + input = event.GetSelection() + self.GetBitmap(input, 1) + event.Skip() + + + def OnComboExpanded(self, event): + + input = event.GetSelection() + self.GetBitmap(input, 2) + event.Skip() + + + def OnComboSelectedExpanded(self, event): + + input = event.GetSelection() + self.GetBitmap(input, 3) + event.Skip() + + + def OnOk(self, event): + + bitmaps = [-1, -1, -1, -1] + normal = self.combonormal.GetSelection() + selected = self.comboselected.GetSelection() + expanded = self.comboexpanded.GetSelection() + selexp = self.comboselectedexpanded.GetSelection() + + bitmaps = [(normal > 0 and normal or -1), (selected > 0 and selected or -1), + (expanded > 0 and expanded or -1), (selexp > 0 and selexp or -1)] + + newbitmaps = [] + + for bmp in bitmaps: + if bmp > 0: + newbitmaps.append(bmp-1) + else: + newbitmaps.append(bmp) + + self.parent.SetNewIcons(newbitmaps) + + self.Destroy() + event.Skip() + + + def OnCancel(self, event): + + self.Destroy() + event.Skip() + + + def GetBitmap(self, input, which): + + if input == 0: + bmp = wx.EmptyBitmap(16,16) + self.ClearBmp(bmp) + elif input > 36: + bmp = GetSmilesBitmap() + else: + bmp = wx.ArtProvider_GetBitmap(eval(ArtIDs[input]), wx.ART_OTHER, (16,16)) + if not bmp.Ok(): + bmp = wx.EmptyBitmap(16,16) + self.ClearBmp(bmp) + + self.bitmaps[which].SetBitmap(bmp) + self.bitmaps[which].Refresh() + + + def GetBitmaps(self, bitmaps): + + output = [] + + for count, input in enumerate(bitmaps): + if input < 0: + bmp = wx.EmptyBitmap(16,16) + self.ClearBmp(bmp) + elif input > 35: + bmp = GetSmilesBitmap() + else: + bmp = wx.ArtProvider_GetBitmap(eval(ArtIDs[input+1]), wx.ART_OTHER, (16,16)) + if not bmp.Ok(): + bmp = wx.EmptyBitmap(16,16) + self.ClearBmp(bmp) + + self.bitmaps[count].SetBitmap(bmp) + + + def ClearBmp(self, bmp): + + dc = wx.MemoryDC() + dc.SelectObject(bmp) + dc.SetBackground(wx.Brush("white")) + dc.Clear() + + +#--------------------------------------------------------------------------- +# Custom Renderer for the column headers +#--------------------------------------------------------------------------- +class HyperTreeHeaderRenderer(object): + """ + Draws the column headers as a solid color (self.color) + """ + + def __init__(self, parent): + self.color = wx.Colour(150,150,150) + + def DrawTextFormatted(self, dc, text, rect): + """ + Draws the item text, correctly formatted. + + :param `dc`: an instance of `wx.DC`; + :param `text`: the item text; + :param `rect`: the item client rectangle. + """ + + # determine if the string can fit inside the current width + w, h, dummy = dc.GetMultiLineTextExtent(text) + width = rect.width + + if w <= width: + + dc.DrawLabel(text, rect, wx.ALIGN_CENTER_VERTICAL) + + else: + + # determine the base width + ellipsis = "..." + base_w, h = dc.GetTextExtent(ellipsis) + + # continue until we have enough space or only one character left + + newText = text.split("\n") + theText = "" + + for text in newText: + + lenText = len(text) + drawntext = text + w, dummy = dc.GetTextExtent(text) + + while lenText > 1: + + if w + base_w <= width: + break + + w_c, h_c = dc.GetTextExtent(drawntext[-1]) + drawntext = drawntext[0:-1] + lenText -= 1 + w -= w_c + + # if still not enough space, remove ellipsis characters + while len(ellipsis) > 0 and w + base_w > width: + ellipsis = ellipsis[0:-1] + base_w, h = dc.GetTextExtent(ellipsis) + + theText += drawntext + ellipsis + "\n" + + theText = theText.rstrip() + dc.DrawLabel(theText, rect, wx.ALIGN_CENTER_VERTICAL) + + + + def DrawHeaderButton(self, dc, rect, flags=0, params=None): + + if params != None: + text_align = params.m_labelAlignment + bitmap = params.m_labelBitmap + text_color = params.m_labelColour + text_font = params.m_labelFont + text = params.m_labelText + + color = self.color + + if flags & wx.CONTROL_DISABLED: + color = wx.Colour(wx.WHITE) + elif flags & wx.CONTROL_SELECTED: + color = wx.Colour(wx.BLUE) + if flags & wx.CONTROL_PRESSED: + self._pressed = True + color = cutils.AdjustColour(color,-30) + elif flags & wx.CONTROL_CURRENT: + self._hover = True + color = cutils.AdjustColour(color,50) + + # Draw a solid background in self.color + dc.SetBrush(wx.Brush(color, wx.SOLID)) + dc.SetBackgroundMode(wx.SOLID) + dc.SetPen(wx.TRANSPARENT_PEN) + dc.DrawRectangleRect(rect) + + # Draw the column divider on the right + x = rect.width + rect.x - 2 + dc.SetPen(wx.Pen(cutils.AdjustColour(color,-30))) + dc.DrawLine(x,2,x,rect.height-2) + x += 1 + dc.SetPen(wx.Pen(cutils.AdjustColour(color,30))) + dc.DrawLine(x,2,x,rect.height-2) + + dc.SetBackgroundMode(wx.TRANSPARENT) + + if params == None: + return + + # We need to draw the text and/or icon bitmap + dc.SetFont(text_font) + dc.SetTextForeground(text_color) + + # Determine the width of the text + wLabel, hLabel, dummy = dc.GetMultiLineTextExtent(text) + wLabel += 4 # 2 pixel margin either side + + # and the width of the icon, if any + if bitmap: + wLabel += bitmap.GetWidth() + 2 # 2 is a margin between the image and text + + # ALIGN_LEFT if the label is larger than the available space + text_align = (wLabel < rect.width and [text_align] or [wx.ALIGN_LEFT])[0] + + x = rect.x + 2 + + if text_align == wx.ALIGN_LEFT: + xAligned = x + + elif text_align == wx.ALIGN_RIGHT: + xAligned = x + rect.width - wLabel - 1 + + elif text_align == wx.ALIGN_CENTER: + xAligned = x + (rect.width - wLabel)/2 + + if bitmap: + dc.DrawBitmap(bitmap, xAligned + wLabel - bitmap.GetWidth() , 2, True) + + dc.SetClippingRegion(x, 1, rect.width-2, rect.height - 2) + self.DrawTextFormatted(dc, text, wx.Rect(xAligned+2, 1, rect.width-2, rect.height-2)) + dc.DestroyClippingRegion() + + + + +#--------------------------------------------------------------------------- +# HyperTreeList Demo Implementation +#--------------------------------------------------------------------------- +class HyperTreeListDemo(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent) + + self.SetMinSize((640, 480)) + self.SetIcon(images.Mondrian.GetIcon()) + self.SetTitle("HyperTreeList wxPython Demo ;-)") + + self.CenterOnParent() + + statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + statusbar.SetStatusWidths([-2, -1]) + # statusbar fields + statusbar_fields = [("HyperTreeList Demo, Andrea Gavana @ 08 May 2007"), + ("Welcome To wxPython!")] + + for i in range(len(statusbar_fields)): + statusbar.SetStatusText(statusbar_fields[i], i) + + self.CreateMenuBar() + + self.oldicons = 0 + + splitter = wx.SplitterWindow(self, -1, style=wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D) + panel = wx.Panel(splitter, -1, style=wx.WANTS_CHARS) + + # Set up a log window + self.log = log + + sizer = wx.BoxSizer(wx.VERTICAL) + # Create the HyperTreeList + self.tree = HyperTreeList(panel, -1, log=self.log) + + sizer.Add(self.tree, 1, wx.EXPAND) + panel.SetSizer(sizer) + sizer.Layout() + + self.leftpanel = wx.ScrolledWindow(splitter, -1, style=wx.SUNKEN_BORDER) + self.PopulateLeftPanel(self.tree.styles, self.tree.events) + + splitter.SplitVertically(self.leftpanel, panel, 300) + + splitter.SetMinimumPaneSize(120) + self.leftpanel.SetBackgroundColour(wx.WHITE) + self.leftpanel.SetScrollRate(20, 20) + + + def CreateMenuBar(self): + + file_menu = wx.Menu() + + AS_EXIT = wx.NewId() + file_menu.Append(AS_EXIT, "&Exit") + self.Bind(wx.EVT_MENU, self.OnClose, id=AS_EXIT) + + help_menu = wx.Menu() + + AS_ABOUT = wx.NewId() + help_menu.Append(AS_ABOUT, "&About...") + self.Bind(wx.EVT_MENU, self.OnAbout, id=AS_ABOUT) + + menu_bar = wx.MenuBar() + + menu_bar.Append(file_menu, "&File") + menu_bar.Append(help_menu, "&Help") + + self.SetMenuBar(menu_bar) + + + def OnClose(self, event): + + self.Destroy() + + + def OnAbout(self, event): + + msg = "This Is The About Dialog Of The HyperTreeList Demo.\n\n" + \ + "Author: Andrea Gavana @ 08 May 2007\n\n" + \ + "Please Report Any Bug/Requests Of Improvements\n" + \ + "To Me At The Following Adresses:\n\n" + \ + "andrea.gavana@maerskoil.com\n" + "andrea.gavana@gmail.com\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "HyperTreeList Demo", + wx.OK | wx.ICON_INFORMATION) + + if wx.Platform != '__WXMAC__': + dlg.SetFont(wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, False)) + + dlg.ShowModal() + dlg.Destroy() + + + def PopulateLeftPanel(self, styles, events): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + recreatetree = wx.Button(self.leftpanel, -1, "Recreate HyperTreeList") + mainsizer.Add(recreatetree, 0, wx.ALL|wx.ALIGN_CENTER, 10) + recreatetree.Bind(wx.EVT_BUTTON, self.OnRecreateTree) + + staticboxstyles = wx.StaticBox(self.leftpanel, -1, "HyperTreeList Styles") + stylesizer = wx.StaticBoxSizer(staticboxstyles, wx.VERTICAL) + staticboxcolumns = wx.StaticBox(self.leftpanel, -1, "HyperTreeList Columns") + columnssizer = wx.StaticBoxSizer(staticboxcolumns, wx.VERTICAL) + staticboxevents = wx.StaticBox(self.leftpanel, -1, "HyperTreeList Events") + eventssizer = wx.StaticBoxSizer(staticboxevents, wx.VERTICAL) + staticboxcolours = wx.StaticBox(self.leftpanel, -1, "HyperTreeList Images/Colours") + colourssizer = wx.StaticBoxSizer(staticboxcolours, wx.VERTICAL) + staticboxthemes = wx.StaticBox(self.leftpanel, -1, "HyperTreeList Themes/Gradients") + themessizer = wx.StaticBoxSizer(staticboxthemes, wx.VERTICAL) + + self.treestyles = [] + self.treeevents = [] + + for count, style in enumerate(styles): + + if count == 0: + tags = wx.ALL + else: + tags = wx.LEFT|wx.RIGHT|wx.BOTTOM + + if style != "TR_DEFAULT_STYLE": + check = wx.CheckBox(self.leftpanel, -1, style) + stylesizer.Add(check, 0, tags, 3) + + if style in ["TR_HAS_BUTTONS", "TR_HAS_VARIABLE_ROW_HEIGHT"]: + check.SetValue(1) + + if style == "TR_HAS_VARIABLE_ROW_HEIGHT": + check.Enable(False) + + check.Bind(wx.EVT_CHECKBOX, self.OnCheckStyle) + self.treestyles.append(check) + + flexgridcolumn = wx.FlexGridSizer(cols=2, hgap=5, vgap=5) + flexgridcolumn.AddGrowableCol(0) + label = wx.StaticText(self.leftpanel, -1, "Text Font") + label.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + self.buttonfont = wx.Button(self.leftpanel, -1, "Choose...") + self.buttonfont.Bind(wx.EVT_BUTTON, self.OnColumnFont) + flexgridcolumn.Add(label, 0, wx.ALIGN_CENTER_VERTICAL) + flexgridcolumn.Add(self.buttonfont, 0) + + label = wx.StaticText(self.leftpanel, -1, "Text Colour") + label.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + self.columncolour = csel.ColourSelect(self.leftpanel, -1, "Choose...", wx.BLACK) + self.columncolour.Bind(csel.EVT_COLOURSELECT, self.OnColumnColour) + flexgridcolumn.Add(label, 0, wx.ALIGN_CENTER_VERTICAL) + flexgridcolumn.Add(self.columncolour, 0) + + label = wx.StaticText(self.leftpanel, -1, "Alignment") + label.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + alignment = wx.Choice(self.leftpanel, -1, choices=["wx.LEFT", "wx.CENTER", "wx.RIGHT"]) + alignment.Bind(wx.EVT_CHOICE, self.OnColumnAlignment) + flexgridcolumn.Add(label, 0, wx.ALIGN_CENTER_VERTICAL) + flexgridcolumn.Add(alignment, 0) + + label = wx.StaticText(self.leftpanel, -1, "Width Options") + label.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + widthoptions = wx.Choice(self.leftpanel, -1, choices=["USEHEADER", "AUTOSIZE"]) + widthoptions.Bind(wx.EVT_CHOICE, self.OnColumnWidth) + flexgridcolumn.Add(label, 0, wx.ALIGN_CENTER_VERTICAL) + flexgridcolumn.Add(widthoptions, 0) + + columnimages = wx.CheckBox(self.leftpanel, -1, "Images On Columns", style=wx.ALIGN_RIGHT) + columnimages.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + columnimages.Bind(wx.EVT_CHECKBOX, self.OnColumnImages) + flexgridcolumn.Add(columnimages, 0, wx.ALIGN_CENTER_VERTICAL) + flexgridcolumn.Add((20,20), 0) + + columnimages = wx.CheckBox(self.leftpanel, -1, "Custom Renderer", style=wx.ALIGN_RIGHT) + columnimages.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + columnimages.Bind(wx.EVT_CHECKBOX, self.OnCustomRenderer) + flexgridcolumn.Add(columnimages, 0, wx.ALIGN_CENTER_VERTICAL) + flexgridcolumn.Add((20,20), 0) + + columnssizer.Add(flexgridcolumn, 1, wx.EXPAND) + + for count, event in enumerate(events): + + if count == 0: + tags = wx.ALL + else: + tags = wx.LEFT|wx.RIGHT|wx.BOTTOM + + if count not in [6, 17, 22, 23]: + check = wx.CheckBox(self.leftpanel, -1, event) + eventssizer.Add(check, 0, tags, 3) + + if event in ["EVT_TREE_ITEM_EXPANDED", "EVT_TREE_ITEM_COLLAPSED", + "EVT_TREE_SEL_CHANGED", "EVT_TREE_SEL_CHANGING"]: + + check.SetValue(1) + + check.Bind(wx.EVT_CHECKBOX, self.OnCheckEvent) + self.treeevents.append(check) + + sizer1 = wx.BoxSizer(wx.HORIZONTAL) + label = wx.StaticText(self.leftpanel, -1, "Connection Pen") + font = label.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + label.SetFont(font) + buttonconnection = wx.Button(self.leftpanel, -1, "Choose...") + buttonconnection.Bind(wx.EVT_BUTTON, self.OnButtonConnection) + sizer1.Add(label, 0, wx.ALL|wx.ALIGN_CENTER, 5) + sizer1.Add((1,0), 1, wx.EXPAND) + sizer1.Add(buttonconnection, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5) + + sizer2 = wx.BoxSizer(wx.HORIZONTAL) + label = wx.StaticText(self.leftpanel, -1, "Border Pen") + font = label.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + label.SetFont(font) + buttonborder = wx.Button(self.leftpanel, -1, "Choose...") + buttonborder.Bind(wx.EVT_BUTTON, self.OnButtonBorder) + sizer2.Add(label, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5) + sizer2.Add((1,0), 1, wx.EXPAND) + sizer2.Add(buttonborder, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5) + + sizer3 = wx.BoxSizer(wx.HORIZONTAL) + label = wx.StaticText(self.leftpanel, -1, "Tree Buttons") + font = label.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + label.SetFont(font) + buttontree = wx.Button(self.leftpanel, -1, "Choose...") + buttontree.Bind(wx.EVT_BUTTON, self.OnButtonTree) + sizer3.Add(label, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5) + sizer3.Add((1,0), 1, wx.EXPAND) + sizer3.Add(buttontree, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5) + + sizer4 = wx.BoxSizer(wx.HORIZONTAL) + label = wx.StaticText(self.leftpanel, -1, "Check/Radio Buttons") + font = label.GetFont() + font.SetWeight(wx.FONTWEIGHT_BOLD) + label.SetFont(font) + buttoncr = wx.Button(self.leftpanel, -1, "Choose...") + buttoncr.Bind(wx.EVT_BUTTON, self.OnButtonCheckRadio) + sizer4.Add(label, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5) + sizer4.Add((1,0), 1, wx.EXPAND) + sizer4.Add(buttoncr, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5) + + sizer5 = wx.BoxSizer(wx.HORIZONTAL) + radioimage = wx.RadioButton(self.leftpanel, -1, "Image Background", style=wx.RB_GROUP) + radioimage.Bind(wx.EVT_RADIOBUTTON, self.OnBackgroundImage) + self.imagebutton = wx.Button(self.leftpanel, -1, "Choose...") + self.imagebutton.Bind(wx.EVT_BUTTON, self.OnChooseImage) + sizer5.Add(radioimage, 0, wx.ALL|wx.ALIGN_CENTER, 5) + sizer5.Add((1,0), 1, wx.EXPAND) + sizer5.Add(self.imagebutton, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_RIGHT, 5) + + sizer6 = wx.BoxSizer(wx.HORIZONTAL) + radiobackground = wx.RadioButton(self.leftpanel, -1, "Background Colour") + radiobackground.Bind(wx.EVT_RADIOBUTTON, self.OnBackgroundColour) + self.backbutton = csel.ColourSelect(self.leftpanel, -1, "Choose...", wx.WHITE) + self.backbutton.Bind(csel.EVT_COLOURSELECT, self.OnChooseBackground) + sizer6.Add(radiobackground, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5) + sizer6.Add((1,0), 1, wx.EXPAND) + sizer6.Add(self.backbutton, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER, 5) + + colourssizer.Add(sizer1, 0, wx.EXPAND) + colourssizer.Add(sizer2, 0, wx.EXPAND) + colourssizer.Add(sizer3, 0, wx.EXPAND) + colourssizer.Add(sizer4, 0, wx.EXPAND) + colourssizer.Add(sizer5, 0, wx.EXPAND) + colourssizer.Add(sizer6, 0, wx.EXPAND) + + sizera = wx.BoxSizer(wx.HORIZONTAL) + self.checknormal = wx.CheckBox(self.leftpanel, -1, "Standard Colours") + self.focus = csel.ColourSelect(self.leftpanel, -1, "Focus", + self.tree.GetHilightFocusColour()) + self.unfocus = csel.ColourSelect(self.leftpanel, -1, "Non-Focus", + self.tree.GetHilightNonFocusColour()) + self.checknormal.Bind(wx.EVT_CHECKBOX, self.OnCheckNormal) + self.focus.Bind(csel.EVT_COLOURSELECT, self.OnFocusColour) + self.unfocus.Bind(csel.EVT_COLOURSELECT, self.OnNonFocusColour) + sizera1 = wx.BoxSizer(wx.VERTICAL) + sizera1.Add(self.focus, 0, wx.BOTTOM, 2) + sizera1.Add(self.unfocus, 0) + sizera.Add(self.checknormal, 0, wx.ALL, 3) + sizera.Add((1, 0), 1, wx.EXPAND) + sizera.Add(sizera1, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.EXPAND, 3) + + sizerb = wx.BoxSizer(wx.VERTICAL) + self.checkgradient = wx.CheckBox(self.leftpanel, -1, "Gradient Theme") + self.checkgradient.Bind(wx.EVT_CHECKBOX, self.OnCheckGradient) + sizerb1 = wx.BoxSizer(wx.HORIZONTAL) + sizerb1.Add((10, 0)) + self.radiohorizontal = wx.RadioButton(self.leftpanel, -1, "Horizontal", style=wx.RB_GROUP) + self.radiohorizontal.Bind(wx.EVT_RADIOBUTTON, self.OnHorizontal) + sizerb1.Add(self.radiohorizontal, 0, wx.TOP|wx.BOTTOM, 3) + sizerb2 = wx.BoxSizer(wx.HORIZONTAL) + sizerb2.Add((10, 0)) + self.radiovertical = wx.RadioButton(self.leftpanel, -1, "Vertical") + self.radiovertical.Bind(wx.EVT_RADIOBUTTON, self.OnVertical) + sizerb2.Add(self.radiovertical, 0, wx.BOTTOM, 3) + sizerb3 = wx.BoxSizer(wx.HORIZONTAL) + self.firstcolour = csel.ColourSelect(self.leftpanel, -1, "First Colour", + self.tree.GetFirstGradientColour()) + self.secondcolour = csel.ColourSelect(self.leftpanel, -1, "Second Colour", + self.tree.GetSecondGradientColour()) + self.firstcolour.Bind(csel.EVT_COLOURSELECT, self.OnFirstColour) + self.secondcolour.Bind(csel.EVT_COLOURSELECT, self.OnSecondColour) + sizerb3.Add(self.firstcolour, 0, wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, 3) + sizerb3.Add(self.secondcolour, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, 3) + sizerb.Add(self.checkgradient, 0, wx.ALL, 3) + sizerb.Add(sizerb1, 0) + sizerb.Add(sizerb2, 0) + sizerb.Add(sizerb3, 0, wx.ALIGN_CENTER) + + self.checkvista = wx.CheckBox(self.leftpanel, -1, "Windows Vista Theme") + self.checkvista.Bind(wx.EVT_CHECKBOX, self.OnVista) + + themessizer.Add(sizera, 0, wx.EXPAND) + themessizer.Add(sizerb, 0, wx.EXPAND) + themessizer.Add((0, 5)) + themessizer.Add(self.checkvista, 0, wx.EXPAND|wx.ALL, 3) + + mainsizer.Add(stylesizer, 0, wx.EXPAND|wx.ALL, 5) + mainsizer.Add(columnssizer, 0, wx.EXPAND|wx.ALL, 5) + mainsizer.Add(colourssizer, 0, wx.EXPAND|wx.ALL, 5) + mainsizer.Add(themessizer, 0, wx.EXPAND|wx.ALL, 5) + mainsizer.Add(eventssizer, 0, wx.EXPAND|wx.ALL, 5) + + self.leftpanel.SetSizer(mainsizer) + mainsizer.Layout() + + radiobackground.SetValue(1) + self.checknormal.SetValue(1) + self.radiohorizontal.Enable(False) + self.radiovertical.Enable(False) + self.firstcolour.Enable(False) + self.secondcolour.Enable(False) + self.imagebutton.Enable(False) + + + def OnRecreateTree(self, event): + + panelparent = self.tree.GetParent() + panelsizer = panelparent.GetSizer() + panelparent.Freeze() + + panelsizer.Detach(self.tree) + self.tree.Destroy() + del self.tree + self.tree = HyperTreeList(panelparent, -1, log=self.log) + panelsizer.Add(self.tree, 1, wx.EXPAND) + panelsizer.Layout() + + panelparent.Thaw() + + + def OnCheckStyle(self, event): + + self.tree.ChangeStyle(self.treestyles) + event.Skip() + + + def OnCheckEvent(self, event): + + obj = event.GetEventObject() + self.tree.BindEvents(obj) + + event.Skip() + + + def OnButtonConnection(self, event): + + pen = self.tree.GetConnectionPen() + dlg = PenDialog(self, -1, oldpen=pen, pentype=0) + + dlg.ShowModal() + + event.Skip() + + + def OnColumnFont(self, event): + + font = self.tree.GetColumn(0).GetFont() + + data = wx.FontData() + data.SetInitialFont(font) + dlg = wx.FontDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetFontData() + font = data.GetChosenFont() + for i in xrange(0, self.tree.GetMainWindow().GetColumnCount()): + self.tree.SetColumnFont(i, font) + + dlg.Destroy() + event.Skip() + + + def OnColumnColour(self, event): + + col1 = event.GetValue() + for i in xrange(0, self.tree.GetMainWindow().GetColumnCount()): + self.tree.SetColumnColour(i, col1) + + event.Skip() + + + def OnColumnAlignment(self, event): + + selection = event.GetSelection() + if selection == 0: + alignment = wx.ALIGN_LEFT + elif selection == 1: + alignment = wx.ALIGN_CENTER + else: + alignment = wx.ALIGN_RIGHT + + for i in xrange(1, self.tree.GetMainWindow().GetColumnCount()): + self.tree.SetColumnAlignment(i, alignment) + + event.Skip() + + + def OnColumnImages(self, event): + + for i in xrange(self.tree.GetMainWindow().GetColumnCount()): + randimage = random.randint(1, len(ArtIDs)) + img = (event.IsChecked() and [randimage] or [-1])[0] + self.tree.SetColumnImage(i, img) + + event.Skip() + + def OnCustomRenderer(self, event): + + if event.IsChecked(): + renderer = HyperTreeHeaderRenderer(self) + renderer.color = wx.Colour(211,227,247) + renderer.text_color = wx.Colour(30,30,30) + self.tree.SetHeaderCustomRenderer(renderer) + else: + renderer = None + self.tree.SetHeaderCustomRenderer(renderer) + + self.Refresh() + + event.Skip() + + + + def OnColumnWidth(self, event): + + selection = event.GetSelection() + if selection == 0: # wx.LIST_AUTOSIZE_USEHEADER + choice = wx.LIST_AUTOSIZE_USEHEADER + else: + choice = wx.LIST_AUTOSIZE + + for i in xrange(self.tree.GetMainWindow().GetColumnCount()): + self.tree.SetColumnWidth(i, choice) + + event.Skip() + + + def SetConnectionPen(self, pen): + + self.tree.SetConnectionPen(pen) + + + def OnButtonBorder(self, event): + + pen = self.tree.GetBorderPen() + dlg = PenDialog(self, -1, oldpen=pen, pentype=1) + + dlg.ShowModal() + event.Skip() + + + def SetBorderPen(self, pen): + + self.tree.SetBorderPen(pen) + + + def OnButtonTree(self, event): + + dlg = TreeDialog(self, -1, oldicons=self.oldicons) + dlg.ShowModal() + + event.Skip() + + + def OnButtonCheckRadio(self, event): + + dlg = CheckDialog(self, -1) + dlg.ShowModal() + + event.Skip() + + + def SetTreeButtons(self, selection): + + bitmap_plus = opj(bitmapDir + "plus" + str(selection+1) + ".ico") + bitmap_minus = opj(bitmapDir + "minus" + str(selection+1) + ".ico") + + bitmap = wx.Bitmap(bitmap_plus, wx.BITMAP_TYPE_ICO) + width = bitmap.GetWidth() + + il = wx.ImageList(width, width) + + il.Add(wx.Bitmap(bitmap_plus, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_plus, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_minus, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_minus, wx.BITMAP_TYPE_ICO)) + + self.il = il + self.tree.SetButtonsImageList(il) + + + def SetCheckRadio(self, selection): + + if selection == 0: + self.tree.SetImageListCheck(13, 13) + else: + bitmap_check = opj(bitmapDir + "aquachecked.ico") + bitmap_uncheck = opj(bitmapDir + "aquanotchecked.ico") + bitmap_flag = opj(bitmapDir + "aquaflagged.ico") + bitmap_unflag = opj(bitmapDir + "aquanotflagged.ico") + + il = wx.ImageList(16, 16) + + il.Add(wx.Bitmap(bitmap_check, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_uncheck, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_flag, wx.BITMAP_TYPE_ICO)) + il.Add(wx.Bitmap(bitmap_unflag, wx.BITMAP_TYPE_ICO)) + self.tree.SetImageListCheck(16, 16, il) + + + def OnBackgroundImage(self, event): + + if hasattr(self, "backgroundimage"): + self.tree.SetBackgroundImage(self.backgroundimage) + + self.backbutton.Enable(False) + self.imagebutton.Enable(True) + + event.Skip() + + + def OnChooseImage(self, event): + + wildcard = "JPEG Files (*.jpg)|*.jpg|" \ + "Bitmap Files (*.bmp)|*.bmp|" \ + "PNG Files (*.png)|*.png|" \ + "Icon Files (*.ico)|*.ico|" \ + "GIF Files (*.gif)|*.gif|" \ + "All files (*.*)|*.*" + + dlg = wx.FileDialog(self, "Choose An Image File", ".", "", wildcard, wx.OPEN) + + if dlg.ShowModal() == wx.ID_OK: + path = dlg.GetPath() + else: + dlg.Destroy() + return + + dlg.Destroy() + bitmap = wx.Bitmap(path, wx.BITMAP_TYPE_ANY) + self.tree.SetBackgroundImage(bitmap) + self.backgroundimage = bitmap + + event.Skip() + + + def OnBackgroundColour(self, event): + + self.imagebutton.Enable(False) + self.backbutton.Enable(True) + self.tree.SetBackgroundImage(None) + + event.Skip() + + + def OnChooseBackground(self, event): + + col1 = event.GetValue() + self.tree.SetBackgroundColour(col1) + event.Skip() + + + def OnCheckNormal(self, event): + + self.radiohorizontal.Enable(False) + self.radiovertical.Enable(False) + self.firstcolour.Enable(False) + self.secondcolour.Enable(False) + self.focus.Enable(True) + self.unfocus.Enable(True) + self.checkgradient.SetValue(0) + self.checkvista.SetValue(0) + self.tree.EnableSelectionGradient(False) + self.tree.EnableSelectionVista(False) + event.Skip() + + + def OnFocusColour(self, event): + + col1 = event.GetValue() + self.tree.SetHilightFocusColour(col1) + event.Skip() + + + def OnNonFocusColour(self, event): + + col1 = event.GetValue() + self.tree.SetHilightNonFocusColour(col1) + event.Skip() + + + def OnCheckGradient(self, event): + + self.radiohorizontal.Enable(True) + self.radiovertical.Enable(True) + self.firstcolour.Enable(True) + self.secondcolour.Enable(True) + self.checknormal.SetValue(0) + self.checkvista.SetValue(0) + self.focus.Enable(False) + self.unfocus.Enable(False) + self.tree.SetGradientStyle(self.radiovertical.GetValue()) + self.tree.EnableSelectionVista(False) + self.tree.EnableSelectionGradient(True) + + event.Skip() + + + def OnHorizontal(self, event): + + self.tree.SetGradientStyle(self.radiovertical.GetValue()) + event.Skip() + + + def OnVertical(self, event): + + self.tree.SetGradientStyle(self.radiovertical.GetValue()) + event.Skip() + + + def OnFirstColour(self, event): + + col1 = event.GetValue() + self.tree.SetFirstGradientColour(wx.Colour(col1[0], col1[1], col1[2])) + event.Skip() + + + def OnSecondColour(self, event): + + col1 = event.GetValue() + self.tree.SetSecondGradientColour(wx.Colour(col1[0], col1[1], col1[2])) + event.Skip() + + + def OnVista(self, event): + + self.radiohorizontal.Enable(False) + self.radiovertical.Enable(False) + self.firstcolour.Enable(False) + self.secondcolour.Enable(False) + self.checknormal.SetValue(0) + self.checkgradient.SetValue(0) + self.focus.Enable(False) + self.unfocus.Enable(False) + self.tree.EnableSelectionGradient(False) + self.tree.EnableSelectionVista(True) + + event.Skip() + + +#--------------------------------------------------------------------------- +# HyperTreeList Implementation +#--------------------------------------------------------------------------- +class HyperTreeList(HTL.HyperTreeList): + + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, + size=wx.DefaultSize, + style=wx.SUNKEN_BORDER, + agwStyle=wx.TR_HAS_BUTTONS | wx.TR_HAS_VARIABLE_ROW_HEIGHT, + log=None): + + HTL.HyperTreeList.__init__(self, parent, id, pos, size, style, agwStyle) + + alldata = dir(HTL) + + treestyles = [] + events = [] + for data in alldata: + if data.startswith("TR_"): + treestyles.append(data) + elif data.startswith("EVT_"): + events.append(data) + + events = events + [i for i in dir(wx) if i.startswith("EVT_TREE_")] + for evt in ["EVT_TREE_GET_INFO", "EVT_TREE_SET_INFO", "EVT_TREE_ITEM_MIDDLE_CLICK", + "EVT_TREE_STATE_IMAGE_CLICK"]: + events.remove(evt) + + treestyles = treestyles + [i for i in dir(wx) if i.startswith("TR_")] + treeset = {} + treestyles = [treeset.setdefault(e,e) for e in treestyles if e not in treeset] + + treestyles.sort() + + self.events = events + self.styles = treestyles + self.item = None + + il = wx.ImageList(16, 16) + + for items in ArtIDs[1:-1]: + bmp = wx.ArtProvider_GetBitmap(eval(items), wx.ART_TOOLBAR, (16, 16)) + il.Add(bmp) + + smileidx = il.Add(images.Smiles.GetBitmap()) + numicons = il.GetImageCount() + + self.AssignImageList(il) + self.count = 0 + self.log = log + + # NOTE: For some reason tree items have to have a data object in + # order to be sorted. Since our compare just uses the labels + # we don't need any real data, so we'll just use None below for + # the item data. + + # create some columns + self.AddColumn("Main column") + self.AddColumn("Column 1") + self.AddColumn("Column 2") + self.SetMainColumn(0) # the one with the tree in it... + self.SetColumnWidth(0, 175) + + self.root = self.AddRoot("The Root Item") + + if not(self.GetAGWWindowStyleFlag() & wx.TR_HIDE_ROOT): + self.SetPyData(self.root, None) + self.SetItemImage(self.root, 24, which=wx.TreeItemIcon_Normal) + self.SetItemImage(self.root, 13, which=wx.TreeItemIcon_Expanded) + self.SetItemText(self.root, "col 1 root", 1) + self.SetItemText(self.root, "col 2 root", 2) + + textctrl = wx.TextCtrl(self.GetMainWindow(), -1, "I Am A Simple\nMultiline wx.TexCtrl", style=wx.TE_MULTILINE) + self.gauge = wx.Gauge(self.GetMainWindow(), -1, 50, style=wx.GA_HORIZONTAL|wx.GA_SMOOTH) + self.gauge.SetValue(0) + combobox = wx.ComboBox(self.GetMainWindow(), -1, choices=["That", "Was", "A", "Nice", "Holiday!"], style=wx.CB_READONLY|wx.CB_DROPDOWN) + button1 = wx.Button(self.GetMainWindow(), -1, "wxPython") + button1.SetSize(button1.GetBestSize()) + button2 = wx.Button(self.GetMainWindow(), -1, "Rules!") + button2.SetSize(button2.GetBestSize()) + listctrl = ListCtrl.TestListCtrlPanel(self.GetMainWindow(), self.log) + listctrl.SetSize((500, 200)) + + textctrl.Bind(wx.EVT_CHAR, self.OnTextCtrl) + combobox.Bind(wx.EVT_COMBOBOX, self.OnComboBox) + + for x in range(15): + txt = "Item %d" % x + if x == 1: + child = self.AppendItem(self.root, txt + "\nHello World\nHappy wxPython-ing!") + self.SetItemBold(child, True) + else: + child = self.AppendItem(self.root, txt) + + self.SetPyData(child, None) + self.SetItemText(child, txt + " (c1)", 1) + self.SetItemText(child, txt + " (c2)", 2) + self.SetItemImage(child, 24, which=wx.TreeItemIcon_Normal) + self.SetItemImage(child, 13, which=wx.TreeItemIcon_Expanded) + + for y in range(5): + txt = "item %d-%s" % (x, chr(ord("a")+y)) + if y == 0 and x == 1: + last = self.AppendItem(child, txt, ct_type=2, wnd=self.gauge) + elif y == 1 and x == 2: + last = self.AppendItem(child, txt, ct_type=1, wnd=textctrl) + if random.randint(0, 3) == 1: + self.SetItem3State(last, True) + elif 2 < y < 4: + last = self.AppendItem(child, txt) + elif y == 4 and x == 1: + last = self.AppendItem(child, txt, wnd=combobox) + else: + last = self.AppendItem(child, txt, ct_type=2) + + self.SetPyData(last, None) + self.SetItemText(last, txt + " (c1)", 1) + self.SetItemText(last, txt + " (c2)", 2) + self.SetItemImage(last, 24, which=wx.TreeItemIcon_Normal) + self.SetItemImage(last, 13, which=wx.TreeItemIcon_Expanded) + + if y == 3 and x == 0: + self.SetItemWindow(last, button1, 1) + self.SetItemWindow(last, button2, 2) + + for z in range(5): + txt = "item %d-%s-%d" % (x, chr(ord("a")+y), z) + if z > 2: + item = self.AppendItem(last, txt, ct_type=1) + if random.randint(0, 3) == 1: + self.SetItem3State(item, True) + elif 0 < z <= 2: + item = self.AppendItem(last, txt, ct_type=2) + elif z == 0: + item = self.AppendItem(last, txt) + + self.SetPyData(item, None) + + if x == 0 and y == 0 and z == 0: + self.SetItemText(item, "", 1) + self.SetItemText(item, txt + " (c2)", 2) + self.SetItemWindow(item, self.CreateTreeCtrl(), 1) + elif x == 0 and y == 0 and z == 1: + self.SetItemText(item, txt + " (c1)", 1) + self.SetItemText(item, "", 2) + self.SetItemWindow(item, listctrl, 2) + else: + self.SetItemText(item, txt + " (c1)", 1) + self.SetItemText(item, txt + " (c2)", 2) + if z == 0: + self.SetItemHyperText(item, True) + + self.SetItemImage(item, 28, which=wx.TreeItemIcon_Normal) + self.SetItemImage(item, numicons-1, which=wx.TreeItemIcon_Selected) + + self.GetMainWindow().Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick) + self.Bind(wx.EVT_IDLE, self.OnIdle) + + self.eventdict = {'EVT_TREE_BEGIN_DRAG': self.OnBeginDrag, 'EVT_TREE_BEGIN_LABEL_EDIT': self.OnBeginEdit, + 'EVT_TREE_BEGIN_RDRAG': self.OnBeginRDrag, 'EVT_TREE_DELETE_ITEM': self.OnDeleteItem, + 'EVT_TREE_END_DRAG': self.OnEndDrag, 'EVT_TREE_END_LABEL_EDIT': self.OnEndEdit, + 'EVT_TREE_ITEM_ACTIVATED': self.OnActivate, 'EVT_TREE_ITEM_CHECKED': self.OnItemCheck, + 'EVT_TREE_ITEM_CHECKING': self.OnItemChecking, 'EVT_TREE_ITEM_COLLAPSED': self.OnItemCollapsed, + 'EVT_TREE_ITEM_COLLAPSING': self.OnItemCollapsing, 'EVT_TREE_ITEM_EXPANDED': self.OnItemExpanded, + 'EVT_TREE_ITEM_EXPANDING': self.OnItemExpanding, 'EVT_TREE_ITEM_GETTOOLTIP': self.OnToolTip, + 'EVT_TREE_ITEM_MENU': self.OnItemMenu, 'EVT_TREE_ITEM_RIGHT_CLICK': self.OnRightDown, + 'EVT_TREE_KEY_DOWN': self.OnKey, 'EVT_TREE_SEL_CHANGED': self.OnSelChanged, + 'EVT_TREE_SEL_CHANGING': self.OnSelChanging, "EVT_TREE_ITEM_HYPERLINK": self.OnHyperLink} + + mainframe = wx.GetTopLevelParent(self) + + if not hasattr(mainframe, "leftpanel"): + self.Bind(wx.EVT_TREE_ITEM_EXPANDED, self.OnItemExpanded) + self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed) + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged) + self.Bind(wx.EVT_TREE_SEL_CHANGING, self.OnSelChanging) + self.GetMainWindow().Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) + self.GetMainWindow().Bind(wx.EVT_RIGHT_UP, self.OnRightUp) + else: + for combos in mainframe.treeevents: + self.BindEvents(combos) + + if hasattr(mainframe, "leftpanel"): + self.ChangeStyle(mainframe.treestyles) + + if not(self.GetAGWWindowStyleFlag() & wx.TR_HIDE_ROOT): + self.SelectItem(self.root) + self.Expand(self.root) + + + def CreateTreeCtrl(self): + + tree = wx.TreeCtrl(self.GetMainWindow(), -1, wx.Point(0, 0), wx.Size(160, 200), + wx.TR_DEFAULT_STYLE) + + items = [] + + imglist = wx.ImageList(16, 16, True, 2) + imglist.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, wx.Size(16,16))) + imglist.Add(wx.ArtProvider_GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16,16))) + tree.AssignImageList(imglist) + + root = tree.AddRoot("HyperTreeList :-D", image=0) + + items.append(tree.AppendItem(root, "Item 1", 0)) + items.append(tree.AppendItem(root, "Item 2", 0)) + items.append(tree.AppendItem(root, "Item 3", 0)) + items.append(tree.AppendItem(root, "Item 4", 0)) + items.append(tree.AppendItem(root, "Item 5", 0)) + + for ii in xrange(len(items)): + + id = items[ii] + tree.AppendItem(id, "Subitem 1", 1) + tree.AppendItem(id, "Subitem 2", 1) + tree.AppendItem(id, "Subitem 3", 1) + tree.AppendItem(id, "Subitem 4", 1) + tree.AppendItem(id, "Subitem 5", 1) + + tree.Expand(root) + tree.Expand(items[1]) + tree.Expand(items[3]) + tree.SelectItem(root) + + return tree + + + def BindEvents(self, choice, recreate=False): + + value = choice.GetValue() + text = choice.GetLabel() + + evt = "wx." + text + binder = self.eventdict[text] + + if value == 1: + if evt == "wx.EVT_TREE_BEGIN_RDRAG": + self.GetMainWindow().Bind(wx.EVT_RIGHT_DOWN, None) + self.GetMainWindow().Bind(wx.EVT_RIGHT_UP, None) + try: + self.Bind(eval(evt), binder) + except: + self.Bind(eval("HTL." + text), binder) + else: + try: + self.Bind(eval(evt), None) + except: + self.Bind(eval("HTL." + text), None) + + if evt == "wx.EVT_TREE_BEGIN_RDRAG": + self.GetMainWindow().Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) + self.GetMainWindow().Bind(wx.EVT_RIGHT_UP, self.OnRightUp) + + + def ChangeStyle(self, combos): + + style = 0 + for combo in combos: + if combo.GetValue() == 1: + if combo.GetLabel() == "TR_VIRTUAL": + style = style | HTL.TR_VIRTUAL + else: + try: + style = style | eval("wx." + combo.GetLabel()) + except: + style = style | eval("HTL." + combo.GetLabel()) + + if self.GetAGWWindowStyleFlag() != style: + self.SetAGWWindowStyleFlag(style) + + + def OnCompareItems(self, item1, item2): + + t1 = self.GetItemText(item1) + t2 = self.GetItemText(item2) + + self.log.write('compare: ' + t1 + ' <> ' + t2 + "\n") + + if t1 < t2: + return -1 + if t1 == t2: + return 0 + + return 1 + + + def OnIdle(self, event): + + if self.gauge: + + try: + if self.gauge.IsEnabled() and self.gauge.IsShown(): + self.count = self.count + 1 + + if self.count >= 50: + self.count = 0 + + self.gauge.SetValue(self.count) + + except: + + self.gauge = None + + event.Skip() + + + def OnRightDown(self, event): + + pt = event.GetPosition() + item, flags, column = self.HitTest(pt) + + if item: + self.item = item + self.log.write("OnRightClick: %s, %s, %s\n" % (self.GetItemText(item), type(item), item.__class__)) + self.SelectItem(item) + + + def OnRightUp(self, event): + + item = self.item + + if not item: + event.Skip() + return + + if not self.IsItemEnabled(item): + event.Skip() + return + + # Item Text Appearance + ishtml = self.IsItemHyperText(item) + back = self.GetItemBackgroundColour(item) + fore = self.GetItemTextColour(item) + isbold = self.IsBold(item) + font = self.GetItemFont(item) + + # Icons On Item + normal = self.GetItemImage(item, wx.TreeItemIcon_Normal) + selected = self.GetItemImage(item, wx.TreeItemIcon_Selected) + expanded = self.GetItemImage(item, wx.TreeItemIcon_Expanded) + selexp = self.GetItemImage(item, wx.TreeItemIcon_SelectedExpanded) + + # Enabling/Disabling Windows Associated To An Item + haswin = self.GetItemWindow(item) + + # Enabling/Disabling Items + enabled = self.IsItemEnabled(item) + + # Generic Item's Info + children = self.GetChildrenCount(item) + itemtype = self.GetItemType(item) + text = self.GetItemText(item) + pydata = self.GetPyData(item) + + self.current = item + self.itemdict = {"ishtml": ishtml, "back": back, "fore": fore, "isbold": isbold, + "font": font, "normal": normal, "selected": selected, "expanded": expanded, + "selexp": selexp, "haswin": haswin, "children": children, + "itemtype": itemtype, "text": text, "pydata": pydata, "enabled": enabled} + + menu = wx.Menu() + + item2 = menu.Append(wx.ID_ANY, "Modify Item Text Colour") + menu.AppendSeparator() + if isbold: + strs = "Make Item Text Not Bold" + else: + strs = "Make Item Text Bold" + item3 = menu.Append(wx.ID_ANY, strs) + item4 = menu.Append(wx.ID_ANY, "Change Item Font") + item13 = menu.Append(wx.ID_ANY, "Change Item Background Colour") + menu.AppendSeparator() + if ishtml: + strs = "Set Item As Non-Hyperlink" + else: + strs = "Set Item As Hyperlink" + item5 = menu.Append(wx.ID_ANY, strs) + menu.AppendSeparator() + + item7 = menu.Append(wx.ID_ANY, "Disable Item") + + menu.AppendSeparator() + item8 = menu.Append(wx.ID_ANY, "Change Item Icons") + menu.AppendSeparator() + item9 = menu.Append(wx.ID_ANY, "Get Other Information For This Item") + menu.AppendSeparator() + + item10 = menu.Append(wx.ID_ANY, "Delete Item") + if item == self.GetRootItem(): + item10.Enable(False) + item11 = menu.Append(wx.ID_ANY, "Prepend An Item") + item12 = menu.Append(wx.ID_ANY, "Append An Item") + + self.Bind(wx.EVT_MENU, self.OnItemForeground, item2) + self.Bind(wx.EVT_MENU, self.OnItemBold, item3) + self.Bind(wx.EVT_MENU, self.OnItemFont, item4) + self.Bind(wx.EVT_MENU, self.OnItemHyperText, item5) + self.Bind(wx.EVT_MENU, self.OnDisableItem, item7) + self.Bind(wx.EVT_MENU, self.OnItemIcons, item8) + self.Bind(wx.EVT_MENU, self.OnItemInfo, item9) + self.Bind(wx.EVT_MENU, self.OnItemDelete, item10) + self.Bind(wx.EVT_MENU, self.OnItemPrepend, item11) + self.Bind(wx.EVT_MENU, self.OnItemAppend, item12) + self.Bind(wx.EVT_MENU, self.OnItemBackground, item13) + + self.PopupMenu(menu) + menu.Destroy() + event.Skip() + + + def OnItemForeground(self, event): + + colourdata = wx.ColourData() + colourdata.SetColour(self.itemdict["fore"]) + dlg = wx.ColourDialog(self, colourdata) + + dlg.GetColourData().SetChooseFull(True) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetColourData() + col1 = data.GetColour().Get() + self.SetItemTextColour(self.current, col1) + dlg.Destroy() + event.Skip() + + + def OnItemBold(self, event): + + self.SetItemBold(self.current, not self.itemdict["isbold"]) + event.Skip() + + + def OnItemFont(self, event): + + data = wx.FontData() + font = self.itemdict["font"] + + if font is None: + font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + + data.SetInitialFont(font) + + dlg = wx.FontDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetFontData() + font = data.GetChosenFont() + self.SetItemFont(self.current, font) + + dlg.Destroy() + event.Skip() + + + def OnItemHyperText(self, event): + + self.SetItemHyperText(self.current, not self.itemdict["ishtml"]) + event.Skip() + + + def OnDisableItem(self, event): + + self.EnableItem(self.current, False) + event.Skip() + + + def OnItemIcons(self, event): + + bitmaps = [self.itemdict["normal"], self.itemdict["selected"], + self.itemdict["expanded"], self.itemdict["selexp"]] + + wx.BeginBusyCursor() + dlg = TreeIcons(self, -1, bitmaps=bitmaps) + wx.EndBusyCursor() + dlg.ShowModal() + event.Skip() + + + def SetNewIcons(self, bitmaps): + + self.SetItemImage(self.current, bitmaps[0], which=wx.TreeItemIcon_Normal) + self.SetItemImage(self.current, bitmaps[1], which=wx.TreeItemIcon_Selected) + self.SetItemImage(self.current, bitmaps[2], which=wx.TreeItemIcon_Expanded) + self.SetItemImage(self.current, bitmaps[3], which=wx.TreeItemIcon_SelectedExpanded) + + + def OnItemInfo(self, event): + + itemtext = self.itemdict["text"] + numchildren = str(self.itemdict["children"]) + itemtype = self.itemdict["itemtype"] + pydata = repr(type(self.itemdict["pydata"])) + + if itemtype == 0: + itemtype = "Normal" + elif itemtype == 1: + itemtype = "CheckBox" + else: + itemtype = "RadioButton" + + strs = "Information On Selected Item:\n\n" + "Text: " + itemtext + "\n" \ + "Number Of Children: " + numchildren + "\n" \ + "Item Type: " + itemtype + "\n" \ + "Item Data Type: " + pydata + "\n" + + dlg = wx.MessageDialog(self, strs, "HyperTreeListDemo Info", wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + event.Skip() + + + def OnItemDelete(self, event): + + strs = "Are You Sure You Want To Delete Item " + self.GetItemText(self.current) + "?" + dlg = wx.MessageDialog(None, strs, 'Deleting Item', wx.YES_NO | wx.NO_DEFAULT | wx.CANCEL | wx.ICON_QUESTION) + + if dlg.ShowModal() in [wx.ID_NO, wx.ID_CANCEL]: + dlg.Destroy() + return + + dlg.Destroy() + + self.DeleteChildren(self.current) + self.Delete(self.current) + self.current = None + + event.Skip() + + + def OnItemPrepend(self, event): + + dlg = wx.TextEntryDialog(self, "Please Enter The New Item Name", 'Item Naming', 'Python') + + if dlg.ShowModal() == wx.ID_OK: + newname = dlg.GetValue() + newitem = self.PrependItem(self.current, newname) + self.EnsureVisible(newitem) + + dlg.Destroy() + event.Skip() + + + def OnItemAppend(self, event): + + dlg = wx.TextEntryDialog(self, "Please Enter The New Item Name", 'Item Naming', 'Python') + + if dlg.ShowModal() == wx.ID_OK: + newname = dlg.GetValue() + newitem = self.AppendItem(self.current, newname) + self.EnsureVisible(newitem) + + dlg.Destroy() + event.Skip() + + + def OnItemBackground(self, event): + + colourdata = wx.ColourData() + colourdata.SetColour(self.itemdict["back"]) + dlg = wx.ColourDialog(self, colourdata) + + dlg.GetColourData().SetChooseFull(True) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetColourData() + col1 = data.GetColour().Get() + self.SetItemBackgroundColour(self.current, col1) + + dlg.Destroy() + event.Skip() + + + def OnBeginEdit(self, event): + + self.log.write("OnBeginEdit\n") + # show how to prevent edit... + item = event.GetItem() + if item and self.GetItemText(item) == "The Root Item": + wx.Bell() + self.log.write("You can't edit this one...\n") + + # Lets just see what's visible of its children + cookie = 0 + root = event.GetItem() + (child, cookie) = self.GetFirstChild(root) + + while child: + self.log.write("Child [%s] visible = %d\n" % (self.GetItemText(child), self.IsVisible(child))) + (child, cookie) = self.GetNextChild(root, cookie) + + event.Veto() + + + def OnEndEdit(self, event): + + self.log.write("OnEndEdit: %s %s\n" %(event.IsEditCancelled(), event.GetLabel())) + # show how to reject edit, we'll not allow any digits + for x in event.GetLabel(): + if x in string.digits: + self.log.write("You can't enter digits...\n") + event.Veto() + return + + + def OnLeftDClick(self, event): + + pt = event.GetPosition() + item, flags, column = self.HitTest(pt) + if item and (flags & wx.TREE_HITTEST_ONITEMLABEL): + if self.GetAGWWindowStyleFlag() & wx.TR_EDIT_LABELS: + self.log.write("OnLeftDClick: %s (manually starting label edit)\n"% self.GetItemText(item)) + self.EditLabel(item) + else: + self.log.write("OnLeftDClick: Cannot Start Manual Editing, Missing Style TR_EDIT_LABELS\n") + + event.Skip() + + + def OnItemExpanded(self, event): + + item = event.GetItem() + if item: + self.log.write("OnItemExpanded: %s\n" % self.GetItemText(item)) + + + def OnItemExpanding(self, event): + + item = event.GetItem() + if item: + self.log.write("OnItemExpanding: %s\n" % self.GetItemText(item)) + + event.Skip() + + + def OnItemCollapsed(self, event): + + item = event.GetItem() + if item: + self.log.write("OnItemCollapsed: %s" % self.GetItemText(item)) + + + def OnItemCollapsing(self, event): + + item = event.GetItem() + if item: + self.log.write("OnItemCollapsing: %s\n" % self.GetItemText(item)) + + event.Skip() + + + def OnSelChanged(self, event): + + self.item = event.GetItem() + if self.item: + self.log.write("OnSelChanged: %s" % self.GetItemText(self.item)) + if wx.Platform == '__WXMSW__': + self.log.write(", BoundingRect: %s\n" % self.GetBoundingRect(self.item, True)) + else: + self.log.write("\n") + + event.Skip() + + + def OnSelChanging(self, event): + + item = event.GetItem() + olditem = event.GetOldItem() + + if item: + if not olditem: + olditemtext = "None" + else: + olditemtext = self.GetItemText(olditem) + self.log.write("OnSelChanging: From %s To %s\n" %(olditemtext, self.GetItemText(item))) + + event.Skip() + + + def OnBeginDrag(self, event): + + self.item = event.GetItem() + if self.item: + self.log.write("Beginning Drag...\n") + + event.Allow() + + + def OnBeginRDrag(self, event): + + self.item = event.GetItem() + if self.item: + self.log.write("Beginning Right Drag...\n") + + event.Allow() + + + def OnEndDrag(self, event): + + self.item = event.GetItem() + if self.item: + self.log.write("Ending Drag!\n") + + event.Skip() + + + def OnDeleteItem(self, event): + + item = event.GetItem() + + if not item: + return + + self.log.write("Deleting Item: %s\n" % self.GetItemText(item)) + event.Skip() + + + def OnItemCheck(self, event): + + item = event.GetItem() + self.log.write("Item " + self.GetItemText(item) + " Has Been Cheched!\n") + event.Skip() + + + def OnItemChecking(self, event): + + item = event.GetItem() + self.log.write("Item " + self.GetItemText(item) + " Is Being Checked...\n") + event.Skip() + + + def OnToolTip(self, event): + + item = event.GetItem() + if item: + event.SetToolTip(wx.ToolTip(self.GetItemText(item))) + + + def OnItemMenu(self, event): + + item = event.GetItem() + if item: + self.log.write("OnItemMenu: %s\n" % self.GetItemText(item)) + + event.Skip() + + + def OnKey(self, event): + + keycode = event.GetKeyCode() + keyname = keyMap.get(keycode, None) + + if keycode == wx.WXK_BACK: + self.log.write("OnKeyDown: HAHAHAHA! I Vetoed Your Backspace! HAHAHAHA\n") + return + + if keyname is None: + if "unicode" in wx.PlatformInfo: + keycode = event.GetUnicodeKey() + if keycode <= 127: + keycode = event.GetKeyCode() + keyname = "\"" + unichr(event.GetUnicodeKey()) + "\"" + if keycode < 27: + keyname = "Ctrl-%s" % chr(ord('A') + keycode-1) + + elif keycode < 256: + if keycode == 0: + keyname = "NUL" + elif keycode < 27: + keyname = "Ctrl-%s" % chr(ord('A') + keycode-1) + else: + keyname = "\"%s\"" % chr(keycode) + else: + keyname = "unknown (%s)" % keycode + + self.log.write("OnKeyDown: You Pressed '" + keyname + "'\n") + + event.Skip() + + + def OnActivate(self, event): + + if self.item: + self.log.write("OnActivate: %s\n" % self.GetItemText(self.item)) + + event.Skip() + + + def OnHyperLink(self, event): + + item = event.GetItem() + if item: + self.log.write("OnHyperLink: %s\n" % self.GetItemText(self.item)) + + + def OnTextCtrl(self, event): + + char = chr(event.GetKeyCode()) + self.log.write("EDITING THE TEXTCTRL: You Wrote '" + char + \ + "' (KeyCode = " + str(event.GetKeyCode()) + ")\n") + event.Skip() + + + def OnComboBox(self, event): + + selection = event.GetEventObject().GetValue() + self.log.write("CHOICE FROM COMBOBOX: You Chose '" + selection + "'\n") + event.Skip() + + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test HyperTreeList ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = HyperTreeListDemo(self, self.log) + self.win.Show(True) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = HTL.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/KnobCtrl.py b/demo/agw/KnobCtrl.py new file mode 100644 index 00000000..1d9337ed --- /dev/null +++ b/demo/agw/KnobCtrl.py @@ -0,0 +1,184 @@ +import wx +import wx.lib.colourselect as csel + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import knobctrl as KC +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.knobctrl as KC + + +#---------------------------------------------------------------------- + +class KnobCtrlDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + self.log = log + + self.panel = wx.Panel(self, -1) + self.LayoutItems() + + + def LayoutItems(self): + + leftbottomsizer_staticbox = wx.StaticBox(self.panel, -1, "Play With Me!") + lefttopsizer_staticbox = wx.StaticBox(self.panel, -1, "Change My Properties!") + + self.knob1 = KC.KnobCtrl(self.panel, -1, size=(100, 100)) + self.knob2 = KC.KnobCtrl(self.panel, -1, size=(100, 100)) + + self.knob1.SetTags(range(0, 151, 10)) + self.knob1.SetAngularRange(-45, 225) + self.knob1.SetValue(45) + + self.knob2.SetTags(range(0, 151, 10)) + self.knob2.SetAngularRange(0, 270) + self.knob2.SetValue(100) + + self.knobtracker1 = wx.StaticText(self.panel, -1, "Value = 45") + self.knobtracker2 = wx.StaticText(self.panel, -1, "Value = 100") + + knobslider = wx.Slider(self.panel, -1, 4, 1, 10, style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS) + tickslider = wx.Slider(self.panel, -1, 16, 3, 20, style=wx.SL_HORIZONTAL|wx.SL_AUTOTICKS|wx.SL_LABELS) + tagscolour = csel.ColourSelect(self.panel, -1, "Choose...", wx.BLACK) + boundingcolour = csel.ColourSelect(self.panel, -1, "Choose...", wx.WHITE) + firstcolour = csel.ColourSelect(self.panel, -1, "Choose...", wx.WHITE) + secondcolour = csel.ColourSelect(self.panel, -1, "Choose...", wx.Colour(170, 170, 150)) + + knobslider.SetValue(4) + tickslider.SetValue(16) + + mainsizer = wx.BoxSizer(wx.VERTICAL) + panelsizer = wx.BoxSizer(wx.HORIZONTAL) + rightsizer = wx.FlexGridSizer(6, 2, 10, 10) + leftsizer = wx.BoxSizer(wx.VERTICAL) + leftbottomsizer = wx.StaticBoxSizer(leftbottomsizer_staticbox, wx.VERTICAL) + lefttopsizer = wx.StaticBoxSizer(lefttopsizer_staticbox, wx.VERTICAL) + + lefttopsizer.Add(self.knob1, 1, wx.ALL|wx.EXPAND, 5) + lefttopsizer.Add(self.knobtracker1, 0, wx.ALL, 5) + leftsizer.Add(lefttopsizer, 1, wx.ALL|wx.EXPAND, 5) + leftbottomsizer.Add(self.knob2, 1, wx.ALL|wx.EXPAND, 5) + leftbottomsizer.Add(self.knobtracker2, 0, wx.ALL, 5) + leftsizer.Add(leftbottomsizer, 1, wx.ALL|wx.EXPAND, 5) + panelsizer.Add(leftsizer, 1, wx.EXPAND|wx.ALL, 20) + + label_1 = wx.StaticText(self.panel, -1, "Knob Radius: ") + rightsizer.Add(label_1, 0, wx.ALIGN_CENTER_VERTICAL, 5) + rightsizer.Add(knobslider, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) + label_2 = wx.StaticText(self.panel, -1, "Number Of Ticks: ") + rightsizer.Add(label_2, 0, wx.ALIGN_CENTER_VERTICAL, 0) + rightsizer.Add(tickslider, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 5) + label_3 = wx.StaticText(self.panel, -1, "Tags Colour: ") + rightsizer.Add(label_3, 0, wx.ALIGN_CENTER_VERTICAL, 0) + rightsizer.Add(tagscolour, 0) + label_4 = wx.StaticText(self.panel, -1, "Bounding Colour: ") + rightsizer.Add(label_4, 0, wx.ALIGN_CENTER_VERTICAL, 0) + rightsizer.Add(boundingcolour, 0) + label_5 = wx.StaticText(self.panel, -1, "First Gradient Colour: ") + rightsizer.Add(label_5, 0, wx.ALIGN_CENTER_VERTICAL, 0) + rightsizer.Add(firstcolour, 0) + label_6 = wx.StaticText(self.panel, -1, "Second Gradient Colour: ") + rightsizer.Add(label_6, 0, wx.ALIGN_CENTER_VERTICAL, 0) + rightsizer.Add(secondcolour, 0) + panelsizer.Add(rightsizer, 1, wx.ALL|wx.EXPAND, 20) + + self.panel.SetSizer(panelsizer) + panelsizer.Layout() + + mainsizer.Add(self.panel, 1, wx.EXPAND) + self.SetSizer(mainsizer) + mainsizer.Layout() + + self.Bind(wx.EVT_COMMAND_SCROLL, self.OnKnobRadius, knobslider) + self.Bind(wx.EVT_COMMAND_SCROLL, self.OnTicks, tickslider) + self.Bind(KC.EVT_KC_ANGLE_CHANGED, self.OnAngleChanged1, self.knob1) + self.Bind(KC.EVT_KC_ANGLE_CHANGED, self.OnAngleChanged2, self.knob2) + tagscolour.Bind(csel.EVT_COLOURSELECT, self.OnTagsColour) + boundingcolour.Bind(csel.EVT_COLOURSELECT, self.OnBoundingColour) + firstcolour.Bind(csel.EVT_COLOURSELECT, self.OnFirstColour) + secondcolour.Bind(csel.EVT_COLOURSELECT, self.OnSecondColour) + + + def OnAngleChanged1(self, event): + + value = event.GetValue() + self.knobtracker1.SetLabel("Value = " + str(value)) + self.log.write("KnobCtrl 1 changed value to %s\n"%value) + self.knobtracker1.Refresh() + + + def OnAngleChanged2(self, event): + + value = event.GetValue() + self.knobtracker2.SetLabel("Value = " + str(value)) + self.log.write("KnobCtrl 2 changed value to %s\n"%value) + self.knobtracker2.Refresh() + + + def OnKnobRadius(self, event): + + value = event.GetPosition() + self.knob1.SetKnobRadius(value) + event.Skip() + + + def OnTicks(self, event): + + minvalue = self.knob1.GetMinValue() + maxvalue = self.knob1.GetMaxValue() + + therange = (maxvalue-minvalue)/(event.GetPosition()-1) + tickrange = range(minvalue, maxvalue+1, therange) + self.knob1.SetTags(tickrange) + + event.Skip() + + + def OnTagsColour(self, event): + + self.knob1.SetTagsColour(event.GetValue()) + + + def OnBoundingColour(self, event): + + self.knob1.SetBoundingColour(event.GetValue()) + + + def OnFirstColour(self, event): + + self.knob1.SetFirstGradientColour(event.GetValue()) + + + def OnSecondColour(self, event): + + self.knob1.SetSecondGradientColour(event.GetValue()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = KnobCtrlDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = KC.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/agw/LabelBook.py b/demo/agw/LabelBook.py new file mode 100644 index 00000000..3148576d --- /dev/null +++ b/demo/agw/LabelBook.py @@ -0,0 +1,565 @@ +import wx +import wx.lib.colourselect as csel +import random + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +bitmapDir = os.path.join(dirName, 'bitmaps') +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import labelbook as LB + from agw.fmresources import * +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.labelbook as LB + from wx.lib.agw.fmresources import * + +import images + +_pageTexts = ["Hello", "From", "wxPython", "LabelBook", "Demo"] +_pageIcons = ["roll.png", "charge.png", "add.png", "decrypted.png", "news.png"] +_pageColours = [wx.RED, wx.GREEN, wx.WHITE, wx.BLUE, "Pink"] + +#---------------------------------------------------------------------- +class SamplePane(wx.Panel): + """ + Just a simple test window to put into the LabelBook. + """ + def __init__(self, parent, colour, label): + + wx.Panel.__init__(self, parent, style=0)#wx.BORDER_SUNKEN) + self.SetBackgroundColour(wx.Colour(255,255,255)) + + label = label + "\nEnjoy the LabelBook && FlatImageBook demo!" + static = wx.StaticText(self, -1, label, pos=(10, 10)) + +#---------------------------------------------------------------------- + +class LabelBookDemo(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent) + + self.initializing = True + self.book = None + self._oldTextSize = 1.0 + + self.log = log + + self.splitter = wx.SplitterWindow(self, -1, style=wx.SP_3D|wx.SP_BORDER| + wx.SP_LIVE_UPDATE|wx.SP_3DSASH) + self.mainpanel = wx.Panel(self.splitter, -1) + self.leftpanel = wx.Panel(self.splitter, -1, style=0)#wx.SUNKEN_BORDER) + + self.sizer_3_staticbox = wx.StaticBox(self.leftpanel, -1, "Book Styles") + self.sizer_4_staticbox = wx.StaticBox(self.leftpanel, -1, "Colours") + + radioList = ["LabelBook", "FlatImageBook"] + self.labelbook = wx.RadioBox(self.leftpanel, -1, "Book Type", wx.DefaultPosition, + wx.DefaultSize, radioList, 2, wx.RA_SPECIFY_ROWS) + + radioList = ["Left", "Right", "Top", "Bottom"] + self.bookdirection = wx.RadioBox(self.leftpanel, -1, "Book Orientation", + wx.DefaultPosition, wx.DefaultSize, radioList, + 2, wx.RA_SPECIFY_ROWS) + + self.border = wx.CheckBox(self.leftpanel, -1, "Draw Book Border") + self.onlytext = wx.CheckBox(self.leftpanel, -1, "Show Only Text") + self.onlyimages = wx.CheckBox(self.leftpanel, -1, "Show Only Images") + self.shadow = wx.CheckBox(self.leftpanel, -1, "Draw Shadows") + self.pin = wx.CheckBox(self.leftpanel, -1, "Use Pin Button") + self.gradient = wx.CheckBox(self.leftpanel, -1, "Draw Gradient Shading") + self.web = wx.CheckBox(self.leftpanel, -1, "Web Highlight") + self.fittext = wx.CheckBox(self.leftpanel, -1, "Fit Label Text") + self.boldtext = wx.CheckBox(self.leftpanel, -1, "Bold Label Text") + self.boldselection = wx.CheckBox(self.leftpanel, -1, "Bold Selected Tab") + + self.textsize = wx.TextCtrl(self.leftpanel, -1, "1.0",style=wx.TE_PROCESS_ENTER) + self.background = csel.ColourSelect(self.leftpanel, -1, "Choose...", + wx.Colour(132, 164, 213), size=(-1, 20)) + self.activetab = csel.ColourSelect(self.leftpanel, -1, "Choose...", + wx.Colour(255, 255, 255), size=(-1, 20)) + self.tabsborder = csel.ColourSelect(self.leftpanel, -1, "Choose...", + wx.Colour(0, 0, 204), size=(-1, 20)) + self.textcolour = csel.ColourSelect(self.leftpanel, -1, "Choose...", + wx.BLACK, size=(-1, 20)) + self.activetextcolour = csel.ColourSelect(self.leftpanel, -1, "Choose...", + wx.BLACK, size=(-1, 20)) + self.hilite = csel.ColourSelect(self.leftpanel, -1, "Choose...", + wx.Colour(191, 216, 216), size=(-1, 20)) + + self.SetProperties() + self.CreateLabelBook() + self.DoLayout() + + self.Bind(wx.EVT_RADIOBOX, self.OnBookType, self.labelbook) + self.Bind(wx.EVT_RADIOBOX, self.OnBookOrientation, self.bookdirection) + + self.Bind(wx.EVT_CHECKBOX, self.OnStyle, self.border) + self.Bind(wx.EVT_CHECKBOX, self.OnStyle, self.onlytext) + self.Bind(wx.EVT_CHECKBOX, self.OnStyle, self.onlyimages) + self.Bind(wx.EVT_CHECKBOX, self.OnStyle, self.shadow) + self.Bind(wx.EVT_CHECKBOX, self.OnStyle, self.pin) + self.Bind(wx.EVT_CHECKBOX, self.OnStyle, self.gradient) + self.Bind(wx.EVT_CHECKBOX, self.OnStyle, self.web) + self.Bind(wx.EVT_CHECKBOX, self.OnStyle, self.fittext) + self.Bind(wx.EVT_CHECKBOX, self.OnStyle, self.boldtext) + self.Bind(wx.EVT_CHECKBOX, self.OnStyle, self.boldselection) + self.Bind(wx.EVT_TEXT_ENTER, self.OnStyle, self.textsize) + + self.Bind(csel.EVT_COLOURSELECT, self.OnBookColours, self.background) + self.Bind(csel.EVT_COLOURSELECT, self.OnBookColours, self.activetab) + self.Bind(csel.EVT_COLOURSELECT, self.OnBookColours, self.activetextcolour) + self.Bind(csel.EVT_COLOURSELECT, self.OnBookColours, self.tabsborder) + self.Bind(csel.EVT_COLOURSELECT, self.OnBookColours, self.textcolour) + self.Bind(csel.EVT_COLOURSELECT, self.OnBookColours, self.hilite) + + self.Bind(LB.EVT_IMAGENOTEBOOK_PAGE_CHANGING, self.OnPageChanging) + self.Bind(LB.EVT_IMAGENOTEBOOK_PAGE_CHANGED, self.OnPageChanged) + self.Bind(LB.EVT_IMAGENOTEBOOK_PAGE_CLOSING, self.OnPageClosing) + self.Bind(LB.EVT_IMAGENOTEBOOK_PAGE_CLOSED, self.OnPageClosed) + + + statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + statusbar.SetStatusWidths([-2, -1]) + # statusbar fields + statusbar_fields = [("LabelBook & FlatImageBook wxPython Demo, Andrea Gavana @ 03 Nov 2006"), + ("Welcome To wxPython!")] + + for i in range(len(statusbar_fields)): + statusbar.SetStatusText(statusbar_fields[i], i) + + self.CreateMenu() + + self.SetSize((800,700)) + + self.SetIcon(images.Mondrian.GetIcon()) + self.CenterOnScreen() + + self.initializing = False + self.SendSizeEvent() + + + def SetProperties(self): + + self.SetTitle("LabelBook & FlatImageBook wxPython Demo ;-)") + self.splitter.SetMinimumPaneSize(120) + self.pin.SetValue(0) + self.fittext.SetValue(1) + self.border.SetValue(1) + self.onlytext.SetValue(1) + + + def DoLayout(self): + + mainsizer = wx.BoxSizer(wx.VERTICAL) + panelsizer = wx.BoxSizer(wx.VERTICAL) + leftsizer = wx.BoxSizer(wx.VERTICAL) + sizer_3 = wx.StaticBoxSizer(self.sizer_3_staticbox, wx.VERTICAL) + sizer_4 = wx.StaticBoxSizer(self.sizer_4_staticbox, wx.VERTICAL) + gridsizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5) + + sizer_2 = wx.BoxSizer(wx.VERTICAL) + sizer_1 = wx.BoxSizer(wx.VERTICAL) + sizer_1.Add(self.labelbook, 0, wx.ALL, 3) + leftsizer.Add(sizer_1, 0, wx.ALL|wx.EXPAND, 5) + sizer_2.Add(self.bookdirection, 0, wx.ALL, 3) + leftsizer.Add(sizer_2, 0, wx.ALL|wx.EXPAND, 5) + + sizer_3.Add(self.border, 0, wx.ALL, 3) + sizer_3.Add(self.onlytext, 0, wx.LEFT|wx.BOTTOM, 3) + sizer_3.Add(self.onlyimages, 0, wx.LEFT|wx.BOTTOM, 3) + sizer_3.Add(self.shadow, 0, wx.LEFT|wx.BOTTOM, 3) + sizer_3.Add(self.pin, 0, wx.LEFT|wx.BOTTOM, 3) + sizer_3.Add(self.gradient, 0, wx.LEFT|wx.BOTTOM, 3) + sizer_3.Add(self.web, 0, wx.LEFT|wx.BOTTOM, 3) + sizer_3.Add(self.fittext, 0, wx.LEFT|wx.BOTTOM, 3) + sizer_3.Add(self.boldtext, 0, wx.LEFT|wx.BOTTOM, 3) + sizer_3.Add(self.boldselection, 0, wx.LEFT|wx.BOTTOM, 3) + leftsizer.Add(sizer_3, 0, wx.ALL|wx.EXPAND, 5) + + lbl = wx.StaticText(self.leftpanel, -1, "Text Font Multiple: ") + label1 = wx.StaticText(self.leftpanel, -1, "Tab Area Background Colour: ") + label2 = wx.StaticText(self.leftpanel, -1, "Active Tab Colour: ") + label3 = wx.StaticText(self.leftpanel, -1, "Tabs Border Colour: ") + label4 = wx.StaticText(self.leftpanel, -1, "Text Colour: ") + label5 = wx.StaticText(self.leftpanel, -1, "Active Tab Text Colour: ") + label6 = wx.StaticText(self.leftpanel, -1, "Tab Highlight Colour: ") + + gridsizer.Add(lbl, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 3) + gridsizer.Add(self.textsize, 0) + gridsizer.Add(label1, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 3) + gridsizer.Add(self.background, 0) + gridsizer.Add(label2, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 3) + gridsizer.Add(self.activetab, 0) + gridsizer.Add(label3, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 3) + gridsizer.Add(self.tabsborder, 0) + gridsizer.Add(label4, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 3) + gridsizer.Add(self.textcolour, 0) + gridsizer.Add(label5, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 3) + gridsizer.Add(self.activetextcolour, 0) + gridsizer.Add(label6, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 3) + gridsizer.Add(self.hilite, 0) + + sizer_4.Add(gridsizer, 1, wx.EXPAND) + gridsizer.Layout() + leftsizer.Add(sizer_4, 0, wx.ALL|wx.EXPAND, 5) + + self.leftpanel.SetSizer(leftsizer) + leftsizer.Layout() + leftsizer.SetSizeHints(self.leftpanel) + leftsizer.Fit(self.leftpanel) + + panelsizer.Add(self.book, 1, wx.EXPAND, 0) + self.mainpanel.SetSizer(panelsizer) + panelsizer.Layout() + + self.splitter.SplitVertically(self.leftpanel, self.mainpanel, 200) + mainsizer.Add(self.splitter, 1, wx.EXPAND, 0) + + self.SetSizer(mainsizer) + mainsizer.Layout() + self.Layout() + + + def CreateLabelBook(self, btype=0): + + if not self.initializing: + self.Freeze() + panelsizer = self.mainpanel.GetSizer() + panelsizer.Detach(0) + self.book.Destroy() + else: + self.imagelist = self.CreateImageList() + + self.EnableChoices(btype) + style = self.GetBookStyles() + + if btype == 0: # it is a labelbook: + self.book = LB.LabelBook(self.mainpanel, -1, agwStyle=style) + if self.bookdirection.GetSelection() > 1: + self.bookdirection.SetSelection(0) + + self.SetUserColours() + self.book.SetFontSizeMultiple(1.0) + self.book.SetFontBold(False) + + else: + self.book = LB.FlatImageBook(self.mainpanel, -1, agwStyle=style) + + self.book.AssignImageList(self.imagelist) + + for indx, txts in enumerate(_pageTexts): + label = "This is panel number %d"%(indx+1) + self.book.AddPage(SamplePane(self.book, _pageColours[indx], label), + txts, True, indx) + + self.book.SetSelection(0) + + if not self.initializing: + panelsizer.Add(self.book, 1, wx.EXPAND) + panelsizer.Layout() + self.GetSizer().Layout() + self.Layout() + self.Thaw() + + self.SendSizeEvent() + #wx.CallAfter(self.book.SetAGWWindowStyleFlag, style) + + + def EnableChoices(self, btype): + + self.bookdirection.EnableItem(2, btype) + self.bookdirection.EnableItem(3, btype) + self.onlyimages.Enable() + self.onlytext.Enable() + self.gradient.Enable(not btype) + self.web.Enable(not btype) + self.shadow.Enable(not btype) + self.background.Enable(not btype) + self.activetab.Enable(not btype) + self.activetextcolour.Enable(not btype) + self.textcolour.Enable(not btype) + self.hilite.Enable(not btype) + self.tabsborder.Enable(not btype) + self.fittext.Enable(not btype) + self.boldtext.Enable(not btype) + + + def GetBookStyles(self): + + style = INB_FIT_BUTTON + style = self.GetBookOrientation(style) + + if self.onlytext.IsEnabled() and self.onlytext.GetValue(): + style |= INB_SHOW_ONLY_TEXT + if self.onlyimages.IsEnabled() and self.onlyimages.GetValue(): + style |= INB_SHOW_ONLY_IMAGES + if self.pin.GetValue(): + style |= INB_USE_PIN_BUTTON + if self.shadow.GetValue(): + style |= INB_DRAW_SHADOW + if self.web.GetValue(): + style |= INB_WEB_HILITE + if self.gradient.GetValue(): + style |= INB_GRADIENT_BACKGROUND + if self.border.GetValue(): + style |= INB_BORDER + if self.fittext.IsEnabled() and self.fittext.GetValue(): + style |= INB_FIT_LABELTEXT + if self.boldselection.IsEnabled() and self.boldselection.GetValue(): + style |= INB_BOLD_TAB_SELECTION + + if self.book: + self.book.SetFontBold(self.boldtext.GetValue()) + + return style + + + def CreateImageList(self): + + imagelist = wx.ImageList(32, 32) + for img in _pageIcons: + newImg = os.path.join(bitmapDir, "lb%s"%img) + bmp = wx.Bitmap(newImg, wx.BITMAP_TYPE_PNG) + imagelist.Add(bmp) + + return imagelist + + + def GetBookOrientation(self, style): + + selection = self.bookdirection.GetSelection() + if selection == 0: + style |= INB_LEFT + elif selection == 1: + style |= INB_RIGHT + elif selection == 2: + style |= INB_TOP + else: + style |= INB_BOTTOM + + return style + + + def OnBookType(self, event): + + self.CreateLabelBook(event.GetInt()) + event.Skip() + + + def OnBookOrientation(self, event): + + style = self.GetBookStyles() + self.book.SetAGWWindowStyleFlag(style) + + event.Skip() + + + def OnStyle(self, event): + + style = self.GetBookStyles() + self.book.SetAGWWindowStyleFlag(style) + + self.book.SetFontSizeMultiple(float(self.textsize.GetValue())) + if self.textsize.GetValue() != self._oldTextSize: + self.book.ResizeTabArea() + + self._oldTextSize = self.textsize.GetValue() + + event.Skip() + + + def OnBookColours(self, event): + + obj = event.GetId() + colour = event.GetValue() + + if obj == self.background.GetId(): + self.book.SetColour(INB_TAB_AREA_BACKGROUND_COLOUR, colour) + elif obj == self.activetab.GetId(): + self.book.SetColour(INB_ACTIVE_TAB_COLOUR, colour) + elif obj == self.tabsborder.GetId(): + self.book.SetColour(INB_TABS_BORDER_COLOUR, colour) + elif obj == self.textcolour.GetId(): + self.book.SetColour(INB_TEXT_COLOUR, colour) + elif obj == self.activetextcolour.GetId(): + self.book.SetColour(INB_ACTIVE_TEXT_COLOUR, colour) + else: + self.book.SetColour(INB_HILITE_TAB_COLOUR, colour) + + self.book.Refresh() + + + def SetUserColours(self): + + self.book.SetColour(INB_TAB_AREA_BACKGROUND_COLOUR, self.background.GetColour()) + self.book.SetColour(INB_ACTIVE_TAB_COLOUR, self.activetab.GetColour()) + self.book.SetColour(INB_TABS_BORDER_COLOUR, self.tabsborder.GetColour()) + self.book.SetColour(INB_TEXT_COLOUR, self.textcolour.GetColour()) + self.book.SetColour(INB_ACTIVE_TEXT_COLOUR, self.activetextcolour.GetColour()) + self.book.SetColour(INB_HILITE_TAB_COLOUR, self.hilite.GetColour()) + + + def OnPageChanging(self, event): + + oldsel = event.GetOldSelection() + newsel = event.GetSelection() + self.log.write("Page Changing From: " + str(oldsel) + " To: " + str(newsel) + "\n") + event.Skip() + + + def OnPageChanged(self, event): + + newsel = event.GetSelection() + self.log.write("Page Changed To: " + str(newsel) + "\n") + event.Skip() + + + def OnPageClosing(self, event): + + newsel = event.GetSelection() + self.log.write("Closing Page: " + str(newsel) + "\n") + event.Skip() + + + def OnPageClosed(self, event): + + newsel = event.GetSelection() + self.log.write("Closed Page: " + str(newsel) + "\n") + event.Skip() + + + def OnAddPage(self, event): + + pageCount = self.book.GetPageCount() + indx = random.randint(0, 4) + label = "This is panel number %d"%(pageCount+1) + self.book.AddPage(SamplePane(self.book, _pageColours[indx], label), + "Added Page", True, indx) + + + def OnDeletePage(self, event): + + msg = "Please Enter The Page Number You Want To Remove:" + dlg = wx.TextEntryDialog(self, msg, "Enter Page") + + if dlg.ShowModal() != wx.ID_OK: + dlg.Destroy() + return + + userString = dlg.GetValue() + dlg.Destroy() + + try: + page = int(userString) + except: + return + + if page < 0 or page > self.book.GetPageCount() - 1: + return + + self.book.DeletePage(page) + + + def OnDeleteAllPages(self, event): + + self.book.DeleteAllPages() + + + def CreateMenu(self): + + menuBar = wx.MenuBar(wx.MB_DOCKABLE) + fileMenu = wx.Menu() + editMenu = wx.Menu() + helpMenu = wx.Menu() + + item = wx.MenuItem(fileMenu, wx.ID_ANY, "E&xit") + self.Bind(wx.EVT_MENU, self.OnQuit, item) + fileMenu.AppendItem(item) + + item = wx.MenuItem(editMenu, wx.ID_ANY, "Add Page") + self.Bind(wx.EVT_MENU, self.OnAddPage, item) + editMenu.AppendItem(item) + + editMenu.AppendSeparator() + + item = wx.MenuItem(editMenu, wx.ID_ANY, "Delete Page") + self.Bind(wx.EVT_MENU, self.OnDeletePage, item) + editMenu.AppendItem(item) + + item = wx.MenuItem(editMenu, wx.ID_ANY, "Delete All Pages") + self.Bind(wx.EVT_MENU, self.OnDeleteAllPages, item) + editMenu.AppendItem(item) + + item = wx.MenuItem(helpMenu, wx.ID_ANY, "About") + self.Bind(wx.EVT_MENU, self.OnAbout, item) + helpMenu.AppendItem(item) + + menuBar.Append(fileMenu, "&File") + menuBar.Append(editMenu, "&Edit") + menuBar.Append(helpMenu, "&Help") + + self.SetMenuBar(menuBar) + + + def OnQuit(self, event): + + self.Destroy() + + + def OnAbout(self, event): + + msg = "This Is The About Dialog Of The LabelBook & FlatImageBook Demo.\n\n" + \ + "Author: Andrea Gavana @ 03 Nov 2006\n\n" + \ + "Please Report Any Bug/Requests Of Improvements\n" + \ + "To Me At The Following Adresses:\n\n" + \ + "andrea.gavana@gmail.com\n" + "andrea.gavana@maerskoil.com\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "LabelBook wxPython Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test LabelBook And FlatImageBook ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = LabelBookDemo(self, self.log) + self.win.Show(True) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = LB.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/ListCtrl.py b/demo/agw/ListCtrl.py new file mode 100644 index 00000000..367e70b3 --- /dev/null +++ b/demo/agw/ListCtrl.py @@ -0,0 +1,510 @@ +#---------------------------------------------------------------------------- +# Name: ListCtrl.py +# Purpose: Testing lots of stuff, controls, window types, etc. +# +# Author: Robin Dunn & Gary Dumer +# +# Created: +# RCS-ID: $Id: ListCtrl.py 51049 2008-01-06 21:38:01Z RD $ +# Copyright: (c) 1998 by Total Control Software +# Licence: wxWindows license +#---------------------------------------------------------------------------- + +import sys +import wx +import wx.lib.mixins.listctrl as listmix + +import images + +#--------------------------------------------------------------------------- + +musicdata = { +1 : ("Bad English", "The Price Of Love", "Rock"), +2 : ("DNA featuring Suzanne Vega", "Tom's Diner", "Rock"), +3 : ("George Michael", "Praying For Time", "Rock"), +4 : ("Gloria Estefan", "Here We Are", "Rock"), +5 : ("Linda Ronstadt", "Don't Know Much", "Rock"), +6 : ("Michael Bolton", "How Am I Supposed To Live Without You", "Blues"), +7 : ("Paul Young", "Oh Girl", "Rock"), +8 : ("Paula Abdul", "Opposites Attract", "Rock"), +9 : ("Richard Marx", "Should've Known Better", "Rock"), +10: ("Rod Stewart", "Forever Young", "Rock"), +11: ("Roxette", "Dangerous", "Rock"), +12: ("Sheena Easton", "The Lover In Me", "Rock"), +13: ("Sinead O'Connor", "Nothing Compares 2 U", "Rock"), +14: ("Stevie B.", "Because I Love You", "Rock"), +15: ("Taylor Dayne", "Love Will Lead You Back", "Rock"), +16: ("The Bangles", "Eternal Flame", "Rock"), +17: ("Wilson Phillips", "Release Me", "Rock"), +18: ("Billy Joel", "Blonde Over Blue", "Rock"), +19: ("Billy Joel", "Famous Last Words", "Rock"), +20: ("Billy Joel", "Lullabye (Goodnight, My Angel)", "Rock"), +21: ("Billy Joel", "The River Of Dreams", "Rock"), +22: ("Billy Joel", "Two Thousand Years", "Rock"), +23: ("Janet Jackson", "Alright", "Rock"), +24: ("Janet Jackson", "Black Cat", "Rock"), +25: ("Janet Jackson", "Come Back To Me", "Rock"), +26: ("Janet Jackson", "Escapade", "Rock"), +27: ("Janet Jackson", "Love Will Never Do (Without You)", "Rock"), +28: ("Janet Jackson", "Miss You Much", "Rock"), +29: ("Janet Jackson", "Rhythm Nation", "Rock"), +30: ("Janet Jackson", "State Of The World", "Rock"), +31: ("Janet Jackson", "The Knowledge", "Rock"), +32: ("Spyro Gyra", "End of Romanticism", "Jazz"), +33: ("Spyro Gyra", "Heliopolis", "Jazz"), +34: ("Spyro Gyra", "Jubilee", "Jazz"), +35: ("Spyro Gyra", "Little Linda", "Jazz"), +36: ("Spyro Gyra", "Morning Dance", "Jazz"), +37: ("Spyro Gyra", "Song for Lorraine", "Jazz"), +38: ("Yes", "Owner Of A Lonely Heart", "Rock"), +39: ("Yes", "Rhythm Of Love", "Rock"), +40: ("Cusco", "Dream Catcher", "New Age"), +41: ("Cusco", "Geronimos Laughter", "New Age"), +42: ("Cusco", "Ghost Dance", "New Age"), +43: ("Blue Man Group", "Drumbone", "New Age"), +44: ("Blue Man Group", "Endless Column", "New Age"), +45: ("Blue Man Group", "Klein Mandelbrot", "New Age"), +46: ("Kenny G", "Silhouette", "Jazz"), +47: ("Sade", "Smooth Operator", "Jazz"), +48: ("David Arkenstone", "Papillon (On The Wings Of The Butterfly)", "New Age"), +49: ("David Arkenstone", "Stepping Stars", "New Age"), +50: ("David Arkenstone", "Carnation Lily Lily Rose", "New Age"), +51: ("David Lanz", "Behind The Waterfall", "New Age"), +52: ("David Lanz", "Cristofori's Dream", "New Age"), +53: ("David Lanz", "Heartsounds", "New Age"), +54: ("David Lanz", "Leaves on the Seine", "New Age"), +} + +#--------------------------------------------------------------------------- + +class TestListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin): + def __init__(self, parent, ID, pos=wx.DefaultPosition, + size=wx.DefaultSize, style=0): + wx.ListCtrl.__init__(self, parent, ID, pos, size, style) + listmix.ListCtrlAutoWidthMixin.__init__(self) + + +class TestListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin): + def __init__(self, parent, log): + wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS) + + self.log = log + tID = wx.NewId() + + sizer = wx.BoxSizer(wx.VERTICAL) + + if wx.Platform == "__WXMAC__" and \ + hasattr(wx.GetApp().GetTopWindow(), "LoadDemo"): + self.useNative = wx.CheckBox(self, -1, "Use native listctrl") + self.useNative.SetValue( + not wx.SystemOptions.GetOptionInt("mac.listctrl.always_use_generic") ) + self.Bind(wx.EVT_CHECKBOX, self.OnUseNative, self.useNative) + sizer.Add(self.useNative, 0, wx.ALL | wx.ALIGN_RIGHT, 4) + + self.il = wx.ImageList(16, 16) + + self.idx1 = self.il.Add(images.Smiles.GetBitmap()) + self.sm_up = self.il.Add(images.SmallUpArrow.GetBitmap()) + self.sm_dn = self.il.Add(images.SmallDnArrow.GetBitmap()) + + self.list = TestListCtrl(self, tID, + style=wx.LC_REPORT + #| wx.BORDER_SUNKEN + | wx.BORDER_NONE + | wx.LC_EDIT_LABELS + | wx.LC_SORT_ASCENDING + #| wx.LC_NO_HEADER + #| wx.LC_VRULES + #| wx.LC_HRULES + #| wx.LC_SINGLE_SEL + ) + + self.list.SetImageList(self.il, wx.IMAGE_LIST_SMALL) + sizer.Add(self.list, 1, wx.EXPAND) + + self.PopulateList() + + # Now that the list exists we can init the other base class, + # see wx/lib/mixins/listctrl.py + self.itemDataMap = musicdata + listmix.ColumnSorterMixin.__init__(self, 3) + #self.SortListItems(0, True) + + self.SetSizer(sizer) + self.SetAutoLayout(True) + + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list) + self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self.list) + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self.list) + self.Bind(wx.EVT_LIST_DELETE_ITEM, self.OnItemDelete, self.list) + self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list) + self.Bind(wx.EVT_LIST_COL_RIGHT_CLICK, self.OnColRightClick, self.list) + self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, self.list) + self.Bind(wx.EVT_LIST_COL_DRAGGING, self.OnColDragging, self.list) + self.Bind(wx.EVT_LIST_COL_END_DRAG, self.OnColEndDrag, self.list) + self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list) + + self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) + self.list.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) + + # for wxMSW + self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightClick) + + # for wxGTK + self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightClick) + + + def OnUseNative(self, event): + wx.SystemOptions.SetOptionInt("mac.listctrl.always_use_generic", not event.IsChecked()) + wx.GetApp().GetTopWindow().LoadDemo("ListCtrl") + + def PopulateList(self): + if 0: + # for normal, simple columns, you can add them like this: + self.list.InsertColumn(0, "Artist") + self.list.InsertColumn(1, "Title", wx.LIST_FORMAT_RIGHT) + self.list.InsertColumn(2, "Genre") + else: + # but since we want images on the column header we have to do it the hard way: + info = wx.ListItem() + info.m_mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT + info.m_image = -1 + info.m_format = 0 + info.m_text = "Artist" + self.list.InsertColumnInfo(0, info) + + info.m_format = wx.LIST_FORMAT_RIGHT + info.m_text = "Title" + self.list.InsertColumnInfo(1, info) + + info.m_format = 0 + info.m_text = "Genre" + self.list.InsertColumnInfo(2, info) + + items = musicdata.items() + for key, data in items: + index = self.list.InsertImageStringItem(sys.maxint, data[0], self.idx1) + self.list.SetStringItem(index, 1, data[1]) + self.list.SetStringItem(index, 2, data[2]) + self.list.SetItemData(index, key) + + self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(2, 100) + + # show how to select an item + self.list.SetItemState(5, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) + + # show how to change the colour of a couple items + item = self.list.GetItem(1) + item.SetTextColour(wx.BLUE) + self.list.SetItem(item) + item = self.list.GetItem(4) + item.SetTextColour(wx.RED) + self.list.SetItem(item) + + self.currentItem = 0 + + + # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py + def GetListCtrl(self): + return self.list + + # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py + def GetSortImages(self): + return (self.sm_dn, self.sm_up) + + + def OnRightDown(self, event): + x = event.GetX() + y = event.GetY() + self.log.WriteText("x, y = %s\n" % str((x, y))) + item, flags = self.list.HitTest((x, y)) + + if item != wx.NOT_FOUND and flags & wx.LIST_HITTEST_ONITEM: + self.list.Select(item) + + event.Skip() + + + def getColumnText(self, index, col): + item = self.list.GetItem(index, col) + return item.GetText() + + + def OnItemSelected(self, event): + ##print event.GetItem().GetTextColour() + self.currentItem = event.m_itemIndex + self.log.WriteText("OnItemSelected: %s, %s, %s, %s\n" % + (self.currentItem, + self.list.GetItemText(self.currentItem), + self.getColumnText(self.currentItem, 1), + self.getColumnText(self.currentItem, 2))) + + if self.currentItem == 10: + self.log.WriteText("OnItemSelected: Veto'd selection\n") + #event.Veto() # doesn't work + # this does + self.list.SetItemState(10, 0, wx.LIST_STATE_SELECTED) + + event.Skip() + + + def OnItemDeselected(self, evt): + item = evt.GetItem() + self.log.WriteText("OnItemDeselected: %d" % evt.m_itemIndex) + + # Show how to reselect something we don't want deselected + if evt.m_itemIndex == 11: + wx.CallAfter(self.list.SetItemState, 11, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) + + + def OnItemActivated(self, event): + self.currentItem = event.m_itemIndex + self.log.WriteText("OnItemActivated: %s\nTopItem: %s" % + (self.list.GetItemText(self.currentItem), self.list.GetTopItem())) + + def OnBeginEdit(self, event): + self.log.WriteText("OnBeginEdit") + event.Allow() + + def OnItemDelete(self, event): + self.log.WriteText("OnItemDelete\n") + + def OnColClick(self, event): + self.log.WriteText("OnColClick: %d\n" % event.GetColumn()) + event.Skip() + + def OnColRightClick(self, event): + item = self.list.GetColumn(event.GetColumn()) + self.log.WriteText("OnColRightClick: %d %s\n" % + (event.GetColumn(), (item.GetText(), item.GetAlign(), + item.GetWidth(), item.GetImage()))) + + def OnColBeginDrag(self, event): + self.log.WriteText("OnColBeginDrag\n") + ## Show how to not allow a column to be resized + #if event.GetColumn() == 0: + # event.Veto() + + + def OnColDragging(self, event): + self.log.WriteText("OnColDragging\n") + + def OnColEndDrag(self, event): + self.log.WriteText("OnColEndDrag\n") + + def OnDoubleClick(self, event): + self.log.WriteText("OnDoubleClick item %s\n" % self.list.GetItemText(self.currentItem)) + event.Skip() + + def OnRightClick(self, event): + self.log.WriteText("OnRightClick %s\n" % self.list.GetItemText(self.currentItem)) + + # only do this part the first time so the events are only bound once + if not hasattr(self, "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + self.popupID4 = wx.NewId() + self.popupID5 = wx.NewId() + self.popupID6 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + self.Bind(wx.EVT_MENU, self.OnPopupFour, id=self.popupID4) + self.Bind(wx.EVT_MENU, self.OnPopupFive, id=self.popupID5) + self.Bind(wx.EVT_MENU, self.OnPopupSix, id=self.popupID6) + + # make a menu + menu = wx.Menu() + # add some items + menu.Append(self.popupID1, "FindItem tests") + menu.Append(self.popupID2, "Iterate Selected") + menu.Append(self.popupID3, "ClearAll and repopulate") + menu.Append(self.popupID4, "DeleteAllItems") + menu.Append(self.popupID5, "GetItem") + menu.Append(self.popupID6, "Edit") + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + self.PopupMenu(menu) + menu.Destroy() + + + def OnPopupOne(self, event): + self.log.WriteText("Popup one\n") + print "FindItem:", self.list.FindItem(-1, "Roxette") + print "FindItemData:", self.list.FindItemData(-1, 11) + + def OnPopupTwo(self, event): + self.log.WriteText("Selected items:\n") + index = self.list.GetFirstSelected() + + while index != -1: + self.log.WriteText(" %s: %s\n" % (self.list.GetItemText(index), self.getColumnText(index, 1))) + index = self.list.GetNextSelected(index) + + def OnPopupThree(self, event): + self.log.WriteText("Popup three\n") + self.list.ClearAll() + wx.CallAfter(self.PopulateList) + + def OnPopupFour(self, event): + self.list.DeleteAllItems() + + def OnPopupFive(self, event): + item = self.list.GetItem(self.currentItem) + print item.m_text, item.m_itemId, self.list.GetItemData(self.currentItem) + + def OnPopupSix(self, event): + self.list.EditLabel(self.currentItem) + + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestListCtrlPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + +overview = """\ + + +A list control presents lists in a number of formats: list view, report view, +icon view and small icon view. In any case, elements are numbered from zero. +For all these modes (but not for virtual list controls), the items are stored +in the control and must be added to it using InsertItem method. + +

To intercept events from a list control, use the event table macros described in +wxListEvent. + +

Mix-ins

+This example demonstrates how to use mixins. The following mixins are available. + +

ColumnSorterMixin

+ +ColumnSorterMixin(numColumns) + +

A mixin class that handles sorting of a wxListCtrl in REPORT mode when the column +header is clicked on. + +

There are a few requirments needed in order for this to work genericly: +

    +
  1. The combined class must have a GetListCtrl method that returns + the ListCtrl to be sorted, and the list control must exist at the time the + ColumnSorterMixin.__init__()method is called because it uses + GetListCtrl. + +
  2. Items in the list control must have a unique data value set with + list.SetItemData. + +
  3. The combined class must have an attribute named itemDataMap + that is a dictionary mapping the data values to a sequence of objects + representing the values in each column. These valuesare compared in + the column sorter to determine sort order. +
+ +

Interesting methods to override are GetColumnSorter, +GetSecondarySortValues, and GetSortImages. + +

Methods
+
+
SetColumnCount(newNumColumns) +
Informs the mixin as to the number of columns in the control. When it is +set, it also sets up an event handler for EVT_LIST_COL_CLICK events. + +
SortListItems(col=-1, ascending=1) +
Sort the list on demand. Can also be used to set the sort column and order. + +
GetColumnWidths() +
Returns a list of column widths. Can be used to help restore the current +view later. + +
GetSortImages() +
Returns a tuple of image list indexes the indexes in the image list for an +image to be put on the column header when sorting in descending order + +
GetColumnSorter() +
Returns a callable object to be used for comparing column values when sorting. + +
GetSecondarySortValues(col, key1, key2) +
Returns a tuple of 2 values to use for secondary sort values when the +items in the selected column match equal. The default just returns the +item data values. + +
+ +

ListCtrlAutoWidthMixin

+ +ListCtrlAutoWidthMixin() + +

A mix-in class that automatically resizes the last column to take up the +remaining width of the ListCtrl. + +

This causes the ListCtrl to automatically take up the full width of the list, +without either a horizontal scroll bar (unless absolutely necessary) or empty +space to the right of the last column. + +

NOTE: This only works for report-style lists. + +

WARNING: If you override the EVT_SIZE event in your ListCtrl, +make sure you call event.Skip() to ensure that the mixin's _OnResize method is +called. + +

This mix-in class was written by Erik Westra + +

Methods
+
+ +
resizeLastColumn(minWidth) +
Resize the last column appropriately. If the list's columns are too wide to +fit within the window, we use a horizontal scrollbar. Otherwise, we expand the +right-most column to take up the remaining free space in the list. This method is +called automatically when the ListCtrl is resized; you can also call it yourself +whenever you want the last column to be resized appropriately (eg, when adding, +removing or resizing columns). 'minWidth' is the preferred minimum width for +the last column. + +
+ + +

ListCtrlSelectionManagerMix

+ +ListCtrlSelectionManagerMix() + +

Mixin that defines a platform independent selection policy + +

As selection single and multi-select list return the item index or a +list of item indexes respectively. + +

Methods
+
+ +
getPopupMenu() +
Override to implement dynamic menus (create) + +
setPopupMenu(menu) +
Must be set for default behaviour. + +
afterPopupMenu() +
Override to implement dynamic menus (destroy). + +
getSelection() +
Returns the current selection (or selections as a Python list if extended +selection is enabled) + + + + +""" + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/MacLargeDemo.py b/demo/agw/MacLargeDemo.py new file mode 100644 index 00000000..5903a21a --- /dev/null +++ b/demo/agw/MacLargeDemo.py @@ -0,0 +1,355 @@ +import sys +import os +import wx +import random +import math +import images + +import wx.lib.mixins.listctrl as listmix + +from wx.lib.embeddedimage import PyEmbeddedImage + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import ultimatelistctrl as ULC +except ImportError: # if it's not there locally, try the wxPython lib. + from wx.lib.agw import ultimatelistctrl as ULC + +#--------------------------------------------------------------------------- + +catalog = {} +index = [] + +folder = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABGdBTUEAANkE3LLaAgAABI5J" + "REFUeJztls+LHEUUxz+vqntmYgL+RCFoEPyFR6/r1Vs8ehRviwTBq4f8B+rBePCg+QM0gig5" + "qFFERFdFQSNiiCRqyK5r1nVNsjuZ6ep673nontmJ6Uk25iLig0dR1d31/bxvdVU3/EciALv/" + "yYPSNXjw4MHF/fv3v3pDSDOxsLDQqdMZbz5323vublVV+Xg89pSS55z9RmJpacn7/f69XXrF" + "FQOR+1NKsry8jLsTQiCEQIzxigwxEttrYaYV6Sz4Cq3OQTeX7996mrKMqBnuDg7mBg7guF/+" + "jAiEIDz4+Cv0ej2KopgHcW0ANWffY4e44/Y9WK6ZvibT+bYn9pl+nTO/fHmYvY88xWAwoCzL" + "HUF02uKAjzfZ2tgAd1wVN8VdcbWmNWfqhgi4M/r1BKOHK4qimC7JtSA6AQRwzbgmMMfdGogJ" + "gCluTWuquDuj9d8Y/r5CykrOeSoeY7x+AABM8VQ1jljjAGbQthMITMEh0PRTXaOqmBmq+g8B" + "TBmdOwNEXHMrbFMQNwM3UJ0CoAncUdUpwKz9VVV1SoXOUTfWv3qXvLmBWG4m1wo0IZoQrSBX" + "0zG0ImgCHFObVm+TXXSV6AQQN9Jvpzh//MOmiroRFB3PgFQNTK6QnBBLiBtqDcAsBECv1+t8" + "G7sdsExZCsPvjlGtnCBE2qpTI5arFmA7g7UOzAAAxBhZXV09lVIaXR9AcEpPXPz8DfTCOQJO" + "mAhaRcip6VtTfbCEW7P+ua3czDh8+PDygQMHXgT+2DmAZwpqBrt6hOEawy9ex4frBHFExwRN" + "iDVLEDQR8pgoxu7BXVwaDkkpUZYlR48eXVlcXHx2bW3tCLBTBxyxTEGmF2kgNleovj6Cnz9L" + "jEJoKw5WNaljAs5d9zwAP7zA5vmLpJQ4ffr0D8AHwJ+dhc5zQDxTkumX0kAMehSjdfT42/jy" + "N0RPRIxozTIESwSUfp15aN+jDD9/hosXLmJmNTCeJw7zTkJTSqnxguYFFKAowWv850/x9VOE" + "Ox+EPXcgIjgZ8Qyu+OpP3Kp7GW4NyTkHIAJ5xwC7b7k7Bq8pJOOlNHdImwTwAONzcGYNBrcS" + "9tyJD26B2AcCEgW9NGY0HKJmMs/luQBBfJDWz3BTkWHwdwDaL1UBBtR/wsYGYhEJfQh9XARJ" + "GbXmVGTOX9dcgNGFFRVqKHMjFtsaLgOgASgjKFBDyGMkjcEyQXehZqhd/RTsBGiQK7yoIUgD" + "MGvkBEBbCG0h64AEiDkilTdfSdMbAChzozxxoAtgkmE7RUDaE5FrrP8cAIdg0PNtByZLIGzb" + "P6k+zwAISBBCKeScOXt2ecjkx+m6HIjgPSAIUgoSZRtiFiC3WQARDENdqerMyy8d+vH9j44d" + "ae+8LgDbXP2WrbXjF+pYIP1eiP1BDGURRKKIBMEEUQFFrDK3UbY8rDRtVRqHl/LyuX7xyccn" + "D9V1/VHr084BPjtZLY7rd57fVdx8XyyMEJ1YjoIEIwR3EXd3TFoXXHEy1u4GCfTK/a9tPQEc" + "u5rwJObt0b1LS0tPdl1YWFj4YAfzfrMT8f/jXxF/AROfMsX0/mQPAAAAAElFTkSuQmCC") +index.append('folder') +catalog['folder'] = folder + +#---------------------------------------------------------------------- +movie = PyEmbeddedImage( + "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" + "Zj7VD/wb8xLWxx63hcwAAAAASUVORK5CYII=") +index.append('movie') +catalog['movie'] = movie + + +PIPE_HEIGHT = 18 +PIPE_WIDTH = 2000 + +class MacRenderer(object): + + DONE_BITMAP = None + REMAINING_BITMAP = None + + def __init__(self, parent): + + self.progressValue = random.randint(1, 99) + + + def DrawSubItem(self, dc, rect, line, highlighted, enabled): + """Draw a custom progress bar using double buffering to prevent flicker""" + + canvas = wx.EmptyBitmap(rect.width, rect.height) + mdc = wx.MemoryDC() + mdc.SelectObject(canvas) + + if highlighted: + mdc.SetBackground(wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))) + mdc.SetTextForeground(wx.WHITE) + else: + mdc.SetBackground(wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))) + mdc.Clear() + + mdc.SetFont(wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + + if line == 0: + text1 = "Apple Ads" + text2 = "2.67 MB of 11.9 MB selected (22.53%) - 5 min 13 sec remaining" + text3 = "Downloading from 1 of 1 peer - DL: 30.0 KB/s, UL: 0.0 KB/s" + progress = 22.53 + else: + text1 = "Apple TV Intro (HD).mov" + text2 = "13.4 MB, uploaded 8.65 MB (Ratio: 0.64) - 1 hr 23 min remaining" + text3 = "Seeding to 1 of 1 peer - UL: 12.0 KB/s" + progress = 18.0 + + ypos = 5 + xtext, ytext = mdc.GetTextExtent(text1) + mdc.DrawText(text1, 0, ypos) + ypos += ytext + 5 + + mdc.SetFont(wx.Font(7, wx.SWISS, wx.NORMAL, wx.NORMAL, False)) + + xtext, ytext = mdc.GetTextExtent(text2) + mdc.DrawText(text2, 0, ypos) + ypos += ytext + 5 + + self.DrawProgressBar(mdc, 0, ypos, rect.width, 20, progress) + + mdc.SetFont(wx.Font(7, wx.SWISS, wx.NORMAL, wx.NORMAL, False)) + ypos += 25 + + mdc.DrawText(text3, 0, ypos) + dc.Blit(rect.x+3, rect.y, rect.width-6, rect.height, mdc, 0, 0) + + + def GetLineHeight(self): + + dc = wx.MemoryDC() + dc.SelectObject(wx.EmptyBitmap(1, 1)) + dc.SetFont(wx.Font(9, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + dummy, ytext1 = dc.GetTextExtent("Agw") + dc.SetFont(wx.Font(7, wx.SWISS, wx.NORMAL, wx.NORMAL, False)) + dummy, ytext2 = dc.GetTextExtent("Agw") + + dc.SelectObject(wx.NullBitmap) + return ytext1 + 2*ytext2 + 40 + + + def GetSubItemWidth(self): + + return 250 + + + def DrawHorizontalPipe(self, dc, x, y, w, colour): + """Draws a horizontal 3D-looking pipe.""" + + for r in range(PIPE_HEIGHT): + red = int(colour.Red() * math.sin((math.pi/PIPE_HEIGHT)*r)) + green = int(colour.Green() * math.sin((math.pi/PIPE_HEIGHT)*r)) + blue = int(colour.Blue() * math.sin((math.pi/PIPE_HEIGHT)*r)) + dc.SetPen(wx.Pen(wx.Colour(red, green, blue))) + dc.DrawLine(x, y+r, x+w, y+r) + + + def DrawProgressBar(self, dc, x, y, w, h, percent): + """ + Draws a progress bar in the (x,y,w,h) box that represents a progress of + 'percent'. The progress bar is only horizontal and it's height is constant + (PIPE_HEIGHT). The 'h' parameter is used to vertically center the progress + bar in the allotted space. + + The drawing is speed-optimized. Two bitmaps are created the first time this + function runs - one for the done (green) part of the progress bar and one for + the remaining (white) part. During normal operation the function just cuts + the necessary part of the two bitmaps and draws them. + """ + + # Create two pipes + if self.DONE_BITMAP is None: + self.DONE_BITMAP = wx.EmptyBitmap(PIPE_WIDTH, PIPE_HEIGHT) + mdc = wx.MemoryDC() + mdc.SelectObject(self.DONE_BITMAP) + self.DrawHorizontalPipe(mdc, 0, 0, PIPE_WIDTH, wx.GREEN) + mdc.SelectObject(wx.NullBitmap) + + self.REMAINING_BITMAP = wx.EmptyBitmap(PIPE_WIDTH, PIPE_HEIGHT) + mdc = wx.MemoryDC() + mdc.SelectObject(self.REMAINING_BITMAP) + self.DrawHorizontalPipe(mdc, 0, 0, PIPE_WIDTH, wx.RED) + self.DrawHorizontalPipe(mdc, 1, 0, PIPE_WIDTH-1, wx.WHITE) + mdc.SelectObject(wx.NullBitmap) + + # Center the progress bar vertically in the box supplied + y = y + (h - PIPE_HEIGHT)/2 + + if percent == 0: + middle = 0 + else: + middle = (w * percent)/100 + + if w < 1: + return + + if middle == 0: # not started + bitmap = self.REMAINING_BITMAP.GetSubBitmap((1, 0, w, PIPE_HEIGHT)) + dc.DrawBitmap(bitmap, x, y, False) + elif middle == w: # completed + bitmap = self.DONE_BITMAP.GetSubBitmap((0, 0, w, PIPE_HEIGHT)) + dc.DrawBitmap(bitmap, x, y, False) + else: # in progress + doneBitmap = self.DONE_BITMAP.GetSubBitmap((0, 0, middle, PIPE_HEIGHT)) + dc.DrawBitmap(doneBitmap, x, y, False) + remainingBitmap = self.REMAINING_BITMAP.GetSubBitmap((0, 0, w - middle, PIPE_HEIGHT)) + dc.DrawBitmap(remainingBitmap, x + middle, y, False) + + +class TestUltimateListCtrl(ULC.UltimateListCtrl, listmix.ListCtrlAutoWidthMixin): + + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, agwStyle=0): + + ULC.UltimateListCtrl.__init__(self, parent, id, pos, size, style, agwStyle) + listmix.ListCtrlAutoWidthMixin.__init__(self) + + +class UltimateListCtrlPanel(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS) + + sizer = wx.BoxSizer(wx.VERTICAL) + + self.log = log + self.il = wx.ImageList(32, 32) + + self.il.Add(folder.GetBitmap()) + self.il.Add(movie.GetBitmap()) + + self.list = TestUltimateListCtrl(self, -1, + agwStyle=wx.LC_REPORT + | wx.BORDER_SUNKEN + #| wx.BORDER_NONE + #| wx.LC_SORT_ASCENDING + #| wx.LC_NO_HEADER + #| wx.LC_VRULES + | wx.LC_HRULES + #| wx.LC_SINGLE_SEL + | ULC.ULC_HAS_VARIABLE_ROW_HEIGHT) + + self.list.SetImageList(self.il, wx.IMAGE_LIST_SMALL) + sizer.Add(self.list, 1, wx.EXPAND) + + self.PopulateList() + self.SetSizer(sizer) + self.SetAutoLayout(True) + + self.Bind(wx.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, self.list) + + + def PopulateList(self): + + self.list.Freeze() + + info = ULC.UltimateListItem() + info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT + info._format = 0 + info._text = "" + + self.list.InsertColumnInfo(0, info) + + info = ULC.UltimateListItem() + info._format = wx.LIST_FORMAT_LEFT + info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT + info._image = [] + info._text = "Some useful info here" + + self.list.InsertColumnInfo(1, info) + + for i in xrange(2): + index = self.list.InsertImageStringItem(sys.maxint, "", [i]) + self.list.SetStringItem(index, 1, "") + klass = MacRenderer(self) + self.list.SetItemCustomRenderer(index, 1, klass) + + self.list.SetColumnWidth(0, 34) + self.list.SetColumnWidth(1, 300) + self.list.Thaw() + self.list.Update() + + + def OnColBeginDrag(self, event): + + if event.GetColumn() == 0: + event.Veto() + return + + event.Skip() + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent, -1, "UltimateListCtrl in torrent style :-D", size=(800, 600)) + + self.log = log + # Create the CustomTreeCtrl, using a derived class defined below + self.ulc = UltimateListCtrlPanel(self, self.log) + + self.SetIcon(images.Mondrian.GetIcon()) + self.CenterOnScreen() + self.Show() + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.App(0) + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + + diff --git a/demo/agw/MultiDirDialog.py b/demo/agw/MultiDirDialog.py new file mode 100644 index 00000000..85f47e52 --- /dev/null +++ b/demo/agw/MultiDirDialog.py @@ -0,0 +1,115 @@ +import wx + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import multidirdialog as MDD +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.multidirdialog as MDD + +import images + + +class MultiDirDialogDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + + self.log = log + + self.mainPanel = wx.Panel(self) + self.dialogSizer_staticbox = wx.StaticBox(self.mainPanel, -1, "Dialog Styles") + + self.dd_multiple = wx.CheckBox(self.mainPanel, -1, "MDD.DD_MULTIPLE") + self.dd_must = wx.CheckBox(self.mainPanel, -1, "wx.DD_DIR_MUST_EXIST") + self.dd_new = wx.CheckBox(self.mainPanel, -1, "wx.DD_NEW_DIR_BUTTON") + + self.showDialog = wx.Button(self.mainPanel, -1, "Show MultiDirDialog") + + self.SetProperties() + self.DoLayout() + + self.Bind(wx.EVT_BUTTON, self.OnShowDialog, self.showDialog) + + + def SetProperties(self): + + self.showDialog.SetDefault() + + + def DoLayout(self): + + frameSizer = wx.BoxSizer(wx.VERTICAL) + panelSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer = wx.BoxSizer(wx.HORIZONTAL) + buttonSizer = wx.StaticBoxSizer(self.dialogSizer_staticbox, wx.VERTICAL) + buttonSizer.Add(self.dd_multiple, 0, wx.LEFT|wx.RIGHT|wx.TOP, 5) + buttonSizer.Add((0, 2), 0, 0, 0) + buttonSizer.Add(self.dd_must, 0, wx.LEFT|wx.RIGHT, 5) + buttonSizer.Add((0, 2), 0, 0, 0) + buttonSizer.Add(self.dd_new, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, 5) + + mainSizer.Add(buttonSizer, 0, wx.ALL|wx.EXPAND, 5) + mainSizer.Add((10, 0), 0, 0, 0) + mainSizer.Add(self.showDialog, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 5) + mainSizer.Add((10, 0), 0, 0, 0) + + panelSizer.Add(mainSizer, 0, wx.EXPAND) + self.mainPanel.SetSizer(panelSizer) + + frameSizer.Add(self.mainPanel, 1, wx.EXPAND) + self.SetSizer(frameSizer) + frameSizer.Layout() + + + def OnShowDialog(self, event): + + dlgStyle = 0 + for child in self.mainPanel.GetChildren(): + if isinstance(child, wx.CheckBox): + if child.GetValue(): + dlgStyle |= eval(child.GetLabel()) + + userPath = wx.StandardPaths.Get().GetUserDataDir() + dlg = MDD.MultiDirDialog(self, title="Custom MultiDirDialog :-D", defaultPath=userPath, + agwStyle=dlgStyle) + + dlg.SetIcon(images.Mondrian.GetIcon()) + if dlg.ShowModal() != wx.ID_OK: + self.log.write("You Cancelled The Dialog!\n") + dlg.Destroy() + return + + paths = dlg.GetPaths() + for indx, path in enumerate(paths): + self.log.write("Path %d: %s\n"%(indx+1, path)) + + dlg.Destroy() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = MultiDirDialogDemo(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = MDD.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/PeakMeter.py b/demo/agw/PeakMeter.py new file mode 100644 index 00000000..8a974d5b --- /dev/null +++ b/demo/agw/PeakMeter.py @@ -0,0 +1,191 @@ +import wx +import random + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import peakmeter as PM +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.peakmeter as PM + + +class PeakMeterCtrlDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + self.log = log + + self.mainPanel = wx.Panel(self) + + # Initialize Peak Meter control 1 + self.vertPeak = PM.PeakMeterCtrl(self.mainPanel, -1, style=wx.SIMPLE_BORDER, agwStyle=PM.PM_VERTICAL) + # Initialize Peak Meter control 2 + self.horzPeak = PM.PeakMeterCtrl(self.mainPanel, -1, style=wx.SUNKEN_BORDER, agwStyle=PM.PM_HORIZONTAL) + + self.startButton = wx.Button(self.mainPanel, -1, "Start") + self.stopButton = wx.Button(self.mainPanel, -1, "Stop") + self.staticLine = wx.StaticLine(self.mainPanel) + + self.gridCheck = wx.CheckBox(self.mainPanel, -1, "Show Grid") + self.falloffCheck = wx.CheckBox(self.mainPanel, -1, "Show Falloff Effect") + + colour = self.mainPanel.GetBackgroundColour() + self.backColour = wx.ColourPickerCtrl(self.mainPanel, col=colour) + self.lowColour = wx.ColourPickerCtrl(self.mainPanel, col=wx.GREEN) + self.mediumColour = wx.ColourPickerCtrl(self.mainPanel, col=wx.NamedColour("yellow")) + self.highColour = wx.ColourPickerCtrl(self.mainPanel, col=wx.RED) + + self.timer = wx.Timer(self) + + self.SetProperties() + self.DoLayout() + self.BindEvents() + + + def SetProperties(self): + + self.vertPeak.SetMeterBands(10, 15) + self.horzPeak.SetMeterBands(10, 15) + self.falloffCheck.SetValue(1) + + + def DoLayout(self): + + frameSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer = wx.BoxSizer(wx.VERTICAL) + horzSizer = wx.BoxSizer(wx.HORIZONTAL) + rightSizer = wx.BoxSizer(wx.VERTICAL) + bottomSizer = wx.BoxSizer(wx.HORIZONTAL) + checkSizer = wx.BoxSizer(wx.VERTICAL) + colourSizer = wx.FlexGridSizer(2, 4, 1, 10) + + horzSizer.Add(self.vertPeak, 0, wx.EXPAND|wx.ALL, 15) + horzSizer.Add(self.horzPeak, 0, wx.EXPAND|wx.ALL, 15) + + rightSizer.Add(self.startButton, 0, wx.ALL, 5) + rightSizer.Add(self.stopButton, 0, wx.LEFT|wx.RIGHT, 5) + horzSizer.Add(rightSizer, 0, wx.ALIGN_TOP|wx.ALL, 5) + horzSizer.Add((15, 0)) + + mainSizer.Add(horzSizer, 0, wx.EXPAND) + mainSizer.Add(self.staticLine, 0, wx.EXPAND|wx.ALL, 5) + + checkSizer.Add(self.gridCheck, 0, wx.EXPAND|wx.ALL, 5) + checkSizer.Add(self.falloffCheck, 0, wx.EXPAND|wx.LEFT|wx.BOTTOM, 5) + + labelBack = wx.StaticText(self.mainPanel, -1, "Background") + labelLow = wx.StaticText(self.mainPanel, -1, "Low Freq") + labelMed = wx.StaticText(self.mainPanel, -1, "Med Freq") + labelHigh = wx.StaticText(self.mainPanel, -1, "High Freq") + + colourSizer.Add(labelBack) + colourSizer.Add(labelLow) + colourSizer.Add(labelMed) + colourSizer.Add(labelHigh) + + colourSizer.Add(self.backColour, 0, wx.EXPAND) + colourSizer.Add(self.lowColour, 0, wx.EXPAND) + colourSizer.Add(self.mediumColour, 0, wx.EXPAND) + colourSizer.Add(self.highColour, 0, wx.EXPAND) + + bottomSizer.Add(checkSizer, 0, wx.EXPAND|wx.ALL, 5) + bottomSizer.Add((0, 0), 1, wx.EXPAND) + bottomSizer.Add(colourSizer, 0, wx.EXPAND|wx.ALL, 5) + bottomSizer.Add((0, 5)) + mainSizer.Add(bottomSizer, 0, wx.EXPAND|wx.BOTTOM|wx.RIGHT, 5) + + self.mainPanel.SetSizer(mainSizer) + mainSizer.Layout() + frameSizer.Add(self.mainPanel, 1, wx.EXPAND) + self.SetSizer(frameSizer) + frameSizer.Layout() + + + def BindEvents(self): + + self.Bind(wx.EVT_TIMER, self.OnTimer) + self.Bind(wx.EVT_CHECKBOX, self.OnGrid, self.gridCheck) + self.Bind(wx.EVT_CHECKBOX, self.OnFalloff, self.falloffCheck) + self.Bind(wx.EVT_BUTTON, self.OnStart, self.startButton) + self.Bind(wx.EVT_BUTTON, self.OnStop, self.stopButton) + + self.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnPickColour) + + + def OnTimer(self, event): + + # generate 15 random number and set them as data for the meter + nElements = 15 + arrayData = [] + + for i in xrange(nElements): + nRandom = random.randint(0, 100) + arrayData.append(nRandom) + + self.vertPeak.SetData(arrayData, 0, nElements) + self.horzPeak.SetData(arrayData, 0, nElements) + + + def OnGrid(self, event): + + self.vertPeak.ShowGrid(event.IsChecked()) + + + def OnFalloff(self, event): + + self.vertPeak.SetFalloffEffect(event.IsChecked()) + + + def OnStart(self, event): + + self.timer.Start(1000/2) # 2 fps + + self.vertPeak.Start(1000/18) # 18 fps + self.horzPeak.Start(1000/20) # 20 fps + + + def OnStop(self, event): + + self.timer.Stop() + self.vertPeak.Stop() + self.horzPeak.Stop() + + + def OnPickColour(self, event): + + obj = event.GetEventObject() + colour = event.GetColour() + if obj == self.backColour: + self.horzPeak.SetBackgroundColour(colour) + else: + low = self.lowColour.GetColour() + med = self.mediumColour.GetColour() + high = self.highColour.GetColour() + self.horzPeak.SetBandsColour(low, med, high) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = PeakMeterCtrlDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = PM.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/agw/PersistentControls.py b/demo/agw/PersistentControls.py new file mode 100644 index 00000000..1387732d --- /dev/null +++ b/demo/agw/PersistentControls.py @@ -0,0 +1,576 @@ +import wx +import os +import sys +import images +import random + +from wx.lib.expando import ExpandoTextCtrl +import wx.lib.agw.aui as AUI +import wx.lib.agw.floatspin as FS + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + import agw.persist as PM +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.persist as PM + +_sampleText1 = "wx.Frame with AUI perspective, wx.MenuBar, wx.ColourDialog, " \ + "wx.FindReplaceDialog, wx.FontDialog, wx.TextEntryDialog, " \ + "wx.ColourPickerCtrl, wx.DirPickerCtrl, wx.FilePickerCtrl, " \ + "AuiToolBar, wx.RadioBox, wx.ToggleButton, wx.ComboBox, " \ + "wx.Slider, wx.SpinCtrl, FloatSpin\n\n" \ + "PersistenceManager Style: PM.PM_DEFAULT_STYLE\n" + +_sampleText2 = "wx.Frame, wx.SplitterWindow, wx.TreeCtrl, wx.Notebook, " \ + "wx.CheckListBox, wx.CheckBox, wx.SearchCtrl, wx.TextCtrl, " \ + "wx.DatePickerCtrl, wx.Choice, AuiNotebook, wx.ListCtrl, " \ + "TreeListCtrl, wx.HtmlListBox\n\nPersistenceManager Style: " \ + "PM.PM_SAVE_RESTORE_TREE_LIST_SELECTIONS\n" + +_sampleList = ['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight'] +_sampleList2 = _sampleList + ['nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen'] + +_title = "PersistentControls for wxPython :-D " +_configFile1 = os.path.join(dirName, "Example1") +_configFile2 = os.path.join(dirName, "Example2") + + +ID_AuiToolBar = wx.ID_HIGHEST + 100 + + +class PersistentPanel(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + + mainSizer = wx.BoxSizer(wx.VERTICAL) + sizer = wx.FlexGridSizer(3, 2, 10, 10) + + btn1 = wx.Button(self, -1, "Example 1") + text1 = ExpandoTextCtrl(self, -1, _sampleText1, size=(300,-1), style=wx.TE_READONLY) + + btn2 = wx.Button(self, -1, "Example 2") + text2 = ExpandoTextCtrl(self, -1, _sampleText2, size=(300,-1), style=wx.TE_READONLY) + + sizer.Add(btn1, 0, wx.ALIGN_CENTER) + sizer.Add(text1, 1, wx.EXPAND) + + sizer.Add(btn2, 0, wx.ALIGN_CENTER) + sizer.Add(text2, 1, wx.EXPAND) + + sizer.AddGrowableCol(1) + mainSizer.Add(sizer, 1, wx.EXPAND|wx.ALL, 20) + self.SetSizer(mainSizer) + mainSizer.Layout() + + btn1.Bind(wx.EVT_BUTTON, self.OnExample1) + btn2.Bind(wx.EVT_BUTTON, self.OnExample2) + + + def OnExample1(self, event): + + frame = PersistentFrame1(self, _title + "- Example 1", (700, 500)) + + + def OnExample2(self, event): + + frame = PersistentFrame2(self, _title + "- Example 2", (700, 500)) + + +class PersistentFrame1(wx.Frame): + + def __init__(self, parent, title, size): + + wx.Frame.__init__(self, parent, -1, title, size=size, name="Example1") + + self._auiMgr = AUI.AuiManager() + self._auiMgr.SetManagedWindow(self) + + self._persistMgr = PM.PersistenceManager.Get() + self._persistMgr.SetPersistenceFile(_configFile1) + + self.CreateMenuBar() + self.CreateAuiToolBar() + + self.BuildPanes() + + self.SetIcon(images.Mondrian.Icon) + self.CenterOnParent() + self.Show() + + self.Bind(wx.EVT_CLOSE, self.OnClose) + wx.CallAfter(self.RegisterControls) + + + def CreateMenuBar(self): + + # Prepare the menu bar + menuBar = wx.MenuBar() + menuBar.SetName("MenuBar1") + + # 1st menu from left + menu1 = wx.Menu() + menu1.Append(101, "wx.Colo&urDialog") + menu1.Append(102, "wx.F&ontDialog") + menu1.AppendSeparator() + menu1.Append(103, "wx.&TextEntryDialog") + menu1.AppendSeparator() + menu1.Append(105, "&Close", "Close this frame") + # Add menu to the menu bar + menuBar.Append(menu1, "&Dialogs") + + menu2 = wx.Menu() + # Radio items + menu2.Append(201, "Radio 1-1", "", wx.ITEM_RADIO) + menu2.Append(202, "Radio 1-2", "", wx.ITEM_RADIO) + menu2.Append(203, "Radio 1-3", "", wx.ITEM_RADIO) + menu2.AppendSeparator() + menu2.Append(204, "Radio 2-1", "", wx.ITEM_RADIO) + menu2.Append(205, "Radio 2-2", "", wx.ITEM_RADIO) + menuBar.Append(menu2, "&Radio Items") + + menu3 = wx.Menu() + # Check menu items + menu3.Append(301, "Check 1", "", wx.ITEM_CHECK) + menu3.Append(302, "Check 2", "", wx.ITEM_CHECK) + menu3.Append(303, "Check 3", "", wx.ITEM_CHECK) + menuBar.Append(menu3, "Chec&k Items") + + self.SetMenuBar(menuBar) + + self.Bind(wx.EVT_MENU_RANGE, self.OnDialogs, id=101, id2=103) + self.Bind(wx.EVT_MENU, self.CloseWindow, id=105) + + + def CreateAuiToolBar(self): + + tb3 = AUI.AuiToolBar(self, -1, wx.DefaultPosition, wx.DefaultSize, AUI.AUI_TB_DEFAULT_STYLE) + tb3.SetName("AuiToolBar") + tb3.SetToolBitmapSize(wx.Size(16, 16)) + + tb3_bmp1 = wx.ArtProvider.GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, wx.Size(16, 16)) + tb3.AddSimpleTool(ID_AuiToolBar, "Check 1", tb3_bmp1, "Check 1", AUI.ITEM_CHECK) + tb3.AddSimpleTool(ID_AuiToolBar+1, "Check 2", tb3_bmp1, "Check 2", AUI.ITEM_CHECK) + tb3.AddSimpleTool(ID_AuiToolBar+2, "Check 3", tb3_bmp1, "Check 3", AUI.ITEM_CHECK) + tb3.AddSimpleTool(ID_AuiToolBar+3, "Check 4", tb3_bmp1, "Check 4", AUI.ITEM_CHECK) + tb3.AddSeparator() + tb3.AddSimpleTool(ID_AuiToolBar+4, "Radio 1", tb3_bmp1, "Radio 1", AUI.ITEM_RADIO) + tb3.AddSimpleTool(ID_AuiToolBar+5, "Radio 2", tb3_bmp1, "Radio 2", AUI.ITEM_RADIO) + tb3.AddSimpleTool(ID_AuiToolBar+6, "Radio 3", tb3_bmp1, "Radio 3", AUI.ITEM_RADIO) + tb3.AddSeparator() + tb3.AddSimpleTool(ID_AuiToolBar+7, "Radio 1 (Group 2)", tb3_bmp1, "Radio 1 (Group 2)", AUI.ITEM_RADIO) + tb3.AddSimpleTool(ID_AuiToolBar+8, "Radio 2 (Group 2)", tb3_bmp1, "Radio 2 (Group 2)", AUI.ITEM_RADIO) + tb3.AddSimpleTool(ID_AuiToolBar+9, "Radio 3 (Group 2)", tb3_bmp1, "Radio 3 (Group 2)", AUI.ITEM_RADIO) + + tb3.Realize() + + self._auiMgr.AddPane(tb3, AUI.AuiPaneInfo().Name("tb3").Caption("AuiToolbar").ToolbarPane().Top()) + + + def BuildPanes(self): + + pickerPanel = wx.Panel(self) + + box1 = wx.BoxSizer(wx.VERTICAL) + fgs = wx.FlexGridSizer(cols=2, hgap=5, vgap=5) + + fgs.Add(wx.StaticText(pickerPanel, -1, "wx.ColourPickerCtrl:"), 0, wx.ALIGN_CENTER_VERTICAL) + cp1 = wx.ColourPickerCtrl(pickerPanel, name="ColourPicker1") + fgs.Add(cp1, 0, wx.ALIGN_CENTER) + fgs.Add(wx.StaticText(pickerPanel, -1, " with label:"), 0, wx.ALIGN_CENTER_VERTICAL) + cp3 = wx.ColourPickerCtrl(pickerPanel, style=wx.CLRP_SHOW_LABEL, name="ColourPicker2") + fgs.Add(cp3, 0, wx.ALIGN_CENTER) + + fgs.Add(wx.StaticText(pickerPanel, -1, "wx.DirPickerCtrl:"), 0, wx.ALIGN_CENTER_VERTICAL) + dp1 = wx.DirPickerCtrl(pickerPanel, name="DirPicker1") + fgs.Add(dp1, 0, wx.ALIGN_CENTER) + + fgs.Add(wx.StaticText(pickerPanel, -1, "wx.FilePickerCtrl:"), 0, wx.ALIGN_CENTER_VERTICAL) + fp1 = wx.FilePickerCtrl(pickerPanel, name="FilePicker1") + fgs.Add(fp1, 0, wx.ALIGN_CENTER) + + fgs.Add(wx.StaticText(pickerPanel, -1, "wx.FontPickerCtrl:"), 0, wx.ALIGN_CENTER_VERTICAL) + fnt1 = wx.FontPickerCtrl(pickerPanel, style=wx.FNTP_FONTDESC_AS_LABEL, name="FontPicker1") + fgs.Add(fnt1, 0, wx.ALIGN_CENTER) + + box1.Add(fgs, 1, wx.EXPAND|wx.ALL, 5) + pickerPanel.SetSizer(box1) + box1.Layout() + + otherPanel = wx.Panel(self) + box2 = wx.BoxSizer(wx.VERTICAL) + + radiobox = wx.RadioBox(otherPanel, -1, "RadioBox", choices=_sampleList, majorDimension=2, + style=wx.RA_SPECIFY_COLS, name="RadioBox1") + toggle = wx.ToggleButton(otherPanel, -1, "ToggleButton", name="Toggle1") + combo = wx.ComboBox(otherPanel, -1, choices=_sampleList, style=wx.CB_DROPDOWN|wx.CB_READONLY, + name="ComboBox1") + + boldFont = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "") + + box2 = wx.BoxSizer(wx.HORIZONTAL) + box2.Add((0, 0), 1) + box2.Add(radiobox, 0, wx.ALL|wx.ALIGN_CENTER, 5) + box2.Add((20, 0)) + + sizer_1 = wx.BoxSizer(wx.VERTICAL) + sizer_1.Add((20, 20), 1) + sizer_1.Add(toggle, 0, wx.ALL, 5) + sizer_1.Add((0, 10)) + label_1 = wx.StaticText(otherPanel, -1, "ComboBox") + label_1.SetFont(boldFont) + sizer_1.Add(label_1, 0, wx.ALL, 5) + sizer_1.Add(combo, 0, wx.LEFT|wx.RIGHT, 5) + sizer_1.Add((20, 20), 1) + box2.Add(sizer_1, 1, wx.EXPAND|wx.ALIGN_CENTER, 0) + box2.Add((0, 0), 1, 1) + + otherPanel.SetSizer(box2) + + otherPanel2 = wx.Panel(self) + box3 = wx.BoxSizer(wx.VERTICAL) + + gs1 = wx.FlexGridSizer(2, 3, 5, 10) + + slider = wx.Slider(otherPanel2, -1, 3, 0, 10, style=wx.SL_HORIZONTAL|wx.SL_LABELS, + name="Slider1") + spinctrl = wx.SpinCtrl(otherPanel2, -1, "20", min=0, max=100, name="SpinCtrl1") + floatspin = FS.FloatSpin(otherPanel2, -1, value=150, min_val=20, max_val=200, name="FloatSpin1") + floatspin.SetDigits(2) + + label_2 = wx.StaticText(otherPanel2, -1, "Slider") + label_2.SetFont(boldFont) + gs1.Add(label_2, 0, wx.ALIGN_CENTER_VERTICAL, 0) + label_3 = wx.StaticText(otherPanel2, -1, "SpinCtrl") + label_3.SetFont(boldFont) + gs1.Add(label_3, 0, wx.ALIGN_CENTER_VERTICAL, 0) + label_4 = wx.StaticText(otherPanel2, -1, "FloatSpin") + label_4.SetFont(boldFont) + gs1.Add(label_4, 0, wx.ALIGN_CENTER_VERTICAL, 0) + gs1.Add(slider, 0, wx.ALIGN_CENTER_VERTICAL, 0) + gs1.Add(spinctrl, 0, wx.ALIGN_CENTER_VERTICAL, 0) + gs1.Add(floatspin, 0, wx.ALIGN_CENTER_VERTICAL, 0) + gs1.AddGrowableCol(0) + gs1.AddGrowableCol(1) + gs1.AddGrowableCol(2) + box3.Add(gs1, 1, wx.EXPAND|wx.ALL, 5) + otherPanel2.SetSizer(box3) + + self._auiMgr.AddPane(pickerPanel, AUI.AuiPaneInfo().Name("DummyPanel1").Caption("Pickers"). + Left().MinSize(wx.Size(300, -1)).FloatingSize(wx.Size(300, 300))) + self._auiMgr.AddPane(otherPanel, AUI.AuiPaneInfo().Name("DummyPanel2").CenterPane()) + self._auiMgr.AddPane(otherPanel2, AUI.AuiPaneInfo().Name("DummyPanel3").Bottom(). + BestSize(wx.Size(-1, 200)).Caption("Slider & Spins"). + FloatingSize(wx.Size(300, 300))) + self._auiMgr.Update() + + + def RegisterControls(self): + + self.Freeze() + self.Register() + self.Thaw() + + + def Register(self, children=None): + + if children is None: + self._persistMgr.RegisterAndRestore(self) + self._persistMgr.RegisterAndRestore(self.GetMenuBar()) + children = self.GetChildren() + + for child in children: + + name = child.GetName() + + if name not in PM.BAD_DEFAULT_NAMES and "widget" not in name and \ + "wxSpinButton" not in name and "auiFloating" not in name and \ + "AuiTabCtrl" not in name and "AuiNotebook" not in name: + self._persistMgr.RegisterAndRestore(child) + + if child.GetChildren(): + self.Register(child.GetChildren()) + + + def CloseWindow(self, event): + + self.Close() + + + def OnClose(self, event): + + self._persistMgr.SaveAndUnregister() + event.Skip() + + + def OnDialogs(self, event): + + evId = event.GetId() + + if evId == 101: + # wx.ColourDialog + data = wx.ColourData() + dlg = wx.ColourDialog(self, data) + dlg.SetName("ColourDialog1") + + elif evId == 102: + # wx.FontDialog + data = wx.FontData() + dlg = wx.FontDialog(self, data) + dlg.SetName("FontDialog1") + + elif evId == 103: + # wx.TextEntryDialog + dlg = wx.TextEntryDialog(self, 'What is your favorite programming language?', + 'Eh??', 'Python') + dlg.SetValue("Python is the best!") + dlg.SetName("TextEntryDialog1") + + self._persistMgr.RegisterAndRestore(dlg) + + if dlg.ShowModal() == wx.ID_OK: + self._persistMgr.Save(dlg) + + self._persistMgr.Unregister(dlg) + dlg.Destroy() + + +# The wx.HtmlListBox derives from wx.VListBox, but draws each item +# itself as a wx.HtmlCell. +class MyHtmlListBox(wx.HtmlListBox): + + def OnGetItem(self, n): + if n % 2 == 0: + return "This is item# %d" % n + else: + return "This is item# %d
Any HTML is okay." % n + + +class PersistentFrame2(wx.Frame): + + def __init__(self, parent, title, size): + + wx.Frame.__init__(self, parent, -1, title, size=size, name="Example2") + + self._persistMgr = PM.PersistenceManager.Get() + self._persistMgr.SetManagerStyle(PM.PM_DEFAULT_STYLE|PM.PM_SAVE_RESTORE_TREE_LIST_SELECTIONS) + self._persistMgr.SetPersistenceFile(_configFile2) + + self.split1 = wx.SplitterWindow(self, -1, style=wx.SP_3D|wx.SP_BORDER, name="Splitter1") + self.treectrl = self.CreateTreeListCtrl(False) + + self.split2 = wx.SplitterWindow(self.split1, -1, style=wx.SP_3D|wx.SP_BORDER, name="Splitter2") + self.notebook = wx.Notebook(self.split2, name="Notebook1") + dummyPanel = wx.Panel(self.split2) + + text = "Hello world!\nI am a simple wx.TextCtrl" \ + "I will remember my value if you change it!" + + self.checklistbox = wx.CheckListBox(dummyPanel, -1, choices=_sampleList2, name="CheckListBox1") + self.textctrl = wx.TextCtrl(dummyPanel, -1, text, style=wx.TE_MULTILINE, name="TextCtrl1") + self.searchctrl = wx.SearchCtrl(dummyPanel, -1, "", name="SearchCtrl1") + self.checkbox = wx.CheckBox(dummyPanel, -1, "CheckBox", name="CheckBox1") + self.datepickerctrl = wx.DatePickerCtrl(dummyPanel, style=wx.DP_DROPDOWN, name="DatePicker1") + self.choice = wx.Choice(dummyPanel, -1, choices=_sampleList, name="Choice1") + + self.split2.SplitHorizontally(self.notebook, dummyPanel) + self.split1.SplitVertically(self.treectrl, self.split2) + + self.DoLayout(dummyPanel) + self.SetIcon(images.Mondrian.Icon) + + self.Bind(wx.EVT_CLOSE, self.OnClose) + wx.CallAfter(self.RegisterControls) + + self.CenterOnParent() + self.Show() + + + def DoLayout(self, dummyPanel): + + sizer_5 = wx.BoxSizer(wx.HORIZONTAL) + sizer_6 = wx.BoxSizer(wx.VERTICAL) + + self.notebook.AddPage(self.CreateNotebook(), "AuiNotebook") + self.notebook.AddPage(self.CreateListCtrl(), "wx.ListCtrl") + self.notebook.AddPage(self.CreateTreeListCtrl(True), "TreeListCtrl") + self.notebook.AddPage(self.CreateHtmlListBox(), "wx.HtmlListBox") + + sizer_5.Add(self.checklistbox, 1, wx.EXPAND|wx.ALL, 5) + sizer_6.Add(self.textctrl, 1, wx.EXPAND|wx.BOTTOM, 10) + sizer_6.Add(self.searchctrl, 0, wx.BOTTOM, 10) + sizer_6.Add(self.checkbox, 0, wx.BOTTOM, 10) + sizer_6.Add(self.datepickerctrl, 0, wx.BOTTOM, 10) + sizer_6.Add(self.choice, 0, 0, 0) + sizer_5.Add(sizer_6, 1, wx.ALL|wx.EXPAND, 5) + + dummyPanel.SetSizer(sizer_5) + self.Layout() + + + def CreateNotebook(self): + + # create the notebook off-window to avoid flicker + ctrl = AUI.AuiNotebook(self.notebook, -1) + ctrl.SetName("AuiNotebook1") + page_bmp = wx.ArtProvider.GetBitmap(wx.ART_NORMAL_FILE, wx.ART_OTHER, wx.Size(16, 16)) + ctrl.AddPage(wx.Panel(ctrl), "Page 1", False, page_bmp) + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "Page 1", False, page_bmp) + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "Page 2") + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "Page 3") + + ctrl.AddPage(wx.TextCtrl(ctrl, -1, "Some more text", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE|wx.NO_BORDER), "Page 4") + + return ctrl + + + def CreateListCtrl(self): + + il = wx.ImageList(16, 16) + il.Add(images.Smiles.GetBitmap()) + + listCtrl = wx.ListCtrl(self.notebook, -1, style=wx.LC_REPORT|wx.SUNKEN_BORDER, name="ListCtrl1") + for col in xrange(6): + listCtrl.InsertColumn(col, "Column %d"%col) + + listCtrl.AssignImageList(il, wx.IMAGE_LIST_SMALL) + text = "Row: %d, Col: %d" + for row in xrange(30): + if random.randint(0, 1): + idx = listCtrl.InsertImageStringItem(sys.maxint, text%(row+1, 1), 0) + else: + idx = listCtrl.InsertStringItem(sys.maxint, text%(row+1, 1)) + + for col in xrange(1, 6): + listCtrl.SetStringItem(idx, col, text%(row+1, col+1), random.randint(0, 1)-1) + + return listCtrl + + + def CreateTreeListCtrl(self, isTreeList): + + if isTreeList: + treeList = wx.gizmos.TreeListCtrl(self.notebook, style=wx.TR_DEFAULT_STYLE|wx.TR_FULL_ROW_HIGHLIGHT| + wx.SUNKEN_BORDER|wx.TR_MULTIPLE, name="TreeList1") + else: + treeList = wx.TreeCtrl(self.split1, style=wx.TR_DEFAULT_STYLE|wx.SUNKEN_BORDER|wx.TR_MULTIPLE, + name="TreeCtrl1") + + il = wx.ImageList(16, 16) + fldridx = il.Add(wx.ArtProvider_GetBitmap(wx.ART_FOLDER, wx.ART_OTHER, (16, 16))) + smileidx = il.Add(images.Smiles.GetBitmap()) + + treeList.AssignImageList(il) + + if isTreeList: + # create some columns + treeList.AddColumn("Main column") + treeList.AddColumn("Column 1") + treeList.AddColumn("Column 2") + treeList.SetMainColumn(0) # the one with the tree in it... + treeList.SetColumnWidth(0, 175) + + root = treeList.AddRoot("The Root Item") + + if isTreeList: + treeList.SetItemText(root, "col 1 root", 1) + treeList.SetItemText(root, "col 2 root", 2) + + treeList.SetItemImage(root, fldridx) + + for x in range(15): + txt = "Item %d" % x + child = treeList.AppendItem(root, txt) + treeList.SetItemImage(child, smileidx) + if isTreeList: + treeList.SetItemText(child, txt + "(c1)", 1) + treeList.SetItemText(child, txt + "(c2)", 2) + + for y in range(5): + txt = "item %d-%s" % (x, chr(ord("a")+y)) + last = treeList.AppendItem(child, txt) + treeList.SetItemImage(last, fldridx) + if isTreeList: + treeList.SetItemText(last, txt + "(c1)", 1) + treeList.SetItemText(last, txt + "(c2)", 2) + + for z in range(5): + txt = "item %d-%s-%d" % (x, chr(ord("a")+y), z) + item = treeList.AppendItem(last, txt) + treeList.SetItemImage(item, smileidx) + if isTreeList: + treeList.SetItemText(item, txt + "(c1)", 1) + treeList.SetItemText(item, txt + "(c2)", 2) + + treeList.Expand(root) + return treeList + + + def CreateHtmlListBox(self): + + hlb = MyHtmlListBox(self.notebook, -1, style=wx.BORDER_SUNKEN|wx.LB_MULTIPLE, name="HtmlListBox1") + hlb.SetItemCount(300) + hlb.SetSelection(0) + + return hlb + + + def OnClose(self, event): + + self._persistMgr.SaveAndUnregister() + event.Skip() + + + def RegisterControls(self): + + self.Freeze() + self.Register() + self.Thaw() + + + def Register(self, children=None): + + if children is None: + self._persistMgr.RegisterAndRestore(self) + children = self.GetChildren() + + for child in children: + + name = child.GetName() + + if name not in PM.BAD_DEFAULT_NAMES and "wxtreelist" not in name and \ + "AuiTabCtrl" not in name: + self._persistMgr.RegisterAndRestore(child) + + if child.GetChildren(): + self.Register(child.GetChildren()) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + + win = PersistentPanel(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = PM.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/agw/PieCtrl.py b/demo/agw/PieCtrl.py new file mode 100644 index 00000000..e242c97c --- /dev/null +++ b/demo/agw/PieCtrl.py @@ -0,0 +1,200 @@ +import wx +from math import pi + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + import agw.piectrl + from agw.piectrl import PieCtrl, ProgressPie, PiePart + docs = agw.piectrl.__doc__ +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.piectrl + from wx.lib.agw.piectrl import PieCtrl, ProgressPie, PiePart + docs = wx.lib.agw.piectrl.__doc__ + +#---------------------------------------------------------------------- +# Auxiliary Timer Class For The Demo (For The ProgressPie) +#---------------------------------------------------------------------- + +class MyTimer(wx.Timer): + + + def __init__(self, parent): + + wx.Timer.__init__(self) + self._parent = parent + + + def Notify(self): + + if self._parent._progresspie.GetValue() <= 0: + self._parent._incr = 1 + + if self._parent._progresspie.GetValue() >= self._parent._progresspie.GetMaxValue(): + self._parent._incr = -1 + + self._parent._progresspie.SetValue(self._parent._progresspie.GetValue() + self._parent._incr) + self._parent._progresspie.Refresh() + + +#---------------------------------------------------------------------- +# Beginning Of PIECTRL Demo wxPython Code +#---------------------------------------------------------------------- + +class PieCtrlDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + + self.log = log + # Create Some Maquillage For The Demo: Icon, StatusBar, MenuBar... + + panel = wx.Panel(self, -1) + self._incr = 1 + self._hiddenlegend = False + + panel.SetBackgroundColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNFACE)) + + # Create A Simple PieCtrl With 3 Sectors + self._pie = PieCtrl(panel, -1, wx.DefaultPosition, wx.Size(180,270)) + + self._pie.GetLegend().SetTransparent(True) + self._pie.GetLegend().SetHorizontalBorder(10) + self._pie.GetLegend().SetWindowStyle(wx.STATIC_BORDER) + self._pie.GetLegend().SetLabelFont(wx.Font(10, wx.FONTFAMILY_DEFAULT, + wx.FONTSTYLE_NORMAL, + wx.FONTWEIGHT_NORMAL, + False, "Courier New")) + self._pie.GetLegend().SetLabelColour(wx.Colour(0, 0, 127)) + + self._pie.SetHeight(30) + + part = PiePart() + + part.SetLabel("SeriesLabel_1") + part.SetValue(300) + part.SetColour(wx.Colour(200, 50, 50)) + self._pie._series.append(part) + + part = PiePart() + part.SetLabel("Series Label 2") + part.SetValue(200) + part.SetColour(wx.Colour(50, 200, 50)) + self._pie._series.append(part) + + part = PiePart() + part.SetLabel("HelloWorld Label 3") + part.SetValue(50) + part.SetColour(wx.Colour(50, 50, 200)) + self._pie._series.append(part) + + # Create A ProgressPie + self._progresspie = ProgressPie(panel, 100, 50, -1, wx.DefaultPosition, + wx.Size(180, 200), wx.SIMPLE_BORDER) + + self._progresspie.SetBackColour(wx.Colour(150, 200, 255)) + self._progresspie.SetFilledColour(wx.Colour(255, 0, 0)) + self._progresspie.SetUnfilledColour(wx.WHITE) + self._progresspie.SetHeight(20) + + self._slider = wx.Slider(panel, -1, 25, 0, 90, wx.DefaultPosition, wx.DefaultSize, wx.SL_VERTICAL | wx.SL_LABELS) + self._angleslider = wx.Slider(panel, -1, 200, 0, 360, wx.DefaultPosition, wx.DefaultSize, wx.SL_LABELS | wx.SL_TOP) + sizer = wx.BoxSizer(wx.VERTICAL) + hsizer = wx.BoxSizer(wx.HORIZONTAL) + btnsizer = wx.BoxSizer(wx.HORIZONTAL) + panel.SetSizer(sizer) + + hsizer.Add(self._progresspie, 1, wx.EXPAND | wx.ALL, 5) + hsizer.Add(self._pie, 1, wx.EXPAND | wx.ALL, 5) + hsizer.Add(self._slider, 0, wx.GROW | wx.ALL, 5) + + btn1 = wx.Button(panel, -1, "Toggle Legend Transparency") + btn2 = wx.Button(panel, -1, "Toggle Edges") + btn3 = wx.Button(panel, -1, "Hide Legend") + btnsizer.Add(btn1, 0, wx.ALL, 5) + btnsizer.Add(btn2, 0, wx.ALL, 5) + btnsizer.Add(btn3, 0, wx.ALL, 5) + + sizer.Add(hsizer, 1, wx.EXPAND | wx.ALL, 5) + sizer.Add(self._angleslider, 0, wx.GROW | wx.ALL, 5) + sizer.Add(btnsizer, 0, wx.ALIGN_RIGHT | wx.BOTTOM | wx.LEFT | wx.RIGHT, 5) + + mainSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer.Add(panel, 1, wx.EXPAND) + self.SetSizer(mainSizer) + mainSizer.Layout() + + self._timer = MyTimer(self) + self._timer.Start(50) + + self._slider.Bind(wx.EVT_SLIDER, self.OnSlider) + self._angleslider.Bind(wx.EVT_SLIDER, self.OnAngleSlider) + btn1.Bind(wx.EVT_BUTTON, self.OnToggleTransparency) + btn2.Bind(wx.EVT_BUTTON, self.OnToggleEdges) + btn3.Bind(wx.EVT_BUTTON, self.OnToggleLegend) + + self.OnAngleSlider(None) + self.OnSlider(None) + + + def OnToggleTransparency(self, event): + + self._pie.GetLegend().SetTransparent(not self._pie.GetLegend().IsTransparent()) + self._pie.Refresh() + + + def OnToggleEdges(self, event): + + self._pie.SetShowEdges(not self._pie.GetShowEdges()) + self._progresspie.SetShowEdges(not self._progresspie.GetShowEdges()) + + + def OnToggleLegend(self, event): + + self._hiddenlegend = not self._hiddenlegend + + if self._hiddenlegend: + self._pie.GetLegend().Hide() + else: + self._pie.GetLegend().Show() + + self._pie.Refresh() + + + def OnSlider(self, event): + + self._pie.SetAngle(float(self._slider.GetValue())/180.0*pi) + self._progresspie.SetAngle(float(self._slider.GetValue())/180.0*pi) + + + def OnAngleSlider(self, event): + + self._pie.SetRotationAngle(float(self._angleslider.GetValue())/180.0*pi) + self._progresspie.SetRotationAngle(float(self._angleslider.GetValue())/180.0*pi) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = PieCtrlDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = docs + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/agw/PyBusyInfo.py b/demo/agw/PyBusyInfo.py new file mode 100644 index 00000000..fee90ea3 --- /dev/null +++ b/demo/agw/PyBusyInfo.py @@ -0,0 +1,62 @@ +import wx + +import os +import sys + +import images + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import pybusyinfo as PBI +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.pybusyinfo as PBI + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test PyBusyInfo ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + + evt.Skip() + message = "Please wait 5 seconds, working..." + busy = PBI.PyBusyInfo(message, parent=None, title="Really Busy", + icon=images.Smiles.GetBitmap()) + + wx.Yield() + + for indx in xrange(5): + wx.MilliSleep(1000) + + del busy + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = PBI.__doc__ + + +if __name__ == '__main__': + import sys, os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/agw/PyCollapsiblePane.py b/demo/agw/PyCollapsiblePane.py new file mode 100644 index 00000000..63dc5239 --- /dev/null +++ b/demo/agw/PyCollapsiblePane.py @@ -0,0 +1,306 @@ +import wx +import wx.lib.buttons as buttons + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import pycollapsiblepane as PCP +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.pycollapsiblepane as PCP + +import images + +btnlbl1 = "call Expand(True)" +btnlbl2 = "call Expand(False)" + +choices = ["wx.Button", + "GenButton", + "GenBitmapButton", + "GenBitmapTextButton", + "ThemedGenButton", + "ThemedGenBitmapTextButton"] + +gtkChoices = ["3, 6", + "4, 8", + "5, 10"] + +styles = ["CP_NO_TLW_RESIZE", + "CP_LINE_ABOVE", + "CP_USE_STATICBOX", + "CP_GTK_EXPANDER"] + + +class PyCollapsiblePaneDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + + self.log = log + + self.label1 = "Click here to show pane" + self.label2 = "Click here to hide pane" + + title = wx.StaticText(self, label="PyCollapsiblePane") + title.SetFont(wx.Font(18, wx.SWISS, wx.NORMAL, wx.BOLD)) + title.SetForegroundColour("blue") + + self.cpStyle = wx.CP_NO_TLW_RESIZE + self.cp = cp = PCP.PyCollapsiblePane(self, label=self.label1, + agwStyle=self.cpStyle) + self.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged, cp) + self.MakePaneContent(cp.GetPane()) + + self.btnRB = radioBox = wx.RadioBox(self, -1, "Button Types", + choices=choices, style=wx.RA_SPECIFY_ROWS) + self.static1 = wx.StaticText(self, -1, "Collapsed Button Text:") + self.static2 = wx.StaticText(self, -1, "Expanded Button Text:") + + self.buttonText1 = wx.TextCtrl(self, -1, self.label1) + self.buttonText2 = wx.TextCtrl(self, -1, self.label2) + self.updateButton = wx.Button(self, -1, "Update!") + + sbox = wx.StaticBox(self, -1, 'Styles') + sboxsizer = wx.StaticBoxSizer(sbox, wx.VERTICAL) + self.styleCBs = list() + for styleName in styles: + cb = wx.CheckBox(self, -1, styleName) + if styleName == "CP_NO_TLW_RESIZE": + cb.SetValue(True) + cb.Disable() + cb.Bind(wx.EVT_CHECKBOX, self.OnStyleChoice) + self.styleCBs.append(cb) + sboxsizer.Add(cb, 0, wx.ALL, 4) + + self.gtkText = wx.StaticText(self, -1, "Expander Size") + self.gtkChoice = wx.ComboBox(self, -1, choices=gtkChoices) + self.gtkChoice.SetSelection(0) + + self.gtkText.Enable(False) + self.gtkChoice.Enable(False) + + sizer = wx.BoxSizer(wx.VERTICAL) + radioSizer = wx.BoxSizer(wx.HORIZONTAL) + dummySizer = wx.BoxSizer(wx.VERTICAL) + + dummySizer.Add(self.gtkText, 0, wx.EXPAND|wx.BOTTOM, 2) + dummySizer.Add(self.gtkChoice, 0, wx.EXPAND) + + radioSizer.Add(radioBox, 0, wx.EXPAND) + radioSizer.Add(sboxsizer, 0, wx.EXPAND|wx.LEFT, 10) + radioSizer.Add(dummySizer, 0, wx.ALIGN_BOTTOM|wx.LEFT, 10) + + self.SetSizer(sizer) + sizer.Add((0, 10)) + sizer.Add(title, 0, wx.LEFT|wx.RIGHT, 25) + sizer.Add((0, 10)) + sizer.Add(radioSizer, 0, wx.LEFT, 25) + + sizer.Add((0, 10)) + subSizer = wx.FlexGridSizer(2, 3, 5, 5) + subSizer.Add(self.static1, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5) + subSizer.Add(self.buttonText1, 0, wx.EXPAND) + subSizer.Add((0, 0)) + subSizer.Add(self.static2, 0, wx.LEFT|wx.ALIGN_CENTER_VERTICAL, 5) + subSizer.Add(self.buttonText2, 0, wx.EXPAND) + subSizer.Add(self.updateButton, 0, wx.LEFT|wx.RIGHT, 10) + + subSizer.AddGrowableCol(1) + + sizer.Add(subSizer, 0, wx.EXPAND|wx.LEFT, 20) + sizer.Add((0, 15)) + sizer.Add(cp, 0, wx.RIGHT|wx.LEFT|wx.EXPAND, 20) + + self.btn = wx.Button(self, label=btnlbl1) + sizer.Add(self.btn, 0, wx.ALL, 25) + + self.Bind(wx.EVT_BUTTON, self.OnToggle, self.btn) + self.Bind(wx.EVT_BUTTON, self.OnUpdate, self.updateButton) + self.Bind(wx.EVT_RADIOBOX, self.OnButtonChoice) + self.Bind(wx.EVT_COMBOBOX, self.OnUserChoice, self.gtkChoice) + + + def OnToggle(self, event): + + self.cp.Collapse(self.cp.IsExpanded()) + self.OnPaneChanged() + + + def OnUpdate(self, event): + + self.label1 = self.buttonText1.GetValue() + self.label2 = self.buttonText2.GetValue() + + self.OnPaneChanged(None) + + + def OnStyleChoice(self, evt): + style = 0 + for cb in self.styleCBs: + if cb.IsChecked(): + style |= getattr(wx, cb.GetLabel(), 0) + + self.cpStyle = style + self.Rebuild() + + + def OnButtonChoice(self, event): + + #self.gtkText.Enable(selection == 4) + #self.gtkChoice.Enable(selection == 4) + + self.Rebuild() + + + def MakeButton(self): + + if self.cpStyle & wx.CP_GTK_EXPANDER: + return None + + selection = self.btnRB.GetSelection() + + if selection == 0: # standard wx.Button + btn = wx.Button(self.cp, -1, self.label1) + elif selection == 1: # buttons.GenButton + btn = buttons.GenButton(self.cp, -1, self.label1) + elif selection == 2: # buttons.GenBitmapButton + bmp = images.Smiles.GetBitmap() + btn = buttons.GenBitmapButton(self.cp, -1, bmp) + elif selection == 3: # buttons.GenBitmapTextButton + bmp = images.Mondrian.GetBitmap() + btn = buttons.GenBitmapTextButton(self.cp, -1, bmp, self.label1) + elif selection == 4: # buttons.ThemedGenButton + btn = buttons.ThemedGenButton(self.cp, -1, self.label1) + elif selection == 5: # buttons.ThemedGenBitmapTextButton + bmp = images.Mondrian.GetBitmap() + btn = buttons.ThemedGenBitmapTextButton(self.cp, -1, bmp, self.label1) + + return btn + + + def Rebuild(self): + + isExpanded = self.cp.IsExpanded() + self.Freeze() + cp = PCP.PyCollapsiblePane(self, label=self.label1, agwStyle=self.cpStyle) + cp.Bind(wx.EVT_COLLAPSIBLEPANE_CHANGED, self.OnPaneChanged) + self.MakePaneContent(cp.GetPane()) + cp.SetExpanderDimensions(*self.GetUserSize()) + self.GetSizer().Replace(self.cp, cp) + self.cp.Destroy() + self.cp = cp + + btn = self.MakeButton() + if btn: + self.cp.SetButton(btn) + self.gtkText.Enable(btn is None) + self.gtkChoice.Enable(btn is None) + self.btnRB.Enable(btn is not None) + + if isExpanded: + self.cp.Expand() + self.Thaw() + + self.OnPaneChanged(None) + self.Layout() + + + def OnPaneChanged(self, event=None): + + if event: + self.log.write('wx.EVT_COLLAPSIBLEPANE_CHANGED: %s\n' % event.Collapsed) + + # redo the layout + self.Layout() + + # and also change the labels + if self.cp.IsExpanded(): + self.cp.SetLabel(self.label2) + self.btn.SetLabel(btnlbl2) + else: + self.cp.SetLabel(self.label1) + self.btn.SetLabel(btnlbl1) + + self.btn.SetInitialSize() + + + def OnUserChoice(self, event): + + self.cp.SetExpanderDimensions(*self.GetUserSize(event.GetSelection())) + + + def GetUserSize(self, selection=None): + + if selection is None: + selection = self.gtkChoice.GetSelection() + + choice = gtkChoices[selection] + width, height = choice.split(",") + + return int(width), int(height) + + + def MakePaneContent(self, pane): + '''Just make a few controls to put on the collapsible pane''' + + nameLbl = wx.StaticText(pane, -1, "Name:") + name = wx.TextCtrl(pane, -1, ""); + + addrLbl = wx.StaticText(pane, -1, "Address:") + addr1 = wx.TextCtrl(pane, -1, ""); + addr2 = wx.TextCtrl(pane, -1, ""); + + cstLbl = wx.StaticText(pane, -1, "City, State, Zip:") + city = wx.TextCtrl(pane, -1, "", size=(150,-1)); + state = wx.TextCtrl(pane, -1, "", size=(50,-1)); + zip = wx.TextCtrl(pane, -1, "", size=(70,-1)); + + addrSizer = wx.FlexGridSizer(cols=2, hgap=5, vgap=5) + addrSizer.AddGrowableCol(1) + addrSizer.Add(nameLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(name, 0, wx.EXPAND) + addrSizer.Add(addrLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + addrSizer.Add(addr1, 0, wx.EXPAND) + addrSizer.Add((5,5)) + addrSizer.Add(addr2, 0, wx.EXPAND) + + addrSizer.Add(cstLbl, 0, + wx.ALIGN_RIGHT|wx.ALIGN_CENTER_VERTICAL) + + cstSizer = wx.BoxSizer(wx.HORIZONTAL) + cstSizer.Add(city, 1) + cstSizer.Add(state, 0, wx.LEFT|wx.RIGHT, 5) + cstSizer.Add(zip) + addrSizer.Add(cstSizer, 0, wx.EXPAND) + + border = wx.BoxSizer() + border.Add(addrSizer, 1, wx.EXPAND|wx.ALL, 5) + pane.SetSizer(border) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = PyCollapsiblePaneDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = PCP.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/agw/PyGauge.py b/demo/agw/PyGauge.py new file mode 100644 index 00000000..a98833a1 --- /dev/null +++ b/demo/agw/PyGauge.py @@ -0,0 +1,162 @@ +import wx +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import pygauge as PG +except ImportError: # if it's not there locally, try the wxPython lib. + try: + import wx.lib.agw.pygauge as PG + except: + raise Exception("This demo requires wxPython version greater than 2.9.0.0") + + +class PyGaugeDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + self.log = log + + self.mainPanel = wx.Panel(self) + self.mainPanel.SetBackgroundColour(wx.WHITE) + + self.gauge1 = PG.PyGauge(self.mainPanel, -1, size=(100,25),style=wx.GA_HORIZONTAL) + self.gauge1.SetValue(80) + self.gauge1.SetBackgroundColour(wx.WHITE) + self.gauge1.SetBorderColor(wx.BLACK) + + self.gauge2 = PG.PyGauge(self.mainPanel, -1, size=(100,25),style=wx.GA_HORIZONTAL) + self.gauge2.SetValue([20,80]) + self.gauge2.SetBarColor([wx.Colour(162,255,178),wx.Colour(159,176,255)]) + self.gauge2.SetBackgroundColour(wx.WHITE) + self.gauge2.SetBorderColor(wx.BLACK) + self.gauge2.SetBorderPadding(2) + self.gauge2.SetDrawValue(draw=True, drawPercent=True, font=wx.SMALL_FONT, colour=wx.BLUE) + + self.gauge2.Update([30,0],2000) + + self.gauge3 = PG.PyGauge(self.mainPanel, -1, size=(100,25),style=wx.GA_HORIZONTAL) + self.gauge3.SetValue(50) + self.gauge3.SetBarColor(wx.GREEN) + self.gauge3.SetBackgroundColour(wx.WHITE) + self.gauge3.SetBorderColor(wx.BLACK) + + self.backColour = wx.ColourPickerCtrl(self.mainPanel, col=self.gauge3.GetBackgroundColour()) + self.borderColour = wx.ColourPickerCtrl(self.mainPanel, col=self.gauge3.GetBorderColour()) + self.barColour = wx.ColourPickerCtrl(self.mainPanel, col=self.gauge3.GetBarColour()) + self.gaugeValue = wx.TextCtrl(self.mainPanel, -1, str(self.gauge3.GetValue()), style=wx.TE_PROCESS_ENTER) + self.gaugeRange = wx.TextCtrl(self.mainPanel, -1, str(self.gauge3.GetRange()), style=wx.TE_PROCESS_ENTER) + self.gaugePadding = wx.TextCtrl(self.mainPanel, -1, str(self.gauge3.GetBorderPadding()), style=wx.TE_PROCESS_ENTER) + + self.DoLayout() + self.BindEvents() + + + def DoLayout(self): + + frameSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer = wx.BoxSizer(wx.VERTICAL) + + colourSizer = wx.FlexGridSizer(2, 6, 1, 10) + + label1 = wx.StaticText(self.mainPanel, -1, "Welcome to the PyGauge demo for wxPython!") + mainSizer.Add(label1, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10) + + mainSizer.Add(self.gauge1, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 20) + mainSizer.Add(self.gauge2, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 20) + mainSizer.Add(self.gauge3, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 20) + + labelBack = wx.StaticText(self.mainPanel, -1, "Background Colour") + labelHover = wx.StaticText(self.mainPanel, -1, "Border Colour") + labelText = wx.StaticText(self.mainPanel, -1, "Bar Colour") + labelValue = wx.StaticText(self.mainPanel, -1, "Gauge Value ") + labelRange = wx.StaticText(self.mainPanel, -1, "Gauge Range") + labelPadding = wx.StaticText(self.mainPanel, -1, "Border Padding") + + colourSizer.Add(labelBack) + colourSizer.Add(labelHover) + colourSizer.Add(labelText) + colourSizer.Add(labelValue) + colourSizer.Add(labelRange) + colourSizer.Add(labelPadding) + + colourSizer.Add(self.backColour, 0, wx.EXPAND) + colourSizer.Add(self.borderColour, 0, wx.EXPAND) + colourSizer.Add(self.barColour, 0, wx.EXPAND) + colourSizer.Add(self.gaugeValue, 0, wx.EXPAND) + colourSizer.Add(self.gaugeRange, 0, wx.EXPAND) + colourSizer.Add(self.gaugePadding, 0, wx.EXPAND) + + mainSizer.Add(colourSizer, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL|wx.LEFT|wx.RIGHT, 10) + + + boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + boldFont.SetWeight(wx.BOLD) + + for child in self.mainPanel.GetChildren(): + if isinstance(child, wx.StaticText): + child.SetFont(boldFont) + + self.mainPanel.SetSizer(mainSizer) + mainSizer.Layout() + frameSizer.Add(self.mainPanel, 1, wx.EXPAND) + self.SetSizer(frameSizer) + frameSizer.Layout() + + + def BindEvents(self): + + self.Bind(wx.EVT_COLOURPICKER_CHANGED, self.OnPickColour) + self.Bind(wx.EVT_TEXT_ENTER, self.OnEnter, self.gaugeValue) + self.Bind(wx.EVT_TEXT_ENTER, self.OnEnter, self.gaugeRange) + self.Bind(wx.EVT_TEXT_ENTER, self.OnEnter, self.gaugePadding) + + def OnEnter(self,event): + obj = event.GetEventObject() + if obj == self.gaugeValue: + self.gauge3.SetValue(int(self.gaugeValue.GetValue())) + if obj == self.gaugeRange: + self.gauge3.SetRange(int(self.gaugeRange.GetValue())) + if obj == self.gaugePadding: + self.gauge3.SetBorderPadding(int(self.gaugePadding.GetValue())) + self.gauge3.Refresh() + + + def OnPickColour(self, event): + + obj = event.GetEventObject() + colour = event.GetColour() + if obj == self.backColour: + self.gauge3.SetBackgroundColour(colour) + elif obj == self.borderColour: + self.gauge3.SetBorderColour(colour) + else: + self.gauge3.SetBarColour(colour) + + self.gauge3.Refresh() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = PyGaugeDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = PG.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/agw/PyProgress.py b/demo/agw/PyProgress.py new file mode 100644 index 00000000..1a87b5fb --- /dev/null +++ b/demo/agw/PyProgress.py @@ -0,0 +1,153 @@ +import wx +import wx.lib.colourselect as csel + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import pyprogress as PP +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.pyprogress as PP + + +class PyProgressDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent) + + self.panel = wx.Panel(self, -1) + self.log = log + + self.LayoutItems() + + + def LayoutItems(self): + + mainsizer = wx.BoxSizer(wx.HORIZONTAL) + rightsizer = wx.FlexGridSizer(7, 2, 5, 5) + + startbutton = wx.Button(self.panel, -1, "Start PyProgress!") + + self.elapsedchoice = wx.CheckBox(self.panel, -1, "Show Elapsed Time") + self.elapsedchoice.SetValue(1) + + self.cancelchoice = wx.CheckBox(self.panel, -1, "Enable Cancel Button") + self.cancelchoice.SetValue(1) + + static1 = wx.StaticText(self.panel, -1, "Gauge Proportion (%): ") + self.slider1 = wx.Slider(self.panel, -1, 20, 1, 99, style=wx.SL_HORIZONTAL| + wx.SL_AUTOTICKS|wx.SL_LABELS) + self.slider1.SetTickFreq(10, 1) + self.slider1.SetValue(20) + + static2 = wx.StaticText(self.panel, -1, "Gauge Steps: ") + self.slider2 = wx.Slider(self.panel, -1, 50, 2, 100, style=wx.SL_HORIZONTAL| + wx.SL_AUTOTICKS|wx.SL_LABELS) + self.slider2.SetTickFreq(10, 1) + self.slider2.SetValue(50) + + static3 = wx.StaticText(self.panel, -1, "Gauge Background Colour: ") + self.csel3 = csel.ColourSelect(self.panel, -1, "Choose...", wx.WHITE) + + static4 = wx.StaticText(self.panel, -1, "Gauge First Gradient Colour: ") + self.csel4 = csel.ColourSelect(self.panel, -1, "Choose...", wx.WHITE) + + static5 = wx.StaticText(self.panel, -1, "Gauge Second Gradient Colour: ") + self.csel5 = csel.ColourSelect(self.panel, -1, "Choose...", wx.BLUE) + + rightsizer.Add(self.elapsedchoice, 0, wx.EXPAND|wx.TOP, 10) + rightsizer.Add((10, 0)) + rightsizer.Add(self.cancelchoice, 0, wx.EXPAND|wx.TOP, 3) + rightsizer.Add((10, 0)) + rightsizer.Add(static1, 0, wx.ALIGN_CENTER_VERTICAL, 10) + rightsizer.Add(self.slider1, 0, wx.EXPAND|wx.TOP, 10) + rightsizer.Add(static2, 0, wx.ALIGN_CENTER_VERTICAL, 10) + rightsizer.Add(self.slider2, 0, wx.EXPAND|wx.TOP|wx.BOTTOM, 10) + rightsizer.Add(static3, 0, wx.ALIGN_CENTER_VERTICAL) + rightsizer.Add(self.csel3, 0) + rightsizer.Add(static4, 0, wx.ALIGN_CENTER_VERTICAL) + rightsizer.Add(self.csel4, 0) + rightsizer.Add(static5, 0, wx.ALIGN_CENTER_VERTICAL) + rightsizer.Add(self.csel5, 0) + + mainsizer.Add(startbutton, 0, wx.ALL, 20) + mainsizer.Add(rightsizer, 1, wx.EXPAND|wx.ALL, 10) + + self.panel.SetSizer(mainsizer) + mainsizer.Layout() + + framesizer = wx.BoxSizer(wx.VERTICAL) + framesizer.Add(self.panel, 1, wx.EXPAND) + self.SetSizer(framesizer) + framesizer.Layout() + + startbutton.Bind(wx.EVT_BUTTON, self.OnStartProgress) + + + def OnStartProgress(self, event): + + event.Skip() + + style = wx.PD_APP_MODAL + if self.elapsedchoice.GetValue(): + style |= wx.PD_ELAPSED_TIME + if self.cancelchoice.GetValue(): + style |= wx.PD_CAN_ABORT + + dlg = PP.PyProgress(None, -1, "PyProgress Example", + "An Informative Message", + agwStyle=style) + + proportion = self.slider1.GetValue() + steps = self.slider2.GetValue() + + backcol = self.csel3.GetColour() + firstcol = self.csel4.GetColour() + secondcol = self.csel5.GetColour() + + dlg.SetGaugeProportion(proportion/100.0) + dlg.SetGaugeSteps(steps) + dlg.SetGaugeBackground(backcol) + dlg.SetFirstGradientColour(firstcol) + dlg.SetSecondGradientColour(secondcol) + + max = 400 + keepGoing = True + count = 0 + + while keepGoing and count < max: + count += 1 + wx.MilliSleep(30) + + if count >= max / 2: + keepGoing = dlg.UpdatePulse("Half-time!") + else: + keepGoing = dlg.UpdatePulse() + + dlg.Destroy() + wx.SafeYield() + wx.GetApp().GetTopWindow().Raise() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = PyProgressDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = PP.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/agw/RibbonBar.py b/demo/agw/RibbonBar.py new file mode 100644 index 00000000..4135a6db --- /dev/null +++ b/demo/agw/RibbonBar.py @@ -0,0 +1,922 @@ +import wx + +import os +import sys + +import images + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +##try: +from agw import ribbon as RB +##except ImportError: # if it's not there locally, try the wxPython lib. +## import wx.lib.agw.ribbon as RB + +from wx.lib.embeddedimage import PyEmbeddedImage + +# --------------------------------------------------- # +# Some constants for ribbon buttons +ID_CIRCLE = wx.ID_HIGHEST + 1 +ID_CROSS = ID_CIRCLE + 1 +ID_TRIANGLE = ID_CIRCLE + 2 +ID_SQUARE = ID_CIRCLE + 3 +ID_POLYGON = ID_CIRCLE + 4 +ID_SELECTION_EXPAND_H = ID_CIRCLE + 5 +ID_SELECTION_EXPAND_V = ID_CIRCLE + 6 +ID_SELECTION_CONTRACT = ID_CIRCLE + 7 +ID_PRIMARY_COLOUR = ID_CIRCLE + 8 +ID_SECONDARY_COLOUR = ID_CIRCLE + 9 +ID_DEFAULT_PROVIDER = ID_CIRCLE + 10 +ID_AUI_PROVIDER = ID_CIRCLE + 11 +ID_MSW_PROVIDER = ID_CIRCLE + 12 +ID_MAIN_TOOLBAR = ID_CIRCLE + 13 +ID_POSITION_TOP = ID_CIRCLE + 14 +ID_POSITION_TOP_ICONS = ID_CIRCLE + 15 +ID_POSITION_TOP_BOTH = ID_CIRCLE + 16 +ID_POSITION_LEFT = ID_CIRCLE + 17 +ID_POSITION_LEFT_LABELS = ID_CIRCLE + 18 +ID_POSITION_LEFT_BOTH = ID_CIRCLE + 19 +ID_TOGGLE_PANELS = ID_CIRCLE + 20 + +# --------------------------------------------------- # +# Some bitmaps for ribbon buttons + +align_center = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAADpJ" + "REFUKJFjZGRiZqAEMFGkm4GBgQWZ8//f3//EaGJkYmaEsyn1Ags2QVwuQbaZNi4YDYMRGwYU" + "ZyYAopsYTgbXQz4AAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +align_left = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAADxJ" + "REFUKJFjZGRiZqAEMFGkm4GBgYWBgYHh/7+//4lRzMjEzIghRqkX8LoAm430dQExLhoNg2ER" + "BhRnJgDCqhhOM7rMkQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +align_right = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAADdJ" + "REFUKJFjZGRiZqAEMFGkm4GBgQWb4P9/f/8To5mRiZmRkVIvYHUBsS6inQtGw2DEhQHFmQkA" + "gowYTpdfxvkAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +aui_style = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAMFJ" + "REFUWIXtlrENgzAUBQ/beAQWYAcGYYIkgyWZxz2lF0CiRwJBCmKJIlGq+DV+lS1ZutO39eSq" + "MpaU5+O+kyGX661Ka3eG932fgw+wJwmTi/gtRcCdN9u2aQWWZdEKzPOsFVjXVSsguYJz++Wc" + "QOI6gLZtAZimKQs88WKMh0CMMQv4UxxA0zQS+DiOh4D3XiIA7wkYo2tkB2Ct/XXuvwJ1XWsF" + "5BOQv4FhGLQCXddJ4CEE/Y+oCBSBIlAEHByNpMoLu1w1qHGIod8AAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +auto_crop_selection = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAi5J" + "REFUWIXFlz1r20AYx/+ns4PjR7jG1IgG2tIO/QAdkyyZOvcrlECnQujWT9AtFDIF+h06dcjU" + "KaFTxg4dWwiIBNU1d8Y0Ol0H+8TpxUKKpOgPB7Is7vfoebtHjDkcXcrplA4AzOFYe0ED0Pd9" + "zUwIdKQ0czhr/Y3XMjxWlAP3YVScAzpSOg0/9g8z95uS2Tc3CQ0cAE5vjuKH2zAmNsC42oYT" + "d0Gc8OXvR+hI6TNx0pgRhpebhDpS+vTmCMQJ5LgAgOHamP3tN2giLwwvNwTM4eztw08ZOHG3" + "LjejTAjs368ffEjAyaHGwIZXWAVn4qQVeIJnd0Jzne6O9ko/Q/vfM/fKLKQ7YVXRwaWeTAZw" + "iUNIhSBYQn57WTk579SK6eBSP3lM2PG2MB71MJuHuPL/4ddvWdoIw+tVtRgAJpMBdrwtPH86" + "gDftw7++BQAIqSAr7rWxCjZpuHuuXeIYj3rwpn28eLYNb9rHeNSDSxzD3fNSjcrwYg+UDcHi" + "Yo+JRz/0bB7Gb+5f32I2DyGkwuJir/0QBMESV7TKneBPGOdAECwr79V5FRT2gTIrrw+gRP9A" + "ug80NXzoSOmf4VcAgIwkpBKQSuKV+y6R6JnDqOnJpwhu8zaeBU3BF0rE84T9TOFEVNsAC74y" + "SCQmK1uthMC43cClWnnEnjELJ6K6MnuZyUquPfHe+5wY/ZjDWe0yLHPsHvuHmVJE3eP4Lh7J" + "+6+VKkgrD547EaHLb8Ou9B/kXYasrB2oNQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +auto_crop_selection_small = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAASRJ" + "REFUOI2lkzFLw1AUhb+XdOvQiiAqgqAgLeJSWo0RG+iiOBRcXV3t6OIPEHfnQPUPFERxExRK" + "i7gLXUSoo4hDxuQ62AsSQxPaAw8u7753OOdwrwGECWEs2+S0AJAoFK3TIFEoAJZerDhz0uo0" + "kSgUbWZBTtkOTmtseRvM3y0y6A65vrjPRGCphcvDG957n3iNTfJ2PquAXwWKQXfIR/+Ll6dX" + "AAqOL9/949RMxFg28VN02+KcvEnRbSf29Z+VxFhwfClVPPYbM5QqHgXHHxvqVArMqEj0qRnU" + "dtelWi8ThAFX57cYyzY6M4kWFBpgtV7m6GyPtZ2lf2/GEiiCMODx4Znl7Vl02FIziPsFpNVp" + "yqq7IJkziOPvrmhtmHIbzUjOxPgBMl93hZvH4+AAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +circle = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAANtJ" + "REFUWIXNV8sSxCAIA/z/T67d0864PiBQ2ZpbHQkxlGKZpVAEtV53+yxSOMLDqIA+oQVUkCnA" + "m9grRDKTIxxLAUhykcKI1RrXtARagJXQGzsIWBF433KU50fALCjaXiinoBujmHG0udQu+AeE" + "KO/0Gtc35xkODIsbT29xvu/Ajs9tFLVe9+BAhv0a9/sl6BcySzJv90TLLYgUPq8ERDllWE7H" + "3Ym8ECJ7Yj2FNmvOcIAozwVr0p51JbOCESGPL6UIUU/o2QsLQIkRaK6pXZB1KW1x/s8pKijq" + "1gcd75B9JbWfpAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +circle_small = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAHxJ" + "REFUOI2lU0EOwCAIg/r/J6u7TKMVgWXcDG2paFVRxKrWal/PQFELpyzARC4WQjSVCYyZDtbG" + "za6FQZbMvcHBDZARERFBtDSvWqt9OshMt7DwgCmx1U6WtC/9g/VjOoq6HymaLvJewXrfiDw4" + "WxZuAfKC9TtMh0DkhusBDWJQP2fEFKMAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +colours = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAA3NCSVQICAjb4U/gAAAAOklE" + "QVQokWNgIBEwMjAwXJJiwpTQefgPU5CJlQGLUvxgRGpgYWBgiNiHReJu3H9s6hkHoR8GoQaS" + "AQBoQQZvRwyakAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +cross = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAO9J" + "REFUWIXNl9sOAyEIRIHu/39xU/epiXVRhltSX3ZNZOZoDCCzvGge4/MeLBdTw9C0ZV0wf6vN" + "NW1ZF+zmFebaXE5mFRCWNhMN0yR6J5ANCCIeOQkkhuVi+f5UQqDmRNMlrILwmP8AVEB4zR8A" + "GYiIuQoQgYiaExHxmop3Jplx2pB6AkhghbkJkIVAYk2AKAQaAwF4ITxrYYCuAQNUp2IXQFcx" + "ggAyuQAqx13mqMYWAE2v2QKmAnhzewbiARAtLFEItS33mmcgtm151MALcWzLvcIRiP9vyzvL" + "sdmWdzYkZlte+UI+aattecfzfKd9AzzryGWicE3pAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +empty = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAA3NCSVQICAjb4U/gAAAANElE" + "QVQokWNgIBEwMjAw/P//H84/efIkHtUWFhZMpNpAew0sDKjuNjc3H2gnjWqgiQaSAQBRvgke" + "qvN6jAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +expand_selection_h = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAVFJ" + "REFUWIXtVjFuwzAMJCmjQGrv/UH27vlB9j4gyAvykC5eCz+gewbv3rvnB93lGihCsUNqQ1Ys" + "x0nUJgZ8AGFapOgTKVFGJAW3BN306xOBURIQwyKGpU//UwIAAEgK66etXxRrdMewL83/VoKQ" + "uL8SnNrN19i67OQ65Tr1070SuU6PSDYExLAUVdYiY0s93nfcbJtvflFlLRKIpEAMy8f3O5Ss" + "oeQSvlhDaQ56yRo2T29NcDEsPhK2TQzL6+caYpVArGKIKYHHWlcJPD+8AJJCEsOy228HJjEc" + "dvstiGE5+xgOLcFQEJLCebQcPCFUI5pHywNhJAW/vUCKKpNcpwIAR2L71borrp8ruU6lqLJW" + "vKYESAoXsxXY77bY475VuX5d8xezVdvP7YR1Gofs9HNtXXGjvlWEhC/u/d0FpzBdx6ExzhL4" + "/ooviTW+EkwEQuMHDB37+4Mc8HwAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +expand_selection_v = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAATtJ" + "REFUWIXtlzGOwjAQRb8dhISCRMkN6OnpKaho9gArWho6TkBHQ4v2ADRbpaCnp88NtlyJCAnF" + "HqqAozhoPfEmIPElS04cj59mbE9GCBmAK9KKAEDIQHBtyCqLx2mEOI1uIBwJjgdIKzpedrl3" + "w/YHyxPOAKQVHc5f1rFR59MZwgmAtKL9afPwm3F37gThDJD1v39XubFpb3k36gDQ+vPqhmHS" + "ihJ9Kh13kROAqUQl3Km+AIoe4Ih9DK3G6jiGvsW+Cb1JyKDQABAA+q9+rtlCQFpRlQRTJpvd" + "59wDVbLbI9nsNr4J3yEoDUH2MWlFvvq2dZ4zBHWKlQ19JiN2Ol7/zHLPi/6WZYcNEAZd7lRf" + "AGH9AGbsQ1n0AKdSeq3f8gyiscLEhGisNDMh4jQCAAxaE3aFXOkq9lGeXwGxGs15gJjjygAA" + "AABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +eye = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAJNJ" + "REFUOI3NkjEOwjAQBOdsoE7pwj+gyCP4f0HBD67gDUHJUkRGhkRIlgtYyZJ13h3pzmcWIj0K" + "Xem/ABw+C1pmfQtYiLYLKEF3ByDnDGlaH++nuq4aZBYiWmYVQx0ez0cArrfHG6R4CkTu/jqA" + "SJPGiwSDYFjvadKet3uI3S1Y2cSGIbIZYq3Wb9wAWvX7Ve4GPAEieGRem+OF/wAAAABJRU5E" + "rkJggg==") + +#---------------------------------------------------------------------- +hexagon = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAALNJ" + "REFUWIXt180NgCAMBlALG7ILU7gLGxo9aWL4a/uV6KE9Q/sAxUoU4vZlBGRyjuXMsZxIDtLs" + "QK/ofiRaCuCuVgJhAWYrRnZkCJAm1kCaAPSMJfNfAMuHi5vvAbQGawtzIHduohCrAVaFZ5D9" + "SFRdRKuK93JDN6FFOMABDnCAAyoA2mSOopX7H5/j0UAEImpIpBPRwkOAFmLWlEoTL2vLuRBN" + "YRVgBln+a9aDIK8rBLCICxjaeOXhD450AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +msw_style = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAOhJ" + "REFUWIVjZGRiZkAGU3c8+c9AQ5DtIcOIzGdBtzzaSoCW9jMw7HjyH9kRjLAQmLrjyf8oS37a" + "Wg4Fy45/hIcESgj8+UcX+1EAigN+/x1gB/yjafIbdQARDvg/AA5gZGRiZpi648l/D31+BkZG" + "whqoAf7/Z2DYcRGSFRl7Nj36H2QuQh+b0cC6k28YmAbEZiTAwsDAwPD0xfMBsp4V4gAJUfGB" + "sf/hO4gD/vwdgDIYCgaHA778+DOwDvg7EEUgsgPoVgLhcgDjiHfAaBQMuANGo2DAQ+De6+8D" + "5oABb5CMOgDaJBu4NAAAvuND/BvGPIIAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +position_left = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAExJ" + "REFUKJHtkzEKwDAMA0/yx/z/P7XqVOiQDmmHLDEIBEKCGyy5yHmEDyeXACIX3YlcPP2dvQkI" + "QEblqYFRuTuZGtgIG2EpguR/33gBsoRzDlCsBR0AAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +position_top = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAFJJ" + "REFUKJHtkzEKwDAMA092H5b//ylRppRCpzhToTd50RljJEXi0U0BRQrAiqQ1W5HszIABXAkr" + "kltQCb8E3z1By1Llev5zF4/uONkO8AtAp22caOhgKT6Nla4AAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +ribbon = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAYxJ" + "REFUOI19krtKA0EUhr8xMcYbRIJgk87KBSsRBK0UROMi6y3Wig+wpLQTLMUHsLNSBEVCIoKd" + "gpAyEBBMISKIiDeSmLhqxiLuZrPjeqrhXH6+c/4RoiWAX2iGKQHyR9vCryf43+D4zBLWtwTw" + "FRJeAs0wpbEQ5+4Jql8BIl1tTu385EARCXqHB0bihIKwuxH+zdZY2xQIIRibWgSQbpEWL1Jf" + "j+S5VH/ryQp6ssLOuvS5gItAM0w5ObtMb1eRd6ueS221O0JVq41wKKhQOAT5o21xerzHQ7GV" + "SGeDwI630ge1mlTuoKzQHQ5RsRppPVkhtdVOTcJb+UNZ4U8XVlfmuX385LX0xUu5UStkM4oL" + "ioAtAqDP6Vzff3N1mXHW9PYqH0kzTDk0bhDpCJE63AdgQk/wWr+s/JdAM0zZPzzt4E7oCQDO" + "Uvu4826RJhsHR+O8Ww3Pbx6KynqDo/EmkiYbcxdpYlFBIZtRBgvZDLGoIHeR/pvAFrHVNcOU" + "sWi9r+Cp+d7AHbYTHnElfgAFJbH0Sf7mkQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +selection_panel = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAHlJ" + "REFUOI3tk8EOwzAIQx+w307Dtu9u3UsS9bamuc4Ski8GjIyZByvwJTVA20CAnvBXb5SZAHp/" + "vla3ol9cx666FWEemAeZqc7vVmbKzAMdu8zDZqx3zThiW28KdSvydsip6VfN30LYUhJHDrof" + "gEvibvHR4CmWv/EExjdqKKO2QxEAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +square = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAEdJ" + "REFUWIXt1zEOACAIQ9FC9P4HNinOuhsGPyNLXxoWouRS42RnOABJGvcic8bLQHsdN9feAAAA" + "AAAAAAAAAAAAAILf8HvABvIMCjlFTCZ2AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +triangle = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAALFJ" + "REFUWIXVl0EOgCAMBFvq/39s8ERCyCKwIJY9EYG2M9GDqsGETbzvKCKiZsrWCHT3RaEHSPTl" + "etsAq0INgIhZC+cZyEnVTPMvgLFwloGSHq1HLZxjoEaPno1YOMNAix7t9Vrwb6CXHp3pseDb" + "wCg9Otuy4NcAS4/uvFnwaWCWHt2tWfBnYBU9qoEs+DKwmh7VKi34MfAVPaqZ9/JhYObPhk3q" + "eb1t7ohKlO30eX5/Bx4qMXoN5ex1NgAAAABJRU5ErkJggg==") + +# --------------------------------------------------- # + +def CreateBitmap(xpm): + + bmp = eval(xpm).Bitmap + + return bmp + + +# --------------------------------------------------- # + +class ColourClientData(object): + + def __init__(self, name, colour): + + self._name = name + self._colour = colour + + + def GetName(self): + + return self._name + + + def GetColour(self): + + return self._colour + + +# --------------------------------------------------- # + +class RibbonFrame(wx.Frame): + + def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition, + size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE, log=None): + + wx.Frame.__init__(self, parent, id, title, pos, size, style) + + panel = wx.Panel(self) + + self._ribbon = RB.RibbonBar(panel, wx.ID_ANY, agwStyle=RB.RIBBON_BAR_DEFAULT_STYLE|RB.RIBBON_BAR_SHOW_PANEL_EXT_BUTTONS) + + self._bitmap_creation_dc = wx.MemoryDC() + self._colour_data = wx.ColourData() + + home = RB.RibbonPage(self._ribbon, wx.ID_ANY, "Examples", CreateBitmap("ribbon")) + toolbar_panel = RB.RibbonPanel(home, wx.ID_ANY, "Toolbar", wx.NullBitmap, wx.DefaultPosition, + wx.DefaultSize, agwStyle=RB.RIBBON_PANEL_NO_AUTO_MINIMISE|RB.RIBBON_PANEL_EXT_BUTTON) + + toolbar = RB.RibbonToolBar(toolbar_panel, ID_MAIN_TOOLBAR) + toolbar.AddTool(wx.ID_ANY, CreateBitmap("align_left")) + toolbar.AddTool(wx.ID_ANY, CreateBitmap("align_center")) + toolbar.AddTool(wx.ID_ANY, CreateBitmap("align_right")) + toolbar.AddSeparator() + toolbar.AddHybridTool(wx.ID_NEW, wx.ArtProvider.GetBitmap(wx.ART_NEW, wx.ART_OTHER, wx.Size(16, 15))) + toolbar.AddTool(wx.ID_ANY, wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_OTHER, wx.Size(16, 15))) + toolbar.AddTool(wx.ID_ANY, wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE, wx.ART_OTHER, wx.Size(16, 15))) + toolbar.AddTool(wx.ID_ANY, wx.ArtProvider.GetBitmap(wx.ART_FILE_SAVE_AS, wx.ART_OTHER, wx.Size(16, 15))) + toolbar.AddSeparator() + toolbar.AddDropdownTool(wx.ID_UNDO, wx.ArtProvider.GetBitmap(wx.ART_UNDO, wx.ART_OTHER, wx.Size(16, 15))) + toolbar.AddDropdownTool(wx.ID_REDO, wx.ArtProvider.GetBitmap(wx.ART_REDO, wx.ART_OTHER, wx.Size(16, 15))) + toolbar.AddSeparator() + toolbar.AddTool(wx.ID_ANY, wx.ArtProvider.GetBitmap(wx.ART_REPORT_VIEW, wx.ART_OTHER, wx.Size(16, 15))) + toolbar.AddTool(wx.ID_ANY, wx.ArtProvider.GetBitmap(wx.ART_LIST_VIEW, wx.ART_OTHER, wx.Size(16, 15))) + toolbar.AddSeparator() + toolbar.AddHybridTool(ID_POSITION_LEFT, CreateBitmap("position_left"), "Align ribbonbar vertically\non the left\nfor demonstration purposes") + toolbar.AddHybridTool(ID_POSITION_TOP, CreateBitmap("position_top"), "Align the ribbonbar horizontally\nat the top\nfor demonstration purposes") + toolbar.AddSeparator() + toolbar.AddHybridTool(wx.ID_PRINT, wx.ArtProvider.GetBitmap(wx.ART_PRINT, wx.ART_OTHER, wx.Size(16, 15)), + "This is the Print button tooltip\ndemonstrating a tooltip") + toolbar.SetRows(2, 3) + + selection_panel = RB.RibbonPanel(home, wx.ID_ANY, "Selection", CreateBitmap("selection_panel")) + selection = RB.RibbonButtonBar(selection_panel) + selection.AddSimpleButton(ID_SELECTION_EXPAND_V, "Expand Vertically", CreateBitmap("expand_selection_v"), + "This is a tooltip for Expand Vertically\ndemonstrating a tooltip") + selection.AddSimpleButton(ID_SELECTION_EXPAND_H, "Expand Horizontally", CreateBitmap("expand_selection_h"), "") + selection.AddButton(ID_SELECTION_CONTRACT, "Contract", CreateBitmap("auto_crop_selection"), + CreateBitmap("auto_crop_selection_small")) + + shapes_panel = RB.RibbonPanel(home, wx.ID_ANY, "Shapes", CreateBitmap("circle_small")) + shapes = RB.RibbonButtonBar(shapes_panel) + shapes.AddButton(ID_CIRCLE, "Circle", CreateBitmap("circle"), CreateBitmap("circle_small"), + help_string="This is a tooltip for the circle button\ndemonstrating another tooltip", + kind=RB.RIBBON_BUTTON_TOGGLE) + shapes.AddSimpleButton(ID_CROSS, "Cross", CreateBitmap("cross"), "") + shapes.AddHybridButton(ID_TRIANGLE, "Triangle", CreateBitmap("triangle")) + shapes.AddSimpleButton(ID_SQUARE, "Square", CreateBitmap("square"), "") + shapes.AddDropdownButton(ID_POLYGON, "Other Polygon", CreateBitmap("hexagon"), "") + + sizer_panel = RB.RibbonPanel(home, wx.ID_ANY, "Panel with Sizer", + wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, + agwStyle=RB.RIBBON_PANEL_DEFAULT_STYLE) + + strs = ["Item 1 using a box sizer now", "Item 2 using a box sizer now"] + sizer_panelcombo = wx.ComboBox(sizer_panel, wx.ID_ANY, "", wx.DefaultPosition, wx.DefaultSize, + strs, wx.CB_READONLY) + + sizer_panelcombo2 = wx.ComboBox(sizer_panel, wx.ID_ANY, "", wx.DefaultPosition, wx.DefaultSize, + strs, wx.CB_READONLY) + + sizer_panelcombo.Select(0) + sizer_panelcombo2.Select(1) + sizer_panelcombo.SetMinSize(wx.Size(150, -1)) + sizer_panelcombo2.SetMinSize(wx.Size(150, -1)) + + # not using wx.WrapSizer(wx.HORIZONTAL) as it reports an incorrect min height + sizer_panelsizer = wx.BoxSizer(wx.VERTICAL) + sizer_panelsizer.AddStretchSpacer(1) + sizer_panelsizer.Add(sizer_panelcombo, 0, wx.ALL|wx.EXPAND, 2) + sizer_panelsizer.Add(sizer_panelcombo2, 0, wx.ALL|wx.EXPAND, 2) + sizer_panelsizer.AddStretchSpacer(1) + sizer_panel.SetSizer(sizer_panelsizer) + + label_font = wx.Font(8, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_LIGHT) + self._bitmap_creation_dc.SetFont(label_font) + + scheme = RB.RibbonPage(self._ribbon, wx.ID_ANY, "Appearance", CreateBitmap("eye")) + self._default_primary, self._default_secondary, self._default_tertiary = self._ribbon.GetArtProvider().GetColourScheme(1, 1, 1) + + provider_panel = RB.RibbonPanel(scheme, wx.ID_ANY, "Art", wx.NullBitmap, wx.DefaultPosition, wx.DefaultSize, + agwStyle=RB.RIBBON_PANEL_NO_AUTO_MINIMISE) + provider_bar = RB.RibbonButtonBar(provider_panel, wx.ID_ANY) + provider_bar.AddSimpleButton(ID_DEFAULT_PROVIDER, "Default Provider", + wx.ArtProvider.GetBitmap(wx.ART_QUESTION, wx.ART_OTHER, wx.Size(32, 32)), "") + provider_bar.AddSimpleButton(ID_AUI_PROVIDER, "AUI Provider", CreateBitmap("aui_style"), "") + provider_bar.AddSimpleButton(ID_MSW_PROVIDER, "MSW Provider", CreateBitmap("msw_style"), "") + + primary_panel = RB.RibbonPanel(scheme, wx.ID_ANY, "Primary Colour", CreateBitmap("colours")) + self._primary_gallery = self.PopulateColoursPanel(primary_panel, self._default_primary, ID_PRIMARY_COLOUR) + + secondary_panel = RB.RibbonPanel(scheme, wx.ID_ANY, "Secondary Colour", CreateBitmap("colours")) + self._secondary_gallery = self.PopulateColoursPanel(secondary_panel, self._default_secondary, ID_SECONDARY_COLOUR) + + dummy_2 = RB.RibbonPage(self._ribbon, wx.ID_ANY, "Empty Page", CreateBitmap("empty")) + dummy_3 = RB.RibbonPage(self._ribbon, wx.ID_ANY, "Another Page", CreateBitmap("empty")) + + self._ribbon.Realize() + + self._logwindow = wx.TextCtrl(panel, wx.ID_ANY, "", wx.DefaultPosition, wx.DefaultSize, + wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_LEFT | wx.TE_BESTWRAP | wx.BORDER_NONE) + + self._togglePanels = wx.ToggleButton(panel, ID_TOGGLE_PANELS, "&Toggle panels") + self._togglePanels.SetValue(True) + + s = wx.BoxSizer(wx.VERTICAL) + + s.Add(self._ribbon, 0, wx.EXPAND) + s.Add(self._logwindow, 1, wx.EXPAND) + s.Add(self._togglePanels, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL, 10) + + panel.SetSizer(s) + self.panel = panel + + self.BindEvents([selection, shapes, provider_bar, toolbar_panel]) + + self.SetIcon(images.Mondrian.Icon) + self.CenterOnScreen() + self.Show() + + + def BindEvents(self, bars): + + selection, shapes, provider_bar, toolbar_panel = bars + + provider_bar.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnDefaultProvider, id=ID_DEFAULT_PROVIDER) + provider_bar.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnAUIProvider, id=ID_AUI_PROVIDER) + provider_bar.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnMSWProvider, id=ID_MSW_PROVIDER) + selection.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnSelectionExpandHButton, id=ID_SELECTION_EXPAND_H) + selection.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnSelectionExpandVButton, id=ID_SELECTION_EXPAND_V) + selection.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnSelectionContractButton, id=ID_SELECTION_CONTRACT) + shapes.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnCircleButton, id=ID_CIRCLE) + shapes.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnCrossButton, id=ID_CROSS) + shapes.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnTriangleButton, id=ID_TRIANGLE) + shapes.Bind(RB.EVT_RIBBONBUTTONBAR_CLICKED, self.OnSquareButton, id=ID_SQUARE) + shapes.Bind(RB.EVT_RIBBONBUTTONBAR_DROPDOWN_CLICKED, self.OnTriangleDropdown, id=ID_TRIANGLE) + shapes.Bind(RB.EVT_RIBBONBUTTONBAR_DROPDOWN_CLICKED, self.OnPolygonDropdown, id=ID_POLYGON) + toolbar_panel.Bind(RB.EVT_RIBBONPANEL_EXTBUTTON_ACTIVATED, self.OnExtButton) + + self.Bind(RB.EVT_RIBBONGALLERY_HOVER_CHANGED, self.OnHoveredColourChange, id=ID_PRIMARY_COLOUR) + self.Bind(RB.EVT_RIBBONGALLERY_HOVER_CHANGED, self.OnHoveredColourChange, id=ID_SECONDARY_COLOUR) + self.Bind(RB.EVT_RIBBONGALLERY_SELECTED, self.OnPrimaryColourSelect, id=ID_PRIMARY_COLOUR) + self.Bind(RB.EVT_RIBBONGALLERY_SELECTED, self.OnSecondaryColourSelect, id=ID_SECONDARY_COLOUR) + self.Bind(RB.EVT_RIBBONTOOLBAR_CLICKED, self.OnNew, id=wx.ID_NEW) + self.Bind(RB.EVT_RIBBONTOOLBAR_DROPDOWN_CLICKED, self.OnNewDropdown, id=wx.ID_NEW) + self.Bind(RB.EVT_RIBBONTOOLBAR_CLICKED, self.OnPrint, id=wx.ID_PRINT) + self.Bind(RB.EVT_RIBBONTOOLBAR_DROPDOWN_CLICKED, self.OnPrintDropdown, id=wx.ID_PRINT) + self.Bind(RB.EVT_RIBBONTOOLBAR_DROPDOWN_CLICKED, self.OnRedoDropdown, id=wx.ID_REDO) + self.Bind(RB.EVT_RIBBONTOOLBAR_DROPDOWN_CLICKED, self.OnUndoDropdown, id=wx.ID_UNDO) + self.Bind(RB.EVT_RIBBONTOOLBAR_CLICKED, self.OnPositionLeft, id=ID_POSITION_LEFT) + self.Bind(RB.EVT_RIBBONTOOLBAR_DROPDOWN_CLICKED, self.OnPositionLeftDropdown, id=ID_POSITION_LEFT) + self.Bind(RB.EVT_RIBBONTOOLBAR_CLICKED, self.OnPositionTop, id=ID_POSITION_TOP) + self.Bind(RB.EVT_RIBBONTOOLBAR_DROPDOWN_CLICKED, self.OnPositionTopDropdown, id=ID_POSITION_TOP) + self.Bind(wx.EVT_BUTTON, self.OnColourGalleryButton, id=ID_PRIMARY_COLOUR) + self.Bind(wx.EVT_BUTTON, self.OnColourGalleryButton, id=ID_SECONDARY_COLOUR) + self.Bind(wx.EVT_MENU, self.OnPositionLeftIcons, id=ID_POSITION_LEFT) + self.Bind(wx.EVT_MENU, self.OnPositionLeftLabels, id=ID_POSITION_LEFT_LABELS) + self.Bind(wx.EVT_MENU, self.OnPositionLeftBoth, id=ID_POSITION_LEFT_BOTH) + self.Bind(wx.EVT_MENU, self.OnPositionTopLabels, id=ID_POSITION_TOP) + self.Bind(wx.EVT_MENU, self.OnPositionTopIcons, id=ID_POSITION_TOP_ICONS) + self.Bind(wx.EVT_MENU, self.OnPositionTopBoth, id=ID_POSITION_TOP_BOTH) + + self._togglePanels.Bind(wx.EVT_TOGGLEBUTTON, self.OnTogglePanels, id=ID_TOGGLE_PANELS) + + + def SetBarStyle(self, agwStyle): + + self._ribbon.Freeze() + self._ribbon.SetAGWWindowStyleFlag(agwStyle) + + pTopSize = self.panel.GetSizer() + pToolbar = wx.FindWindowById(ID_MAIN_TOOLBAR) + + if agwStyle & RB.RIBBON_BAR_FLOW_VERTICAL: + + self._ribbon.SetTabCtrlMargins(10, 10) + pTopSize.SetOrientation(wx.HORIZONTAL) + if pToolbar: + pToolbar.SetRows(3, 5) + + else: + + self._ribbon.SetTabCtrlMargins(50, 20) + pTopSize.SetOrientation(wx.VERTICAL) + if pToolbar: + pToolbar.SetRows(2, 3) + + self._ribbon.Realize() + self._ribbon.Thaw() + self.panel.Layout() + + + def PopulateColoursPanel(self, panel, defc, gallery_id): + + gallery = wx.FindWindowById(gallery_id, panel) + + if gallery: + gallery.Clear() + else: + gallery = RB.RibbonGallery(panel, gallery_id) + + dc = self._bitmap_creation_dc + def_item = self.AddColourToGallery(gallery, "Default", dc, defc) + gallery.SetSelection(def_item) + + self.AddColourToGallery(gallery, "BLUE", dc) + self.AddColourToGallery(gallery, "BLUE VIOLET", dc) + self.AddColourToGallery(gallery, "BROWN", dc) + self.AddColourToGallery(gallery, "CADET BLUE", dc) + self.AddColourToGallery(gallery, "CORAL", dc) + self.AddColourToGallery(gallery, "CYAN", dc) + self.AddColourToGallery(gallery, "DARK GREEN", dc) + self.AddColourToGallery(gallery, "DARK ORCHID", dc) + self.AddColourToGallery(gallery, "FIREBRICK", dc) + self.AddColourToGallery(gallery, "GOLD", dc) + self.AddColourToGallery(gallery, "GOLDENROD", dc) + self.AddColourToGallery(gallery, "GREEN", dc) + self.AddColourToGallery(gallery, "INDIAN RED", dc) + self.AddColourToGallery(gallery, "KHAKI", dc) + self.AddColourToGallery(gallery, "LIGHT BLUE", dc) + self.AddColourToGallery(gallery, "LIME GREEN", dc) + self.AddColourToGallery(gallery, "MAGENTA", dc) + self.AddColourToGallery(gallery, "MAROON", dc) + self.AddColourToGallery(gallery, "NAVY", dc) + self.AddColourToGallery(gallery, "ORANGE", dc) + self.AddColourToGallery(gallery, "ORCHID", dc) + self.AddColourToGallery(gallery, "PINK", dc) + self.AddColourToGallery(gallery, "PLUM", dc) + self.AddColourToGallery(gallery, "PURPLE", dc) + self.AddColourToGallery(gallery, "RED", dc) + self.AddColourToGallery(gallery, "SALMON", dc) + self.AddColourToGallery(gallery, "SEA GREEN", dc) + self.AddColourToGallery(gallery, "SIENNA", dc) + self.AddColourToGallery(gallery, "SKY BLUE", dc) + self.AddColourToGallery(gallery, "TAN", dc) + self.AddColourToGallery(gallery, "THISTLE", dc) + self.AddColourToGallery(gallery, "TURQUOISE", dc) + self.AddColourToGallery(gallery, "VIOLET", dc) + self.AddColourToGallery(gallery, "VIOLET RED", dc) + self.AddColourToGallery(gallery, "WHEAT", dc) + self.AddColourToGallery(gallery, "WHITE", dc) + self.AddColourToGallery(gallery, "YELLOW", dc) + + return gallery + + + def GetGalleryColour(self, gallery, item, name=None): + + data = gallery.GetItemClientData(item) + + if name != None: + name = data.GetName() + + return data.GetColour(), name + + + def OnHoveredColourChange(self, event): + + # Set the background of the gallery to the hovered colour, or back to the + # default if there is no longer a hovered item. + + gallery = event.GetGallery() + provider = gallery.GetArtProvider() + + if event.GetGalleryItem() != None: + if provider == self._ribbon.GetArtProvider(): + provider = provider.Clone() + gallery.SetArtProvider(provider) + + provider.SetColour(RB.RIBBON_ART_GALLERY_HOVER_BACKGROUND_COLOUR, + self.GetGalleryColour(event.GetGallery(), event.GetGalleryItem(), None)[0]) + + else: + if provider != self._ribbon.GetArtProvider(): + gallery.SetArtProvider(self._ribbon.GetArtProvider()) + del provider + + + def OnPrimaryColourSelect(self, event): + + colour, name = self.GetGalleryColour(event.GetGallery(), event.GetGalleryItem(), "") + self.AddText("Colour %s selected as primary."%name) + + dummy, secondary, tertiary = self._ribbon.GetArtProvider().GetColourScheme(None, 1, 1) + self._ribbon.GetArtProvider().SetColourScheme(colour, secondary, tertiary) + self.ResetGalleryArtProviders() + self._ribbon.Refresh() + + + def OnSecondaryColourSelect(self, event): + + colour, name = self.GetGalleryColour(event.GetGallery(), event.GetGalleryItem(), "") + self.AddText("Colour %s selected as secondary."%name) + + primary, dummy, tertiary = self._ribbon.GetArtProvider().GetColourScheme(1, None, 1) + self._ribbon.GetArtProvider().SetColourScheme(primary, colour, tertiary) + self.ResetGalleryArtProviders() + self._ribbon.Refresh() + + + def ResetGalleryArtProviders(self): + + if self._primary_gallery.GetArtProvider() != self._ribbon.GetArtProvider(): + self._primary_gallery.SetArtProvider(self._ribbon.GetArtProvider()) + + if self._secondary_gallery.GetArtProvider() != self._ribbon.GetArtProvider(): + self._secondary_gallery.SetArtProvider(self._ribbon.GetArtProvider()) + + + def OnSelectionExpandHButton(self, event): + + self.AddText("Expand selection horizontally button clicked.") + + + def OnSelectionExpandVButton(self, event): + + self.AddText("Expand selection vertically button clicked.") + + + def OnSelectionContractButton(self, event): + + self.AddText("Contract selection button clicked.") + + + def OnCircleButton(self, event): + + self.AddText("Circle button clicked.") + + + def OnCrossButton(self, event): + + self.AddText("Cross button clicked.") + + + def OnTriangleButton(self, event): + + self.AddText("Triangle button clicked.") + + + def OnTriangleDropdown(self, event): + + menu = wx.Menu() + menu.Append(wx.ID_ANY, "Equilateral") + menu.Append(wx.ID_ANY, "Isosceles") + menu.Append(wx.ID_ANY, "Scalene") + + event.PopupMenu(menu) + + + def OnSquareButton(self, event): + + self.AddText("Square button clicked.") + + + def OnPolygonDropdown(self, event): + + menu = wx.Menu() + menu.Append(wx.ID_ANY, "Pentagon (5 sided)") + menu.Append(wx.ID_ANY, "Hexagon (6 sided)") + menu.Append(wx.ID_ANY, "Heptagon (7 sided)") + menu.Append(wx.ID_ANY, "Octogon (8 sided)") + menu.Append(wx.ID_ANY, "Nonagon (9 sided)") + menu.Append(wx.ID_ANY, "Decagon (10 sided)") + + event.PopupMenu(menu) + + + def OnNew(self, event): + + self.AddText("New button clicked.") + + + def OnNewDropdown(self, event): + + menu = wx.Menu() + menu.Append(wx.ID_ANY, "New Document") + menu.Append(wx.ID_ANY, "New Template") + menu.Append(wx.ID_ANY, "New Mail") + + event.PopupMenu(menu) + + + def OnPrint(self, event): + + self.AddText("Print button clicked.") + + + def OnPrintDropdown(self, event): + + menu = wx.Menu() + menu.Append(wx.ID_ANY, "Print") + menu.Append(wx.ID_ANY, "Preview") + menu.Append(wx.ID_ANY, "Options") + + event.PopupMenu(menu) + + + def OnRedoDropdown(self, event): + + menu = wx.Menu() + menu.Append(wx.ID_ANY, "Redo E") + menu.Append(wx.ID_ANY, "Redo F") + menu.Append(wx.ID_ANY, "Redo G") + + event.PopupMenu(menu) + + + def OnUndoDropdown(self, event): + + menu = wx.Menu() + menu.Append(wx.ID_ANY, "Undo C") + menu.Append(wx.ID_ANY, "Undo B") + menu.Append(wx.ID_ANY, "Undo A") + + event.PopupMenu(menu) + + + def OnPositionTopLabels(self, event): + + self.SetBarStyle(RB.RIBBON_BAR_DEFAULT_STYLE) + + + def OnPositionTopIcons(self, event): + + self.SetBarStyle((RB.RIBBON_BAR_DEFAULT_STYLE &~RB.RIBBON_BAR_SHOW_PAGE_LABELS) + | RB.RIBBON_BAR_SHOW_PAGE_ICONS) + + + def OnPositionTopBoth(self, event): + + self.SetBarStyle(RB.RIBBON_BAR_DEFAULT_STYLE | RB.RIBBON_BAR_SHOW_PAGE_ICONS) + + + def OnPositionLeftLabels(self, event): + + self.SetBarStyle(RB.RIBBON_BAR_DEFAULT_STYLE | RB.RIBBON_BAR_FLOW_VERTICAL) + + + def OnPositionLeftIcons(self, event): + + self.SetBarStyle((RB.RIBBON_BAR_DEFAULT_STYLE &~RB.RIBBON_BAR_SHOW_PAGE_LABELS) | + RB.RIBBON_BAR_SHOW_PAGE_ICONS | RB.RIBBON_BAR_FLOW_VERTICAL) + + + def OnPositionLeftBoth(self, event): + + self.SetBarStyle(RB.RIBBON_BAR_DEFAULT_STYLE | RB.RIBBON_BAR_SHOW_PAGE_ICONS | + RB.RIBBON_BAR_FLOW_VERTICAL) + + + def OnPositionTop(self, event): + + self.OnPositionTopLabels(event) + + + def OnPositionTopDropdown(self, event): + + menu = wx.Menu() + menu.Append(ID_POSITION_TOP, "Top with Labels") + menu.Append(ID_POSITION_TOP_ICONS, "Top with Icons") + menu.Append(ID_POSITION_TOP_BOTH, "Top with Both") + event.PopupMenu(menu) + + + def OnPositionLeft(self, event): + + self.OnPositionLeftIcons(event) + + + def OnPositionLeftDropdown(self, event): + + menu = wx.Menu() + menu.Append(ID_POSITION_LEFT, "Left with Icons") + menu.Append(ID_POSITION_LEFT_LABELS, "Left with Labels") + menu.Append(ID_POSITION_LEFT_BOTH, "Left with Both") + event.PopupMenu(menu) + + + def OnTogglePanels(self, event): + + self._ribbon.ShowPanels(self._togglePanels.GetValue()) + + + def OnExtButton(self, event): + + wx.MessageBox("Extended button activated") + + + def AddText(self, msg): + + self._logwindow.AppendText(msg) + self._logwindow.AppendText("\n") + self._ribbon.DismissExpandedPanel() + + + def AddColourToGallery(self, gallery, colour, dc, value=None): + + item = None + + if colour != "Default": + c = wx.NamedColour(colour) + + if value is not None: + c = value + + if c.IsOk(): + + iWidth = 64 + iHeight = 40 + + bitmap = wx.EmptyBitmap(iWidth, iHeight) + dc.SelectObject(bitmap) + b = wx.Brush(c) + dc.SetPen(wx.BLACK_PEN) + dc.SetBrush(b) + dc.DrawRectangle(0, 0, iWidth, iHeight) + + colour = colour[0] + colour[1:].lower() + size = wx.Size(*dc.GetTextExtent(colour)) + notcred = min(abs(~c.Red()), 255) + notcgreen = min(abs(~c.Green()), 255) + notcblue = min(abs(~c.Blue()), 255) + + foreground = wx.Colour(notcred, notcgreen, notcblue) + + if abs(foreground.Red() - c.Red()) + abs(foreground.Blue() - c.Blue()) + abs(foreground.Green() - c.Green()) < 64: + # Foreground too similar to background - use a different + # strategy to find a contrasting colour + foreground = wx.Colour((c.Red() + 64) % 256, 255 - c.Green(), + (c.Blue() + 192) % 256) + + dc.SetTextForeground(foreground) + dc.DrawText(colour, (iWidth - size.GetWidth() + 1) / 2, (iHeight - size.GetHeight()) / 2) + dc.SelectObjectAsSource(wx.NullBitmap) + + item = gallery.Append(bitmap, wx.ID_ANY) + gallery.SetItemClientData(item, ColourClientData(colour, c)) + + return item + + + def OnColourGalleryButton(self, event): + + gallery = event.GetEventObject() + if gallery is None: + return + + self._ribbon.DismissExpandedPanel() + if gallery.GetSelection(): + self._colour_data.SetColour(self.GetGalleryColour(gallery, gallery.GetSelection(), None)[0]) + + dlg = wx.ColourDialog(self, self._colour_data) + + if dlg.ShowModal() == wx.ID_OK: + + self._colour_data = dlg.GetColourData() + clr = self._colour_data.GetColour() + + # Try to find colour in gallery + item = None + for i in xrange(gallery.GetCount()): + item = gallery.GetItem(i) + if self.GetGalleryColour(gallery, item, None)[0] == clr: + break + else: + item = None + + # Colour not in gallery - add it + if item == None: + item = self.AddColourToGallery(gallery, clr.GetAsString(wx.C2S_HTML_SYNTAX), self._bitmap_creation_dc, + clr) + gallery.Realize() + + # Set selection + gallery.EnsureVisible(item) + gallery.SetSelection(item) + + # Send an event to respond to the selection change + dummy = RB.RibbonGalleryEvent(RB.wxEVT_COMMAND_RIBBONGALLERY_SELECTED, gallery.GetId()) + dummy.SetEventObject(gallery) + dummy.SetGallery(gallery) + dummy.SetGalleryItem(item) + self.GetEventHandler().ProcessEvent(dummy) + + + def OnDefaultProvider(self, event): + + self._ribbon.DismissExpandedPanel() + self.SetArtProvider(RB.RibbonDefaultArtProvider()) + + + def OnAUIProvider(self, event): + + self._ribbon.DismissExpandedPanel() + self.SetArtProvider(RB.RibbonAUIArtProvider()) + + + def OnMSWProvider(self, event): + + self._ribbon.DismissExpandedPanel() + self.SetArtProvider(RB.RibbonMSWArtProvider()) + + + def SetArtProvider(self, prov): + + self._ribbon.Freeze() + self._ribbon.SetArtProvider(prov) + + self._default_primary, self._default_secondary, self._default_tertiary = \ + prov.GetColourScheme(self._default_primary, self._default_secondary, self._default_tertiary) + self.PopulateColoursPanel(self._primary_gallery.GetParent(), self._default_primary, + ID_PRIMARY_COLOUR) + self.PopulateColoursPanel(self._secondary_gallery.GetParent(), self._default_secondary, + ID_SECONDARY_COLOUR) + + self._ribbon.Thaw() + self.panel.GetSizer().Layout() + self._ribbon.Realize() + + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b1 = wx.Button(self, -1, " Pure-Python RibbonBar ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton1, b1) + + + def OnButton1(self, event): + self.win = RibbonFrame(None, -1, "wxPython Ribbon Sample Application", + size=(800, 600), log=self.log) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = RB.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/RulerCtrl.py b/demo/agw/RulerCtrl.py new file mode 100644 index 00000000..8c11057b --- /dev/null +++ b/demo/agw/RulerCtrl.py @@ -0,0 +1,453 @@ +import wx +import wx.lib.colourselect as csel +import wx.stc as stc +import keyword + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import rulerctrl as RC +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.rulerctrl as RC + +import images + +if wx.Platform == '__WXMSW__': + faces = { 'times': 'Times New Roman', + 'mono' : 'Courier New', + 'helv' : 'Arial', + 'other': 'Courier New', + 'size' : 9, + 'size2': 7, + } +elif wx.Platform == '__WXMAC__': + faces = { 'times': 'Times New Roman', + 'mono' : 'Courier New', + 'helv' : 'Arial', + 'other': 'Comic Sans MS', + 'size' : 12, + 'size2': 10, + } +else: + faces = { 'times': 'Times', + 'mono' : 'Courier', + 'helv' : 'Helvetica', + 'other': 'new century schoolbook', + 'size' : 12, + 'size2': 10, + } + +#---------------------------------------------------------------------- +class PythonSTC(stc.StyledTextCtrl): + + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, + size=wx.DefaultSize, style=0): + + stc.StyledTextCtrl.__init__(self, parent, id, pos, size, style) + + self.SetReadOnly(True) + self.SetLexer(stc.STC_LEX_PYTHON) + self.SetKeyWords(0, " ".join(keyword.kwlist)) + + self.SetProperty("fold", "1") + self.SetProperty("tab.timmy.whinge.level", "1") + + self.SetViewWhiteSpace(False) + self.SetEdgeColumn(80) + self.SetMarginWidth(0, 0) + self.SetMarginWidth(1, 5) + self.SetMarginWidth(2, 5) + self.SetScrollWidth(800) + + # Make some styles, The lexer defines what each style is used for, we + # just have to define what each style looks like. This set is adapted from + # Scintilla sample property files. + + # Global default styles for all languages + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces) + self.StyleClearAll() # Reset all to be like the default + + # Global default styles for all languages + self.StyleSetSpec(stc.STC_STYLE_DEFAULT, "face:%(helv)s,size:%(size)d" % faces) + self.StyleSetSpec(stc.STC_STYLE_CONTROLCHAR, "face:%(other)s" % faces) + self.StyleSetSpec(stc.STC_STYLE_BRACELIGHT, "fore:#FFFFFF,back:#0000FF,bold") + self.StyleSetSpec(stc.STC_STYLE_BRACEBAD, "fore:#000000,back:#FF0000,bold") + + # Python styles + # Default + self.StyleSetSpec(stc.STC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces) + # Comments + self.StyleSetSpec(stc.STC_P_COMMENTLINE, "fore:#007F00,face:%(other)s,size:%(size)d" % faces) + # Number + self.StyleSetSpec(stc.STC_P_NUMBER, "fore:#007F7F,size:%(size)d" % faces) + # String + self.StyleSetSpec(stc.STC_P_STRING, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces) + # Single quoted string + self.StyleSetSpec(stc.STC_P_CHARACTER, "fore:#7F007F,face:%(helv)s,size:%(size)d" % faces) + # Keyword + self.StyleSetSpec(stc.STC_P_WORD, "fore:#00007F,bold,size:%(size)d" % faces) + # Triple quotes + self.StyleSetSpec(stc.STC_P_TRIPLE, "fore:#7F0000,size:%(size)d" % faces) + # Triple double quotes + self.StyleSetSpec(stc.STC_P_TRIPLEDOUBLE, "fore:#7F0000,size:%(size)d" % faces) + # Class name definition + self.StyleSetSpec(stc.STC_P_CLASSNAME, "fore:#0000FF,bold,underline,size:%(size)d" % faces) + # Function or method name definition + self.StyleSetSpec(stc.STC_P_DEFNAME, "fore:#007F7F,bold,size:%(size)d" % faces) + # Operators + self.StyleSetSpec(stc.STC_P_OPERATOR, "bold,size:%(size)d" % faces) + # Identifiers + self.StyleSetSpec(stc.STC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces) + # Comment-blocks + self.StyleSetSpec(stc.STC_P_COMMENTBLOCK, "fore:#7F7F7F,size:%(size)d" % faces) + # End of line where string is not closed + self.StyleSetSpec(stc.STC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces) + + self.SetCaretForeground("BLUE") + + + # Some methods to make it compatible with how the wxTextCtrl is used + def SetValue(self, value): + if wx.USE_UNICODE: + value = value.decode('iso8859_1') + + self.SetReadOnly(False) + self.SetText(value) + self.SetReadOnly(True) + + +class RulerCtrlDemo(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent) + self.panel = wx.Panel(self, -1) + + statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + statusbar.SetStatusWidths([-2, -1]) + # statusbar fields + statusbar_fields = [("RulerCtrl wxPython Demo, Andrea Gavana @ 03 Nov 2006"), + ("Welcome To wxPython!")] + + for i in range(len(statusbar_fields)): + statusbar.SetStatusText(statusbar_fields[i], i) + + self.CreateMenu() + self.LayoutItems() + + self.SetIcon(images.Mondrian.GetIcon()) + sizex = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_X) + sizey = wx.SystemSettings_GetMetric(wx.SYS_SCREEN_Y) + + self.SetSize((3*sizex/4, 3*sizey/4)) + self.SendSizeEvent() + self.CenterOnScreen() + + + def LayoutItems(self): + + self.stc = PythonSTC(self.panel, -1) + try: + fid = open("RulerCtrl.py", "rt") + except: + fid = open("agw/RulerCtrl.py", "rt") + + text = fid.read() + fid.close() + self.stc.SetValue(text) + + self.ruler1 = RC.RulerCtrl(self.panel, -1, orient=wx.HORIZONTAL, style=wx.SUNKEN_BORDER) + self.ruler2 = RC.RulerCtrl(self.panel, -1, orient=wx.VERTICAL, style=wx.SUNKEN_BORDER) + self.ruler3 = RC.RulerCtrl(self.panel, -1, orient=wx.HORIZONTAL) + + self.rightbottomsizer_staticbox1 = wx.StaticBox(self.panel, -1, "Options") + self.rightbottomsizer_staticbox2 = wx.StaticBox(self.panel, -1, "Messages") + + self.rulerformat = wx.ComboBox(self.panel, -1, choices=["Integer", "Real", "Time", "LinearDB"], + style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.flip = wx.CheckBox(self.panel, -1, "Flip") + self.logscale = wx.CheckBox(self.panel, -1, "Log Scale") + self.labelminor = wx.CheckBox(self.panel, -1, "Label") + self.alwayslabel = wx.CheckBox(self.panel, -1, "Always Label") + self.csel1 = csel.ColourSelect(self.panel, -1, "Choose...", wx.WHITE) + self.csel2 = csel.ColourSelect(self.panel, -1, "Choose...", wx.BLACK) + self.csel3 = csel.ColourSelect(self.panel, -1, "Choose...", wx.BLACK) + self.messages = wx.TextCtrl(self.panel, -1, "Here You'll See GUI Messages\n", + style=wx.TE_READONLY|wx.TE_MULTILINE) + + self.SetProperties() + self.DoLayout() + + self.Bind(wx.EVT_COMBOBOX, self.OnComboFormat, self.rulerformat) + self.Bind(wx.EVT_CHECKBOX, self.OnFlip, self.flip) + self.Bind(wx.EVT_CHECKBOX, self.OnLogScale, self.logscale) + self.Bind(wx.EVT_CHECKBOX, self.OnLabelMinor, self.labelminor) + self.Bind(wx.EVT_CHECKBOX, self.OnAlwaysLabel, self.alwayslabel) + self.Bind(csel.EVT_COLOURSELECT, self.OnBackgroundColour, self.csel1) + self.Bind(csel.EVT_COLOURSELECT, self.OnTickColour, self.csel2) + self.Bind(csel.EVT_COLOURSELECT, self.OnLabelColour, self.csel3) + self.Bind(wx.EVT_SIZE, self.OnSize) + + self.Bind(RC.EVT_INDICATOR_CHANGING, self.OnIndicatorChanging, id=103) + self.Bind(RC.EVT_INDICATOR_CHANGED, self.OnIndicatorChanged, id=101, id2=104) + + + def SetProperties(self): + + self.SetTitle("RulerCtrl wxPython Demo ;-)") + self.rulerformat.SetSelection(0) + self.alwayslabel.SetValue(1) + + self.ruler1.SetFormat(RC.IntFormat) + self.ruler2.SetFormat(RC.IntFormat) + self.ruler3.SetFormat(RC.IntFormat) + + self.ruler3.SetRange(1, 70) + self.ruler3.SetLabelEdges(True) + + self.ruler1.LabelMinor(True) + self.ruler2.LabelMinor(True) + self.ruler3.LabelMinor(False) + + self.ruler1.AddIndicator(101, 2) + self.ruler2.AddIndicator(102, 2) + self.ruler2.AddIndicator(103, 4) + self.ruler3.AddIndicator(104, 50) + + self.ruler1.SetDrawingParent(self.stc) + self.ruler2.SetDrawingParent(self.stc) + + + def DoLayout(self): + + bottomsizer1 = wx.StaticBoxSizer(self.rightbottomsizer_staticbox1, wx.VERTICAL) + bottomsizer2 = wx.StaticBoxSizer(self.rightbottomsizer_staticbox2, wx.VERTICAL) + + mainsizer = wx.BoxSizer(wx.HORIZONTAL) + bottomrightsizer = wx.BoxSizer(wx.VERTICAL) + gridsizer = wx.FlexGridSizer(8, 2, 10, 10) + leftsizer = wx.BoxSizer(wx.VERTICAL) + bottomleftsizer = wx.BoxSizer(wx.HORIZONTAL) + topsizer = wx.BoxSizer(wx.HORIZONTAL) + + leftsizer.Add((20, 20), 0, wx.ADJUST_MINSIZE, 0) + topsizer.Add((39, 0), 0, wx.ADJUST_MINSIZE, 0) + topsizer.Add(self.ruler1, 1, wx.EXPAND, 0) + leftsizer.Add(topsizer, 0, wx.EXPAND, 0) + + bottomleftsizer.Add((10, 0)) + bottomleftsizer.Add(self.ruler2, 0, wx.EXPAND, 0) + bottomleftsizer.Add(self.stc, 1, wx.EXPAND, 0) + leftsizer.Add(bottomleftsizer, 1, wx.EXPAND, 0) + mainsizer.Add(leftsizer, 3, wx.EXPAND, 0) + + mainsizer.Add((10, 0)) + bottomrightsizer.Add(self.ruler3, 0, wx.EXPAND | wx.ALL, 20) + + label_1 = wx.StaticText(self.panel, -1, "RulerCtrl Format: ") + gridsizer.Add(label_1, 0, wx.ALIGN_CENTER_VERTICAL) + gridsizer.Add(self.rulerformat, 0, wx.ALL) + label_2 = wx.StaticText(self.panel, -1, "Set Flipping: ") + gridsizer.Add(label_2, 0, wx.ALIGN_CENTER_VERTICAL) + gridsizer.Add(self.flip, 0, wx.ALIGN_CENTER_VERTICAL) + label_3 = wx.StaticText(self.panel, -1, "Set Logarithmic Scale: ") + gridsizer.Add(label_3, 0, wx.ALIGN_CENTER_VERTICAL) + gridsizer.Add(self.logscale, 0, wx.ADJUST_MINSIZE, 5) + label_5 = wx.StaticText(self.panel, -1, "Label Minor Labels: ") + gridsizer.Add(label_5, 0, wx.ALIGN_CENTER_VERTICAL) + gridsizer.Add(self.labelminor, 0, wx.ALIGN_CENTER_VERTICAL) + label_6 = wx.StaticText(self.panel, -1, "Always Label End Edges: ") + gridsizer.Add(label_6, 0, wx.ADJUST_MINSIZE, 5) + gridsizer.Add(self.alwayslabel, 0, wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 6) + label_7 = wx.StaticText(self.panel, -1, "Change Background Colour: ") + gridsizer.Add(label_7, 0, wx.ALIGN_CENTER_VERTICAL) + gridsizer.Add(self.csel1, 0, wx.ALIGN_CENTER_VERTICAL, 0) + label_8 = wx.StaticText(self.panel, -1, "Change Tick Colour: ") + gridsizer.Add(label_8, 0, wx.ALIGN_CENTER_VERTICAL) + gridsizer.Add(self.csel2, 0, wx.ALIGN_CENTER_VERTICAL, 0) + label_9 = wx.StaticText(self.panel, -1, "Change Label Colour: ") + gridsizer.Add(label_9, 0, wx.ALIGN_CENTER_VERTICAL) + gridsizer.Add(self.csel3, 0, wx.ALIGN_CENTER_VERTICAL, 0) + + bottomsizer1.Add(gridsizer, 1, wx.EXPAND) + bottomrightsizer.Add(bottomsizer1, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 20) + bottomrightsizer.Add((0, 10)) + bottomsizer2.Add(self.messages, 1, wx.EXPAND | wx.ALL, 5) + bottomrightsizer.Add(bottomsizer2, 1, wx.EXPAND|wx.LEFT|wx.RIGHT, 20) + bottomrightsizer.Add((0, 10)) + + mainsizer.Add(bottomrightsizer, 2, wx.EXPAND, 0) + self.panel.SetSizer(mainsizer) + mainsizer.Fit(self.panel) + mainsizer.SetSizeHints(self.panel) + + framesizer = wx.BoxSizer(wx.VERTICAL) + framesizer.Add(self.panel, 1, wx.EXPAND) + self.SetSizer(framesizer) + framesizer.Layout() + + + def OnIndicatorChanging(self, event): + + # Show how to block a changing indicator + self.Write("NoNoNoNoNo! You Can't Change My Value!") + return + + + def OnIndicatorChanged(self, event): + + self.Write("New Indicator Value Is: %0.2f"%event.GetValue()) + event.Skip() + + + def OnSize(self, event): + + event.Skip() + + # Try to emulate the rulers inside a text editor + wx.CallAfter(self.SizeRulers) + + + def Write(self, text): + + self.messages.AppendText(text + "\n") + + + def SizeRulers(self): + + dc = wx.MemoryDC() + width, height = self.stc.GetSize() + dc.SelectObject(wx.EmptyBitmap(width, height)) + widthMM, heightMM = dc.GetSizeMM() + dc.SelectObject(wx.NullBitmap) + + self.ruler1.SetRange(0, widthMM/10) + self.ruler2.SetRange(0, heightMM/10) + + + def OnComboFormat(self, event): + + self.ruler3.SetFormat(event.GetSelection()+1) + event.Skip() + + + def OnFlip(self, event): + + self.ruler3.SetFlip(event.IsChecked()) + event.Skip() + + + def OnLogScale(self, event): + + self.ruler3.SetLog(event.IsChecked()) + event.Skip() + + + def OnLabelMinor(self, event): + + self.ruler3.LabelMinor(event.IsChecked()) + event.Skip() + + + def OnAlwaysLabel(self, event): + + self.ruler3.SetLabelEdges(event.IsChecked()) + event.Skip() + + + def OnBackgroundColour(self, event): + + self.ruler3.SetBackgroundColour(event.GetValue()) + + + def OnTickColour(self, event): + + self.ruler3.SetTickPenColour(event.GetValue()) + + + def OnLabelColour(self, event): + + self.ruler3.SetLabelColour(event.GetValue()) + + + def CreateMenu(self): + + menuBar = wx.MenuBar(wx.MB_DOCKABLE) + fileMenu = wx.Menu() + helpMenu = wx.Menu() + + item = wx.MenuItem(fileMenu, wx.ID_ANY, "E&xit") + self.Bind(wx.EVT_MENU, self.OnQuit, item) + fileMenu.AppendItem(item) + + item = wx.MenuItem(helpMenu, wx.ID_ANY, "About") + self.Bind(wx.EVT_MENU, self.OnAbout, item) + helpMenu.AppendItem(item) + + menuBar.Append(fileMenu, "&File") + menuBar.Append(helpMenu, "&Help") + + self.SetMenuBar(menuBar) + + + def OnQuit(self, event): + + self.Destroy() + + + def OnAbout(self, event): + + msg = "This Is The About Dialog Of The RulerCtrl Demo.\n\n" + \ + "Author: Andrea Gavana @ 03 Nov 2006\n\n" + \ + "Please Report Any Bug/Requests Of Improvements\n" + \ + "To Me At The Following Adresses:\n\n" + \ + "andrea.gavana@gmail.com\n" + "andrea.gavana@maerskoil.com\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "RulerCtrl wxPython Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test RulerCtrl ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = RulerCtrlDemo(self, self.log) + self.win.Show(True) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = RC.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/ShapedButton.py b/demo/agw/ShapedButton.py new file mode 100644 index 00000000..78ec7906 --- /dev/null +++ b/demo/agw/ShapedButton.py @@ -0,0 +1,601 @@ +import wx +import random + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +bitmapDir = os.path.join(dirName, 'bitmaps') +sys.path.append(os.path.split(dirName)[0]) + +try: + import agw.shapedbutton + from agw.shapedbutton import SButton, SBitmapButton + from agw.shapedbutton import SBitmapToggleButton, SBitmapTextToggleButton + docs = agw.shapedbutton.__doc__ +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.shapedbutton + from wx.lib.agw.shapedbutton import SButton, SBitmapButton + from wx.lib.agw.shapedbutton import SBitmapToggleButton, SBitmapTextToggleButton + docs = wx.lib.agw.shapedbutton.__doc__ + +import images + +#---------------------------------------------------------------------- +# Beginning Of SHAPEDBUTTON Demo wxPython Code +#---------------------------------------------------------------------- + +class ShapedButtonDemo(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent, title="ShapedButton wxPython Demo ;-)") + + # Create Some Maquillage For The Demo: Icon, StatusBar, MenuBar... + + self.SetIcon(images.Mondrian.GetIcon()) + self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + + self.statusbar.SetStatusWidths([-2, -1]) + + statusbar_fields = [("wxPython ShapedButton Demo, Andrea Gavana @ 18 Oct 2005"), + ("Welcome To wxPython!")] + + for i in range(len(statusbar_fields)): + self.statusbar.SetStatusText(statusbar_fields[i], i) + + self.SetMenuBar(self.CreateMenuBar()) + + framesizer = wx.BoxSizer(wx.VERTICAL) + self.panel = wx.Panel(self, -1) + mainsizer = wx.BoxSizer(wx.VERTICAL) + hsizer0 = wx.BoxSizer(wx.HORIZONTAL) + + sb0 = wx.StaticBox(self.panel, -1) + recordsizer = wx.StaticBoxSizer(sb0, wx.HORIZONTAL) + + # Make A ToolBar-Like Audio Control With Round Buttons/Toggles + self.BuildAudioToolBar() + + recordsizer.Add(self.rewind, 0, wx.LEFT, 3) + recordsizer.Add(self.play, 0, wx.LEFT, 3) + recordsizer.Add(self.record, 0, wx.LEFT, 3) + recordsizer.Add(self.pause, 0, wx.LEFT, 3) + recordsizer.Add(self.stop, 0, wx.LEFT, 3) + recordsizer.Add(self.ffwd, 0, wx.LEFT | wx.RIGHT, 3) + + for ii in xrange(6): + recordsizer.SetItemMinSize(ii, 48, 48) + + self.eventtext = wx.StaticText(self.panel, -1, "Event Recorder", + style=wx.ST_NO_AUTORESIZE) + self.eventtext.SetBackgroundColour(wx.BLUE) + self.eventtext.SetForegroundColour(wx.WHITE) + self.eventtext.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD, + False, "Verdana")) + + smallsizer = wx.BoxSizer(wx.VERTICAL) + smallsizer.Add((0, 1), 1, wx.EXPAND) + smallsizer.Add(self.eventtext, 1, wx.EXPAND) + smallsizer.Add((0, 1), 1, wx.EXPAND) + + hsizer0.Add(recordsizer, 1, wx.EXPAND) + hsizer0.Add(smallsizer, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 5) + mainsizer.Add(hsizer0, 0, wx.BOTTOM, 5) + + mainsizer.Add((0, 10), 0, wx.EXPAND) + hsizer = wx.BoxSizer(wx.HORIZONTAL) + + # Make 9 SBitmapButtons With Text Rotation And Different Colours + sb1 = wx.StaticBox(self.panel, -1, "Some Buttons") + vsizer1 = wx.StaticBoxSizer(sb1, wx.VERTICAL) + + bsizer = self.BuildNineButtons() + vsizer1.Add((0, 10), 0) + vsizer1.Add(bsizer, 1, wx.EXPAND) + vsizer1.Add((0, 10), 0) + hsizer.Add(vsizer1, 3, wx.EXPAND) + + # Make Some Mixed SButton/SToggle With Bitmap And Text Rotation + sb2 = wx.StaticBox(self.panel, -1, "Other Buttons") + vsizer2 = wx.StaticBoxSizer(sb2, wx.VERTICAL) + btsizer = self.BuildMixedButtons() + vsizer2.Add((0, 10), 0) + vsizer2.Add(btsizer, 1, wx.EXPAND) + vsizer2.Add((0, 10), 0) + hsizer.Add(vsizer2, 2, wx.EXPAND) + + # Build Buttons With Elliptic Shape + sb3 = wx.StaticBox(self.panel, -1, "Elliptic Buttons") + vsizer3 = wx.StaticBoxSizer(sb3, wx.VERTICAL) + esizer = self.BuildEllipticButtons() + vsizer3.Add((0, 10), 0) + vsizer3.Add(esizer, 1, wx.EXPAND) + vsizer3.Add((0, 10), 0) + hsizer.Add(vsizer3, 2, wx.EXPAND) + + mainsizer.Add(hsizer, 1, wx.EXPAND | wx.ALL, 5) + + self.panel.SetSizer(mainsizer) + mainsizer.Layout() + framesizer.Add(self.panel, 1, wx.EXPAND) + self.SetSizer(framesizer) + framesizer.Layout() + self.SetAutoLayout(True) + self.Fit() + + self.Layout() + self.CenterOnParent() + + + def BuildAudioToolBar(self): + + # The Rewind Button Is A Simple Bitmap Button (SBitmapButton) + upbmp = wx.Bitmap(os.path.join(bitmapDir, "rewind.png"), wx.BITMAP_TYPE_PNG) + disbmp = wx.Bitmap(os.path.join(bitmapDir, "rewinddisabled.png"), wx.BITMAP_TYPE_PNG) + self.rewind = SBitmapButton(self.panel, -1, upbmp, (48, 48)) + self.rewind.SetUseFocusIndicator(False) + self.rewind.SetBitmapDisabled(disbmp) + + self.rewind.Bind(wx.EVT_BUTTON, self.OnRewind) + + # The Play Button Is A Toggle Bitmap Button (SBitmapToggleButton) + upbmp = wx.Bitmap(os.path.join(bitmapDir, "play.png"), wx.BITMAP_TYPE_PNG) + disbmp = wx.Bitmap(os.path.join(bitmapDir, "playdisabled.png"), wx.BITMAP_TYPE_PNG) + self.play = SBitmapToggleButton(self.panel, -1, upbmp, (48, 48)) + self.play.SetUseFocusIndicator(False) + self.play.SetBitmapDisabled(disbmp) + + self.play.Bind(wx.EVT_BUTTON, self.OnPlay) + + # The Record Button Is A Toggle Bitmap Button (SBitmapToggleButton) + upbmp = wx.Bitmap(os.path.join(bitmapDir, "record.png"), wx.BITMAP_TYPE_PNG) + disbmp = wx.Bitmap(os.path.join(bitmapDir, "recorddisabled.png"), wx.BITMAP_TYPE_PNG) + self.record = SBitmapToggleButton(self.panel, -1, upbmp, (48, 48)) + self.record.SetUseFocusIndicator(False) + self.record.SetBitmapDisabled(disbmp) + + self.record.Bind(wx.EVT_BUTTON, self.OnRecord) + + # The Pause Button Is A Toggle Bitmap Button (SBitmapToggleButton) + upbmp = wx.Bitmap(os.path.join(bitmapDir, "pause.png"), wx.BITMAP_TYPE_PNG) + disbmp = wx.Bitmap(os.path.join(bitmapDir, "pausedisabled.png"), wx.BITMAP_TYPE_PNG) + self.pause = SBitmapToggleButton(self.panel, -1, upbmp, (48, 48)) + self.pause.SetUseFocusIndicator(False) + self.pause.SetBitmapDisabled(disbmp) + self.pause.Enable(False) + + self.pause.Bind(wx.EVT_BUTTON, self.OnPause) + + # The Stop Button Is A Simple Bitmap Button (SBitmapButton) + upbmp = wx.Bitmap(os.path.join(bitmapDir, "stop.png"), wx.BITMAP_TYPE_PNG) + disbmp = wx.Bitmap(os.path.join(bitmapDir, "stopdisabled.png"), wx.BITMAP_TYPE_PNG) + self.stop = SBitmapButton(self.panel, -1, upbmp, (48, 48)) + self.stop.SetUseFocusIndicator(False) + self.stop.SetBitmapDisabled(disbmp) + self.stop.Enable(False) + + self.stop.Bind(wx.EVT_BUTTON, self.OnStop) + + # The FFWD Button Is A Simple Bitmap Button (SBitmapButton) + upbmp = wx.Bitmap(os.path.join(bitmapDir, "ffwd.png"), wx.BITMAP_TYPE_PNG) + disbmp = wx.Bitmap(os.path.join(bitmapDir, "ffwddisabled.png"), wx.BITMAP_TYPE_PNG) + self.ffwd = SBitmapButton(self.panel, -1, upbmp, (48, 48)) + self.ffwd.SetUseFocusIndicator(False) + self.ffwd.SetBitmapDisabled(disbmp) + + self.ffwd.Bind(wx.EVT_BUTTON, self.OnFFWD) + + + def BuildNineButtons(self): + + # We Build 9 Buttons With Different Colours And A Nice Text Rotation + + colours = [None, wx.BLUE, wx.RED, wx.GREEN, wx.NamedColour("Gold"), + wx.NamedColour("Cyan"), wx.NamedColour("Yellow"), + wx.NamedColour("Orange"), wx.NamedColour("Magenta")] + + labels = ["These", "Are", "Some", "Nice", "Text", "Appended", + "To Different", "Buttons", "Nice Eh?"] + + fnt = self.GetFont() + + fonts = [fnt, wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD), + wx.Font(10, wx.TELETYPE, wx.NORMAL, wx.NORMAL), + wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, True), + fnt, wx.Font(9, wx.DECORATIVE, wx.NORMAL, wx.BOLD), + wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, False, "Tahoma"), + fnt, wx.Font(8, wx.SWISS, wx.NORMAL, wx.NORMAL, True, "Verdana")] + + lcolours = [None, wx.WHITE, wx.NamedColour("Yellow"), wx.WHITE, + None, None, wx.BLUE, wx.WHITE, wx.WHITE] + + bsizer = wx.FlexGridSizer(3, 3, 5, 5) + rotation = [] + + for ii in xrange(9): + + btn = SButton(self.panel, -1, labels[ii]) + btn.SetButtonColour(colours[ii]) + btn.SetFont(fonts[ii]) + btn.SetLabelColour(lcolours[ii]) + btn.SetUseFocusIndicator(True) + btn.SetAngleOfRotation(45*ii) + rotation.append(45*ii) + btn.Bind(wx.EVT_BUTTON, self.OnNineButtons) + + bsizer.Add(btn, 1, wx.EXPAND | wx.BOTTOM | wx.RIGHT, 5) + + bsizer.AddGrowableRow(0) + bsizer.AddGrowableRow(1) + bsizer.AddGrowableRow(2) + bsizer.AddGrowableCol(0) + bsizer.AddGrowableCol(1) + bsizer.AddGrowableCol(2) + + self.buttonlabels = labels + self.buttonrotation = rotation + + return bsizer + + + def BuildMixedButtons(self): + + # Here We Build Some Buttons/Toggles With Different Properties + # Notice That We Put Some Images Also For The "Selected" State + # For A Button + + btsizer = wx.FlexGridSizer(2, 2, 5, 5) + + bmp = wx.Bitmap(os.path.join(bitmapDir, "italy.gif"), wx.BITMAP_TYPE_GIF) + btn1 = SBitmapButton(self.panel, -1, bmp) + bmp = wx.Bitmap(os.path.join(bitmapDir, "canada.gif"), wx.BITMAP_TYPE_GIF) + btn1.SetBitmapSelected(bmp) + btn1.Bind(wx.EVT_BUTTON, self.OnItalyCanada) + + bmp = wx.Bitmap(os.path.join(bitmapDir, "stop.png"), wx.BITMAP_TYPE_PNG) + btn2 = SBitmapTextToggleButton(self.panel, -1, bmp, "Toggle!") + bmp = wx.Bitmap(os.path.join(bitmapDir, "play.png"), wx.BITMAP_TYPE_PNG) + btn2.SetBitmapSelected(bmp) + btn2.Bind(wx.EVT_BUTTON, self.OnTogglePlayStop) + + btn3 = SButton(self.panel, -1, "Rotated") + btn3.SetButtonColour(wx.NamedColour("Cyan")) + btn3.SetLabelColour(wx.WHITE) + btn3.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + btn3.SetAngleOfRotation(90) + btn3.Bind(wx.EVT_BUTTON, self.OnRotated1) + + btn4 = SButton(self.panel, -1, "Button!") + btn4.SetAngleOfRotation(45) + btn4.Bind(wx.EVT_BUTTON, self.OnRotated1) + + btsizer.Add(btn1, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 5) + btsizer.Add(btn2, 1, wx.EXPAND | wx.BOTTOM, 5) + btsizer.Add(btn3, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 5) + btsizer.Add(btn4, 1, wx.EXPAND) + + btsizer.AddGrowableRow(0) + btsizer.AddGrowableRow(1) + btsizer.AddGrowableCol(0) + btsizer.AddGrowableCol(1) + + return btsizer + + + def BuildEllipticButtons(self): + + # Here We Build Elliptic Buttons. Elliptic Buttons Are Somewhat + # More Hostiles To Handle, Probably Because My Implementation + # Is Lacking Somewhere, But They Look Nice However. + + esizer = wx.FlexGridSizer(2, 2, 5, 5) + + btn1 = SButton(self.panel, -1, "Ellipse 1") + btn1.SetEllipseAxis(2, 1) + btn1.SetButtonColour(wx.RED) + btn1.SetLabelColour(wx.WHITE) + btn1.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD, False)) + btn1.Bind(wx.EVT_BUTTON, self.OnEllipse) + + btn2 = SButton(self.panel, -1, "Ellipse 2") + btn2.SetEllipseAxis(2, 3) + btn2.SetAngleOfRotation(90) + btn2.SetLabelColour(wx.BLUE) + btn2.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD, True)) + btn2.Bind(wx.EVT_BUTTON, self.OnEllipse) + + bmp = wx.Bitmap(os.path.join(bitmapDir, "ffwd.png"), wx.BITMAP_TYPE_PNG) + btn3 = SBitmapTextToggleButton(self.panel, -1, bmp, "FFWD") + bmp = wx.Bitmap(os.path.join(bitmapDir, "rewind.png"), wx.BITMAP_TYPE_PNG) + btn3.SetBitmapSelected(bmp) + btn3.SetEllipseAxis(1.4, 1) + btn3.Bind(wx.EVT_BUTTON, self.OnFFWDRewind) + + bmp = wx.Bitmap(os.path.join(bitmapDir, "round.png"), wx.BITMAP_TYPE_PNG) + btn4 = SBitmapButton(self.panel, -1, bmp) + btn4.SetEllipseAxis(1, 1.4) + btn4.Bind(wx.EVT_BUTTON, self.OnRound) + + esizer.Add(btn1, 1, wx.EXPAND | wx.ALL, 5) + esizer.Add(btn2, 1, wx.EXPAND | wx.ALL, 5) + esizer.Add(btn3, 1, wx.EXPAND | wx.ALL, 5) + esizer.Add(btn4, 1, wx.EXPAND | wx.ALL, 5) + + esizer.AddGrowableRow(0) + esizer.AddGrowableRow(1) + esizer.AddGrowableCol(0) + esizer.AddGrowableCol(1) + + return esizer + + + def CreateMenuBar(self): + + file_menu = wx.Menu() + + AS_EXIT = wx.NewId() + file_menu.Append(AS_EXIT, "&Exit") + self.Bind(wx.EVT_MENU, self.OnClose, id=AS_EXIT) + + help_menu = wx.Menu() + + AS_ABOUT = wx.NewId() + help_menu.Append(AS_ABOUT, "&About...") + self.Bind(wx.EVT_MENU, self.OnAbout, id=AS_ABOUT) + + menu_bar = wx.MenuBar() + + menu_bar.Append(file_menu, "&File") + menu_bar.Append(help_menu, "&Help") + + return menu_bar + + + def OnClose(self, event): + + self.Destroy() + + + def OnAbout(self, event): + + msg = "This Is The About Dialog Of The ShapedButton Demo.\n\n" + \ + "Author: Andrea Gavana @ 18 Oct 2005\n\n" + \ + "Please Report Any Bug/Requests Of Improvements\n" + \ + "To Me At The Following Adresses:\n\n" + \ + "andrea.gavana@agip.it\n" + "andrea_gavana@tin.it\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "ShapedButton Demo", + wx.OK | wx.ICON_INFORMATION) + + dlg.ShowModal() + dlg.Destroy() + + + def OnRewind(self, event): + + self.eventtext.SetLabel("Rewind Button!") + self.eventtext.Refresh() + + event.Skip() + + + def OnPlay(self, event): + + if not event.GetIsDown(): + self.eventtext.SetLabel('Press "Stop" To Stop The Music!') + self.eventtext.Refresh() + self.play.SetToggle(True) + return + + self.eventtext.SetLabel("We Started To Play") + self.eventtext.Refresh() + + self.stop.Enable(True) + self.pause.Enable(True) + self.rewind.Enable(False) + self.ffwd.Enable(False) + self.record.Enable(False) + + event.Skip() + + + def OnRecord(self, event): + + if not event.GetIsDown(): + self.eventtext.SetLabel("Recording Stopped") + self.eventtext.Refresh() + self.stop.Enable(False) + self.pause.Enable(False) + self.rewind.Enable(True) + self.ffwd.Enable(True) + self.play.Enable(True) + + event.Skip() + return + + self.eventtext.SetLabel("What Are You Recording? ;-)") + self.eventtext.Refresh() + self.stop.Enable(True) + self.pause.Enable(True) + self.rewind.Enable(False) + self.ffwd.Enable(False) + self.play.Enable(False) + + event.Skip() + + + def OnPause(self, event): + + if event.GetIsDown(): + self.eventtext.SetLabel("Pausing Play Or Recording...") + else: + self.eventtext.SetLabel("Playing After A Pause...") + + self.eventtext.Refresh() + + event.Skip() + + + def OnStop(self, event): + + self.eventtext.SetLabel("Everything Stopped") + self.eventtext.Refresh() + + self.stop.Enable(False) + self.pause.Enable(False) + self.rewind.Enable(True) + self.ffwd.Enable(True) + self.play.Enable(True) + self.record.Enable(True) + self.play.SetToggle(False) + self.pause.SetToggle(False) + self.record.SetToggle(False) + + event.Skip() + + + def OnFFWD(self, event): + + self.eventtext.SetLabel("Fast Forward Button!") + self.eventtext.Refresh() + + event.Skip() + + + def OnNineButtons(self, event): + + btn = event.GetEventObject() + label = btn.GetLabel() + + mystr = "Button: " + label + ", Rotation: " + \ + str(int(btn.GetAngleOfRotation())) + " Degrees" + + self.eventtext.SetLabel(mystr) + self.eventtext.Refresh() + + event.Skip() + + + def OnItalyCanada(self, event): + + self.eventtext.SetLabel("Italy VS Canada ;-)") + self.eventtext.Refresh() + + event.Skip() + + + def OnTogglePlayStop(self, event): + + if event.GetIsDown(): + label = "You Started To Play!" + else: + label = "Why Did You Stop The Music? ;-)" + + self.eventtext.SetLabel(label) + self.eventtext.Refresh() + + event.Skip() + + + def OnRotated1(self, event): + + btn = event.GetEventObject() + label = btn.GetLabel() + angle = int(btn.GetAngleOfRotation()) + + mystr = "You Clicked: " + label + ", Rotated By: " + str(angle) + " Degrees" + self.eventtext.SetLabel(mystr) + self.eventtext.Refresh() + + btn.SetAngleOfRotation(random.randint(0, 359)) + + event.Skip() + + + def OnEllipse(self, event): + + btn = event.GetEventObject() + label = btn.GetLabel() + angle = int(btn.GetAngleOfRotation()) + + mystr = "Do You Like Them? (Rotation = " + str(angle) + " Degrees)" + self.eventtext.SetLabel(mystr) + self.eventtext.Refresh() + + event.Skip() + + + def OnFFWDRewind(self, event): + + btn = event.GetEventObject() + + if event.GetIsDown(): + label = "Let's Rewind Everything" + btn.SetLabel("REW") + else: + label = "Go To The End Of The Tape!" + btn.SetLabel("FFWD") + + self.eventtext.SetLabel(label) + self.eventtext.Refresh() + + event.Skip() + + + def OnRound(self, event): + + self.eventtext.SetLabel("I Have Nothing To Say Here ;-)") + self.eventtext.Refresh() + + event.Skip() + + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test ShapedButton ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = ShapedButtonDemo(self, self.log) + self.win.Show(True) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + + try: + import PIL.Image + win = TestPanel(nb, log) + return win + + except ImportError: + + from Main import MessagePanel + win = MessagePanel(nb, 'This demo requires PIL (Python Imaging Library).', + 'Sorry', wx.ICON_WARNING) + return win + +#---------------------------------------------------------------------- + + +overview = docs + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/ShortcutEditor.py b/demo/agw/ShortcutEditor.py new file mode 100644 index 00000000..b8a9ccb5 --- /dev/null +++ b/demo/agw/ShortcutEditor.py @@ -0,0 +1,396 @@ +import wx + +import os +import sys +import string +import random + +from images import catalog +import images + +from wx.lib.embeddedimage import PyEmbeddedImage + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import shortcuteditor as SE +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.shortcuteditor as SE + + +SE_DIR = os.path.split(SE.__file__)[0] +HTML_HELP = os.path.join(SE_DIR, 'data', 'default_help_text.html') + +TOP_MENUS = ['File', 'Edit', 'View', 'Options', 'Window', 'Help'] + +COMBINATIONS = string.ascii_uppercase + string.digits +COMBINATIONS = [c for c in COMBINATIONS] + SE.KEYMAP.values() + +ACCEL_IDS = [wx.NewId() for i in xrange(6)] + +_ = wx.GetTranslation + + +#---------------------------------------------------------------------- +_accelerators = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9i" + "ZSBJbWFnZVJlYWR5ccllPAAAAUNJREFUeNqkkrFqg1AUho+idLKCEgSnvoBkUiwBoU4tGXyJ" + "Lpmy+QI+gUuzFbK5OhSKQzZBfIlACCEiplAHkQj2XFNDaYOJ6YHPH7n85z/ncqm6ruE/xZDP" + "eDzu66ORELmnrwy+Q9K2U9+6RZ6Rt+MKvw6nyCNy09HkHXk91cBGPpAn5PPiS/wuFnlATKS8" + "dB9qPp+/oE6uvMwZU1XVxDRNyLIMBEGA3W53VkmJogiLxWJC7/d7WK/XMBwOYbVanVVFURqI" + "h3gp13VrXdchTdNesw8GA4iiCOiyLIHneSiKAgzD6NTRaASqqgIJ3G63QLyU4zi1pmmQJEln" + "IsdxkOf58V+SJIjjGBjShZgtywLP8xolu/0slmXB9/3mrNUgCA4T2LbdTLDZbP6knJqgVVmW" + "DxNg2iwMw97vYLlcNu/gS4ABALx5qLfCRWM1AAAAAElFTkSuQmCC") + + +#---------------------------------------------------------------------- +_edit = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAABmJLR0QAAAAAAAD5Q7t/AAAA" + "CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1QsOEh8bQbXRcgAAAhxJREFUKM91ks1rE1EU" + "xc99H5l8m2lolKRuqtamKohFChahYF0IfoBSF4IbwY1/gv+DK/cuXLgTxaWIXSjSjWKEFgm4" + "aGvaJo1NJpm0eTPvzXPRmrZgz+7C+d3DPVz6WvmVTMTwT9tKK2W9le8Ta08VTXei0fL9R8nC" + "iYFBJJPO2VPFwRyEkbLMazwrnvvJTM5frP3+MDz24PHAwGAtDohLZpt113nHNoH5he6nL+mx" + "8wcNDIdFAG++imMVLaCFbzT+vtrdanWOBEyny9sveQjssLUa712aq7e9xaXqkQC8ea4r6Mds" + "nTZKV07O3iu4KSJ7JGCXn8tMAn685WX98dtDI0UOwxj9HzAbCzxeRS+NjrOVnnBn5hJWZdOZ" + "Rr0BIAiCw4Ax0doLFmdQWb+dbo3ccIslwRhx8trtMAybzT+9Xk/shikLbFSEs0zaBZzGjjN8" + "92Hgt8NAdbyOUkprDaDb9cXu9igCTB9RCfGMv15r5qfjEVebTUYUGUNEAIhICM4G9euQuJw1" + "+nplyQ3PzGirTWSFFAQCkRAilzuWz+f3EiTHcn37x8fPpUSKrj5JjZZ1fxuwXLBkKiV4KKWU" + "Uu4dvVtyf0evV9fl5J38hSkE/ZiQrpstFI4LyYul0v7zEWcEcKA8OXX64mWeG9L9MMxlpBOL" + "jI3FOOeCs/0yxepK7c3rt1wwYhJEkQlguYWxFjayjJHndW/dvDYA/gKtTuQVCWY6EAAAAABJ" + "RU5ErkJgggo=") + +#---------------------------------------------------------------------- +_file = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQBAMAAADt3eJSAAAAB3RJTUUH0AwNAR44FPFuJQAA" + "AAlwSFlzAAAK8AAACvABQqw0mAAAADBQTFRFAP8Af39/UFBQz8/P4ODg////8PDw///wn5+f" + "MDAwgICAAAAAAAAAAAAAAAAAAAAAZbZ2KAAAAAF0Uk5TAEDm2GYAAABRSURBVHjaY2BcBQQL" + "GBgYGEOBoAnECC8vL29XgDI0Z0IY6RZCYEZZmXMTRCTFxQjMSHeBMNLdoIySFCgDKABmhKVB" + "GS4uUIYxCIAYSmDAAAcA0SwdEWLFwocAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_help = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAC+ElEQVR4nGWTP2xbVRjFf9+9" + "9/01TgwJCQkMbkMKqCkEKGoXBpiQEqkpZUL8y8BeRqYwMMBQRMWMGtQgJCSKYWCohARIVCCo" + "MJUgLbSipVERTuzYcexn+713L4OlirafdLZzznC+c4TbbnZxrSTIEkoeQ9S8iICob0WkevHM" + "C5Xb+XKLeOH08WIxXnloZqoUhSFRFDHIcmr1XerNDts7navWuTfWPz1SucNgduH0qfm58mt7" + "y/ezfq1LrZmR2SHFaAg9QTtLo1WnnybLv3+yuHrTYHZh7a1DT8ysFEfH+eVyh73TEa8vTvL0" + "o0WsdXzz6w6nzm5x5cYALdDtNMgG3aO/ffxcRWYX18pTE6W/Dj7+CN9daDM17lN5+2GsteS5" + "w1qLc44b9ZSXTlxHRHDOkrRqTWvzPXp837GVw0/OHl7fyOiljt2eJQ4U9VbGiTM1HLBn0iP2" + "hR8v92n1QGmNaB3m6eCS8QNvSZmI7XYXRECED76skTshs6C18OyBGOccm7uOTjrMLNQRottH" + "zOhIoVxrpsM0BPqpo9vJEa15YMLnzWNjWGs590efRg/8yABQUJB0dclYB71BjnWwvZORI3i+" + "RnuKd16ZIA6EK/9mnPy6QxB7KDV8XDFw1BsGM0hzBMfmdooTwfgKZRQLB+9iZtJgrePD7xNS" + "ZQgChdIKgJGCRZRGdZJBpd1OsM4hSlB6iKl7DM45nHNc2nQEoSGIPMLYY2TEIwxAtKkaRH3R" + "au8uFcNRulZQaojKzwn7pn22EjC+xgs0fuhhfE15DP5cbyFKf6Qufvb8atJPqpHOMQKIIEo4" + "+lTMoRmfhTmfuWmD9jReqJm+10ORs/FPv3L+/QNVBeBwy4O01QzE3uz2hesp3QFs7MDfTYdR" + "cN+oUPIyzv3QqIrSy7dsYf+LX82jzOe5GS3rsEgcGeKCR6FouLvkMVYybDV6XNtIqoNMnvnp" + "3Qebd6xx7uWzJZQ6Ltp71XhBOS7EhJEhzS27SV4VbU6ef2//6v81/wH6bjI8fK9HXAAAAABJ" + "RU5ErkJggg==") + +#---------------------------------------------------------------------- +_options = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAA" + "CXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH1QkaDBM5i2PCSAAAAfBJREFUOMulkktoE2EU" + "hb+Z+EyKTRQKgkqwzMaFtt1FrC40FGJm60JwIVSkqLUtElICFQNDQqBrQXRlQIriwomN0GJX" + "gtI2iUkXFYJVadOXhiBERDozbmaGMR3rwrP7ueece++5P/wnBOcjnVGigArI8Vgi9xdNNJ1R" + "bI7YUlT7r/YDqKaZq/j6tQHNbLQd6YxiNBp1I51RDPdaw6pFAcR0RolaZKur19vmZhwFePDw" + "PvFYQgZyACKgDt4cMp4+mzAA9fatETbX15A6Jer1r/das4ndGRUsMYBgFW8MDBqatiXoum7o" + "ukZhfk4ovC8CyDsFK7R0sBHpu0i5UmG59gUgGY8l7v7zjE68yr80SpUS3Sd7KJYLmBNMArqr" + "QTCSOgzUrPeVkE7XCYmjR47RbDZ5N/cWtzU8TvH4cJi+UCcdAS/ZmU2Ot39LLn1eOtd9qoeA" + "P8BKbfnyhfD5+emp11XAABCDkVQXUHs0JjNbXmS2vEjHQR8A5t5yLv8CSZI4e7rX+mR2HiJQ" + "HB8OM/WmxJamI+7zs1Fv2iOaI8vZJ4850O7nTKgXYMxpAMDuXR72+A7x88cvsvkFgHCrSS6v" + "Uv1Y/SNsEWBl4zv7fQHa9np4PvMBIPxpcnTaSTRNkmvrqwtA0r5CMJK6BEw4uNvEO+E3N+LV" + "9uq8VLwAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_view = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAB3RJTUUH2QMSDgcQHD2pKgAA" + "AAlwSFlzAAALEgAACxIB0t1+/AAAAARnQU1BAACxjwv8YQUAAACWUExURb7Dxvz8/ObXxs+0" + "mK6UZb6JXMGZf9rBpezn39PT07unkOq0iuvBotSdZ/7+/trZ2eng1uvr5O7u7v///ubMsNDe" + "7ae+23Og32aX3Y+z58va6vHx8fT09Nzm8Zm66nql4+Dg3/j4+LXN8IOs5vf39/v7+6fE7g8U" + "G8iUWdXGwMqldOvUtr/Jzunp6ayfnaSps5qhs9/NuBN0LcUAAAABdFJOUwBA5thmAAAAqUlE" + "QVR42o2PSxaCMBAEx4kQZIKGGAQEE8NXRUHufzkRL2Dt6vWmGuAfXIzzrLWW7ucKh2HgjAsh" + "gq+/cGDhOE3v0SfCdQ+fXWdMXlecKACp723Vmb6vbd0iPUDLpu1M3vc2tW0jb3BVpavy2to0" + "M65UDFAW5cUsmtmkLJAg1hio5JRm+bmIdcQADlygjNUCUuQfl5BdSLRECYo8tl9TN8i2nuf5" + "PPjr6Qc/LA45I8MgVQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_window = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAKnRFWHRDcmVhdGlvbiBUaW1l" + "AERpIDQgTXJ6IDIwMDMgMDA6MjQ6MDQgKzAxMDDdSQ6OAAAAB3RJTUUH0woGFAwIjuRPzgAA" + "AAlwSFlzAAAK8AAACvABQqw0mAAAAARnQU1BAACxjwv8YQUAAAEVSURBVHjaY2SY/tuDgYll" + "OwMp4OqOKIZJntuArM+MDDP//59pTLzeJQ8ZGA6/ATLSGT2A5AkWkGD6WSDx5g1xJvDwMDBw" + "cIBYlkB8C2zANdvrKGr+/mVg+P0bQv/5g8AgsT9/XjN4PdYEKRMEYjawAZqamigGgBT/+gXR" + "AKORMcNjsDJGEMFEUuBhAdQ34N8/VEwIsMD8jGwAiA8KQBgbn6FgA0ABhWwAsub//xF8nAaA" + "QxbNCzBXwFwAYoMMA2G8LoB5CaQQZggMwwzD6wJ0b6C7AoSh4D/EgGu7IqUZ3JaTFHcdFkuA" + "5HuQ40GpiR+ILRggaRuUPBkJaP8P1XwciE8wQtMCLxALAzErkW4AefotEH8GAEJMrcAWjkHy" + "AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- + +def GetValidMenuImages(): + + keys = catalog.keys() + valid_images = [] + counter = 0 + + for key in keys: + bmp = catalog[key].GetBitmap() + if bmp.GetWidth() == 16 and bmp.GetHeight() == 16: + valid_images.append(bmp) + + return valid_images + +#---------------------------------------------------------------------- + +class ShortcutEditorDemo(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent, -1, 'ShortcutEditor wxPython Demo :-D', size=(900, 800)) + + self.log = log + + self.valid_images = GetValidMenuImages() + self.used_shortcuts = [] + + self.SetIcon(images.Mondrian.GetIcon()) + + self.MakeMenuBar() + self.MakeAcceleratorTable() + + dlg = SE.ShortcutEditor(self) + dlg.FromMenuBar(self) + dlg.FromAcceleratorTable(self.accelTable) + + self.AddTopMenuBitmaps(dlg) + + dlg.Bind(SE.EVT_SHORTCUT_CHANGING, self.OnShortcutChanging) + dlg.Bind(SE.EVT_SHORTCUT_CHANGED, self.OnShortcutChanged) + + self.CenterOnScreen() + self.Show() + self.Raise() + + wx.CallAfter(self.ShowDialog, dlg) + + + def MakeMenuBar(self): + + bar = wx.MenuBar() + top_menus = [] + + for title in TOP_MENUS: + menu = wx.Menu() + + self.AppendMenus(menu, title) + + bar.Append(menu, title) + top_menus.append(menu) + + self.SetMenuBar(bar) + + + def MakeAcceleratorTable(self): + + table = [] + saved_table = [] + + for i in xrange(6): + name = 'Accelerator %d'%(i+1) + choice = random.choice(SE.ACCELERATORS.keys()) + + if choice == wx.ACCEL_ALT: + letter = random.choice(COMBINATIONS) + + if len(letter) > 1: + inv_keyMap = dict(zip(SE.KEYMAP.values(), SE.KEYMAP.keys())) + wxk = inv_keyMap[letter] + else: + wxk = ord(letter) + + else: + wxk = random.choice(SE.KEYMAP.keys()) + + accel = (choice, wxk, ACCEL_IDS[i]) + saved_accel = (name, choice, wxk, ACCEL_IDS[i]) + + self.Bind(wx.EVT_MENU, self.OnAcceleratorShortcuts, id=ACCEL_IDS[i]) + + table.append(accel) + saved_table.append(saved_accel) + + self.accelTable = saved_table + self.SetAcceleratorTable(wx.AcceleratorTable(table)) + + + def AppendMenus(self, top_menu, title, recursive=''): + + num_menus = random.randint(2, 7) + + for index in xrange(num_menus): + shortcut = self.CreateShortcut() + + sub_menu = wx.MenuItem(top_menu, -1, '%s%sItem %d%s'%(recursive, title, index+1, shortcut), + 'Help for %s%sItem %d'%(recursive, title, index+1)) + + if random.randint(0, 1) == 1: + # Get a random image for the menu + bmp = random.choice(self.valid_images) + sub_menu.SetBitmap(bmp) + + self.Bind(wx.EVT_MENU, self.OnMenuShortcuts, id=sub_menu.GetId()) + + if random.randint(0, 10) == 5 and not recursive: + # Append a sub-sub-menu + dummy_menu = wx.Menu() + + recursive = 'Sub-' + self.AppendMenus(dummy_menu, title, recursive) + dummy_item = top_menu.AppendSubMenu(dummy_menu, 'Sub ' + title) + + if random.randint(0, 1) == 1: + # Get a random image for the menu + bmp = random.choice(self.valid_images) + dummy_item.SetBitmap(bmp) + + recursive = '' + + top_menu.AppendItem(sub_menu) + + if random.randint(0, 1) == 1 and index < num_menus - 1: + # Append a separator + top_menu.AppendSeparator() + + + def CreateShortcut(self): + + rand = random.randint(0, 3) + + if rand == 0: + # No shortcut + return '' + + letter = random.choice(COMBINATIONS) + shortcut = '\t%s+' + letter + + if rand == 1: + # Ctrl + character + modifier = 'Ctrl' + + elif rand == 2: + # Shift + character + modifier = 'Shift' + + else: + # Ctrl + Shift + character + modifier = 'Ctrl+Shift' + + shortcut = shortcut % modifier + + if shortcut in self.used_shortcuts: + return self.CreateShortcut() + + self.used_shortcuts.append(shortcut) + return shortcut + + + def AddTopMenuBitmaps(self, dlg): + + manager = dlg.GetShortcutManager() + + for child in manager.children: + name = child.label.lower() + bitmap = eval('_%s'%name).GetBitmap() + child.SetBitmap(bitmap) + + + def ShowDialog(self, dlg): + + answer = dlg.ShowModal() + + if answer == wx.ID_CANCEL: + dlg.Destroy() + return + + dlg.ToMenuBar(self) + dlg.ToAcceleratorTable(self) + + dlg.Destroy() + + + def OnMenuShortcuts(self, event): + + itemId = event.GetId() + menu = event.GetEventObject().GetMenuBar() + menuItem = menu.FindItemById(itemId) + + label = menuItem.GetItemLabel() + label, accel = label.split('\t') + + self.log.write('You have selected the shortcut for %s (%s)'%(label, accel)) + + + def OnAcceleratorShortcuts(self, event): + + itemId = event.GetId() + + for label, choice, accel, ids in self.accelTable: + if ids == itemId: + self.log.write('You have selected the accelerator for %s (%s)'%(label, accel)) + break + + + def OnShortcutChanging(self, event): + + shortcut = event.GetShortcut() + oldAccel = event.GetOldAccelerator() + newAccel = event.GetAccelerator() + + self.log.write('Shortcut for "%s" changing from "%s" to "%s"'%(shortcut.label, oldAccel, newAccel)) + event.Skip() + + + def OnShortcutChanged(self, event): + + shortcut = event.GetShortcut() + newAccel = event.GetAccelerator() + + self.log.write('Shortcut for "%s" changed to "%s"'%(shortcut.label, newAccel)) + + +#--------------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b1 = wx.Button(self, -1, " Run ShortcutEditor ", (50, 50)) + self.Bind(wx.EVT_BUTTON, self.OnButton1, b1) + + + def OnButton1(self, event): + self.win = ShortcutEditorDemo(self, self.log) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = open(HTML_HELP, 'rt').read() + + +if __name__ == '__main__': + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/SpeedMeter.py b/demo/agw/SpeedMeter.py new file mode 100644 index 00000000..2f955510 --- /dev/null +++ b/demo/agw/SpeedMeter.py @@ -0,0 +1,653 @@ +import wx +import wx.lib.buttons +from math import pi, sqrt + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +bitmapDir = os.path.join(dirName, 'bitmaps') +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import speedmeter as SM +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.speedmeter as SM + + +#---------------------------------------------------------------------- +# Beginning Of SPEEDMETER Demo wxPython Code +#---------------------------------------------------------------------- + +class SpeedMeterDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent, style=wx.TAB_TRAVERSAL|wx.NO_FULL_REPAINT_ON_RESIZE) + + panel = wx.Panel(self, -1) + sizer = wx.FlexGridSizer(2, 3, 2, 5) + + # 6 Panels To Hold The SpeedMeters ;-) + + panel1 = wx.Panel(panel, -1, style=wx.SUNKEN_BORDER) + panel2 = wx.Panel(panel, -1, style=wx.RAISED_BORDER) + panel3 = wx.Panel(panel, -1, style=wx.SUNKEN_BORDER) + panel4 = wx.Panel(panel, -1, style=wx.RAISED_BORDER) + panel5 = wx.Panel(panel, -1, style=wx.SUNKEN_BORDER) + panel6 = wx.Panel(panel, -1, style=wx.RAISED_BORDER) + + # First SpeedMeter: We Use The Following Styles: + # + # SM_DRAW_HAND: We Want To Draw The Hand (Arrow) Indicator + # SM_DRAW_SECTORS: Full Sectors Will Be Drawn, To Indicate Different Intervals + # SM_DRAW_MIDDLE_TEXT: We Draw Some Text In The Center Of SpeedMeter + # SM_DRAW_SECONDARY_TICKS: We Draw Secondary (Intermediate) Ticks Between + # The Main Ticks (Intervals) + + self.SpeedWindow1 = SM.SpeedMeter(panel1, + agwStyle=SM.SM_DRAW_HAND | + SM.SM_DRAW_SECTORS | + SM.SM_DRAW_MIDDLE_TEXT | + SM.SM_DRAW_SECONDARY_TICKS + ) + + # Set The Region Of Existence Of SpeedMeter (Always In Radians!!!!) + self.SpeedWindow1.SetAngleRange(-pi/6, 7*pi/6) + + # Create The Intervals That Will Divide Our SpeedMeter In Sectors + intervals = range(0, 201, 20) + self.SpeedWindow1.SetIntervals(intervals) + + # Assign The Same Colours To All Sectors (We Simulate A Car Control For Speed) + # Usually This Is Black + colours = [wx.BLACK]*10 + self.SpeedWindow1.SetIntervalColours(colours) + + # Assign The Ticks: Here They Are Simply The String Equivalent Of The Intervals + ticks = [str(interval) for interval in intervals] + self.SpeedWindow1.SetTicks(ticks) + # Set The Ticks/Tick Markers Colour + self.SpeedWindow1.SetTicksColour(wx.WHITE) + # We Want To Draw 5 Secondary Ticks Between The Principal Ticks + self.SpeedWindow1.SetNumberOfSecondaryTicks(5) + + # Set The Font For The Ticks Markers + self.SpeedWindow1.SetTicksFont(wx.Font(7, wx.SWISS, wx.NORMAL, wx.NORMAL)) + + # Set The Text In The Center Of SpeedMeter + self.SpeedWindow1.SetMiddleText("Km/h") + # Assign The Colour To The Center Text + self.SpeedWindow1.SetMiddleTextColour(wx.WHITE) + # Assign A Font To The Center Text + self.SpeedWindow1.SetMiddleTextFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD)) + + # Set The Colour For The Hand Indicator + self.SpeedWindow1.SetHandColour(wx.Colour(255, 50, 0)) + + # Do Not Draw The External (Container) Arc. Drawing The External Arc May + # Sometimes Create Uglier Controls. Try To Comment This Line And See It + # For Yourself! + self.SpeedWindow1.DrawExternalArc(False) + + # Set The Current Value For The SpeedMeter + self.SpeedWindow1.SetSpeedValue(44) + + + # Second SpeedMeter: We Use The Following Styles: + # + # SM_DRAW_HAND: We Want To Draw The Hand (Arrow) Indicator + # SM_DRAW_SECTORS: Full Sectors Will Be Drawn, To Indicate Different Intervals + # SM_DRAW_MIDDLE_TEXT: We Draw Some Text In The Center Of SpeedMeter + # SM_DRAW_SECONDARY_TICKS: We Draw Secondary (Intermediate) Ticks Between + # The Main Ticks (Intervals) + # SM_DRAW_PARTIAL_FILLER: The Region Passed By The Hand Indicator Is Highlighted + # With A Different Filling Colour + # SM_DRAW_SHADOW: A Shadow For The Hand Indicator Is Drawn + + self.SpeedWindow2 = SM.SpeedMeter(panel2, + agwStyle=SM.SM_DRAW_HAND | + SM.SM_DRAW_SECTORS | + SM.SM_DRAW_MIDDLE_TEXT | + SM.SM_DRAW_SECONDARY_TICKS | + SM.SM_DRAW_PARTIAL_FILLER | + SM.SM_DRAW_SHADOW + ) + + # We Want To Simulate A Clock. Somewhat Tricky, But Did The Job + self.SpeedWindow2.SetAngleRange(pi/2, 5*pi/2) + + intervals = range(0, 13) + self.SpeedWindow2.SetIntervals(intervals) + + colours = [wx.SystemSettings_GetColour(0)]*12 + self.SpeedWindow2.SetIntervalColours(colours) + + ticks = [str(interval) for interval in intervals] + ticks[-1] = "" + ticks[0] = "12" + self.SpeedWindow2.SetTicks(ticks) + self.SpeedWindow2.SetTicksColour(wx.BLUE) + self.SpeedWindow2.SetTicksFont(wx.Font(11, wx.SCRIPT, wx.NORMAL, wx.BOLD, True)) + self.SpeedWindow2.SetNumberOfSecondaryTicks(4) + + # Set The Colour For The External Arc + self.SpeedWindow2.SetArcColour(wx.BLUE) + + self.SpeedWindow2.SetHandColour(wx.BLACK) + + self.SpeedWindow2.SetMiddleText("0 s") + self.SpeedWindow2.SetMiddleTextColour(wx.RED) + + # We Set The Background Colour Of The SpeedMeter OutSide The Control + self.SpeedWindow2.SetSpeedBackground(wx.WHITE) + + # Set The Colour For The Shadow + self.SpeedWindow2.SetShadowColour(wx.Colour(128, 128, 128)) + + self.SpeedWindow2.SetSpeedValue(0.0) + + + # Third SpeedMeter: We Use The Following Styles: + # + # SM_DRAW_HAND: We Want To Draw The Hand (Arrow) Indicator + # SM_DRAW_PARTIAL_SECTORS: Partial Sectors Will Be Drawn, To Indicate Different Intervals + # SM_DRAW_MIDDLE_ICON: We Draw An Icon In The Center Of SpeedMeter + + self.SpeedWindow3 = SM.SpeedMeter(panel3, + agwStyle=SM.SM_DRAW_HAND | + SM.SM_DRAW_PARTIAL_SECTORS | + SM.SM_DRAW_MIDDLE_ICON + ) + + # We Want To Simulate A Car Gas-Control + self.SpeedWindow3.SetAngleRange(-pi/3, pi/3) + + intervals = range(0, 5) + self.SpeedWindow3.SetIntervals(intervals) + + colours = [wx.BLACK]*3 + colours.append(wx.RED) + self.SpeedWindow3.SetIntervalColours(colours) + + ticks = ["F", "", "", "", "E"] + self.SpeedWindow3.SetTicks(ticks) + self.SpeedWindow3.SetTicksColour(wx.WHITE) + + self.SpeedWindow3.SetHandColour(wx.Colour(255, 255, 0)) + + # Define The Icon We Want + icon = wx.Icon(os.path.normpath(os.path.join(bitmapDir, "smfuel.ico")), wx.BITMAP_TYPE_ICO) + icon.SetWidth(24) + icon.SetHeight(24) + + # Draw The Icon In The Center Of SpeedMeter + self.SpeedWindow3.SetMiddleIcon(icon) + + self.SpeedWindow3.SetSpeedBackground(wx.BLACK) + + self.SpeedWindow3.SetArcColour(wx.WHITE) + + self.SpeedWindow3.SetSpeedValue(0.7) + + + # Fourth SpeedMeter: We Use The Following Styles: + # + # SM_DRAW_HAND: We Want To Draw The Hand (Arrow) Indicator + # SM_DRAW_SECTORS: Full Sectors Will Be Drawn, To Indicate Different Intervals + # SM_DRAW_SHADOW: A Shadow For The Hand Indicator Is Drawn + # SM_DRAW_MIDDLE_ICON: We Draw An Icon In The Center Of SpeedMeter + # + # NOTE: We Use The Mouse Style mousestyle=SM_MOUSE_TRACK. In This Way, Mouse + # Events Are Catched (Mainly Left Clicks/Drags) And You Can Change The Speed + # Value Using The Mouse + + self.SpeedWindow4 = SM.SpeedMeter(panel4, + agwStyle=SM.SM_DRAW_HAND | + SM.SM_DRAW_SECTORS | + SM.SM_DRAW_SHADOW | + SM.SM_DRAW_MIDDLE_ICON, + mousestyle=SM.SM_MOUSE_TRACK + ) + + # We Want To Simulate Some Kind Of Thermometer (In Celsius Degrees!!!) + self.SpeedWindow4.SetAngleRange(pi, 2*pi) + + intervals = range(35, 44) + self.SpeedWindow4.SetIntervals(intervals) + + colours = [wx.BLUE]*5 + colours.extend([wx.Colour(255, 255, 0)]*2) + colours.append(wx.RED) + self.SpeedWindow4.SetIntervalColours(colours) + + ticks = [str(interval) + "C" for interval in intervals] + self.SpeedWindow4.SetTicks(ticks) + self.SpeedWindow4.SetTicksColour(wx.BLACK) + self.SpeedWindow4.SetTicksFont(wx.Font(7, wx.TELETYPE, wx.NORMAL, wx.BOLD)) + + self.SpeedWindow4.SetHandColour(wx.Colour(0, 0, 255)) + + self.SpeedWindow4.SetSpeedBackground(wx.SystemSettings_GetColour(0)) + + self.SpeedWindow4.DrawExternalArc(False) + + self.SpeedWindow4.SetHandColour(wx.GREEN) + self.SpeedWindow4.SetShadowColour(wx.Colour(50, 50, 50)) + + # We Want A Simple Arrow As Indicator, Not The More Scenic Hand ;-) + self.SpeedWindow4.SetHandStyle("Arrow") + + # Define The Icon We Want + icon = wx.Icon(os.path.normpath(os.path.join(bitmapDir, "smtemp.ico")), wx.BITMAP_TYPE_ICO) + icon.SetWidth(16) + icon.SetHeight(16) + + # Draw The Icon In The Center Of SpeedMeter + self.SpeedWindow4.SetMiddleIcon(icon) + + # Quite An High Fever!!! + self.SpeedWindow4.SetSpeedValue(41.4) + + + # Fifth SpeedMeter: We Use The Following Styles: + # + # SM_DRAW_HAND: We Want To Draw The Hand (Arrow) Indicator + # SM_DRAW_PARTIAL_SECTORS: Partial Sectors Will Be Drawn, To Indicate Different Intervals + # SM_DRAW_SECONDARY_TICKS: We Draw Secondary (Intermediate) Ticks Between + # The Main Ticks (Intervals) + # SM_DRAW_MIDDLE_TEXT: We Draw Some Text In The Center Of SpeedMeter + # SM_ROTATE_TEXT: The Ticks Texts Are Rotated Accordingly To Their Angle + + self.SpeedWindow5 = SM.SpeedMeter(panel5, + agwStyle=SM.SM_DRAW_HAND | + SM.SM_DRAW_PARTIAL_SECTORS | + SM.SM_DRAW_SECONDARY_TICKS | + SM.SM_DRAW_MIDDLE_TEXT | + SM.SM_ROTATE_TEXT + ) + + # We Want To Simulate The Round Per Meter Control In A Car + self.SpeedWindow5.SetAngleRange(-pi/6, 7*pi/6) + + intervals = range(0, 9) + self.SpeedWindow5.SetIntervals(intervals) + + colours = [wx.BLACK]*6 + colours.append(wx.Colour(255, 255, 0)) + colours.append(wx.RED) + self.SpeedWindow5.SetIntervalColours(colours) + + ticks = [str(interval) for interval in intervals] + self.SpeedWindow5.SetTicks(ticks) + self.SpeedWindow5.SetTicksColour(wx.WHITE) + self.SpeedWindow5.SetTicksFont(wx.Font(7, wx.SWISS, wx.NORMAL, wx.NORMAL)) + + self.SpeedWindow5.SetHandColour(wx.Colour(255, 50, 0)) + + self.SpeedWindow5.SetSpeedBackground(wx.SystemSettings_GetColour(0)) + + self.SpeedWindow5.DrawExternalArc(False) + + self.SpeedWindow5.SetShadowColour(wx.Colour(50, 50, 50)) + + self.SpeedWindow5.SetMiddleText("rpm") + self.SpeedWindow5.SetMiddleTextColour(wx.WHITE) + self.SpeedWindow5.SetMiddleTextFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD)) + self.SpeedWindow5.SetSpeedBackground(wx.Colour(160, 160, 160)) + + self.SpeedWindow5.SetSpeedValue(5.6) + + + # Sixth SpeedMeter: That Is Complete And Complex Example. + # We Use The Following Styles: + # + # SM_DRAW_HAND: We Want To Draw The Hand (Arrow) Indicator + # SM_DRAW_PARTIAL_FILLER: The Region Passed By The Hand Indicator Is Highlighted + # With A Different Filling Colour + # SM_DRAW_MIDDLE_ICON: We Draw An Icon In The Center Of SpeedMeter + # SM_DRAW_GRADIENT: A Circular Colour Gradient Is Drawn Inside The SpeedMeter, To + # Give Some Kind Of Scenic Effect + # SM_DRAW_FANCY_TICKS: We Use wx.lib. + # SM_DRAW_SHADOW: A Shadow For The Hand Indicator Is Drawn + + self.SpeedWindow6 = SM.SpeedMeter(panel6, + agwStyle=SM.SM_DRAW_HAND | + SM.SM_DRAW_PARTIAL_FILLER | + SM.SM_DRAW_MIDDLE_ICON | + SM.SM_DRAW_GRADIENT | + SM.SM_DRAW_FANCY_TICKS | + SM.SM_DRAW_SHADOW + ) + + self.SpeedWindow6.SetAngleRange(0, 4*pi/3) + + intervals = [0, pi/6, sqrt(pi), 2./3.*pi, pi**2/4, pi, 7./6.*pi, 4*pi/3] + self.SpeedWindow6.SetIntervals(intervals) + + # If You Use The Style SM_DRAW_FANCY_TICKS, Refer To wx.lib.fancytext To Create + # Correct XML Strings To Put Here + ticks = ["0", "/6", "sq()", "2/3", "2/4", "", "7/6", "4/3"] + self.SpeedWindow6.SetTicks(ticks) + self.SpeedWindow6.SetTicksColour(wx.Colour(0, 90, 0)) + self.SpeedWindow6.SetTicksFont(wx.Font(6, wx.ROMAN, wx.NORMAL, wx.BOLD)) + + self.SpeedWindow6.SetHandColour(wx.Colour(60, 60, 60)) + + self.SpeedWindow6.DrawExternalArc(False) + + self.SpeedWindow6.SetFillerColour(wx.Colour(145, 220, 200)) + + self.SpeedWindow6.SetShadowColour(wx.BLACK) + + self.SpeedWindow6.SetDirection("Reverse") + + self.SpeedWindow6.SetSpeedBackground(wx.SystemSettings_GetColour(0)) + + # Set The First Gradient Colour, Which Is The Colour Near The External Arc + self.SpeedWindow6.SetFirstGradientColour(wx.RED) + # Set The Second Gradient Colour, Which Is The Colour Near The Center Of The SpeedMeter + self.SpeedWindow6.SetSecondGradientColour(wx.WHITE) + + icon = wx.Icon(os.path.normpath(os.path.join(bitmapDir, "smpi.ico")), wx.BITMAP_TYPE_ICO) + icon.SetHeight(12) + icon.SetWidth(12) + self.SpeedWindow6.SetMiddleIcon(icon) + + self.SpeedWindow6.SetSpeedValue(pi/3) + + + # End Of SpeedMeter Controls Construction. Add Some Functionality + + self.isalive = 0 + + # These Are Cosmetics For The First SpeedMeter Control + bsizer1 = wx.BoxSizer(wx.VERTICAL) + + hsizer1 = wx.BoxSizer(wx.HORIZONTAL) + slider = wx.Slider(panel1, -1, 44, 0, 200, size=(-1, 40), + style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS ) + slider.SetTickFreq(5, 1) + slider.Bind(wx.EVT_SCROLL, self.OnSliderScroll) + slider.SetToolTip(wx.ToolTip("Drag The Slider To Change The Speed!")) + + hsizer1.Add(slider, 1, wx.EXPAND) + + bsizer1.Add(self.SpeedWindow1, 1, wx.EXPAND) + bsizer1.Add(hsizer1, 0, wx.EXPAND) + panel1.SetSizer(bsizer1) + + + # These Are Cosmetics For The Second SpeedMeter Control + + # Create The Timer For The Clock + self.timer = wx.PyTimer(self.ClockTimer) + self.currvalue = 0 + + bsizer2 = wx.BoxSizer(wx.VERTICAL) + + hsizer2 = wx.BoxSizer(wx.HORIZONTAL) + stattext2 = wx.StaticText(panel2, -1, "A Simple Clock", style=wx.ALIGN_CENTER) + + button2 = wx.Button(panel2, -1, "Stop") + self.stopped = 0 + button2.Bind(wx.EVT_BUTTON, self.OnStopClock) + button2.SetToolTip(wx.ToolTip("Click To Stop/Resume The Clock")) + + hsizer2.Add(button2, 0, wx.LEFT, 5) + hsizer2.Add(stattext2, 1, wx.EXPAND) + + bsizer2.Add(self.SpeedWindow2, 1, wx.EXPAND) + bsizer2.Add(hsizer2, 0, wx.EXPAND) + panel2.SetSizer(bsizer2) + + + # These Are Cosmetics For The Third SpeedMeter Control + self.timer3 = wx.PyTimer(self.OilTimer) + + bsizer3 = wx.BoxSizer(wx.VERTICAL) + + hsizer3 = wx.BoxSizer(wx.HORIZONTAL) + sc = wx.SpinCtrl(panel3, -1, size=(60,20)) + sc.SetRange(1, 250) + sc.SetValue(50) + + self.spinctrl = sc + + strs = "Change The Speed And See How Much Fuel You Loose" + self.spinctrl.SetToolTip(wx.ToolTip(strs)) + + button3 = wx.Button(panel3, -1, "Refill!", size=(60,20)) + button3.SetToolTip(wx.ToolTip("Click Here To Refill!")) + button3.Bind(wx.EVT_BUTTON, self.OnRefill) + + hsizer3.Add(self.spinctrl, 0, wx.EXPAND | wx.LEFT, 5) + hsizer3.Add(button3, 0, wx.EXPAND | wx.LEFT, 5) + hsizer3.Add((1,0), 2, wx.EXPAND) + + bsizer3.Add(self.SpeedWindow3, 1, wx.EXPAND) + bsizer3.Add(hsizer3, 0, wx.EXPAND) + panel3.SetSizer(bsizer3) + + + # These Are Cosmetics For The Fourth SpeedMeter Control + bsizer4 = wx.BoxSizer(wx.VERTICAL) + + hsizer4 = wx.BoxSizer(wx.HORIZONTAL) + stattext4 = wx.StaticText(panel4, -1, "Use The Mouse ;-)") + + hsizer4.Add(stattext4, 1, wx.EXPAND | wx.LEFT, 5) + + bsizer4.Add(self.SpeedWindow4, 1, wx.EXPAND) + bsizer4.Add(hsizer4, 0, wx.EXPAND) + panel4.SetSizer(bsizer4) + + + # These Are Cosmetics For The Fifth SpeedMeter Control + bsizer5 = wx.BoxSizer(wx.VERTICAL) + + hsizer5 = wx.BoxSizer(wx.HORIZONTAL) + + button5 = wx.Button(panel5, -1, "Simulate") + button5.SetToolTip(wx.ToolTip("Start A Car Acceleration Simulation")) + button5.Bind(wx.EVT_BUTTON, self.OnSimulate) + + hsizer5.Add(button5, 0, wx.EXPAND | wx.LEFT, 5) + hsizer5.Add((1,0), 1, wx.EXPAND) + + bsizer5.Add(self.SpeedWindow5, 1, wx.EXPAND) + bsizer5.Add(hsizer5, 0, wx.EXPAND) + panel5.SetSizer(bsizer5) + + + # These Are Cosmetics For The Sixth SpeedMeter Control + bsizer6 = wx.BoxSizer(wx.VERTICAL) + hsizer6 = wx.BoxSizer(wx.HORIZONTAL) + + txtctrl6 = wx.TextCtrl(panel6, -1, "60", size=(60, 20)) + txtctrl6.SetToolTip(wx.ToolTip("Insert An Angle In DEGREES")) + + self.txtctrl = txtctrl6 + + button6 = wx.Button(panel6, -1, "Go!") + button6.SetToolTip(wx.ToolTip("Calculate The Equivalent In Radians And Display It")) + + hsizer6.Add(txtctrl6, 0, wx.EXPAND | wx.LEFT, 5) + hsizer6.Add(button6, 0, wx.EXPAND | wx.LEFT, 5) + hsizer6.Add((1,0), 1, wx.EXPAND) + + button6.Bind(wx.EVT_BUTTON, self.OnCalculate) + bsizer6.Add(self.SpeedWindow6, 1, wx.EXPAND) + bsizer6.Add(hsizer6, 0, wx.EXPAND) + panel6.SetSizer(bsizer6) + + bsizer1.Layout() + bsizer2.Layout() + bsizer3.Layout() + bsizer4.Layout() + bsizer5.Layout() + bsizer6.Layout() + + sizer.Add(panel1, 1, wx.EXPAND) + sizer.Add(panel2, 1, wx.EXPAND) + sizer.Add(panel3, 1, wx.EXPAND) + + sizer.Add(panel4, 1, wx.EXPAND) + sizer.Add(panel5, 1, wx.EXPAND) + sizer.Add(panel6, 1, wx.EXPAND) + + sizer.AddGrowableRow(0) + sizer.AddGrowableRow(1) + + sizer.AddGrowableCol(0) + sizer.AddGrowableCol(1) + sizer.AddGrowableCol(2) + + panel.SetSizer(sizer) + + mainSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer.Add(panel, 1, wx.EXPAND) + self.SetSizer(mainSizer) + mainSizer.Layout() + + self.timer.Start(1000) + self.timer3.Start(500) + + + def OnSliderScroll(self, event): + + slider = event.GetEventObject() + self.SpeedWindow1.SetSpeedValue(slider.GetValue()) + + event.Skip() + + + def ClockTimer(self): + if self.currvalue >= 59: + self.currvalue = 0 + else: + self.currvalue = self.currvalue + 1 + + self.SpeedWindow2.SetMiddleText(str(self.currvalue) + " s") + self.SpeedWindow2.SetSpeedValue(self.currvalue/5.0) + + + def OnStopClock(self, event): + + btn = event.GetEventObject() + + if self.stopped == 0: + self.stopped = 1 + self.timer.Stop() + btn.SetLabel("Resume") + else: + self.stopped = 0 + self.timer.Start() + btn.SetLabel("Stop") + + + def OilTimer(self): + + val = self.spinctrl.GetValue() + + if val > 250: + return + + current = self.SpeedWindow3.GetSpeedValue() + new = current + val*0.0005 + + if new > 4.0: + return + + self.SpeedWindow3.SetSpeedValue(new) + + + def OnRefill(self, event): + + self.SpeedWindow3.SetSpeedValue(0) + + + def OnSimulate(self, event): + + for ii in range(50): + self.SpeedWindow5.SetSpeedValue(ii/10.0) + wx.MilliSleep(10) + + current = self.SpeedWindow5.GetSpeedValue() + for ii in range(40): + current = current - 1.0/10.0 + self.SpeedWindow5.SetSpeedValue(current) + wx.MilliSleep(40) + + wx.MilliSleep(50) + current = self.SpeedWindow5.GetSpeedValue() + + for ii in range(59): + current = current + 1.0/10.0 + self.SpeedWindow5.SetSpeedValue(current) + wx.MilliSleep(10) + + event.Skip() + + + def OnCalculate(self, event): + + try: + myval = self.txtctrl.GetValue() + val = float(myval) + except: + msg = "ERROR: Value Entered In The TextCtrl:\n\n" + myval + "\n\n" + msg = msg + "Is Not A Valid Integer/Float Number." + dlg = wx.MessageDialog(self, msg, "SpeedMeter Demo Error", + wx.OK | wx.ICON_ERROR) + dlg.SetFont(wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, False, "Verdana")) + dlg.ShowModal() + dlg.Destroy() + return + + newval = val*pi/180.0 + anglerange = self.SpeedWindow6.GetAngleRange() + start = anglerange[0] + end = anglerange[1] + + error = 0 + + if newval < start: + msg = "ERROR: Value Entered In The TextCtrl:\n\n" + myval + "\n\n" + msg = msg + "Is Smaller Than Minimum Value." + error = 1 + elif newval > end: + msg = "ERROR: Value Entered In The TextCtrl:\n\n" + myval + "\n\n" + msg = msg + "Is Greater Than Maximum Value." + error = 1 + + if error: + dlg = wx.MessageDialog(self, msg, "SpeedMeter Demo Error", + wx.OK | wx.ICON_ERROR) + dlg.SetFont(wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, False, "Verdana")) + dlg.ShowModal() + dlg.Destroy() + return + + self.SpeedWindow6.SetSpeedValue(newval) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = SpeedMeterDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = SM.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/SuperToolTip.py b/demo/agw/SuperToolTip.py new file mode 100644 index 00000000..75730ee3 --- /dev/null +++ b/demo/agw/SuperToolTip.py @@ -0,0 +1,393 @@ +import wx +import wx.lib.buttons as buttons +import wx.lib.scrolledpanel as scrolled + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +bitmapDir = os.path.join(dirName, 'bitmaps') +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import supertooltip as STT +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.supertooltip as STT + +import images + + +class SuperToolTipDemo(wx.Frame): + + def __init__(self, parent): + + wx.Frame.__init__(self, parent, style=wx.DEFAULT_FRAME_STYLE) + self.mainPanel = scrolled.ScrolledPanel(self, -1) + + self.headerSizer_staticbox = wx.StaticBox(self.mainPanel, -1, "Header") + self.bodySizer_staticbox = wx.StaticBox(self.mainPanel, -1, "Message Body") + self.footerSizer_staticbox = wx.StaticBox(self.mainPanel, -1, "Footer") + self.otherSizer_staticbox = wx.StaticBox(self.mainPanel, -1, "Other Options") + self.toolTipSizer_staticbox = wx.StaticBox(self.mainPanel, -1, "SuperToolTip Preview") + self.colourSizer_staticbox = wx.StaticBox(self.mainPanel, -1, "Colours") + self.stylesRadio = wx.RadioButton(self.mainPanel, -1, "Predefined", style=wx.RB_GROUP) + self.stylesCombo = wx.ComboBox(self.mainPanel, -1, choices=STT.GetStyleKeys(), + style=wx.CB_DROPDOWN|wx.CB_READONLY) + self.customStyles = wx.RadioButton(self.mainPanel, -1, "Custom ") + self.topColourPicker = wx.ColourPickerCtrl(self.mainPanel, col=wx.WHITE) + system = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION) + r, g, b = system + self.middleColourPicker = wx.ColourPickerCtrl(self.mainPanel, col=wx.Colour((255-r)/2, (255-g)/2, (255-b)/2)) + self.bottomColourPicker = wx.ColourPickerCtrl(self.mainPanel, col=system) + self.headerCheck = wx.CheckBox(self.mainPanel, -1, "Show Header") + self.headerText = wx.TextCtrl(self.mainPanel, -1, "Merge And Center") + self.headerBitmap = wx.StaticBitmap(self.mainPanel, -1, + wx.Bitmap(os.path.normpath(os.path.join(bitmapDir, "sttheader.png")), + wx.BITMAP_TYPE_PNG)) + self.headerFilePicker = wx.FilePickerCtrl(self.mainPanel, path=os.path.normpath(os.path.join(bitmapDir, "sttheader.png")), + style=wx.FLP_USE_TEXTCTRL) + self.headerLineCheck = wx.CheckBox(self.mainPanel, -1, "Draw Line After Header") + self.bodyBitmap = wx.StaticBitmap(self.mainPanel, -1, + wx.Bitmap(os.path.normpath(os.path.join(bitmapDir, "sttfont.png")), + wx.BITMAP_TYPE_PNG)) + msg = "A Bold Title\n\nJoins the selected cells into one larger cell\nand centers the contents in the new cell.\n" \ + "This is often used to create labels that span\nmultiple columns.\n\n
draw a horizontal line - text on same line will be ignored\n\nI am a link{http://xoomer.alice.it/infinity77}" + self.bodyText = wx.TextCtrl(self.mainPanel, -1, msg, style=wx.TE_MULTILINE) + self.includeCheck = wx.CheckBox(self.mainPanel, -1, "Include Body Image") + self.footerCheck = wx.CheckBox(self.mainPanel, -1, "Show Footer") + self.footerText = wx.TextCtrl(self.mainPanel, -1, "Press F1 for more help") + self.footerBitmap = wx.StaticBitmap(self.mainPanel, -1, + wx.Bitmap(os.path.normpath(os.path.join(bitmapDir, "stthelp.png")), + wx.BITMAP_TYPE_PNG)) + self.footerFilePicker = wx.FilePickerCtrl(self.mainPanel, path=os.path.normpath(os.path.join(bitmapDir,"stthelp.png")), + style=wx.FLP_USE_TEXTCTRL) + self.footerLineCheck = wx.CheckBox(self.mainPanel, -1, "Draw Line Before Footer") + self.dropShadow = wx.CheckBox(self.mainPanel, -1, "Rounded Corners And Drop Shadow (Windows XP Only)") + self.useFade = wx.CheckBox(self.mainPanel, -1, "Fade In/Fade Out Effects (Windows XP Only)") + self.endTimer = wx.SpinCtrl(self.mainPanel, -1, "5") + + btnBmp = wx.Bitmap(os.path.normpath(os.path.join(bitmapDir,"sttbutton.png")), wx.BITMAP_TYPE_PNG) + self.toolTipButton = buttons.ThemedGenBitmapTextButton(self.mainPanel, -1, btnBmp, " Big Test Button ", + size=(-1, 130)) + self.generateTip = wx.Button(self.mainPanel, -1, "Generate SuperToolTip") + + self.CreateMenuBar() + self.SetProperties() + self.DoLayout() + self.mainPanel.SetupScrolling() + + self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioColours, self.stylesRadio) + self.Bind(wx.EVT_RADIOBUTTON, self.OnRadioColours, self.customStyles) + self.Bind(wx.EVT_CHECKBOX, self.OnShowHeader, self.headerCheck) + self.Bind(wx.EVT_CHECKBOX, self.OnShowFooter, self.footerCheck) + self.generateTip.Bind(wx.EVT_BUTTON, self.OnGenerateTip) + self.Bind(wx.EVT_FILEPICKER_CHANGED, self.OnPickBitmap, self.headerFilePicker) + self.Bind(wx.EVT_FILEPICKER_CHANGED, self.OnPickBitmap, self.footerFilePicker) + + self.enableWidgets = {} + + self.enableWidgets[self.headerCheck] = [self.headerBitmap, self.headerFilePicker, + self.headerLineCheck, self.headerText] + self.enableWidgets[self.footerCheck] = [self.footerBitmap, self.footerFilePicker, + self.footerLineCheck, self.footerText] + self.enableWidgets[self.customStyles] = [self.stylesCombo, self.topColourPicker, + self.middleColourPicker, self.bottomColourPicker] + self.enableWidgets[self.stylesRadio] = [self.stylesCombo, self.topColourPicker, + self.middleColourPicker, self.bottomColourPicker] + + self.SetSize((700, 600)) + self.CenterOnScreen() + self.Show() + + + def CreateMenuBar(self): + + menuBar = wx.MenuBar(wx.MB_DOCKABLE) + fileMenu = wx.Menu() + helpMenu = wx.Menu() + + item = wx.MenuItem(fileMenu, wx.ID_ANY, "E&xit", "Exit demo") + self.Bind(wx.EVT_MENU, self.OnClose, item) + fileMenu.AppendItem(item) + + item = wx.MenuItem(helpMenu, wx.ID_ANY, "About...", "Shows The About Dialog") + self.Bind(wx.EVT_MENU, self.OnAbout, item) + helpMenu.AppendItem(item) + + menuBar.Append(fileMenu, "&File") + menuBar.Append(helpMenu, "&Help") + + self.SetMenuBar(menuBar) + + + def SetProperties(self): + + self.SetTitle("SuperToolTip wxPython Demo ;-)") + self.stylesRadio.SetValue(1) + self.headerCheck.SetValue(1) + self.footerCheck.SetValue(1) + self.stylesCombo.SetValue("Office 2007 Blue") + font = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "") + self.generateTip.SetFont(font) + self.headerCheck.SetFont(font) + self.footerCheck.SetFont(font) + self.endTimer.SetRange(1, 100) + self.toolTipButton.SetFont(wx.Font(16, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + for widgets in [self.topColourPicker, self.middleColourPicker, self.bottomColourPicker]: + widgets.Enable(False) + + self.SetIcon(images.Mondrian.GetIcon()) + + + def DoLayout(self): + + frameSizer = wx.BoxSizer(wx.VERTICAL) + mainSizer = wx.BoxSizer(wx.VERTICAL) + topSizer = wx.BoxSizer(wx.HORIZONTAL) + + otherSizer = wx.StaticBoxSizer(self.otherSizer_staticbox, wx.VERTICAL) + toolTipSizer = wx.StaticBoxSizer(self.toolTipSizer_staticbox, wx.HORIZONTAL) + toolTipSizer_1 = wx.BoxSizer(wx.VERTICAL) + footerSizer = wx.StaticBoxSizer(self.footerSizer_staticbox, wx.VERTICAL) + footerSizer_2 = wx.BoxSizer(wx.HORIZONTAL) + footerSizer_1 = wx.BoxSizer(wx.HORIZONTAL) + bodySizer = wx.StaticBoxSizer(self.bodySizer_staticbox, wx.HORIZONTAL) + bodySizer_2 = wx.BoxSizer(wx.VERTICAL) + headerSizer = wx.StaticBoxSizer(self.headerSizer_staticbox, wx.VERTICAL) + headerSizer_2 = wx.BoxSizer(wx.HORIZONTAL) + headerSizer_1 = wx.BoxSizer(wx.HORIZONTAL) + colourSizer = wx.StaticBoxSizer(self.colourSizer_staticbox, wx.VERTICAL) + colourSizer_2 = wx.BoxSizer(wx.HORIZONTAL) + colourSizer_1 = wx.BoxSizer(wx.HORIZONTAL) + colourSizer_1.Add(self.stylesRadio, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + colourSizer_1.Add(self.stylesCombo, 1, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5) + colourSizer.Add(colourSizer_1, 1, wx.EXPAND, 0) + colourSizer_2.Add(self.customStyles, 0, wx.LEFT|wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + label_1 = wx.StaticText(self.mainPanel, -1, "Top:") + colourSizer_2.Add(label_1, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 3) + colourSizer_2.Add(self.topColourPicker, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + label_2 = wx.StaticText(self.mainPanel, -1, "Middle:") + colourSizer_2.Add(label_2, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 3) + colourSizer_2.Add(self.middleColourPicker, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + label_3 = wx.StaticText(self.mainPanel, -1, "Bottom:") + colourSizer_2.Add(label_3, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 3) + colourSizer_2.Add(self.bottomColourPicker, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + colourSizer.Add(colourSizer_2, 1, wx.EXPAND, 0) + mainSizer.Add(colourSizer, 0, wx.ALL|wx.EXPAND, 5) + + headerSizer.Add(self.headerCheck, 0, wx.ALL, 5) + label_4 = wx.StaticText(self.mainPanel, -1, "Header Text:") + headerSizer_1.Add(label_4, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + headerSizer_1.Add(self.headerText, 1, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + headerSizer.Add(headerSizer_1, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, 5) + label_5 = wx.StaticText(self.mainPanel, -1, "Header Bitmap:") + headerSizer_2.Add(label_5, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + headerSizer_2.Add(self.headerBitmap, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + headerSizer_2.Add(self.headerFilePicker, 1, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5) + headerSizer.Add(headerSizer_2, 1, wx.ALL|wx.EXPAND, 5) + headerSizer.Add(self.headerLineCheck, 0, wx.ALL, 5) + + footerSizer.Add(self.footerCheck, 0, wx.ALL, 5) + label_6 = wx.StaticText(self.mainPanel, -1, "Footer Text:") + footerSizer_1.Add(label_6, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + footerSizer_1.Add(self.footerText, 1, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + footerSizer.Add(footerSizer_1, 1, wx.LEFT|wx.RIGHT|wx.EXPAND, 5) + label_7 = wx.StaticText(self.mainPanel, -1, "Footer Bitmap:") + footerSizer_2.Add(label_7, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + footerSizer_2.Add(self.footerBitmap, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + footerSizer_2.Add(self.footerFilePicker, 1, wx.RIGHT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5) + footerSizer.Add(footerSizer_2, 1, wx.ALL|wx.EXPAND, 5) + footerSizer.Add(self.footerLineCheck, 0, wx.ALL, 5) + + topSizer.Add(headerSizer, 1, wx.EXPAND|wx.ALL, 5) + topSizer.Add(footerSizer, 1, wx.EXPAND|wx.ALL, 5) + mainSizer.Add(topSizer, 0, wx.TOP|wx.BOTTOM|wx.EXPAND, 5) + + bodySizer.Add(self.bodyBitmap, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + bodySizer_2.Add(self.bodyText, 1, wx.EXPAND, 0) + bodySizer_2.Add(self.includeCheck, 0, wx.RIGHT|wx.TOP, 5) + bodySizer.Add(bodySizer_2, 1, wx.ALL|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 5) + mainSizer.Add(bodySizer, 0, wx.ALL|wx.EXPAND, 5) + + otherSizer.Add(self.dropShadow, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + otherSizer.Add(self.useFade, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL, 5) + label_8 = wx.StaticText(self.mainPanel, -1, "No Of Seconds SuperToolTip Is Shown:") + otherSizer.Add((0, 5)) + otherSizer.Add(label_8, 0, wx.LEFT|wx.RIGHT, 5) + otherSizer.Add((0, 2)) + otherSizer.Add(self.endTimer, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM, 5) + mainSizer.Add(otherSizer, 0, wx.ALL|wx.EXPAND, 5) + + toolTipSizer.Add(self.toolTipButton, 1, wx.ALL|wx.EXPAND, 5) + toolTipSizer_1.Add(self.generateTip, 0, wx.ALL, 5) + toolTipSizer.Add(toolTipSizer_1, 0, wx.EXPAND, 0) + mainSizer.Add(toolTipSizer, 1, wx.ALL|wx.EXPAND, 5) + self.mainPanel.SetSizer(mainSizer) + mainSizer.Layout() + frameSizer.Add(self.mainPanel, 1, wx.EXPAND, 0) + self.SetSizer(frameSizer) + frameSizer.Layout() + frameSizer.Fit(self) + self.Layout() + + wx.CallAfter(mainSizer.Layout) + + + def OnRadioColours(self, event): + + self.EnableWidgets(event.GetEventObject(), None) + + + def OnShowHeader(self, event): + + checked = event.IsChecked() + self.EnableWidgets(event.GetEventObject(), checked) + + + def OnShowFooter(self, event): + + checked = event.IsChecked() + self.EnableWidgets(event.GetEventObject(), checked) + + + def EnableWidgets(self, obj, checked): + + widgets = self.enableWidgets[obj] + for indx, control in enumerate(widgets): + if obj == self.customStyles: + control.Enable(indx > 0) + elif obj == self.stylesRadio: + control.Enable(indx < 1) + else: + control.Enable(checked) + + + def OnPickBitmap(self, event): + + obj = event.GetEventObject() + path = event.GetPath() + + bmp = wx.Bitmap(path, wx.BITMAP_TYPE_ANY) + if obj == self.headerFilePicker: + self.headerBitmap.SetBitmap(bmp) + self.headerBitmap.Refresh() + else: + self.footerBitmap.SetBitmap(bmp) + self.footerBitmap.Refresh() + + + def OnGenerateTip(self, event): + + if self.stylesRadio.GetValue(): + # Using a predefined style + styleKey = self.stylesCombo.GetValue() + else: + topColour, middleColour, bottomColour = self.topColourPicker.GetColour(), \ + self.middleColourPicker.GetColour(), \ + self.bottomColourPicker.GetColour() + + if self.headerCheck.GetValue() == 0: + headerText, headerBmp, drawHLine = "", wx.NullBitmap, False + else: + headerText = self.headerText.GetValue().strip() + headerBmp = self.headerBitmap.GetBitmap() + drawHLine = self.headerLineCheck.GetValue() + + message = self.bodyText.GetValue() + if self.includeCheck.GetValue(): + bodyImage = self.bodyBitmap.GetBitmap() + else: + bodyImage = wx.NullBitmap + + if self.footerCheck.GetValue() == 0: + footerText, footerBmp, drawFLine = "", wx.NullBitmap, False + else: + footerText = self.footerText.GetValue().strip() + footerBmp = self.footerBitmap.GetBitmap() + drawFLine = self.footerLineCheck.GetValue() + + if not hasattr(self, "tip"): + self.tip = STT.SuperToolTip(message) + else: + self.tip.SetMessage(message) + + self.tip.SetBodyImage(bodyImage) + self.tip.SetHeader(headerText) + self.tip.SetHeaderBitmap(headerBmp) + self.tip.SetFooter(footerText) + self.tip.SetFooterBitmap(footerBmp) + + self.tip.SetTarget(self.toolTipButton) + self.tip.SetDrawHeaderLine(drawHLine) + self.tip.SetDrawFooterLine(drawFLine) + + self.tip.SetDropShadow(self.dropShadow.GetValue()) + self.tip.SetUseFade(self.useFade.GetValue()) + self.tip.SetEndDelay(self.endTimer.GetValue()) + + if self.stylesRadio.GetValue(): + self.tip.ApplyStyle(styleKey) + else: + self.tip.SetTopGradientColour(topColour) + self.tip.SetMiddleGradientColour(middleColour) + self.tip.SetBottomGradientColour(bottomColour) + + def OnClose(self, event): + + wx.CallAfter(self.Destroy) + + + def OnAbout(self, event): + + msg = "This is the about dialog of SuperToolTip demo.\n\n" + \ + "Author: Andrea Gavana @ 07 Oct 2008\n\n" + \ + "Please report any bugs/requests of improvements\n" + \ + "to me at the following addresses:\n\n" + \ + "andrea.gavana@gmail.com\n" + "andrea.gavana@maerskoil.com\n\n" + \ + "Welcome to wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "SuperToolTip wxPython Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +class TestPanel(wx.Panel): + + def __init__(self, parent, log): + + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, "Show SuperToolTip Demo", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + + SuperToolTipDemo(self) + + +#--------------------------------------------------------------------------- + + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + + +#--------------------------------------------------------------------------- + + +overview = STT.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/ThumbnailCtrl.py b/demo/agw/ThumbnailCtrl.py new file mode 100644 index 00000000..55637df5 --- /dev/null +++ b/demo/agw/ThumbnailCtrl.py @@ -0,0 +1,626 @@ +import wx +import os + +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import thumbnailctrl as TC +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.thumbnailctrl as TC + +import images + + +class ThumbnailCtrlDemo(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent) + + self.SetIcon(images.Mondrian.GetIcon()) + self.SetTitle("ThumbnailCtrl wxPython Demo ;-)") + + self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + self.statusbar.SetStatusWidths([-2, -1]) + # statusbar fields + statusbar_fields = [("ThumbnailCtrl Demo, Andrea Gavana @ 10 Dec 2005"), + ("Welcome To wxPython!")] + + for i in range(len(statusbar_fields)): + self.statusbar.SetStatusText(statusbar_fields[i], i) + + self.SetMenuBar(self.CreateMenuBar()) + + splitter = wx.SplitterWindow(self, -1, style=wx.CLIP_CHILDREN | + wx.SP_3D | wx.WANTS_CHARS | wx.SP_LIVE_UPDATE) + self.panel = wx.Panel(splitter, -1) + + sizer = wx.BoxSizer(wx.HORIZONTAL) + scroll = TC.ThumbnailCtrl(splitter, -1, imagehandler=TC.NativeImageHandler) + + scroll.ShowFileNames() + if os.path.isdir("../bitmaps"): + scroll.ShowDir(os.path.normpath(os.getcwd() + "/../bitmaps")) + else: + scroll.ShowDir(os.getcwd()) + + self.TC = scroll + self.log = log + + self.thumbsizer_staticbox = wx.StaticBox(self.panel, -1, "Thumb Style") + self.customsizer_staticbox = wx.StaticBox(self.panel, -1, "Thumb Customization") + self.optionsizer_staticbox = wx.StaticBox(self.panel, -1, "More Options") + self.dirsizer_staticbox = wx.StaticBox(self.panel, -1, "Directory Selection") + self.dirbutton = wx.Button(self.panel, -1, "Change Directory") + self.radiostyle1 = wx.RadioButton(self.panel, -1, "THUMB_OUTLINE_NONE", style=wx.RB_GROUP) + self.radiostyle2 = wx.RadioButton(self.panel, -1, "THUMB_OUTLINE_FULL") + self.radiostyle3 = wx.RadioButton(self.panel, -1, "THUMB_OUTLINE_RECT") + self.radiostyle4 = wx.RadioButton(self.panel, -1, "THUMB_OUTLINE_IMAGE") + self.highlight = wx.CheckBox(self.panel, -1, "Highlight on pointing") + self.showfiles = wx.CheckBox(self.panel, -1, "Show file names") + self.enabledragging = wx.CheckBox(self.panel, -1, "Enable drag and drop") + self.setpopup = wx.CheckBox(self.panel, -1, "Set popup menu on thumbs") + self.setgpopup = wx.CheckBox(self.panel, -1, "Set global popup menu") + self.showcombo = wx.CheckBox(self.panel, -1, "Show folder combobox") + self.enabletooltip = wx.CheckBox(self.panel, -1, "Enable thumb tooltips") + self.textzoom = wx.TextCtrl(self.panel, -1, "1.4") + self.zoombutton = wx.Button(self.panel, -1, "Set zoom factor") + self.fontbutton = wx.Button(self.panel, -1, "Set caption font") + self.colourbutton = wx.Button(self.panel, -1, "Set selection colour") + + self.radios = [self.radiostyle1, self.radiostyle2, self.radiostyle3, + self.radiostyle4] + self.thumbstyles = ["THUMB_OUTLINE_NONE", "THUMB_OUTLINE_FULL", "THUMB_OUTLINE_RECT", + "THUMB_OUTLINE_IMAGE"] + + self.SetProperties() + self.DoLayout() + + self.panel.SetSizer(sizer) + sizer.Layout() + + self.Bind(wx.EVT_RADIOBUTTON, self.OnChangeOutline, self.radiostyle1) + self.Bind(wx.EVT_RADIOBUTTON, self.OnChangeOutline, self.radiostyle2) + self.Bind(wx.EVT_RADIOBUTTON, self.OnChangeOutline, self.radiostyle3) + self.Bind(wx.EVT_RADIOBUTTON, self.OnChangeOutline, self.radiostyle4) + self.Bind(wx.EVT_CHECKBOX, self.OnHighlight, self.highlight) + self.Bind(wx.EVT_CHECKBOX, self.OnShowFiles, self.showfiles) + self.Bind(wx.EVT_CHECKBOX, self.OnEnableDragging, self.enabledragging) + self.Bind(wx.EVT_CHECKBOX, self.OnSetPopup, self.setpopup) + self.Bind(wx.EVT_CHECKBOX, self.OnSetGlobalPopup, self.setgpopup) + self.Bind(wx.EVT_CHECKBOX, self.OnShowComboBox, self.showcombo) + self.Bind(wx.EVT_CHECKBOX, self.OnEnableToolTips, self.enabletooltip) + self.Bind(wx.EVT_BUTTON, self.OnSetZoom, self.zoombutton) + self.Bind(wx.EVT_BUTTON, self.OnSetFont, self.fontbutton) + self.Bind(wx.EVT_BUTTON, self.OnSetColour, self.colourbutton) + self.Bind(wx.EVT_BUTTON, self.OnSetDirectory, self.dirbutton) + + self.TC.Bind(TC.EVT_THUMBNAILS_SEL_CHANGED, self.OnSelChanged) + self.TC.Bind(TC.EVT_THUMBNAILS_POINTED, self.OnPointed) + self.TC.Bind(TC.EVT_THUMBNAILS_DCLICK, self.OnDClick) + + splitter.SplitVertically(scroll, self.panel, 180) + + splitter.SetMinimumPaneSize(140) + self.SetMinSize((700, 590)) + self.CenterOnScreen() + + + def SetProperties(self): + + self.radiostyle4.SetValue(1) + self.showfiles.SetValue(1) + boldFont = wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "") + self.zoombutton.SetFont(boldFont) + self.fontbutton.SetFont(boldFont) + self.dirbutton.SetFont(boldFont) + self.colourbutton.SetFont(boldFont) + + + def DoLayout(self): + + splitsizer = wx.BoxSizer(wx.VERTICAL) + optionsizer = wx.StaticBoxSizer(self.optionsizer_staticbox, wx.VERTICAL) + zoomsizer = wx.BoxSizer(wx.HORIZONTAL) + customsizer = wx.StaticBoxSizer(self.customsizer_staticbox, wx.VERTICAL) + thumbsizer = wx.StaticBoxSizer(self.thumbsizer_staticbox, wx.VERTICAL) + radiosizer = wx.BoxSizer(wx.VERTICAL) + dirsizer = wx.StaticBoxSizer(self.dirsizer_staticbox, wx.HORIZONTAL) + dirsizer.Add(self.dirbutton, 0, wx.LEFT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + splitsizer.Add(dirsizer, 0, wx.EXPAND|wx.TOP|wx.LEFT, 5) + radiosizer.Add(self.radiostyle1, 0, wx.LEFT|wx.TOP|wx.ADJUST_MINSIZE, 3) + radiosizer.Add(self.radiostyle2, 0, wx.LEFT|wx.TOP|wx.ADJUST_MINSIZE, 3) + radiosizer.Add(self.radiostyle3, 0, wx.LEFT|wx.TOP|wx.ADJUST_MINSIZE, 3) + radiosizer.Add(self.radiostyle4, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + thumbsizer.Add(radiosizer, 1, wx.EXPAND, 0) + splitsizer.Add(thumbsizer, 0, wx.TOP|wx.EXPAND|wx.LEFT, 5) + customsizer.Add(self.highlight, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + customsizer.Add(self.showfiles, 0, wx.LEFT|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + customsizer.Add(self.enabledragging, 0, wx.LEFT|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + customsizer.Add(self.setpopup, 0, wx.LEFT|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + customsizer.Add(self.setgpopup, 0, wx.LEFT|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + customsizer.Add(self.showcombo, 0, wx.LEFT|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + customsizer.Add(self.enabletooltip, 0, wx.LEFT|wx.BOTTOM|wx.ADJUST_MINSIZE, 3) + splitsizer.Add(customsizer, 0, wx.TOP|wx.EXPAND|wx.LEFT, 5) + zoomsizer.Add(self.textzoom, 1, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + zoomsizer.Add(self.zoombutton, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + optionsizer.Add(zoomsizer, 1, wx.EXPAND, 0) + optionsizer.Add(self.fontbutton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + optionsizer.Add(self.colourbutton, 0, wx.TOP|wx.LEFT|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 3) + splitsizer.Add(optionsizer, 0, wx.EXPAND | wx.TOP|wx.LEFT, 5) + self.panel.SetAutoLayout(True) + self.panel.SetSizer(splitsizer) + splitsizer.Fit(self.panel) + + + def CreateMenuBar(self): + + file_menu = wx.Menu() + + AS_EXIT = wx.NewId() + file_menu.Append(AS_EXIT, "&Exit") + self.Bind(wx.EVT_MENU, self.OnClose, id=AS_EXIT) + + help_menu = wx.Menu() + + AS_ABOUT = wx.NewId() + help_menu.Append(AS_ABOUT, "&About...") + self.Bind(wx.EVT_MENU, self.OnAbout, id=AS_ABOUT) + + menu_bar = wx.MenuBar() + + menu_bar.Append(file_menu, "&File") + menu_bar.Append(help_menu, "&Help") + + return menu_bar + + + def OnClose(self, event): + + self.Destroy() + + + def OnAbout(self, event): + + msg = "This Is The About Dialog Of The ThumbnailCtrl Demo.\n\n" + \ + "Author: Andrea Gavana @ 10 Dec 2005\n\n" + \ + "Please Report Any Bug/Requests Of Improvements\n" + \ + "To Me At The Following Adresses:\n\n" + \ + "andrea.gavana@agip.it\n" + "andrea_gavana@tin.it\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "ThumbnailCtrl Demo", + wx.OK | wx.ICON_INFORMATION) + + dlg.SetFont(wx.Font(8, wx.NORMAL, wx.NORMAL, wx.NORMAL, False)) + dlg.ShowModal() + dlg.Destroy() + + + def OnSetDirectory(self, event): + + dlg = wx.DirDialog(self, "Choose a directory with images:", + defaultPath=os.getcwd(), + style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON) + + # If the user selects OK, then we process the dialog's data. + # This is done by getting the path data from the dialog - BEFORE + # we destroy it. + if dlg.ShowModal() == wx.ID_OK: + self.TC.ShowDir(dlg.GetPath()) + self.log.write("OnSetDirectory: directory changed to: %s\n"%dlg.GetPath()) + + # Only destroy a dialog after you're done with it. + dlg.Destroy() + + + def OnChangeOutline(self, event): # wxGlade: MyFrame. + + radio = event.GetEventObject() + pos = self.radios.index(radio) + + if pos == 0: + self.TC.SetThumbOutline(TC.THUMB_OUTLINE_NONE) + elif pos == 1: + self.TC.SetThumbOutline(TC.THUMB_OUTLINE_FULL) + elif pos == 2: + self.TC.SetThumbOutline(TC.THUMB_OUTLINE_RECT) + elif pos == 3: + self.TC.SetThumbOutline(TC.THUMB_OUTLINE_IMAGE) + + self.TC.Refresh() + + self.log.write("OnChangeOutline: Outline changed to: %s\n"%self.thumbstyles[pos]) + event.Skip() + + + def OnHighlight(self, event): # wxGlade: MyFrame. + + if self.highlight.GetValue() == 1: + self.TC.SetHighlightPointed(True) + self.log.write("OnHighlight: Highlight thumbs on pointing\n") + else: + self.TC.SetHighlightPointed(False) + self.log.write("OnHighlight: Don't Highlight thumbs on pointing\n") + + event.Skip() + + + def OnShowFiles(self, event): # wxGlade: MyFrame. + + if self.showfiles.GetValue() == 1: + self.TC.ShowFileNames(True) + self.log.write("OnShowFiles: Thumbs file names shown\n") + else: + self.TC.ShowFileNames(False) + self.log.write("OnShowFiles: Thumbs file names not shown\n") + + self.TC.Refresh() + + event.Skip() + + + def OnEnableDragging(self, event): + + if self.enabledragging.GetValue() == 1: + self.TC.EnableDragging(True) + self.log.write("OnEnableDragging: Thumbs drag and drop enabled\n") + else: + self.TC.EnableDragging(False) + self.log.write("OnEnableDragging: Thumbs drag and drop disabled\n") + + self.TC.Refresh() + + event.Skip() + + + def OnSetPopup(self, event): # wxGlade: MyFrame. + + if self.setpopup.GetValue() == 1: + menu = self.CreatePopups() + self.TC.SetPopupMenu(menu) + self.log.write("OnSetPopup: Popups enabled on thumbs\n") + else: + self.TC.SetPopupMenu(None) + self.log.write("OnSetPopup: Popups disabled on thumbs\n") + + event.Skip() + + + def OnSetGlobalPopup(self, event): + + if self.setgpopup.GetValue() == 1: + menu = self.CreateGlobalPopups() + self.TC.SetGlobalPopupMenu(menu) + self.log.write("OnSetGlobalPopup: Popups enabled globally (no selection needed)\n") + else: + self.TC.SetGlobalPopupMenu(None) + self.log.write("OnSetGlobalPopup: Popups disabled globally (no selection needed)\n") + + event.Skip() + + + def OnShowComboBox(self, event): + + if self.showcombo.GetValue() == 1: + self.log.write("OnShowComboBox: Directory comboBox shown\n") + self.TC.ShowComboBox(True) + else: + self.log.write("OnShowComboBox: Directory comboBox hidden\n") + self.TC.ShowComboBox(False) + + event.Skip() + + + def OnEnableToolTips(self, event): + + if self.enabletooltip.GetValue() == 1: + self.log.write("OnEnableToolTips: File information on tooltips enabled\n") + self.TC.EnableToolTips(True) + else: + self.log.write("OnEnableToolTips: File information on tooltips disabled\n") + self.TC.EnableToolTips(False) + + event.Skip() + + + def OnSetZoom(self, event): # wxGlade: MyFrame. + + val = self.textzoom.GetValue().strip() + + try: + val = float(val) + except: + errstr = "Error: a float value is required." + dlg = wx.MessageDialog(self, errstr, "ThumbnailCtrlDemo Error", + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + self.textzoom.SetValue("1.4") + return + + + if val < 1.0: + errstr = "Error: zoom factor must be grater than 1.0." + dlg = wx.MessageDialog(self, errstr, "ThumbnailCtrlDemo Error", + wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + self.textzoom.SetValue("1.4") + return + + self.TC.SetZoomFactor(val) + + event.Skip() + + + def OnSelChanged(self, event): + + self.log.write("OnSelChanged: Thumb selected: %s\n"%str(self.TC.GetSelection())) + event.Skip() + + + def OnPointed(self, event): + + self.log.write("OnPointed: Thumb pointed: %s\n"%self.TC.GetPointed()) + event.Skip() + + + def OnDClick(self, event): + + self.log.write("OnDClick: Thumb double-clicked: %s\n"%self.TC.GetSelection()) + event.Skip() + + + def OnSetFont(self, event): # wxGlade: MyFrame. + + data = wx.FontData() + data.EnableEffects(True) + data.SetInitialFont(self.TC.GetCaptionFont()) + + dlg = wx.FontDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetFontData() + font = data.GetChosenFont() + self.TC.SetCaptionFont(font) + self.TC.Refresh() + self.log.write("OnSetFont: Caption font changed\n") + + # Don't destroy the dialog until you get everything you need from the + # dialog! + dlg.Destroy() + event.Skip() + + + def OnSetColour(self, event): + + dlg = wx.ColourDialog(self) + + # Ensure the full colour dialog is displayed, + # not the abbreviated version. + dlg.GetColourData().SetChooseFull(True) + + if dlg.ShowModal() == wx.ID_OK: + + # If the user selected OK, then the dialog's wx.ColourData will + # contain valid information. Fetch the data ... + data = dlg.GetColourData() + + # ... then do something with it. The actual colour data will be + # returned as a three-tuple (r, g, b) in this particular case. + colour = data.GetColour().Get() + colour = wx.Colour(colour[0], colour[1], colour[2]) + self.TC.SetSelectionColour(colour) + self.TC.Refresh() + + # Once the dialog is destroyed, Mr. wx.ColourData is no longer your + # friend. Don't use it again! + dlg.Destroy() + + + def CreatePopups(self): + + if not hasattr(self, "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + self.popupID4 = wx.NewId() + self.popupID5 = wx.NewId() + self.popupID6 = wx.NewId() + self.popupID7 = wx.NewId() + self.popupID8 = wx.NewId() + self.popupID9 = wx.NewId() + self.popupID10 = wx.NewId() + self.popupID11 = wx.NewId() + self.popupID12 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + self.Bind(wx.EVT_MENU, self.OnPopupFour, id=self.popupID4) + self.Bind(wx.EVT_MENU, self.OnPopupFive, id=self.popupID5) + self.Bind(wx.EVT_MENU, self.OnPopupSix, id=self.popupID6) + self.Bind(wx.EVT_MENU, self.OnPopupSeven, id=self.popupID7) + self.Bind(wx.EVT_MENU, self.OnPopupEight, id=self.popupID8) + self.Bind(wx.EVT_MENU, self.OnPopupNine, id=self.popupID9) + + menu = wx.Menu() + item = wx.MenuItem(menu, self.popupID1, "One") + img = images.Mondrian.GetImage() + img.Rescale(16, 16) + bmp = img.ConvertToBitmap() + item.SetBitmap(bmp) + menu.AppendItem(item) + + # add some other items + menu.Append(self.popupID2, "Two") + menu.Append(self.popupID3, "Three") + menu.Append(self.popupID4, "Four") + menu.Append(self.popupID5, "Five") + menu.Append(self.popupID6, "Six") + # make a submenu + sm = wx.Menu() + sm.Append(self.popupID8, "Sub Item 1") + sm.Append(self.popupID9, "Sub Item 1") + menu.AppendMenu(self.popupID7, "Test Submenu", sm) + + return menu + + + def CreateGlobalPopups(self): + + if not hasattr(self, "popupID10"): + self.popupID10 = wx.NewId() + self.popupID11 = wx.NewId() + self.popupID12 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupTen, id=self.popupID10) + self.Bind(wx.EVT_MENU, self.OnPopupEleven, id=self.popupID11) + self.Bind(wx.EVT_MENU, self.OnPopupTwelve, id=self.popupID12) + + menu = wx.Menu() + item = wx.MenuItem(menu, self.popupID10, "Select all") + menu.AppendItem(item) + menu.AppendSeparator() + + item = wx.MenuItem(menu, self.popupID11, "Say Hello!") + img = images.Mondrian.GetImage() + img.Rescale(16, 16) + bmp = img.ConvertToBitmap() + item.SetBitmap(bmp) + menu.AppendItem(item) + menu.AppendSeparator() + + menu.Append(self.popupID12, "Get thumbs count") + + return menu + + + def OnPopupOne(self, event): + self.log.write("OnPopupMenu: Popup One\n") + + + def OnPopupTwo(self, event): + self.log.write("OnPopupMenu: Popup Two\n") + + + def OnPopupThree(self, event): + self.log.write("OnPopupMenu: Popup Three\n") + + + def OnPopupFour(self, event): + self.log.write("OnPopupMenu: Popup Four\n") + + + def OnPopupFive(self, event): + self.log.write("OnPopupMenu: Popup Five\n") + + + def OnPopupSix(self, event): + self.log.write("OnPopupMenu: Popup Six\n") + + + def OnPopupSeven(self, event): + self.log.write("OnPopupMenu: Popup Seven\n") + + + def OnPopupEight(self, event): + self.log.write("OnPopupMenu: Popup Eight\n") + + + def OnPopupNine(self, event): + self.log.write("OnPopupMenu: Popup Nine\n") + + + def OnPopupTen(self, event): + + items = self.TC.GetItemCount() + + for ii in xrange(items): + self.TC.SetSelection(ii) + + self.log.write("OnGlobalPopupMenu: all thumbs selected\n") + + event.Skip() + + + def OnPopupEleven(self, event): + + self.log.write("OnGlobalPopupMenu: say hello message...\n") + + msgstr = "Info: let's say hello to wxPython! " + dlg = wx.MessageDialog(self, msgstr, "ThumbnailCtrlDemo Info", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + event.Skip() + + + def OnPopupTwelve(self, event): + + items = self.TC.GetItemCount() + self.log.write("OnGlobalPopupMenu: number of thumbs: %d\n"%items) + + msgstr = "Info: number of thumbs: %d"%items + dlg = wx.MessageDialog(self, msgstr, "ThumbnailCtrlDemo Info", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + event.Skip() + + + +#--------------------------------------------------------------------------- + + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test ThumbnailCtrl ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = ThumbnailCtrlDemo(self, self.log) + self.win.Show(True) + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + + try: + import PIL.Image + win = TestPanel(nb, log) + return win + + except ImportError: + + from Main import MessagePanel + win = MessagePanel(nb, 'This demo requires PIL (Python Imaging Library).', + 'Sorry', wx.ICON_WARNING) + return win + +#---------------------------------------------------------------------- + + +overview = TC.__doc__ + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + diff --git a/demo/agw/ToasterBox.py b/demo/agw/ToasterBox.py new file mode 100644 index 00000000..f613fc31 --- /dev/null +++ b/demo/agw/ToasterBox.py @@ -0,0 +1,408 @@ +# Main ToasterBoxDemo + +import wx +import wx.lib.scrolledpanel as scrolled + +import os +import sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import toasterbox as TB + bitmapDir = "bitmaps/" +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.toasterbox as TB + bitmapDir = "agw/bitmaps/" + +# In case of TB_COMPLEX style, create a panel that contains an image, some +# text, an hyperlink and a ticker. + +import wx.lib.hyperlink as hyperlink +from wx.lib.ticker import Ticker + +# ------------------------------------------------------------------------------ # +# Class ToasterBoxDemo +# This class implements the demo for toasterbox control. try to change the +# style using the radiobox in the upper section of the frame, and see how +# ToasterBox acts. +# ------------------------------------------------------------------------------ # + +class ToasterBoxDemo(scrolled.ScrolledPanel): + + def __init__(self, parent, log): + + scrolled.ScrolledPanel.__init__(self, parent) + + self.log = log + + mainSz = wx.BoxSizer(wx.VERTICAL) + + horSz0 = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add((0, 3)) + mainSz.Add(horSz0, 1, wx.EXPAND | wx.BOTTOM, 7) + + sampleList = [" ToasterBox TB_SIMPLE ", " ToasterBox TB_COMPLEX "] + rb = wx.RadioBox(self, -1, "ToasterBox Style", wx.DefaultPosition, + wx.DefaultSize, sampleList, 2, wx.RA_SPECIFY_COLS) + + horSz0.Add(rb, 1, 0, 5) + rb.SetToolTip(wx.ToolTip("Choose the ToasterBox style")) + + self.radiochoice = rb + + horSz1 = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add(horSz1, 1, wx.EXPAND | wx.ALL, 5) + + statTxt1 = wx.StaticText(self, -1, "Popup position x/y") + horSz1.Add(statTxt1, 3) + txtCtrl1 = wx.TextCtrl(self, -1, "500") + horSz1.Add(txtCtrl1, 1) + txtCtrl1b = wx.TextCtrl(self, -1, "500") + horSz1.Add(txtCtrl1b, 1) + + self.posx = txtCtrl1 + self.posy = txtCtrl1b + + horSz2 = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add(horSz2, 1, wx.EXPAND | wx.ALL, 5) + + statTxt2 = wx.StaticText(self, -1, "Popup size x/y") + horSz2.Add(statTxt2, 3) + txtCtrl2 = wx.TextCtrl(self, -1, "210") + horSz2.Add(txtCtrl2, 1) + txtCtrl3 = wx.TextCtrl(self, -1, "130") + horSz2.Add(txtCtrl3, 1) + + self.sizex = txtCtrl2 + self.sizey = txtCtrl3 + + horSz3 = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add(horSz3, 1, wx.EXPAND | wx.ALL, 5) + + statTxt3 = wx.StaticText(self, -1, "Popup linger") + horSz3.Add(statTxt3, 3) + txtCtrl4 = wx.TextCtrl(self, -1, "4000") + helpstr = "How long the popup will stay\naround after it is launched" + txtCtrl4.SetToolTip(wx.ToolTip(helpstr)) + horSz3.Add(txtCtrl4, 1) + + self.linger = txtCtrl4 + + horSz3b = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add(horSz3b, 1, wx.EXPAND | wx.ALL, 5) + statTxt3b = wx.StaticText(self, -1, "Popup scroll speed") + horSz3b.Add(statTxt3b, 3) + txtCtrl4b = wx.TextCtrl(self, -1, "8") + helpstr = "How long it takes the window to \"fade\" in and out" + txtCtrl4b.SetToolTip(wx.ToolTip(helpstr)) + horSz3b.Add(txtCtrl4b, 2) + + self.scrollspeed = txtCtrl4b + + horSz3c = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add(horSz3c, 1, wx.EXPAND | wx.ALL, 5) + statTxt3c = wx.StaticText(self, -1, "Popup background picture") + horSz3c.Add(statTxt3c, 3) + txtCtrl4c = wx.FilePickerCtrl(self, -1, style=wx.FLP_USE_TEXTCTRL|wx.FLP_OPEN) + horSz3c.Add(txtCtrl4c, 2) + + self.backimage = txtCtrl4c + + popupText1 = "Hello from wxPython! This is another (probably) useful class. " \ + "written by Andrea Gavana @ 8 September 2005." + popupText2 = "I don't know what to write in this message. If you like this " \ + "class, please let me know!." + + horSz4 = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add(horSz4, 1, wx.EXPAND | wx.ALL, 5) + statTxt4 = wx.StaticText(self, -1, "Popup text") + horSz4.Add(statTxt4, 1) + txtCtrl5 = wx.TextCtrl(self, -1, popupText1) + horSz4.Add(txtCtrl5, 2) + + self.showntext = txtCtrl5 + self.popupText1 = popupText1 + self.popupText2 = popupText2 + self.counter = 0 + + horSz5 = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add(horSz5, 1, wx.EXPAND | wx.ALL, 5) + self.colButton1 = wx.Button(self, -1, "Set BG Colour") + self.colButton1.SetToolTip(wx.ToolTip("Set the ToasterBox background colour")) + self.colButton1.Bind(wx.EVT_BUTTON, self.SetColours) + horSz5.Add(self.colButton1, 1, 0, 5) + self.colButton2 = wx.Button(self, -1, "Set FG Colour") + self.colButton2.SetToolTip(wx.ToolTip("Set the ToasterBox text colour")) + self.colButton2.Bind(wx.EVT_BUTTON, self.SetColours2) + horSz5.Add(self.colButton2, 1, 0, 5) + + horSz6 = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add(horSz6, 1, wx.EXPAND | wx.ALL, 5) + statTxt6 = wx.StaticText(self, -1, "Popup text font") + horSz6.Add(statTxt6, 1, 0, 5) + fontbutton = wx.Button(self, -1, "Select font") + horSz6.Add(fontbutton, 1, 0, 5) + + horSz7 = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add(horSz7, 1, wx.EXPAND | wx.ALL, 5) + self.checkcaption = wx.CheckBox(self, -1, "Show with caption") + horSz7.Add(self.checkcaption, 1, 0, 5) + self.captiontext = wx.TextCtrl(self, -1, "ToasterBox title!") + horSz7.Add(self.captiontext, 1, 0, 5) + self.captiontext.Enable(False) + self.checkcaption.Bind(wx.EVT_CHECKBOX, self.OnCheckCaption) + + horSz8 = wx.BoxSizer(wx.VERTICAL) + mainSz.Add(horSz8, 1, wx.EXPAND | wx.ALL, 5) + self.radiotime = wx.RadioButton(self, -1, "Hide by time", style=wx.RB_GROUP) + horSz8.Add(self.radiotime, 1, 0, 5) + self.radioclick = wx.RadioButton(self, -1, "Hide by click") + horSz8.Add(self.radioclick, 1, 0, 5) + + horSz9 = wx.BoxSizer(wx.HORIZONTAL) + mainSz.Add(horSz9, 1, wx.EXPAND | wx.ALL, 5) + goButton = wx.Button(self, -1, "Show ToasterBox!") + goButton.SetToolTip(wx.ToolTip("Launch ToasterBox. You can click more than once!")) + horSz9.Add((1,0), 1) + horSz9.Add(goButton, 2, 0, 5) + horSz9.Add((1,0), 1) + + self.colButton1.SetBackgroundColour(wx.WHITE) + self.colButton2.SetBackgroundColour(wx.BLACK) + self.colButton2.SetForegroundColour(wx.WHITE) + + goButton.Bind(wx.EVT_BUTTON, self.ButtonDown) + fontbutton.Bind(wx.EVT_BUTTON, self.OnSelectFont) + rb.Bind(wx.EVT_RADIOBOX, self.OnRadioBox) + + self.curFont = self.GetFont() + + self.SetAutoLayout(True) + self.SetSizer(mainSz) + self.Fit() + self.SetupScrolling() + + + def SetColours(self, event): + + cd = wx.ColourDialog(self) + cd.ShowModal() + colBg = cd.GetColourData().GetColour() + colButton1 = event.GetEventObject() + colButton1.SetBackgroundColour(colBg) + + + def SetColours2(self, event): + + cd = wx.ColourDialog(self) + cd.ShowModal() + colFg = cd.GetColourData().GetColour() + colButton2 = event.GetEventObject() + colButton2.SetBackgroundColour(colFg) + + + def OnSelectFont(self, event): + + curFont = self.GetFont() + curClr = wx.BLACK + data = wx.FontData() + data.EnableEffects(True) + data.SetColour(curClr) + data.SetInitialFont(curFont) + + dlg = wx.FontDialog(self, data) + + if dlg.ShowModal() == wx.ID_OK: + data = dlg.GetFontData() + font = data.GetChosenFont() + colour = data.GetColour() + + self.curFont = font + self.curClr = colour + + dlg.Destroy() + + + def OnRadioBox(self, event): + + mainsizer = self.GetSizer() + + if event.GetInt() == 0: + self.linger.SetValue("4000") + self.scrollspeed.SetValue("8") + + for ii in xrange(5, 10): + mainsizer.Show(ii, True) + + else: + for ii in xrange(5, 10): + mainsizer.Show(ii, False) + + self.linger.SetValue("10000") + self.scrollspeed.SetValue("20") + + mainsizer.Layout() + self.Refresh() + + event.Skip() + + + def OnCheckCaption(self, event): + + if self.checkcaption.GetValue(): + self.captiontext.Enable(True) + self.sizex.SetValue("250") + self.sizey.SetValue("200") + else: + self.captiontext.Enable(False) + self.sizex.SetValue("250") + self.sizey.SetValue("200") + + self.sizex.Refresh() + self.sizey.Refresh() + + + def ButtonDown(self, event): + + demochoice = self.radiochoice.GetSelection() + + if self.checkcaption.GetValue(): + txts = self.captiontext.GetValue().strip() + windowstyle = TB.TB_CAPTION + else: + windowstyle = TB.TB_DEFAULT_STYLE + + if demochoice == 1: + tbstyle = TB.TB_COMPLEX + else: + tbstyle = TB.TB_SIMPLE + + if self.radioclick.GetValue(): + closingstyle = TB.TB_ONCLICK + else: + closingstyle = TB.TB_ONTIME + + tb = TB.ToasterBox(self, tbstyle, windowstyle, closingstyle, + scrollType=TB.TB_SCR_TYPE_FADE + ) + + if windowstyle == TB.TB_CAPTION: + tb.SetTitle(txts) + + sizex = int(self.sizex.GetValue()) + sizey = int(self.sizey.GetValue()) + tb.SetPopupSize((sizex, sizey)) + + posx = int(self.posx.GetValue()) + posy = int(self.posy.GetValue()) + tb.SetPopupPosition((posx, posy)) + + tb.SetPopupPauseTime(int(self.linger.GetValue())) + tb.SetPopupScrollSpeed(int(self.scrollspeed.GetValue())) + + if demochoice == 0: # Simple Demo: + + self.RunSimpleDemo(tb) + + else: + + self.RunComplexDemo(tb) + + tb.Play() + + + def RunSimpleDemo(self, tb): + + tb.SetPopupBackgroundColour(self.colButton1.GetBackgroundColour()) + tb.SetPopupTextColour(self.colButton2.GetBackgroundColour()) + bmp = self.backimage.GetPath() + dummybmp = wx.NullBitmap + + if os.path.isfile(bmp): + dummybmp = wx.Bitmap(bmp) + + if dummybmp.Ok(): + tb.SetPopupBitmap(bmp) + else: + tb.SetPopupBitmap() + + txtshown = self.showntext.GetValue() + if self.counter == 0: + if txtshown in [self.popupText1, self.popupText2]: + self.counter = self.counter + 1 + txtshown = self.popupText1 + else: + if txtshown in [self.popupText1, self.popupText2]: + self.counter = 0 + txtshown = self.popupText2 + + tb.SetPopupText(txtshown) + tb.SetPopupTextFont(self.curFont) + + + def RunComplexDemo(self, tb): + + # This Is The New Call Style: The Call To GetToasterBoxWindow() + # Is Mandatory, In Order To Create A Custom Parent On ToasterBox. + + tbpanel = tb.GetToasterBoxWindow() + panel = wx.Panel(tbpanel, -1) + + sizer = wx.BoxSizer(wx.VERTICAL) + horsizer1 = wx.BoxSizer(wx.HORIZONTAL) + + myimage = wx.Bitmap(os.path.join(bitmapDir, "sttfont.png"), wx.BITMAP_TYPE_PNG) + stbmp = wx.StaticBitmap(panel, -1, myimage) + horsizer1.Add(stbmp, 0) + + strs = "This Is Another Example Of ToasterBox, A Complex One. This Kind Of" + strs = strs + " ToasterBox Can Be Created Using The Style TB_COMPLEX." + sttext = wx.StaticText(panel, -1, strs) + horsizer1.Add(sttext, 1, wx.EXPAND | wx.LEFT | wx.RIGHT, 5) + + hl = hyperlink.HyperLinkCtrl(panel, -1, "My Home Page", + URL="http://xoomer.alice.it/infinity77/") + + sizer.Add((0,5)) + sizer.Add(horsizer1, 0, wx.EXPAND) + + horsizer2 = wx.BoxSizer(wx.HORIZONTAL) + horsizer2.Add((5, 0)) + horsizer2.Add(hl, 0, wx.EXPAND | wx.TOP, 10) + sizer.Add(horsizer2, 0, wx.EXPAND) + + tk = Ticker(panel) + tk.SetText("Hello From wxPython!") + + horsizer3 = wx.BoxSizer(wx.HORIZONTAL) + horsizer3.Add((5, 0)) + horsizer3.Add(tk, 1, wx.EXPAND | wx.TOP, 10) + horsizer3.Add((5,0)) + sizer.Add(horsizer3, 0, wx.EXPAND) + + panel.SetSizer(sizer) + panel.Layout() + + tb.AddPanel(panel) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = ToasterBoxDemo(nb, log) + return win + +#---------------------------------------------------------------------- + +overview = TB.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) diff --git a/demo/agw/UltimateListCtrl.py b/demo/agw/UltimateListCtrl.py new file mode 100644 index 00000000..9322370c --- /dev/null +++ b/demo/agw/UltimateListCtrl.py @@ -0,0 +1,78 @@ +import wx +import sys, os + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import ultimatelistctrl as ULC +except ImportError: # if it's not there locally, try the wxPython lib. + from wx.lib.agw import ultimatelistctrl as ULC + + +#--------------------------------------------------------------------------- + +buttonDefs = { + 814 : ('UltimateReportDemo', ' wx.LC_REPORT style '), + 815 : ('UltimateVirtualDemo', ' wx.LC_VIRTUAL style '), + 816 : ('UltimateListIconDemo', ' wx.LC_ICON style '), + 817 : ('UltimateListListDemo', ' wx.LC_LIST style '), + 818 : ('Windows7Explorer_Contents', ' Windows 7 Explorer "Contents" style'), + 819 : ('MacLargeDemo', ' Torrent Style :-D') + } + + +class ButtonPanel(wx.Panel): + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent, -1) + self.log = log + + box = wx.BoxSizer(wx.VERTICAL) + box.Add((20, 20)) + keys = buttonDefs.keys() + keys.sort() + + for k in keys: + text = buttonDefs[k][1] + btn = wx.Button(self, k, text) + box.Add(btn, 0, wx.ALIGN_CENTER|wx.ALL, 10) + self.Bind(wx.EVT_BUTTON, self.OnButton, btn) + + self.SetSizer(box) + box.Fit(self) + + + def OnButton(self, event): + + event.Skip() + + wx.BeginBusyCursor() + + modName = buttonDefs[event.GetId()][0] + module = __import__(modName) + frame = module.TestFrame(None, self.log) + + wx.EndBusyCursor() + +#--------------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = ButtonPanel(nb, log) + return win + +#--------------------------------------------------------------------------- + + + +overview = ULC.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/UltimateListIconDemo.py b/demo/agw/UltimateListIconDemo.py new file mode 100644 index 00000000..67db9847 --- /dev/null +++ b/demo/agw/UltimateListIconDemo.py @@ -0,0 +1,906 @@ +import wx +import os, sys +import images + +from wx.lib.embeddedimage import PyEmbeddedImage + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import ultimatelistctrl as ULC +except ImportError: # if it's not there locally, try the wxPython lib. + from wx.lib.agw import ultimatelistctrl as ULC + + +catalog = {} +index = [] + +access = PyEmbeddedImage( + "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") +index.append('access') +catalog['access'] = access + +#---------------------------------------------------------------------- +acroread = PyEmbeddedImage( + "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" + "rkJggg==") +index.append('acroread') +catalog['acroread'] = acroread + +#---------------------------------------------------------------------- +agent = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAAK/INwWK6QAAABl0" + "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAABbgSURBVHjaYvz//z/DSAYAAcTE" + "MMIBQACN+AAACKARHwAAATTiAwAggEZ8AAAE0IgPAIAAGvEBABBALDAGIyMj/W0XmcnC8P93" + "AAPDHyWG75sXMnzb+x4o+oueTgAIIEZYQ4juASA82YbhL1MHw18GawYWYEJk/HaD4e+lFoaP" + "C7cAZT8D8T96OAMggOgfAEKTZYBkPcMPhgQ+KT4WKy91BlYeToYD6y4zfH7x4Q8Dy8v1DN92" + "NTJ8O3kHqO4nrZ0DEED0CwCh6WwMDH8zGH7+r2bmZBMzcVdlcAvTZRCVFWB4/+U/w4vHHxgO" + "rr3EcO3oPWDcf3vO8P92B8ObqUuAOj8C8V9aOQsggOgTAEKTXRh+M3Qw/Gc0VjCSZnCPMmBQ" + "NZBi+P//H8PXr38Y3n/9z8DCyszABHTCzTOPGQ6vu8Tw/un7/wxMb/YyfDtcy/BpxyWgKd+B" + "mOodF4AAom0ACExSBDq5leEXYxifLD+zQ4gug4mzCgMrOwvD759/GP4BrX7/5S/Drz8g+yGY" + "jYOF4fP77wynd1xnuHzoLsO/X98/MPy/O4nhzcIZDH/evAaa+oeaTgQIINoEAP8kUD5PB5bn" + "WSw87EJG7moMNgFaDILivAy/fgA9DvQ5KLY/ff/H8AWImdDsZgYWikzMTAyPb7xkOL71KsOb" + "e28ZGJi+3WP4fbud4cWkNdBCkirZAiCAqBsAAtOA+fxPJtDj1QxMTKLywORuF6bHIK8lxvD3" + "z3+Gv7//Qu0Clm6//wOT/j/ciRqohoWNheHX998MV4/cZbh2/AHDjw9ADYyvdjB82lfP8H73" + "VaCqH5RmC4AAol4A8E9yYfjzv5PhP5ORtJ4kg6GbKoOaiSw4b/8GpnHYsAMo5n///c/w7utf" + "hr//QP7Eby8jUAPIjM/vvzFcOXSH4c7Zx8Cmw9e3DH9u9zE87p0FVPKBkmwBEECUBwD/RCVg" + "jd0Cyuc8MvzMpr6aDNp2SvB8/v8fIoJAVvwCpoQP3/4x/AGKE/I8erYABcaz268ZLh24xfDx" + "KahyeHuc4fOxaoZXa06SW0gCBBD5AcA3lQsY8PnA5F7GzM0uoOmgzGDoqc7AJ8oN9PhfYD7/" + "h9He/vYblO//MkDChPQAB+mAZItfDLdOP2S4B0wNf398/cLw5/5shsfTehl+v3sFVPKbFDMB" + "Aoi8AOCd6Aus0tqBCU9bClidGfppMUiqijD8+wOM2T9/GZC9BzIWKMzw5cd/YAAgpQaQCpii" + "/zCKuAhkYmJiYGZlYngHTAU3gO2G949BLeiPVxk+n65heDJ/L5DzhdjUABBApAUAT58EMB0W" + "A5N7IRMHK7M6sEozDtABJ09QckdO6ozQtuwPYHx8/vmfARQujEwwjzOCPQuqDUCQGSgBth/o" + "Foh7iAsIFlYWhj/A8uXa4TsML26+BGr79ZXhx41pDI/nTWb4+fI5MWUDQAARHwC8/dYMf5jW" + "AGNeQlRLnEHXW5NBTFUUGOvAJA0s1GCeBhkHzOYMwFzA8B1o/e8/kHgFBwiw4fP77x+GX0DM" + "+OMzA9vXNwxMv38w/OIWZvjNLcLAxsIGxKwY1SIjLEVhGcAFlQsg/PLua4YH5x8z/AAWlsBy" + "8SrDx1NVDI/m7yeUGgACiLgA4J0CDOq/+zmFeWw0vTUYZAykwXnxD7R0B5kAiuHfwBj99Y+R" + "4fvnDwy/P78FVgjM0FQOJP/9ZmD78oZB+O19BsnXdxikXj9gUHh3j0Hw7yeGF4KKDI+kNRju" + "SugwPBZSZfjBJYRSRjABA46Zg4eBmVcUuycYQYUkM8PPrz8ZXgILyRe3XjL8+fL2KcPtxjiG" + "74/PAJV8wuU1gABiISqt/f+XALTGRs1dnUHWXIHh19dfDL9+QfopH4HUz3+QyAEHJjB/fvvx" + "jUHx7DoG1et7GP4A8z0LExcD19+fDNI/nzCIcn5hEBP9zyCmDWw2GDAwsAoDA+/yW4ZfF88w" + "fDvFyPDxnzDDSy5pBmZgQ4iN+T8DD8cvhsuCGgyTlFMYODiEgKmDCXuE/gY2EYCBIKkvzcDK" + "y85w//gfaQZxr2yGBzMbgLI3cBWOAAFEOAB4e0WApViFkJo4g7CWBLiZCvIoKH6AKR+cv/8j" + "FXuMoCwA9PDv/8wMim9vM+iGWzOwM55g4OT/zSCiB+wW6AKLEgVgjPECFXNB7fgF9BKwbff7" + "7n+G3+ffMDDefcPAAjQHWP0zMAIruLvf5Rm+sPIzsIAKlf/4G4CMwMYWjwQ/A484H8OXX4bO" + "DJzSmxm+P30BlHqNTT1AABEOgP8shYxsrMoyNkrAvA1szf1CtOaANRrDzz+w2vw/PMP+/8/E" + "8FxEjeEbBx+DcUUKg5Am0O6fNyDyP6FxAUqU72CVPFAbK7AfoA7EetCiixEaMMkMDKd/qTH8" + "BgbqH1B58p/wMAETsFDmVxRh+PLmCz+DpG8ow70ZF6G9SozBFoAAYiHQyNEClvjZwgaSDJwy" + "AgzfQBU53J//GT4BPQ/K86ilB7B0/8/C8JFHguHlP26Gl6cvMwhpqAHD/waiyoOl4H+cECf8" + "/QxxGiO00QCigY1qhgdAVz9lZbigogb0FDswsP9iLQgxALCJySbIzcAlxgusek1tGLh3GDN8" + "ffAUmgpQDAAIIPxjgv8Yapj5OPiFjWQYfgCruZ/A2P8JTGK/gPjLr/8MX4H4N7CS/4WC/wJT" + "ChPDDx4xhmdcUgyvz1wDGiTNAK8KmCAxzsAKSg3AvPBFDxwGYDEmBtRAAmp99FuU4RGnNLAY" + "YgTb+wvDPiwYWB78AuZPLhlgYcopxMcg5RMKNE0WGqwoACCAWPC07d0Y/jCGC+pJMTDycTB8" + "//YbOZIZPgM9+es/jsYsqLPDwsvwSlyd4cWFY8AmoA7Qc0AfsvxF1Gkg/B3owO8iDAwiwNBg" + "gaauf9B+HihF3GRguMCkyPCeVYCBA9SZ+k/CKBkwIBh5OBjYhXmAEWdiycCrasrw+fYToMwr" + "5FQAEEAsOHp1rMCuWwOrKC8Tl7o4ww+g52FtelAh9xMYVV8Y8DRYGEHZAFgOAAPg2aVNDN8/" + "MDJwMvEBlQNbbO+Asf6bA2LQJ15wcmV4oQFMAT8h5gk/BgbCD0gX5w4Dw3keZYavTLwMTODk" + "T9owIbgjJc7P8OvDN97/0j5hDDf6z0I7T/ChNoAAwh4A//8mAusUS25tKYbfzMwM/77/hef7" + "P8DS7yu4JYffMf+A1dVLAQWG199YGN5efsAgYyQIFAUGABew9HsEzBLA8omBGRjrjMAS74UM" + "MEsAo1wWGOXsPyHFFTC3fnjCyHBWUAmcN34Tm//RAQcbA6MAF7AHaWjGwK9hzvDxBigVvIDF" + "HkAAYQaAwARg552hnEWKn4FRWoDh+9dfYItBKfYPqI4HJuX/8LSKLwCAkQssuT8y8TD8eA30" + "DbDFB86B/MCiX/MEA8NVYLb4xA9JCSxfGRg0gAU1zzeIsX8gtcT3X6wMz5gFwFni19+/5HX9" + "Qf1vQR5gngWWijJ+YcAAOA2JCfBYAgNAAGEGwH+maGB+VWJVFAZ3Wf8DCx5wMxYY69+BGLmX" + "hz/9AfPg758MXIw/Gdj5gA7/DfQcJ6wgBPJ/AM35CxRjBtI/mBGFJDMibbIyAev0P8DAAdr5" + "j+E/eQEAyrrswDKGix0Y+Nr6DJyS+gzfnz+EpgIGgABiwoj9/4w5TMDqg1GEl+Hv99/AFuxf" + "cBP3OzDm/8Ha4wQxRB3Tn58M3P+/A1tmoCj8iSj933MDAwSYsvSBSd4EWNRzAyPkJS+kNkCK" + "Ela2vwwCf4BNeVjs/ycTg/TyA0OfU5iPQc7fDyggBasRAAIINQUwMpcwsLIqsSiJMPwF5TlQ" + "yAN7XL9ZmCGG/CM2BiA9PjZgh4cdWPJz8AJTG7ADxABrxTIDzTa5D3QUtF1iCmS/AToQ2K5g" + "YP0PUQdUwg4UEvj1GaKXkYXkQhCpOgd6HpQKgH4Ws7BheLJFn+HrE3CNABBAiBQgNMWA4R9T" + "BpMkH8M/HnZw8v8FTDq/Qe1RUCiCkj6JmPPHJwYWYBJn5/wGcQUXNMglgXzBX4gUzQn0rRww" + "ptmBAsAKgoEdEgBsQFoQ1Ej6+5cs+1Ex0GxgtQhsHfEzKASFQhonDGwAAYRIAf/+BjGwsAOr" + "CwGGP1yskLYuWJycUIfo5fzxhYGD6x8DK/t3Boan/yDCPKD+BTQBskJTBKzeB3VcgVme4SWk" + "IGQCBoDA76+QqhJUVvyncLaMFTTSCoxQPiVgCcygDMSPAAIIEQD/n2xn+KdQ/P/9Ny4GYCoA" + "D+OQPdLIBI5xTmAW4OL6y/APVAYoigFrX6Av3wKrvntA+h/Qh6z/IB4HNwGAetiAjmMHlX5A" + "rAEMHbF3DEL3gdXBn18QMXieJjNOQIMUoMB8dRJUAAqA0hpAACEC4GP3RQbBxm0Mj9lCGKSA" + "AQDMBsTneeT89g8yOPDzOwPnz3cMn+79YVjn8IBBQo+ZQVCdnYFfmRUYAbwMPNKMwATwl+H/" + "pz8Mf78AsxuwsfTvGbC6ffabgeXFVwamZ8D2PLBNxPMPWEC+eQZMNaKQ7iEL0MnMzOQFArBQ" + "Z/jx6ivD4+03oF2xHwABhFwIfmf4c2Mywy8hT4aH77gZtMSJCwBYjICHgoCx+usXlP2T4ZaQ" + "DsMMtlQG0U8vGST3v2SQ2fqKQZ7pDYME1wcGIb6/DGKykJ7hj7eMwEhmAfYvuBmeM4kzPOUQ" + "YXjCLsLwmFOM4RKHNHiMgeEPUCGwWgWzWVkhmIkJdVQEX+z//geJ/ecHHwFD+x5Q5D5oggUg" + "gFhQunGfl59hEFZbz/CSK4ZBCphvefGkAvhAPxOCD4oZTk6oAm6Gb7wmDDf/GjPc/AcaLgKa" + "9xOYyX9/YRD9+ZpB8cdTBulnr4A1DDuwBhRjeMQuwfCKVYjhPzOwkABhFg6IeSyMSDH+H3fg" + "EwoEUDf+5/sfwNi/AuTdAmJQ7/A3QAChN4S+M/y+MpmBWcSH4clHAQZ1EewBAErmoKTIwYEa" + "C+ChL9CAACO4scMKrNL42f4zSPL8YxDj4mEQ5hRh4GX7x8ABrBpZmf4Ai5l/4IaaBrBg+vef" + "GdjdZWb4+puR4eNPJoa33xkZXn4F9ie+APsdQLF/f6DmglqOTP8w3fPzJyQFYgsIkB9Aozcv" + "jz1h+Pb8NqSXAW5wMwAEEHoAADv5ay8zsOusZnjLlcrwARhrfGipAGQZKJYFBJBiH9KXZWX9" + "w6DI9Z1Bi/8bgxzPTwZZ7p8Momw/gYXvX2DtB8zvwGzxC5hFQN1qULf131+oR4AeZGUB6Wdm" + "4OBhA9KsQCNZgRUBI8OPvywMz7+zMzz9zsZw5xMHw7WPwGzygxuoFzSK8hfRJOcBppovwBT2" + "6RNiphXeMwRhYI/u0RZQ3xwUAE9ggyMAAdgwlxSEYSAM/6QPqaGIItYHLly79gSewMN5KRd2" + "3VUXUg2CCJW0CWh18tCVN8hkvmH++f4dQwr6uEc02UE8xuChJ89ngQEVPp05LG1HQmRRjU1y" + "wjqqMOxuFvW2anGWGoVUaBoNpbR1B4YSRqky+GFNJ7XV4sxpcqsVzYcE6CcxbZEeUh5jQUFm" + "RcRtM47qNUKu5sj1EtJIlffTvS+l/copZQrhaGCemo4adT1cUJeFx//+naePAMIWAMBUsPkG" + "A5fFNoaPXHHAkgloKCukDhYRZmBQAlaf/5ghefrXVwaF7zcYXL4dY+B48Zrh0YevDHeBWQDY" + "C2BgBnqSi4sLjCX4BYGJBtg3Z+cA8jmBkcUNdCc3eIIDPMkBDAyQx79//wHEkMD6Cawyv337" + "BozUbwxvP35lePryE9BPoKm23wzCwGatl4QQg+IvPoYtf4wZ3nMAS1NWLtC0ETDF8kFS5qOH" + "oN4YJABAfnp++C6QvgeN/R8wzwIEEK4BkV8Mv+/MYmATC2K4/5GHAdQwYgMa9ouDgZHrPYMO" + "6ykG6a93GMSYPjOIcgAbOmysDKz8cgwyyiCPcYI9DUrGzMwswKKCGYxBfJgYaAge5HGQOMjz" + "oBTBAixTWFlZwGrAo1rA1h9olgnkaQj+Cwyc7wwfP35iYAM2EVlYWBnEnz1ikLm/l+HZN2BZ" + "8ZeL4Ra3EcODnyrAvA7MBn/ZoeUFMADe33zP8OIoKPnfhVZ/8DwNEEC4AuA/w9v55xhYBLoZ" + "/ghFMfzgkGBk4eP+/+Yby/+bLxjsg/4wODjIMzx//RFYPACTK9BBoGQLKgcg9H+wByDl0X94" + "Qf0XmOeZmf9APc8C7lkyA1t4TEyQuUSQnt+/IfIQPYg5C9AwOQcHOzBwxRn4+fnAZcn//78Z" + "OHm4GMyAESAiwM3QvfMbw4MrVxm4mN////vt5cefn168Yfj+4j3DS/B6oyvQqu8bskcBAgjf" + "oOgPhpf9M4D0MQZGNk1GNnEFQUF+ZWZOWZWjZ7S0VeWUGURFxYHZ7SXDH2DMgDwEwqAuH8jB" + "II+DPADK14yM/8CegvAR7P/wqTAGFDailvuPweYEFsCggHz79h3D169fGdg5gA1XKUmGIycv" + "MDw6f5pB493d10/vnD/3/cu3uwz//z6FDoG9gib/5+gDGQABRGhmiAXaeucHV+zAHAbEooaG" + "+sVS0or27m7ODBIS4gyvX78GxwgkiTNjYFDAYBPHpxY5UEApA4RB4jzA0v7Dhw/AAHgLLkcE" + "gLXR4SPHGLZs2crw5tXzp1euXj0ADOTzQO0Xofn9EzTWv0NLfpRQBgggUiZHGaHdF05gDMoY" + "GplMFBMTd7ayNGfQ0tIExsYXYA30GWwOsodxeR5ZHFYQgsRg2QNkDnIAgFIOL7CUBwX0x48f" + "gdmAH5hdfjNs3baD4ejRYwxv3rx+evXKpb1AdSeAbjwKjfGvhEZRAAKI3PUBoA6rgoGhUauI" + "iGigqooKk6mpMYOgoCCw1P4CLqzA8x3MzPBUAfMYNs/D+DA2tgDg4ADVIuxgT4PUXb9+g2Hb" + "9h0MDx4+/P/i2dM7N2/eOAxUC1oocQRa2BG1xhAggChZIQIKBDkVFdUEaWmZdAFBQWENDXVw" + "ahAQ4Ac3cn78+A4u1CCFGCLmkWMaOfaRUwhIHFKWMIKTPSj2QTF/+/ZthkOHjzBcBRZ2n798" + "/nLn9u1LL148B02Agsb6QAHwiJQFlgABROkSGVCWEAfmRTM1NfV0YWFhWz4+Pk5ZWVkGEJaW" + "lgI7HFzPA5PwH2BMgucVkQIEOQAgVSErOLZBGKQOFONv3rxluHnzJsPFS5cYHjx4ACr8fgI9" + "fQ/o+XNAeVD1Bsrzl6EjCSStEAEIIGoskmKGDnEoCAgIWiooKAQDA8IYWFrzAxs/jCIiIsCG" + "oySDKJAGZRFgAIGTMnJsw9oFIPwT2KYHxfQbYCH3/NkzUBJneP3qFaSR9OP7l1cvXz26f//+" + "le/fv92GzB0xgFaLPSR36RxAAFFzmRxojAc0sS/HxsamKSoqaiYuLm7Ex8+vwMnBIQz0NCso" + "dkGxDGrIgOp0GP8PsKv7C5hVfvz4wfAbWMiBYh0UEEAaWMN+//T+/fuXb968efLy5ct7wPLg" + "CTSPgwLgMbRZS/YKc4AAovZCSdi0JqjaBK1mEAeaKw3MBsrAVKEJzMtSwJQhCAwgHmDMswNj" + "nAWImf9BANBvf38BPQ708/fPnz59eges6p4Dm8MvgW58BR3GfgalXyPN9lK0ThAggGi5VBbU" + "nOOAtiP4oENQQlAaJMYJLUhZoGqRZwW/QUcIP0Cbru+h9flXaDueaounAQKIXqvFYVMesDFf" + "2JAoM9KEOPLU6G8GxGghzMM02eEJEECMI33nKEAAjfg9QwABNOIDACCARnwAAATQiA8AgAAa" + "8QEAEGAAN3pyzfJrAA8AAAAASUVORK5CYII=") +index.append('agent') +catalog['agent'] = agent + +#---------------------------------------------------------------------- +aktion = PyEmbeddedImage( + "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") +index.append('aktion') +catalog['aktion'] = aktion + +#---------------------------------------------------------------------- +amarok = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAAK/INwWK6QAAABl0" + "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAABj6SURBVHjaYvz//z/DSAYAAcTE" + "MMIBQACN+AAACKARHwAAATTiAwAggFhgDEZGxoF3jeEUToZ/f6OArvFjYPrPzvD7yzaGO5NX" + "MPx48Q4o+4cWVgIEECOsFhjwANDvUWf4yzqfgZXZkpmZkeHvL6C7WNgYGL7evMhwZ1ouw9/v" + "54CqvgExVastgAAaHAGg16XD8J9lk6oMi6KTFhODqCAHw7WnTAybT31j+P2fk4Hh3cEbDA8W" + "JwP9fhGo+is1rQYIoIEvA3RaZBj+/F+nJvFLMcrsB4OG1H8GOREmhih7HoYMbyEGpr9A/wrb" + "ajDwaZQBVcsDMRs1rQcIoIENAN02TobfDIslRNhU3bV/MzAx/GP4+ZuB4Rcwt3/98Y/Bw4SP" + "wd2Mj4Hhx3cGBklfVwZGJkegLiFQgsVqnrExM6lOAAiggQ2AH9+niYrxOcQ7CTFwsvxi+PMP" + "4a9/wJz5B0hEOIox8PICORyyXAxc8oF4U8H//yoMpjoxDFzsPMgFPD4AEEADFwBqVTUcnOwJ" + "NUmmDBx/ngFj/h+Gkl+//zPIS3AyOBoKQpKFoIkeUFgTiPmxmvny+UNgIOgz6MtvZpARAKnl" + "wplaoAAggAYmANTKoxj+/m9sK/ZgUBf/y/DwyXMGJiZmBlCBjN41+QcMF1dTUQYmVmAA8GoK" + "MzCymgGFRYAYM7k/ff6T4dqdXqCfRRmUhNcySPPYAUV58QUCQADRPwDUSqwYfv2dXphqz5QS" + "YMRw/ORpcL3GzMzMwMnJxgCqApE7aL9+/2XQVuRjUJTiAEUoEwOHuC4DF4cmg5GWP1CAHS0g" + "/jN8+/me4cW7UgZmJjkGNcHpDELsoADjwRUIAAFE3wBQK1Bk+PFrqZONNl9bvivD4yfPGO7f" + "v8/Aw83BICnJyyArK8wgLy/OwM7OCgyEf/CygJ+blcFMSxDSFOKQkWP49oOL4f8/WwZLtUUM" + "gpwK0ICAgZ8M918fYfj6czEDG7MCgw5/J1BMFaQTm5MAAoh+AaBWyMvw+/cyQV4xhYJwVwYO" + "DiaG69dvMvz48Y1BQICdgYWFCZz8ubjYGaSkgEmeiQmeJUDpwVANGAAswBDglgcyGOQYLt1a" + "Bkwuugw6YssZeFm1ofkdBr4wvPjYC8xm7xn4WY0YjPgKgWIy2ApGgACiTwCo5DIy/P4xi5Od" + "3yLZ15PBzlqS4evXfwx3794DxjbQVSyM8Lz/9+8/Bh4eDmCg8MKzAigbaCkKArMIMBVzSAM9" + "yqTA8BdYZbx4W8vAwWLKYCgyGWQLUiz/Z3j08RbD99+rwDxp9iAGMVasVShAANEnAP78bGFh" + "Zo8Is3NniIswYODhY2L49Ok7w+PHD4ApgRmj4APxBQV5weUCyC/AMAG2DjkZ5MU5QTUgMwML" + "lww4xu+8OsLw7fcGBl4WKwZTAVBDSRYpln8xvP8xG5iHvjGwMnIxaHAkAcWU0LMCQADRPgAU" + "koEWM1Z5mTozRPhbMggKQ5L6mzfvGD5+fM3AzIytOv8PDBh2cKEIyQb/geUeC4OqHLBR9Beo" + "gJVfHFoV/mZ497UX6MmfDFJsIQzSbJ7QGoIRHHLX3l1l+PnvMNhQcWZDBkkWByBLGDkVAAQQ" + "bQNAPt4JmKYn2+rYMMQFOjNw8bBCLAXa+uzZU4bv3z8zYOuCgDwMKgO4ubkQAcLGwqAgCSzM" + "QY0lFj4+aACwMFx/e47hx989DEyM7MBYToYWeJzwAvHnn9VgFjMjG4MKix+0IQVPBQABRLsA" + "kItRY/jze5GesjFXQoAvA58AJ8Pnz6BC7j+4bn/+/BmwAPwCDABmHI26/8AUwAEtDIERD6wO" + "5IA1BbgNyMLLDQ0AUOn/neHHn4UM/xn/Mwiz6DDIs7oDxcTgqeD1z53AwvAtUB6UCnQYOBm1" + "gOICMHsAAog2ASAbJgTM98sVpTSlE/3DGMQl+Bk+fIDkbU5g3Pz8CQqAp/CqDlcAgKpDFhZm" + "eOEoJcrDwMwKNISZix3qCUj1d+/zXmCH6iHQy0wMSixeoIwHTwU3Pr8AdilPg9mcjLwMSswO" + "0AAClxUAAUT9AJCNYGH482euqJCcUbxPDIO8nBg45n/8ADV2/gJj9D+Q/Zvh5ctnDIR64KDY" + "Z2NjhRaE/xkkhHkY2EDOZuYGpQNBaFJmYnj54yOwcbUPXF+KMakz8DHqIZX4f4CBcxhuqARY" + "ThoWQAABRP0A+POti4dbKCDGI45BU12B4es3oBCw+n758jOw0HvJwMrKCAyAHwyvXr2AlvJ4" + "BiuAIQQKAFCW+QckBPg4GHiA7QdgALAAJXmhAQAy5C/D7797wZrYgCW+ArMdciwD5Y6D2lTg" + "8BBmkmVgBbYjGBhA5QgDQABRNwAkfbJYWTgLQ53jGYz19Bi+/4B4/uPHHww3btwF538mJkaG" + "L1++AsXegWOYEGBlZQGnFFD2YQU2loT4gZH/HyjIwMgNzQKQdPTlzzGgFz+DuWKMoA6TFLxx" + "9ObXFUg5ABbhhcqDyhAmgACiXgBIeHoCs2Cfj00Ug62pDbjz9hdYZX379ovh5s27wID4Cazb" + "IVn23bsPwFTwFegxJnAs4x6N+g8sA1ggBSEoOoHlAT8PGzTiGDmg3WJIMrr17RnQk3fBbCFG" + "SWDcy0I7QsDk9/s9MI3cg5Z6TMAAUINWh6wAAUSdABB312H4+2eho0kAu7udDyitgT3/8+cf" + "htu37wFbfV+BBRoLsF/PAhb/8OE9w69fv4Et47/AgPgJGZ1lYcFSEEI6SeDwAXJYmZkY+ID9" + "AnCJzsgCysOs8FT88e9vYHvgOjikuIHJW4hRBd4TfPX7D7DvcB9uMD+DBLSM4AQIIMoDQMxJ" + "iuHPjxVGWi6iAS6RDKxskGrrz5+/DHfu3AUWgJ/AMQjq5XFxsYDzMygL/PvHBmwMfWU4d+4q" + "w549B4G1wktogYc2bM3CCPYDpMcIbBsAG0QM//4Ckw0zOzQAGOHJ5T/DbWgsMwObQ0rQmoIV" + "2qt6ADeUB1yAgmsRgABiIdnDInbsDP//ygN9YAJ0iAnDz2/uqqr2WpE+GQw8vBxgDzICq+RH" + "jx5BY54dWv0xgzGoTADFvqCgGBALA9l/Ga5du8CwfPkqhrS0RAY9PT2M7gqo3ACZAaLZgS1h" + "oP2wIX0WlO7w339P4GxeBlGkqvIXMHCew+U4GLihhSA7QAARDgBBEyGg7XrAtGsMdIIJMCgN" + "2Nl5FIUEpNnFBGUZpMTkGTwcfRj4wY0zUIz9Z3jw4DnQ89+BLTlucP4GBQrI86B2/x9w2QCq" + "4zkZ+PgEGKytLRl8fDwY2tsbGVasWM2gpqYGVMsJj1RQ8of1CUApiQMUAP+AAcDIBPM8cgHy" + "HDpszgj0Ij80C7BBjXoDV8UOLj9ABSQrQAChBoCAARPQtWoM//6YAZOMMQMruyELK4eWAK+E" + "oJiwApO4iAKDhKgisD6WY+DjFQR6kI9BWoqbQUSUCZicgTYBrXr48B0w2X8HJndOeCkPCgAu" + "LmZwExjE/vnzB7hhY2ZmyODubs0gLMwHDLhfDElJiQxnz55j8PLyhJcBkOoQwmYCVYusTJAA" + "gOR9ZpSa7B+4pP8LThlsDHBPQgPzPTxwWMGBApJnBQggRADw6wLrzf+r+PjEzcVFFDnEgR6V" + "FFVhkBRTYhAUEGfg4eIDeoKLgQXoADZgXc7KBoptYI4Adj1+/waWO9zANPb8E7CA+waOQVBy" + "hdXloIIPlP/BTdq/kFYdBweoyysE7BO8BvYJfjK4urowqKurM5w4cQIYKG7A6o+VAWPWChwQ" + "/yBVOrgkxBjl+cTAAA0AFrAn2eFtAWDzAx4AzOBAA9cgAAGECIBf38LNTMPtfV0LwD0xLk5e" + "cAEESn1gzALxMCgWQc3Uv0Cf/Pz5F1jNsTA8efIVGOu/wfkZ5DGYg2E0SD8rKzPY8//+gfT9" + "Aifrd+8+AWsGSI0gLS3BYG5uzrBp0zqgmV+RsgF61fAPVgYwYAQAwpOQghDiSWgyBLYRIKmD" + "CWlakBEggFiQNFspyeszSEmIgpWAPApyPwT/Bzv8+/d/4Krt+/c/0MIO5DEmoOf/Aj3HCI41" + "dM9DkjIjuASHdW0h2QLYT3n9BpgK+MBsHh5eBgkJKWAD6SPQ/B8o5iCbBXILMIvCkgLqSAIL" + "4z8G1NEFJnggMWGdUmMECECGFe0ACIJA1HqLpo/9/yf25JoWB25hPTs2OY7jYHHG++CtKLUR" + "gmrWeqlggbJ6mhonqij6Y1WNImpJmLGSH+Pzh00EMQZ7f9FGiwAA5l1aKOvqm3NRc3TK8uBd" + "ooFgoIEtFPqgwiepqJS3wEZtektikcP9896PAEI4+/9fJhZQPcsNCYCvX/8AA+Af2KGgIWuQ" + "IGqDjRE8jvf7NyNGIwZbAICUgNrzIE+AAhIkDvLM8+evwV1iMTFhcPcXpPU3qFBB6hWC9IGy" + "DEgvKPsA/Q40BJQMwJ78h9Rw5AP3CBkgXSCo/H+oQYg5gr9wPf8BAgjh8n9/vjMCQxZcmwGV" + "vX3LBI5hSBZghDsa4TEGcGyBqjXkTg1utYzgbAQJODawpyDd3L9AM/6APffhw0cwn4eHhwFz" + "7RJQ/39YAPwGRdgvFA9CLBKA++knw0/wiBEsgJgY+aEFJ6hV8Bs63f4fIIBYkMbtHnz/8QnY" + "OAGqBfrn0SMmcDkAK83RYxjZk7h6dTB1IL+A/AsqBEHdYVDAQcT/gWlQjIOaxU+ePAGnAl5e" + "XgZsi7f+AbPit2/fgc7+9R8aAH9QUgAjsA8Ai+Wv4Fnkn/B1Bf8ZheFh9ev/T3AwAJ0EEECI" + "jPbn+4NPn14zCAJbyNLA3jI7OxNKZwWEQfkSmQ0pFxgw1KCrg+RnJmCShzSCmJkh4/6w2AeN" + "D3z48Inh4sULDIqKiuAGFCiFwBIRKHWA4uE3UP2nL19AKeAv1HO/UQKAgVEOqUL8CF1P8Bta" + "PkjB5b6Bxb+D5AACCBEA//88fPP2CbCpycAgKgqqtxnBpTey5zBLd0jtgK4G23oDUECBRoL+" + "/PkHLjTBgxx/f4Pxb2Bf5eHDxwyXLp1jsLS0BDao2KApgBEayJAq5w/Q3x8/gQLgO6ga+AaN" + "RaQUwKAMzeN/GF4zvAKyPkPVgPTLI80afIYFDkAAMSHVAjcfPbr+5+17SPMTXBji6KKC+x3g" + "tsAfcDcXnzqEWlAVCinQWFkhY5J//vwGY5D8/v07wENg1tZWQHU/UcwB6QUF6G9gann/Hhix" + "/3/8hnoAEQBhIsAYYNAEZ4BvQA9+/A8KgPfglBImDIodRbiR7xneQRtNPwECCKmu+Xf32fPr" + "rx49/ADpMPH8B+dLUAyDPArBv8FJFuRoSOz9Ag9sgtiQEh6k/g8Yg5I3TB+ID4rlHz/+Q8f6" + "uIDZgAUsB8pmd+5cYTh6dAdDSEgwg5CQMFgvYnL0H7y8+QLM/5+BPUmGf6CSEJzEf8AD4BeD" + "GDCfaIAD/Q2wSfwX3Pb/AM4C/4E9AybwGABI9T+Gl/9fQPX/BAggRCH499unn19fXDtz9oKU" + "j48jAz//X7AHf/36jxHzkPLpP9hjX79+gHqIDWmQE9HggdD/wbXF16//gR4ElQmswJh8Aw6E" + "Bw/uMNy4cZ7BycmBwdbWFhz7sGYwKCWCsgxkXICJ4eWr95DU8Q801gSOwR/QmgA0XG4OjH1I" + "j+zpv2dAEpYFgJYzajKw/RcBp44vwMLx3X9Qp+ktqBwACCDkChwYNp9OnTh5wOXbN0dgvQzK" + "f9/AyRbV8wg2KMZBAcDBwQssvbnhVRtCDQM8UH79ArZFP4N6g+xA9TzAztMzoN6PQH3sDB4e" + "zgwmJibgmEct/RnBqQQkxgKsaV68fMPw5wcwBfz/+Q3qOUQKYGB0hlR//78yPAQPfjyDqgEG" + "EaM1pIEENPvVP6Ah4MABZYNfAAGE3oLZc/bczorLlwuZzM0FgDHxDdhe/wVu9UE89x/eMIH1" + "K75//8Tw6dMroBpJqGNhKeAfSmD9+QOq51mBAQHspbBxMsjIyALNEWCQlZVnEBcXg7YFMIfJ" + "QVkHHAAszAxPngHd/Q2UBX5/QQqA/wwBUqCRUzdwDD//94jhx3/QuMBTaDkBcqYdYg3Bv8fQ" + "bjMoe/wHCCC08YB/Z968vHhr7dqdGubm4QxycowM9+69ByZxRjQPQVp0kFbbT2D7/RWwzBAE" + "F4iQZvN/cMQgpxjQCNGbN2zAFMUFzAJswGavODBwP4M9DfIkroIUJgfS/+gpMOv+/QE0+M8H" + "cGKGVIVARzDaAbu4GiBrGG78ugkUeQDNAn8YvCWEGJj+WUOqv/+fGR7/uwMNHHDqAAggFrSe" + "FjB4f65evmJKrY+PJTCWOIEF1zsg/gsNgH+Qwg5U+oMLPlA9/gucdP/9A/XVORjYOdjh6mCB" + "AAosiEcZgcke2N9gBbX7JYABchPvWAys6csGLBO+AbP9vfvAyGMEFgL//72HlgG/oPk/CRz7" + "r37fYnj1FzT4eQdaA4Ci3wkoJ8YA6kQ9/vsU2Ah6BA0AUDuAASCA0EeEgPUN07wnj09GR8eE" + "KokIizN8+fIN2AD5DS3NISX7P6RW3L//4AD5z87Ox6isaM8gJ6sHLED5wY0fkHpYloEEyl+G" + "ly/FgMmeFxgA0tA+Bm4Ain1QKxHUPQe54+6Dx6Aq8Ds0dj+BY9hdUZmB8U8g0PBvDBe+nweK" + "gcYF78M8CGwBhkPKgf+/GG79ug6VewVrIQIEEJah2L/AwuNfzpPHpxqePAa3nhihBQ2sc/EH" + "CwbFBP/bd7c1nr+0YFeStwA2qSWgkxogz0NS0I8fv4DNXREGKSkpcACwsnLinB4DBSBoxBiU" + "pUBzA7fv3WN49xZUcP8AefwFNACA9TJjObBnz8lw78c2hg9/QLF/GYhfg/OPu5wCA9NfD0je" + "B8p9ACf/O9D8DwYAAYRtTBDU2zgCpHOA2Bw6gfAP2qT8jRQQsLY4TIzh7893hg/u7Y56+/a2" + "vLycBYOYsCKwe80Ob/eDqrBbt1gZdHW1gO19CWDM8uMMAJCeb99+QCdEWBmuXLvN8O8L0N3/" + "foFK7zfgAHDQMGRg/J3K8PH3EYbLny5APX8HKfaTgdHHw/AbWDNc/n4JKALKc4/gZQcQAAQQ" + "rkFRUAFzFZpXYG1CWNcThtH5IHAK2E4/9PnDnexrX1+6vhHVZJcU1wamBG54Frh9+zMw79sB" + "xfiBgSADFHuMtRMFKvRAA6ugUeVfv38xXLxyDVQAAgP9zytwDAvyAqsHhjkMP/+cYDj5age0" + "2jsPrd//MzgqigCpVLCBd76dZfj8F5Q1rkADD17XAgQQC552LKzDwAifasa+UBlZ7D2kfv3/" + "+N/vTydfPD+b/OnzUwVxUU0GXh5xYFXGAfTUL2DL7w6Dvr4NsOutAKwJHmFJ/ozANsNXYJX5" + "BzwO+ebtB4YLl4ABwPQTWG0wPAEq+MigppjP8OP7dYazj3cy/AH3s0Gefwzv/TEwFwPLBnGG" + "978uMVz/CkodF6D5H6XtDhBAhCZG/qPF9n8sGLUQhVQvoNCeB6yuMr59frrlwaOjP588PQNs" + "LzwBeuoLw82bN8DZgZcXNL3AARnmQop9UL4HjReCjGcH9s7OX7zC8Ob5M1AD6A24ihMUBCaP" + "H6cYTt6eAPQ8qE4/A036EM/ZqWsBDSpj+PX3DsPpdweBIsDQY7gIbfyguBkggEifGCEO/IIW" + "VMDA+P/k/59vJ9+9u5385etrBX4+KYbLl78wGBpaAQNADuhOYfDQGyjWId1nRmAWgYwL8vHy" + "gKvCg0eOAUuaz6Dk/xScLd++vQXE36Dl0yNosod43loHWPL+XQzMQ7cZzr/cyPATVKgDsyZK" + "6kAAgACi5RIZtNTwN+PXj3ebX7+99eP+g2MMBw+uApbuPMBAUAf2C74BPfwb3J549eoDw+vX" + "H8AdAVCf4OHDRwzHjwPdz/jnPTQJP4XWAJ+g7Jdwz5sasjL8YWoCNlLeAbPGZIbPv0C1wglo" + "6viBzZEAAcTCQHuAkhqAVcWx339/ph48tFBJRsaAQUnJApgCbjO8ePERWOpD5gtAQ2JMoPkL" + "YDW6dccuhq/vXwCz4G9QDN6CFnaIgQ5k8BfY5f39+ybDhVvboJOfj6Ce/4LLcQABRO8NE6Bu" + "HmjODrROJ5uZhcPD3DyJQ1/PBJgSnoAHQnh4uMFYRFiI4fnL5ww1dQ0MXz+9Acby3z1APWuB" + "+Ah6SY6YqBVjByYhPujUN6zB9IMBzy4TgAAaiB0jjNC1u6D5e9CqrVRRMQ0lTw83Bg0NFXCn" + "R0hIEFww9vb3MVy7cg40CAgq5LYA8Q5oXf4Tj9mwNQO/GIjYZwQQQAO5ZYYVuqYPtMy1ipeX" + "39HTK5BBV0cPWB58Zdi4eR3D1cvnQR4FNV8PAfFWID6LrSSnBAAEEMpszQAARugMri64oAQW" + "aJycXL+YmFl/QJMvaG3PNCAOgq7vY6W2AwACaLDsGmOHrtwCdVstoAXYZ2i39iK0Hn8OTfpU" + "jS2AABo82+Ygk5WgBQ3iSAsZP0JTwkdonqZ6UgUIoMEUALAswQybuUXqff6jlYUAAcQ40rfP" + "AwQYAE5pjFBtR4nAAAAAAElFTkSuQmCC") +index.append('amarok') +catalog['amarok'] = amarok + +#---------------------------------------------------------------------- +amor = PyEmbeddedImage( + "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" + "0Rvi9O4K3N8AAAAASUVORK5CYII=") +index.append('amor') +catalog['amor'] = amor + +#---------------------------------------------------------------------- +applixware = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAABGdBTUEAAK/INwWK6QAAABl0" + "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAApnSURBVHjaYvz//z/DSAYAAcTE" + "MMIBQACN+AAACKARHwAAAcQAKgOwYTqBVCB+C8QfgLgHiMWAmJWe/gUIoIEMAA4gvigiIvJf" + "VVUVZOE7II6EBgIjvQIAIIAGMgv4A7Geq6srQ3h4OAMjI6MgkB8GxNJAzEIvRwAE0EAGQLqy" + "sjKDpaUlg4SEBAMwFYDEzIFYEYh56eUIgAAaqABwBGIHCwsLBiYmiBNMTExAlAQQuwCxKL3c" + "BhBAAxUAWeLi4owaGhoM3759A2N1dXUGYWFhUN63BWI5IOaih0MAAmggAkAfiL2NjY0ZODk5" + "GX79+gXGXFxcDHp6eiB5UF4AJQchWhaGMAAQQAMRAKl8fHycurq6DD9+/GD4+/cvGIMCASTG" + "xsbGDlTjBi0M2WjtGIAAoncAgJJ2OMijvLy8DD9//mT48+cPGIPYwCoRVhiCUokGEPPT2kEA" + "AUTvAEhiZ2cXASV1mOdBsQ+if//+DWaDAgcIQFWiK7RQpGmVCBBA9AwAUJ6OBxV2goKC8OT/" + "/ft3sOdBgQBiy8jIgKtFILAEYnkg5qGlowACiJ4BEAms8hR0dHTgyf7fv38MR44cYXj69ClY" + "ASggWFhYGLS0tEBcWSC2A2JhWhaGAAFErwAAFWbJ8vLyDKKiouDYB4EnT54wnD59muHevXvg" + "wAAFCkhOSUmJgZubmxmoxAkaEJy0chhAANErAHyB2BAUs6D2NyimQR6+ceMGWPLu3bsMX79+" + "BWcJUNkAqhJBrURoQagPLRNokgoAAoheAZAJbPgwSElJgT0ICoSPHz8y3LlzByT3582bN/9B" + "qQEEYIWiiooKqJUIagy5A7EkrXqJAAFEjwCwBzV9QYUfMzMzOPZBAXD//n2GL1++gORvAvEn" + "EB/meVAgCQkJgQMMCIyBWIlW/QOAAKJHAGTw8/MzgUp3WMkP8iA09kFd4FNAfPnhw4cMnz59" + "AmcNWCBBs4EYtGEEopmp7TiAAKJ1AOgAsR+oUGNlZQW39kAefPXqFcPz58/B5SAQ3wbi9cDU" + "AM4GII/DCkNQdQhsNYLU2UCrRKr3DwACiNYBkAps73PJycmhNHygpf5PoDyoFAQlhY2ggACl" + "AlAgwRpGoCoRVHNAs4AFLapEgACiZQDIgOp+WVlZBg4ODrDHQJ4H5fvHjx+D5F8A8T0gfgjE" + "oOSw/cWLFwwfPnyAV4mgQANlHWD/gBXaTZaGjiRRDQAEEC0DIAEYg6KgAIDFKih5P3v2DFTl" + "/Yd6/gHU89+BeDVQ3S9QowiWDUD6QD1GUA0CBKA2sja1+wcAAUSrAAA5MgGUh0F1OigmYT2+" + "R48egeQ/QpM/KBDeg4bqgPgcEJ8HBRCssIRlBWlpUMQz8CH1D6hWJQIEEK0CIIKRkVEZ5HBY" + "sxfkoXfv3jEA63yQ/GMk/A2qB9Q83AxS8/79e3gAgAINVBCC+g/QckABiLmp5VCAAKJFAIB6" + "b8nCwsIMPDw88MIPlK9BJT+Q/oUU+6DQ+AfVB0oFG4Hyn0BlAawcAKUA8FgZpIMEahg4UHPI" + "DCCAaBEA3kBsCnIwzBOg2AQ1dUEeA4KXSPn/M5peUJV4FFRNgnqGyA0jUAoAFqZM0ACQo1b/" + "ACCAaBEAWaDBDlCyhRV+oIAAJX2Qp9AKv19oekH8DaCaApQNkFMBqBUJSlXQ/oE1tapEgACi" + "dgCAGizOoB4fuJEPjX2QB0CxilT43Ucq/JABiL8dVEWCAgw2XAZLCaDmMbB/ABoyA02gKFKj" + "YQQQQNQMAFDJ3ABMpszApi9K7H/+/Bnc+YEWeqB6/xFS4YcOQCljL6gwBI0WIxeGoPYEyGwg" + "UGGADK2LUpoKAAKImgEAihVnUF4F1gDwUR6QB96+fQsr/G5CYx9U+P3FYc4fIF4D9PB/UKMI" + "FgAwswQEBGAFrTt0rICihhFAAFErAECxkAZquiLnfdiQFyg2gQCUB+5C8/8nAuYdAOJboHIA" + "5nlYYQhqV4DKGGg/A9Q4EqAkFQAEELUCwANUMIE8D5rpQY59UA8PFCBozd5fBMwD1Q7bQIUh" + "cjaAZSlQWQAdK6R44BQggKgVAJnA9jo4ecI8Dyu9QckYWvhdhwbCOyyFHzoAZY+1QI//BAUg" + "cgCAAhOU0kBNZCAwY6BwLhEggKgRACBHuIMaPbDhLuTkD4pBIHgKLQDxFX7oANw0BhWgsCyF" + "nAq4ucGNQdBIkTMlDSOAAKJGAKQCY4QNVEIjxz4IgxwPDJTf0MIPFPuv8RR+6ADcNAble+S+" + "ASwVgFIc0F5G6Mgx2XOJAAFEaQCA+ukhIM8jxz7MkdDYhxV+D4ko/NDbBBuA5n4EtSKRAxbW" + "s2RnBzUJKJtLBAggSgMgBVjlCYBGe5A9D0v+IDZSy+8pEYUfOgAF3FFQCkBPXSA+yF6g/ezQ" + "wpCsuUSAAKIkAEBjdLEgR6DHPogNHfv/jNTxIabwY8DSNF4PGyJDzgawThKoQAQCAyBWJ2es" + "ACCAKJl3iwaGvgzIATDHwNMudEADqdVHSuGHng02gwpQYJaSxWh8ABtc0JFm2FziWWhA/yHW" + "AoAAIjcAQHVQMsgBoBIZoykHyaMgx/9GKqlNyQwAkBkvgWbKgtoYIDsxkjFQHOgOK+hYAai2" + "+UCsBQABRG4ABIKGp0COgcY0aiX+9y+sdWgIxZSC/7BUhS0AoEAW2hm7Bm13EJXdAAKI3ABI" + "wxX7yMmTigBsGD77GCBzBs7Q3uRzYrMcQACRUwiCJinsGQYZgAa4JgOJc4kAAUROAGRQOXap" + "CbigEUT0XCJAAJGaBYyA2JNAZqVXbGMVB9oPm0sEdbvfEjILIIBIDYA0fP1vqOdfQxswv6HV" + "EbWSy3+oe00JjAGAJhFAkyiXobUB3qY3QACREgCgKiaUiOQPGtjcC+39faNBAigCBrQdAXeA" + "+gfrGCBzj5/xKQQIIFICIAna3sYX+5+g1RCoQXIKGgDULjBEoR7Elw0Uob1UUCR8wVclAgQQ" + "savFRUCtOqDh/3FhqCXngbiKATKFxUyjIoAPGsCE3HIYOnrMgc+/AAFEbC0QBe1y4gMfoH14" + "UNv/BQndXlLBVyCeSUQhCZtLFMCnFiCAiAkADlizl0Dyfwwt/G5BW2K0An+h/YMnBNTxQwtD" + "vENmAAFETACAFjjpEdFruwkNgBekdEbIBKCaZge+KhcaYaC5RLxrDQECiJgAyCQi9pFHfD/T" + "ocEDHjonIpuBxggc8Q2ZAQQQoQAAr+snwkGwEd8XZAx6kAuOAPEVIlq69gx45hIBAoiJiNgn" + "VI3BRnzvkznoQS4ATTRuJSIbqEMHTLD2DwACiIlAs9eXiGYvOSO+1AD/oNngKxFjF564hswA" + "AghfQygO1JyFjuqyYAk9Rmhz9yo0/5My4kstAGp07QW60RW524wlklWh2QC0IOsnsiRAADHi" + "SkLA5MMPHcwwhrYA/+Nonz8D4mPQ+v8nvXvB0Ji1gnaF2bC4kxGaSkB9g5NA/75ClgQIIHwB" + "wAb1OD80BeAKgG/QXtdXOuZ/ZMCO5E4mPNkFVDu9Bfr3B7IEQAAxjvTd4wABNOL3DgMEGAAt" + "pUQRZvTA4wAAAABJRU5ErkJggg==") +index.append('applixware') +catalog['applixware'] = applixware + +#---------------------------------------------------------------------- +ark = PyEmbeddedImage( + "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") +index.append('ark') +catalog['ark'] = ark + + +class TestFrame(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent, -1, + "UltimateListCtrl in wx.LC_ICON mode", + size=(600, 400)) + + # load some images into an image list + il = wx.ImageList(64, 64, True) + imgs = catalog.keys() + imgs.sort() + + for img in imgs: + bmp = catalog[img].GetBitmap() + il_max = il.Add(bmp) + + # create the list control + self.list = ULC.UltimateListCtrl(self, -1, + agwStyle=wx.LC_ICON | wx.LC_AUTOARRANGE | + ULC.ULC_HEADER_IN_ALL_VIEWS) + + # assign the image list to it + self.list.AssignImageList(il, wx.IMAGE_LIST_NORMAL) + + info = ULC.UltimateListItem() + info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT + info._format = 0 + info._text = "Artist\nName" + + self.list.InsertColumnInfo(0, info) + + info = ULC.UltimateListItem() + info._format = wx.LIST_FORMAT_RIGHT + info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT + info._text = "Title" + + self.list.InsertColumnInfo(1, info) + + info = ULC.UltimateListItem() + info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT + info._format = 0 + info._text = "Genre" + + self.list.InsertColumnInfo(2, info) + + for i in xrange(3): + self.list.SetColumnWidth(i, 130) + + # create some items for the list + for x in range(25): + img = x % (il_max+1) + text = "%02d" % x + self.list.InsertImageStringItem(x, text, img) + + self.SetIcon(images.Mondrian.GetIcon()) + self.Show() + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.App(0) + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + diff --git a/demo/agw/UltimateListListDemo.py b/demo/agw/UltimateListListDemo.py new file mode 100644 index 00000000..342d640d --- /dev/null +++ b/demo/agw/UltimateListListDemo.py @@ -0,0 +1,124 @@ +import wx +import os, sys +import random +import images + +from wx.lib.embeddedimage import PyEmbeddedImage + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import ultimatelistctrl as ULC +except ImportError: # if it's not there locally, try the wxPython lib. + from wx.lib.agw import ultimatelistctrl as ULC + + +catalog = {} +index = [] + +smicon01 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAB3RJTUUH1AgHFicMIwSmbQAA" + "AAlwSFlzAAALEwAACxMBAJqcGAAAAARnQU1BAACxjwv8YQUAAACZSURBVHjapZMBDsAQDEVX" + "cTA3w816MyPSaqXG4ie1Neb5rQFEfG7k2xBCKNZkhcMO4OillKLiC2wCLDXQDuJlAgC8sOe5" + "jqlCUEEQA5emHEj74xlV9NIG0M0OZKxLiwwxHUgnEjzyzE7MHgwlVQ7tLkG/HFjluZOPZrCE" + "+34s9h9HjbIaShD/HEjuOGsLoI4v529vo7taXfUCVHt4TiSsPYMAAAAASUVORK5CYII=") +index.append('smicon01') +catalog['smicon01'] = smicon01 + +#---------------------------------------------------------------------- +smicon02 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAB3RJTUUH1AgHFiYzjHm6EQAA" + "AAlwSFlzAAAewgAAHsIBbtB1PgAAAARnQU1BAACxjwv8YQUAAABjSURBVHja7ZPRCsAgCEV3" + "Y///y2ZjgrSrxXztQtSDHg9REJGrktsOAFKSDkIKeItos8KfAQzSWLHfPZxZfgBmMds4sKQA" + "ZjBgtn4bRFkaRHeybbAyOgbTU46mZEH1N7ZSt6YD1C9PHbDZOYgAAAAASUVORK5CYII=") +index.append('smicon02') +catalog['smicon02'] = smicon02 + +#---------------------------------------------------------------------- +smicon03 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAB3RJTUUH1AgHFiYeyabmZAAA" + "AAlwSFlzAAALEwAACxMBAJqcGAAAAARnQU1BAACxjwv8YQUAAABcSURBVHja7ZNLCgAgCEQb" + "6f5XtjaBmZ/IbQOhSI3PQDBzq6ivBEDoNBvBqtN2yTlRA9IFqCgITJPDgFUUI5okVwR6nCcC" + "TymB9yfXBBnRJxC7EHWJhOo2Uun11ADQZCkbCzp5EwAAAABJRU5ErkJggg==") +index.append('smicon03') +catalog['smicon03'] = smicon03 + +#---------------------------------------------------------------------- +smicon04 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAB3RJTUUH1AgHFiYK03wyGQAA" + "AAlwSFlzAAAewgAAHsIBbtB1PgAAAARnQU1BAACxjwv8YQUAAACISURBVHja5VNtDoAgCIXm" + "vepm4M3wZCQ2Kvua2c/exhAdj/ecoqrCF4R9EWM8sRERPjKYAgtmLksRqfKyr3AXwScTMaQk" + "MI5TlYmmfA6XPou6bfo7WI8ZGGpOzFNTU67uwBUc/T9lV3Cw0Nbsl3si+KkCtOrqCbcgkwD6" + "Z0LELpKVoBfDp+6MGUT4tQ7B0XvcAAAAAElFTkSuQmCC") +index.append('smicon04') +catalog['smicon04'] = smicon04 + +#---------------------------------------------------------------------- +smicon05 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAB3RJTUUH1AgHFiUuxFKFCwAA" + "AAlwSFlzAAALEwAACxMBAJqcGAAAAARnQU1BAACxjwv8YQUAAACQSURBVHja5VPhCsYgCPRG" + "77W9mfVm9mR+OhZMaiPWz0+II+nOSxSqSiuR7pdSSqfGzHhVcAd+cs7uRUUk4Jm/3oxOapU5" + "Z6oitB9HQDYsJjQq7u7SzQrtD8gDshUlALqFLEC11ikMPbj+2f3/DZ3j9CAwS27N7QT+1AGc" + "NhrhmTARQlsmH4ovIljdxm2JbfED/cdja9DB0AMAAAAASUVORK5CYII=") +index.append('smicon05') +catalog['smicon05'] = smicon05 + +#---------------------------------------------------------------------- +smicon06 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAB3RJTUUH1AgHFiUHhuAdZwAA" + "AAlwSFlzAAAuIgAALiIBquLdkgAAAARnQU1BAACxjwv8YQUAAABxSURBVHjatVMBDoAgCJTG" + "/79M4KoRIiEuNnXj5DhPbW0zgAcVap5AmYhyHAAw5DACdcyaHLseYKGGQoLID4vJsX0FH35c" + "bG8FbmcvZ8jxljIQ8eoJ6bgChEBvW31Uf14jy6SsBxFJTUHyb/QetnTVgxOMpSQrnCCj/wAA" + "AABJRU5ErkJggg==") +index.append('smicon06') +catalog['smicon06'] = smicon06 + + +class TestFrame(wx.Frame): + def __init__(self, parent, log): + wx.Frame.__init__(self, parent, -1, + "UltimateListCtrl in wx.LC_LIST mode", + size=(600, 400)) + + # load some images into an image list + il = wx.ImageList(16, 16, True) + imgs = catalog.keys() + imgs.sort() + + for img in imgs: + bmp = catalog[img].GetBitmap() + il_max = il.Add(bmp) + + # create the list control + self.list = ULC.UltimateListCtrl(self, -1, agwStyle=wx.LC_LIST|ULC.ULC_HOT_TRACKING) + self.list.EnableSelectionVista() + + # assign the image list to it + self.list.AssignImageList(il, wx.IMAGE_LIST_SMALL) + + # create some items for the list + for x in range(25): + img = x % (il_max+1) + it_kind = 0 + if random.randint(0, 2) == 2: + it_kind = random.randint(1, 2) + + self.list.InsertImageStringItem(x, "This is item %02d" % x, img, it_kind=it_kind) + + self.SetIcon(images.Mondrian.GetIcon()) + self.Show() + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.App(0) + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + \ No newline at end of file diff --git a/demo/agw/UltimateReportDemo.py b/demo/agw/UltimateReportDemo.py new file mode 100644 index 00000000..cbacfb0b --- /dev/null +++ b/demo/agw/UltimateReportDemo.py @@ -0,0 +1,1141 @@ +import sys +import os +import wx +import random +import datetime +import math +import operator + +import wx.lib.mixins.listctrl as listmix +import wx.lib.colourdb as cdb +import wx.lib.colourselect as csel +import wx.lib.colourutils as cutils + +from wx.lib.embeddedimage import PyEmbeddedImage + +import images + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import ultimatelistctrl as ULC +except ImportError: # if it's not there locally, try the wxPython lib. + from wx.lib.agw import ultimatelistctrl as ULC + +#--------------------------------------------------------------------------- + +musicdata = { +1 : ("Bad English", "The Price Of Love", "Rock", ""), +2 : ("DNA featuring Suzanne Vega", "Tom's Diner", "Rock", ""), +3 : ("George Michael", "Praying For Time", "Rock - HYPERTEXT", ""), +4 : ("Gloria Estefan", "Here We Are", "Rock", ""), +5 : ("Linda Ronstadt", "Don't Know Much", "Rock", ""), +6 : ("Michael Bolton", "How Am I Supposed To Live Without You", "Blues - HYPERTEXT", ""), +7 : ("Paul Young", "Oh Girl", "Rock", ""), +8 : ("Paula Abdul", "Opposites Attract", "Rock", ""), +9 : ("Richard Marx", "Should've Known Better", "Rock", ""), +10: ("Rod Stewart", "Forever Young (DISABLED)", "Rock", ""), +11: ("I am a really long item and I am going into overflow", "", "", ""), +12: ("Sheena Easton", "The Lover In Me", "Rock", ""), +13: ("Sinead O'Connor", "Nothing Compares 2 U", "Rock", ""), +14: ("Stevie B.", "Because I Love You", "Rock", ""), +15: ("Taylor Dayne", "Love Will Lead You Back", "Rock", ""), +16: ("The Bangles", "Eternal Flame", "Rock", ""), +17: ("Wilson Phillips", "Release Me", "Rock", ""), +18: ("Billy Joel", "Blonde Over Blue", "Rock", ""), +19: ("Billy Joel", "Famous Last Words", "Rock", ""), +20: ("Billy Joel", "Lullabye (Goodnight, My Angel)", "Rock", ""), +21: ("Billy Joel", "The River Of Dreams", "Rock", ""), +22: ("Billy Joel", "Two Thousand Years", "Rock", ""), +23: ("Janet Jackson", "Alright", "Rock", ""), +24: ("Janet Jackson", "Black Cat", "Rock", ""), +25: ("Janet Jackson", "Come Back To Me", "Rock", ""), +26: ("Janet Jackson", "Escapade", "Rock", ""), +27: ("Janet Jackson", "Love Will Never Do (Without You)", "Rock", ""), +28: ("Janet Jackson", "Miss You Much", "Rock", ""), +29: ("Janet Jackson", "Rhythm Nation", "Rock", ""), +30: ("Janet Jackson", "State Of The World", "Rock", ""), +31: ("Janet Jackson", "The Knowledge", "Rock", ""), +32: ("Spyro Gyra", "End of Romanticism", "Jazz", ""), +33: ("Spyro Gyra", "Heliopolis", "Jazz", ""), +34: ("Spyro Gyra", "Jubilee", "Jazz", ""), +35: ("Spyro Gyra", "Little Linda", "Jazz", ""), +36: ("Spyro Gyra", "Morning Dance", "Jazz", ""), +37: ("Spyro Gyra", "Song for Lorraine", "Jazz", ""), +38: ("Yes", "Owner Of A Lonely Heart", "Rock", ""), +39: ("Yes", "Rhythm Of Love", "Rock", ""), +40: ("Cusco", "Dream Catcher", "New Age", ""), +41: ("Cusco", "Geronimos Laughter", "New Age", ""), +42: ("Cusco", "Ghost Dance", "New Age", ""), +43: ("Blue Man Group", "Drumbone", "New Age", ""), +44: ("Blue Man Group", "Endless Column", "New Age", ""), +45: ("Blue Man Group", "Klein Mandelbrot", "New Age", ""), +46: ("Kenny G", "Silhouette", "Jazz", ""), +47: ("Sade", "Smooth Operator", "Jazz", ""), +48: ("David Arkenstone", "Papillon (On The Wings Of The Butterfly)", "New Age", ""), +49: ("David Arkenstone", "Stepping Stars", "New Age", ""), +50: ("David Arkenstone", "Carnation Lily Lily Rose", "New Age", ""), +51: ("David Lanz", "Behind The Waterfall", "New Age", ""), +52: ("David Lanz", "Cristofori's Dream", "New Age", ""), +53: ("David Lanz", "Heartsounds", "New Age", ""), +54: ("David Lanz", "Leaves on the Seine", "New Age", ""), +} + +#--------------------------------------------------------------------------- + +_ulcStyles = ["ULC_VRULES", "ULC_HRULES", "ULC_ICON", "ULC_SMALL_ICON", "ULC_LIST", + "ULC_REPORT", "ULC_TILE", "ULC_ALIGN_TOP", "ULC_ALIGN_LEFT", "ULC_AUTOARRANGE", + "ULC_VIRTUAL", "ULC_EDIT_LABELS", "ULC_NO_HEADER", "ULC_NO_SORT_HEADER", + "ULC_SINGLE_SEL", "ULC_SORT_ASCENDING", "ULC_SORT_DESCENDING", + "ULC_NO_HIGHLIGHT", "ULC_STICKY_HIGHLIGHT", "ULC_STICKY_NOSELEVENT", + "ULC_SEND_LEFTCLICK", "ULC_HAS_VARIABLE_ROW_HEIGHT", "ULC_AUTO_CHECK_CHILD", + "ULC_AUTO_TOGGLE_CHILD", "ULC_AUTO_CHECK_PARENT", "ULC_SHOW_TOOLTIPS", + "ULC_HOT_TRACKING", "ULC_BORDER_SELECT", "ULC_TRACK_SELECT", "ULC_HEADER_IN_ALL_VIEWS", + "ULC_NO_FULL_ROW_SELECT", "ULC_FOOTER"] + +#--------------------------------------------------------------------------- + +coloursBitmap = PyEmbeddedImage( + "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") + +#---------------------------------------------------------------------- +decryptedBitmap = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABGdBTUEAAK/INwWK6QAAABl0" + "RVh0U29mdHdhcmUAQWRvYmUgSW1hZ2VSZWFkeXHJZTwAAAUnSURBVHjaYvz//z8DCISGpjLA" + "AEjs9+8/DL9+fefh4uKoVlCQi5KQkBBnYmJifPHi2Ztbt66v+/DhfTMrK/Or////AHUwwvXu" + "3bsXTAMEEAsDDvD79y95WVnpXV5eHmqSknJA/j8GVlYWBh4eLqlXr57mrFq1NPDKlQs+bGws" + "F7DpBwggFuyG/mEBGrrJ399f7f9/NoYdO3b/f/Tozot///7+VVJSl/Lw8GDKzMyXnj69f8Pl" + "yxcM2NnZP6CbARBATDDG338MDP/+/WP48+cPAwcHW7OFhaXez59MQEM3/zp58kDO06cPpB4/" + "vi+7d+/m8IUL537984eJwc8vTJ6fX7Dj798/DIyMjGAMAwABBDeYjfk/w38WLgYmZlYWdjY2" + "75s3b//fu3fb7ydPH7X8Z+Gc9p+ZneEfCycDEyvbmuvXzubt37/7v6KiGoOGhk4o0DF8//4B" + "4+Tvf7jBAAEEN9jo9yEGiX+PGThYmf99+cMWfPX2A/X7z16rMjP8a5X5/5RBiuEFgzzjcwY+" + "pp8Mv/4xLLpy5fyDHz9+MqioaAoyMzPb/wDGoQjzF7jBAAEED2Puv+8YdH/sZnjDJv/vOyPP" + "bYZ/fxmAocPA+f8rg/i/J0A2MwMz0z+Gd0y8DIf+qP159+XrjU+fPikKCokw/mXiUJP6/5rB" + "juMJ3GCAAIIb/O8/I8P3XywMvL8eMPCBjISG139gUvrCwAJmgZIVJ+NHBss/ZxjOf+X/+Pnb" + "X4Zvf1gZRP5/+GvDcoPh/z9OuMEAAQQ3mJ2TvVtaUTSQiQmUjBn/w0MKbgETPL0y/f/9W4Hl" + "gxzrw6UMYj++MYQZM1bz/FfOevH0436gdDpIDUAAMcIyyP4265/2Ee5sIC////sTaNJvIP4F" + "9Aowxpn+M7Cw/QHz//z6xfD/538G5r/AZPnjK1COkYGZDehSdm6GU3vu/LHM38sKMg8ggOAu" + "5mAH5iseQQYmFiGgjrfA9PcJkgYZgIb/fMLw7No1hn+/fzDIKPMBxXgZGL6yMbADLWQAWsAA" + "DBIGRgEGDk5meHoDCCC4wf+BkcXw4zUDAzPQtb/fAzUAY5jpB9DQZwxb5h9gKJrzheEn0BOt" + "MSwMMVEyDAx/eKAWgzQD9TL9Yfj/hwue3gACCJHz/gMV/fkIpIFe/guk/wENZv7B8Pv5I4ZF" + "W78wPHoH5AKVLdr5h8HP6h0DnxTIAVBzQHpAIfefA24cQAAhGfwfajDQ638+QVz8/zsDK9cf" + "BjclJoY7V4G5EqjMXR4YEGzfgb77BTYMkqR+g3IYkBaDGwcQQEwIg0EKvgIxyLWfIfgn0AIB" + "RgZ3O04GVXYGBnmgag9TYNYVAFrxB+hiBhgGBTTI2n9w4wACCGEwKFkxgmL+KwQzfAOGGxB/" + "+8Jw6/hPhn9A/cxAfbfPgPSzMTDwAb3NxQ7B3ECPc7KiFEIAAYSIPJDBTCCDf0AMBWEWoJdv" + "f2QQeP+HIUQD4gzRX/8Z/r1gZGDSARr8AxZXQH0cQMuYEO4ECCAWFBczgILhE9RbQEN/AZ0p" + "wsJgVCXEYMwGzSjAoGVkBRrAAsTcMM3MoPQKch3cOIAAQoo8oEImoKH/XgHVsYJdB9Ygzs3A" + "iEiekLwHCkqkkgwchKzsyBUJA0AAwQ1mBBnEDTQQWLADy0cGkgDItywsKA4ACCAWpNTGyMAt" + "AlQESjbMJBoMTBXMfMCE9QceyAABBDf43vXnp5nnMpswAQv0///+/yfNwSCH/GK6e+X5dWOo" + "GECAAQCxvOh5cbsDqwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- + +PIPE_HEIGHT = 18 +PIPE_WIDTH = 300 + +class UltimateRenderer_1(object): + + DONE_BITMAP = None + REMAINING_BITMAP = None + + def __init__(self, parent): + + self.progressValue = random.randint(1, 99) + + + def DrawSubItem(self, dc, rect, line, highlighted, enabled): + """Draw a custom progress bar using double buffering to prevent flicker""" + + canvas = wx.EmptyBitmap(rect.width, rect.height) + mdc = wx.MemoryDC() + mdc.SelectObject(canvas) + + if highlighted: + mdc.SetBackground(wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_HIGHLIGHT))) + else: + mdc.SetBackground(wx.Brush(wx.SystemSettings_GetColour(wx.SYS_COLOUR_WINDOW))) + mdc.Clear() + + self.DrawProgressBar(mdc, 0, 0, rect.width, rect.height, self.progressValue) + + mdc.SetFont(wx.Font(8, wx.SWISS, wx.NORMAL, wx.BOLD)) + text = "%d Mb"%self.progressValue + textWidth, dummy = mdc.GetTextExtent(text) + mdc.DrawText(text, rect.width/2 - textWidth/2, rect.height/2 - dummy/2) + dc.SetClippingRegion(rect.x, rect.y, rect.width, rect.height) + dc.Blit(rect.x+3, rect.y, rect.width-6, rect.height, mdc, 0, 0) + dc.DestroyClippingRegion() + + + def GetLineHeight(self): + + return PIPE_HEIGHT + 6 + + + def GetSubItemWidth(self): + + return 130 + + + def UpdateValue(self): + + self.progressValue += 5 + if self.progressValue >= 100: + self.progressValue = 1 + + + def DrawHorizontalPipe(self, dc, x, y, w, colour): + """Draws a horizontal 3D-looking pipe.""" + + for r in range(PIPE_HEIGHT): + red = int(colour.Red() * math.sin((math.pi/PIPE_HEIGHT)*r)) + green = int(colour.Green() * math.sin((math.pi/PIPE_HEIGHT)*r)) + blue = int(colour.Blue() * math.sin((math.pi/PIPE_HEIGHT)*r)) + dc.SetPen(wx.Pen(wx.Colour(red, green, blue))) + dc.DrawLine(x, y+r, x+w, y+r) + + + def DrawProgressBar(self, dc, x, y, w, h, percent): + """ + Draws a progress bar in the (x,y,w,h) box that represents a progress of + 'percent'. The progress bar is only horizontal and it's height is constant + (PIPE_HEIGHT). The 'h' parameter is used to vertically center the progress + bar in the allotted space. + + The drawing is speed-optimized. Two bitmaps are created the first time this + function runs - one for the done (green) part of the progress bar and one for + the remaining (white) part. During normal operation the function just cuts + the necessary part of the two bitmaps and draws them. + """ + + # Create two pipes + if self.DONE_BITMAP is None: + self.DONE_BITMAP = wx.EmptyBitmap(PIPE_WIDTH, PIPE_HEIGHT) + mdc = wx.MemoryDC() + mdc.SelectObject(self.DONE_BITMAP) + self.DrawHorizontalPipe(mdc, 0, 0, PIPE_WIDTH, wx.GREEN) + mdc.SelectObject(wx.NullBitmap) + + self.REMAINING_BITMAP = wx.EmptyBitmap(PIPE_WIDTH, PIPE_HEIGHT) + mdc = wx.MemoryDC() + mdc.SelectObject(self.REMAINING_BITMAP) + self.DrawHorizontalPipe(mdc, 0, 0, PIPE_WIDTH, wx.RED) + self.DrawHorizontalPipe(mdc, 1, 0, PIPE_WIDTH-1, wx.WHITE) + mdc.SelectObject(wx.NullBitmap) + + # Center the progress bar vertically in the box supplied + y = y + (h - PIPE_HEIGHT)/2 + + if percent == 0: + middle = 0 + else: + middle = (w * percent)/100 + + if middle == 0: # not started + bitmap = self.REMAINING_BITMAP.GetSubBitmap((1, 0, w, PIPE_HEIGHT)) + dc.DrawBitmap(bitmap, x, y, False) + elif middle == w: # completed + bitmap = self.DONE_BITMAP.GetSubBitmap((0, 0, w, PIPE_HEIGHT)) + dc.DrawBitmap(bitmap, x, y, False) + else: # in progress + doneBitmap = self.DONE_BITMAP.GetSubBitmap((0, 0, middle, PIPE_HEIGHT)) + dc.DrawBitmap(doneBitmap, x, y, False) + remainingBitmap = self.REMAINING_BITMAP.GetSubBitmap((0, 0, w - middle, PIPE_HEIGHT)) + dc.DrawBitmap(remainingBitmap, x + middle, y, False) + + +class UltimateRenderer_2(object): + + def __init__(self, parent): + + e = wx.FontEnumerator() + e.EnumerateFacenames() + fontList = e.GetFacenames() + fontList.sort() + + rdn = random.randint(0, len(fontList)-1) + randomFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + randomFont.SetFaceName(fontList[rdn]) + + self.randomFont = randomFont + self.text = "This is my renderer" + + dc = wx.ClientDC(parent) + dc.SetFont(self.randomFont) + self.width, self.height, descent, el = dc.GetFullTextExtent(self.text) + + self.height += descent + + + def DrawSubItem(self, dc, rect, line, highlighted, enabled): + + dc.SetBackgroundMode(wx.SOLID) + dc.SetBrush(wx.Brush(wx.BLACK, wx.SOLID)) + dc.SetPen(wx.TRANSPARENT_PEN) + dc.DrawRectangleRect(rect) + + dc.SetBackgroundMode(wx.TRANSPARENT) + dc.SetFont(self.randomFont) + + colours = [wx.RED, wx.WHITE, wx.GREEN, wx.NamedColour("SKY BLUE")] + w, h = dc.GetTextExtent("Hg") + x = rect.x + 1 + y = rect.y + rect.height/2 - h/2 + + for ch in self.text: + dc.SetTextForeground(random.choice(colours)) + dc.DrawText(ch, x, y) + w, h = dc.GetTextExtent(ch) + x = x + w + if x > rect.right - 5: + break + + + def GetLineHeight(self): + + return self.height + 5 + + + def GetSubItemWidth(self): + + return self.width + 5 + + +class UltimateRenderer_3(object): + + def __init__(self): + + cdb.updateColourDB() + colourList = cdb.getColourList() + lenCDB = len(colourList) + colourIndex = random.randint(0, lenCDB-1) + self.colour = colourList[colourIndex] + + + def DrawSubItem(self, dc, rect, line, highlighted, enabled): + + centerX, centerY = rect.width/2, rect.height/2 + dc.GradientFillConcentric(rect, self.colour, wx.WHITE, (centerX, centerY)) + + + def GetLineHeight(self): + + return 30 + + + def GetSubItemWidth(self): + + return 40 + + +class UltimateHeaderRenderer(object): + + def __init__(self, parent): + self._hover = False + self._pressed = False + + def DrawHeaderButton(self, dc, rect, flags): + + self._hover = False + self._pressed = False + + color = wx.Colour(150,150,150) + if flags & wx.CONTROL_DISABLED: + color = wx.Colour(wx.WHITE) + elif flags & wx.CONTROL_SELECTED: + color = wx.Colour(wx.BLUE) + + if flags & wx.CONTROL_PRESSED: + self._pressed = True + color = cutils.AdjustColour(color,-50) + elif flags & wx.CONTROL_CURRENT: + self._hover = True + color = cutils.AdjustColour(color,50) + + dc.SetBrush(wx.Brush(color, wx.SOLID)) + dc.SetBackgroundMode(wx.SOLID) + dc.SetPen(wx.TRANSPARENT_PEN) + dc.DrawRectangleRect(rect) + + dc.SetBackgroundMode(wx.TRANSPARENT) + + + def GetForegroundColour(self): + + if self._hover: + return wx.Colour(30,30,30) + else: + return wx.Colour(230,230,230) + + + +class TestUltimateListCtrl(ULC.UltimateListCtrl): + + def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition, size=wx.DefaultSize, style=0, agwStyle=0): + + ULC.UltimateListCtrl.__init__(self, parent, id, pos, size, style, agwStyle) +## listmix.TextEditMixin.__init__(self) + + +class UltimateListCtrlPanel(wx.Panel, listmix.ColumnSorterMixin): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS|wx.SUNKEN_BORDER) + + sizer = wx.BoxSizer(wx.VERTICAL) + + cdb.updateColourDB() + self.colourList = cdb.getColourList() + self.count = 0 + self.log = log + + self.il = ULC.PyImageList(16, 16) + + self.idx1 = self.il.Add(images.Smiles.GetBitmap()) + self.sm_up = self.il.Add(images.SmallUpArrow.GetBitmap()) + self.sm_dn = self.il.Add(images.SmallDnArrow.GetBitmap()) + self.il.Add(images.core.GetBitmap()) + self.il.Add(images.custom.GetBitmap()) + self.il.Add(images.exit.GetBitmap()) + self.il.Add(images.expansion.GetBitmap()) + self.il.Add(decryptedBitmap.GetBitmap()) + self.il.Add(coloursBitmap.GetBitmap()) + + self.list = TestUltimateListCtrl(self, -1, + agwStyle=wx.LC_REPORT + #| wx.BORDER_SUNKEN + | wx.BORDER_NONE + | wx.LC_EDIT_LABELS + #| wx.LC_SORT_ASCENDING + #| wx.LC_NO_HEADER + | wx.LC_VRULES + | wx.LC_HRULES + #| wx.LC_SINGLE_SEL + | ULC.ULC_HAS_VARIABLE_ROW_HEIGHT) + + self.list.SetImageList(self.il, wx.IMAGE_LIST_SMALL) + sizer.Add(self.list, 1, wx.EXPAND) + + self.timer = wx.Timer(self, wx.ID_ANY) + + self.PopulateList() + self.SetSizer(sizer) + self.SetAutoLayout(True) + + self.itemDataMap = musicdata +## listmix.ColumnSorterMixin.__init__(self, 4) + + self.Bind(ULC.EVT_LIST_ITEM_SELECTED, self.OnItemSelected, self.list) + self.Bind(ULC.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected, self.list) + self.Bind(ULC.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated, self.list) + self.Bind(ULC.EVT_LIST_DELETE_ITEM, self.OnItemDelete, self.list) + self.Bind(ULC.EVT_LIST_COL_CLICK, self.OnColClick, self.list) + self.Bind(ULC.EVT_LIST_COL_RIGHT_CLICK, self.OnColRightClick, self.list) + self.Bind(ULC.EVT_LIST_COL_BEGIN_DRAG, self.OnColBeginDrag, self.list) + self.Bind(ULC.EVT_LIST_COL_DRAGGING, self.OnColDragging, self.list) + self.Bind(ULC.EVT_LIST_COL_END_DRAG, self.OnColEndDrag, self.list) + self.Bind(ULC.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list) + self.Bind(ULC.EVT_LIST_BEGIN_DRAG, self.OnBeginDrag) + self.Bind(ULC.EVT_LIST_END_DRAG, self.OnEndDrag) + + self.list.Bind(wx.EVT_LEFT_DCLICK, self.OnDoubleClick) + self.list.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown) + + # for wxMSW + self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightClick) + + # for wxGTK + self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightClick) + + self.Bind(wx.EVT_IDLE, self.OnIdle) + self.Bind(wx.EVT_TIMER, self.OnTimer) + + + def PopulateList(self): + + self.list.Freeze() + + font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + boldfont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + boldfont.SetWeight(wx.BOLD) + boldfont.SetPointSize(12) + boldfont.SetUnderlined(True) + + info = ULC.UltimateListItem() + info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_CHECK + info._image = [1, 2] + info._format = 0 + info._kind = 1 + info._text = "Artist\nName" + + self.list.InsertColumnInfo(0, info) + + info = ULC.UltimateListItem() + info._format = wx.LIST_FORMAT_RIGHT + info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONT + info._image = [] + info._text = "Title" + info._font = boldfont + + self.list.InsertColumnInfo(1, info) + + info = ULC.UltimateListItem() + info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_IMAGE | wx.LIST_MASK_FORMAT + info._format = 0 + info._text = "Genre" + info._font = font + info._image = [3] + self.list.InsertColumnInfo(2, info) + + info = ULC.UltimateListItem() + info._mask = wx.LIST_MASK_TEXT | wx.LIST_MASK_FORMAT | ULC.ULC_MASK_FONTCOLOUR + info._format = 0 + info._text = "Custom Renderer" + info._colour = wx.RED + + # Add our custom renderer for the header of column 3, we can also use + # SetHeaderCustomRenderer to set the renderer for all the columns. + klass = UltimateHeaderRenderer(self) + info.SetCustomRenderer(klass) + + self.list.InsertColumnInfo(3, info) + + # The custom renderer can also be set for all columns on the header and/or footer + # self.list.SetHeaderCustomRenderer(klass) + + # We must first have a footer in order to set its custom renderer: + # style = self.list.GetAGWWindowStyleFlag() | ULC.ULC_FOOTER + # if self.list.GetAGWWindowStyleFlag() != style: + # self.list.SetAGWWindowStyleFlag(style) + # self.list.SetFooterCustomRenderer(klass) + + items = musicdata.items() + renderers = {} + + for key, data in items: + if key == 3: + index = self.list.InsertImageStringItem(sys.maxint, data[0], [3, 4, 7], it_kind=1) + elif key == 4: + dt = "\n".join(data[0].split()) + index = self.list.InsertImageStringItem(sys.maxint, dt, [self.idx1, 8, 7]) + else: + index = self.list.InsertImageStringItem(sys.maxint, data[0], self.idx1) + + if key == 6: + self.list.SetStringItem(index, 1, data[1], it_kind=1) + elif key == 7: + self.list.SetStringItem(index, 1, data[1], [6, 5, 4]) + elif key == 8: + dt = "\n".join(data[1].split()) + self.list.SetStringItem(index, 1, dt) + else: + self.list.SetStringItem(index, 1, data[1]) + + it_kind = 0 + if random.randint(0, 2) == 2: + # set some radiobutton-like item on the 3rd column + it_kind = 2 + + self.list.SetStringItem(index, 2, data[2], it_kind=it_kind) + self.list.SetStringItem(index, 3, data[3]) + + randomRenderer = random.randint(0, 2) + if randomRenderer == 2: + # set some custom renderers... + klass = UltimateRenderer_1(self) + renderers[index] = klass + self.list.SetItemCustomRenderer(index, 3, klass) + elif randomRenderer == 1: + klass = UltimateRenderer_2(self) + self.list.SetItemCustomRenderer(index, 3, klass) + else: + klass = UltimateRenderer_3() + self.list.SetItemCustomRenderer(index, 3, klass) + + self.list.SetItemData(index, key) + + self.renderers = renderers + + # show how to select an item + self.list.Select(5, True) + + # show how to change the colour of a couple items + item = self.list.GetItem(1) + item.SetTextColour(wx.BLUE) + pyData = datetime.date(2009, 1, 1) + item.SetPyData(pyData) + + self.list.SetItem(item) + item = self.list.GetItem(4) + item.SetTextColour(wx.RED) + pyData = datetime.date(2011, 3, 2) + item.SetPyData(pyData) + self.list.SetItem(item) + + # Disable one item + item = self.list.GetItem(9) + item.Enable(False) + self.list.SetItem(item) + + # Set 2 hypertext items + for ids in [2, 5]: + item = self.list.GetItem(ids, 2) + item.SetHyperText(True) + self.list.SetItem(item) + + # Set 2 items with widgets + item = self.list.GetItem(8, 1) + self.gauge = wx.Gauge(self.list, -1, 50, style=wx.GA_HORIZONTAL|wx.GA_SMOOTH) + self.gauge.SetValue(20) + item.SetWindow(self.gauge) + self.list.SetItem(item) + + item = self.list.GetItem(11, 0) + textctrl = wx.TextCtrl(self.list, -1, "I Am A Simple\nMultiline wx.TexCtrl", style=wx.TE_MULTILINE) + item.SetWindow(textctrl) + self.list.SetItem(item) + + # Put an item with overflow + self.list.SetItemOverFlow(10, 0, True) + + self.currentItem = 0 + + fontMask = ULC.ULC_MASK_FONTCOLOUR|ULC.ULC_MASK_FONT + fullMask = fontMask|ULC.ULC_MASK_BACKCOLOUR + + customRow, customCol, colours = [0, 3], [2, 1], [wx.RED, wx.NamedColour("Yellow")] + + for row, col, colour in zip(customRow, customCol, colours): + item = self.list.GetItem(row, col) + item.SetMask(fullMask) + item.SetTextColour(wx.GREEN) + font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + font.SetWeight(wx.BOLD) + item.SetFont(font) + item.SetBackgroundColour(colour) + self.list.SetItem(item) + + standardFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + italicFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + italicFont.SetStyle(wx.FONTSTYLE_ITALIC) + boldFont = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT) + boldFont.SetWeight(wx.BOLD) + + lenCDB = len(self.colourList) + + for indx in xrange(11, 20): + for col in xrange(self.list.GetColumnCount()): + result = random.randint(0, 2) + colourIndex = random.randint(0, lenCDB-1) + + if result == 0: + fnt = standardFont + elif result == 1: + fnt = boldFont + else: + fnt = italicFont + + item = self.list.GetItem(indx, col) + item.SetMask(fontMask) + item.SetFont(fnt) + item.SetTextColour(wx.TheColourDatabase.FindColour(self.colourList[colourIndex])) + self.list.SetItem(item) + + self.list.SetColumnWidth(0, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(1, wx.LIST_AUTOSIZE) + self.list.SetColumnWidth(2, 100) + self.list.SetColumnWidth(3, 130) + +## self.list.SetColumnShown(1, False) + + self.list.Thaw() + self.list.Update() + + self.timer.Start(300) + +## self.list.EnableSelectionVista(True) +## self.list.SetGradientStyle(1) +## self.list.SetBackgroundImage(wx.Bitmap("splash.png", wx.BITMAP_TYPE_PNG)) + + + def ChangeStyle(self, checks): + + style = 0 + for check in checks: + if check.GetValue() == 1: + style = style | eval("ULC." + check.GetLabel()) + + if self.list.GetAGWWindowStyleFlag() != style: + self.list.SetAGWWindowStyleFlag(style) + + + # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py + def GetListCtrl(self): + return self.list + + # Used by the ColumnSorterMixin, see wx/lib/mixins/listctrl.py + def GetSortImages(self): + return (self.sm_dn, self.sm_up) + + + def OnTimer(self, event): + + for key, renderer in self.renderers.items(): + renderer.UpdateValue() + self.list.RefreshItem(key) + + + def OnIdle(self, event): + + if self.gauge: + try: + if self.gauge.IsEnabled() and self.gauge.IsShown(): + self.count = self.count + 1 + + if self.count >= 50: + self.count = 0 + + self.gauge.SetValue(self.count) + + except: + self.gauge = None + + event.Skip() + + + def OnRightDown(self, event): + x = event.GetX() + y = event.GetY() + + self.log.write("x, y = %s\n" % str((x, y))) + + item, flags = self.list.HitTest((x, y)) + + if item != wx.NOT_FOUND and flags & wx.LIST_HITTEST_ONITEM: + self.list.Select(item) + + event.Skip() + + + def getColumnText(self, index, col): + item = self.list.GetItem(index, col) + return item.GetText() + + + def OnItemSelected(self, event): + self.currentItem = event.m_itemIndex + self.log.write("OnItemSelected: %s, %s, %s, %s\n" %(self.currentItem, + self.list.GetItemText(self.currentItem), + self.getColumnText(self.currentItem, 1), + self.getColumnText(self.currentItem, 2))) + + if self.list.GetPyData(self.currentItem): + self.log.write("PYDATA = %s\n"%repr(self.list.GetPyData(self.currentItem))) + + if self.currentItem == 10: + self.log.write("OnItemSelected: Veto'd selection\n") + #event.Veto() # doesn't work + # this does + self.list.SetItemState(10, 0, wx.LIST_STATE_SELECTED) + + event.Skip() + + + def OnItemDeselected(self, evt): + item = evt.GetItem() + self.log.write("OnItemDeselected: %d\n" % evt.m_itemIndex) + +## # Show how to reselect something we don't want deselected +## if evt.m_itemIndex == 11: +## wx.CallAfter(self.list.SetItemState, 11, wx.LIST_STATE_SELECTED, wx.LIST_STATE_SELECTED) + + + def OnItemActivated(self, event): + self.currentItem = event.m_itemIndex + self.log.write("OnItemActivated: %s\nTopItem: %s\n" %(self.list.GetItemText(self.currentItem), self.list.GetTopItem())) + + def OnBeginEdit(self, event): + self.log.write("OnBeginEdit\n") + event.Allow() + + def OnItemDelete(self, event): + self.log.write("OnItemDelete\n") + + def OnColClick(self, event): + self.log.write("OnColClick: %d\n" % event.GetColumn()) + event.Skip() + + def OnColRightClick(self, event): + item = self.list.GetColumn(event.GetColumn()) + self.log.write("OnColRightClick: %d %s\n" %(event.GetColumn(), (item.GetText(), item.GetAlign(), + item.GetWidth(), item.GetImage()))) + + def OnColBeginDrag(self, event): + self.log.write("OnColBeginDrag\n") + ## Show how to not allow a column to be resized + #if event.GetColumn() == 0: + # event.Veto() + + + def OnColDragging(self, event): + self.log.write("OnColDragging\n") + + def OnColEndDrag(self, event): + self.log.write("OnColEndDrag\n") + + def OnBeginDrag(self, event): + self.log.write("OnBeginDrag\n") + + + def OnEndDrag(self, event): + self.log.write("OnEndDrag\n") + + def OnDoubleClick(self, event): + self.log.write("OnDoubleClick item %s\n" % self.list.GetItemText(self.currentItem)) + event.Skip() + + def OnRightClick(self, event): + self.log.write("OnRightClick %s\n" % self.list.GetItemText(self.currentItem)) + + # only do this part the first time so the events are only bound once + if not hasattr(self, "popupID1"): + self.popupID1 = wx.NewId() + self.popupID2 = wx.NewId() + self.popupID3 = wx.NewId() + self.popupID4 = wx.NewId() + self.popupID5 = wx.NewId() + self.popupID6 = wx.NewId() + + self.Bind(wx.EVT_MENU, self.OnPopupOne, id=self.popupID1) + self.Bind(wx.EVT_MENU, self.OnPopupTwo, id=self.popupID2) + self.Bind(wx.EVT_MENU, self.OnPopupThree, id=self.popupID3) + self.Bind(wx.EVT_MENU, self.OnPopupFour, id=self.popupID4) + self.Bind(wx.EVT_MENU, self.OnPopupFive, id=self.popupID5) + self.Bind(wx.EVT_MENU, self.OnPopupSix, id=self.popupID6) + + # make a menu + menu = wx.Menu() + # add some items + menu.Append(self.popupID1, "FindItem tests") + menu.Append(self.popupID2, "Iterate Selected") + menu.Append(self.popupID3, "ClearAll and repopulate") + menu.Append(self.popupID4, "DeleteAllItems") + menu.Append(self.popupID5, "GetItem") + menu.Append(self.popupID6, "Edit") + + # Popup the menu. If an item is selected then its handler + # will be called before PopupMenu returns. + self.PopupMenu(menu) + menu.Destroy() + + + def OnPopupOne(self, event): + self.log.write("Popup one") + self.log.write("FindItem: %s"%self.list.FindItem(-1, "Roxette")) + self.log.write("FindItemData: %s\n"%self.list.FindItemData(-1, 11)) + + def OnPopupTwo(self, event): + self.log.write("Selected items:") + index = self.list.GetFirstSelected() + + while index != -1: + self.log.write(" %s: %s" % (self.list.GetItemText(index), self.getColumnText(index, 1))) + index = self.list.GetNextSelected(index) + + self.log.write("\n") + + def OnPopupThree(self, event): + self.log.write("Popup three") + self.list.ClearAll() + wx.CallAfter(self.PopulateList) + + + def OnPopupFour(self, event): + self.list.DeleteAllItems() + + def OnPopupFive(self, event): + item = self.list.GetItem(self.currentItem) + self.log.write(("%s, %s, %s")%(item._text, item._itemId, self.list.GetItemData(self.currentItem))) + + def OnPopupSix(self, event): + self.list.EditLabel(self.currentItem) + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent, -1, "UltimateListCtrl in wx.LC_REPORT mode", size=(800, 600)) + + splitter = wx.SplitterWindow(self, -1, style=wx.CLIP_CHILDREN | wx.SP_LIVE_UPDATE | wx.SP_3D) + + self.log = log + # Create the CustomTreeCtrl, using a derived class defined below + self.ulc = UltimateListCtrlPanel(splitter, self.log) + + self.leftpanel = wx.ScrolledWindow(splitter, -1, style=wx.SUNKEN_BORDER) + self.leftpanel.SetScrollRate(20, 20) + width = self.PopulateLeftPanel() + + # add the windows to the splitter and split it. + splitter.SplitVertically(self.leftpanel, self.ulc, width+5) + splitter.SetMinimumPaneSize(width+5) + + sizer = wx.BoxSizer() + sizer.Add(splitter, 1, wx.EXPAND) + self.SetSizer(sizer) + self.SetIcon(images.Mondrian.GetIcon()) + self.CenterOnScreen() + self.Show() + + + def PopulateLeftPanel(self): + + pnl = wx.Panel(self.leftpanel) + mainsizer = wx.BoxSizer(wx.VERTICAL) + + staticboxstyles = wx.StaticBox(pnl, -1, "UltimateListCtrl Styles") + stylesizer = wx.StaticBoxSizer(staticboxstyles, wx.VERTICAL) + staticboxthemes = wx.StaticBox(pnl, -1, "UltimateListCtrl Themes/Gradients") + themessizer = wx.StaticBoxSizer(staticboxthemes, wx.VERTICAL) + + self.ulcstyles = [] + sorted_styles = [] + + for style in _ulcStyles: + sorted_styles.append((style, eval("ULC." + style))) + + sorted_styles.sort(key=operator.itemgetter(1)) + + count = 0 + for styleName, styleVal in sorted_styles: + + if styleName in ["ULC_VIRTUAL", "ULC_TILE", "ULC_LIST", "ULC_ICON", + "ULC_SMALL_ICON", "ULC_AUTOARRANGE"]: + continue + + if "SORT" in styleName or "ALIGN" in styleName or "VIEWS" in styleName: + continue + + if count == 0: + tags = wx.ALL + else: + tags = wx.LEFT|wx.RIGHT|wx.BOTTOM + + check = wx.CheckBox(pnl, -1, styleName) + stylesizer.Add(check, 0, tags, 3) + + if self.ulc.list.HasAGWFlag(styleVal): + check.SetValue(1) + else: + check.SetValue(0) + + if styleName in ["ULC_HAS_VARIABLE_ROW_HEIGHT", "ULC_REPORT"]: + check.SetValue(1) + check.Enable(False) + + check.Bind(wx.EVT_CHECKBOX, self.OnCheckStyle) + self.ulcstyles.append(check) + count += 1 + + sizera = wx.BoxSizer(wx.HORIZONTAL) + self.checknormal = wx.CheckBox(pnl, -1, "Standard Colours") + self.checknormal.Bind(wx.EVT_CHECKBOX, self.OnCheckNormal) + sizera.Add(self.checknormal, 0, wx.ALL, 3) + + sizerb = wx.BoxSizer(wx.VERTICAL) + self.checkgradient = wx.CheckBox(pnl, -1, "Gradient Theme") + self.checkgradient.Bind(wx.EVT_CHECKBOX, self.OnCheckGradient) + sizerb1 = wx.BoxSizer(wx.HORIZONTAL) + sizerb1.Add((10, 0)) + self.radiohorizontal = wx.RadioButton(pnl, -1, "Horizontal", style=wx.RB_GROUP) + self.radiohorizontal.Bind(wx.EVT_RADIOBUTTON, self.OnHorizontal) + sizerb1.Add(self.radiohorizontal, 0, wx.TOP|wx.BOTTOM, 3) + sizerb2 = wx.BoxSizer(wx.HORIZONTAL) + sizerb2.Add((10, 0)) + self.radiovertical = wx.RadioButton(pnl, -1, "Vertical") + self.radiovertical.Bind(wx.EVT_RADIOBUTTON, self.OnVertical) + sizerb2.Add(self.radiovertical, 0, wx.BOTTOM, 3) + sizerb3 = wx.BoxSizer(wx.HORIZONTAL) + self.firstcolour = csel.ColourSelect(pnl, -1, "First Colour", + self.ulc.list.GetFirstGradientColour()) + self.secondcolour = csel.ColourSelect(pnl, -1, "Second Colour", + self.ulc.list.GetSecondGradientColour()) + self.firstcolour.Bind(csel.EVT_COLOURSELECT, self.OnFirstColour) + self.secondcolour.Bind(csel.EVT_COLOURSELECT, self.OnSecondColour) + sizerb3.Add(self.firstcolour, 0, wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, 3) + sizerb3.Add(self.secondcolour, 0, wx.LEFT|wx.TOP|wx.BOTTOM|wx.ALIGN_CENTER_HORIZONTAL, 3) + sizerb.Add(self.checkgradient, 0, wx.ALL, 3) + sizerb.Add(sizerb1, 0) + sizerb.Add(sizerb2, 0) + sizerb.Add(sizerb3, 0, wx.ALIGN_CENTER) + + self.checkvista = wx.CheckBox(pnl, -1, "Windows Vista Theme") + self.checkvista.Bind(wx.EVT_CHECKBOX, self.OnVista) + + themessizer.Add(sizera, 0, wx.EXPAND) + themessizer.Add(sizerb, 0, wx.EXPAND) + themessizer.Add((0, 5)) + themessizer.Add(self.checkvista, 0, wx.EXPAND|wx.ALL, 3) + + mainsizer.Add(stylesizer, 0, wx.EXPAND|wx.ALL, 5) + mainsizer.Add(themessizer, 0, wx.EXPAND|wx.ALL, 5) + + pnl.SetSizer(mainsizer) + pnl.Fit() + + swsizer = wx.BoxSizer(wx.VERTICAL) + swsizer.Add(pnl, 0, wx.EXPAND) + self.leftpanel.SetSizer(swsizer) + swsizer.Layout() + swsizer.Fit(self.leftpanel) + + self.checknormal.SetValue(1) + self.radiohorizontal.Enable(False) + self.radiovertical.Enable(False) + self.firstcolour.Enable(False) + self.secondcolour.Enable(False) + + return mainsizer.CalcMin().width + wx.SystemSettings.GetMetric(wx.SYS_VSCROLL_X) + + + def OnCheckStyle(self, event): + + self.ulc.ChangeStyle(self.ulcstyles) + event.Skip() + + + def OnCheckNormal(self, event): + + self.radiohorizontal.Enable(False) + self.radiovertical.Enable(False) + self.firstcolour.Enable(False) + self.secondcolour.Enable(False) + self.checkgradient.SetValue(0) + self.checkvista.SetValue(0) + self.ulc.list.EnableSelectionGradient(False) + self.ulc.list.EnableSelectionVista(False) + event.Skip() + + + def OnCheckGradient(self, event): + + self.radiohorizontal.Enable(True) + self.radiovertical.Enable(True) + self.firstcolour.Enable(True) + self.secondcolour.Enable(True) + self.checknormal.SetValue(0) + self.checkvista.SetValue(0) + self.ulc.list.SetGradientStyle(self.radiovertical.GetValue()) + self.ulc.list.EnableSelectionVista(False) + self.ulc.list.EnableSelectionGradient(True) + + event.Skip() + + + def OnHorizontal(self, event): + + self.ulc.list.SetGradientStyle(self.radiovertical.GetValue()) + event.Skip() + + + def OnVertical(self, event): + + self.ulc.list.SetGradientStyle(self.radiovertical.GetValue()) + event.Skip() + + + def OnFirstColour(self, event): + + col1 = event.GetValue() + self.ulc.list.SetFirstGradientColour(wx.Colour(col1[0], col1[1], col1[2])) + event.Skip() + + + def OnSecondColour(self, event): + + col1 = event.GetValue() + self.ulc.list.SetSecondGradientColour(wx.Colour(col1[0], col1[1], col1[2])) + event.Skip() + + + def OnVista(self, event): + + self.radiohorizontal.Enable(False) + self.radiovertical.Enable(False) + self.firstcolour.Enable(False) + self.secondcolour.Enable(False) + self.checknormal.SetValue(0) + self.checkgradient.SetValue(0) + self.ulc.list.EnableSelectionGradient(False) + self.ulc.list.EnableSelectionVista(True) + + event.Skip() + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.App(0) + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + + diff --git a/demo/agw/UltimateVirtualDemo.py b/demo/agw/UltimateVirtualDemo.py new file mode 100644 index 00000000..d1ac7d47 --- /dev/null +++ b/demo/agw/UltimateVirtualDemo.py @@ -0,0 +1,205 @@ +import wx +import images +import random +import os, sys + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import ultimatelistctrl as ULC +except ImportError: # if it's not there locally, try the wxPython lib. + from wx.lib.agw import ultimatelistctrl as ULC + + +def GenerateRandomList(imgList): + + rList = [] + chance = random.randint(0, 2) + if chance < 2: + return rList + + numImages = random.randint(1, 3) + listSize = imgList.GetImageCount() + + for i in xrange(numImages): + rList.append(random.randint(0, listSize-1)) + + return rList + + +class TestUltimateListCtrl(ULC.UltimateListCtrl): + + def __init__(self, parent, log): + + ULC.UltimateListCtrl.__init__(self, parent, -1, + agwStyle=wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES|ULC.ULC_SHOW_TOOLTIPS) + + self.log = log + + self.il = wx.ImageList(16, 16) + self.il.Add(images.Smiles.GetBitmap()) + self.il.Add(images.core.GetBitmap()) + self.il.Add(images.custom.GetBitmap()) + self.il.Add(images.exit.GetBitmap()) + self.il.Add(images.expansion.GetBitmap()) + + self.SetImageList(self.il, wx.IMAGE_LIST_SMALL) + + self.InsertColumn(0, "First") + self.InsertColumn(1, "Second") + self.InsertColumn(2, "Third") + self.SetColumnWidth(0, 175) + self.SetColumnWidth(1, 175) + self.SetColumnWidth(2, 175) + self.SetColumnToolTip(0,"First Column Tooltip!") + self.SetColumnToolTip(1,"Second Column Tooltip!") + self.SetColumnToolTip(2,"Third Column Tooltip!") + + # After setting the column width you can specify that + # this column expands to fill the window. Only one + # column may be specified. + self.SetColumnWidth(2, ULC.ULC_AUTOSIZE_FILL) + + self.SetItemCount(1000000) + + self.attr1 = ULC.UltimateListItemAttr() + self.attr1.SetBackgroundColour(wx.NamedColour("yellow")) + + self.attr2 = ULC.UltimateListItemAttr() + self.attr2.SetBackgroundColour(wx.NamedColour("light blue")) + + self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnItemSelected) + self.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemActivated) + self.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnItemDeselected) + + self.randomLists = [GenerateRandomList(self.il) for i in xrange(5)] + + + def OnItemSelected(self, event): + + self.currentItem = event.m_itemIndex + self.log.write("OnItemSelected: %s, %s, %s, %s\n" %(self.currentItem, + self.GetItemText(self.currentItem), + self.getColumnText(self.currentItem, 1), + self.getColumnText(self.currentItem, 2))) + + def OnItemActivated(self, event): + self.currentItem = event.m_itemIndex + self.log.write("OnItemActivated: %s\nTopItem: %s\n" %(self.GetItemText(self.currentItem), self.GetTopItem())) + + def getColumnText(self, index, col): + + item = self.GetItem(index, col) + return item.GetText() + + def OnItemDeselected(self, evt): + self.log.write("OnItemDeselected: %s\n" % evt.m_itemIndex) + + + #--------------------------------------------------- + # These methods are callbacks for implementing the + # "virtualness" of the list... Normally you would + # determine the text, attributes and/or image based + # on values from some external data source, but for + # this demo we'll just calculate them + + def OnGetItemText(self, item, col): + return "Item %d, column %d" % (item, col) + + def OnGetItemToolTip(self, item, col): + if item == 0: + return "Tooltip: Item %d, column %d" % (item, col) + return None + + def OnGetItemTextColour(self, item, col): + if item == 0 and col == 0: + return wx.Colour(255,0,0) + elif item == 0 and col == 1: + return wx.Colour(0,255,0) + elif item == 0 and col == 2: + return wx.Colour(0,0,255) + else: + return None + + + def OnGetItemColumnImage(self, item, column): + + return self.randomLists[item%5] + + + def OnGetItemImage(self, item): + + return self.randomLists[item%5] + + + def OnGetItemAttr(self, item): + if item % 3 == 1: + return self.attr1 + elif item % 3 == 2: + return self.attr2 + else: + return None + + + def OnGetItemColumnCheck(self, item, column): + + if item%3 == 0: + return True + + return False + + + def OnGetItemCheck(self, item): + + if item%3 == 1: + return True + + return False + + + def OnGetItemColumnKind(self, item, column): + + if item%3 == 0: + return 2 + elif item%3 == 1: + return 1 + + return 0 + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent, -1, "UltimateListCtrl in wx.LC_VIRTUAL mode", size=(700, 600)) + panel = wx.Panel(self, -1) + sizer = wx.BoxSizer(wx.VERTICAL) + + listCtrl = TestUltimateListCtrl(panel, log) + + sizer.Add(listCtrl, 1, wx.EXPAND) + panel.SetSizer(sizer) + sizer.Layout() + + self.SetIcon(images.Mondrian.GetIcon()) + self.CenterOnScreen() + self.Show() + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.App(0) + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() + + diff --git a/demo/agw/Windows7Explorer_Contents.py b/demo/agw/Windows7Explorer_Contents.py new file mode 100644 index 00000000..24e88fab --- /dev/null +++ b/demo/agw/Windows7Explorer_Contents.py @@ -0,0 +1,363 @@ +import sys +import os +import wx +import time +import datetime +import operator + +from wx.lib.embeddedimage import PyEmbeddedImage + +import images + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import ultimatelistctrl as ULC +except ImportError: # if it's not there locally, try the wxPython lib. + from wx.lib.agw import ultimatelistctrl as ULC + +bitmapDir = os.path.join(dirName, 'bitmaps') +sys.path.append(os.path.split(dirName)[0]) + +# helper function to make sure we don't convert unicode objects to strings +# or vice versa when converting lists and None values to text. +convert = str +if 'unicode' in wx.PlatformInfo: + convert = unicode + + +def FormatFileSize(size): + + for x in ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']: + + if size < 1024.0: + return "%3.2f %s" % (size, x) + + size /= 1024.0 + + +class FirstColumnRenderer(object): + + def __init__(self, parent, fileName): + + self.parent = parent + self.fileName = fileName + + self.normalFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + self.normalFont.SetPointSize(self.normalFont.GetPointSize() + 1) + self.smallerFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + + self.greyColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT) + + if os.path.isdir(fileName): + self.text = fileName + bitmap = wx.Bitmap(os.path.join(bitmapDir, "folder.png"), wx.BITMAP_TYPE_PNG) + self.icon = wx.IconFromBitmap(bitmap) + self.description = "" + return + + self.text = os.path.split(fileName)[1] + extension = os.path.splitext(fileName)[1] + + if not extension: + self.text = fileName + bitmap = wx.Bitmap(os.path.join(bitmapDir, "empty_icon.png"), wx.BITMAP_TYPE_PNG) + self.icon = wx.IconFromBitmap(bitmap) + self.description = "File" + return + + fileType = wx.TheMimeTypesManager.GetFileTypeFromExtension(extension) + + bmp = wx.Bitmap(os.path.join(bitmapDir, "empty_icon.png"), wx.BITMAP_TYPE_PNG) + bmp = wx.IconFromBitmap(bmp) + + if not fileType: + icon = wx.IconFromLocation(wx.IconLocation(fileName)) + if not icon.IsOk(): + self.icon = bmp + else: + self.icon = icon + + self.description = "%s File"%extension[1:].upper() + return + + #------- Icon info + info = fileType.GetIconInfo() + icon = None + + if info is not None: + icon, file, idx = info + if icon.IsOk(): + bmp = icon + else: + icon = None + + if icon is None: + icon = wx.IconFromLocation(wx.IconLocation(fileName)) + if icon.IsOk(): + bmp = icon + else: + command = fileType.GetOpenCommand(fileName) + command = " ".join(command.split()[0:-1]) + command = command.replace('"', "") + if " -" in command: + command = command[0:command.index(" -")] + + icon = wx.IconFromLocation(wx.IconLocation(command)) + if icon.IsOk(): + bmp = icon + + self.icon = bmp + self.description = convert(fileType.GetDescription()) + + if not self.description: + self.description = "%s File"%extension[1:].upper() + + + def DrawSubItem(self, dc, rect, line, highlighted, enabled): + """Draw a custom progress bar using double buffering to prevent flicker""" + + bmpWidth, bmpHeight = self.icon.GetWidth(), self.icon.GetHeight() + dc.DrawIcon(self.icon, rect.x+5, rect.y+(rect.height-bmpHeight)/2) + + dc.SetFont(self.normalFont) + + textWidth, textHeight = dc.GetTextExtent(self.text) + dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNTEXT)) + dc.DrawText(self.text, rect.x+bmpWidth+10, rect.y+(rect.height - textHeight)/4) + + if not self.description: + return + + dc.SetFont(self.smallerFont) + + dummy1, dummy2= dc.GetTextExtent("Type: ") + textWidth, textHeight = dc.GetTextExtent("Type: " + self.description) + + dc.SetTextForeground(self.greyColour) + dc.DrawText("Type: ", rect.x+bmpWidth+10, rect.y+3*(rect.height - textHeight)/4) + + dc.SetTextForeground(wx.BLACK) + dc.DrawText(self.description, rect.x+bmpWidth+dummy1+10, rect.y+3*(rect.height - textHeight)/4) + + + def GetLineHeight(self): + + dc = wx.MemoryDC() + dc.SelectObject(wx.EmptyBitmap(100, 20)) + + bmpWidth, bmpHeight = self.icon.GetWidth(), self.icon.GetHeight() + dc.SetFont(self.normalFont) + + textWidth, textHeight = dc.GetTextExtent(self.text) + + dc.SetFont(self.smallerFont) + dummy1, dummy2= dc.GetTextExtent("Type: ") + textWidth, textHeight = dc.GetTextExtent("Type: " + self.description) + + dc.SelectObject(wx.NullBitmap) + + return max(2*textHeight, bmpHeight) + 20 + + + def GetSubItemWidth(self): + + return 250 + + +class SecondColumnRenderer(object): + + def __init__(self, parent, fileName): + + self.parent = parent + self.fileName = fileName + + self.smallerFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + + self.greyColour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT) + + t = os.path.getmtime(fileName) + date = datetime.datetime.fromtimestamp(t) + self.date = date.strftime("%d/%m/%Y %H:%M") + + if os.path.isdir(fileName): + self.size = "" + return + + s = os.path.getsize(fileName) + self.size = FormatFileSize(s) + + + def DrawSubItem(self, dc, rect, line, highlighted, enabled): + """Draw a custom progress bar using double buffering to prevent flicker""" + + dc.SetFont(self.smallerFont) + + date = self.date + dummy1, dummy2= dc.GetTextExtent("Date modified: ") + textWidth, textHeight = dc.GetTextExtent("Date modified: " + date) + + dc.SetTextForeground(self.greyColour) + dc.DrawText("Date modified: ", rect.x+5, rect.y+(rect.height - textHeight)/4) + + dc.SetTextForeground(wx.BLACK) + dc.DrawText(date, rect.x+dummy1+5, rect.y+(rect.height - textHeight)/4) + + if not self.size: + return + + dummy1, dummy2= dc.GetTextExtent("Size: ") + + dc.SetTextForeground(self.greyColour) + dc.DrawText("Size: ", rect.x+5, rect.y+3*(rect.height - textHeight)/4) + + dc.SetTextForeground(wx.BLACK) + dc.DrawText(self.size, rect.x+dummy1+5, rect.y+3*(rect.height - textHeight)/4) + + + def GetLineHeight(self): + + dc = wx.MemoryDC() + dc.SelectObject(wx.EmptyBitmap(100, 20)) + textWidth, textHeight, d1, d2 = dc.GetFullTextExtent("Date modified: %s"%self.date, + self.smallerFont) + + dc.SelectObject(wx.NullBitmap) + return 2*textHeight + 20 + + + def GetSubItemWidth(self): + + dc = wx.MemoryDC() + dc.SelectObject(wx.EmptyBitmap(100, 20)) + + textWidth, textHeight, d1, d2 = dc.GetFullTextExtent("Date modified: %s"%self.date, + self.smallerFont) + + dc.SelectObject(wx.NullBitmap) + + return textWidth+10 + + +class Windows7Explorer(ULC.UltimateListCtrl): + + def __init__(self, parent, log): + + ULC.UltimateListCtrl.__init__(self, parent, -1, style=wx.BORDER_THEME, + agwStyle=wx.LC_REPORT|wx.LC_NO_HEADER|wx.LC_HRULES| + ULC.ULC_HAS_VARIABLE_ROW_HEIGHT) + + self.EnableSelectionVista() + self.PopulateList() + + + def PopulateList(self, path=""): + + self.ClearAll() + + self.InsertColumn(0, "Column 1") + self.InsertColumn(1, "Column 2") + + if not path.strip(): + path = os.getcwd() + + os.chdir(path) + files1 = os.listdir(path) + files1.sort() + + files = [] + for file in files1: + kind = not os.path.isdir(file) + name = os.path.split(file)[1] + files.append((kind, name, name.lower())) + + files = sorted(files, key=operator.itemgetter(0, 2)) + dummy_log = wx.LogNull() + + for kind, file, lower in files: + index = self.InsertStringItem(sys.maxint, "") + + klass = FirstColumnRenderer(self, file) + self.SetItemCustomRenderer(index, 0, klass) + + self.SetStringItem(index, 1, "") + klass = SecondColumnRenderer(self, file) + self.SetItemCustomRenderer(index, 1, klass) + + self.SetColumnWidth(0, ULC.ULC_AUTOSIZE_FILL) + self.SetColumnWidth(1, wx.LIST_AUTOSIZE) + + +#--------------------------------------------------------------------------- + +class TestFrame(wx.Frame): + + def __init__(self, parent, log): + + wx.Frame.__init__(self, parent, -1, "UltimateListCtrl - Windows 7 Explorer", size=(800, 600)) + + self.log = log + + panel = wx.Panel(self) + panelSizer = wx.BoxSizer(wx.VERTICAL) + + font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + font.SetWeight(wx.BOLD) + + static = wx.StaticText(panel, -1, "Choose a folder to display:") + static.SetFont(font) + panelSizer.Add(static, 0, wx.EXPAND|wx.LEFT|wx.RIGHT|wx.TOP, 10) + + dp1 = wx.DirPickerCtrl(panel, path=os.getcwd(), style=wx.DIRP_USE_TEXTCTRL) + dp1.SetTextCtrlProportion(2) + panelSizer.Add(dp1, 0, wx.EXPAND|wx.LEFT|wx.RIGHT, 10) + + # Create the CustomTreeCtrl, using a derived class defined below + self.ulc = Windows7Explorer(panel, self.log) + + panelSizer.Add(self.ulc, 1, wx.EXPAND|wx.ALL, 10) + panel.SetSizer(panelSizer) + + self.Bind(wx.EVT_DIRPICKER_CHANGED, self.OnPickDir, dp1) + + self.ulc.SetFocus() + self.SetIcon(images.Mondrian.GetIcon()) + self.CenterOnScreen() + self.Show() + + + def OnPickDir(self, event): + + wx.BeginBusyCursor() + self.Freeze() + path = event.GetPath() + + try: + self.ulc.PopulateList(path) + except OSError: + self.log.write("You dont have permission to access folder: %s"%path) + wx.EndBusyCursor() + self.Thaw() + return + + self.Layout() + self.SendSizeEvent() + self.Thaw() + + self.ulc.DoLayout() + wx.EndBusyCursor() + + +#--------------------------------------------------------------------------- + +if __name__ == '__main__': + import sys + app = wx.App(0) + frame = TestFrame(None, sys.stdout) + frame.Show(True) + app.MainLoop() diff --git a/demo/agw/XLSGrid.py b/demo/agw/XLSGrid.py new file mode 100644 index 00000000..caa6a169 --- /dev/null +++ b/demo/agw/XLSGrid.py @@ -0,0 +1,236 @@ +import os +import sys +import wx + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +sys.path.append(os.path.split(dirName)[0]) + +_isStandalone = False + +try: + from agw import xlsgrid as XG + _isStandalone = True +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.xlsgrid as XG + +dataDir = os.path.join(dirName, "data") + +_hasXLRD = True + +try: + import xlrd +except ImportError: + _hasXLRD = False + +_hasWin32 = False + +if wx.Platform == "__WXMSW__": + try: + from win32com.client import Dispatch + _hasWin32 = True + except ImportError: + pass + + +_msg = "This is the about dialog of the XLSGrid demo.\n\n" + \ + "Author: Andrea Gavana @ 17 Aug 2011\n\n" + \ + "Please report any bugs/requests of improvements\n" + \ + "to me at the following addresses:\n\n" + \ + "andrea.gavana@gmail.com\n" + "andrea.gavana@maerskoil.com\n\n" + \ + "Welcome to wxPython " + wx.VERSION_STRING + "!!" + + +class XLSGridDemo(wx.Panel): + + def __init__(self, parent, log): + + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test XLSGrid ", (50, 50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + + XLSGridFrame(None) + + +class XLSGridFrame(wx.Frame): + + def __init__(self, parent, size=(950, 730)): + + wx.Frame.__init__(self, parent, title="XLSGrid wxPython Demo", size=size) + panel = XLSGridPanel(self) + + self.CreateMenuAndStatusBar() + self.CenterOnScreen() + self.Show() + + + def CreateMenuAndStatusBar(self): + + menuBar = wx.MenuBar() + fileMenu = wx.Menu() + helpMenu = wx.Menu() + + item = wx.MenuItem(fileMenu, wx.ID_ANY, "E&xit", "Exit XLSGrid demo") + self.Bind(wx.EVT_MENU, self.OnClose, item) + fileMenu.AppendItem(item) + + item = wx.MenuItem(helpMenu, wx.ID_ANY, "About...", "Shows the about dialog") + self.Bind(wx.EVT_MENU, self.OnAbout, item) + helpMenu.AppendItem(item) + + menuBar.Append(fileMenu, "&File") + menuBar.Append(helpMenu, "&Help") + + self.SetMenuBar(menuBar) + + statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + statusbar.SetStatusWidths([-2, -1]) + + statusbar_fields = [("wxPython XLSGrid Demo, Andrea Gavana @ 08 Aug 2011"), + ("Welcome To wxPython!")] + + for i in xrange(len(statusbar_fields)): + statusbar.SetStatusText(statusbar_fields[i], i) + + + def OnClose(self, event): + + wx.CallAfter(self.Destroy) + + + def OnAbout(self, event): + + dlg = wx.MessageDialog(self, _msg, "XLSGrid wxPython Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + + +class XLSGridPanel(wx.Panel): + + def __init__(self, parent): + + wx.Panel.__init__(self, parent) + + self.start_button = wx.Button(self, -1, "Start") + self.grid = XG.XLSGrid(self) + + self.grid.Hide() + + self.DoLayout() + + self.Bind(wx.EVT_BUTTON, self.OnStart, self.start_button) + + + def DoLayout(self): + + xlrd_ver = xlrd.__VERSION__ + string_xlrd = "Version " + xlrd_ver + + if xlrd_ver <= "0.7.1": + string_xlrd += ": hyperlink and rich-text functionalities will not work. xlrd 0.7.2 (SVN) is required for this." + else: + string_xlrd += ": hyperlink and rich-text functionalities will work!" + + if _hasWin32: + string_pywin32 = "You have pywin32! XLSGrid cells should appear exactly as in Excel (WYSIWYG)." + else: + string_pywin32 = "You don't have pywin32. Cell string formatting will be severely limited." + + main_sizer = wx.BoxSizer(wx.VERTICAL) + top_sizer = wx.BoxSizer(wx.HORIZONTAL) + top_right_sizer = wx.BoxSizer(wx.VERTICAL) + top_center_sizer = wx.BoxSizer(wx.VERTICAL) + top_sizer.Add(self.start_button, 0, wx.ALL|wx.ALIGN_CENTER_HORIZONTAL|wx.ALIGN_CENTER_VERTICAL, 10) + label_1 = wx.StaticText(self, -1, "xlrd:") + label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + top_center_sizer.Add(label_1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, 5) + top_center_sizer.Add((0, 0), 1, wx.EXPAND, 0) + label_2 = wx.StaticText(self, -1, "pywin32:") + label_2.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + top_center_sizer.Add(label_2, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ALIGN_RIGHT, 5) + top_sizer.Add(top_center_sizer, 0, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0) + label_xlrd = wx.StaticText(self, -1, string_xlrd) + top_right_sizer.Add(label_xlrd, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + top_right_sizer.Add((0, 0), 1, wx.EXPAND, 0) + label_pywin32 = wx.StaticText(self, -1, string_pywin32) + top_right_sizer.Add(label_pywin32, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + top_sizer.Add(top_right_sizer, 1, wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 0) + main_sizer.Add(top_sizer, 0, wx.ALL|wx.EXPAND, 5) + main_sizer.Add((0, 10)) + main_sizer.Add(self.grid, 1, wx.ALL|wx.EXPAND, 5) + self.SetSizer(main_sizer) + + main_sizer.Layout() + + + def OnStart(self, event): + + event.Skip() + + filename = os.path.join(os.path.abspath(dataDir), "Example_1.xls") + + if not os.path.isfile(filename): + dlg = wx.MessageDialog(self, 'Error: the file "Example_1.xls" is not in the "data" directory', + 'XLSGridDemo Error', wx.OK | wx.ICON_ERROR) + dlg.ShowModal() + dlg.Destroy() + return + + busy = wx.BusyInfo("Reading Excel file, please wait...") + + sheetname = "Example_1" + book = xlrd.open_workbook(filename, formatting_info=1) + + sheet = book.sheet_by_name(sheetname) + rows, cols = sheet.nrows, sheet.ncols + + comments, texts = XG.ReadExcelCOM(filename, sheetname, rows, cols) + + del busy + + self.grid.Show() + self.grid.PopulateGrid(book, sheet, texts, comments) + + self.start_button.Enable(False) + self.Layout() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + + if _hasXLRD: + win = XLSGridDemo(nb, log) + return win + else: + msg = 'This demo requires the xlrd package to be installed.\n' \ + 'See: http://pypi.python.org/pypi/xlrd' + + if _isStandalone: + dlg = wx.MessageDialog(nb, msg, 'Sorry', wx.ICON_WARNING|wx.OK) + dlg.ShowModal() + dlg.Destroy() + return None + else: + from Main import MessagePanel + win = MessagePanel(nb, msg, 'Sorry', wx.ICON_WARNING) + + return win + +#---------------------------------------------------------------------- + +overview = XG.__doc__ + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/ZoomBar.py b/demo/agw/ZoomBar.py new file mode 100644 index 00000000..1b9fdaf9 --- /dev/null +++ b/demo/agw/ZoomBar.py @@ -0,0 +1,229 @@ +import wx + +import os +import sys +import glob +import random + +import wx.lib.colourselect as csel +from wx.lib import masked + +try: + dirName = os.path.dirname(os.path.abspath(__file__)) +except: + dirName = os.path.dirname(os.path.abspath(sys.argv[0])) + +bitmapDir = os.path.join(dirName, 'bitmaps') +sys.path.append(os.path.split(dirName)[0]) + +try: + from agw import zoombar as ZB +except ImportError: # if it's not there locally, try the wxPython lib. + import wx.lib.agw.zoombar as ZB + + +_buttonStatus = {True: "Disable First Button", + False: "Enable First Button"} + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + + def __init__(self, parent, log): + + self.log = log + self.enabled = True + + wx.Panel.__init__(self, parent, -1) + + self.sizer_1_staticbox = wx.StaticBox(self, -1, "ZoomBar Options") + self.zoomSpin = wx.SpinCtrl(self, -1, "3", min=1, max=5) + + self.colourzoom = csel.ColourSelect(self, colour=wx.Colour(97, 97, 97)) + self.buttonSize = masked.NumCtrl(self, value=32, allowNegative=False, + min=32, max=72) + + self.centerZoom = wx.CheckBox(self, -1, "Center Zoom") + self.showReflections = wx.CheckBox(self, -1, "Show Reflections") + self.showLabels = wx.CheckBox(self, -1, "Show Labels") + self.enableButton = wx.Button(self, -1, "Disable First Button") + + self.zbp = ZB.ZoomBar(self, -1) + + standard = glob.glob(bitmapDir + "/*96.png") + reflections = glob.glob(bitmapDir + "/*96Flip40.png") + + separatorImage = bitmapDir + "/separator.gif" + separatorReflection = bitmapDir + "/separatorFlip.png" + count = 0 + + for std, ref in zip(standard, reflections): + if random.randint(0, 1) == 1 and count > 0: + sep1 = wx.Bitmap(separatorImage, wx.BITMAP_TYPE_GIF) + sep2 = wx.Bitmap(separatorReflection, wx.BITMAP_TYPE_PNG) + self.zbp.AddSeparator(sep1, sep2) + + bname = os.path.split(std)[1][0:-6] + self.zbp.AddButton(wx.Bitmap(std, wx.BITMAP_TYPE_PNG), wx.Bitmap(ref, wx.BITMAP_TYPE_PNG), bname) + count += 1 + + self.zbp.ResetSize() + + self.SetProperties() + self.DoLayout() + + self.Bind(wx.EVT_SPINCTRL, self.OnZoomFactor, self.zoomSpin) + self.Bind(wx.EVT_CHECKBOX, self.OnCenterZoom, self.centerZoom) + self.Bind(wx.EVT_CHECKBOX, self.OnShowReflections, self.showReflections) + self.Bind(wx.EVT_CHECKBOX, self.OnShowLabels, self.showLabels) + self.Bind(wx.EVT_BUTTON, self.OnEnable, self.enableButton) + + self.Bind(masked.EVT_NUM, self.OnButtonSize, self.buttonSize) + + self.colourzoom.Bind(csel.EVT_COLOURSELECT, self.OnZoomColour) + + self.Bind(ZB.EVT_ZOOMBAR, self.OnZoomBar) + + + def SetProperties(self): + + self.centerZoom.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + self.showReflections.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + self.showLabels.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + + self.centerZoom.Enable(False) + self.showLabels.SetValue(1) + self.showReflections.SetValue(1) + + + def DoLayout(self): + + mainSizer = wx.BoxSizer(wx.HORIZONTAL) + centerSizer = wx.BoxSizer(wx.VERTICAL) + sizer_1 = wx.StaticBoxSizer(self.sizer_1_staticbox, wx.VERTICAL) + sizer_2 = wx.BoxSizer(wx.VERTICAL) + sizer_3 = wx.FlexGridSizer(3, 2, 5, 5) + mainSizer.Add((20, 20), 1, wx.EXPAND, 0) + centerSizer.Add((20, 20), 1, 0, 0) + label_1 = wx.StaticText(self, -1, "Zoom Factor:") + label_1.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + sizer_3.Add(label_1, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + sizer_3.Add(self.zoomSpin, 1, wx.ALIGN_CENTER_VERTICAL, 0) + + label_2 = wx.StaticText(self, -1, "Bar Colour:") + label_2.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + sizer_3.Add(label_2, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + sizer_3.Add(self.colourzoom, 0, wx.ALIGN_CENTER_VERTICAL, 0) + + label_3 = wx.StaticText(self, -1, "Button Size:") + label_3.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, "")) + sizer_3.Add(label_3, 0, wx.RIGHT|wx.ALIGN_CENTER_VERTICAL, 5) + sizer_3.Add(self.buttonSize, 0, wx.ALIGN_CENTER_VERTICAL, 0) + + sizer_2.Add(sizer_3, 0, wx.EXPAND|wx.ALL, 5) + + sizer_2.Add(self.centerZoom, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + sizer_2.Add(self.showReflections, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + sizer_2.Add(self.showLabels, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + sizer_2.Add(self.enableButton, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5) + sizer_1.Add(sizer_2, 1, wx.EXPAND, 0) + centerSizer.Add(sizer_1, 0, wx.EXPAND, 0) + centerSizer.Add(self.zbp, 0, wx.TOP|wx.EXPAND, 20) + centerSizer.Add((0, 0), 1, 0, 0) + mainSizer.Add(centerSizer, 10, wx.EXPAND, 0) + mainSizer.Add((0, 0), 1, wx.EXPAND, 0) + self.SetSizer(mainSizer) + mainSizer.Fit(self) + + + def OnZoomBar(self, event): + + self.log.write("Selected button index and label: %d, %s\n"%(event.GetSelection(), event.GetLabel())) + + + def OnZoomFactor(self, event): + + value = event.GetInt() + self.zbp.SetZoomFactor(value) + + event.Skip() + + + def OnZoomColour(self, event): + + colour = event.GetValue() + self.zbp.SetBarColour(colour) + + + def OnCenterZoom(self, event): + + self.zbp.SetCenterZoom(event.IsChecked()) + wx.CallAfter(self.ReLayout) + + + def OnShowReflections(self, event): + + if event.IsChecked(): + self.centerZoom.SetValue(0) + self.centerZoom.Enable(False) + self.zbp.SetCenterZoom(False) + self.zbp.SetShowReflections(True) + else: + self.centerZoom.Enable(True) + self.zbp.SetShowReflections(False) + + wx.CallAfter(self.ReLayout) + + + def OnShowLabels(self, event): + + self.zbp.SetShowLabels(event.IsChecked()) + wx.CallAfter(self.ReLayout) + + + def OnEnable(self, event): + + self.zbp.EnableButton(0, not self.enabled) + self.enabled = not self.enabled + + obj = event.GetEventObject() + obj.SetLabel(_buttonStatus[self.enabled]) + obj.Refresh() + + + def OnButtonSize(self, event): + + value = event.GetValue() + event.Skip() + + if value < 32 or value > 72: + return + + self.zbp.SetButtonSize(value) + wx.CallAfter(self.ReLayout) + + + def ReLayout(self): + + self.Layout() + self.Refresh() + self.Update() + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + +overview = ZB.__doc__ + + +if __name__ == '__main__': + import sys, os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/agw/__demo__.py b/demo/agw/__demo__.py new file mode 100644 index 00000000..affa8233 --- /dev/null +++ b/demo/agw/__demo__.py @@ -0,0 +1,199 @@ +""" +This module contains the meta data needed for integrating the samples +in the AGW subdir into the wxPython demo framework. Once imported, +this module returns the following information: + +* GetDemoBitmap: returns the bitmap used in the wxPython tree control + to characterize the AGW package; +* GetRecentAdditions: returns a subset (or the whole set) of demos in + the AGW package which will appear under the Recent Additions tree + item in the wxPython demo; +* GetDemos: returns all the demos in the AGW package; +* GetOverview: returns a wx.html-ready representation of the AGW docs. + +These meta data are merged into the wxPython demo tree at startup. + +Last updated: Andrea Gavana @ 04 Feb 2013, 21.00 GMT. +Version 0.9.7. + +""" + +__version__ = "0.9.7" +__author__ = "Andrea Gavana " + + +# Start the imports... +import wx +from wx.lib.embeddedimage import PyEmbeddedImage + +# ======================================== +# For AGW (Advanced Generic Widgets :-D ) +# ======================================== + +import wx.lib.agw +_agwDocs = wx.lib.agw.__doc__ + +# ======================================== +# End AGW things +# ======================================== + + +def GetDemoBitmap(): + """ Returns the bitmap to be used in the demo tree for the AGW package. """ + + # Get the image as PyEmbeddedImage + image = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAvdJ" + "REFUOI2NkX1I3HUcx1/f7+/B85yXpXa38o+ltIdzGRUUs4fpClaYi5iFERpkG6yQtkEEBZ0Q" + "QkW1GotVFEEQGcFkOIK2Nq1mszqJdeKdDzsU9fS86dx5nre78/vtj3ViBtH73/f7/eLzIFij" + "A8fHm6evmU/3+q1sbLT0efrEfM7Tvg9dZJOHVSi8V0Yj21VscViGB942c4Gd+/0lgaWyur4e" + "STaGyUSoFJgH0K2tLianT2UvnLzXTA21YSmHjBtNlKrXVwEu75bG7m4KsuMqSKHchr3VDQwB" + "MBY/TODMgyI/9III8/n1xkobgAlQu/9sRWRpw67E4MKCXZ7/c8bK26Znlm8DfgLgz9BelsOY" + "Y9fL+tlDZ5idg4s9WQlQoS74HCfuqK3fWPnE196HjhTSX4DJxtXjRMObIQPAZ08aV6b8R2s5" + "3/EI9sRF+VrdlmOVMV+Tac5aBim+DfrLqyvvq9lZ1PRUrj/uupwgo1m+wQq2zOyuK66v/oW8" + "QqY8Wos9XjMbtJpHRiI1x4g1f/TSA489PrjQ3ZlXmjLf32V8PBUke3VCt9RHVVwlpVvaHmUb" + "xo/xhsjdfyyoIU4fkHrA57XXvvNsMxWzHTK92G/o/n2G+v4Zu551Gus0TwfeknNyeobMrZ7R" + "PWvNh7/k0uQPso0eKLuTFYeRHlgPsG1uTsdJmoNR0eH5XX0x90FBqPjg0oDwceqmiLNoLnWt" + "6tdunbIPKsdXl8Vwxz6jutGTdTgkrxZNO1eMRLpqZEgcFQCv7BDfbS4Ruzfkyyvtvcql08ps" + "rJI9b+xQgXK/9eimmsztx++RHOnTVwOzwmotEc4bJ3Wg9xZ1l8iN1LIdtzBkwzdl1nMJrzWv" + "nca7aP0yAmHFlX1oMpk8Nybud1kkG4p1+4td6lMAsX43fK53AC/oMRBlwCiwFU0UgRulP+HN" + "xa5cXP4LsCqxCfT5vwEgcKP1IknnubWp/wAAWdH5T6Y4yXvRpf8L+I32+CUQwwBoVkjkd60P" + "/QWR0DSJqhvOegAAAABJRU5ErkJggg==") + + # Return the AGW bitmap to use in + # the wxPython demo tree control + return image + + +def GetRecentAdditions(): + """ + Returns a subset (or the full set) of the AGW demo names which will go + into the Recent Additions tree item in the wxPython demo. + """ + + # For the moment, we add all the widgets in AGW as + # Recent Additions + if wx.VERSION < (2, 9): + recentAdditions = ['AdvancedSplash', 'AquaButton', 'AUI', 'BalloonTip', + 'ButtonPanel', 'CubeColourDialog', 'CustomTreeCtrl', + 'FlatMenu', 'FlatNotebook', 'FloatSpin', + 'FoldPanelBar', 'FourWaySplitter', 'GenericMessageDialog', + 'GradientButton', 'HyperLinkCtrl', 'HyperTreeList', + 'AGWInfoBar', 'KnobCtrl', 'LabelBook', 'MultiDirDialog', + 'PeakMeter', 'PersistentControls', 'PieCtrl', 'PyBusyInfo', + 'PyCollapsiblePane', 'PyProgress', 'RibbonBar', 'RulerCtrl', + 'ShapedButton', 'ShortcutEditor', 'SpeedMeter', 'SuperToolTip', + 'ThumbnailCtrl', 'ToasterBox', 'UltimateListCtrl', + 'XLSGrid', 'ZoomBar'] + elif wx.VERSION < (2,9,2): + recentAdditions = ['AUI', 'AGWInfoBar', 'PersistentControls', 'PyBusyInfo', 'PyGauge', + 'RibbonBar', 'ShortcutEditor', 'UltimateListCtrl', + 'XLSGrid', 'ZoomBar'] + else: + recentAdditions = ['AGWInfoBar', 'PersistentControls', 'ShortcutEditor', 'XLSGrid'] + + # Return the Recent Additions for AGW + return recentAdditions + + +def GetDemos(): + """ + Returns all the demo names in the AGW package, together with the tree item + name which will go in the wxPython demo tree control. + """ + + # The tree item text for AGW + AGWTreeItem = "Advanced Generic Widgets" + + # The AGW demos + AGWDemos = ['AdvancedSplash', 'AquaButton', 'AUI', 'BalloonTip', + 'ButtonPanel', 'CubeColourDialog', 'CustomTreeCtrl', + 'FlatMenu', 'FlatNotebook', 'FloatSpin', + 'FoldPanelBar', 'FourWaySplitter', 'GenericMessageDialog', + 'GradientButton', 'HyperLinkCtrl', 'HyperTreeList', + 'AGWInfoBar', 'KnobCtrl', 'LabelBook', 'MultiDirDialog', + 'PeakMeter', 'PersistentControls', 'PieCtrl', 'PyBusyInfo', + 'PyCollapsiblePane', 'PyGauge', 'PyProgress', 'RibbonBar', + 'RulerCtrl', 'ShapedButton', 'ShortcutEditor', 'SpeedMeter', + 'SuperToolTip', 'ThumbnailCtrl', 'ToasterBox', + 'UltimateListCtrl', 'XLSGrid', 'ZoomBar'] + + return AGWTreeItem, AGWDemos + + +def GetOverview(): + """ + Creates the HTML code to display the Advanced Generic Widgets documentation + starting from wx.lib.agw.__doc__. + """ + + # wxPython widgets to highlight using the tag + wxPythonWidgets = ["wx.SplashScreen", "wx.ColourDialog", "wx.TreeCtrl", "wx.MenuBar", + "wx.Menu", "wx.ToolBar", "wx.Notebook", "wx.MessageDialog", + "wx.gizmos.TreeListCtrl", "wx.DirDialog", "wx.CollapsiblePane", + "wx.ProgressDialog", "wx.TipWindow", "wx.lib", "wx.aui", "wx.ListCtrl", + "wx.BusyInfo", "wx.Panel", "wx.Gauge", "wx.grid.Grid"] + + import wx.lib.agw + _agwDocs = wx.lib.agw.__doc__ + + _agwDocs = _agwDocs.replace("`", "").replace("L{", "").replace("}", "") + + # Split the docs in many lines + splitted = _agwDocs.split("\n") + # Add the title + strs = "\n

Advanced Generic Widgets (AGW)

\n\n" + + # Get the number of widgets in the package... + numWidgets = len(GetDemos()[1]) + widgetsFound, endRemarks = 0, 0 + for line in splitted: + # Loop over the lines in the AGW documentation + newLine = line + if line.startswith("- "): + # That's a new widget + indxStart = line.index("-") + 1 + indxEnd = line.index(":") + sw = line[indxStart:indxEnd] + # Put a bullet + newLine = "
  • %s:"%sw + line[indxEnd+1:] + if widgetsFound == 0: + newLine = "

      \n" + newLine + widgetsFound += 1 + elif line.strip().endswith(";"): + newLine = "%s"%line + elif line.startswith("Description:"): + # It's a title + newLine = "

      %s
      "%line + if endRemarks: + if ":" in newLine and not line.startswith("http"): + indxEnd = newLine.index(":") + newLine = "
      %s"%newLine[0:indxEnd] + newLine[indxEnd:] + else: + newLine = "
      %s"%newLine + if line.startswith("http:"): + # It's a web address + newLine = " %s"%(newLine, newLine) + elif line.find("@") > 0: + # It's an email address + newLine = " %s"%(newLine, newLine) + + strs += newLine + + if widgetsFound == numWidgets and line.find(".") >= 0 and line.find("ListCtrl") < 0: + # Break the loop, all widgets included + strs += "\n

    " + widgetsFound = 0 + endRemarks = 1 + + strs += "" + # Make AGW bold and wxPython underlined... + strs = strs.replace("AGW", "AGW") + strs = strs.replace("wxPython", "wxPython") + for widget in wxPythonWidgets: + # Show wx things with the tag + strs = strs.replace(widget, "%s"%widget) + + # Return the beautified AGW docs, ready for wx.html + return strs + diff --git a/demo/agw/bitmaps/Explorer96.png b/demo/agw/bitmaps/Explorer96.png new file mode 100644 index 00000000..4db45886 Binary files /dev/null and b/demo/agw/bitmaps/Explorer96.png differ diff --git a/demo/agw/bitmaps/Explorer96Flip40.png b/demo/agw/bitmaps/Explorer96Flip40.png new file mode 100644 index 00000000..3c31ede7 Binary files /dev/null and b/demo/agw/bitmaps/Explorer96Flip40.png differ diff --git a/demo/agw/bitmaps/Folder96.png b/demo/agw/bitmaps/Folder96.png new file mode 100644 index 00000000..36a6d537 Binary files /dev/null and b/demo/agw/bitmaps/Folder96.png differ diff --git a/demo/agw/bitmaps/Folder96Flip40.png b/demo/agw/bitmaps/Folder96Flip40.png new file mode 100644 index 00000000..f846e125 Binary files /dev/null and b/demo/agw/bitmaps/Folder96Flip40.png differ diff --git a/demo/agw/bitmaps/Monitor96.png b/demo/agw/bitmaps/Monitor96.png new file mode 100644 index 00000000..b0644716 Binary files /dev/null and b/demo/agw/bitmaps/Monitor96.png differ diff --git a/demo/agw/bitmaps/Monitor96Flip40.png b/demo/agw/bitmaps/Monitor96Flip40.png new file mode 100644 index 00000000..2a631ecc Binary files /dev/null and b/demo/agw/bitmaps/Monitor96Flip40.png differ diff --git a/demo/agw/bitmaps/Music96.png b/demo/agw/bitmaps/Music96.png new file mode 100644 index 00000000..1109e38b Binary files /dev/null and b/demo/agw/bitmaps/Music96.png differ diff --git a/demo/agw/bitmaps/Music96Flip40.png b/demo/agw/bitmaps/Music96Flip40.png new file mode 100644 index 00000000..dc839d75 Binary files /dev/null and b/demo/agw/bitmaps/Music96Flip40.png differ diff --git a/demo/agw/bitmaps/Photo96.png b/demo/agw/bitmaps/Photo96.png new file mode 100644 index 00000000..46fccafa Binary files /dev/null and b/demo/agw/bitmaps/Photo96.png differ diff --git a/demo/agw/bitmaps/Photo96Flip40.png b/demo/agw/bitmaps/Photo96Flip40.png new file mode 100644 index 00000000..2de0ac51 Binary files /dev/null and b/demo/agw/bitmaps/Photo96Flip40.png differ diff --git a/demo/agw/bitmaps/Search96.png b/demo/agw/bitmaps/Search96.png new file mode 100644 index 00000000..899f803d Binary files /dev/null and b/demo/agw/bitmaps/Search96.png differ diff --git a/demo/agw/bitmaps/Search96Flip40.png b/demo/agw/bitmaps/Search96Flip40.png new file mode 100644 index 00000000..b124e97b Binary files /dev/null and b/demo/agw/bitmaps/Search96Flip40.png differ diff --git a/demo/agw/bitmaps/Wizard96.png b/demo/agw/bitmaps/Wizard96.png new file mode 100644 index 00000000..e030f985 Binary files /dev/null and b/demo/agw/bitmaps/Wizard96.png differ diff --git a/demo/agw/bitmaps/Wizard96Flip40.png b/demo/agw/bitmaps/Wizard96Flip40.png new file mode 100644 index 00000000..b9eda5f2 Binary files /dev/null and b/demo/agw/bitmaps/Wizard96Flip40.png differ diff --git a/demo/agw/bitmaps/advancedsplash.png b/demo/agw/bitmaps/advancedsplash.png new file mode 100644 index 00000000..0b2abe5e Binary files /dev/null and b/demo/agw/bitmaps/advancedsplash.png differ diff --git a/demo/agw/bitmaps/aquabutton.png b/demo/agw/bitmaps/aquabutton.png new file mode 100644 index 00000000..9dc9f99d Binary files /dev/null and b/demo/agw/bitmaps/aquabutton.png differ diff --git a/demo/agw/bitmaps/aquachecked.ico b/demo/agw/bitmaps/aquachecked.ico new file mode 100644 index 00000000..fd50f45b Binary files /dev/null and b/demo/agw/bitmaps/aquachecked.ico differ diff --git a/demo/agw/bitmaps/aquaflagged.ico b/demo/agw/bitmaps/aquaflagged.ico new file mode 100644 index 00000000..b3b4816f Binary files /dev/null and b/demo/agw/bitmaps/aquaflagged.ico differ diff --git a/demo/agw/bitmaps/aquanotchecked.ico b/demo/agw/bitmaps/aquanotchecked.ico new file mode 100644 index 00000000..28610339 Binary files /dev/null and b/demo/agw/bitmaps/aquanotchecked.ico differ diff --git a/demo/agw/bitmaps/aquanotflagged.ico b/demo/agw/bitmaps/aquanotflagged.ico new file mode 100644 index 00000000..030dc1c7 Binary files /dev/null and b/demo/agw/bitmaps/aquanotflagged.ico differ diff --git a/demo/agw/bitmaps/canada.gif b/demo/agw/bitmaps/canada.gif new file mode 100644 index 00000000..2afbb21f Binary files /dev/null and b/demo/agw/bitmaps/canada.gif differ diff --git a/demo/agw/bitmaps/checked.ico b/demo/agw/bitmaps/checked.ico new file mode 100644 index 00000000..e63306ff Binary files /dev/null and b/demo/agw/bitmaps/checked.ico differ diff --git a/demo/agw/bitmaps/columns.png b/demo/agw/bitmaps/columns.png new file mode 100644 index 00000000..33426b40 Binary files /dev/null and b/demo/agw/bitmaps/columns.png differ diff --git a/demo/agw/bitmaps/contexthelp-16.png b/demo/agw/bitmaps/contexthelp-16.png new file mode 100644 index 00000000..aa69cc4c Binary files /dev/null and b/demo/agw/bitmaps/contexthelp-16.png differ diff --git a/demo/agw/bitmaps/contexthelp.png b/demo/agw/bitmaps/contexthelp.png new file mode 100644 index 00000000..53b84f93 Binary files /dev/null and b/demo/agw/bitmaps/contexthelp.png differ diff --git a/demo/agw/bitmaps/copy.png b/demo/agw/bitmaps/copy.png new file mode 100644 index 00000000..cfa9cb43 Binary files /dev/null and b/demo/agw/bitmaps/copy.png differ diff --git a/demo/agw/bitmaps/cut.png b/demo/agw/bitmaps/cut.png new file mode 100644 index 00000000..79d2dcae Binary files /dev/null and b/demo/agw/bitmaps/cut.png differ diff --git a/demo/agw/bitmaps/editcopy.png b/demo/agw/bitmaps/editcopy.png new file mode 100644 index 00000000..8df8201e Binary files /dev/null and b/demo/agw/bitmaps/editcopy.png differ diff --git a/demo/agw/bitmaps/editcut.png b/demo/agw/bitmaps/editcut.png new file mode 100644 index 00000000..514bd97c Binary files /dev/null and b/demo/agw/bitmaps/editcut.png differ diff --git a/demo/agw/bitmaps/editpaste.png b/demo/agw/bitmaps/editpaste.png new file mode 100644 index 00000000..8906e80f Binary files /dev/null and b/demo/agw/bitmaps/editpaste.png differ diff --git a/demo/agw/bitmaps/empty_icon.png b/demo/agw/bitmaps/empty_icon.png new file mode 100644 index 00000000..1ffd2bd6 Binary files /dev/null and b/demo/agw/bitmaps/empty_icon.png differ diff --git a/demo/agw/bitmaps/exit-16.png b/demo/agw/bitmaps/exit-16.png new file mode 100644 index 00000000..fb510fbe Binary files /dev/null and b/demo/agw/bitmaps/exit-16.png differ diff --git a/demo/agw/bitmaps/exit.ico b/demo/agw/bitmaps/exit.ico new file mode 100644 index 00000000..81b3d5d4 Binary files /dev/null and b/demo/agw/bitmaps/exit.ico differ diff --git a/demo/agw/bitmaps/ffwd.png b/demo/agw/bitmaps/ffwd.png new file mode 100644 index 00000000..87421d52 Binary files /dev/null and b/demo/agw/bitmaps/ffwd.png differ diff --git a/demo/agw/bitmaps/ffwddisabled.png b/demo/agw/bitmaps/ffwddisabled.png new file mode 100644 index 00000000..105b883d Binary files /dev/null and b/demo/agw/bitmaps/ffwddisabled.png differ diff --git a/demo/agw/bitmaps/field-16.png b/demo/agw/bitmaps/field-16.png new file mode 100644 index 00000000..4a0ac4d4 Binary files /dev/null and b/demo/agw/bitmaps/field-16.png differ diff --git a/demo/agw/bitmaps/filenew.png b/demo/agw/bitmaps/filenew.png new file mode 100644 index 00000000..4828b633 Binary files /dev/null and b/demo/agw/bitmaps/filenew.png differ diff --git a/demo/agw/bitmaps/fileopen.png b/demo/agw/bitmaps/fileopen.png new file mode 100644 index 00000000..e3528f02 Binary files /dev/null and b/demo/agw/bitmaps/fileopen.png differ diff --git a/demo/agw/bitmaps/filesave.png b/demo/agw/bitmaps/filesave.png new file mode 100644 index 00000000..82db5055 Binary files /dev/null and b/demo/agw/bitmaps/filesave.png differ diff --git a/demo/agw/bitmaps/flagged.ico b/demo/agw/bitmaps/flagged.ico new file mode 100644 index 00000000..5edb063a Binary files /dev/null and b/demo/agw/bitmaps/flagged.ico differ diff --git a/demo/agw/bitmaps/folder.png b/demo/agw/bitmaps/folder.png new file mode 100644 index 00000000..4215fa2b Binary files /dev/null and b/demo/agw/bitmaps/folder.png differ diff --git a/demo/agw/bitmaps/folder_new.png b/demo/agw/bitmaps/folder_new.png new file mode 100644 index 00000000..cf189f46 Binary files /dev/null and b/demo/agw/bitmaps/folder_new.png differ diff --git a/demo/agw/bitmaps/ghost.png b/demo/agw/bitmaps/ghost.png new file mode 100644 index 00000000..8c8fbaeb Binary files /dev/null and b/demo/agw/bitmaps/ghost.png differ diff --git a/demo/agw/bitmaps/gradientbutton.png b/demo/agw/bitmaps/gradientbutton.png new file mode 100644 index 00000000..8838345a Binary files /dev/null and b/demo/agw/bitmaps/gradientbutton.png differ diff --git a/demo/agw/bitmaps/help-16.png b/demo/agw/bitmaps/help-16.png new file mode 100644 index 00000000..9f0c92f2 Binary files /dev/null and b/demo/agw/bitmaps/help-16.png differ diff --git a/demo/agw/bitmaps/help.ico b/demo/agw/bitmaps/help.ico new file mode 100644 index 00000000..e8d18c4e Binary files /dev/null and b/demo/agw/bitmaps/help.ico differ diff --git a/demo/agw/bitmaps/italy.gif b/demo/agw/bitmaps/italy.gif new file mode 100644 index 00000000..f1102b5b Binary files /dev/null and b/demo/agw/bitmaps/italy.gif differ diff --git a/demo/agw/bitmaps/lbadd.png b/demo/agw/bitmaps/lbadd.png new file mode 100644 index 00000000..18f0a81c Binary files /dev/null and b/demo/agw/bitmaps/lbadd.png differ diff --git a/demo/agw/bitmaps/lbcharge.png b/demo/agw/bitmaps/lbcharge.png new file mode 100644 index 00000000..70e4126b Binary files /dev/null and b/demo/agw/bitmaps/lbcharge.png differ diff --git a/demo/agw/bitmaps/lbdecrypted.png b/demo/agw/bitmaps/lbdecrypted.png new file mode 100644 index 00000000..2b49969a Binary files /dev/null and b/demo/agw/bitmaps/lbdecrypted.png differ diff --git a/demo/agw/bitmaps/lbnews.png b/demo/agw/bitmaps/lbnews.png new file mode 100644 index 00000000..9299bbcc Binary files /dev/null and b/demo/agw/bitmaps/lbnews.png differ diff --git a/demo/agw/bitmaps/lbroll.png b/demo/agw/bitmaps/lbroll.png new file mode 100644 index 00000000..19d88b00 Binary files /dev/null and b/demo/agw/bitmaps/lbroll.png differ diff --git a/demo/agw/bitmaps/minus1.ico b/demo/agw/bitmaps/minus1.ico new file mode 100644 index 00000000..18893b14 Binary files /dev/null and b/demo/agw/bitmaps/minus1.ico differ diff --git a/demo/agw/bitmaps/minus2.ico b/demo/agw/bitmaps/minus2.ico new file mode 100644 index 00000000..60dbadc0 Binary files /dev/null and b/demo/agw/bitmaps/minus2.ico differ diff --git a/demo/agw/bitmaps/minus3.ico b/demo/agw/bitmaps/minus3.ico new file mode 100644 index 00000000..ea65ef84 Binary files /dev/null and b/demo/agw/bitmaps/minus3.ico differ diff --git a/demo/agw/bitmaps/minus4.ico b/demo/agw/bitmaps/minus4.ico new file mode 100644 index 00000000..17f8d434 Binary files /dev/null and b/demo/agw/bitmaps/minus4.ico differ diff --git a/demo/agw/bitmaps/minus5.ico b/demo/agw/bitmaps/minus5.ico new file mode 100644 index 00000000..e748ca58 Binary files /dev/null and b/demo/agw/bitmaps/minus5.ico differ diff --git a/demo/agw/bitmaps/month-16.png b/demo/agw/bitmaps/month-16.png new file mode 100644 index 00000000..01a5f2a0 Binary files /dev/null and b/demo/agw/bitmaps/month-16.png differ diff --git a/demo/agw/bitmaps/new_file.png b/demo/agw/bitmaps/new_file.png new file mode 100644 index 00000000..a71c1a25 Binary files /dev/null and b/demo/agw/bitmaps/new_file.png differ diff --git a/demo/agw/bitmaps/new_folder.png b/demo/agw/bitmaps/new_folder.png new file mode 100644 index 00000000..dfc7a103 Binary files /dev/null and b/demo/agw/bitmaps/new_folder.png differ diff --git a/demo/agw/bitmaps/notchecked.ico b/demo/agw/bitmaps/notchecked.ico new file mode 100644 index 00000000..d69bc99e Binary files /dev/null and b/demo/agw/bitmaps/notchecked.ico differ diff --git a/demo/agw/bitmaps/notflagged.ico b/demo/agw/bitmaps/notflagged.ico new file mode 100644 index 00000000..d0ccc4cd Binary files /dev/null and b/demo/agw/bitmaps/notflagged.ico differ diff --git a/demo/agw/bitmaps/ok-16.png b/demo/agw/bitmaps/ok-16.png new file mode 100644 index 00000000..ac479f25 Binary files /dev/null and b/demo/agw/bitmaps/ok-16.png differ diff --git a/demo/agw/bitmaps/open_folder.png b/demo/agw/bitmaps/open_folder.png new file mode 100644 index 00000000..c0854974 Binary files /dev/null and b/demo/agw/bitmaps/open_folder.png differ diff --git a/demo/agw/bitmaps/paste.png b/demo/agw/bitmaps/paste.png new file mode 100644 index 00000000..a192060b Binary files /dev/null and b/demo/agw/bitmaps/paste.png differ diff --git a/demo/agw/bitmaps/pause.png b/demo/agw/bitmaps/pause.png new file mode 100644 index 00000000..88de2fcb Binary files /dev/null and b/demo/agw/bitmaps/pause.png differ diff --git a/demo/agw/bitmaps/pausedisabled.png b/demo/agw/bitmaps/pausedisabled.png new file mode 100644 index 00000000..6518c553 Binary files /dev/null and b/demo/agw/bitmaps/pausedisabled.png differ diff --git a/demo/agw/bitmaps/play.png b/demo/agw/bitmaps/play.png new file mode 100644 index 00000000..49fb0288 Binary files /dev/null and b/demo/agw/bitmaps/play.png differ diff --git a/demo/agw/bitmaps/playdisabled.png b/demo/agw/bitmaps/playdisabled.png new file mode 100644 index 00000000..901c3c64 Binary files /dev/null and b/demo/agw/bitmaps/playdisabled.png differ diff --git a/demo/agw/bitmaps/plus1.ico b/demo/agw/bitmaps/plus1.ico new file mode 100644 index 00000000..a7435fe8 Binary files /dev/null and b/demo/agw/bitmaps/plus1.ico differ diff --git a/demo/agw/bitmaps/plus2.ico b/demo/agw/bitmaps/plus2.ico new file mode 100644 index 00000000..0cf031a9 Binary files /dev/null and b/demo/agw/bitmaps/plus2.ico differ diff --git a/demo/agw/bitmaps/plus3.ico b/demo/agw/bitmaps/plus3.ico new file mode 100644 index 00000000..4ddbd455 Binary files /dev/null and b/demo/agw/bitmaps/plus3.ico differ diff --git a/demo/agw/bitmaps/plus4.ico b/demo/agw/bitmaps/plus4.ico new file mode 100644 index 00000000..e61dbac6 Binary files /dev/null and b/demo/agw/bitmaps/plus4.ico differ diff --git a/demo/agw/bitmaps/plus5.ico b/demo/agw/bitmaps/plus5.ico new file mode 100644 index 00000000..6acf059e Binary files /dev/null and b/demo/agw/bitmaps/plus5.ico differ diff --git a/demo/agw/bitmaps/record.png b/demo/agw/bitmaps/record.png new file mode 100644 index 00000000..bc95ad3e Binary files /dev/null and b/demo/agw/bitmaps/record.png differ diff --git a/demo/agw/bitmaps/recorddisabled.png b/demo/agw/bitmaps/recorddisabled.png new file mode 100644 index 00000000..2ef8d862 Binary files /dev/null and b/demo/agw/bitmaps/recorddisabled.png differ diff --git a/demo/agw/bitmaps/rewind.png b/demo/agw/bitmaps/rewind.png new file mode 100644 index 00000000..5d082270 Binary files /dev/null and b/demo/agw/bitmaps/rewind.png differ diff --git a/demo/agw/bitmaps/rewinddisabled.png b/demo/agw/bitmaps/rewinddisabled.png new file mode 100644 index 00000000..06b6f579 Binary files /dev/null and b/demo/agw/bitmaps/rewinddisabled.png differ diff --git a/demo/agw/bitmaps/round.png b/demo/agw/bitmaps/round.png new file mode 100644 index 00000000..5995c31e Binary files /dev/null and b/demo/agw/bitmaps/round.png differ diff --git a/demo/agw/bitmaps/save.png b/demo/agw/bitmaps/save.png new file mode 100644 index 00000000..55ca1ec2 Binary files /dev/null and b/demo/agw/bitmaps/save.png differ diff --git a/demo/agw/bitmaps/separator.gif b/demo/agw/bitmaps/separator.gif new file mode 100644 index 00000000..9f5b4509 Binary files /dev/null and b/demo/agw/bitmaps/separator.gif differ diff --git a/demo/agw/bitmaps/separatorflip.png b/demo/agw/bitmaps/separatorflip.png new file mode 100644 index 00000000..6b56c65d Binary files /dev/null and b/demo/agw/bitmaps/separatorflip.png differ diff --git a/demo/agw/bitmaps/smfuel.ico b/demo/agw/bitmaps/smfuel.ico new file mode 100644 index 00000000..cfdb96c0 Binary files /dev/null and b/demo/agw/bitmaps/smfuel.ico differ diff --git a/demo/agw/bitmaps/smpi.ico b/demo/agw/bitmaps/smpi.ico new file mode 100644 index 00000000..c04c4f37 Binary files /dev/null and b/demo/agw/bitmaps/smpi.ico differ diff --git a/demo/agw/bitmaps/smtemp.ico b/demo/agw/bitmaps/smtemp.ico new file mode 100644 index 00000000..9de6beb3 Binary files /dev/null and b/demo/agw/bitmaps/smtemp.ico differ diff --git a/demo/agw/bitmaps/stop.png b/demo/agw/bitmaps/stop.png new file mode 100644 index 00000000..750a8a72 Binary files /dev/null and b/demo/agw/bitmaps/stop.png differ diff --git a/demo/agw/bitmaps/stopdisabled.png b/demo/agw/bitmaps/stopdisabled.png new file mode 100644 index 00000000..f5c096c6 Binary files /dev/null and b/demo/agw/bitmaps/stopdisabled.png differ diff --git a/demo/agw/bitmaps/sttbutton.png b/demo/agw/bitmaps/sttbutton.png new file mode 100644 index 00000000..d73d0ab8 Binary files /dev/null and b/demo/agw/bitmaps/sttbutton.png differ diff --git a/demo/agw/bitmaps/sttfont.png b/demo/agw/bitmaps/sttfont.png new file mode 100644 index 00000000..f1428836 Binary files /dev/null and b/demo/agw/bitmaps/sttfont.png differ diff --git a/demo/agw/bitmaps/sttheader.png b/demo/agw/bitmaps/sttheader.png new file mode 100644 index 00000000..652f19de Binary files /dev/null and b/demo/agw/bitmaps/sttheader.png differ diff --git a/demo/agw/bitmaps/stthelp.png b/demo/agw/bitmaps/stthelp.png new file mode 100644 index 00000000..28a0f9e5 Binary files /dev/null and b/demo/agw/bitmaps/stthelp.png differ diff --git a/demo/agw/bitmaps/view1.png b/demo/agw/bitmaps/view1.png new file mode 100644 index 00000000..abb2830e Binary files /dev/null and b/demo/agw/bitmaps/view1.png differ diff --git a/demo/agw/bitmaps/view2.png b/demo/agw/bitmaps/view2.png new file mode 100644 index 00000000..7688e8a0 Binary files /dev/null and b/demo/agw/bitmaps/view2.png differ diff --git a/demo/agw/bitmaps/view_choose.png b/demo/agw/bitmaps/view_choose.png new file mode 100644 index 00000000..d12ece21 Binary files /dev/null and b/demo/agw/bitmaps/view_choose.png differ diff --git a/demo/agw/bitmaps/view_detailed.png b/demo/agw/bitmaps/view_detailed.png new file mode 100644 index 00000000..78f40769 Binary files /dev/null and b/demo/agw/bitmaps/view_detailed.png differ diff --git a/demo/agw/bitmaps/view_icon.png b/demo/agw/bitmaps/view_icon.png new file mode 100644 index 00000000..4a6426b0 Binary files /dev/null and b/demo/agw/bitmaps/view_icon.png differ diff --git a/demo/agw/bitmaps/view_multicolumn.png b/demo/agw/bitmaps/view_multicolumn.png new file mode 100644 index 00000000..77e13e69 Binary files /dev/null and b/demo/agw/bitmaps/view_multicolumn.png differ diff --git a/demo/agw/bitmaps/viewmag-16.png b/demo/agw/bitmaps/viewmag-16.png new file mode 100644 index 00000000..4909e4df Binary files /dev/null and b/demo/agw/bitmaps/viewmag-16.png differ diff --git a/demo/agw/bitmaps/viewmag-m-16.png b/demo/agw/bitmaps/viewmag-m-16.png new file mode 100644 index 00000000..1a7c6d7f Binary files /dev/null and b/demo/agw/bitmaps/viewmag-m-16.png differ diff --git a/demo/agw/bitmaps/viewmag-p-16.png b/demo/agw/bitmaps/viewmag-p-16.png new file mode 100644 index 00000000..81c1a93f Binary files /dev/null and b/demo/agw/bitmaps/viewmag-p-16.png differ diff --git a/demo/agw/bitmaps/viewmagfit-16.png b/demo/agw/bitmaps/viewmagfit-16.png new file mode 100644 index 00000000..34b85d4f Binary files /dev/null and b/demo/agw/bitmaps/viewmagfit-16.png differ diff --git a/demo/agw/data/Example_1.xls b/demo/agw/data/Example_1.xls new file mode 100644 index 00000000..0a3a825e Binary files /dev/null and b/demo/agw/data/Example_1.xls differ diff --git a/demo/agw/images.py b/demo/agw/images.py new file mode 100644 index 00000000..f83aa89b --- /dev/null +++ b/demo/agw/images.py @@ -0,0 +1,6714 @@ +#---------------------------------------------------------------------- +# This file was generated by encode_bitmaps.py +# +from wx.lib.embeddedimage import PyEmbeddedImage + +Mondrian = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAHFJ" + "REFUWIXt1jsKgDAQRdF7xY25cpcWC60kioI6Fm/ahHBCMh+BRmGMnAgEWnvPpzK8dvrFCCCA" + "coD8og4c5Lr6WB3Q3l1TBwLYPuF3YS1gn1HphgEEEABcKERrGy0E3B0HFJg7C1N/f/kTBBBA" + "+Vi+AMkgFEvBPD17AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Background = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAJYAAACWCAIAAACzY+a1AAAAA3NCSVQICAjb4U/gAAAgAElE" + "QVR4nES8QYskvbIsaEG7wB0kkKACOi7Ug75wHpzFHXiLmeUsZjn/H87iPOgL/UEWZEII0kHW" + "YAmziOxvCrq6KCqjUpLL3dzNrLbv/+93OAKxuEiOPr6PTpAnAPro8+fNvw8HSAAgz0UCPr4H" + "JxbW6AMAAB/ucAAEeRIBLvj1GSAI4Jxr9PDo7n++tzjJ83YD4cMBBLDgowfcCXp0rnnO9ePH" + "D3K693l+Ae7XLw2fiz0c7iR5zpNrePTxfa6vHp2LJL+PPhdBEnB3kg5cXwMg6Q7AfXSeXwR6" + "9Gu5Dnf3nz9/kjx+HIA7CO/v7XDw5G2eDoxjnLfz2orjGI4+17y2jFwAeh+T7KNjcYLfx/d5" + "znOeJN09PL6Pjj7m7adHn+e8Vngt53osAQdOIrjgcb15g1/rev/MOc/uPo5j4ZwnefIE/eu8" + "DgFAOAhgTU6cf06VALBwjonpcIR7OBznOUEsLCAWMNyPwwHH4lzT4QQxFzzGcWCu81ozfIzw" + "0bnmmut64Pj7LZLgunb3HRckw3FOAHA/3BF+7T7w9xfXCnzxBHDO89q14+iLmOf0AOEDsY7v" + "QARwmzeeJNiPfvz44SBxfXKe00e/YohBn4CHA9Gvp7h7J3l+3QiMPtzjCjn/swqPHsAMHDgI" + "ejivm8H156cWGYsn4HAg3IHe+9fPr+BaALCcwOjfPv/Xp6BjP0orhaA07w+YjbZnTsAKJRAy" + "OPgkNhlgxUptIAUUYEnFwswEq+HVXSaSnM+2t2Mcdd9/cxoMBQ5LJYi6V9+cel1rs972MbYN" + "ZTOZoNeZa3KGRR8ffVQZRHDNlaXtrhSA83EffaDYmblJ3iokbzbvlEjmPZ9K/mbeblOvhFne" + "H5SO4/hoNal8JkmPakDUaN7CTNLjfEAAAEEkqZwTQB0VSWxotUnJpzZsBfCoECQZzMMl5ZwC" + "Aqi15ST5lBUP92KjD9TSrPFFK+buJKTJTddD7jkhwG3U8OiCDGju2Mxbe9mrqJi7F/u2/9e+" + "2XZ8HiZL/gb5yFTmbd4ft4mNgubiKF5q4MXw0WpsCNgSzaDysTcPSWYShXAq77/u1AbTNjcL" + "GSxnPqWA1X2vxVVkMi4+86nMr3PiN1vd3QvF85z5Uj7Ti49jVHMaeJtU3r5OPGer8cwlSVLb" + "dwdepA93WErYrEYFJClU9s8GhV4Kt4LgptpsjF3APOf9cQ8Pj6tWWMF2z/vX/WvNJSmlAj6T" + "GzZ37+GAJakig5GSZGZmJglgbV1F19m/sIGU9FKBryXstaFUc0nImZM0gKDLWcTHKW1mds6z" + "eSu1tNa8VHfAjJIIgrZECAlBHv6t/VdbXPayVGo+ZWbFRqlcaQYrFdDM9KgF5XH/klBaePVq" + "UWpsJmiT1IerVIFKCire9lZLFEmAkXzmc9Tmw5tFsSKIT16VQIAVE7CJJBehQsCsmPcxoqZk" + "0H1mMShJCZsFonlpfXgxwAF5626WZC1G5O2v8+v2FwoCjTzzSW4KQ9TW6shHUidQRh+SjqPz" + "XVQIgkmZQleSbo/7Q5ltDBSTJKXLtIHnpKnC9E7y8vA885znSy8AAqK2Xv18kGLUZgUS8pkq" + "chjg5pCUiycJU1iQ3PfW2wcM0JUB3c2tGk8KMNiTT5lefH07/q+Dky+9LMy0zczhjhpR2hiN" + "UMgAa83cGzfNnCPcPHRVF22LKzNjtMN3BCBY1M/PPerI+6zNrHht9Td+GyyZfDHPTGaNWqxI" + "atXC2/CQlTOz9RZoUUHKHCUaFi3slfTWCza9JOn4GHX/8HAzk0GkbZB0ZhbAW9/0m2RtddQg" + "N2wwKCUQm3FJrY5qZuEAMplznjxfWTwMgYghvQDsteVvolizkiTJ2jozk3xyFYrcBJlJuW75" + "Tr/FirtvJKz0/ePr8eXApuINXALQW7dqBog2z8fKp4GwNlotrRjcqpkkwauHRTElYRusmBW9" + "bGtq5vZt/+e++QahjipBmaW2Nc98Ui9+/Xp4q9asefiow0eU8N7Oec45KRUrpZZRx/k4LYwC" + "JC8GIcn7vL24AfANmZS0cm3anvl83B6lFoNt4GI0Ax0QwsPdzSVrkCBEKxBq1HsmeRYUAHpm" + "jCCFDZIgqZgWVWwjZeYbEB4qxQvzuaBRB5kCtBJtjNqO0edGLQH417/+hQ15pgo3bQbzYiSL" + "FTcbtR377uFJgouZT0mpMAINWJAM7akpYv/Yxxhv5CUtaePv1kdYkcHDJJzz3LAxyY0CnvOE" + "A9YC6KOPj0HB9AaK5ibqcZ85pwMzkxRyWQ0Pt9u8HcdxztNPXIj7++hfXNHjAn7hAIIEb9Md" + "y9EDMSN69NEBcuGcZ3jMNS88xsW5Zo/+4/gRHngjKPTR+3IC5zz76Guuk6f7G9z5H2R8/d+H" + "O4IE4AiOY/z8+UXO6DF6nITDbxdUBo7juJBed+fxHeTtdht9eHdOnuf00fvoJMOX96MfTmKR" + "DkdwngQwvo83SAYQProT3RcnueY5+kGet3N6AOsNEeHj++jzvPoTcIKL15ad8wQw+ujhDv86" + "vwCsefr4AcxJBs+TODB8eHjA/f1kh8OP7idPnpOgLyd58nR4H46J23kD4OdE+Lfjvw5BbbTe" + "PmqrEWHA/ZEFut2mUjBFNHdYdaaKATDzd/224lastFKjenGCz1SYWZiWEM58/Px1+83fcJyP" + "s3h4OOek1GoLoPXhQJJ19GN0FDvnWUyI5sX76KM2c/vvn1/NVWqDYPJxBAWKRz9e/nK5FUiG" + "sOFB8vFIiYGwqhY7c/73v/53Gw4Lc5szz3nOzJdepBZXbXUfuxWj4NcVhOX9FxTmYmJz9jpa" + "jL2PbQMkAK0PZvbjuzIlJfn5Pz8dNs/Zahtj1GZ68tfjlpkA5jNHLYBTGnUUbDKdM5NnoBjs" + "OI6kRM7JPCfJ87H2PTgVHsUayb57qwMbLLzV9s3/6cXKR6vhLTO5iGIFL6moyB1jHN69twrZ" + "yVMpimPEvn9ascczUdT70Rw/b4+/fv2szY/P/wQkyjbMpZyTZBikCJcESvvHbmYixY0uF+ro" + "Asz0e76WFFZqs+i7m1FUktTKlcqigmYuL/4S/Cr5KuqtNo/b7XbPNAjAZpsS0jOf16+10YLX" + "7lvZrIALVkothYIVFX207uEp6fl4pjbblEti813ibd7DysfnZ1h5qQiq7iIzJa3xsXtxLspU" + "o7o7KUobtvBoVlBsQ5HEzFKLN38+nsyk8HkMax1ScuKJmY9nPjMTUKDJtOYS2GqrzbHZSy9J" + "RbLwADBPxrFGH8vXNeIA4PBxDACc59cMdx99IJznbS54X+HRg3AM93Oua1YSCHJd2ci7dwDf" + "x5pwf49CABx9EOA8b+fswZiOPgI4LzzqGP6nlsxz/Umt75fznWp8uOM7SSz8nCe+6D+cBIEA" + "4HHOMxDeHfTjIDje4x53D3e/8Ge/nsyg+58seuXT8CDWXOPH8BPnvM3FPrq7z3P28PeAJnye" + "8+ftp7v/6AMOLIBg0OFcRMAJH93dnZMLAI7vB8LdcRwHFwkOP5YvTv494rmWhgDJxZMLWPDr" + "/V7/GHB88394s4aAwTPzcX+A3ABJ80xSj5wiYoTBIAKQtqXn/Pqdml4c5iInZ8DCYnG98BuC" + "D1dqLnrYpjfmuD/uynxZ+WhVeuGl0YfVBjJT9/nr6+dDm4pJ2q5uhBu1dM5zAxcLoGICCjZI" + "yaUkmJOLkoptBtRWPZxk6w0Ak2Zgrvs5+WKzYuGSBGIZxTknQI8qKiWeKQkFms/yEUoJKo5W" + "RvECCWbMfHLttaGox0fyse/HR/u47p+KuCDSw6tXZirAJ624irx43SsoCloEKDiZeJFLgdhs" + "K1JYiwDMCpVLHmhtAEIxrUwKBgDf9v+1G4xizjznmRci90EmYGO4bbDie2+1uUe/5WyjH6Nt" + "4bW493ef9zhT4MpFMHx8jC7o9utWfPvYP+twbaYrbKXWB6TMZ96zRQN0znOjJPOAFucLRm5W" + "JD3nk3POZ1rx6KWgAEUmLw7YPVN8NmttNEnh0UeX5O4bNxg4z8XcgCUqibDiAIuQmUbL59f9" + "r9uXFY8I7z68WTFsEPRMNm+Srq7T/RpA+QVNW211+OOegiTstaVom1k1ECjycg0xbWaKMrNa" + "7BpqmkzXMEACzK4pkADADb3VzBewFhEWkKK1YuEO9+4FKgbS3KvZt/Ff4+oTC9TqKFYgyba/" + "/vUF4/75uak87n9lKnNuXphPZv7mS4AXEwRBJr34fDwJHH2vw81NqUcmqdaqGch8UlBC72v5" + "zMyZE0Rq5hTU2ig1ophJVz5cEsnmrkDz5heOMnm4eR21idywefXaatHLW7Xa8pwgU1TqZNpC" + "G/vo7diPl21AEVRb9zBcFbJYqwYUb76PvbU2OSULe5Hy0Xt4Zj7zGd4IIllHr63OM++P+yNz" + "1EbpnvfNQi8K1r3K7JreSQJQWzV3M0uKSrNaq3l5z9wt3Ird//qVKmEAdL9nZpqkYkVaEs8s" + "sRHvPgpmBnzjzqjRWqsxJD3zXtC+7731EWHVg5QVb81SKirt2De9FlaxDcXNYN4C5XGmyNaj" + "xgekZGqpjdFaseoizFCE8LbZVt3NbN/3TTQJUcGEWWw6yTArZjAriOJl9PFxHDmzWJGZwEVs" + "kG8GB194h3CKEAC+BCkJdz258v6gEBugDQ7IhCdQAFiRhAtrAEWSKFl58Zz3pCTKh5+3+2al" + "7h8ttvvjzJntOLSIjSlSqGb7vnv4Ztuaz802CbYB18QRfOYqVjz8OlFm3uczYgPxuD/ujzul" + "opcBj0wTim2AK3NmVveZaQAkkg8mf1OZkyzSSX77+OeHoPk1SW7YiuDexqit+eRvN7vN++P2" + "mDOZ9OGbvbz1iCbhmfkS7QV4KJPgdYkz80mNdiUdYyqfiU0URC6eL+p2m3sdKYoYeyvh2FB8" + "RI1eG7FJar3U1pWaeWt11GYQDLaZAPdigt1//RpjKEWcQHnmcz6y2AbIzDdumXRHFJcJ2Nyr" + "t3aBBVLVDGbPfMpUUMzEF0SpmCmfeTIFYIzhZmY+xnjZywQPn2f25kwexzHPCfD+dUoadVhA" + "6z0x9uIvvXy4wa5r6iZR0Uaec3GZKbwJcKthW3gDBDf+lknWjDPh3mKMo/GRCDN3kxWDgG/2" + "j7rvo6A0KxWgleftV/XxYH60+o7LMG+4+opWGyUpESZKWi+UWuz29TPULtKxWCkAqTr6n0uf" + "z8ez+Obm4c082mhz3hcQYU9JxPF9ByT3PnpKj9vXGzpDPnZmnlOby2CilqkV99rm4/7S6z7v" + "oD3Oh4e3GtcYITNXnriupjBG694VAGDFOM8ltTGsWGvlxc3dHXbPe4uW55TQ6uBkGGBlzmlF" + "zXxOfeyeT37sH49fs3gBqFxiCUN8NKNdg0aSIhEwmLcO0+OvBzPbPsKGF/ThY+zbVdoNAmEO" + "A8wcKDVKCxFUSrCwzQs27d+P4fGyDVaatW/H/7lX2c9fv6IYVdb9Nif/++trH21O3uYvCcf3" + "43P/EaO8sMnMA7V9uKG13vbhBaIyWaCCaF7EdWbCsbdh3hzQZlQqRWxhugb8S7rGEcODUPGg" + "1FuV2TknM32M/fjeW3WzWurM++P24Iaw0lrPxftfv665dK70grHvrbbaKi6S4hqxb27F99a8" + "eos6V94f95desFIuZCMp+eQKhIybCgCTnlycc/Qm6TmZ5yPq2I9DL+aT12w2531JpJoPM5mV" + "X79uUWAWJIHVx1777sVaH4BeeIWFKOXZW6PhcT4uwsFLTdFgffgYFcWvIloga/toJkPeU4XF" + "ws1gF2LQN//0F7Z8PCTNr8e8yQK1e2ZyE9dV6ps315Mw+8ePH2Mf0vbIySd7c8mo/M/9ILaL" + "1qq1bVaKlzr2efvJTQ4rKBu25gC6dJ4z949Wx96syThnFgm1Hfs+8zG/7plZw/cYMPBkKsNj" + "/MfRrFxn08NLazlnrgSJ6MfRrHR3u1rbq2sIR7EQFrDldSMni8u9STrzOS9Wz8P8DZmfj/vm" + "kCJqiAtAMXzNaS95sVy8Dh4bYCWwfd0fUXC/Px6PR28f7SMcleLJ3LSJvM1Zi81kLX6lB1ix" + "cN6nmVuYX0iU8ICsMikpMxdXAQQVj6tUj313v6YZgPTk+rb/1+5/emeDoeg4vo82kjn2fd/3" + "VhsCfPLNp/xmQSkOXA2ANM+8/3Vj5pNsKv3zexsDG8/U7zmfWhu3PhxbBdKjW8Ht68HFMfba" + "qoVhszknzHYPFsv7JOGj7h7j2FttJcrj8ZCkeT5JqTS3a8YRPlqLFiM+yrF/kmo19LKXfrfa" + "oo7qhRBUpGXYbo+7kIHx5DPzcZXri28yQQ43n5mADS8fx/f7nMXDrSQ5MwWQTJDJl14fnx++" + "2cwctanYaLXUUC7idXHFqby2SxQlLzLzd4IgT64YgUUVM5k1G3UftVw99HULr21v1sY+Rg03" + "s3BmXlPO4vFt/PCnlc/9M7ZycZWTEwUqFh5mhoDDrZkokj9//pTJY7RaCDD1zHueqQ3NTF6U" + "+ZiT1H704/NHLW7FzFzi/XEWKyrSTBQrVqTkZnsfCAwLhuf9cXK5oflVBsjfnLdZRwUgbMVK" + "MdRWJf163PfezMxGNUEvcaU1E+EXri2g9MxnnonNwotI81qgv25fnKqtx0eIWvOcQLB8Hh+w" + "smG7WMyi1zsXvWThZvauTdI852jjcU6SSZpUarsqLd5MnAzWaqujarNajNC8TzMpIVttH937" + "RQHBqQTBgiimST3nbd4elHxD9GbFILta+ySVTyKq4Rs+1Ir9+PE/Zs7tkhdQ+94pvY+wuF0B" + "lbm4xnC3hmJk8p5nJqBRxnxOC3zuxxiHN6+tCjbnl5tLymdKSWrDZrDNyjWbt7AOK31I9LEP" + "h0dtEa3tfdS34IF8zmcyA3Ed5DU83LAZMCdL3SxxijlPYtuubqAoT53M+bjn/ZGGWrD52I+9" + "WBG2+d8TQj1qQbndbigGJSRr7YoP5ZN6PbkEFKl87KO2MUa0UXw79qPU0lu3YsePo/AVfZjZ" + "NRjyQFKpNNjmGycFenGDkZQAA1D+8eMfMSKwPbVI8UlRmY/HI0WmaHILaZk2vfSiCLNazOBE" + "LjLJbz/+738Ytjnn7edtHPs+WjT/3o+X2D8/92O0GhcLSFyjiq226maCtNkGSkV5eqs89RIR" + "pisrUQnlfZI0Cebhm8lphKG3jnLlLU9yno+9DXjLOecicrIY3gkHUoY1q1aLodRi2xgD4WGl" + "2Oatk1kAWRnDUfydgHQR3PBW9/DysffmWMxL5wbC8fn5aSZs1sxQR3iQp0ogU1bcfXI2b33f" + "vZiKqtfx0Tz8cT4AF2nF9r6zWA3HBqx3+pMUQvG4gnjleimBcmk0zN1MEfac/O/50DmTtDAU" + "eKlXqR117P+xD29bFEnNmrmBV3mHoxSP8PjW/tEMOOf5+EoL5Mmyme0NetW9FmuAgKJLjvC3" + "ZK3IZAZ4663ohZL3x2R6qW0ULHGTefXqoKqZtXpxUxShBWteLM+8FA4gn1Bto0jRA1MpGukX" + "tqRkyDPLJlmrRTPzwuuXaMVbZealchjj45rEApuwgHJdHW97LxCAYtcqajEbvWCTUKzAyj56" + "Hz1zGgolOGrUsKj7h1cTpSUEAvGYWYsf+56vK8Qg0NwMpg2ZKam7Y4Ro1lCjvvS63R4RIdMz" + "V3iAesxMJVLWUEvPlZK8eG39KoJWzFs1WRvNIAHe6hUlBli4Mr+Nfw5xvcvrJEFRZBLYSmQ+" + "JMvMfE6LaqSAOroteauP++P2+DXaTnK0po3XkEoABWwwWM7pzbh0AYGFlZO4ZkYmD6/FVWwT" + "9WLz9vPXDZC1CsBkFubCS9vX1xehiCLi1/z1+PmA0Ebz8Nv9UdxXPmkKbX3fX1JrdUMpphp1" + "nrx9/cw5iw+Jn5+fn//zc/S9F7PhR+ssVgNc+vnfP0ld3J6ol17XPLr1xmRt1bwVwDxEhiOp" + "S5CXT9kL+cxUfm/f66gWDpHzlDYP5zzbGO4QIWnjZrsbrIYRFwFHD1c+yYvFunSNyGcm0+GT" + "eWGc8/FkzpReegn45gfyKYlmVmGE5ObNwpuFnytflJRrLmZ+3f/SCxt5qUUkhV3aL1DimVYs" + "avNwb7VWM0Myz8dzw1Zb5TxLvfQHCgvBanECl9JXoqgnOR/3nFPSi68zz5e23n3Ox4XjRXHR" + "3PZj//j8bB4iRWYmYG2M48fxOfbHnFdbiCIDihUBc2bbw2BbcplAkwmweX+Qkp6k3L3V1mrb" + "QKCguBZzZiqTqRdEmqN5WxSk2znJZ9F2kpu0tMYYJB/3BymvrZrNRy5kUQgLLMWLV++tj/Ap" + "WMFHqzV81J2batQKY1He7n3fR/jMpOjwJ59FStEAyMRM0gB4INDhcI/gWsTwOAGsOb/O+D7O" + "uYbHOU8Q5LwBPrpPD4+FhRPgWoTHH4Hx+yOIBWJyBuD9B84J0N3XXBjwhYv74nLHIkHn8H76" + "uiQLHt7RsUj4cXw/ieFAH8H3/IVzfZ1fi2scxzH61fXc/nWb62sR4e7hPOcigBUewy95Qyxf" + "gbjhhhMY6KPfbrfr3USPHt37mBNY4B91ch/feU4H5jk7OvEWlxyjw7vDv25fcPCL0yeAxRXA" + "pTE/z9sYHY5Lr+GjX+XoUs6DHj3WxQcuMHhptU9wnuSl5CboDOB2KZ7DhwM+ArDw8Ufa7h2O" + "0S9Z8Y/R32fSu2N6+OJ6i94vnpSExyXWvqrLcPc+CGARuMjXP1qQHvGmKt/Cw7dWH3CihzvG" + "pTb34UccALj4VssDvM1LOb7oA2/6lACIPjrWRYE6AZ6cMRcRgId3+JcDc8EJDB8+b5NOhNOJ" + "S/WDcbkNHBh/JNfk+UdH4x7o3sPjHADn4lq3NXqsr4X+5p+5sLAw/3+F/8Wln/MWcL82800y" + "o1+LumjcC2NM8pxf8MUzJhYwMMIHMG+39eP4ccVqeHjQ3zsZAMBl600MrzVPfD86HOE85yQd" + "dPeBuAXhCAKj8+fX+4659z9XLjzWPP2S/pNwv+LhGo7E93HtiwfOEyTh8PDrpDEuPt8Jvq0O" + "f5Y6r4gD3N3hJK+fub41PBZW+CDOi/jGch/u9H78iVuwR0d34Fw81w34o8Y/fhx9dA+fa665" + "Ro8e/a1hwtt98Ob8CQC3ecO6huOXCSDguN1uCFzahHEc3X2SADHhHSAWHR5H9zlP8jImLMIB" + "5zxnONa8YnFhvR0lHTEXcSmbPSbgwHJg/a1n+GOPwAK+2aeFx5mZ54xi+75DSvL+dZtJ4qUX" + "eE4IEpvHzFnNbdQgfd8vS0c1K1YAQKLjY3y0YwQCvuk3auvYKCqXigRg73vfK1+ApE1uHh4U" + "9RQ33O+Px9dt1ObhViwzRbXerl9xUU6+AR6Uvv79l0RJNaoV92p5MvnwrV93S4sS1xRFk42P" + "UUyyaMVlBqWX+rLSw7zvrRbIrJooAAZQvGr8/cwwM6l44OoUPeyl8f2zjRht7N9H8ZL3+YdC" + "hQ9/YYPAeV9mIoshyQ0FwJOkcrPigDWPiN4+rFkPF0qNqqXaqqDb123j1j6KWTddAvD3R7nU" + "/FcWgvvCH6cLMH4cOC+fxsTf1hfgGN+vGFiOfqnqvh9/a1vIy8IRl7AD8N6d8/3ixTN8jKP/" + "7VOZINYfxcrlp2LMef5tO+I5F9ck+/RLNbMuSWQ4uS6IO3y8r8aafgU/fK4vR79y9eLiogei" + "X4UlAphrrnOBGMfR4zLonATmYh/+x8WFy4/DxTG8wxnOc15Pcbh/PzwAOBd//ryteV45CVhE" + "+IIDJxYXhw844HHJe/rh1z12uIeP735O/tmRy1c2Lg3T3/cejO8DX2+h5nUDAYRFD8ADYDAI" + "nvNa84F+w4m5rns2PPh+0w7gdkkn/w6HP3YvH05wYa0TxBo+1qUvBXyAxBg4fJw8L8nlmgtY" + "YPThPK9148ePH939nUjJ8AiPfnzHOfnHoPXO2Oe1QC4u3LDe2ZZXSF7FoocjDvpcc91ut+M4" + "FhaI4eOdoC/Lk/tVljDp4x3YHNO9f/kk2aNfuOi83Tx8fD9IOvHz660XPbkcCAQcmAHHnLys" + "SZfM9ZwYjuUOx+gHfIDn120isOblrHsLzyYnz68+OtfPY/Tj+3GNNt3/+U6hb2TkHv7t+MeA" + "Sbl4zTOAIrU+fv3730rYJgPw1EzO+RD12srJ5zwni0TtH3s/Ol7ej2rFzQzmj/uXCqq1zKeY" + "nAmTbz5aEyw5a61JoYh56any8cjW22U98Vabx8zHMymgjV5HvxYmqlu1MF62nduDzD3GhuKO" + "cL8/7pf+GkDfdwNotn+00UZCFtAUgf04equ2QbKc8ySLIMlb97Bfv24bthFOISXl/WSGxaV3" + "jWKPe/74H8elBSuI+Zx6aVh7MJuFw6XneU9sDHcJZG4eySwebW8Gm79JTr65VF0z07fDRKmF" + "2urRB4rtx3F/3DOzR99s058EUEetreYzv7V/DrsYios5eyY2bCoRLQJFrTm4mTJzyirGsY9j" + "7GMvKMWKNRs+4IXMS85xJV0Lc0OKFX5Z0QhSNAHFL5rksp6MOjYUEJvoVij1ZsXC3GKzEuAS" + "yR4u6pl6kRDPXPP2yLs+/8f3j4+9ul/6uk0bDDKr4ddboSTx6z4XGV6KlWGtX0NzMwvzVluz" + "GpUb9FRqNpQzn+LvGhcKa6MNawYahV5Ha8WjAzSrJ8/5Nd18HGPU9pzPjVyCSdGGe9uwFQNU" + "Ro06usFSacXhxmc6LuIC0lN50UG2t3p8ftbRAxuKvfQCCZd0OeKuFpoqxtS3438NEgZsVsgJ" + "QcX4nD/+89OsuFndx8ZXacZM81qi9NbNTEWCaqnhobewA2YGN3/BqhviwgL3+YRJD6VUfLtk" + "15SWnsOHj96L/fbXojYr7u5b/aOqMgnPx13YtmIoFgaDOeyFzUgVpbS9ZLXMyWc+U0kyrHh0" + "qxCVi2SeX/c8p212maqs1HzOnBMybTJBZiZLPc6vcz+OzGQqRuEfeV3DEE0AACAASURBVBmf" + "FLO6+aiQJEwmxaKCAAqaNdgVQ0XX1M6KmZ65JJRazL22KjNscjcjUNz/DPzAIqOE0Uff98uK" + "jPIenRUPCeFxefkeohEbXnAzj37Oq6v9A9WBc/HrNt1BLl+DXN4H/OvKw/Oc74bpb9cql7+d" + "zhGO8/3tBfL2deOiD+fbmR0EPAgwcKmQvxzeo58/b1/8+vHjB8cfRW4fV2124Pbz51uLDE4C" + "XFcLNm88Mfv3AyDXBPytwQUvaPCn0vnfDUl4YPEkOU93xLWY0bt7R1+O4/t47+CCBwnHmhcS" + "QHgQEyCnE+gOYOCCKuBk7x3AmgvnJfq9ehOsuRbWuzbDr8ak9475pzvwCIzAnxdd3uM/sM7D" + "fcGjnz9PLFxNzfCB8HeEXcbna3Lh3ccfuLPI9XUC6MP77H/bVtY8o4+rE15Yf6rrineneHKC" + "Dl7uleVwH4hFLF6i796Hz5MI4MQbPsQbHV0+fSzA13UG4c7LnTPPRRD0hb+PhIDHdUSA09F9" + "+Lyg0eK1ax5HnLhizx0eFzy72kg4wMWvNT36O3c64Jhr8iScTn/bfW7zOjYQ/egB/8mvxfPo" + "PxBOfhF0eAA3EmD4ER0gomPNk5NfQA+8sXUP/LF7XzLtNw5fRGDNc/llNB+IC+1z9OEd5Prb" + "0P0tfoSSMA8gQQCBsBrHqBb+4nbNM/tn39Bajefjmcy8iCeISYtqFuQpWfi2IBFmMjiKmooK" + "Rh0XWcqkyOKbR8fG82Rz3/ddVl7QsR8fe8Vmeeb9cZ+PxyXBHB77+CymJzcoDUDxVlwSiz72" + "jzGCwMzp0Y8fY+87XjJAxSBZseoubXlPKTN1pVNJUaOGSzLg19f9SsIqNu8PvN4CnKVFsrUi" + "QRQh5bP39si8fd3zzLYPGCQ+80myoEhbKh0+RohXliqbhxuUQrOj761Z87a9ZaZPqZnhsmOa" + "ROnyfgSa7W5LMBN56TeBbbPizQD7Nn647NqTCAtJm1Ha6uhvK4mpWUO4MW30zNnMJA8vlwcV" + "xUDO5zxn6kXIyGlmgJkgcGOpw1R84wuXkJN4YbMCUpvJ2yBP37zu+6hD0j3vjzOZiWL7R7Oo" + "F3nIeeeChPcoIXzf6/5xWPPLzrH3se/74pIZpesWXjRMksw5J0HikmBuKiowEPg4jo2EVGrz" + "gDYZzJp58YKy+eaqVymuZudkse1+Ox/5cEO03cQzBSosVA18asNowwzSOp9TpRUtqSys0UYg" + "zsxi5XZ/kAQKrtIvs2Is5kUvba0WG374wU1WLEnmE9jItaSXNge+jf/am5Wtlt68x8dm2zMp" + "aYuNj1yGQKmjQppSD/+P8R8+arMNzWqpAFB0PzO1NDOhTdsFbbAhF5/zWSBvwwAPlDaKbUmN" + "ET9+/NMdVt5mVq8jgCuQX3xdgva9H32vEvKckoSwjSrQEorCW++7DwcBAwsk6MV///vfYeWy" + "G5kZgCQxF0VSBsBcAIQYIcnNvFht9Tc2kF7cvEKC+Xw+LGot4HV/U4BIzfNx/Pjc2/54zOSM" + "1va9Fy/mJmKJZta8udtJajLz8chE0po3lZ+Px1///teT6+v2pZeuyN5S8g0CMy/LHKlNGwpu" + "t9vleLEN172dz4e98LLy7cf/8yOTK8/WmvCW68jKRvW9l/BLeM9FC+czLeznv36+bPsY1cwR" + "0FObWdg29qNFkejRrYgrQWXm+NitGBelix218FBBQ5GXnDnPBzY/jvGkwsrkNFhBGcfxMerj" + "TKUWn8VKqz4zHd6K5VJEvMetwtf962N0bDbPx8V6FiuLF7mK6kbjaOPtijcdYy8R0Dql/3n8" + "Z0ICQZORSRQZzKvlQxbKG+uo59ctxYJIPbz0Tdv9fr9KxtiHUhTMIJ1KjM/jGHVOMqdFBdRb" + "tahhuOXUk39zhNefT/k8Pi3Ci0uqrSLAB6Oij93dI7aXtsykcpReIGv9+Nj7Xr8d/8cAtDG8" + "GbySl8dj7WOf5xTg4dX9Nuf8ukn6zd95PqK1iyPOCRk88LF/jL6bhV7voY1SJ9cwE7Zr2qni" + "VDrMLiMVOe/Tip55aWQS1PXHeACYGYrhkjCIpTaXvNWNWzGtS3S/aa97MpkUzArm+YBj+DFG" + "e4NPXNK8i+S2i1KHoURz97qP0EvFvYYJ3C4pP56pF6CcMtVSaeylX6QrhDzpgVZDL6RoV/00" + "k1O0RcIQKikyeamWWlx/KaQAZd6/ZHDzz2MvPq7w3rBJqs2wvX0zxUttY/RRakFaIm0zzGQY" + "gDDrY8D82/jnfqldEKYnLyVlzrwGJf/48WPeH9wwwjfEI7+MJjGKyUPzibo5DM2RoslQyAnA" + "vfdWC7YrM1yxRqXJEE6owhKEWFttzUvx7tWqzdsEQLDC/qh5YWY1XIBk5nhyu86VUhvt/DqJ" + "rZiuAaQ3O9o+RWbau6mDSEj3eafgZvvYL7dyXoJ7CC+l5MBJSuuaKDEvuSVEWVjRS0AYMulh" + "m8fuTS82HwsrahjtyRNEVBg25vNq/TYVvyLJICGTbvBRj323UVFi06s2UwGfume+Huep1yYR" + "vIpxIn3z1lr00ayER63t0jZ82/9rR4FB/x9Tb7AiS9JkaR7lioAIqIIqhEHYD7G4DVmQDX9D" + "NUwvZjEPMA8+r1CLv+EWRIIHuIMpmIDJhePQC/XImoRMgiTwMDdzVxU9cs4nucoM4gKIdPF7" + "nNsY8WQeMzOvPIeMYID0MbqIjdG33VqzFXZgUiCJuAJJ+Ot/SJMlSeSRstVe7X7MrfVahzQz" + "Cl/OZD5uj5MsJOKC+TrASKsI1lHnnMtdUJIUNh/i4vBipYkRzIQZQPzr61P5vM3DRRfTIjIJ" + "PG5fQgRjbCMJEZ6JJoBIRIibAArMSJAC8a7mloFjfibUzQoKqBEPwFwdVQoVhmXgFJPMBNHM" + "YcaXyZ+3+xE59SlnslVFkdaGQtfbX7qmqfFa7vuLgFeFAIl7BDNjxpFHc41HkhfJFTtBgaw0" + "Ptw6bB0pOmxeMJjldczjuN0yc7WpYOu8sxTt7uZ974vBlbhywpAwuw5ceTh8yfDzuwN85LVn" + "x/cJcJg5Vq9vribmamUAuP5LNcDq5yPXYQkwWLd1ULNrxWYvALe87bavhji+8gLySnSkm33r" + "FquXkjfc7GYw2/dhCevrkNjNMtGHHfPw94F5GcxgaYuhdkvbL1z+OokCuFYb9sprQezWD+jr" + "zJZm6GYzkXPCcGCa978Pna8XX03kebtyLNxFH91s5Lfe/Trnr9bPhb53rI77kUcenv4DHyC0" + "gL11qwOgiYnXldvLzL8+/zK3/W1vo+XMGQ+spI8KgchnZEZcGZnXRIEIngSRjWpbNbHIeeap" + "0oBSkHyKNBMshBEJ8JxHpDpc2jKlFZa1BpJcNC8CmSdBh0NsrbLItaDG45z5SBumorXV1tqT" + "z3xSgMInMtMgKapoapPRrcItMwt0xVdEBMXymnBTlLfxFvmbJBxVjRGEePW4xxit+RjVSY0z" + "UDJJF48MEWmmhAqYcTHIqmDOmIBVMTRx8TNOJov5tg8AkTPmy49TtyrSBkADIaZUr6ZmauoQ" + "tduv2xNPcyNYWGD2o/+zI0nQ2xBh3AMFEEqR29dt3qaYbG078lA+37Y+jxRCRyOQc85MPoME" + "kKJ1VSFIzkiSzRvJgwmqNlHIlWfBs3q33oQKoRAzIx4HkyWz7mMFYv9OVp55rmWqScvIYkUE" + "mSmUA7lVU2munsjh40wWsLYqKs18LrJZBIgixUTFWlPR1lT0cT5Y1pERZD75m0JLkbEOlWCc" + "FLcmKk6y1cbfMfa9t24uZMYTAmm2TNxw+Mljq4OUM2Zcob9BsGklUrw6IebLfgDoQmeBUNE2" + "2ssrzCDh1R0KiImQnFcy8pgHZDF2FMAZJ7PIPvbbNTFfUIL13Xwf71/X18/3n7PP43bA4BPW" + "DcA+xu24/c0iNLxWqNttjgG87BFLFQOAeU3/lt3S179rURg27CUy4tX5zCsNmEB3ZGIdCZZR" + "Yx/7WlH+fw1DOHD7Ovb3Aes9j3WFNrr34cD1aiUClg5cefU+1mVfuZAG2PeRiXn8ysvg2P/8" + "mcfcrf/6huzs38vdEt5gthxKS4Fc5o++91WFAZhH7h02DBMzE5iGPrrnMYGEv3RWJPI4fuGy" + "Ce8Os259fgvC/u7XvGbOV9vyZcECDJ6+Ng5zG9iB/LH/z/1JNCss2GQTlWPeiuiqno44pZCZ" + "2/v2H//xq0AFYGGrW9/fpAhJU0ly/7nnSsYScLQ2xFsc8yKaV6gAIpACXEgttm3bKjsnkpE2" + "rPXGwseRBpCgiCKP5Gr+PfkEskDximWRyYsXmEGO0Z5WBFL3DgJW2qjJrG3842N07/evCWZE" + "qDQy40wSHx8fmfz165cAJlWaNBQCj0hwvRXdtp45SYi4gU+UI45nBOyZxBUXJFsbfesF5cSJ" + "J0ptGbHt++gjfmezJtVGG9pU4Z+3z8iwbbTmIN384tXaMBEblkdExL7tuexrX5GIM/H4vD3i" + "UbUSr6DE8qsD+OF/OhanTY3MvLJAPz4++KSpFD69j3l/lOLyqrpIkbGNVhsSc2UFI7ZtxO+l" + "n6zP6qqn0LY3E644RyJBKESagBkzizxfqW4RUCMmIymvvqNJU3NFIUnGGHsfnYzj6yQYGTxD" + "tEJSZbyNvmT3GZMi4BOACwA8bo/CVBGtjcnjCHiCbG2IUJqZVlFC5IkiSxtsVdz20TMTECHF" + "bTKuWNZCJxdnFW5tBUJJFnGvCkj/zjhGRJ6prq9YT7LtrRVp28ZMpd7iMNDFxxhqyiJg+Gik" + "yjOOOAlFHvDaR93rUPPaqpCRL0lWllcBA8uOllce8zj+v9vP//7n120ex2282FiXw45r5oXu" + "/Xa7LeNlJkb3vr9fid5tmb8MZt2Xj8++F9yFfFn4VPumdV25Tg6wv02LeS2PZP5X4WcwXPN7" + "OYYtB6oZYN3N+xijjysvg4/1FOf8j+PXPkZan8c8vm7AMq5eC5YF9MQqrZchE2b7WrHXn8hr" + "GmwCec1vFg2QVybGz7GsbJg5r8RAR//2z6bhPTGtj/mN+52YfxNzLlw//efE3Pu4XWnD8ILM" + "4JjHWL/ny1uUsD76smmO5ZK1v/8MvjljgNiw45Y4ctrXa5Mx4MLtdstjzq+EH8g8lj1wGZk8" + "X0heG7buJjDn0furan9d8N+tqdd/v2G6yxjz4vxemS9U0RiWVy406Or+vFyX3hfnZx6ZOS9c" + "jrUf2N4H3EYf+BtDecHguL5swY9fQZDs1m0V89aBY7n5rnnY2h1XGzSxTKoA8rJl+AQskUce" + "A+NKmGG3flvw4/eBefnfn6s0M5uZZoa88nq1ffBqZsEMDve+GpToo69PUyJxIa+8Ib8/Dbki" + "78fLW5R99Lzydrv9/Pkzj3mbCSzj5PuP/X/sT2RvXdRIAskJNsQR2+gprCrEEl4T1QQyxqaV" + "kdKqLgGluOcxZVQTByALyL0M8Wbkq/V8xVlE9za0toi7EEnMI464MyYXAFLMVPKVzeO3t5O1" + "VRQkcvUWWlW3Vkf/448/qAtK6F71mleS5qJEdSREkM6mpnV0ccxgZMjJto/5+VBvZ1wqpOjq" + "JEAQJDKt1a0Paa0OW/rZqtT2n/9gMCJ66yvndszjd/xmBlR4Zd03JCMnApddLn7E6abVTUZ3" + "0XU7pTbO43FNPihGQEBAwZP8navN8tfta84pgG8NgWQWlMiDQUi6DehrL4SpLbUVRWI+VpZ8" + "1A0KkK1toshMEyFznX2ScFOtTVGWriFq8gopKES57P6kmHU3cWvu0EXgzDgiy6J6BACx4bag" + "x7YKaIj0Ua0OYcSZWXLrm6mtzEptvbbq5tKE5JlU4IorM0HizEi8oBYEeK3YJgky5zHNZdRt" + "xiMLeQWKbfsGKuX1USPpom3bVKiiUiQLMkIMW9tgiBnr68fvfwoJ0WMeY2zJyJc5ioY2YypJ" + "USlwIFLm9ahPzCs5zyNX3ILkiXze4/gdAVEi8VvEZf/46NptoOTziFPF1VTFVwJSVuG/nHQ/" + "f/4cfeR7DuQxryOP5aK3bh07zObtKydgiZ/7T9gC2v9tZ/gv8zXmYj0uPPn7/u59eCbMj1zu" + "fVud97k2zm+0vnWbc64E8zAYOvKaa+E/cNiFF/D9ReO/gOPXL7Mx5+3r+DZEArfbzdyWmSKR" + "S9V5OQHWacRGIsfYb7dfgJnnvM1FW4K9xHHzjheT0tbpxLub92U8WCvb2u3eR88r58v/iBcb" + "M3NBLxP52qozb/Own3teicT01wXnlReOZUfJ9R4vIG94CVjruDUXTj2P6bt/RxWuKy9ZNcMw" + "v/LIKw8cuVberwNX7j9/ZmbOtN18+rRX8sAyJ9K+TTJLRXvZZPAStWGe8zAbmYl5/G0mflUi" + "B47vvWvh9NdF4cKFa/38dcwXkh5mezfDzLS0NOACOtwMueqMb5MMAGB4vx1fvpt5zwvIA91x" + "fbte85XW6Hu/3WBm3sdxu72sQ/b3DXoh7oG5trZ99PE+jq9j1UHL87l29tvX7euYffSfP39O" + "pF142UoNV177vr+jzyvn7Yb95Zxen6cjVyZwJVIcZtfXAczXL9i48uhX3uYxvkXjYx6jr9LH" + "3fBj/3MsFpKKv21vJLvbv379wpXzK8fHZq1CwMi3j/eSNBeQmWi9mRtVeqsk/+Nf/6pNrEht" + "tdW20DPzmKvpk5nkshNwibPHPDKi1WbDcCEymDA3FDyh2xh97/I0Krny2hFSRExUVK2cyZLc" + "/jG+YmbkitVXCEVAnhmLUf87s9qAKUHxyohjHnX0skSRTBQTFQUzkTlXgJTBlJLzUNG+bWZN" + "FKomZmM0tcZIIJ8sKnrEqaKF3LdtefVrs/u8k7n1JvJiO98e95Ipjt8sZkae98dU0TymmYzR" + "j8xmnqSCmTlan5nNRWsD6aIwqyLxXA1PDHM04Tx/yE9DBAGSjjIZVfs22lPUHGUl/92qW54B" + "eCa9t2bNmgHg9U1gyTRrWx9j340CwUnO//2wYW6juyQz5+pG8pjHzMmLbduqmjTp3rPkYgNy" + "UbEUUtuwBl2Ba0JBMmOhrS8XT0JACkxQpbKAEZlo1fPIZGZmKZQxqpoYMhLmLtqrWatMFCSJ" + "Vl2bSwFhAMVkSCtSpIlZA66l1G7WZNSlgN0+byoKw+tGmFur3Q1NAHvGnEEXUBZVsmwvpBVU" + "KM05M4UuPrZtGwPmKioA8+r7Pratt1YWr9cMJMwWbH+Fs5soRUAQ5cf2z00XfossoohLmjcz" + "0+qmR5wl01rjlb++bmraXqWdmC2iGBZ4b9+2QgEYc94eN5JDWiCGWx2t2YiMM8+IyEScX6DA" + "0VbCVNCsMSOuFFYiAWEhkgCYPCJUICqAiaNAWnNrPTPv91vyqcVA5pVHnMwogI7mKnOm6Arl" + "L8YsyqKAiJA0QaLoCpEmyBRIM2l9WLMEzsfxm+RzubkAcVfD4nR4qV4X2vKe6UvPVTExIpNP" + "Ei7emwFOnn0bi/fWR6vWiaKgmXZ/W8YfRuRr4oduWmkS66sVJ6kEmddJqqgZIC+wkAE/fv7f" + "P1e8zWAKHpklM1FMEWRZIUKAwOP+EJVcuOCMSXKmValbZQqZVKzMe2bGGVDMOUGZMSEwWGSQ" + "HL21tlNTKDB/Zi7VLL6bFwYTBy7cI35HfLfQtIC19VpN1LY6fGsCzvl7NDOrVgVPrOxyMxez" + "OoaCFFn8eKpYW+RBMA7CrVl3EwEoZ9zXdkppY4ihRsyISGFzFamAMCJyrqSVWDWRODOR8TgW" + "2ieR1WtkiMrW1uZlosyZkU/GCVHzugANwDMBBqEpNBuynrGQ4cx73udnJvOMLHRziKrQrBmq" + "OA0VDeb1h/90Asj03iCax8wCFV3gGqvtbXtbkRcWuDnJUT1ErnmsR1LU43gksJhtJB3OQp4B" + "SkQkk09m5Nf9KzMXJq1Zo9CtWRMASYApijPoQtNKZUlegAoIRV5qi+PtZEC8uRS4LAFSNDLy" + "zBcNzwxAbUJoQYEYkVXtxcJk3jPBVD4TYK6tOgFJUAg1xytqxyZeva7xFyuxfUQ+vm6FTyqT" + "6F4TZTX3126ZGWZm1Zi5sLwXg5FapY9mkBSAEEUGzzyfLOIUqeZWtcIpsOV/adIwpFlbfcTa" + "hhWEJi+IUy5L5g/bTUGt7X1/j8c9E9ZsHWIAfGxvzXxGMHORrBVuoxrliefX7Wudn9bStI3x" + "eDyOebj4usR9/9g+tm3bPj4+ihQ+2Uff9319IZ7UPnqtBtjiDnItGQKoGcTc1CGUjNP7MAfM" + "mOvIlSoNjuHukJPn4x5nHhGEaPL0NkwMBWvADtQEL3ZaZiqKUu+xwOEBZn77IkZv9g1rCDwV" + "V+L5Em4d4lIgEBLqkDoMNEUwgWFvWwcUCCQjEcf9ylCBSlOD2ajNIIhMXrE8qiqrziTJLGkr" + "RnMtwWptJHhBdsgoS+hZViMmk3H+2P6sMBjaaHabk4WtNizuOHXs9T4jIs48SCxWyJwzI9V0" + "jCEq27b1fY/HAwUAlAoDQRchy0IOi4qozDlbbTY6T0rJVHSxXMYDMzxJEmLINd1EICYElcls" + "bSwuJgkYBAakwusyBDP5RIG6FQpcWm0iJjQBmGcmwyiRKSq1VdEKobKQSZiAvCBKwNYjfNmc" + "4ggCSbWyTCSmZk2aNl3SdhEioHImN69izQ2ArD72SbqI2ahNkCV5iqqI5D0OXvMR83i0NgAc" + "67FEFndeM5NaWxtt3/bihflytwqEQNUqznxFaPTH+Od2zCAo7o/Hw8y22pI8IiAQ9Xm7Ldif" + "kIQNk3lGMrdtq60+qeayBnGZGQrAvM+L54Qbk2Mfa/G0Pp6ZF6CrmbrQPkXieGRZIrstO8hq" + "1Zv3pX+TMkZbwsoS6t7G8o8HoM/Me5xkrj0ykwqaVzIBAzMP3L4+M9Jr45rERWbMZRUKSZzx" + "iOitr7kg7g2KXPNp+IRw1FG9wnFERh5PKlTyiPvjHpkq5W37KAXSIUBrbYxRUOJ35sy2DVvA" + "OkiymNftbUDxO2K1tKl0cQghDnK0RgVzWVutvW2MjAhdyCCVedzEfVHLr7xa1R/7v+9tay5l" + "Jd2GbZQUMVJHbxFx+3y8NgYgr5Bif/7bT5eWcYDPM8/H519PK10tyXlM5jXvXytLPfpGRN3e" + "TSQXc3bpSGRrUtsbydqs1wq4CEcf+ZsnUgEUqd1IESFg21t73ONCNpe1kJoNN1y8GLmGSxCZ" + "GVdiDIuTOae1LoWZub1tawkFcPH8t5//BjVzurT4nX3f3QhrovDNV9AAwD3OJn6Pe2Eh5GN7" + "+83ffVSeSREX9a29t7cUiomhwdS1LoYrmU8813i32uzz665Cgz5m3L7ujBQzcwisbducj49t" + "37ZNqux9j2d0NQJf97/yka2rSJPEmvXUmiZYXbaP3VR+/PH/fOTJY56JBCUlC/Vtq+597XFQ" + "LP6VmzeVOKdKA5KiYlYys8Dpdesi8jI2JEThZlJ9H28JRE5eFK/Vbe1wK1HNMyPXZCRQkMHt" + "rbFACnrffDSXMmfez8f9a6pQ3ar19VCbKASPz0cwhEBBnnmfJyOKlJ/7BxxmwuRTnm/+1nob" + "bv/x16eZbGNzUUCyIDKb8IK7WRtu6EQSrF5Ha0fmx8fet74QOUhKkc/HZ85w8z6qWGNGBq27" + "uwnkdtznY5IQxd9ihpuTJUnGuXyVow+35sMNdbS2dp/HZ4gmKI9r5iNvt9tjPuQJrw2C4+u+" + "f2xmPZn32/E7flPxY/sfY+X+C7Vtmy+4cTEBb7dbLuxJ9StOFQV1Lhb/OjdHBAkkRNx9laDW" + "QGoBr0yvbdsHk4sm2a1KbWJA2njzTKww3oIwm7gIH49IpsDMoChHXky6WuZBUlFQRIjx1kAc" + "j4Pf8wJXARk5QXgdUMnkWu6YLFIigiWZ9LpsUrrqAUYJxraNSqtbFUMe64ohTZraeNs1Vsmc" + "wTC1+fmVymYNannMmEFHlaZYjEMFMpg88sKlptUr+SLiW23D/GllPV1xiWua2ipo7zHn44jH" + "o207efAJc2t9VBECRdSW3ZdwKyLW1X5gl7G16j0Yb1s3tcxFFcqIEAoFq36zakw2X1gtUWkU" + "NBFfXH0g8kg+hQjmFZGAUheFKZbRLMlnrMVuzkdmrH7TPY7C33wil/TCXBgIgAIf3ds2eGSy" + "MK7ks7l59YuIzONxLyhArmaZWhtb+/jYAQVSijzl2azZMCZFTUXFMc/E73VTZTQrLB8/P1Dg" + "dSgLVcwrSwpl9HHF/a/bYwmH+cjqEuQQW92YM+4ROcY2zI84M6NtY7TGmYls0qrX1TuE8Ixr" + "1cOr6b9ZC+Kap7bGK1GgWPFtMvNxn6Kyv++1yQzUhn28JTEjhGKtMvjr179+yIeMNig8vo6i" + "Jc8XS/r+uM8rRRH3iIzIcPcrrmDyHqnw6kpe5orrSpYst3gwuabCPY6JTCoyU0UhPL4ucBZp" + "VS0ZgAFSh1mR4mpazSyYvXUU5hUvMr8oBAjGkyWXXZlPPvOZBgEZj1jPbimHK6MlgjkfPNeo" + "O0qrQkQEfGH7lhgDKSJmVqWO+viM2/xk5CMexwxlHMEngGfEPc68/jH+YYLMoPIZxUxXrovE" + "VlsfXUVnPEQE1AJJ0rxWtzjj169faxolMiGyZEuFWpMkmrk1YfIed5emKD9/7r/zySdHH2+t" + "xsUzDpUiXuMeTFYR8wpkFvzof9qTJZmKpeKQydWK28Zo9TWpVFT2vmtVpaKxybAKseYiIu7D" + "37Y3F2+1FdFhLgU2+lbbtu/mlkTGpNgYXq2yiCiXBS/ANQookzwilbxW8SRWkAanXrhetLqg" + "AEEqS0SsxtPSYgCYgwocnDlrexOHuUCtr8G0keKVyO61b7upcGX4koRIiScKIcgzZlB8GKrX" + "ecTqRYP51+MBkim1yj3OQrWKpU6QBsQ8icJMRjxEzLBU4UCRzGy1te5u3/RwIUIoKRAWJjMe" + "3LaRSEmzZmuphEo87moutMkUZt26eZ3XjK8Mxo/6z67QNZ/nmovkfgAAIABJREFUe4AJzEFi" + "ZVnmTDMhWaSsGSf6PWVkAXcXJTZLLqL0uv2Lkjszxz7APCKJNEhhWTfurXXbByg4M5UmtVaR" + "UXGkrDk0KjCYrCZBY04WKAvJZoA1kDGDV6iKoECkqsGqaEKXToRaDYudCh6R7nhrbxTZaktk" + "HAFlHJEk1GTNYAAjmTldWgImIkIRi5m3+220BpPq9jsCWKr1+v0Qfc1dWKafKpLLN6W2Thrm" + "toTrvKZ5tdZFM4NnnBmpUDeFg8EjDhW9fd1JPvm8hM2aNWTk/XaMbTRIREqXrbYf279vJkah" + "UI482mhLe8A66sGe+N1qW3OLihQAvW59M2ud3/zoYkVUuJzgwtr6mlAMypPPI0+HevXX9Eih" + "eU2GSSPj82vVb1GKb/sm3/jauGjlFcb4uj2YXLPwCgpZeqt99NZaks3cbM2NylzGtnkknwUp" + "WkcdaiUTugi2IpEzicf9i5C31qlcfQwpcmS6tSYqeM2brlt9dcEEKNg/PpAprVb34POax8yc" + "OZkyho73TcTN2uiupvvYfDiTn5+fKirkgotCZSHSH+e84gIS1jQvq+14HH9PzYvINb9IoUuO" + "Aa58cgyfVx5xFJQkf4w/hjSprVav//j4R5PGJ0WF5LZtf/eGIFgM8m4dvubXZk7OmHE+YiaI" + "mLFQD1h6qeiMObq7NIqs4FnfunnnGdZMCEKKlwbV0d6sUgqSK0DTW7VuGZnEW6sosG5Yh4dc" + "rgrWVn/P+Xl/aIFIe9vfYsaFy+vYWrVmZi3i/kK3XYQSgnXx3ft93lyd4Oevu4uu+hPKNaH2" + "Pg8II54pVIWpqeic8+BZWMa2zTnVPJG1bs2072+kznnLjIiIWDpCZuaTIeLiFozlbbjNW+Gr" + "KHVrajBoiiiKCEWNNJVyxvlknCyb2bKQ7D//mOc85+l9tUHkh/1pJYsppI4mWGOq11dwZuY9" + "jsdtjYusrXbvj8cnxKF43Oc57wRq62MMFf26fSXJJyPimXlmCul1mNtKXIrXKiZAlqxS05aa" + "izV0nWWxVaWKUSWulCfMzKqAeJyP+1/3OaeK1iaiVVSayK+vr3gEnATcffmjrNU1N6BVnZl1" + "DQUoYlaRTIRQpErJwoWEQXn7+BAizkgm1KBUcZWiYs2rmSQBpXgd3mqrwQAhrTZx32ptvdUR" + "cb/fY3gVkzhzUVUj4pixbVtemZFXXm5lBtWKNRttAGCe9yQyGVHE++jb28jfMyK3bVdA3MzN" + "RjNQ3NpQKwIzcf74X//vP2dGBqXkIzjPhynM6ufnZz7Cdy9QNzfY59f9mfNKFCmYefIAbXtv" + "Y2x99Hjck1yWixUMzJOi8NpERayKo1ZzcYoiKbUJVoc3SLmQhcwESq4cAcoCQTMz5pnd61Oe" + "ChWR+hpkLARaU5e2v21PFADnPCks+TwinwzzAaZIi/s8HveY8ynP88G2WZMmrRlgddRhSM5M" + "KEVrNzMxKUiiD6tvQ8xBiEDk9ZGKZG91vDUWVph0V/DrNv/6/FcSJZ8QQqz6+jookEg58wQw" + "xjZa69s+VhijIPPposvqgNq2YWfk45wKNbfPx2dGatMqdWbUt9psLJiC9SrLuJL2IrTY4ixm" + "fh1zDaHto89rHvPIY94M+9iPecOFMbq9j/+KkJnvA33fX1GGvID0PpbzyABfHLlv/lu+rCzr" + "7y4wnfXx+utryhuQt9vMeVg389G9rwG4x69f3ocBRx677X3HsD2PW34TO2zYdeQrBobhwHTk" + "Vybg6bDL8L6ueubsy8F1Lc+qLUvqoqcAabY7XnHhI5EzMxcX9eXufXlY8OLM/Pz55zGP27x1" + "66Pbcjotg+4K8q0Ms/XhuG5z9tdMSetuC2UH4GXVWoyXC0jb/9zXQODVwUjrK4qLaXJ83RYu" + "/poXAO++Zl++j+7m85iLLwdg/7m/ruUFKgTWy8xFBbqsj2F2u5aB9fvCl4nYXnTAlRZ8vfm/" + "78CCrJq9ZM98eZ4yX7a2MfZuBnPk5fh6pQ8dA2PmRML25Ui2F651fcIMV2LOW8LyyNEN8Csv" + "mM+cC+J7JWBzvbvXZS+uzYox4pWrwbxGd+Q3JDiRRxrsC9PcDHO+Xgu2Zoaij31065mY+WsZ" + "lv5+MQDLLXccmflrfaLx7ob+ajJd82+rHADr+DtvuVzFr/sPy8QP/7MRZMTjnEw2fyUEVvbi" + "jNPNra15v29MAtyae2sMnhmauISFXKOX3I2ZTyZJXCiKewTJJ37bmj0QCVkGFIhBxEWWwFZX" + "3CVIgbeqFBWoO7S1LpYGZswjLtKh0mSxcAWyHJqirNte1ajrCPiCli8OPwIQtWGFpZkl8/Y4" + "GEmkmhKyj42ZjyOSUbVaH02YJhnJjDhn/oaQx+No1mp7zeRBnCIaTEbe4+7Qc54u3ratW3Xz" + "0RufmPPL0YJ5PQ7tw5qINJDeas4ZmXFF/mZBWabpb8R7urW+vcdj/s7fVNb29szAaqqq4QKY" + "P8YfYxvNx96qb2N73RogAWaq6N962uOI+7w1OAWZF4gA8wopUHnJ2u6LaunPZDCGj8c5UeDi" + "VCEjjjXOw0iIIJNxn1EIQkQiMo5HbUNfbWcIHMzIqDZkcTCa1dZrHWNrQplzXnm11mCy1VGw" + "8nqWRwiWKYR1vBkIEVPbf/7c/jEYooiZrNWUCpGYXzPjmCeS2hSQGSkZr/l9MwUgY0626sKF" + "r7CMEHNZPX9kq+O//fxvNiwzbp+3iFhAkpxsH00gSW7jxRmKDBK1NTf3Aog0Udmas5Sq29hW" + "qNFaVS/Vq0BMpLZRW928tmqtmWhdNAEzZM7rMPiCDo++WK4Ov+XNpo3u17wMOI5jvoAIZrC5" + "9o0BIK8v/Pp1+16j1y5328eOV/Yk85a3vAG2I9/He2bO27zlYV8YP/e1TJl34LpeK/H1fR7A" + "1/Wrj3eYYSaQC6O6vLDfSRA78siZ88prRRlXdsTttdmuZWntNgYb+26zj3cD0H3+upnbyJVX" + "ssxFyO4d8O75be5d8Z2cr3XtOCa+eee4Eh0XkHMet5Xq8dV/n9cXfmG8OxLzmrZSlReOfNFp" + "lz86zZcBNWf2n72PvrhueSQGDMsK/IX1A15v58f+7+P+yHjcKTKkEef9FvP+5bq+WIvZA1WP" + "88FgkN0kyQjKsJhZt7q97y4tM+KxbAwQQAzD6m3ONlrFCpxxZuBgay0ioDjnOayNPhYCcWkc" + "M0OCNMRMMgAj45iXuzO5vw/fxsXVA+YTRaVAkWfmEwTOuLuoidXxRmB7awTnMZe6Fkc8fsfP" + "t92r4jdSCLCZP2acjCZWmgtkJbkBbPsgKUWyJMFg5szx5qtjl0QbBrXH/WFNmvgYA9Z+P26P" + "ZAOIQtJKHe8jkwp9399BzmOKrC9lT+T28dNb+26GcH/bREVElsmEmfd5FlErqK1nzpjnmVmy" + "UPBj++de8oyVQgaPW8w5zcSLXWRJehte8Otff4HcPj6aStvGKjdG28aw8bb10U2t4DkjmTRD" + "rzZqNTcf1mvDmlULkDBF60NEljAL4CQX06h7JVJg1YzE+tBUN1MbW9vexkshlZJ5iahAI8Ig" + "UEBhEDE8qeYVKlIFTLehUvI38pr3OD8+9mpjbG9ZmBmC1RLR2uR3BF3erY+3TYcjkkhSVUBw" + "9IFiYzRvbttbBq3ZM59m6tZE2VhPsLaaEUdEnsFibqrUVrW3N35DdETF3LZtY8m42P0tmQCE" + "rK3u24Zi+3sr0K9j8hGXQEhFOTKHSgZO5jCXzSrqj+2fG1GQufUBCpUCjtEvwg3HOVGEx4zk" + "21tvwz/2D4H87//8TyTp2D8+hCJFvm6/TqoxKNJr9SZXYOYjyfyNYCqfFFnCWx1DVDKyjw5H" + "SYI4eI6x1WqAEDkzELTRxQAiiVaHS1Fr+vJ/YeZRXViYF87HERFPqDl630Z3kHGP+J3BzDPN" + "qy69WlBYjscxjzAHTCT5FROU3kysUV4mcpE29i6JGdPNv+bDpJIpQB91ScqLAPM7ywUC6d7y" + "QsHqMzQzexvVRs8zP78+5zGX4Wgec2YyEiRcjtut8Lms6HCb96/HXzMVwqBZkzpG6/s+hrk1" + "FqooREyRKj/aH80A7yMyxcSzqDdAVYjEfMwkbVg1c7fzCEasNM3Y+/72sdxbMyaozZBPQSaF" + "rlVdkCJCNDhEalvHNDFfo8ngqFatmhRJJKiqMnpLMCPOI9VQ1SCWZ/RWm/mZjDXeMCFrEO2R" + "prb2fG+jLqkWsgpGcYiYgAupVF1yvXrMOOeV55MKRSZ5hY1abcx5ywiRBqgbznl8Pb7ifOWw" + "ah1mQsrHxx4Z+YQYJBF5cDlT3ZbbQWvrrW7btiymMSOOh8C20Var74yDotvocSVRmnVx5iOP" + "eWfwcT5GbYAwUwRBypMCeUTcj9t8zCALi7j92P8cCZA8brfmfovDieN8uI/b518JVJFtbO5+" + "/3xExtcjyGytWnURezxuRDGzc96L+WuWtbyCyxD4qGrN1vN7cexIMhh1YX3El6FhtEpkBJfO" + "XpCvSY4loWZViriSixkmwojVdU8s9xBEADODQCCRKSJmbf0mkCZ19NbEA8yT5rVAgWTmGblQ" + "RsA1jxSFmWSu4n4ex6HSpMj+vqlYa/6IqXAy12dlXhNUFe3DYHUJTgBMZVFp5u3rdrub19ba" + "4qxYM6Vm3rUNRqjZ69YRj3wA2Lbtrb3NmMc8lLpi9ZlpKs98JnI5FJPPH9u/7+fjvmYeuY88" + "ZxKru5+ZYq/hqGOMGVOE+I6Qz0g+43GP5k3Ar2PKU5IJF6OkY6Xms8DhYozII84ZAeScAUJb" + "S67nQDDq1tepXyqZoKJ5rSrLlxiZQlB0tTogwjPIhKwaI2/zKPIUrwaBeeYUgYjnjLgmKSho" + "20C++itvrcqLq8HMo0jhMzOX7V/yiPucrYlIfbL0YcE0aRF3Uud9zvnFp1htecwzz21s5gYQ" + "tInAwqAA9uQ8eXvcMiZAuDDoUiLz8/Y5k0IG6SjH445MrUMyBcYMHw2ZTLSqhImsMd7zyAug" + "VfM6WpMf2x9bAeMMEUGRpoDasDZzbuNN3OYjyFQVuHGGmImICLfxptZaE4D3e/zx3/944jmP" + "KZQ2zKX51vbtI5nNFGJnnMgUM7dX1klXi+piRlBsLe9SxdASWUVqHWJY/t7lF42ccY9EWBEq" + "39pbJE1IsbHKPvOIiJx5ZBJba7BlvMT9nHGPfC4PLtbzI6O1rlJuXwegi68ihsiIONwHGdJM" + "YMd9lgIyYQK1c94LnrVZPlHwNF15NsaVCCxr6so5I/k4HiaSCVN4b9X6Ececs0ttLjBvBhVX" + "G93wFGVyHo9mA5CCpOgxz7jPZG5bK+LDWpGy6rgf7aeYjUd8CSQec/vYS5JV/SnWR0Hu2+Zu" + "t9vXjMgDprRaWzOzdj8OFLbatHn3fp/3nCmb7PsHxIRJgZtbq6LyjAjh1rfaqooGw+HVa5AX" + "TxXPjO6Va56aucCBa97mkanCRYqqily6jjKPpPKtdRRJ8pynolA5zxcFRRRiArhXdRsxA0hS" + "RI0MFORFgG/bLgplaWNVUtjehvmIyMyjwD/2DaauWC0cZlg1LX5GFpcuxiKy4ACK+18HLFsb" + "a6ACjWvREtiiuGfM4tqkicu2b4JSzJh839+3Nr7mA3k97rOPOnq7Pw4ymw1doYFCRyOTPK/Q" + "Agrkx/5/fRyftzkTEKvCJ+OK0drbvhlErN3njdfy8gAEHGP09/cPGMoklQUOweevzzaajMbI" + "giINgPTRM6eomYHe+Jj/eX+sju4yADzz+b69FS2M7Nt7656LaJwRkbfbZ7Lso/fWUfDrr39p" + "ev/oVkRMjkeOrQokzmDmv/3xb1Tmkec8gmzNu3UQSbrpleQzzmA87m141RoXf+77jIzHA4oz" + "6S62jNiRkTPnmcS+D4er2IJ8kYTJ6lVtYzPxjCCSkNWyV9PWHBdfZnoCwNa2bWvxO42gS+Ya" + "aa0isv/xkb+54NIQ3P/6VBESovZkPj6/kphzPh6zj956extV3DKfTSBmmfnjj//14dV9tGWx" + "bWqp2Pp4PIIGASPoKst5jIK3agTmXM47utmVjOORoKisZNPou6ksLjbV4piff904J/rYWmtV" + "Z3DF7eMZRbyqmZvVpmJA8nswZ8FzjS+VIjDEIxZHlMgqtYB1bKNqFsmIOWcy38bb2EdTf7EX" + "z5QCr65ijAzkH3/8XKMhkjRdc0YOBkdtpq85PwIhpDCScKi01kR0uIuLKJbj+Ag+I5P3Y5bk" + "8qIIcDxixqkovVXzbr4qygzSE7q1lTFqb+OVCyCx+NfXCw3AhCgdchEQbltv7eWIV6iIZcwz" + "LxftrVa3H9yhKAJQNGPmIi49oaLVxLwXFLHi3sYwyALrrG91CIyFeREutVWHp8BEfLRqlmcE" + "KUomE/+HqTdokWRZkjXFKDVQBTMwgzQob8gL+eA23AvnwQz0+wHvz89uevFgzuIs6kIWREA4" + "uIEruBRowCwssrprWVRFVoW7m5uJinxCKesDVK0keUKsjzrKKL0ttcJJpCnS1yt+LXpXRPiV" + "5bnKN3vrawmVLB4uT/x8TCUpohLnUnAgDPfDg7E4mtMZ7lCMvhmyRyBC8ysSnDWv9AKBOH3F" + "2HDxDMpKiyWE5MyAhPs1j/tjP4CUIKVKzQ0mL3ZqFqsa7hGRJZeqflKC6914IteiyyG2bNP9" + "e/XpEPDk7X7LkrPkqtm0C1KSQNIqFkDNdXyvrb/t++e5dIOnJDxJfou3oHs8JSOQVFTo1K4Z" + "QVgxzOnL9Fi15xyRwrLCEFAx5eVA9Dpqq6KSkbJkMYWEMy5y3h8EFGKSz7jofMoTRAa0KrIW" + "kZA4/AjnPlmrICTCca3isjCJiBwRdVTNTcDbPJNkIDTr4Y+nc0U/l1lI8+so+PBHRK6motDS" + "RcDp604frVszIGuVUYdozQowJufXtheM1MuX24ycByORx+I/ZxRUK6N0a1Xi1fwtQKslIS3E" + "72u7TYgEVBffr9QiIQ5HqCR4+LLYEtxK11p8HiGplAZkQyJxnAcysticE4gsYkkDSIjT49v7" + "/3xjgl8uplasSuYKN0WGxLIIX3EBZkUCKcMQsQYOtSuSenDloRaaR5ak/wL8CSSqWEiuXc26" + "yYK1r76VeOxHRhKTp+eI6YxabR3yYnV4LyRtLQJoXk4NoXvtvdSmRX7NXysZq123sY33YWJ0" + "PvaHQPqoow0TC14M8mRELBdIMO6PXZ4guH/e8cR++sUzSy1ZJUs2tGXxuvjYH3N6iqcIAlJ7" + "sYBmgVr4eb/dH/tJekTMOdOKeGGZEi4gn3GRHGX0qjvpPlttUvXzdk9fx8RRh44SjB+fP8Vj" + "/Nu2gu0QzDnnnL77PndAkMIv330iolb9tv3He0So6dZ6G28M8ccdWbJmVe2jq2lCSsvshQWv" + "c58eEpElrgh6ENvfNgAlKzMYqxs6skiWhEBWSKwXKpGU4VpVcgn3hISsAc+w0brWhghVZUL4" + "sngGnb/ReaUW67281Zj+eezh17J5CaSWujbz99t9972X/tbfPOL++fPhjxy5bU2zQnRZ6yPY" + "xiYCZzAcjKy5WYEq1rs/AMB392NfEbuEpAsanqWoQjI9yMc85jpvgrAMlRqMi0esFSUEwVzM" + "E3CtAKWIrA551SyqTYuA8NP5i+N906zLhJglJDQQELz//f2f//5PqUp3MfSxfX9/FzXt6GrQ" + "toGX2otCuRi37VWQq8Cr5AdKg2JrvMhjWRMaXhSrLzLY12j6Intvq/dSgVVQ2FSJRrCpYtuw" + "OmSIbWsf28ftuN2P2dCa6h2LOmnXPND6QndBrQMXrnmR81i44tdM55iq+gXWVYJ//vkngaaw" + "1gmsURR+99pfWEA4gGpNjbz0ywuCl2dicVqwinT+W1fxBWumqodeX0VEINi1a3tVLf52lpji" + "ot7m0SfatgF6HHPbvn/fvpOYvC/DxTymmnbV1tt/+w6BbhsMwMfHh+KLjLZajMhv/R8dBrng" + "a1O3MECt+5wRUmsXwaRfHnWoJDTTkJwiIwURKqX3bsVAOB3A4julKtUkYSH7AFJNRUWzQuGM" + "rY1c6lf1g4SfTzwRoPPHzx/B3Htx9wgPsSUJMdZpXfYgZiBLrRaM27wtm8H37bsaTOtLxYPQ" + "PS5qL1WqAJFD8muVXhngrFVztPqmIiEayeOCJLzqDoTn/bEf0+kgqtXVz4UIYMGc0vIb1mLb" + "2MY2ZG1tBEUkSyUCYlmzc9fQKLYoVEmi9WFaiXnc+FyUSEaxctv3ZzyDYS2Z1MlZA1rqGRFO" + "pvDbzUV6qWW8Mfzb+GNsdWOKCA/RH59/FSsZ6eMfH9mSH1OyaJbdD05/xtOJc79FwFTEtCa5" + "IoKekK84FrCU5MUwyNImVKL1N2uWI7u7QHqpxzxM8joqqIh1e/x8PCUf+wOCqiZZtOvftv8h" + "Bp9uahBUMckqskyVVG10ryrxVVQWgf/8f/8zIhLSwsWMUU0qTFfnq0Aky1NyBq0NNcSFSTrn" + "jz//smLCeMwjRTr3RxaLFzJHtCsEWXJESBXNrQpu7nFR6vJxx9rirhk+eYha7z1Xfdtahk2f" + "Ve2xjhyj1dKPeYPjibX7jlYb8KpH2963biMWagHMmkfREJXgjznj9DFGSYpFyBeTpa4hIhZT" + "VM1MIuTk8cSTTrrXt6q1rdTTqqbDazaCLPXitQ50SdLBSyKSJrVyzsOQkWV+3vc5Cfr0Oefi" + "5/vhZ5xWe9OyIrVVa9a84KUkFuc71xyQcHq4iY2tVzGBBAlDMGXJqipZAGTJy/Xqh1+85vRa" + "KiIAiYiHPzLye2+onXM+5lm7vdUWSSAx6ghTk6eI0j2A/jaQoBlVNatdvGqpLWvA748pAMGS" + "dV7z2I9sFiCySo6AreFmLOhRlRTp4KVgLqZJ+xi+z9502XAuvzz8OZ+ByCUPK5eumfbz1bYR" + "r90tPDSrFdOqEvLt/X+9f4HM3Z0APFwhPj3FMyNrVTHJWhWCHOc84wxkVJUAIMhqEDhdoev1" + "MHp/SgakZPF4JoDkySvC1/Fu9x3EirSlSG9b62MTQJJILZoEhpLLNgbUApSQY39AbZQO01VU" + "EAzo+kcgJM77Y90iGblUUS0RYd3ySkwy1oQrRVqJAAHcHasoUuJ1is8SF9UkXhmw6GU88cxq" + "rVSIJKTw0yVr4LY/aqnFBCiImPM++lju1hV6WWh2Apqllw7TOe+ivYpKLe9j/Nx3p2OVpZaa" + "Il1xRKBqjYQ4fLpfvHIEJJ+8/LHHL87DAUZC4i9Cvm3/9xbhcYIRD39UrcGopS7gYC75fbzX" + "NjRxMs79ABApVDWr5cj5a6cP0r4PFXm5gU3JSV+bzeuKMLVaOpEQjighrL222iKLqhgykWTh" + "4q8IJ0zH1hPj/rgf+0FgjKpZA5wnOX3ZPkNCkmjWJxJJwUJsFnJfeMhSy2M/askeELJ0pYe7" + "Sw5YSfEMMAjNsgzaJNVKuO+3CQsrVRZfqr6E68sjYj6RsSggkAVPikCuWSB+zXOPhLP0rZeK" + "HFr6+/Y9m0ksjzDJ8Dk/bz9iD2IdyQDKV1taKtb2mCsDC5EsOUeGrdewqIlJFQEC39DpjCee" + "IpFpbbSViaqlmppAaq2I2B8zwEDui68m+Tfj/GWoD9RiC/L2C0kTGDj8MORr1ef1VmpJOV4U" + "Z8ioPUQifB70X5MMhqs2TYChabFqweCTJpY1ScjDfd4fVrK+jP2IYECK6tpc1FKJCGAFawlq" + "1YysvYBx+Pl8IdACkFbFncd+jDFUNRjLhSyhS90pWXsZUQFyJc8AZM3hWKSX43aLX/TJFBxt" + "KeM8/BJELtb6qAonROJfP+/zdn+lD4g2iopmy2mJIRGPedInRExNFJrFdzKIi5KQ1VSQJFc1" + "f1KALBaB0x/fvDEiaq4rU6uGCCEpsq42APHwx/2RNY/aSi2RRQCBnH4uwCsE+7EjLX4aTJL2" + "hsTwFHKZ9jbK4veIlIw0wV4MGX7Oc4/AmWClikfoyZciIBEeuzuuINisSZZ93hgcMlDBoGQ0" + "bYuQMR8TihUQvCL97WOTJKWX8JAs8zEXxs/dq+QARERtZdg8i61w3cXLkEMQpKSVBCIgXMl5" + "QFcslJ5LVVVf2lUQCX97f5/uxzy0yDa2NrauIJRzLv8gDJIEGcFAxu0xDVJEtJYF4piXa0IG" + "BPk2j6CvCsYAbPGsahnWoNmkllEQnOS39s9Wasmag0BcjFRqIXnuV5IEiJoG4xlPFV2JJwEk" + "l8hMni69KqqomNnaR9RiUkVCA2DQEFr7SsO8prs5MlKz7w5eHlYwxmh91NEV5k9fJVkquiSr" + "Vb677pvkjEBtdfUoFSvjbUTEfvjlZ9aqhmCquswcEDE/pkcc/uDy1YnQPetaILGCRWp43I41" + "3UsRJ5mJ2upiQwVCFUUaZGnwV4gMqRGMZ/RaLGlWUfuCwYhV07U+Oye/eEUM+DHFVv01DKKm" + "y8OAiKRLCQbO4JM8XWrppWa8LKatFlH1oLvLGvcwGPz2j//9jyoZIud8rITov//93yXLL58o" + "ORhrm6emkuN2+JOkoakilOF5keNMPz4+aq5igoTH4U5ft3UvHXltYIXhx+GJoaOVUgXyzPF9" + "vI/RzUppJTPuK7/ifr/fV8g7Asc8TJ4ReMypqr13yUFG623O6eHnfhDc+iha1kFTElRk+q61" + "NcPoW0aybilSkLX1ktt+fEakt/EmonNOU8uSEeHHRIapnfOobz0iRLR0WUtxBmrrEbzdjlrR" + "2rvKk5F9v50EhHTOOe/7fToTn2eEZQEYkM8ff1oZAjAoVuTiYx6cMwErue/HZCzkrm82UDSY" + "nHtQkmYmxhUiAhFUFcEo4+Wd4Tz20zWV/tb5a0bgcF/sYvf9GQmGou2XO1Q1KyKICPKYh7ub" + "GhJi1UeJ9Fp+ud/mMUqVKjxIQBNES62CDJyBKvT5po0RuVrRogI+Gc4sz+VqISNLjjj3x0SS" + "VUAkIs94ruv3ettBn/E0Me26InBqWHm2kgsj1gPtESUJ0LzUAAAgAElEQVQreYw2xNQvP51j" + "VD+5XGVLQFDJkdc5K/e2fd7/Moiozem3z08na+/n/pjHJH2MTQTTA7gQUb+PhAxFMAIySr1w" + "GbJ2VSnz3Effiqm7XwEzSGCf0y9WU0RetMfe2zrgjW0E+fBDtVgxkUAu63lYxJGQIPmt/zGW" + "Eu+kVvQ+eIXkeEay5QYQW96F9RiBcZJPINwvXku6zFLH6OG+P1wyRERqqZKlCi9AZMGnIAGo" + "BKKKeMQaMq93i//6tZIZkvFchcK1lioiEcufJ3XUjLyK3Q8eFkl6k5PMUkxbb1VrSA73NX5b" + "Iudt/3zy+drfXyy1I4sCS9PMi6apGFr5DJKPedsfExE5V1VMp33NK3zOIKtpLhWr+vMpz+Bx" + "7FzVQr9QNSdkqCm4INoqGiv5xjjjfCKriMmK5klEIMFEoFmlJoSqJQSSPoOnewDjbUgtrWp/" + "2yQwySvOQM5V1coitpDTuPppgGaNSu26SnEWtXcpoLraoVfFgS6sneIryTUvgse8ersAAww8" + "0DrwxWzGQRhXY9i8Jgzg7w84cHT7yu2sn7gqgFbjuv3+zaUOElwlBL2By5+ur+AWgGsxtXHh" + "4sFrAw5qV/IgTVW1N73mqra+HTc7jNv3l8B7AcQkiR+34yt3tWjVthqvrW3fqW0VVQDQ3oxA" + "w+q0WImk3jZ8xeMA4JpLpCVuLxEV6E371o/b8fXn1pd0LX2LlxJs9rt8XbGiZ+RFWzBsVXz7" + "5//+AFRMrORe+qouq1qXY+yMM8FOHk9kTg9ATM/9SEiXR8RlMCIe80HnyTPDFPHww91TpIvn" + "1yJcsKB6i+s4HREXz1+RJKuqrYnE8qKt+XX4CXke8wzSSoXkiLh4PJFFxJBDVcid89iPp6fH" + "fOz7vspvI6KWaprmdMmyuL5jjFK7u4fEsOJJSm1BMrhPHzULWuuSexWR0guShHuIyJd2t8oP" + "8hjDlCnCcfoMka4mrZbafe5ZLcIB2bZthcsFIhF9bGq69Ln5mEispb+NgpD1m6/6noj8ou5L" + "37TWntW0ikgJgJz32/2xHyJR62gLcHYRUNuaKfsa/t+v+/ftY2t6NO23Nbh4PQMG8vhCwX+N" + "Jo5VfaETUNsMqsbrIlbV37qv5/WKVkL7K5FKAHbMm9pLVEVXflHuXx8+XyGWTZclAtfUg0dv" + "vamSvM3VLAI0GA3EKlWcx+Q8oNa1X7igtv6Zk1yPyEEex83QoSs4w3kQOvV6/UQDrPX1INur" + "yuVVbHPN2408VkuwaleDqtrvRkIY++o4AWDEAfBi/45jUk2NNjGxqmCI/5Y4XDnSDuD7Wn7s" + "qx1G1yddnK/VBVQF1xr2bfzPEWQION1Pf7iHX2m5NwNMS0JfAuOZpa4M2bIiVqlQYHVBMCAh" + "GSZZpCYyAh7cti0i1q4HWDgACUSrLZuGzxTrDMQncoDn/cGIBZ8JRJy+OgnXgczKcrQgw4Jn" + "CLbWtW8tS4BJ8lttAnX67bHXWrUo5wySoSl4e+xIEEiumZMhzJJXBG5sTU2WFy1p0hXkRo4n" + "c6kRkSJnzUGP9Kp0rpL7GGPb4rnY4ZEln/OsrYbEutP7GAi/3R9z+jGPZzxVAaujmWTcbo+k" + "aR2CVcCAiCi0jo5n7LfpfEjtUswElFwC2XKOnJexIEnQv9k/jAF3Hv5gJFMEsgFl673X3qvA" + "xt82Feu9SFU4GdkQAau6zrlUK1oFhDOQwjSvEJAC+5zuXkW29/cxRqkyp19+1VqL6pyeJa/S" + "3dotPL4Yj2ICJ5FFVBMTNABRlGcwgCTpiuhqUkWB+zEfnweeTGr0Gbzet63Vgiw/f/yL5NjG" + "9zF6qSu6V9qwujy+JSc1g5SyiuUlC17GC577RURXS5K1qIhEgoj0hdlVDKsOMDwQq8Y1M0IT" + "iON2s1qRsJ/Tb/vdfXRVrWrlb9tWa5+Hp3VDLeslv5T4eJWX/5iffjCrSRIgQnIg4jYXhT2Q" + "QQrkGwZMMkRypNFbG1tKYHgxTWYCnTyMyXns7rxNqcUEoSkDRRUhpPdWEwwR011EczV4EFG1" + "z3OGe2SxNXkJaC0LTYHAz/1n1UpgNNP6RvfeepbIapDV7CxV5EKYVhBSA5EWn9jJrAbGS0On" + "1zEWMkckhwjdBfBnjN50DStMkXW0nhULjousvGZk2doGULRWhWjXLJLkiSfJsXK5seqCaYrQ" + "ukKeTyREIEOhHg5CxwjnxStIG+P4+bk/ZgAx+fH+LqYERxsR8fnzs5YajNL/y+EoCjrEAlkz" + "cq1VaxEJEZHIqzu8qKoaIg4eT8a37R/t8giftVlkdK2iKHUA2ecjIonm8CsYt9snnRlJqizM" + "ptbi8+Gn51pVkDK0F0nhpLXat61UhIOICMcvCUQkRDguWbEKcdm5F9HJmPPeS4ehWG+9eUQv" + "vZZaen/G87F/jm1TFL5sN2GlKnDwslITX6vWNt4WC7TVoqb77ia4luWp99r6yhdkZIYzKIFz" + "nmNs5BSp4LU753GPJAEGo7fuJCBOXxOPCGTQnf17b7VJDj8I41v+7nwEn1hoZJOKZDCkoMfb" + "eMuSAtBAJOy+b2Njoljxx1zjAQBkaFEPbGPMObFggknm4b7v4YdqXXCtk5dBoPZt+/ugOAIm" + "HYA/nSRU1oxc1RAXA4jVHAuf/sXYjCzPkxEJBgtBG2OM8SueUNQ+VDEfnjXXLGKlv3U14FrG" + "E7pTRa1YHz2Jgaxapcqq7GSgZJEqYqLxiozU3uN6cf8voErmV73GGREJOYJrp/h1IDnmGUKE" + "IpjU4hnLrDA5/dMByJKVE1QwnTyd4Qrdxqit4rkiFnwxa6F960/6QahE1t6qiBTJEZcgeOwz" + "E0C+eHWxY80sPEZvWS3iCpJI7v6Yj9GHivLhJ0+ST3+ePCPC1N56y6Uii4ZIL2WVtHgc7rVU" + "AKVKFhNd4woFqLwmG8FFgMCmWIcO64pr7ee4MBr9e/9tDCFhavY6Wl7AahNsuNbJRy9cxpfb" + "5b9QDRdef4NsW1PtxKHoy5nzKn5Stv79ZTxp1r93kvOamDh48KKaohkmTI28TM2Iizx40wtm" + "+H/+/LH2ct97s2aAAZwHm+ptHvOYJFtv85jft+/rc8ALzUAcPNRefpgXdeJF4GDTDTqV1zr2" + "3W8TwDUPrH0tMG93bU3JQzHn/VVXBLsdNwDb9qFdFy2DJC4ei/j61ZF0fO32j/sBrOJYM2JV" + "jnftXG1FuioEyYOycCK22fpoU11/bX3l18HfpeQX7dVWvk6hShBNW98UxI/b5MVLj7URniQu" + "mvaLR8eKn5HrpKFYDUUHDz1U+wVg1fwRbL3Ni9c8JibB7/b9xhsurKfnwqVfh1xALxzrY5Ww" + "BkzwIBS80Jqu/Ps6RFjreH3GMvJg69+Btb9f6Y2DQJ8GvXjMVSB2ux0GaOtY7AGyzWVtst8u" + "KVXVti0mIy6Q2KDXMh0caJty8nbcXhwWcN54HDeY4sJtHqamsIPXbR4LtqPaF55l9V7Z6nXi" + "/H2HvX70+r4Wv7NtbQ3cD70WZMa6XgcnedzuxKWEqfX2epwI6irG4jEVmI0HW8c8OI+l4IAX" + "XxWiX//Xr8609X85+up+fF1Zro5jXbIOSc5jPRkdOHDMW28f2qHXkkjWowxMkJjHVLxElNWo" + "ZkvHaApgzuN1pwPrCVtlXd+3bV78h3603njhuv/gMa9ltrOXHAQCzbBKtngD9HZ7EWRet/Dr" + "IVWsa7ieOVvPFTjx+iPK1c4FvtYi/Y1RmtcSiXBN7d+3vmlTU0W7QHAe/C/LHIzAuoVe9w/U" + "9Fv9ozZr1rqaRCS8ZNREHk76PDWW+Q5qDZesZhetQBL6E7g4n5/+mWlXXAl5KbAqupDyL03D" + "g7FksFdsIpdcpRZTKOIMkkAE5Ng/I1BLX1poqaKppJq3MUQFT2hThSJBtZhZQkLCKtup2nsx" + "a7VoOuaRpZahgpwkvzTxCH/sMEXwF1PwfHt/N5Ef90+eLiKSC4K8mHPVigpDF/opkvzhOoZJ" + "LrWoqZiAeDym73Ofc346Z9BDCAZBWu1B7gdBvI1mvXDO2ntItiShyEiMDPFaLCFL1t56GcM0" + "r5r66fNx8yeoedX7eF4NQvnLQwcg+G37Y0PCdCd9f8x4epBgzKBeyEhjVEUJMkj343B/+vPF" + "YVWRSFFQQw56LVUVq3l5DSh8Hn6utAcjotRWS130QINJfYGwCUBkTZiT59rq+3hbBIXPn7es" + "uVXNYvl1f0SIMEKL1FY1a601R0CkttrGG0gytm1bhqE5CbkUNeBFNNkqvKkhQOTRy0Xe912z" + "SC29WAImKSlqH72XCABPElZr1VU2E6WWOEOqJE+r8pnzlfxa9+uKKdGdAa3YPrZSKkOSxXHb" + "59JLsnWFlf46DUaQTBFiEsiGvEp2tGpBeczHPHbJOsa2xp5fRkvIeqXf5m0trTq7NWhvuN2g" + "/bW+g5zXBfJi7+3Cb67L9Zsl1dt6KWzgNTl5YQlvbWuL2aWAqbWu8/i9mGMevHiYWrP2Whsa" + "SN6OSfLixWuSfRL8XVu/SF74rfGht86LmMdqxyUmed0PHLfbgs6YdoAHYWDret2u7ePjVZZL" + "KrB93/hVaghg20xfvZjW1a6vEsV5LAX390qI67rI+VLk1uJ5veBinHMNAVp7lTVvH1s3vfBj" + "fRUgDlwb2uqvf3VaYlmKj0kA1K5Nm6nhBrX2z398HOTXSxAEG9q3+vcKYP/xE1m2t8551ZJ9" + "+jG9ShbB4/NhKc4gLlQrV3C5cYALYstHk0uGZ+mLjwAEuJLcQTXVWjTBI+IZCVk1stiFy/ms" + "ImnpAIaiheFLVROxUou79z5a17g08stbvfTwgCgACSt2+BGM0ntE8Jjr5be13ntPEblUALf9" + "IWQAT0m1jwBHG1ny/ZiRA4EzIsUZkY55fHx8zHmjJzFZ4Ju//vprjaXIw50RkZEF8kxPy7Va" + "7b33ohHBGVLRWhPVMYZ1dXpKduDMeIZJlep4BhEKTl+UXpGQjFf2OBghvGZ4iBWV2B8zadrG" + "Brw63lZ6b5XcfBt/DAVyFiv19GueE78kY53CER7ue84lX5GXLChStYtKOCG59aamdOpoWyum" + "tqJfMBgyEwtKL5Zar2YLmJCQteu2/Y9/6yq1F4jnwAUkAmstSvKaDzwjlOA5DzqfktVEIZPT" + "T0YioGSsdqeImNc85ukHkUlHlhSSm6rWYkhJLUu+AglE0vvjJ59cdAoGws9c+hXncpmsPUHk" + "mA9f9swsAeSI19h5G5tkeeyPuDxX01VM5NQq5a2YaEikairZI5jpD2cS0xwmicxFa5WqazAk" + "mgsvh0lrDdDH519Z+9KcGUE/EHnrLVTooUVFhSQugfHb+x+DgCAJkCIkYfnWA1GlhgQ98OLK" + "RxDZRMqqw0uqWmrx0x/7IyMxRTDm6cs3vSKNuS2fc6hqRIpwD1Sx1cyyks8CRQIgrRVkpfvp" + "5zOeIVCRYuUpOcAqFkkQ4VcAlLwsWiJqVjKdx37MYwYiHGpIa11DiqXm8Trca7ODV+01iFK1" + "vA2VWqr86+d9jGrWx9YPZ+16MjiXZhCm9WKs4ri12CZJyPDbTqD3TsaFqKIERSSbRETtBlF/" + "OoDSixTjAkZIRKRk8ja2Pqp4+EWYLDsnuQDacRFmS+t4qqgYEOLnjlyWdLQEkG/97/Xwc7Wf" + "nR6mkmXZtMOKFalMtBDGKkQksjAikW3UVQ3x2B/LmJs1L08GTIqWWmrvqrksCjvJXHKmQcPE" + "phPPCFBEarFFA67ae7f1HFy4woNIGRCQkZPEKhhVYLV5HX7U2iXC6fNkBiWrJsBktK2okDw9" + "ErhYxyKStSKYcm61qVbENeld6kn2/iYRDPzrzz8F8mK8SgDWelv+Eln0I8krDvaU1Gtvqh5H" + "DujoOaHWKiWn/DIJ7sck+f7+blWSWO+995GzxOXxZBXZD4ehqcaqHFO03uIZifHySr2izhrr" + "KkQwEccrEfwtNkiEtc6I/diDXAAcEgkBSYlEVYaIYnpEULNESO3GKySLxxOIXrpWXYmF5Xgw" + "QBea8BnP8AiswJuJvUgxeZnz7GVbIYG8NC4xmNkCzYgIrHRTrdpSk4piRbuGx3Qm/HIGp19+" + "ZrFaqpW6IsqTPHwXIERAmkhuphAbmwTf3z/mvO3u8XAYRm0BqihPj6eHqEkGLtUuIqWWX5wh" + "aUVqoFDRkkVMxRZ/IYmmpiXiSeDFsIpzP11E3sa7qTC4HHBbL4HgZDB+/OuvLBAzLaUKbBu9" + "1pdA4wfJbJlB8ILlos3dI+J8hWSBCFHV3l4H39eRGDh49WaLlLtAo73jIrA2X6qrpZpg29qH" + "tnmsfNrXIZ0kyMX1PebX0Pi61jZKget1dAYI2JJnVEFca3+nqqodei13U9/6a+J8AfMgqNTW" + "G1ZbOAiFwX67k1X1dr8BigvWFWpf1hGw46P1Y752fnoBva2v7MXPBT6+f3AJEPP6vjV8iV7X" + "vK7fqM+GeeDg0Zvxv4JofNGOvw7kzdS+9398fPy433DgNm8L0av6hepVPeZUQlVNOy7yi/84" + "ORteG3V+OTj0hR9+1dWT/Db+4/2tv01SJWrpWbKWmpAWYl2LJsmiCOSsxkxF6b0yIkkCrzH+" + "LQTIUUQR+N05BkBEkHjbjyx5lXsGr5DIkbUKLvVMnMFnIFBLzlIhqS/1Vgy4GK94NGCr3uLY" + "H5+fn/t9f8YzXmCXgKnmUnrTJO6+Fm0TycXwlFqsqD5XdbZqOPl0EV1ko2VtlaA7r3nQY/qd" + "DsIN2ST3MYL0iyK2bs1AiMorEAom4LHPIK2ZzxOACqSY+3EcU7JkMcnKc4qgj1GligQsNJQ8" + "tzHucyK4GjB8hY5U/JgCsQLNXTM0yyJFOiVLqoIFExKRb3iXsfV4AhmLf6NdNevtfoNi7bsi" + "IBFlWcRSJMnhXlsPJDWdTgl4hIB+4fLza/MWt/tjudDWPLOWamJSS2tFs0QQsfrwWKVqLQy6" + "H/HFXCcj3E+eKcXCY/jh7s6LkoWc99terQIhr8y+0N1998eULFVtlQw8IxC5FBUDILf9tvUB" + "YLQx54zFlSLqm/UykuSgIxbnPYspIx77o/f+jCeCtfVR6xNW1Xqvajan+zXNOiJut4lgTvY4" + "dpLaW5bs7iIKiGZE8LgfaVJLhaTwMBXT3npZmXQIhBTTnLNkA8Ivai616Dy4LhtW85HHyfPb" + "9sd43B9Wq6r8+LxlTc2an54lV+S5O+OQSMe8nnMvUnOx9e5U02Y6T1+HuVbLX3/9uH/+jIha" + "O/S/AEgJ6fN2c3f+Ykj+57bNGSHwk+c8qpjWNt3vt3/FpDOOOXNGEVWR1e1zzjB9+dPXKEOT" + "QmQZirS2pgqgAsiSmCWwvX88Pm9zn3MnJDjdqgklBKOPWmqW+Nzvi0YMkcD5+PT5677YZssK" + "U8rw5AJ5ylOzEszawdi2d81CznBxkI/5vr2/2GbB9+3DIzh3ByTCcm1FxfSxP56eBPjX7a7W" + "nsFgjri0WAR8P9x/zTklyf640XMxxAUEH/fD1OKJxa8OB5XXfoWEqX3TDyW44EtkmGZJ8ghf" + "LdGI63Dm9bRguWhS6VpyC8R+zPBzPXDhHmrFgCQARh+rM2a1FiGh1FGLrcoFP+df//pTAoCR" + "p89J94wstUiWRJ6MFLHggxGRZaFUAzxXk+9asldeRExxxj732/54+vPiwcCcdzFBgFznouhZ" + "HTwnnS75peOKlTUELrUnSaa1qplaMK5gLSZZoWjWxvt7DZB87I/jfpvunE5EZfbkmXLQ+XCt" + "zTkjUPvYRs9PuSKekkD0Yqrlr7/+fNNmtYJx+/wpJilwuFsIEFfEM55gXE4nE1L4qlnMADz8" + "x//5ZJomNWuuJYfg2/iP0bW/9VasVDNkDZD7WUttXRmr8CsA+EHkBRvptVVykq+wyMXLSqZf" + "phUKE1u8n1JLkrRc2LW8NjDLDaWiphaC1dgzxoApjxnAFWHAGTHvt91dgOUrJv3yQMbIxaog" + "aW+j9FJUd/rtr7+mOzKq9r71ata1p4Q5HQfC4fB9ehmFfDHNs+UVVRRIhIuofBVrP87d3XOu" + "9IOrCzHCuWrhKABE+tvYeu+j0dMVHhd7bbX1eew1K0oWqGiadBBJ0+GnTydi295Pf/jlpb8t" + "CAkicqsqOUVcEVXNWk0kJENQS38lQBi1V0Bqqef+SGIIfPv4X5vUF7ZViqwO+QBHH2sUZaX2" + "Up/ukw7AegcQz5iHrxdnsfKMp4gmTSq6jS2ySEbRYmr+XNudvBqUA5BaUjz94VZtRWcXNFAi" + "REqxqFa0t5olIQVZS317fx9qYfr0XwyaViB77BlAXTYW3+eEasullrxW4FcbOSgdkfD21krX" + "/jbyyz8RGXm1OxCJfnW1UotPiiKewcnReyAu0slfc972HWRtfWjPklotBoWA9Hm7M6KalFbT" + "L7SPDSR5itRAMGiwsY2MjCfvt733seobUbWqrUxFUSXpZNWuFYzUuipETHmFmuq6ddRKb7/i" + "2VRRRXhQO+fBF4x8Ccfa53Imc9VENJJ6ES9/x6tNAeirQaH1djtuXTtMJycuLDT46iFtqtga" + "Li5veAPuAGw1jrz21+sna//yXy6Zd+2iec15rE3/cRzEhPa2NT0ArENFA/B9+25q2hsuTvJ2" + "u6m1rortoyuOeW0f25pXT+rWyYPLFL5OQPOYIExxcOqhcy7q3NVa19+tGUt6xsvByWP+mFd/" + "HcRUwdsxVfvXOPa1N7TbOjx8zc6hwATQrb3KLRpAO+ZxfTnbyeP2g6r6Xb8T5MXb/bZ972rf" + "b//ff8LQuYEXVRv02/i/uoSKCTKKFbwUK0UwRK/5mL7TkxTNyUxwuYfCxGrppiJZFkA22+tp" + "eMyHT/d4JgZBFQ0ogsc86DMhiSnJvm2JvOaVSyr2pnnJeqq6yG1SspA0zVrqVkcuRjJ+BSMk" + "SUYmz4fPLh11pf+S6srrABF1jI/3TayvRuRAjDGsWJYswEIRe4SaVK2LPAQyRIZ068YgPT7+" + "/k4CGs3eYPEkI8K0A/HYH08iwCQSCPrU/l0RTLE/9rWxCFnOUorKKOPP+6cQUG7jI+LUYqXU" + "p6QiCsR+TE6qSQC91Ky2TOSrkCsxB0D69rfRtUPiMff9MRn+7f2PDSYKqJZ18TRBVNWKJDjp" + "jxmLaS2Xls4Iky/8ii2hCwF8fGwMMIfFy5VUu5X6JgkLb+XuflGyPOOJ5T5VtWJiJQ7/nJ/u" + "SwF+pabWr2NeWZJmBHC73yDo1rNEKR2ac+QzzhRpcSbPiGUjbtv3bduqWkhai6a7jzF+j+VE" + "a5CHP7r1MkqkMBg9ELRigOYnAVjG4ZMO64ZrqX32NgrJ++0uVrZWIfnx2OdnjPeSk/q1jkMO" + "SDUJpEAs2WEbYyUdeumq2T2OedaW1+DVfzEsug4rVrq2/iZZcDEy8DWeOW63F5M+kLWG+9je" + "v/U/hu+Ph/uvOZ2/JIdoMbVFQ37GU7qONk4/3ZkjxrYp8OAxP+/uTGqlioju+72IltIjIcuz" + "96FayBlXHJNZLqCqvXJEgdBX76cKIFZSPBeud9sGE+COWgrUyitv0Hv3/ZG1tyJEQhARZ1wk" + "eqtv463U0mv5FdHG28e2tVGmMyLWLHe6+/z1C+7TD7KbhoTvzzHUpO63/W28JUlLK1aVbbxD" + "0+HOi5HRe9csYgqBZpmkJGzfh9ZCwOfkr+hjIGIGt9FqHX3rpXcAy++7NFUGt20bvbrHjx9/" + "fnz83cnwU3tf/nd7bfpEExZJMCIeP2+MiPBIpZb61tvSsu73vdf6rb7LGtvmAkVdBOjpjiyq" + "cOfoo9Tyr/u//vj4Q6oBC21n2V4WkeP+8Dn72HZOQYjgmEygWimiSHgKNaoVWWiiqvWtF61F" + "TSOEl0fmW3+rvWdLPIHgsZ+Tu2FdYQHg7qJWqjLi3M95eGR0WC759DPBtm0sO2EASbI7gWWQ" + "zhLxRAo+gjZGe+FZGaZyuz8+908Tkyy+P84Ik7wKIv768Zea1jFMjaDkRvjhR0IOkSyZcZY+" + "kNDHINjfLCTvP/fei7YKQCI+77eF5x5jdNVIkIgEu8+7JNRiEAmkYx619YVeCT9PMkl294gz" + "Ijn5/jaeWi2okmEAgh7We+n6bfuPd04ul1uSFBH0WNYMJMFrUQ8r9nuuxDlfe9/W37aWIq3C" + "VwVUewT2/XPOuaqpR+tcwHVDZmYwGPe5P+MpIVrlC0ISr0FuRkQkSXQGIqs1a310352xqOLM" + "CLOaEY/DV6dStlxzPRGIEMBBRHK/9sfuvvv0Yz8johYDX5rfY3/sj5+9DxMDcMzDOat0Efyf" + "v/66z71AxzZCVWspeUFMJfEpVSJwxekTHnOFF7NWMQnIxzZa35AZjhBGIJdctUZEJAD0KyIF" + "5+ELMkRmybVktUIy4rziRQ/KksGAZFNr483vt4PMCjA5z3N6gM/I38Yf4/64L+ltXbDlml0M" + "egLHPCKial1Agf3zJwAk8PRsVqwwMZzuv56xJqiS8Fy9yX0MkxxZiilPnv9/U2fQGsuuJOEo" + "TgoyQQIJusG18AMP3AtvdrOZ//8r3lnMQC/uhWroBglaoDiQhllk9ZmHwQvb2FXl6uqUIuKL" + "8fI1PUEXPCEhhhK4j2j1kOTeXSVYtj4ed377N7/HHBEDdoFPX/QkaXE+5+Ak4KdigNOUN899" + "WmITcYiEl1ZM0//cbrxTTZ/96U+0pivS7sDzMb7+3LNdYi/g+rk7F7CJwQPw+KKL5KKkX0uz" + "lsittMo1P/YLCZ8TRbAIhxcNX09/doKbbzAViCf3Pl/u7j5fM6iJW+h0BoGRTO5lb5/tk+Y+" + "XhHMe4wBwLQ4Vh8MnS4JfpQ/SlRD5SKWm8FShiLR/TH6OO6TlCQ+56BzPufdTzAX+RzDp2+6" + "JU2RyCddDbqdXP1kmzNYhnw8H+MxXJBLNitFC5Q+BcU1XbSobnAIMXFq0Nskg1fhmN/YON3p" + "C52vSbonKN++qYQ5eH/e+ZzDf23k8XxwTEad6a3ovTgAAAkpSURBVOD9ceeY4zlqVrpfP69q" + "ENG2F9Oy73uIYvv+CcEmyTZoLi/yer06RAUMpSgqpPia/N4gSVySviZby3jXffX5muTm3wQ1" + "6Zyz5eDkUk0FMkf3kLoTARGRhKRNs+QoKVnurTRkNOgxfiVZIlZyKTllUcpmAtNWssmJQqiR" + "e22nyborwTV6LNdqq+H5NNV+J8AKRUReFwk2tNrqiKjtmc87rdCKGpIKF03NvkIxUVWMEZWo" + "qO+fGeDqNOLgoTilI1VA0bT1sbiGtmpoaAuEVdOP6IsMGQuxfVpR7WPfVWFgj/xe2DipUDX9" + "ahVjAWj76UwPZ3foOWH07hyNtu+7qpKDPZrDgpCIFhFooLY6Ou1dyqjvjG6UkoFRSHY2SsYH" + "gB4dW1qb7nE96glkPFecqsp1rsqjzyu+fYwFLCga7Le/VLTVSDbGiBjCGc6ocYvP4RYn2Re1" + "wpoCWmtjZZilBxmlZ7WFQfa0qBGDPZbpa993AMftGOvYWwUswpVcHGc3Zf99IeK0qhr7wU42" + "xEwBon5UhXL0FeRJArBWw9kGkk2bAsGDvON+7lfwjAA03f/59XE77krb9y9g9T6OfjRY/foy" + "LLb6FvLCIw8cOLOksRfQoNqsorM3bQdvhrOnbURBZaRWTWHvG6KHpWr8jrwDGn4+rZUjGtmi" + "j1NpZ2Zh9FEbV7j8AFMbxx1Nd61o+vH2Fste2+LiaYuLfz1UbZEcPR6YILXV0QeBqgroWgOn" + "344g1ziTt1aNdx7HEVGH28/71z+/rEKxn7dIyKKwMNchQvdxp2qz6KGFqqkpKnnj4hqLGvtA" + "9jZ7dxILB4ZCYVA0Kgxm1d7HDIbwqhb5gt5BDrAfh5ILxNFvIHrATBsqVwebtrMclyTY2NgG" + "oGMRfVCVnbWREf9oBCNFfPJLw+vdsdCpqn10VQ3L4e8r0OoOrLfn0YgBKhZr1YiudHajAQhb" + "4rt0dmmrqlr31nSHLqOhQuIECNL0pAyQS7V97P1+4P08CHP919dX1L6uxb4Y4YjaFB3na/HO" + "23Ebx/jaP1Abjnu/d0CJQ2/nk40DN95qrdgb3qvDGhtY60yrxNNjnNWq2j6aAk21moajs9WG" + "CoW+aQ4cZJTRxvPw3u8xZyq01nY+nVoDcIzDoAs8ft5DLN//8yvssuMYQ9lHjwyKQm/9X31g" + "rxaBglZbHDJX5FR21njvYB8dBD6gCqPVve618XbaPn/+/KlVI+2tqgGeGJ3oNwAfu1Lr+ToO" + "WypX3ff9Ix7EOO7HWFTTwWHdYEe8dajih/2RnA7RnFSKFCtJzXSD5TMOiQTVOUYfveRSW36S" + "/k1JYqUleJ9099baXOzz4dNhWnLBfI3n5JPa5PPjM1ki6XDJklvWhE1NXCBQlzlGNJWUmsac" + "nJOcDHx9bQDmoKgfz/7tv17PR2jK+bPxxclJ8Y/y4brFUN1HT5IW1rV+bvINcQKP52HZ4Biv" + "qF25ksym149dk35+fk5OOF6jl2rXcp3uteRc2j8+m2/5erU5mXIJVNvls2rKjuiG4pxeJAUF" + "ChZVQ/l5PAXexyvIhAnJHVk09LI5GatAzUUtB0emtl0MKenLZ0LirxkjVGBCFWgfV4X6ybfb" + "ZJMf7Y+2sHzy278jL5FL1nZV4Bd+Ifh/4lrU4a20wNaU2kxSztpJ9vG8D7u0RbZWrvs1eNw1" + "l32/0qemvPmmWa/Xa5J0vV7//PxTiiJKjhi8pc6Xh2A+OR3YPMEXJImI2jl5biRySeJJrM+5" + "yfail6aXcmkX4y/JLQc0R5tusGxOk5wukvi/P/+ec1hSOglYEm4otV2ul+vl2qNXyN2a5XKB" + "O3365nC0eg0pxcyQ/DEeJi3g9nBxJ4fD18vd59xyyUVlE7g/no8gegWxWNxjWJ1zJvcetj+Y" + "qOimEy6iJScS4j7HNN0kZfcJxyZmFSVfL+2iBmzyzSmSJOUf+3/tm28uKQjo0aAASRYIn+RO" + "hyNbTki55PmiR44WAShOrZTr5+5gEuRyUS3zOQL6e71e9v0/8jVHGzBW+AmJBC5yTp8vl82J" + "5+PuTrXaPlpyT2qa1ck1J92/fbtcL9hA/64lq5WAvmtR0s0Eok6frzvodOSSfbkYstac9Vpb" + "Elu+NMnfxxPwWnLKZa9NRcQ0Nrfosz/75huSzz5VAM+SOCf/+uuvMUYqqWr95veCJ5AumkRS" + "QA6sqX1Lgni1GnjgOWerrbW27/uck3OOOf016S7Wou+jZKMHLNaxQQQ+ORYTtsu1hl+0z+5n" + "XYK3ZMMx+1icppaLSlgMTuZGDCedsAE9weqL3apBT3JPZDA4+nHcY3L82ndtFX3AVBX34ziO" + "AwB13W73GFu42O8dGlP26rcznKba3m9mHyuQIwjNJ+x0hmEhZgFnqfqb8hECju772Uvfqt6p" + "v4fyUHysWh/r4MFOkgp8VIWpaVuja21Ure8YZ0XtSiBG3dDL2v126+OIt8Dbv251r1/7F4HR" + "7//vlzsPOVBGCjWMHpyWuJ7jOE7TGWKS01YVAIedpxQTh4HUsbjYDUb+DqC1iIYo9N7H4opJ" + "PAZ4eY+5EXY7I3C6ODDC9xcWuDM/fYKeiLcyR5KxEgoJLX6B4ZwfuUAwom0fpu+BH/i3vOP5" + "x80UqjpI4FQmg1BTWz1nKtN6/spI6VmELuNUVVttcSwcfdRWEd2BfQBcY+G8CKpqCl04XXwI" + "TGHnvu9NtRPGfp45l8b00VTPcLLFsP0erDAAjo4RJkpoB9riv91pcQwK2L7vQdKPJa/Vs7o6" + "vhBL4PclWVi6zhVa4BHeAdf39I4FLFJ/fP7353R3p0++/EXfijissk93F8sbv7VJkOg8+ezz" + "xVUkldqurfm3pGyXpoPAJtdLwaaxG3jNRVubg3BOQYV40XmM7r1YyUUhMl/z8ffj+RjcaAJy" + "0xxssgQg2JA8n3LMJRdR36BJyO/aqoo8+9MTFBL7VQrQX6/JzUzBMd19VqulFFO7tPZ4zg1J" + "c6Cq4SKSfPT58peYOH3MFydN4b5hgzQtVh63x9/zfv34vJZMUCEuKuLiGItrDHduisVEvpJt" + "Ck2GhFRbTfJtW8Hm173lVLUINplzxuTs87XCJC2iRQAlmWQrkgAh3bFENncfo/fBlFOCQ4P/" + "ndTk/wDWjbRY8zgTJQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +TestStar = PyEmbeddedImage( + "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" + "TkSuQmCC") + +#---------------------------------------------------------------------- +TestStar2 = PyEmbeddedImage( + "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" + "zwAumKtrAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +TestMask = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAIAAAABc2X6AAAAA3NCSVQICAjb4U/gAAADgElE" + "QVR4nNVcyXYEIQhs8+b/f9kcJjGODchSYKeOPYriwlKYtN779YvW2qXA3OUOiJA8vI6Mel1X" + "aw2r87LQnPAG32G9HKW0LYTh7sK/goNF0HtP1Zb89ZjCj7jDvfftacybqPISCl24NrMoj9Fy" + "zGzB0oWc9/sjfH3XI+0wSK21+aPJYm3bW6VtQdxhUmf9QvRPxKeIhXSkIdN9C+E2ynEJg9De" + "4eDMNObQAY0tWNqwbin1NGYof+kcO6Fw3mwyxMoDPSjSSlrWAW63T4aWeXmV0EWrsGbUgkMb" + "PxeswtlHTomxiEt44wbrlu7bJbsWbM4Y7CWAVXiOnMZHOYqQMe+Vo7sV8ygfOb+SACA3MCm/" + "uXYr6ztN714vudH8a2VgfJ8MhCrovcM4rbzlsEqWd+5L00jfBg6TtltL3lo7xlqiYN0Gf6RV" + "sOEZ0U51aHmcEnAqTBI93E8Lzur8GpNQTlRopj/kkQAmAqRbmoVaW1ZqTkRaJG8ikynzAfGd" + "2GBQpVm7n2MFuVFc4OqTMAMijY2l3XAofO+C1ZmD7Q7Haw6CWM1V0oiSu4SMFjdRazbjo/59" + "AAQeQRtb7JYxbmlx4/Imo5wQ6Sn2h2u0doyxxbYygDXpGoHOHSbvrRBvAhEkKjz5MMnvXQz3" + "fTxbWGDwn77oQl7Kmqs0489KFxemTQBWmz/cEkmRoBhwEvXrSBith9QckpDOeCRVJNwI1RBs" + "I4GYkKCcOk5LmEfl8xfzDkdmpnmDQbbUvOUQpH305bo5wkBNDrR15nplfLkqoZVj/VCztN5P" + "OWcmx3qZhiQjVXdwG7y3Vv70/fFBr2lR9S1VMc0t7lQVzk2SlhbTglTuIsTx63X22VIcjoWr" + "22HI9g6QzK7qzYXyjQcnF8vg6d2Se1znnwBgiTjso4ZNXyvPlpTcKItD8dGlQKKAah3QF+uC" + "8NeW4Ic/sr56s5JopU8xJ9ztAJRLsSo5MhNN9wWJO1xj7axIibQ4Rv4JNH3dGw8hZatUuyiW" + "fg7LvyrcfrHtqSeogtDI1I9rzocdOJUzk3D+zUOxyZU30HSspAfiwluTerjzwQV7K12p4TaM" + "j9sIsJUGpo1DFHbFK9yS0szWVGr/AaeFdXV/CgOpJv338et5twSHEEuX2kVrYS5SuVvHhuZ9" + "SqxuaevuOLWf9jyJA+2Ht7P/L+rdcfh/8UDamPANIgqdxHdWF6wAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +Test2 = PyEmbeddedImage( + "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") + +#---------------------------------------------------------------------- +Test2m = PyEmbeddedImage( + "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" + "Mpi6AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Robin = PyEmbeddedImage( + "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" + "L2b2/wO95SbBGokj2QAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +Bulb1 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAA3NCSVQICAjb4U/gAAAAuklE" + "QVRYhe3XSw6AIAwE0I7x/lfGhbLwR2catSbQHYnwaAkfYVYsI6YUdcBdwHO0I/ZNeWsEYJhZ" + "KTsJgMpDnCwO5IlnR5PWuKXaVgY0PojBjqraJEypks3Agsrb/R0gLizXeQ232v/NeMCfwaVe" + "AFq45/Z/M86E5Woz9yOZsWCTtzJfasrm3wLSGjv2ey+Qli2pAfjaVtUY/EykwXKJaq9zaOME" + "/yRuHvRCjIzpXheT+QB+IPrbx2nwAhZDRFVKSaXBAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Bulb2 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAA3NCSVQICAjb4U/gAAABZ0lE" + "QVRYhd2XTRKDIAyFQ6euPZk9rJ7MtQu6oLYRXn6gLXb6xo0I+UggAQNRpDN0OYX6dfC63ZSv" + "8fms28RflfasBXaQrO2PxfCQzHnYYGmYz5bdk30VPpuBguvlpsaArLy2xjjMRXMgonWbeNM4" + "LDte22XcmgZG7JAhCzywBh0wwFlnhSqxhbCxPF63m5p2NpUeSxBMKpUeczYb46KygQtRVKgA" + "nE1iHOZaKmcrHbSSqcz3fXU6JMoNJIb6nTgnPVeaUPCuEAm7tuKxnQP4s0hdB3AfZFKPzQXr" + "kgmO+wFQJ57H4zCX7E7pVC7i7132WMpXR9uslyQVEFTfvZXEQ6XS4+QoyiuX3xlVOWcP4ITM" + "qGywwS59hfs5qfbqQ1LMlQjDEDbsauC3vq7J78x1DaxfIaqUVpCzu+Zx5kbDDwGU6z/DdaGX" + "FWI8jAqh2k4jGDXW2QE3EI+Qx3U6zeM28Af0e8fi34LvHAyFYho2A4MAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +DbDec = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAAcUlE" + "QVRIie3UQQ6AIAwEwG3Dv+Tp9WV68EAoGhuknrY3COwAAcTMkFnq2rVurz3zwPL0DshIb0BS" + "OoASSR8HmO1BQIBjYl1xQMeh8cmRKleiOwTX84XUp4hV+2jXNMnoHlqGIX//RQQIECBAgACB" + "2zoBmUYswftQP5gAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +Dec = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAAaklE" + "QVRIie2UUQ7AIAxC607Wo3O0/S2xwW6L+Ae/Gl4RdQCIk7qatUQeBEjclwCVOwcI3SNilJJf" + "3ZHoNxRNCbSzE8Df6b6oHlHMOfaRpGRtDn5NhYzlQ1MxSAdadX+RAQYYYIABBhjw6AbsOBx9" + "les1zAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +Pt = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAAQElE" + "QVRIiWM8cOAAAy0BE01NHxYWsECoAwcciNTg4HCAJAuGfhCNWjDwFjCOFhWjFoxaMGrBqAWj" + "FoxaMDIsAABPtQfBbeinLQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +DbInc = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAAcUlE" + "QVRIie3USw6AIAwE0MF4Lzn6cDLduaBSPta4me74zQslIZHEl7XZqZwPZxgAxBrPQKDRBLrk" + "YCXgdJbJUuWSJRJoqeObOy2yWbM32O2Buyfv0zH1yAvpHlDFraU3gah0AOmHv0iAAAECBAgQ" + "YOsCx7AqwchhZKwAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +Inc = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAAZElE" + "QVRIie3TsRHAIAwDQDuTeXSNliINBWAuEp1cUujRYRJA3Jxnelqou4DQWAIqYwdIjATQpqDw" + "G2gafMP0OAKYBjn9B+OVmfRoG5DpDcCn7wBJeqzeQDhHW2TAgAEDBgwYeAGQuBx9fpoCrwAA" + "AABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +Tog1 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAFdJ" + "REFUKJFjZGRiZqAEMFGkm4GBgQXG+P/v739SNDIyMTNS5IL6utr/KC6AmYgMYK5qaGjAaRAL" + "Thk00NjUjGEBAwMVAnHUgMFgAN50gJS4cCZzRkpzIwAQgA63kzHTVAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +Tog2 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAD5J" + "REFUKJFjZGRiZqAEMFGkmxoGsCBz/v/7858UzYxMLIwUu4CRUCDCXMXIxMKITX7gA3HUgMFg" + "AMGERAgAAPsqCDCpcwplAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Smiles = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAolJ" + "REFUOI1tk91Lk2EYxn/vx7OmwyBhVsytmY1cCBFBQWSRlYVGJ51EjajptliH4X/QQeJ5J+ZJ" + "f0AnIVSWJ0EQQfQhzNG3JkRQILrl3tft6sDNRvnAdfI8z8V939d13Vi2w79IpS4pHt8p17Vk" + "jK1EIqpcLqPN/to0nWwmrc5IUL29n3jw4Ajl8mVKpYvcv7+frq5HdEZqymauqZljWbYDwOlT" + "xxSL/eTOnfMY4wElYAWoAhXgI75fIJ/3mJ8/wvST5xaw3kE2k1YsBhMTtzEmCYTqxEaxVaCM" + "MRYTE1uIxZ6RzVxdf7Rsh2i0XZ5XkPRF0mONjo4KkJSSlBKgcDgsqVVSizwPRTuRZTu42Uxa" + "XV1rGNMCOECN8fHxpimX6OnpYW5uDmgF1TAEuXG9yuf5lOyZmYcMDUWAReAj8LqJXAEWWVhY" + "aLqrQaWVoZNtzMxMYRljq1S6iTFtwCrDw9+ZnPQ2hIOFuqB1crUKSx34qw6hXfMNG7264stM" + "TvrAEvAOKDaRBVpjd2cQ/BbwgwDY8XiEYvEb8AMokky+BF7UK+svGR+qNp+/L0O5jeKcRXxX" + "GLe//wxTU/fo7Q0AolCAUEiUGoWpAWtQtTi4rw19iUB5K1OPf9F//GTDRkue11K3ad0qBYMK" + "BAJyXUehoKv93e3S4l6p0Cfv1QlFdwS0EeXBwTT5/Op6mw389qn4Pr5jcTjZweunUVgOw1qA" + "/K0ig2fOsREky3YYGOjTyAjyPCTVUbWllW3St6T04ZC8N0c1cmGHBo4f0H/LNP3kueU4w3R3" + "w9gYzM6CX3HwKzaz71cYu/uV7rMvcLb2Mf3srbURi81WNJdLK5HYLuMi46LEng7lMlc2Xec/" + "xiMt8QU2mDwAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +GridBG = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAFQAAABUCAYAAAAcaxDBAAAABHNCSVQICAgIfAhkiAAAAX9J" + "REFUeJzt3FtqgjEUAOGjBi+tgpt3C751b4XaakXRDYRfiJOQwHyPDVgZCByStLPD8esRwqSI" + "iP1um138/jnF52adXfs9XybX1qtldu3yfy3+zBHW5tmfqphBYQaFGRRmUNjMsYmVIiLSYpFd" + "vN3vXY1Gpd9zao0eGd3yMIPCDAozKMygMMcmWIqIKiNOjROs0rXtxya7dvo745/plocZFGZQ" + "mEFhBoU5NsGqjU2jrNEnWG55mEFhBoUZFGZQmGMTrNrYVONCbYT3Um55mEFhBoUZFGZQmGMT" + "LEVElUusUS7+fNvUOYPCDAozKMygMMcmWHeXdCOcKE19T7c8zKAwg8IMCjMozLEJ9nJs6ulp" + "d08Xhp42NWJQmEFhBoUZFObYBBvqbVPrv6QrGRnd8jCDwgwKMyjMoDDHJthQ/7dphDHNLQ8z" + "KMygMIPCDApzbIK9ddrU8hSnt4s/x6ZGDAozKMygMIPCHJtg3b1tan2CRf8+tzzMoDCDwgwK" + "MyjsCUFtsOQdiq21AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +SmallUpArrow = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADxJ" + "REFUOI1jZGRiZqAEMFGke2gY8P/f3/9kGwDTjM8QnAaga8JlCG3CAJdt2MQxDCAUaOjyjKMp" + "cRAYAABS2CPsss3BWQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +SmallDnArrow = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEhJ" + "REFUOI1jZGRiZqAEMFGke9QABgYGBgYWdIH///7+J6SJkYmZEacLkCUJacZqAD5DsInTLhDR" + "bcPlKrwugGnCFy6Mo3mBAQChDgRlP4RC7wAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +NoIcon = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAIxJ" + "REFUWIXtlUsKwCAMRJPY+9+4tSshldRqP4zQyUYyanxgPqqWBGkGfZ0ABBCRZeRw3tbsfbWk" + "0Z7XXwWIHlVLWtZa74kH/wICDOdAZCUPvN99l7OAAFMD1K33C4NXQbMP+J4e1fmV5vVbABHI" + "meb9kcE0dxL+AqArB6Jh82QAHWKjyxD+BQQgABxgB0zmRH3prALAAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +WizTest1 = PyEmbeddedImage( + "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") + +#---------------------------------------------------------------------- +WizTest2 = PyEmbeddedImage( + "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" + "YII=") + +#---------------------------------------------------------------------- +Vippi = PyEmbeddedImage( + "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") + +#---------------------------------------------------------------------- +LB01 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAACu0lE" + "QVRIibVWO3LbMBB9dty4hEuUuMKqcpHKOoK6FK7AI8iVJqNKrlK4Io9gHsFXIK6AVl1QZUau" + "lGJJcLmA4kwyfoVmBCzf2z8JfDKuAAznoWu6+/uv+/0OQIyR74wxAJxz2TpfyUN1lVJig91u" + "//j47Voa7XZ79bBzDkQgqvPyFZG8YreMMe/vvwBcT5b08vJD+sJ2ABDCyKWQT0KQEUxnoes6" + "ADejsScPnzVk4M65UUNhycuZmd2aTsYa8NHqaiUZpLVzTnKVROVTFYHQhaZp2MhtNuxmjFF6" + "l+ky0VinKSyZq5TSosicNQAjOwAi51ymls7mbgGNtc72UBjOw3AeiCg7JTNA3ssrCSLiW2ls" + "BBYCJUU76OarCBA556QlG2efxhQ1qzH1kih0/nUby9RLmxjj6zaGzkt2FuPfscjru7Xybk5x" + "MdvSALXij2UPIYRwo3hzpNw8siXk5lCtot0XVdECAFicG1/1eJbPt3pfFf06t+nMNY1oxTVA" + "LR+2mQMKASHEvs8nOgI1+pXgAAIFAkIwxvBwGGPULsq4rp4qLMYCxdYrZlC6OArIeP8ZaQk+" + "nHfR+m59SWCxdiZwTjg/f/BsrkG1bRRUomXvX3pwsU2bVVPVyNO7NQbI7wZ6TinLXBJYFLkd" + "Wt6dsqpyeT2nhLHI9JySXmqFW1qANd5+vuUVnU1jjETePDywBrMT+RhjVSAf1tuUZeQeds71" + "/ROBjDFPTErU90+bzQFTqdWirrzRSnBrzWMMAAghSG35LeO9J08Qb9/aLhI4HA78ElX9o/5K" + "agYRcb98MMnkqW3bPIYcNRHJaSrZJb4A8N999Y5hyVrYvu+NMdZaay0Aa+3t7a0x5nQ6bbfb" + "kt3CxhiPx+MHKZrjQMu5Khd41XfyhA74y2WHKVdq2zjn2qG9/Azhwy76H+SvrM/Fb1QY3j5A" + "lgwhAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +LB02 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAECUlE" + "QVRIibVWK5DjRhB9Vo4ETqCqlkzIXd0FtfkSHQy0wJELGiGDrQUSDbNRwCENO5AFEliyzCIG" + "y9QoVXdsqFmGmm1Aj0Yfu5Yk6dK65PHM6+7X/XoW+J9tBUBrnWVZWZYA8jwHYAg07CBDizNs" + "ebEuKwxUrRPApmm01qvVKgGgsqzruq7r8jw3NKKToUv0qy7jym6jtdZEpLV2zgFIABAzAGut" + "QMfTIS7L64LXBU8X47v8xJbJkBw0BAa+fv1TyEhkq1LKez/jQZ4BzjkX3+NLwZP9E8e+6758" + "+WO7vQPwJuQIUKbG2C9eBK62zEOKbFlI0FovNpeZAvDh81v8Fh3Mq8qWjSGQESQb+ZmniIET" + "Cn/gImylupZfVwBqQyGJWL0Bmi0zYBnOud1GzzhktM5tJHyi2oynrGUCUNfr1To4mKKz5QJk" + "wNJzSqn4OW0fZjBgKLSmcEVEBqFlCVhbThaxx1pZhvd+t9sJ0YsWiFa1znuvlJKdbdtakAXF" + "SJIZJ5FWsOxh5r6G9957H8QxFFnKJuhN6Zg5JAEmjEpMcCEc+WrARGStXRdj+GMjSLpgSW5d" + "wFqrtY5KIkOgGqFN5+FLC7FlQ7AIeVxSRAPv0/LMOgU8OADNOxBRmQZgy0wUZbSollIKRAYc" + "oReTKhlRJ3lMNRxnAIOnZFJsbuZ4RNp6am8mGQfPcTTCXtHXnCVicNQoD0BkyKlSww8ZcLFI" + "Ygg5POLR0KwXACwWaFIDrb3AJJjPqWnuYiLj6coU0TnFAPM44QE4VcbtSWCCC7CNSUQfgq61" + "l/ADy5ZjTN575xwDrcoGt3Ucf4hFniVBNYBWZUVAH4dlfOIRQyQ+AKiykbPBuADwAwDza/rE" + "SE+nND0hJefO7fPZOff8/Oy9T9MUSPkE+8RPfPrmf3x25333jZGe32fvlXvi0/l8Pp/Pm81G" + "NAEuOE1PKdnfbewiWIaxDBSqbKy1mMwfIhJVM493QNM0ALpOA6FH9vt9LfN00vHDsKPggwG/" + "z4nIOSfhZFn26dMnZu77nogAlGV5OBy01vv9flZzqdN8LiSxH0YN1bUB73Y7DFP65uamruuq" + "qpqmISJjjNa6qqqyLHkiLDK0QMdUyWSIaLiJ6jqKVoiqqmq323VdF/cbY6y18bao+xrXbLgy" + "DYGMMTNFHP4+fPzpY9u28jXWIM/z7fbu+/e/AHRdp5Tq+97j+oWxAvDSG3EiQ26xI/85V0pJ" + "bTG54kEEZgBN03h9HX29Wg9dRAYX9Ql5HA55nj8+Pt7e3k7Xj8fjPfMr6GJJRA9KvjCv/XZ7" + "9/DwcDweZ+j391mWvY6OQNFLDxC4uJqBWFu1mChDKfXu3S8fPr99HT38V/Hy0l9l/9/berX+" + "zzGX9g/BE1Gzc614hwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +LB03 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAD30lE" + "QVRIibVWrXIbSRD+pPILjB5hjAIO9ZJTVWQyC/wAK5AKMOpFRgfWj6AFRkFqJpAA7wMYeIni" + "qoRoWECIpwIO36ADQT7Q2tFo7bq4kkqD1e78fN399Z+A3ywTALvH3W9CLybFFMDydFnOynJW" + "ftl8/XXQL5uviqafUwDGGGNMjPHi4m0xKbz4n4P24otJcXHxNsaYFqcAQNQ0jTFGl+q6Tvpf" + "LuWsrOta3xPUoABgZvWDmAHEGMtZWdfyEui6lnJWqtXWWsVJuyf6s91unXPeeyYS5tj3IYTQ" + "dWXXWWuZGYBzLl3r+x6AiIQQ1CCFZmYRIaKu644UfPv293y+0BMQEYCA2PcxxhCCiNzc3Fh7" + "YNY5t1wuFT0ZzszMHEJ49eqPpGAKAN5///6v2rXZvFd71S69zMw5OgBrIzNbaw+kEzHzZvO+" + "7/t3nz6mkxPdtlXFRMy83W7/+vABQOg6XXTOKXoIJlegKyLSx6iHAVy/eXN2dnZ6emqMWe/W" + "xaSYAFiv11dXV7aqQtclo5g5QSuW8p4oyrcSXdbaEIIxpmkaYiomxQkAYjKtAbBarZxzImKt" + "ZaaB4T26+KP6SDqsjbvduijqEAKIVsxt2xLTgaLd486LVyeYaJQwKsu21WgBABGAm6YZnRER" + "ETHGGOfWawaw90CdWGHVti2IEnriRLyH9yEEa22MMXadtXbZtmpNMkizQ0SaYR0pTfcbTaNH" + "EyEEEJGiA4gxpjbgjBGRZIGmQ55aYwXMrLwruhZBNEZxjTFJh74ndI2S7EEIx7JvFXUtue2h" + "69TSGGMqmSS5HwcVXSfeh2BGOqYAUpfWTFd0a22s7tTfBJf6jD7zM3oxT+UjD1TyclVCvPf2" + "7h+lBYBzLjWyWN1574kpbxj6kifhkYIRD6YrjTGhnBljvPd5j8x3MQQmORozQ0/wnOjpp0SP" + "LBidt1XFTCEY2NHAAS7ni7ZtQzCJhNze9PmU4rRrrWWiEEw8botTAK9f/wnAD/fz6aaSyFWr" + "n9WtVTZCR6JIdWib1XaUELXXO2MAELMX6WIkIu990t00DQB6UgQYBflyvhDv+77XCZrPP+1z" + "XqQLQUGJSHebpjkqumOZAHh83GkF3N9/Vj+0yehEtNYqlq7wMLT90J2Un2fN3/8vwnEFqB+j" + "5owhQinOmv76fBZd5QRACEYVaCTu7z9fzhfvPn0EkQVCCBpb59z19fXt7W3ePEat7akcYpCc" + "UDWX8wUAEO2DPKTv+fl5VVUvRIfG4OHhIVeQxwNDamnH1oI6lNUQqvVu/Sz6fianICOb5vqZ" + "wj66mY+a5XL5Pwp+6OKvyn+2lmdb7GZzQAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +LB04 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAACUUlE" + "QVRIidWWPXLbMBCFP2Sc3hzXSkEegenDQi50gOQAKZAjSEewj0AWKV3kAiqiggcQ3acAirDO" + "SL0KpAAI8A+0VXgywWg0hLB4b/e9JSD434eILZgjAA2A+BaJKQHIAcTHK5kdgUeZjZEh2Mdf" + "gW6kNFL2gQbEchgTyePd/M9NNNnp0vLvEQIwJaKqHHTuhLZpeuntg6gqIxHVPE7cZJ+yRe/v" + "z3v55pAvOXwTWxAVpnSJW7jskAJqrQfTXEexXz+MJE1TY4wxJk3T0XR5b9QDB10GrYQY6Omn" + "yw0aN/kYOi87pFprIMsytdZON89RLb0rMx703+FY86kfOvuSAmqraaKvOstdJKquR5uew136" + "3n+L7iIZnxw3Hs6t2aCqh54DKDRwr9dogJ+fD/e7tdtbHvyRZeS4mkEFnsaFVpgjNPD1DIj3" + "t0mSAPYbOJ1Odqp+PfP9liaktSCaY3JHTYlSylzO9mNXk2644MvZXM5KKZ+iKUNrjU02EqQT" + "19Zb1y2QfrizWLYUD20f9O8/Yxm67ph4YNe8kwC0bdufKqWyLFNK9XFDjISpyW404cyyUhqJ" + "KAqgrutRrX3Woih89aNzaaZNg0q2GtshkcPSjrquPz0VoQmbkOucB3nAdXsa6rperVYxgrZt" + "Q+nlQIm5NmUolHR8u2S72WzoBKHTbb/fP5wep+LMEMyQDaveJdtp5MPp0d8QUyXnCQZNRffc" + "xO/LuEnRCgZMnmM0XuH/CwQzfHmoZhnajhcunH8z+nfRG6CX1/2Ju8KD/vUAV9jwtuMvbsIk" + "t9g4CtEAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +LB05 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAClElE" + "QVRIie1WO47bQAx9CpI+OsA29hHoA7jYbotUyhFGR1gX6eMrcNJsEaRwrrCFXKQbArmAK/cO" + "tl+AKTgzlqWRrRRJFcIYCBTNx9+jBvgv/1DYzTYNTKrzzRGCC0xzrZUZQGCE4MYw4zADU2AA" + "UDcvJg2cTQNTCPnZfmQPPYDoXfvaJG8LCAI4UjgAVetDiOUSAURABAGIVGHK1cqrc5ioUAGg" + "alsNDAIkIXoBBCAQEUFAEBGx1xQPA56VAaJrIbH6rFr7qwQ2R5I0CCyxvSJV68veisLu3GSn" + "nE9zd6EJ7sqAvpl60XpAYkReJJ+WXV9DV+dzEsAk+lz584mhRnyp9kmqqReByWIjyi7GjlLb" + "vQCyaucBsAMRQM5yFy/1/Q5A20YH2+Z58/0eADP/ev4IgBxZECJyrdPszgRWdZliT09fVRVA" + "XdeLJHVdq+rhcMgZ28K4vZHOjE0bpuu6pmlUVVXrJKraNE3XdUi7KwfUlwIPRJDnThLfHh4+" + "4PVl8+nz6XSqqkpVN5vN7tuX/Y+fAEAkPlPvQoY9MM/knHHVHoxWXdfd3d0BWC6XVpnj8bhe" + "rwMTOQJgGIMeFJocGHk8kFfQmc8D4zhsFtC4w+US5fmx9M27quL1ZViBd+9VbYSEiMajPARg" + "h9YDkMCSw7dc9vu9lSjL8XiMATmqKgEk/b0XwTiDnHtO2fZ8kUfpQ1Zm2TWAQSyxMUAeFaO5" + "NWYc+G2AcrD9xdZb2lfkDwAuMMRP1WQgN7bpQOS8n+feISYBIpcfLzTk4gYE0cU95REASt/8" + "CYDARPkOsgO2RSsBgC2wSwpyY4ypDGT8ncrELq2cZEDDG1iByewAutyLC2CLVQt23ugqgtYD" + "W2AxCm0K/y/Jb6NFiKLVxRI/AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +LB06 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAD1klE" + "QVRIibVWLY/kRhB9Mxnt4h5FAQN7FCkr3UmRyjjI+xOMl5V/QgaddEEbsDpwqIsdPdNjY7Tg" + "kIsFBDU1u6Z7aAPK7rE9s6uQK1madne5Pt6r6hrgB8sKQPfcSS0h8OHQ3Ny8vfv+qKqiAMAE" + "CgEiAFS1EO2YClEmYgIR1aKiwysAUYhq99yZ9WJVrAGgrpumidEx88evjwCICECbkiggAuYc" + "kTk+FyKyrxayzt/s93vvE1Q/Xf9h1mOMr6ev+oK3hQMT51yMrizLu++P+7/bV6wzkYymmYbX" + "l5xtADQxeu+nFm2dkTUOFiKKwASAoQAVoh2fa2Ez/BIhRgA3N2/3f71jIosuS6Z93D+dEVH2" + "wWc0rAB4751zZVmmlKCaTU9JsxI65QSIwgrpQgRdsMVQRSmlh4eH1LY6YLosCR28nqwTERNE" + "TzzT5HQqPwF4enq6urrSvg+73lRV9f2X/ov2O/R93w8mdiCi3W7X9/3OBD2AfhQi2qHXHtfX" + "v/7y+88A5L2sDaK2bWkMZNZlo0yDslNTs8c2a1HL4+vHD1l5A+Bz6RaIA0OFALAuk6JmulD4" + "gckUgkgtWosGJob+8+nfN3e/wUh+DjzFetGrCqSUSudCF7SuRdGm9Ll0oghd2G5vnXMppcr7" + "IR4aYEAIxarYnJuWkdImRgDHb75Yxca5MCqUzomiidFqJaV0/OZvtzGlZDAzVBScITI0m5g1" + "4JxrUzpWXqBSKzNE0oV2E6mqBEBqBZylIqrTLllNgwVgmeY0awXGxs6ng3HVKXNhvFwtUCbi" + "bgJRSsk5V3mfqVVVIuoIqirwAJoYT/gCAIkqYdZuTAC8qDYxcs7AMMnWz1sMwG0TK+9zzUDE" + "gF00l7m/bYy84zgP5hpgNiuZeftgJswWh9FORBQChWDrKZLrDO4QyzxAI7/y/qQgktnOU0xV" + "h01mzG/JWQYDOKP1qW/ru+2hWdVSiK5WxfbQAAhdWPqYyxyicTRa4Lm0DDcKgSfQMbNhYmov" + "jdIlBxjaQi32wBSYahmiu7+vrO2fA9/fV5Zu5b3pXxxqm+WGiOhQVKd7BrI9NF5ROpdaBbCq" + "5c/oANirc66JkenEbeZ5A4CXl6U65wbrIjpm0zSNGCXMUE1tOzUn8/Azz+ZgiWDl/dS6nR4r" + "D8BwB1AX9TkgJxnVlhzoZGSOCQ0LK/ZxV0wnazrnLjraLDK6KNYKtSjrMmqb+KKza2oqa1Ma" + "whSxVlgMn/GORB5h9pxfLZcdZMnDPb+aY++9917G8m3HW/2CGG0ZyezgdYgAlM4xkbmJMeaE" + "/s+/xx8r/wFXh3rTELfZNgAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +LB07 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAADyElE" + "QVRIibVWK5YbSRCMmecLtPACv7pCNDJYNHOE3iNkoQHzTPoIYgsWdaJFS/oIEjExUhxh6wgq" + "Yu4FWd1qaTUeEyeY109TFZEZ+SvgF9sDgNP301v/9j5PEwFAkuQizWi8PZYdksiXT79//etP" + "kDYZgP6h//C+DxJIkAQMcnc5AMylbE/VWv9+ef348bevcWWxnyBYLmQHwBvoISUARj3PXTsL" + "EPDsEcQ7En378u2fz58vRMvHViOjSD5kkTQzSS0C0t0ff+S3K9CNMipcIzBRxsblixpG1lol" + "XX6U8AOJvM8CJopk7wyvw1mAko611loBuGiQERCPx+PT01PXdSvOfYILulmftYXejZGA7jCU" + "P44JwFyKC13X1aqu6yQF8ZsEN+gRBGiQsrczh6GS/JeQiqtlZC6l1lpKiQiIexK9gc5AFzkA" + "kwFAhHI+2LS0yJCSS7XWrUSPN+jG5k/OmqjwTu4PWSIneKBLigKNLiEZaTey67ogGEt3S3Ab" + "jeiSpN4BgBJJLf4add6n3Vh2z/OWY0ipbBrlfxKJm78C0NDNJjbou97sxgJ0Q0LEYZQRvd9E" + "QG671MjlNCllx4q+dtxhqE2odkUA5lKySPJWIpusKbtYSulY66eX17kUM82liARQSsmiJJLn" + "fQqm82FYL5ZSIvQrArkATNbq5FjrMAwAXl9fDvtW2ifDZE3oLEbh7sYSsyi8HlI6DPVkdwh8" + "MoAXlff7Iarieez6jNVHo9Zkrs0RTKvIUcePG/TLjN0ayVJKSun7yW7kPgw1wj0MNYQK2yZy" + "S3DlfqRrHOdpMjMjIPdA18IRguzGksW4uKWJ/DcC38a5jIRSyvF4HMd5MhjlYvaLIM9z1y/f" + "pZQ+tynd6mqh/7CCLmpehIq2AjDiaW82BRzV1sFcSingcN43uSXRDNKQkqshNQKXpmmSNM8z" + "lj01Ub2aIKoLcdsljDaOUXE+UL7RYJOGRmBmOeeu64aUjKLFagGvZ28bfECfdbKN4pKLUdw3" + "1nJgk0U5GpVF0Ma5iyCeui5mKs1irMq9lNIWwzJojYrvANynehUBgPM+ZQfJk7Hv8+k0QX4Z" + "TYLxIsKQ0lzKFj3U3w6rw1B7v1763mfEuCcB5NwGS0qp1vq0TPnNQo5h1dAjz/FjbJusawLK" + "A3RNZ601Fkigr9DknZm6df8+wRpHe82hPeie5+5mCK62Uq4BrUYo695OttMEORg14QQOkHjn" + "xSiXX1cnoci0lqfTmw8vxgNRctyB3nKsHRDoaw4EuvTOy+5nLDgCHRuhQqJfbv8BP7qkTc4J" + "UvYAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +LB08 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAADYUlE" + "QVRIie1WO5LkKBB9dHREG2P1FcoeDx0BjqBxxmgvZa9VOkKttTZYsxFrtY4gjgDe2LpCHyHX" + "eIiiVLW95jiToVCg5OXLHyCA3/KrxWTBvLmU0uc45xyAyykBmDcH4HMT4k8fCVmgGpxzVN3j" + "skADstzoqdGA3opjt4tqyILnWBAg64ppmIhIKTnn1jGVAiABMFMlBVAKrEUpGCKVycOtYyJm" + "T/TDigUQCwwAsQhZgTgN0/ZaEUAhRYvd2uqJzpqPLNcBLFAQCwlRJtM7AKKhfSkWgLWlxd7T" + "WXutVUsIACwG4lUBTIMRiycmMg0GcaCBmQAUjrMgS2VvqZgJZkIpVU/2IQI73hhTJkNlzUC6" + "oDjBxPlm9emSteo/m+++pPPmTh+p9sA5dzmlQ8XvhYCGIW+rT+8mCyzgN5dSMuz7ekrlNvwm" + "h3j/V99IVGAinsnex5gFf36My7L0Bi3xdUyA+GW7ILWcmrAYxNPvE4ACmJ2aRT+/Ltx9moW7" + "ZoiwljtZ/LK1ku57ynJnXW5jBf6jBzwM1nX89i0555ZlaZatPmYCj5lxHFNK7+/O+wq7rg7V" + "50MdWNnVJgBlSu/vAUBfLQK4gufNXU7JyijivF/2zV95VGCMMfyeN7deTgD8vHEAACUC8Itr" + "4VsrYP8j3cS9K4AVlAgrZDBD1CwlxidaUsWBnzc/b6T2S7W3IgBgAQQggKcC8Yvzi/Pz1tgB" + "aBa0jZYFVsTPW0pJH26EUsxUNIu5XTfU7CaFPqlpyJoBQ3bOccIM8cq1r/Oe/Xw+HzSAZUk1" + "i583rsCb9lLqssvCaQ5UVbMQcz6fyQ5Ag9VgOdvwvTm4TA9Z959miKpqjFFVxMFM112rwUIy" + "AM4aY3rbY4l6YbmI4MHLN6xtFKpK9gOmVfie9ig15c64umkA1fvZPoksqP+Dh2KGyFP63rIC" + "jEGZruxlOgA+S6P9ylvr2lQIIYTQ+vzQd8sA9z2op/fYTp6i2fLNmry8fHl5+XK5XPhZZ8MN" + "iQaIvc3gGnKobz4ANNudXVRFb0R2H4/l+qNsdM453nY4aD6cc+SqzrJt7D9+/HMIv0WJdlyz" + "Jv39B4Bfrje4xvL29h1l+PvnH29f/wLg59f+ildJp9qDWGAeXujupbH0l7NeL4/qtL26fwHi" + "Q5sXlpUuEwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +LB09 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAADoklE" + "QVRIibVWMY4jNxAsLe4DrSfQiQ1c1owcXDTzBG5yB6wj8guKLnA0XyAjL+DIfIL0BHZkA+tk" + "+QTxCXLQM9RIe6vdg+2GMOBQZFd3VTc5wP9sGwDF4/5gAAxEAA6ttdaIqLW2d23MdJzMvJx5" + "O2Yd7l1Lwp4Fsbzm3W7sHYAkPBC11mKJ0WMgUu8AxkwAREREAECfwHEyYybPkoQR7I0M7gDk" + "WgEQkbUBPsbIfwzVGaOTOhgzbXdVRI6T2bu23VUA7H2u9TbGZu1FkY57B0BSSsI644zJtV7R" + "JUs2YyZnjC/xVYrUuyLtXdvYZIOs1+VanTGdru2uagZJOAnvXQOQbHiVIgCeBcBAdH8wxSOy" + "9PAVWONQXwA0G8+iFM2Db2HMVaSWhAEcWhuIPAszdzbGTOp07xozhzSH9XLNuqjsxm56gGqd" + "rnVmakqRaqAUEdE5FGaVbS2G3dgP/eU4me2uehZ1pEia00LLGcwZc2it1pqAQzODIPoL2S6M" + "FjsVT0SeuXgUDyLS59WgeHjm+TWCiJ6fn3XXvPdU9Icu8nEyvf5yrWMmJVezUW17TppWJ3M/" + "NWut/vWy9WaRk3D0AJ8JUeG6et1j7wxVyCYAMMa01vpkV2LuA90fEkIQACHIdszbMYP5XBsr" + "9jtMEj5F1iLslcKXUW4AeOa+R6Xuz5CuQ+471/pjKW4AMbIeXohlzkC9a5h6AGx31RmjY2dM" + "p7sLcAWG5SQGAPbr+XOZKlFYJAXmZnbG9Epf1s4xKsY6lRmVuZ+7Hzqz6isJ+gnhDPausWdw" + "hCR1OmYyxoA5QnpLX5gksAfSGWCmYglQwTQc9h7skYK6JjK+VYhAJAPwEv23MK4oUt378bsC" + "E7CHJBG5PxgiuFrdqSyBSg4h8bXyUaSHPwNED5wvq+vywEwLAZj47Iw9A7GGAAYz24QSOYqE" + "BEC61ndYbkRmRiyIxZdIw9AJFRGt8YLrTmTPP/32u45Libs8X+lJJF2IHIuCnimaHOC045Mw" + "MDfa48+fPr5gOcBHSSxpcggBdbmAVwA3bCUMmD8+/Lj+86/Hvx8ePj88fH58/IT0BUCuRETG" + "mN7PGwDl9Op3B4Jl73+4PwD4+vXXp6c/3eTeiGllF/fBDRuIcq1Pv3yZTicAgteP/hd29/YS" + "9gCI6MBsQ9jtdu/3/j4AIJY4EDHAIt9FEd7WAECwrPe4JLk8yN6092kQSwiJiFal8R32jgz+" + "hdnNrc/W/8b+AWuuNm4mLOApAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +LB10 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAACG0lE" + "QVRIibWWW5HrMAyG/+6USSAoEA4WiUIhLAWbwlJYCBGEYOk+yHZs+dL24Wg605nY+T9dLDk3" + "4if+p90BqMbpuor9BwKAsk+12kNh9jYR31d0FdMtxkgYqp6ryoLxNdQtjg+NMym7icX+FqBi" + "Xts7zv0FZsGoACqBsBY1E4XkGhTMjDFK0SsjAtHFwJKRAcuERHg5xruMQQSiYFy5ioAq/rWM" + "ofHooQdIq2XqgfCbV2s5F8TQGoAoiPALBIJoVmeAEPLvJcNlqWm0QKh7Oqmn94CRswzElkFt" + "LRtArEVrdSBqWgo5Ue5QlM0SQXS1d04RheKFxOaFon6ep0SAkvrL7Jv5Ip/n6Z4U9ZkEV2mR" + "mCIrlagAFFSx/Wz4hsT0gw3Ob2w/W9kYRufR9pt6vd5N00cjIRGBIQ8A2B7brOYMgFI/ltpY" + "WINx3Ts4dNnKMOt/zpeHr0Gj9UYZXVv0vHaafqiON45T28mltuofDiw7O2OYt76TG57isKsw" + "Yo/jSli1F/W4xrVbuNQBMA4axJGQyzuqiaCO9HDXOOMAdkHgdHY9bBLE3dwngmonmm2XC2mj" + "ph8nvcU+gn3ybXCEayl9IFGCBU4nYlaDG/GT9WZz9OBVQndpJMxBrSrsGBEAPd+99GfB1b73" + "eAxHxVC6D78Mg36pBEeUAXYx7dHX2aWlZ7iU9h15RZAYbSre+Q4bqquCcagV+QONz+0Phw4J" + "ZHiPPT8AAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +LB11 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAADPUlE" + "QVRIib1VvZnrNhCc07sGeCFCtDAqQRcqlEsAS3gvvdAlcEvwpZedStCUYKXIHkuwgwVAkJRC" + "GwE/EMTu7Mz+EPiP1wuA2z+39k6ZTPI9AKDtVZ++JCRCdeM3JaTb1LwdX46vG9dWjd2AXJBY" + "XbTlr4IEVhO5H0wFpgKMo3b2JKSC4ccmERQEgKBTJegwZW9SjakAUNZ7J0GAiWbyfYvUY6zh" + "V4/1hKCLtstB4sZ7u8Q9MAlAkoBE+qZdcHmnia7S8eX4AwAZmjIhIAMmIYcQEICvjfeUQIac" + "eQ44p5AzckbAVxZyyBmJyMqeA/uwQ5fSAlKUrVRY5SzefXUbkqxa0esKwDj690Mv6H7p8TEA" + "yOq3lJo+Ne1gomP8AICQ/WZGRg5nBuRwDjCVQgJchhxyboX18fF1RvZ9yFk5K2eCLmxWBmDK" + "rzWZdB6CIDrTRFjHwIRSI+Po9Xo0W1q0JwekRDPBqyixeHcYVx8P2krzHE/DsGQFJYJWP83W" + "zUfTYQPemkDrw0Tc78M8z9d5lkDPbvLCl0m/Pu/Nr0pqiJZkEiwlXhJIrBYTvy/xEuM8z+0I" + "TExM5P0+LDexOFkAmhSs7vrwAZiVqrnEuCUN/P6+/P6+oNZPH9wiUT9zNvbsI+giRJmNANPK" + "JLG5OmDdBG1OqLvNVNSr/dymTxmZNo49trriWxho6ZuV/n6b3Z2utNRszcRO2ybUViL3KFOD" + "MVWM0qsg8ed1fnv/fHt7f3v/HB91eyNxQO2yXh8PpBGxGrjXa0r8+69TjBFAjHEi1px3OWg0" + "+1D6qBuGG5sIptvEGOPtNi0BuV9bMdo12joKx7jW2pdgYhkDTIkwE6dp1zaLqy2AU2tReCZO" + "w3Cd5wIjgyxRGsdyQcZWrx17X694vnoSUMG4XiEt6jmM1lZbgDbm8KTR2uHP01Bq0TtLZh1X" + "mVpMeijRanbaFmue55X3yvGhVQvrqUQCYPI29h/VJcb3z/s3wGTNnQn96NnoUwC6GV549L/i" + "YlleownXP64ATsPQzjcTVN342s4it9lPlR7uNAy999SNh70SBxSEZar0PHruXNNa/TzS0xp5" + "mgM+iObBpxa+w2ymy/+x/gWtyv3j8QyAFwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +LB12 = PyEmbeddedImage( + "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" + "0EwqYgAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +FloatCanvas = PyEmbeddedImage( + "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" + "AcASfwHe9K0xabrlBgAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +TheKid = PyEmbeddedImage( + "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" + "a9zlvVY5xpJgn2H7Jkevv3eruhfAeXe263vvN1VpaiGu1BsKpFmbmlYVcJWMyDudY5vwrxfa" + "/i215XaV2DcHbVCy1W2259nmRd6VCLweV5xMVc6O24blu9DtnExo99WxbAZ1Y8lkId52lufv" + "DkHemm/u/Tw8iXxAlv/1X/Lerz689rvs5kt/Sqab79eOF4ToNAnRqnQ0Z/KC6csXuNYcznu9" + "37nz2Znx34U+K7SANe8AbaN4NnTqmrRTqvK6Xss8zct5WqTKuTnVu8M54dzQrDFCm0jzThLh" + "3HEaXFy1YbIYdNksikix/Z1z3shkWK6t5VeLVmv5PWsW325UCT8L3dzCS3vZEpSbcwKe9FEx" + "/rnDofsvb274wOQk3/IIcvmx3/7JfPrKf6Dzk59Upoed9xq8Y5omDCOnVLH3uaE3w10r4edO" + "sn3N3WPu/oHyveuyC5ef3ZWTt7VUxKFUpM02fef1XNlKsVLe/TrW98p3HOFd3qvmQu3/l56T" + "DcXc/t0q/Ww2gHfmN+0+vROSlmvPa1L+DgjLWe5T2MPidCuvsIG7le6uxz+Sy0dfna+e/Zvw" + "+gdiZte31EGGT/zEd4X5G/+hi1e/30kehmEQ5xzjNNaeijVv2NYatom3iGxM913yD1b25yx5" + "Xl+17OIL9LK7ecJKqTbGp1GiLflfqdNziLTCudXJmsQ82zsr7tsI2HKLZtQt4myh1PbYu9As" + "hLDJSVaYuIVIS087K8XbiAfdKJq3kHKbu7RwdZbQnyX37Z4LTs1bnj89PP+8TY9f+LkPQo3k" + "W+cgL35+P6Rv/rtduvkjIvmyC168c8Q4M89FFjEMO+Z5OoNMIYQlmrRdzem22isLPoe7RrqJ" + "LuUfQK2O14R3S2e2HXiRmrSkuL5PmXl1lyJeOwS3BlWcqSx1ulQgmvO905lX3F+Ypw15sNih" + "LO8tsn6eRu8uzlAh1NJX4tdZXbq99vrfViiwbkCbomTVt20j0LZQ2c5b/r/pvsCpkCw/hPh9" + "/UcfXU9vfvnnuburfZutb5WD6OH+4V8dpuO/jMzPhdBpHwLTNJJiXnqpGyW5woCWI6wwo30x" + "KdUw33D8HSNqdYL25W6RRYMH65cqd758d2bEdyFL6fE+L8pBgVlLqJJ1F2/HLTdjI0NZGLCq" + "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") + +#---------------------------------------------------------------------- +Carrot = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAfRJ" + "REFUWIXFV9uRgzAMXNnXEaklJdACNdACJVALlJT4PkBm/Qyvy+0ME5MYdiWtBBExFnfBvV9O" + "12Ks8DlDjBW/vkuAe7+ca4lkADBmNs4A+k3Ez1+QJ4QxOsD1LyfGymUBSi4DwCJcC8hzIUOf" + "ClBcEqDkuSC9iB5pKZ7b8pIHOPUzgEeUBU8yRF+MiwgxVk4LqNY9wgygwZapxypIjBVziv0D" + "OGIlB30yTglg4+Uw0W9KOiPvlcMCSqlnMQ0WLyih+gP6Saa8VAKOlNfzKkjr3qy/PwYsLUip" + "OCQgjl5vrGSltc9ARxeu2N0FpYHD0MC47pp6dAhboT/ZBVPFfEquhgvIeQNhlwCOXg3GYMcH" + "vd6F+3gCKg6N4lLqs1nhZwAri/AxA7m2i8nUdJ54JefnfglVAaWBoxFz2z14z05yYGcJpsj9" + "HLHQXC+9AdVQzEDNeEJTTYyVINomvAdGpPWnPdUSzEiNN2ObanvTDCB8KXlu12YFaPTcsuyD" + "w+QVJB7ITTyNmut9BzlQyACnvlrv0sVHIMb6A4Bz7XIAcFO7HAAc76sdvBeAw7hdH5+LsVsJ" + "4vc7//jEvSmPkZTgcMovQsTY5PX6isvde/nDEcyAPhxUfO+gC76R8hy86fYaba8ZYwPGJhVj" + "YbTnvx21wvwnOQD8AjaMF/ZJlUR1AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Pointy = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAalJ" + "REFUWIXFl2GSgyAMhR90byRnkjPRM8GRNPtjDRskINraZoZpK8X38UJiawAQxQDjPIx9GHw4" + "LL+hGEDrQl8D+BaEBQDj/NcgrJb3T0LkFEgXJMTdIMbYx5/gJkQx1F+6sUL+HdgE9k4w1F1O" + "ZAeymOJESgkA4PyzgL0FQELEMBfCDMUuvQXE2Ic6ABAPioFimIvPFAMBoNb60fHT2j3vOKWU" + "dyzTkq+tC73iRAEg838oXF67DFGcAVoXimGuct4SLm50sVQrgLPCAIBpAoRjZ0CqM3BKWIhj" + "mmSVDKfE9iabXVE2q008v+Jc4+oCdIVlvAAxDKABvQNiCMA4jxjm3BnVkOIKRAukWQWtQ5hS" + "ymVaze8hlI3sD6fqAO84LxL5n7ad8XySQooDMrSUFACSzvlnFtnDyFRIN44c0CDUpyGAipQ7" + "JFsuH9ExzNmZnnix2S0dTYAjIAlSQQyGcb7twChM79lw1EWN8+1W3F24nRVaF2o2J/y5c+TK" + "5UbEINrgeeefZZVo97iSgtGQP+32TvAhfMmBo2A3ek7c6oCMfRXlvwGfAmjFL1FBV3kCEik9" + "AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Pencil = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAArlJ" + "REFUWIXFl6tu3EAUhj8nlQJa4gcIGbK00lkQqSBNdvMKIQVhzgOE5BX6CB4UUBRWUOZcDCIV" + "5EiRCqIQK6C8KGDB7hT4srZ39ubdqkcymPHY3z//OTNjB8HOLv8z3m3zZW4ydr7+YGc3+KcC" + "SrCTyHs/UOvmiQg2TUEJj+MYgCRJuM5CiPI29rwU4XViIwFuMnb39/cA7O/vA2CMwVo7FVKH" + "eUTsbAtujMEYQ5qm9Ho9hsMhp+ZP45lYopk66VQDJfzw08eqL03Txpher8fe3ntOf3znOgux" + "c961toByBocvn+GlgPdyMenDUzXu9fU3o9Hb0vetlQI3GbtHB48ONMovgA8XF+jBoOHIaPRG" + "lmUYYwh03vzXcKCE10MsEDmEvK70YMDhzxvShyeyLMv7VGtPzApZyYFFcOy0qCVS9GBQtVW1" + "EgKWhpYili7DVeH1UCtchmEFz7KMiHz+5Wq5ub0LYIkDXeAAl2FIkiRQAH0xOD5yg+MjN1dA" + "V7it2WyMQUTyfiAMw5nx3iJ0k7GLY0FsK2mrwFWg4IhIVYRhGHoFzDhQwiMRkCi/itDzPqqy" + "EC4yFa2qJEnSgLdT4nUgKmxTyQ+UEqko4qnkJnwqcBn85vYumFsDJbwtTIWGC234ZTYtwGVw" + "8KQgjv0W10XMg9djFTi0UuAmY1cHAIiez4hQAWw+rgFXSHS57fW2NwVV7j1wmLrQhvdV14JD" + "y4HS/nngMqxqgd0MDrWtuP6h4B7933YlHIpNSTaDQ8uBq6tvPD//Iuh/9Qqp4FpYvyG8IWA4" + "HHJ29oUgmB1va8eYqBZVuDm8EuAmYycinJycNG4GfdtYlqJK3wIs3l5XhVcCYLpttkNsPtMy" + "2lDfabcqHIoinPdHsw60CxwWfJKtA+0KrwT4/lhEZKEr24BXArpGV2hnAdsAtuMv2rGEjWiw" + "u+IAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +WXPdemo = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAWlJ" + "REFUWIW1V1sSwjAIBMebeBU9db2KZ8EPmxbCI4TUnXGskWaXDQktwhjErjERP4XRhER08iPi" + "5SKiyQR5JyI7xxB3j7wn5GI6V2hFxM0gJtjYANFBiIjQu7L/1lYlwR0QxLDZhE0II1+CtwRC" + "RI8riBva7DL7CC9VAwDbbxwKtdDXwBi7K+1zCP99T1vDFedd8FBwYd6BCAUXuACEF7QsbET/" + "FaHs+gDQw4vOLNHkMojAnTw8nlNipIiwmR0DCXJbjCXkFCAL23BnpQgRWt1EMbyujCK9AZzZ" + "f+b3sX0oSqJQ6EorFeT4NiL6Wtj0+LXnQAzThYoAAsN6ehqR3sHExmcEqGeFApQLcTvm5Kt9" + "wkHGgb+RZwSkyc1dwOcpCtCoNKSz6FRCUQ3o7Nn+5Y+Lg+y5CIXlcyAk99ziiQS32+svz/UY" + "vClJoLpIC8gi+VwwfDecEiEtT/WZTJDf94uk1Ru8vbz0cvoF7S2DnpeVL9UAAAAASUVORK5C" + "YII=") + +#---------------------------------------------------------------------- +_rt_alignleft = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEJJ" + "REFUOI1jZGRiZqAEMFGkm4GBgYWBgYHBx9vrPzmat2zdxshIqRdIcsGWrdsY0cXo6wJsLhoN" + "g2ERBhRnJooNAACQdhhQZbXeGAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_alignright = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADxJ" + "REFUOI1jZGRiZqAEMFGkm4GBgYWBgYHBx9vrPzmat2zdxshIqRdYsAkS6yLquWA0DEZ8GFCc" + "mSg2AADQZxhQFG0xxgAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_bold = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEtJ" + "REFUOI3NUkEKACAMyq3//7jWNQwWY0HzKNOJCIi2DCSlfmHQmbA5zBNAFG4CPoAodo4fFOyA" + "wZGvHTDqdwCecnQHh0EU/ztIGyy1dBRJuH/9MwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_centre = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEJJ" + "REFUOI1jZGRiZqAEMFGkm4GBgYWBgYHBx9vrPzmat2zdxshIqRdYkDnEumTL1m2MMDZ1XDAa" + "BiM+DCjOTBQbAAAwdhhQDziCqAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_colour = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAPZJ" + "REFUOI1jZGRiZqAEsOCS+Mcu9h+bONPPV4wofEKa37Lz4zWYEd0LuGzG5RKsLiAFDEIDllTz" + "MWxtyGJ4yiWKofgfCyTSkGMCJRDd/hr/Z2BgYGCZ5cAg8v0jg++C9wy6zx8ysP37zfCYXYFh" + "g1gww+VfUSiGwg2AaRZ/JcPw6v0fhv/qLxg4vv1jCOv5zPBvZgrDSukghp8/ZRkY/rFiGgDT" + "jBV84mX4572WgekzL8O/v5hBxoRXMwMDw/+3QgwM/3CHNeFY+MvMwMDyE6vtRBnAKPqWgUH2" + "OQUu4P/IwGh8HrcFBAORgYFhF/NZRhetP1jVAACsCFJPHjA77wAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_copy = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAATlJ" + "REFUKJGFk71OwzAURo/tpE2AdihiAAmQWNiKWICpDIhnQEi8A0+ASsXAzDsgIcTEA3QANsZu" + "XTMQBiqkUkFF04aB2sRJSO90bV+f+33+EUIqzq7bMam471UA6JzuiPRaMqROltc2KS9tMFhY" + "JVArAJw31qlfPWfguYCqp6j5Lou+S81XpmAWRGgLe1t13r8i+sMxYdAtasrFyYGx5eik4v11" + "DYHW8T6dl0/6w4i3wYjXjxFh0KV51ADasYYYQNUzKXlQDQYsiNnluzLJA6CsBKQgrdtHa2x2" + "zJdkeoq5koLvsYEc7m5bdqxqRwk8V5C4GFwlDCRKKdR2Egq01IkpUhJgCsmKtkdKJiHTOSFA" + "xoWQ7NFbgF8F+ZAU4PLuKbMopYBJXAhxwH5ZgPW5ZkH+tdC8eShyZ+IHUNNZHhrzal0AAAAA" + "SUVORK5CYII=") + +#---------------------------------------------------------------------- +_rt_cut = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAbBJ" + "REFUKJGdk0FLG1EQx3/vpRdv7sG49CKYxvSmVDwkpd78ALbSShQkbU81guAH8BN4EE0KGlCQ" + "5iAIoiaIwWAP3bi0WXZLW1q2WfGmJ8mhV19Pu+xqWsSBx/Bm/vObmQcPIWP4Jz83r96vb6pw" + "LJxzXfdWThKyuJR8/2rjOI4Kxz8ZDQUwkHosuGERwOLKsohLydpaKSIqfyjfrOsM8C2VSlKr" + "1RRAtVJRAK8mJ+8GWFxZFldui93dPTzvTFWqhwCMPnt6a3yAB52CWjLBSCLBwcH+P0f/7wpX" + "bouLywvys+/uB9CSCfRendVCkezMm/tN8PnwiKHBQX59axKXHWUACCFjAHyp15VX2gIgbdg0" + "MkO8LG+I7WxO+XeARwt5ngwPBw8q/eLe1wtI75y25QTCsG9bDtI7p+fFW6xmU0UAXmkLU9eY" + "OK0LNf0cIOji+4ezOSZO68LUNX4vrUbfIG3YXPf3AdD9o4Wpa5E9TV3jT8MC4Lq/j7RhRwGm" + "rtG2HPx9u6bGI4CuqXHShs12NqfalhNtIGSMn8cnaiczpnYyY6paKHb8jdVCMdA0Tz4Gmr9P" + "zKg0oZ3GfwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_font = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAIpJ" + "REFUOI21k8ENgCAMRSmMpwzAgenUsgDMhweCgUpRJDYhJG362v8DAFKJmZBT3W8A67LFz4Bj" + "T835HgY4V99DADqV24IF5Kk+WOht0QTkabm5twW03kHPeQoVIFV1EDFqjZHmtU55xLp2k8Bp" + "NaZdrwCcdhqlF5cHVHcJ4TzxwULTxJH4/zM9xQmi7UCACkKFWgAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_idea = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAVtJ" + "REFUWIXtl2FOwkAQhd8u3gAJp1EXuQEBrmOU24DxBtoWjmA8BAlXsOsPXNjadjtvRImJ708T" + "pnS+fTudnRpjezinLjR/Wq5K//W3+cwazbMM40BIPJ3c1GKPT4UKRASQShxruyuwWYMC6QRY" + "rkpfTZwBGCUhAGCzlkFYCeUxcTW5Ma521/Ay7RIFcFx9VouF5E0QAHB13VysFEBd7dbHYlxo" + "BUitXgohcYFwQLZ6VoJGpE+834oieQ9ZA5zCK3kWAEnyJMB8Zk1or1pJmpHaAe/zylUrRSvu" + "VjgTJK1YdRwD1Q4YuyDd+6DOLWBqgT2IAGIekGwFY30QVYQpJ+JZgJEYILUqzSASRBXh2+sd" + "Bn3XGBv0gTzPASyYR/JvwT7J6UQDOOdaYxq4fwcogPuHhQHQOuF8xilRHyaxspfnA8jodqz6" + "KvoWgC/fDwDG9n4f4FT60ZHsTwB8AA6FjDfFEDh8AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_indentless = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAHRJ" + "REFUOI3Nkm8KgCAMxfe2TlftCJ0u6ATa9eyTIqZiKdEDYfj25+eQwEKlo6qu5oOFABbq0eSD" + "dZldbBh7Ir3LaSTB7ozdEJstBOyL3xJA9bgVpyTVBmAJBK1PMPYMefx0YpagR7/6B2WCeGnD" + "CbhmfrKDC/GuLg9MR0atAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_indentmore = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAHlJ" + "REFUOI3NkmEKgCAMhbfZ6aododMJncB5PftlTE2TkuiBID7f9jkEJAO1xcyh5SMZQCQDbzTF" + "zbrMQRtOPOZnVxpJYIOTDbXZQ0BpwN4GciHzXoRykmaBOIPYXYdrT3DizzuUGv2dC4Kn+tU/" + "qBPooQ0noJb5yQwOwa4uD/KzgEcAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_rt_italic = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAGdJ" + "REFUOI3Vk1EOgDAIQwt4/2P0lopfS6YOgsEfl+xntK8kMBE1dI623F8Atqzox+73N1GTcgez" + "mOTDPEThJekAHIBHmhQwzCTfAyrpKaCSHgKq6SGgmi5qkHmVV3Nfzf5S+/9faANOrocplI0e" + "xSoAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_rt_open = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAbpJ" + "REFUKJGlkz1IW1EUx39X3zNRgwFBMaCoQ0sFJwfpICgBccgkQQlOIUWE0lJCVTS0KWhU0KhY" + "LeigoIMaQXCwgx9YR3XoIC2lpYMu4uLg0/jy8gLPQfLwGePimc79n3t+5+NyhcjJ5TkmPSbW" + "BwaM++ejhbDICqjy9hoPxaOFsKgPDBirUQ8APjCyQSSAd54mi7hVUWZE/B583TGmwy9YjXqy" + "QkR1W7/xEKBoOopyxXXihuPTc758dFDjasTdGTPvnKyPCoCcx9oqssmUlxTzqqI8Izb9oSNz" + "BICZ7/uWQKnTYfqq8QdoBOD91DIAVd5eo7bSZX2Fr2992GUZm02mZ26NN8M/AbgAdpKD9H+D" + "5rzPuDtj/F0Zwts3czeCoqoAxFWNhK6jaTpjXe3Mh+osXaWTfy2G2T74jbmDpb1DAi0NXN0k" + "LJCIv9WEpJMPZ0Noeoq5jR9sTgSFOUKBJKFpuqWiXZaJ+Fv5FIKRyxg740GSqSSQZ13i65fV" + "KKpKEfkZW09DnMWFxNW7Av9Oz6wAhz0XXUuhkB2SiCehEFBhcm2LzYmgAJCcBXZ2j/9nJD1l" + "tZUu0xfP/Y230rSdugX3RssAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_rt_paste = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAXNJ" + "REFUKJGFkzsvREEYhp/vzDnWWHuxdnsJjd+wRKPYgkIUKqHVKtYlQoi4FX6BiGQTolEpFBIU" + "/gUJtbXWdSMuo1jGHueceJvJN5nvmff9JiPiKH6UL5YMITrfGJWwfQARR5EvlsxY8pqr6gvL" + "60u+A3NT8wCcOd2hICdfLJmT/k+AQPPPXke6hcP241CHbmOxtboW5TRS0jO9a06HM5j7MgAf" + "lRsAzE2N15cLBm77A02NURxLSmUBUJlcvc5pYi1dAGxODDI7WgDgaHHEF8UBkERbJAQgrV2y" + "rZ510AixM5BEG+bxDkllMfdlVCZn46T071MXFvZ9cVwAiScxzw+hEIAm5ZDSsD05RLX2Tvnp" + "jZXS0S8AnUAgFALQ7AlQh/yVHSI6gcSTNo5vJiI0e/LtRJHWrh8gno6EAHhKLCTepHwzqaNi" + "McRVmNpTIA5U6J3ZC3r3AZz6IroV3j8wYCFn4532cN/OZeA/uAC98weRN/ynL78NdulpYuMM" + "AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_redo = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAg5J" + "REFUKJGdkr9rU1EcxT/3vbz2vfS924qRpmopVmIsFCWDiFkCAXHs5CDoJqSrJIP+BS5tXCw0" + "EHDo4FBUguDgULVQImJJLe0Qu2hqWyKNMT9q0p/XofRHmtrBA9/l3HPPPffcK4Sms4fxyRn1" + "NDXFYqG0z4Wv+kg+uC34B8SeQTSRUq/S87SbLU2iUn2D6/5unj+612AUTaSUEJpO/OV7Nfb2" + "Mx5TA2B9W6OyuYVjuGjVdxq4zGhMHD5QCE0nFB1RHl1h6DrZ4hrhgI/+nk7mvueZyCzQK00M" + "XadS32G5VuNyTydLywUqm1u4AMprNXxdkmp9m3DAx3BkoPHOg0PKf6qNrg4Dx9TYKJa45HEz" + "vVJGA3AMF7bpxjZ1zp1pb+ogMxoT2eIaAN4Oh+7THdimG2A3AYCUDtK2SE3NH9u2bLOwTTdS" + "OvucY6zuGlzrv0C1XuOsI/G0NL9YYHBIhXq9SMtqWtMAhiMDYjpXQNoWtwJ9hKIjak9w5/GY" + "AljIr5L7XaBcqyFtC2lbiBbj4B/cfzKupLZN0H+RX+Uqzz5+JR2PNMQZn5xR2cU887mfLC0X" + "+FH5c2AAcPNhQt290cf5Tg8r+SIjH+aaTJogNL1hgrGkejExq2az39Trd19UMJZURzWHRztq" + "mI5HxPCbT6yW1rni7ybo954YwHUcmY5HRNxOKmm1nrgZaOzgf/AXUUy2DjrCDG0AAAAASUVO" + "RK5CYII=") + +#---------------------------------------------------------------------- +_rt_sample = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAMNJ" + "REFUWIXtl0sawiAMhGcoN2mvqIeoV6RHUVwoC5VqiOkXFsyahJ+8ADJM8FRw3X0A9AAQfy3I" + "t2vWOGaYaAIAAPN8atp82y7ite4pEAOktCKl1Q/gKLkDiIpQovfCk3aPGQAA5MaGJYGo7XMr" + "RQD4RiCaJi8q3mSWHRVhSSDr5MtyPgTAPQJEOftOBFpq4OlIbElKbsOaIT5vO203uafAHcB0" + "Ej7UNjk6isBO/7dI48IsBdI3YBXg/7PrxfE1GwDeAHen2yjnZJXsxQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_save = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAQ1J" + "REFUKJFjjE/L/c9AJlg0ZxojCwMDA8Oee78YvOzNGGbVJBHUFFc7hWHfiSsMLkpsDAwMDAws" + "DAwMDPE+rgyvP39kYGBgYNi7bz9Ozc5Ojgww9U+vHUQYgE0RsQDDAGJcgNcAsl0gysvPEFc7" + "haAGWRFJ3C5AlyTJBTCw7fxVvBq8DLVxG7Dt/FWG0kBLOF+In5eBn5eHgYeXl4Gfl49BTlKQ" + "wTChCcUQDBcwMDAwlE1Zy6CppsrAwMDA0JTkjtdFTHhlGRgYfv3+x8D89wfD7z9/yDOA+d93" + "hq9/WBh+/f2LVR7DC3KifAwrGhMZhKXkGTQVJAiZz8DIyMTMEJeSRXKOXDRnGiMDAwMDALeo" + "P7cp9rvcAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_smiley = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAATpJ" + "REFUWIXtV9EWwiAIRdeH7dP3Y0UPxiIHXjR31kO8VIPuvQNFTCkvdKXdRv7EjzvXz1Je0qkC" + "NCkf6IlSevt7xCRUAiG2SH3QuJCMyJn7yIlKPLNdqtrMDIy8tU/w+nSy4WZgBrngtLJxECBp" + "tyyBiiI/FIDImX0S5Pey0FyENbgA1STI3xKxC/DeXoNrIPQ7Wg6YAQ3eswaiizhUgjMtE7UX" + "nzYUE8XQ6+A3MvAXgKy3w/XEZ6JyUES22LQYdTCFB5JNARDZ/UFi1ihoVIB0ts0QoomFvG94" + "UfMA6gciwrMI+XAJiD57vBayKn8PeXlWTUTRrtjb9y1yImMbRnaEkI7Mi1DALmRoyrdxvLcv" + "/sZYHi1HkxyM5s1OKOUY6YQR8hIbvBvim5H6PvNmhMSMkH4tYKZdfhw/Ad89rp/htXYGAAAA" + "AElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_underline = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAFdJ" + "REFUOI1jZGRiZqAEMFGkmxoGsKAL/P/39z8yn5GJmRGbGE4XIEvC2NjEcBpAKhg1gIABS5cs" + "/o9MYwOMuJIyetwzMGBGIV4DiAUEUyI2gJKwBjw3AgDOdhYrghF5ggAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_undo = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAhVJ" + "REFUKJGNkstrE1EYxX8zmcSZZDJp2rSNfSg22CANYhYijWjAjcviwkVxW2hBVyZ/gZu6aOtK" + "aLC7dicqwcdGiIrUoCIhpUVDsPZhq4GENqE2aUu5LuqkLxv94Fvce885995zPkmSLRxVffce" + "ikQ6W123N7i41XOR65fPSeaeFH3wTAz390h7ib2D4+J9ZhGXajskWqxscq27C5MjP0nOEInF" + "hQkIDgyJpeUCvjoVjyrjtCoAOK0KHlXGV6eSSGUZefxaACgu1cbH6W/0Do6LL/M5WjQNpyqz" + "tb3NbKnClaCPwMlmpudzJFJZ/G4Hhm2b+OQMAApAp8fOykoRv9uBrlpYq+yQU6NRKbXn+ZFY" + "XCzNLeN22Jj9UdoV0FU7umoHYK2yTmblF6nR6D5fAFobXRR/5tBVO07r+o6A06pgGM59QMOx" + "9ddU4pMzhDu8ICtAHgAZwDhmrXZbYz3hDi/BgSFxUMBjkzA0jbXNMucDp3YEJJsVQ9cwdI1S" + "uczCaoFsLl+N0ySHI/fF1eAZDF3j00KhGqOyWCgy8TZNa0sDXSeauNTuqw6KaWD37Zi4caGT" + "ekPnXeYrp9uaePPnTKo1iSb5ZjjA8WY333N5JpKfeXm3f9dgSbYc2aHomHj6Ki2mMnPiUWJK" + "hKJj4iBGrnV7yO/lrL+dfHGD4RcfSI70H4q25hdME0vlDZ7f6TtE/i8P/lW/AfYJsF99ZciZ" + "AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_zebra = PyEmbeddedImage( + "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" + "OwcAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_bp_btn1 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAABLpJ" + "REFUOI2NlVtsFFUYx39nzlx2Z7eX7S5FyrVcKrcW5WLLTVJAiZAGCQFjJEGixsTERHyQxER4" + "wQf1RcODl8CLiRElJBARqGBUioi0GKDY0lIopaVAW3Zpt9vd2Z2d8WGgC3LRk3wvc+b8zne+" + "//+cT/CfY7MfXyqCo5tgu0g7QVLvgx3W41aJR84Ym6txeQ1pPItRMArdrwKQTqSx4p1kU0eR" + "7CT5acP/A5vvjyKb+gyzeF14eiVzq8oon1bEiJCOnYVrPRZnzvfRWN9MvO1Ph2TsK4L2FqI7" + "Bh4NDmwpJ+vsN8sWlb60cRmvrgpQOgJsG1JpyDreb1YWznfC1wdiHNtXi3214TSKfJHkx10P" + "gn3vjkXIusi8mvHbP1jM2kq4EYP2m5CwPKgiQCqgKBAwAAX2HIfduw6RbP75NIH00ruZy2Gw" + "rPwmOG3ZMx9tX87quXChC/rikMmCpsL0sd4G0UFI2xBPwVAKykaDHZpC26VoidN7PUT25I85" + "sP7OavLHbd20eT0bl6mcvQL9Q2BlQFdhaQWMCUOBCX9d9sBp25tPWlAShqvWaHrbGmcjZh3E" + "PtmtAKCob46ZvYD1S31c6ILeAYgnQZNQXQ5Bn3eopg6b/gQMpnIxkISsDeUzQpilVQpCvAGg" + "kr+tCE2fX7WwDJ8KrZ1eNqOL4Pmn79QSOHTKovaciqqCEDmBhOLVPpIHoUnTSF2pW+4UbDMV" + "ZHaULHyicOqkApquQnMXSAEr5+Sg9S1p/rioUpQvKQh4303DE7E/AQNDXtb54QhqMDwGKzte" + "VTWRb+SFEFLhTLuXzYYl4NdzLqyYqPPU5JyFHBdc13PK57Vwus0TWGo6MlCgq5lbERXVj2ao" + "JNJwLQZjitw7Nc050dAeuEbDIxx06RsUDGUg7YJmaLhSF6rwGYOQZijjcispaG+DD/dm2Lpe" + "G4bXNWU42eqQ5/cydVxwHM85R5pU+pMSBPgMG+HaGambMdVQ1BsZKz54Oz4UjBQFSMcE+89r" + "+Pw279WogKBigsZ39S7H6sFQPfBd+QwNAkHQNRjojeO41o2EonbIdPTwkFa8aoUZGTlh4uQQ" + "iQyYpqD5psJAwqZqkoJPE1TPEHTEBDFLEAwITL/A9INheJEXhJtt7fR3tx9IX3j7WwVASrnz" + "aksbWdehJAJmAIpCgtpLKjuP24CLX4NX5oM/AIF7wgzAyDBgW0Q7LiJ1Y9fwzUsv3vC36I4v" + "w/CPmzojjCbBlWD6BK23FAaTNhETjrS69CQVfD7QNNB0iOSDzweNvzfR19m5p79+0yf3SR9a" + "snumKmXdvBULCudWlpDOQH8KbAfsrIvEwREKqiJwAU2BQr/3EJ34tZ1zvzVcVhy5qK9u7fX7" + "PQWEl+6rlqrYO2txRWjh4nEU5ikMWZDM5J5MVQFTB58OvVGbY7+003yqqUPBrek5uqYxJ+u/" + "xsjnfpjpKnxRPG7UwllzxvLklELCBTqa1z+wMi59UYvmltucbbhCtLvvgKbYb3X/tKbzXs7D" + "W9O672VxIvgyKK+b+f45oaK8oBnw4bouicEksWi8PzWYOgF82XPwhf0PQzy65909QU1tqeOI" + "MgcngiNdKd2bmm23XDu8sutx6/4BbTzYDeu8eUUAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_bp_btn2 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAABLxJ" + "REFUOI2NlFtsVFUUhr99zj7nzKWdtjO9DBWkYGnLrS3XREIaMCZAguCFCCQGQV7wFkzQaHyQ" + "QEKMDz54iRITA0ZjeBGJmCCJUoMiBEEQBCmUll7odWbaubTTOTPnbB8GC6gVVrKTneysb/1Z" + "+19LcF+xU0Kvmb9PsmFX7l4ZYsKX4M4AyaEnUPpqpDUbXRYB4OTi5DKXEO5hCt1DxD5I3D/Y" + "2r4Z4XlLlNdMe3DWHGbUVVJR5sNV0Nc/yrWWHm5e+QM12NKOm9lN5r399wDvlHjieyms2tq4" + "ahVb19fQNBeKfOA4kHPAdmAgAccvwoGvr9LSfAQSNz5lrGjbnS3S7+Ka8/Zp4YYtm3ds4v0d" + "YeZMgZ4odAxAVwT6h2E4Ba4DNZWwZFGIYX897e3R+Wq0owrn1KF/g61XXiY4442trz3D7s0+" + "4im4MQAjGUiNwaRiUAoiCRjLwtAIKBfqqw2iZi2drZ0N2DUxnFOnb4O9L1ZCwYGH12/0vf1C" + "Kb1R6IqC60JiFMIl8MhcmF4B/XG4GYGcC2kbcjl4oMLgWryceOuFhRgLviB7KqUBoIxNVtW8" + "0ueenkpyBNr6YcyGSBI6ItATcVCuQuqwch5MLYdYElJpGB4BQ4OG+VMxpzSU4YpNAHmw7ltT" + "t6iBuslwpTuvJJHOtyKZht87ND7/wcZxFLoGaxfDjMp84UQa4iNQGYTi6kaE5V0LICl5vQgj" + "UDt7VpiBIfizO99yQ+ZVaxpIKTjXZSKPZ9mwzEDXBBuWgp2Dky1gynxOYUWYIV+gNmu+Gpb4" + "9QIpAwWBgIdzbdATg+dXwszJt35Xu+1MxzVB5U2qCXh2GQzG4Xw7SAmG5UH3BwpIpkLSqwLC" + "tTzCQaMzCpquWDAdTGPioRwvJSBUqIiNCEaz4AgNaXqEY5ia1P1yDOlmRu2sEbMlfUOCN7+0" + "aaxSQF6ZJgSZnMJvwZrFJqbMF22+mGPfT4LkmI4CLDOLkG5G042kTBVejXtHG7tjw6m6YKWX" + "aBp+vG5y7JpCiLwqpcBnwZ51jENPXMmx6xuBLXT8fjAMiPelQNndGcPXq3H2k6zQRXN3Zw9F" + "ASgKQLAESkOCUFBQUiKYVC54Z6OgqS4P/bUtx57vBLpHpygAhYVQXAxjQz04SjTTuj2jAUhL" + "7u9ra1GJVJopFeDzg78gf0wPNNXBkofyfT3fmePdZoH06gQC4CuA8hCobJpYR4uSutw/PnmZ" + "3sM3zYq1VRlHNs6sD+OxwNXANMGywMGlqsjlesTl41OCnK7jtcAwoTQAHg9cOHGZWHfvZ/Hf" + "tnx0166Q1etOpAaH1rjSW1o3s4RiPygdpAk2gpNdirN9GpqpY1ng80C4GLxeOPNLG21nL16x" + "TbXR7jg4mjfnHRFafqhW19S3NYtnVzctr6I8ZJC2b+0E95YADXwmeEwYiGU5fuwGV09fanVc" + "sTra/HjLbdf/I0pXfDUJ1/gwGA49Wb9wGrNqSygNWuO+trOKSCzD5ZYhLpxpJ9YXPYiWfSly" + "9Kneuzw+kfnLVhxZoXRtm98nlwaChaX+Ai8AI6k0iVgyMjJq/ywc9g4eXXX0P4dnIvDfUf7Y" + "9xUq51S7qDIADTEopN46cPjR/v/L+wte8dZC22ApeAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_bp_btn3 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAA/9J" + "REFUOI21029MVXUcx/H37/y7594ul1tASKL8UTHTxD9zUxwYK3OK5sgVlG2WzuZKe+TaatNm" + "60mbzc3+Th9UWipNzdkqjRqwGsGGdsNpjslVQLjA9R4E7p9zL5dzemCY6FVarc+j8+D3ee37" + "O7994X+KGPtQK+prM9P00ril2EKRpIgpx0yhvMOx2btTNjfFXkKTdiMpHkmSbEXCTtqctfaK" + "JQDK2DkNueSNF/Idj8x5gIuGxQV/XPvyZP+7g+suTeXY9NfGo9EdXo/YaauqEh8VTHnwxoT+" + "bhZYfx2Rxs5GLHnX+0f7k0P9Jo/NcDB3pofKVblSRpZrG8/3HL+Jbox+UjhJ2pWXoylCFuRn" + "g6ZAdx9W0mLPHb8CgJVnqjz3OT7bsWGyvrDYy4/t4POP0uQbxgjbtSja8PypaqXLrYlzvZB9" + "P9g2dAYYSSTZzkdi7xglj4Mv7Tsfn7nV13BupCLLI+vLZjnoCUsMjGhEE9I0VVVnOZya6LgO" + "GV5IJqGjl2jSZjMfiv0pH29cqtqLsPX6zSvTcyqWujjQLPjpPERNkCSYnAlmAgJBBmyL1Xws" + "Gm8npFQuNdPacIsl+2sTbftOJaheYLOoAEbtG+hQBHqCdNsyZanQu088lpe7XZgZtSWPaiWb" + "HhfUtsHJFohGacVBOXuEcbfqvWGAt2yFHo7PyWONqsFvfhqwWMU+Eb1XbWL4Bi7Rx5uAixhv" + "87kwJ6r8DZeeKCMUrGQkKlBUGU2/itO9n6ZnU1/3mTo3MX0jsjwD1FEUFRTtO2qKfhgHO8sO" + "DzxZmu2VVY2wKbjSNUTbReN33GlP0PDUtdtvIFp+rRPu9DLb4cHtknE6BIYRiyQPFrrhlpWO" + "Dw6E8rILvdteXcTVsODMHwkOH2otPtPU4WPZ6dU0rPABsLypQG1pPJU3Pbso5MxD0RWmZIIR" + "uE7QSA6NeTcXxM6uONLcGKjoHUhklS6exKisoWY8hGnLnr6A8RwPbz7N7FdUt5psmj8vNy+S" + "lk9CkpnstejvCtHVOdyJ0Mpofe/6OJi+byNMq/7igs8ob+8M564ozULRVUJ2BnFb0weCQ+tl" + "rC2LFhZkhhy5BE1BjidJz5Vr9Aci59Hkcg7mdt75eLdmbs2J4sU5a3e9Po+OaBoH6uCyP0Q8" + "YSPcmeguyHQmCFy5xqAxUs9X+eW3E3Iql76jR/q0dbktrYPzV5Ski+lTdX5udzGYcOFNB49q" + "0tMeZDic+JqaglWpiNQwwNVD3xjp661fzoZLl81zSUuLnXQZMBqN0OsPWrGY9QFHCl+8a3/C" + "LG/ekP60z9z5vWFvOR62qb48QpV/+0S1f7Z5a8+t0XTHp6quqhFTbKUm/+C/n/Q/5k/sN4aU" + "VfMVHQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_bp_btn4 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAABG9J" + "REFUOI2N03tM1XUYx/H373bO7xzgAAJGCOEN5CaCXEZpstlkZbY516i2bJUuHEvTudpaLWZt" + "6VotyaVhzWbrolRbFy+ltnA6UQyVywTxriTXA5zOjfM7v0t/oISh4vPn9/s8r3337PMVuM+S" + "ircfcwhCnm8ouJlE9zsc3qDfs/++1Kxamxqlb/xoU5nLriqPtv3lryDuCTfu/WfuNiLcXasS" + "yUlOwNJsmKIqO6T6nd88ExeT5KL+SBe7vmrgQvO1FkSxkrOvHp0YLq2S6Ut4C8F60RGpxDlU" + "WTJNC1WRHBVvLxPM6GgcdtBDBqeOXub4vkaz+2p3Haa4ko41l+8M526dTDh8OG32lIziRbNx" + "PZCArChYgAiINic9AREskBVwOMHwh+hpaud0XUvoRo93u3Wmcs3tcGmVTN+klvR5uRnZi+fh" + "CysMayCKN18gQBTgDoIogGWNnEt2iI+DYNs5/txVpw2fWGUHkEfh/rh3J01LzshevIBhXUSV" + "YNgzgHfQCwJIokD89CRcThlMsKkg28DdOciRX0/T13ahG1lYf4v7DxbE50rKcslMFTFNqN/T" + "RP1PxzRdN3sBUbbLiYVV5eL0xFjsCgz2B2g41EpTXbM/5PFto33d62O3OgpHudSkksIYZiTD" + "pQsDnNzbYOq6sYTW1QfJqrUJkqczPVVJiI03+f3nNg78cEp3dw58j2pbS/u63v9nYBQOaqbx" + "xQeHsNkky+fXhIBm9tK6+uBoo12Srp69zo597VZL/fUGnMpKOta2jkvVuFQU1pTi1SYT1g3s" + "koLTfoXGihOj9wWfbRY1s9QM6ZvoWLP7buB4+F6VWZ0P0kZUuZ3Tq9aOnhdtTycYSiVs6gii" + "jFMa4FRl48TwnI9j8LIlOT3+2UVPZcq1u1v8fr82lcaKfgDyt52LdqkzIyJslm5YwsBAIKCf" + "fCUKxqZibKV+qaJ63rTbnetLl+ZELHs+H9OE775uNgmK5shqah5UQtpDK9Y/JuYVpXDj+hAf" + "vvGLo/8mMR7OqX5ZFAPvzSrJSZr/5FxSpsXytw88Xf9ghLQI0I6TsyVMUEuZXTZHdSalcKkP" + "Os4HGfQEPIyD82oeIWxscz2UlJu9sJCUzCkMmdDdPrIwp+Agb+lCUdetNMuycERHkjg9iaYr" + "oDqhfm8rhqb/MQ62ycZv859+OCoiNw+PFzp7AGsENS2Y5FCISEvDGFkEpjnyvWMjLM7XnaGz" + "paMf1fbaODgcFmsvHm9/Ya5TVtIyZmGpCgE/mAaYQKLTQlE0DNNCEMDULbx9blr2t9J87KIb" + "m7KExoquW97tqciqzsKyPk+eOaWkZHGRmFOcgiiL+IfBHvTx4yd7CA5rmiiJ+IOG1d3r91lh" + "/QA2VyVNLw2Npe4ct+zqMgxpa0bB1Bnly4vIL56Mt8fHiuXf+sMDwccxxH7sQJT9Go0VgTsa" + "96xZ1auFnE/d5RuOWDsbuqzIBTt8FNTE38/oxD+voMaJP/R+TFzkKl/Y6NR90VmcLdcmGvsX" + "ZajORhkOFtcAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_book_red = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAApVJ" + "REFUOI2Fk09IFHEUxz+/mdmdddddd7Usc/2LYoSWsbVqWIfoIEgQUd2yTt4ju3SocxBdO3Qq" + "6BAEUVFRJCGBWaQZ/gs127RyXV1T193ZndmZ6dAallZfePAO733gve97gn9LrMvt/xWIyyBO" + "VFAnUoRtD/vdW/yhlKbrnSOpjlcQBTIbAKkGDtp5ol0u8O8Tqjtkuz1+NT8PLAucKmQ1Hj8f" + "fXps2r5gwPifEPlSqLRPKalsc+4NVcuW7cqW1mCU1GDuPoTZeBhFT1MrrdYE55Z89zXeAyuA" + "9QtwPujoUgu8+VlDIGcSJMLtSEXbkPLyUUwDSXXB7AS7A44GZXrFeGEyCiTXIPJZR7q1uK5s" + "Z+LjNK6S7SjRCHL0M+pAN1LfExh9C0YGyamIRp8jvPg1Nd9vMwmkAFtuMpnf5dBPu4PFIrGY" + "wp2OI8fnwNBBkn/u2bLANHDlC6lJyraMzJtTkxABNKljmddjkwv3hJ0hvfAdPAGwLTBNMA3I" + "apBcYnV8jpHeGIMle9ymEPVAFeBUAO1RlCvlQ1/aixurXEuRGH6vDrMLRKMmo4WlTFW0YJxp" + "xRVuIVhepj2rq1YBDyApgHUxy3D9p+Sto+Wxzp5IkoXgTpaaT6HvDePz+/F5vRR6PLi9frbK" + "dl5XMc6rMTTAUnJupO8sc620O3byRtvxQFnoALWVFRT5CgiILDVf37F17A0F/T1a//S3QWEC" + "4AfUNYB9GyJHUlyvtNMXG1cmaO59SWB4wE5OzIzfjfPhoUF8wMLUbZaBmZyV9m+nvAd2nHPx" + "QBdkbmpMDkFmBdJADPiSi1lgGUgAq+sBAA6gGmgF3Oua4sBqzvs0YJJ7rj8BACoQAKRcgwbo" + "a6NuUr+pxF/gG/QDEGYH9mMazfQAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_book_green = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAopJ" + "REFUOI2Nk0tPEwEUhb+ZQgeYtrQ8lPAsTwkREgJUUKLooibEhSG60YWu/AWGhb/AjSvjxr0m" + "bn0gC6MkoBgCATGCsVILyMOW8ui0006nM+NmICjxcVY3ufd+yc05V+DvEg7V1r8GBK4i0kUr" + "CgGhkJ6KMrkrmdJV5UH2BmF+ANpRwGMuYDBY6fJ0+wRnZ6kkebwuJ5qaxZF1ocsZxp4vv9Tv" + "M4xO6HeI49yt+rnGQv/5YEOt34jnS3WOVqrMNk5VBDldFSS+twXVieYNKeVmlg+AApgHgLJL" + "8p36Go8Ujwukswku+i9TWlyOLLlI51LITplwcgHZX9ARs1SdBRaB1D7EobZrA4N9zY0Toe9U" + "VBSxvLlKRA0xtjnCWGyU2d1ZNMNCdIpCfo0joOxpMSJ8BVTAcmjHjbjos661t5QLS5EMirzB" + "lh5DswwEnJiI5EwLLZdDlC1Rr8n16StWmCgRIC3yhPF3b9dGJMtCM1K4hBJypoCBhSYYpEWN" + "HXOPcHSXb/MJ2pKdRYicBOoBZx6gah9zd1+PR4IDA/X5b+aiOI5prMd22IlCtVJJt3mWM6X9" + "9J3opbaqWm0abpIAGRDzAJNXzHyp23rU1Oy5ufF+mwZnC9e9/QRKevD5vbiL3bhcMt5iH6LX" + "KCKAkynSgJlnu5ExFrj3bDQ8NLR8xdPX0UtjbQNutwfdoTGVmWB6c5KJ2Hh6Y3lv3g6gD5D2" + "ARaThGjhYVbO3F7IfmJk6QUzqWkzsa2ECPOZJbaJomOgACu2ldavUfZTSw9PUVFYJMw6GhnS" + "QAxYA1aBTWDXDlTyMAAgH2gC+oECe2ENiANJ2/sMYGA/1+8A7EWf3VOBNJA9OPU/JfwBfkQ/" + "AU/kDpSM2ckCAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_book_blue = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAn9J" + "REFUOI2NkztMFGEQx3+77Hnc3e4dRwSJPETeBEwk8lIphEITqaAyxkQ7GitjLEyMrY2thZ2F" + "DQUFCSpGEiNBjJHwChHlkRM45Y7Hcdw+WW7XwoMgxMe/msnM/DLzfTMCf5dwwHb/lSBAr8g1" + "oQZVbMYnNyEHz2Fu67y6f5PEWAywjgJuL3cg2FdRvI14jQbwBRF9oBuImDiuBNNDLxnouQf2" + "3GFIVlHXnYkChfZUcXGpP77uPSNbNAc1Oms9dNf5WU1axMivJLtcYWlwEkgBzh5AXNkyBU9u" + "LvnrUcy0QHtdgJpShRyfRMKAsyUySBJUXrxBw4Me4CQg7XdA/pVLdkt9uXdhCS0QYjWmMhNL" + "0zelMTyRZPLLBpgauGkBpaiZHc8am+PzgA64WXiqN0y57Hp2dbmgrCwQUSUSSQssC9wdSNuw" + "u/vLd1wRX+l5jO1F1PkIYIhMPxxm9O2LuCNiih7C0g7YFti7YNlgpUG1Ia5DdIOGQsMvCOl6" + "4DRwTAJ0vn54xLvKy8mOVk945D3YPkgYoKY4EUzQWqhxoT2Llio/RcUFesWz114gAIgS4PDj" + "yRjTtc93K2puGYvjNOebtNVD4ymRUEhGCYWQAzLhHAXNV+CnsPsY0T4DcPZe0+T78GMG8ro7" + "C/qDTTV1lFVWEVQCmK6fNxEfI5Eshj5rBt8Gp3AEAQgD3j2AS6x3jry2p7pw/O5MXGZgQeBT" + "xHFSq2tzqB9nSY5uoi/YuHYKWAI0wP19lXMaSsjr6sdWU2wOLaLNWqQ1A1gDosAysApsZRZK" + "PQgA8AAVQBuQnSmIAhuAmvl7E0iTOa7DADKF4UxMBwxgZ3/U/5TwB/gR/QQ8K/3nl/ZkqAAA" + "AABJRU5ErkJggg==") + + +# ***************** Catalog starts here ******************* + +catalog = {} +index = [] + +#---------------------------------------------------------------------- +book = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAhBJ" + "REFUOI2lk89LVFEUxz8Td8yGnBmTsnSKfviIRGph7QZCIYNoIfQvuGoTtGoVtGrfxkULF0E7" + "F0IFtol2FhqSbVQEbRYFI4SvUXz3nPNui+c8FKaVZ3nO/X7P55x7LxwzCgBTrxdG84yAIIgI" + "b5+MLwFMvnw3KpLlRATZE0T2+DL9eKmQiQuLl/pKpKlhlpKakXhh6/efm957BvtOfycYqoqK" + "oKr82PhFsXTqtgtpukjhBM8eXs8h0jRl/tsWqz+b86bKvVs1Hty5egR9dOoVXcXiogMwMwBW" + "VlYwyzqNjYxw5Yy70NNT5mJ/L8vLy5gZrVaLer2O9wniu3AAqgpAFEWYGSJCo9GgsbnJ8PAw" + "SVIiiiJEhDiOAfBJgj/ZhQsBVASAtbU10jRFRKhUKsRxTJIkeU1VabVaDAwM4L1HvMelpsiB" + "QRRF2aJUaTabhBDymYeGhlBVdnZ2ssvyHhHBqSriPSEE1tfX8x2Uy+Vc3K61CWq1WmbgDxkc" + "JvDes729TQghp2gTtHcgIqh4nEomAOju7s47lkolqtUq1WoV5xzFYvGIYXtUJ+LxScLdpzOI" + "F0R8jjdZv0EIgTcfFrKOqtiB0MxQUZyIcHnwbMd3Pvv5KyrK/YmxjvW5ufe4/f19NuO/B52P" + "EpzvP4eZMf/xU0eC1Cz7TJ3i2qMXM7u7rXFTpVzpXd2YfT7xv7PHin/ZG4/t2teD9QAAAABJ" + "RU5ErkJggg==") +index.append('book') +catalog['book'] = book + +#---------------------------------------------------------------------- +clipboard = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAf5J" + "REFUOI2tkUFLVFEYhp977h1znAnSCRKbEaGwNgZF0K4gV22iP9Am6Dc0ENU2cKFCtKtlq+gX" + "ZLRqIS2MiNAkyKLSgZm8jV7vnPN9X4vJQRlrU9/ucM778HzvgX+c6E8Xs7Ozp8rl8lMzk2az" + "ebVer6/9FeAfTE1z5Ph9xU02pBI3T14vlkZPuEKhQHN1UY68f7gz4r+JBVayfKs+enttASDp" + "oSq1GVepnE2OllluXOHShct47wEYG7sWv8yT0rQ8Jmxn58PnjzPAuX0A0WgyGSnz6PUUb989" + "59XiG0QEAOccjY0Gn05f5Eb1BZLb5G6uB7CgIJ7iUIm5ufl9e4pACHD3Th1qEUECfQA1hRAw" + "U9rtwOrqNnGckKbrbG5+pVqtYgao4n+b7Qd0chCPqlEuJ4yPHyKKHHl+jCwbZnDw8K4rqgcB" + "VByimBmtlrC0lDEwUKDdXidNvzAxUeuFvA/W34HsRISAiCGiOJdjJjinxDFEkQMMRFEV7Tfw" + "HkQwM7LMk6bfKRQSvN+i0/lJp9PZVcVrL7+3xEDXIMK5IYaHS8SxI4SEYjGhVKp0SzRD9YBf" + "IHQNyFvMz93qPt4zZlCrlLqWcpBBCCv5ZnrmZnUBahGo0qOo9s6tjQZm9qEPsJX+uBc0PFOx" + "yEzAjKCKiBJECCKICEHDMlnnCf9rfgG9Rixh8s0DuQAAAABJRU5ErkJggg==") +index.append('clipboard') +catalog['clipboard'] = clipboard + +#---------------------------------------------------------------------- +code = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAw9J" + "REFUOI1V001oXFUYxvH/OXPv3MxMnJlOk6atQR0XdmGtVNCYRYyg1YXgVkuL1HShC4VQW4La" + "nR+LFqEoSoIbwRaKFEQkRYwupBG1kAoumqih1U4bms6Mkzsf9+vcc46LmqE+8Gx/vPDyCP7L" + "S19ce0xIe+r+cm48UIZAGZQxBKnxhbUdK2gIhMbSAppI87nXaHzrbALWpGN7tg2OvzE5zJ3p" + "JaYUJKbUivRooqATa/5qdDm/2t0XFivTfUCn6UgxKwCobWhcIXAEZBzwXMk9niQjJW4G9o7m" + "2FkqVD795cYHsg8kqlg2EamBTiLwFbTbEX4EfgTNEG51NQBvnrnGeLXA7uHscB8YDDdGnvhq" + "jvTlQ/QiTfXEDEOffUTg9+jEhm5kCRMwgNBtfr7SYulvf00C2MOHKzNLZ58tOCFKOASxReHg" + "0mH73EmiVodebOgpAxbW2zGnFlbbOlGHZHzw4Ithu3Njxza3ZGpNakffJQUu7Z8mue6TFT0e" + "ODqFt/gDUSowFrSrceK0+uXrjy5IHUZzydjuAXNpBY7N0B6sICToYoU/X3gNfv0dNfYgd8+e" + "QCqFtZDGMS3V0wCSKHxFnl+MTHUn4vjb2Ft1JJas36A6+x7pfTsQ84vUpqYRWRelNd1eL/1u" + "5uk2gMzPz5+dHZ0cu7K6gRr0qB6ZAgu73j9GpugQtAyXZ8/hT+wj50KzG5PGyTpC2NsXAPND" + "u5IPJw7gxJCp10FIZKNO4MPV4ydRhRJYyDuSeitEJ8na5vecySNnhtI0euehPXvpTp/m++WE" + "Qkfz0ydfM+BaXAeymdst5mG1FqCSeL0PRGH8lLT2uaXlq7RCh25sUdoSK0GSGlJtMNZSKZV4" + "9Znt3GwG6FjV+4BRySPPP/lw7q0Dj/9vA9qC0pYkBSx8/M0aeRc63QCdJs07AHX1ZsPn9MIy" + "5cEc5eIA5YJHqeBxVz6Ll5V4jmT/xAieA/V/OuhEXe8DJPG5CxdXRi9cXL5XCLEV2Ap2i0Vs" + "wdpSzsu6AwMuxUKOcjHPbyu1P8iYHzeBfwEwiol55ANRRAAAAABJRU5ErkJggg==") +index.append('code') +catalog['code'] = code + +#---------------------------------------------------------------------- +core = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAmJJ" + "REFUOI2lkk1LG1EYhZ+ZuQljPsSQkFAwbbMICKnQRXfRRegvEALG7uxPKbjJVuii9AdM3LpQ" + "F+4rLUERi1QUP5MRgwmaxNzJzZ0urCGpiy569ud5z3k5huM4Pv8hAZBIJLi5uSEWiyGEYHNz" + "k42NDbrdLq1Wi06ng+8/3TFQqk86naZcLmM4juMXCgXa7TZKKbTW9Ho9pJQopZBSorXG9w36" + "CnzdQWuDqakparXaY4JkMkkymRyL5vs+vu9jGAbdbg+tGkSsn6C6DCJFhBBUKpVHwKju7u64" + "vb1FKUWz2eTs7IzvP3Z59ybE21yKF6/yqHaXQMACwBw1NxoNTk9PkVLSbDa5vr7m5OSEr18+" + "8+HjJ365rwlEsvT7cvyJAFJK9vb2sCyLer1OrVajXq9zfn6O1++j+pLd6jfeF/L4vo9pmuOA" + "w8NDdnZ2ME2Ti4sLXNfl8vKS4+Nj2u02AGtraywvL2PbNpZljQOurq5wHId0Oo3ruriuS6PR" + "wPO8x66mycPDA0ophBDPE8TjcY6Ojtjf38c0TbTWAASDQSYnJwmFQmQyGSYmJjAMYwgwAQaD" + "AbOzsxSLRQC01gQCARKJBJlMhmw2SzQaZWFhgXA4PNzGMIFhGAghKJfLuK7L9vY28XicVCqF" + "bdtorVlaWiIWi7G+vv58yk+RhRCsrKwwPz/PwcEBANFolHw+z9zcHNVqlcXFRQAqlQqlUiky" + "NqRwOMzMzAy5XA4pJZ7nEQqFCAaD3N/fA9Bqtdja2qJUKtmAHAJs2+Zv2KienvbHbIxVWF1d" + "rXue15+enn7JPzRqBvgN0r4cgCHFMd4AAAAASUVORK5CYII=") +index.append('core') +catalog['core'] = core + +#---------------------------------------------------------------------- +custom = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAvpJ" + "REFUOI2lk19MlXUcxj+/933PezwvdF4OCBxg5g4cp9IQDHQsxWq6YsNlUW7pNKYXtLm5vGhz" + "y7zLorpwja0CabU2HVt1YUuT/jAxU0eaOEUMEUqSIxzOOXA4vH/Ov7c7Jce66bl7novPvnv2" + "fOF/Sjwa7Fu39HBFQeagLDs5yYxD3BbG6Kzr6Infw28vBpAXmtZa38GqUucd7TGhKm6BJAvA" + "cQnSDQXeXOn2lHn2UYC00Kz1Z9s0TYhYPEN0LkPCgqykosiK8LlSBxa74F+AmbkMJU/vY+f+" + "Qzz70l5C8woRS8FQ8tA8suej/Y3u/+ygc/fyyO4Pf8hP3uklYZhMR2fx5mrolVvoadser2vM" + "b80YwW45t4r56T6w7rUoCwFmVhsy717ZkHYvxZeTxldYSiItQ3QYfZkaydU3d3sqGtADa5kZ" + "W8lQT9cHD0us7XDdSSzZ9Hj4m+qamipQvQhJQXUsrvzURk1Ts+4rqxdzE7eQkwaat5jZyT8V" + "ARBsPO2OEdvrofjjM531DHbsxMEBIN83T13jBvTy57FD3ZgRwdQfBknTjlh24ikZHJEKDOzS" + "1WXHejrXc1VoXF6xg5HyHWRLSnihxkYPbsWa6ERSDaCI1Mi1SdOwnqt74/Sgsrr5i21lUvjz" + "199s5lxEZtBwSFngv/8te4IX0YMvYt37BMmVJhkPMP7zb3x2Y9WnR491DABIxyvf//pES5TJ" + "m99zaQKMmKDw71O87LtA0RNNJO93IasOdnw5ob7LFAWq2a73vfVgB5IQkuLWOH9pmqBi4Bvp" + "5tWCi2SdUkLX28liMR8t4+4vtzhydRsuzYssS8pDwIoth8Z6v0wvSYbSJ4/3s97sonJjK+7x" + "8wyf/JWBnij9Z65xoLeJPGfcGD33le2p3HzkAWDNa+3vafWb8v1+/FMziY6h21MkB78jUN1A" + "Ts5KxvqHeffsM7G/UkU/qi41oD1ZV7impf3woksEeGVjnllbUaysW12O47Iv2OHwnq1t10cX" + "+wOAfwAJ9yQGhieeeAAAAABJRU5ErkJggg==") +index.append('custom') +catalog['custom'] = custom + +#---------------------------------------------------------------------- +deleteperspective = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAnpJ" + "REFUOI2Fk0tIVVEUhr+9z9nnmrc0095RVIJSCNFAGkiEFDXIRk6aNCkIoiALIiKiJpZBEyuK" + "GkQIEUhCCGVQg8pKJJWil/nonXY1vd6Hj3PuOatB96aV1IIN/2Ctf63//9mqufXlYF7OzJAv" + "QqYCgYkxF8/zGBiKat8NhqOx0S27dmx+wZ/1tKNrLAgCmfp835fkmCexuCcdz3ulq6dPmu62" + "D1yuu73hz3n9FyOglEJrUDpAW5oFCwvYUFZSUFS47M61Gw8q/0sggAIcx+bd+0+0tLTT9uwV" + "fmrcScSi9UePn6v6JwGA0gqtYG7BHNxA8a1/hO6eTzhZDvHESHWmz552GNBKkfJSlKwpxh33" + "GIxPMNTXhzEOrS3N00gIfHjdCp1tBEBKIGUMid5e9OkDmHsNmOwwjmOw9OTeSfT5LTxpgmQU" + "+dhLsqwS+dBJXu0RQveamLH0Md7qUvS8xSjFNAQLV8KyIrjbgNV5hfDTR+jubszD+3iLVjC8" + "9wRWwXyMCtIiMwRpPK5t1PpK1OgE5vpFQi8bITKMt2oNQ8fO4y0vxkoksGwbNeUEO2NCygdl" + "LGydhfoSga8DEB+HL99RgUI5BkuBpTJBp00MMs57Lk7dWUI1h2FgBH/tOoJwPqbtDflbNxG6" + "1QgzstPbJy/4lYLd3IQ5fwr6B3G37yR+9Q7JM5eQnFysSITZB/ehI/2IcX6LfFJCaTmqfBuy" + "pBB3VxUigldRQbT+JtmH9pPcvYdgVi6Wl/pNgh2kcTgvB05eQAAD+D6IgL9xPW5HO8oTwkkX" + "2zZMzdEeiceT1TW1Ka0NP+3xUViI+IiApH+GiIAISmmSsdhEhuAH7okWfiVuCWIAAAAASUVO" + "RK5CYII=") +index.append('deleteperspective') +catalog['deleteperspective'] = deleteperspective + +#---------------------------------------------------------------------- +demo = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAuZJ" + "REFUOI2lk0tPYwUARs9te7l9pDCEPmCGkQ6FlostwlCKCk5MGFw4asDEmBg2Jv4B1vMDZONa" + "F5MMW6LRhWhmYWYzwvAsj2mTYkcqhZa+L7X0cft0OwsXk8xZf/lW58AbIrzGRj8+Pj7o8/ne" + "uXdv9r1cTiktLy8/BFr/e9Df339rampq1O/3TU1M3PUNDDi8JpN5QK21xVpNZVR2IsuyNxwO" + "BwF0w8PDg/Pz83Ozs9N+r8czYbX2DjXbuq5kpsJ1IUkicUmpkiRfMpFIpOjr7WFhYeHByspK" + "EEBYW1v748Enn86tP9kjGM4QT6kIooXJt0184Ldhtd1C1GmoVss82z7DeqNJp6m25fe/PwO0" + "NKenL5PxeJKH3z5l9ccoh+EGoqjHK1uotuycXTaIXqhkFJBdb3GZLjEyIk86nU4ZQGswGPuW" + "vvri493DS7JKg2arib27jMncSyzZJpnKUShWySkq2ZxCJltk6I5F+28h98/m5vNNbbVaFZeW" + "vvw6kSoLhyGFZqOGpC1wXdaRzLbpNOupVK5JJBVSqSy/PjlC39Fi7sMx06NHjx9rYrHYyelp" + "9HJs1I5eMnL7tpNqy06v1cBNmw67xcC4dxDZ1YcoXFMsi+wcxHG7R3wul8utAXJ7+8ehYYeV" + "HkeRtlik54aHeK4TS7eRmzYd3eYajUqCZiXCRzMi05P9mExdHYuLi59rAAKBwF63WUQed3I1" + "s0He8RtdRg3FUoXIyzP29wOYjS3enb5L5vwZumaUi4sLJZ1OCwKAx+NZ+PmntV9enGj50/w7" + "Y2YH7roHq02i0yyh0YCiKI1A4Ci6urr6dyQSuV+v15/GYrHPBABJkobW19ePBwfvGCSMIDTI" + "FFKcnPx1vrsbeLGzs/M8FApt5/P5IJCRJOkbvV7/faFQ+E4HoKpqbGNj4+DqShnZ2to+Ojg4" + "2A4Gg1vpdPoYOAcar+ququoP9Xq9QxAEy6stuIEOIAJUXzPGN+c/irhDxtglzjIAAAAASUVO" + "RK5CYII=") +index.append('demo') +catalog['demo'] = demo + +#---------------------------------------------------------------------- +dialog = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAJ5J" + "REFUOI2tk1EOgjAQRN8ULkXizSrRkHoySHus9cMULQJa8f1sMtmdTnZTyTUcQWEI9utwf72o" + "BfC9R7p9PWjmkYRcgwOqhpf9bXasRToDPBJk0pSqKgBhCGZmFsdYVQGTa54GtSZvBn9J8Aow" + "N6/p2WBe4tqCulO3qRdnzKKk4lRpSpt6pkhgZsQxzjUnWNOLBMsXatDR3+g+t+xzB+jeEF9n" + "B4s2AAAAAElFTkSuQmCC") +index.append('dialog') +catalog['dialog'] = dialog + +#---------------------------------------------------------------------- +exit = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAthJ" + "REFUOI2lk91vU3UYxz/nre26ttkGpZvdWJ0LkF3AhWSijMQoaEKMLwn/gqIJAYyaQLwwxmAm" + "S9BLLzSazBhRYBqXErKEYTJggwwYvgADRgPr1rOenb31nLZn53d+XhibSORGv5dP8nzyPM/3" + "+cL/lPJw4SvYpGvKgUQm80p9e/vawPdZyOXswsxstuyLTw/Br48EfA17W7ufPLZx//5o83PP" + "YxUKBHMWSemTPzfM2KkB/8btqfeBYx+CD6D93dwPezftefXzp7/9zmjY9gylhUUmxy5j2zb1" + "5QrpJzrZ0Namera1617BdEbgfG2Cfuhq7t46/uzgYERPprAnJijncshkEgm4AwPUS0k8kESX" + "bL45fVpcnzW7P4Mr6l+LKPu63nk7oidT3Dl5ktz4OPlLl1B8H9XzKObzWFu2cGfqLsK02P5Y" + "WtNV5TCAChBPp15LeUUWhs8QqBqdO3dCfhpWV1GEQE5Pk+npofH1N5j67Tp6UKEhFtsFoANE" + "081rguwJCvdWaP5xCOvE96TXJNEjEdA0WkoO5ie9tB7t42JDE9EHU8RDRqwGCAJJtVRGiYSQ" + "noe4PIoqA6o3bgES6S5TGR1FlF1CmQzVyd8RkSg1wKK9uFB9fP06LV9Ea2zAt2zun8kihn7C" + "XwVn3qFp+w70WAJpmkhFZanqubUbFPNm1lJj6PNzeCMXSB3pxUilqcw6uJZDfdNaOvr6qN78" + "A3fiCm5dmJlK9ZeajUdhc3vXhvGeznV6aXKGllNZRDyKM/AzUggSL7+EEQpxbfduqrnbjKEG" + "V1ecHcfhggYwBObm4rwr400vtCR0lr/4EsOoo27bU4TbWqmcO8vdt96kcj/HLd3g4nLpyHHo" + "/8crfwC6B+92dLR/vDEWUhJzFroICHzBilOmaBjcVFSuldzeEnw0CO6/hukgbDXC4fcaw6EX" + "w4qMCSFYEtI1V73hJT/o+wFGHp3N/6A/AcbQQIv/cYpDAAAAAElFTkSuQmCC") +index.append('exit') +catalog['exit'] = exit + +#---------------------------------------------------------------------- +expansion = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAlhJ" + "REFUOI2VkjtrXVcQhb/9uPdcS4okSyCQwSkCEqRwogRsFzaCgGzsVk4d0qQQpE+RPj8ivZpA" + "qrhKcws3TiOnMNgqLGxDGgkhoat7HnvvmUlxpCiPKl+zGZhZzJq13a0f3v66fL36IicjTQup" + "FlIjpLqQGyG1hdwKqRZynSmdol3BSoO178dxZWVu87P1pXh6CudnMJ3C5AymZ31tHrKAeEgK" + "mujxgD7djMuVy2tzVBMHeQ7OJ9AuQNNC20BTX7wNNFNIHaiBx9j/Pea4tmx8/QkcHR3z4sUe" + "W48eAGAAAXBgBppBiiIqaDGqAXz1vScGYOBh4ARJNdWAK45fQn0MzmErn6OjGUoxNBpVgIE3" + "IloAUDNCiPyd9udvkFe/QYD47TPs5j2kGKqGB4oYUbRvrqqKg4MDdnd36bqOjdv32Vhcpput" + "wAeMQBEwVUQUdaCmRMwAyDmzurrK1tYWZsa1mVnK6xmYWQAfEAKmhogiYhQMFSPahYCZMRwO" + "WVxcvKihfPlTn1YB7RKlqVHtLRQMMyOqGv/GDEpWZOgxIPs+Oi2GmKKqeLsQQPWvQeeuBGzg" + "sV924N1zQgjIwx+RpVtoN0XE8GqYcXUDgMnknMPDQ1LKVAtLfHC0j/3xEh8C1k5Q9Yj0FtQb" + "mBEv5+fn56lGI8bjMV2XWP/0Lrd9pmQBFUQFUVC1fgP6zWPo/xyj0Ygn29v/uEV2O7iPHmM4" + "qusfEqiRIKiHYTRicLg73+2dfHxjMNfVmZIKpU2UnCidIDYiF0dOCW1PQAuXhoN37L85Pf9P" + "Av+XPwHwQHwFXrN+IwAAAABJRU5ErkJggg==") +index.append('expansion') +catalog['expansion'] = expansion + +#---------------------------------------------------------------------- +find = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAtRJ" + "REFUOI1tk8FvFFUcxz/vzcyb2e7utMx2d1tbLCutuCExHDCKJCpRSDAGDkQPhGjiDbjoCf0P" + "9AInOTZKjCHhwkVJwNgQMcRYisJa6oaWggI17K7d7my309mZ56F2s2v4Jr/k977J75Nv3u89" + "wX+amiqllOfdzGcSo3Gsg00/0hCsI6o13y7Pl88cP/rWpzxNF6/dSd9ZqC7Fcay7qx3HutKI" + "9Uy5pmfKFT154dqZ7jnZfYi7eq01WmskoKwNb8izeXv/yx+d//bGWbQWAGY3wDQFa80W09Nl" + "gvUQp89maGgLQ1tHSKccZu8+IgKk6jt+6rOv3c/hWAdQmatS9ltcXlgkU9jGeGGUhCl4XG2w" + "9PcsYxPjZAezzC8+QmMihXwHeK4DuHLlUi4/OuzsOHCQ4hsFMhYowBnL82D2L+7fXSCZyeOm" + "k5gqga0sAcgOIAzWPgzcQn9qrEDtHwgToCSsaVhJDdN+WGNYrZBKpTGVjaksDegOIIqjFyst" + "l8oSWAH4yY1bbaxBzZckwiRjJjiOwlI2liF7t9D0V6t2vILXB/0KPBvSCmwNoi3QgY8UEsdW" + "JBwL0xC9gJV6/Zv6/C9tGS6zYxwmRqC4FZ4vQNZ4QiKqk/SyGKaJIUHI/yV4/b3914vbs9Uf" + "zk3y+89zCL+F8Fs8vP0H965fpemHcP8SYn0ZwwKxufpNwOFDhxlMmizeLvH9xcvcnHJxEg7e" + "QD8j+QxPpr8knatiBFeJdp1GmE4voFKt4Nk5Dhzcy2tvvkKt3kRriTuQYrWxzMyvJ9miMjgT" + "Fo3ZU4TNlzQQ9TzlzViOMngm6zKSS5FUMJgZYOeJ7/jtp2XCuRu4xT5elZPOqEuuk6A/9PTc" + "vT+bt0q34hgZaCCKQeuNEpbLUvYTSuc+Nt7Xsdqz+1lnT9E70gHs25f33/3gxN4LX50doPdf" + "dckOt6WjXLvy4xfrLxzbVVrd2fgXbJkZTtWGQBcAAAAASUVORK5CYII=") +index.append('find') +catalog['find'] = find + +#---------------------------------------------------------------------- +findnext = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAuVJ" + "REFUOI1tk0tsG1UUhr8Ze8bjPDzOuH6QOA/nUccqoBaBRNoKqPqQyiJdIFghENkgyooFahft" + "nlXEAthUiqCLqhIbxAKkFIgMilIgpdC6YCoaKlBFq9iJXY89M57HZdHYiqX+0pGO7uLTf85/" + "j8SOVlZKA6phXE8notkgEE7n3RcwdGFR9z1P/NOfuDp3/v2D7JLcaepKSDIGI4OTw7o2nY3r" + "nZoZjeue4xA9cEAax567eubctccCAIJdvRACIQQy4DWbCM9DHRtj2LOeWXvr7T8QQgII7waE" + "wxJ202J9/TZO20Xri5DJDBG2LALbxjNN1KkpktWfZr88+vKdeZjsAirlKrdNi+WNuyRyE0zn" + "skTDEv9VG2TqdXzbpl2tAqDm80w+eJD7NpO51wVcufJ1Kp19QsufOEnhpRwJBVRAG0/TrtUI" + "HAe/0UBSFCQgsCzavl/uAlzHXnBiOX1gPMfWNrhRUGWwBWg7DnbmZLtY5C8RcRc2N9/pAvzA" + "f7pixajcB8UBs//RVhs25Gs1PNNEUhS2i0WaE7NsHJ5vNb5f9rspNM1WNRI8xOgDXQUjAoMq" + "RAS4rRbCttleXcWeeZLRDy8QDkm9MT6s1y/V7/zsyW6N/DTMjEBhFPbmwBeCytoa5t6nSH/w" + "ESEZJFnuBbz42vG1wlSy+t3FJW79WEYyLSTT4t7NP7F9nw19hOTCMaR2jZACUif6DuDU/Cn2" + "9Ie5e7PEN18sc30lhhbVMOI62uJlNtc/5fDWEiGniL9/ESms9QIq1QpGJMWJk4d44ejzbNWb" + "CCETiw/QatT45dd3GVITaDMKjd/P4DafE4Df85U7tjQ1xHAyxkhqgH4V9iTi7Dv9Fb+t1nDL" + "14gV+jgoL2nZGKmuA901RPnvf5s3SjeCANkRgB+AEI9KUmLcT56ldPG90BsiUOeeHdPmCsYr" + "XcCRI2nz1TdPH/r8s0/i9N7VLkXciUE/5VV++Lg9+/r+Umtf438yITEwJvx/5AAAAABJRU5E" + "rkJggg==") +index.append('findnext') +catalog['findnext'] = findnext + +#---------------------------------------------------------------------- +frame = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAHhJ" + "REFUOI3tkzEKhEAUQ1/+zK1dUWT2ZC56rG8xiIKg+7U1TZokpEgkSzyBylD8rrntO2WApm2Q" + "vpcG96qrLGQJA/4y73V7fV6To5A+ALXBivk3hxiAMhR3d5/GKcSAy9IWEA05BLwN7jfIdRQK" + "D2kb1MM32rXkHAss9IUYpp5t/QAAAABJRU5ErkJggg==") +index.append('frame') +catalog['frame'] = frame + +#---------------------------------------------------------------------- +images = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAylJ" + "REFUOI1lk11oWwUAhb/7k581XfqXNF1tunbVLVVr7ag4ZVrrNsaQbiJaZKBDmRWLoi8b+jSK" + "MPVBQV8UXwT1xfmDLXMZVijinNrJOqzdZtquadIuTdI2aXZzf3Jv7vVBmJqdx4/DgQPnCFQo" + "ej5+PNzkOyYJwk3mAKYlUCgaxGLXxhIz4y+MjIzYAHJlgOz1+TvbGgJCBb9hQCKl0HV35HmP" + "16XCyCsAYmUASz/rzi0QRBFEUaCxzsPeh3e+/Pno5FsA0n9Np57CLWZmBr1uqzf96xfk539j" + "I3kV16ZqqmoD6JaLpVQGQ9fRTXZ3Pzjwb9HRAQarG+uHN3f19y4S8SFWs6PFhZ25Qj4Vpyrc" + "Q/jxEyzlbObnFlE0i3Q2YwoApw9xsnXvwBudh9/morqN937yUJag20zy7D6Vufg0N858jGD7" + "2HH0U5azKiWjxJXY/IY0OsBQ/faOd5xNNd+rid8zq+Wq8JtnAly6DG1alKmmT5iouobZ2kEk" + "Nsvs1RkCXQdwy5BdyxvS0L7gV3Wd93gvfnZ2KPHHdHxX35ZDnSGDbmeS1x7NcTL1JRPajwTT" + "RV7t3c/k6VOE7h/E568nlU4bsi8UaLnrycdkX430tSg40paQyDMtv0BEB1Pg3dUI55d9HLSa" + "cDfEqHVraNk4weatuEQJeenPhfHgufED7fdtDyCUYGURNAVKGhgaexydPQtNlL0PUfgrCsUN" + "cGzcbgFREpDzBf3IxAffHvTfVnO0py+ya1tH3T8mQwW9SNkqsh69TmAxQVZMkt5p097YjAgI" + "goA0Noc6tsBUv9/45vL0cri5Qe6q8QOKArqOYOkoSoHVdI5Mi0Wi9XbufeJ1JFEmnrxu3Fzi" + "8DlyhsLweDR2yczlwNZAKyIUVEI9Zba+WGY+CO19Q3h9XsAGxP8v8YcUxgN3BNs21tXdm0s5" + "3JaGpFnkCw7fTcFaaz+PvPQ+luUgCiLx5Ipxy5nufO4js71e58LZD3HSs7iwWTO91O0/zNNH" + "TiB6PGiqjccl4pIkT+XpiF5IHy/p68dKSgFFUSiXQZJdVNcGKZsGhq5jOw6SKLG8ki38DbMJ" + "XHT2R43dAAAAAElFTkSuQmCC") +index.append('images') +catalog['images'] = images + +#---------------------------------------------------------------------- +inspect = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAp9J" + "REFUOI3Fk+tLk1Ecx79ne+Yed2tuc8vlLTJF1HlJcoqaaEZaJHQjsIJAqBdlQr0JohDqVVGZ" + "78JukHTRl0mYUEpleWFD0OVyCtN5mc+e5Ww3t7WnN3tirD+gL/zg/M7ly+d3fucA/1skcYLj" + "uLIHd9/0OFbspZFIFKyLASUSWy623y4pLyfhxP3C+KS6+lCK/xdZqKkzqNUpYq/danWbJ8xs" + "Tr5h5/vBlzeNlU29ZvOIO/4MFZ8U5le47bYp5+nWZkW6Ji0SmKZnRZodrom3H5ZzG/YUOZnF" + "uURqnoB0XLp3/OvwO+OJA61MyA025IsE7JbVFXbZ48lS5vnMpuFwzeEjGYaiKurb2OAIAC6e" + "gJJK5V0bqy7vjwFmxiZkQ5BEWUoe2fQEWY+YStaVZ9ZzTsdi3ja15jKAWwC2AEAQMxBvBX1p" + "almalxAq/DsS3WCdLtvo5JfPNmba5AttzhFQDLu25iksqJADSOJL4A2ENC3r9wR/0kKBICIg" + "glASJfJxhLBBzrtOU8kbhGDLUFIi02/PHI+/O37APe7p7JZSyl6Xb02ilab75GK10qhv0AHR" + "CEegHF0Y2jVw/VmqsbL+Al9/PEF41bXEtJxqm31lerh33edQyZLkegWdUqQQq4q/r0/uO3Oj" + "pdZinZ8am/xoA/D3PfAtEQJIBZB5paPrqnXaXG8ZH3fQAklArlPI+ode5LgtT+cNKlKQcfT+" + "boeDsfMm8T2VANDFAgcbT5bptFKtP+R39fW9NgEQtjdnn23eX9s266GzOjofLSJBAgBSABkA" + "DAAqAFQBMAIoBZANQHbtWE73nfO13NLMp6ZEAnAcRwghIgB0LIQAogCCAAIxbK61SvNEn5V7" + "Tq9Vdf3zmRKIeEUTFxuLNc89/nDdH/xlAzHUigZXAAAAAElFTkSuQmCC") +index.append('inspect') +catalog['inspect'] = inspect + +#---------------------------------------------------------------------- +layout = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAZ1J" + "REFUOI2lkrFrFEEYxX+zHBE0G9BCRBCVJIqdoI0YK5FUgkXSaor8AynSWQhWtqkEtbHTRiwO" + "q5QprzHgoSSQFBaKJIGA2b2Z73sWu7e3ASMJPphi2J03v/fmg/9UAHi80lsKcJkQZoBbyAUh" + "4CLLAlkAd8eS9sY6bFy/NHEbF8tzNwIAT1Z6r3RCvXj/RQAdAAXuAbxZ22nQ9A/sxbvn6G/v" + "lY0BxoXhx+nzp6ps4e+Hv/4oASiKwdiIQDo9vPXbz/JY5ck9jAjcO0O048rNaRFUrzH/bJXC" + "HRd0nz/g4etZ8jzH3ZtlZnxY6CK3loFXbr8OIvdvXqTb+w5Ano8zNXmFOiaS83m9X+1TZZBV" + "BlXn+4URJX6XCQAzJ3C4zWRWp04jglATlGXkIBpWxPonRxIgkJCE1TcrDVoRWq+u1gCkZLis" + "ieAS5sN9i8CjiXqsP61tNQb5+Bk2NreJMTKIEUtGFjLq3kaTaO5bwNX1l48O5X07946jJNdu" + "Y4Dp4/zT1WuO7gTXWfcEcuSGPIEMNX24QPsKWf9I95PoDxEAIhVEfbTGAAAAAElFTkSuQmCC") +index.append('layout') +catalog['layout'] = layout + +#---------------------------------------------------------------------- +miscellaneous = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAklJ" + "REFUOI21kklIVXEUxn//+67ac0LNCQcUSpMCUxdRhhLWQl0k4qoBMV0kiGATEVSrCNq1iEAN" + "sxZtkiipwLICtQg0DC2TJIee+nJKvW9S37vvtEglrKCIPjir7/w45/Ad+N/Sq+y7NpX3nf17" + "skKSa14tSYNDpNEpEn6459Yfs1FlNyoPDIkcGRY5ulrloyJRlbaOnzb85dpmoN4eBOEfwPAB" + "AmmRkH8lKe9+024rvPas9Wo/glLCPsfp1BHd5/digJEIOTrszYDEBHjwBbjbm/fTRCkk3Gwo" + "dcrwU5GhJ9J86qSflyJ0iWR2i1i6RFSnCC9E6uWa6NeT69ZYy3JVRIul9tJtFZEQyOwEzNrI" + "Sg1SMy2f6E7OJkZgygC8kHKvk4yCj+TszCh8mzKW7H1otCp3dewj654dxQwMgx4KpsDiPMTF" + "c6gt39N37qrV3j5IVvUJrFoISgO/8jNp2um/3HdGc7lNmFmE2BiwfQanE4qOQVYh6dONb/Tw" + "4tH5mmzs5iSP3z+nbbADp25QEJWPZUHF6Y5lIXrO9f2g9AyQEOjvhrkxPB5BaSvLzAQwyAi5" + "aTk4zRWcC8vU25vB60Ovffb1YuvmsGLN6wUPMDcBIqAUbpepjQ7Zeom0bENpjLvmsLntiPhB" + "QYDPjwJICmLrQFnCUFiAArvBtFdjf4dx550pxwGntS725tJ2VZEYFse4YwqlFJYew+Zrchet" + "RxkK0YOlqVISrHUC8RujDjwYfH5LY64EX4h2E0jRRn891t8Zq8rc+Hz/rG+GvgB5gkbPfgAA" + "AABJRU5ErkJggg==") +index.append('miscellaneous') +catalog['miscellaneous'] = miscellaneous + +#---------------------------------------------------------------------- +modifiedexists = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAAkAAAAOCAYAAAD9lDaoAAAABHNCSVQICAgIfAhkiAAAAWFJ" + "REFUKJFlkEsrhGEYhq/3fT9jxviM6TOnnEJW4gcgKX6AJhuUhYWyIAt7+Q0KS0OWsrWxUVYk" + "hySNxkyGkZzGZ2GQxwKD3PWsnqvuuwulDd9X4pRKsDssxLRMzExK8ae0AWB4dkQC8QjnJseZ" + "m0FtvtC+08rc/ILSALUNNdI82EJ51KaypAK7MQD1huWVZQA0gCjhxJxxzCm3T3dkuODxIk+8" + "Lw6ABeAv85PMJnEbCpg3yOPyvH1FYmlfFSFtNLn3a96zcBvL4+yW464+8h0N4PP7MPcK77VF" + "KB3ASdlE7PBfyAk6GFfxVnjFysLNRo7B/oEiVFQQ6olKsCOMu/dA6DLAwc6h+qG+hI1OjwlN" + "ljhtYfktWGnzWWc6vOKZchhaH8W7VYfV7hN+RQP0dvaQTCVJPWXwpBU1kWompsblz6ZoS0y8" + "iRj3lS72kQdrsUB67fT/Jl9VmVBnxOmK/tv0AbSrcOMtNiLbAAAAAElFTkSuQmCC") +index.append('modifiedexists') +catalog['modifiedexists'] = modifiedexists + +#---------------------------------------------------------------------- +morecontrols = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAp1J" + "REFUOI2F0jFLG2Ecx/HvPXeJUROiPUmgmA4FqUUdpBTEaNFJHaSLxfQVuPQNFNpRhAwuvoAu" + "Qk86OJQSBUVXaUkrImjFOKjxSkIaNNE8591zHWyN6eJvffh/+D/P89Msy/K5Jz+/fkVkMvia" + "hhof58nz57dnBkBHRweFQoH29nYMw2BlZYVMJsPl5SXlcpmA4/D53TvwPCbn5ijMz5NIJEin" + "02iWZfmjo6NUKhVc10UpRa1WQ0qJ67pIKclubjKq6/iuy5py6RkYpK2tjXw+f7NBLBYjFos1" + "rF2pVAAQQlDOHeH/+I7vXtP3LMSLkRF0XSeXy90Ad3N+fk6pVOLL4CAPe3vxpMTzfUgkENfX" + "eJ9KbHx8iVKK82y2ESgWi+TzeZqamojF4/R2dSGkhFqNy1IJ3/N4Gm3H9X1c36cajdYBKSXb" + "29vous7Z2Rkr+/usHR3hui5etcqb/n5wHD58+0YgEkHXNH79/l0H9vb22NraQgjB8fExlYkJ" + "9k5OODw8xK9Webu/D75P9/v3vJqZIRwOs7y8XAdOT0+xLItEIoFt29i2TbFYxHEcOoAH/f1o" + "SuFcXWEYBkKIeg8ATNPk4OCAnZ0dhBAopQAIBoO0GAbbuRxC19GEQNO0RsDzPPr6+piammJx" + "cRGlFIFAgGg0immadD1+zMdwmPGxMV5PTiKlpLm5uQ5omoZhGKTTaWzbZn19HdM0icfjhEIh" + "CqUSA8kkKhxmbWOj4duNf2VRSmEYBrOzswwPD7O7uwtAJBIhmUwyNDRENptlenoagKWlJVKp" + "VLihB62trXR3d9PT04OUEsdxaGlpIRgMcnFxAUC5XGZ1dZVUKhUC5C0QCoX4H7ubf4/2d1hr" + "uMLCwsKZ4zjXnZ2dj7gnd4cB/gA1hCWaJRLM3gAAAABJRU5ErkJggg==") +index.append('morecontrols') +catalog['morecontrols'] = morecontrols + +#---------------------------------------------------------------------- +moredialog = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAaJJ" + "REFUOI3VksFLG1EQxn8vu4poK1KtYFhCscaDpVpKLyu59D9oi+A/UDS5e4uKSDx59yJaj3rw" + "Li20h4Tdg5deSpMSQnJoS1vUGoiaxed4cdeNrujV7zK8mfd9880wBneA8dJ425t+uNX5uiPT" + "rJ/+kd9S9Gsqt5iT2wRKP0uMvn+GFs339RLJ+DAAs/OzygTIzmVRaulGgY5+TXLKQ4tma1tz" + "/DeLUgoAE7iB7PkmwdAc6X9o0ShDo9SC/6nLBBDJXqM/WbV4Zb0gpoR2ATHbENG8WftPgwLV" + "2hDls9ovM0xyCy52ysYtuDzt7Wc8OQgxj1Ma7B3tI6J5PtyDp4WRxCN2vnndZhTZTtnsTpep" + "fj3k5PiEZqzJxGQC4YzVDy59D/qoVCpgsk9uMSc+nLwTGWeWZiRd7pJ0uVNWNlfEyTsCSLDE" + "KAfhGE/Eae8ZAwXFH0Uyk5nLucMOwgACB8sby/LusyUTXyzhMS0OAoGrtoHgXW/U5aP7SaoH" + "NRmwBoJ6ywh2yg6O4+pYUXkfsXBSRHDyThD9HUTlfVxcYmuH+4VzlkEmgUrj7QoAAAAASUVO" + "RK5CYII=") +index.append('moredialog') +catalog['moredialog'] = moredialog + +#---------------------------------------------------------------------- +overview = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAkVJ" + "REFUOI19kUlMU1EUhr/7+mj7Sm1BSgsU4hCDgQ0JjhCTJiQu3NVEo7KRVdW4dOfClSv2sjBd" + "uHGjiUMwURwaIhICCBEhQashDGppqbQQOtE3uKCQloJ/cnPucP7/nP9cQQGhUCin63qePSCE" + "MEWj0Ynu7u5LwHJZgt1uv6iqqrHfymQyRjgcNoLB4BjgKOZKhWjsVbkYqVSKnp6eU319fW8A" + "126B/0KWZVRVJR6PEwgEOnp7e/uBOgBRsOBPJpPPtwnL8TWevJ5kJZHGwKDGodBcb8LrqULT" + "NKqrq/H5fDcikchDubiSYRh8GJllaCrGdX8nRxsUMpsGv1eyPHoxwmkZzne2oigKQghTmYXV" + "tTQvhxY40dbM8JdFUuk80z+iDE7M09l+nLfjMZIbuVJ7xYf+wRmEcpB344vYbRXEXn1nfSPH" + "ylqWgdEl5iNpnr2f4fa1c3sLTP2MM/3HQl7VqHdXcudKGwMTvwg++IyWzyNJJr7Ore7fgcks" + "MxfPIoBwdJVvkQ00IIeMcsAKQIV5y7Wu65TNoKPFg2QxY7ZacToqMVfIWGUJZ5UdxWZFViyc" + "aXHv30HXycO0f/pLQtThtmk4LYKmGoXWJgcpoxK7HuPC2SMlAhKApmmFtjTu+t14s2M01lbx" + "dCRDaFZwrNGDd3OSe34XQmx99zanpANd1/HW13L/Vhcfh0dZWlhHSIJ2jwPfTR82mw3DMHb8" + "lwm4XK6dx6uXG0qES4ZtMu3sRSEe8ng8Ab0oczep6F4AJBKJx8DsP7f3ACwAunutAAAAAElF" + "TkSuQmCC") +index.append('overview') +catalog['overview'] = overview + +#---------------------------------------------------------------------- +process = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAA2pJ" + "REFUOI11k11oWwUYht/zl5NzcpaTk98lNI1JOc2kbbqxYqpTx2y6Ib2Y28hovRFkbFi88CLi" + "TWWgFVRkFnH4AxWcd4PBmBtM98Na0+ykFdKltN3SLMsMC5u1PelfTtrkpF7YyhT9bt/vfS4+" + "vgf4n2lrO/pVd/fgitkc6LNa/d3R6Md3+/uHbgGwP71H/FdZlqNnZTncL4ocaNoAQTDB4dgB" + "j8eBROKnxLlzp48BePwPAMNIrXv3vv6DptVIq9UbCgScEEUBgmACxxnBMBSampzQdQax2Hs3" + "8/lLPQDWqW1Aa2vfNUFobHe7na7jx19GJLIbsuwBz3PQ9Tp4ngVJEiAIwGDgbJnMxNj6+tqD" + "vwGS1PpWIOB3nTx5CDabGYqSQzx+D4qShtttQUODHRRFwmrl0dX1HEtRjS+Mj98aoQDA5+v+" + "Yteu51/t7d1PmUw8rl+fRSIxXk2nlfvx+NnY8nKV3rfvlWZRZMFxNESRxeamYIvHx5boUOjY" + "18Fg1ymvV0Jjox03btxFKjVVHRv77rO1td8uAkhr2mqIYRhYLH/dolgsgaLq6OzsjdHBYOSU" + "wyHA53NBVTVMTWUwOvrNkKYVzgNIS5Iv3Nf35tGdOzkwDIlCQcXs7CMUiypKJVUjS6UHv7As" + "C12vY2mpDFUtQdMKSQCTZnNDx8DAt1d7el7yWSwG1Go6ZmYeYXIyB0WZWFWU4Q/I0dHvTwMk" + "eJ7DxoYOSdpRYVm7LRzu/XRg4MvLBw92mAmiCkFg4fGIWF4uI5OZWcpmL3xULhev0LLcErRY" + "eLAsDY5jcPjwi7Tff2YwEtnvcDqNMJkIGI0mWCwcdH0TLEtgbu7KcKmUuwSgSEWjb3/S0hLy" + "u1wCGIaCKPJke3vQZLcbQNMEKpUqbDYTarU6RkayqNdpzM9XrA8fjg8DWKAmJn7+kedd4ebm" + "0DM0TcDlEsFxJGiaxNzc70gmc0ilClhc3MCTJ6tIpXKYnk5rCwtT5wGo26/s2LPnjYuyvLvz" + "xIlD9Y4OmZ6eLuD27fu4cyeHTOaeJor0Y1VdJMvlCpHPXx3StD8uA8g/JRPbZDQ6XvN63cZY" + "7PNBSTIjkZhFMvnrWjZ74cP5+dw1ALUtf8pbMq38W0QDAN7pbHvnyJEzKwcOvL/I8653ATwL" + "QNrKDQDo7cKfzfc7KseZc4UAAAAASUVORK5CYII=") +index.append('process') +catalog['process'] = process + +#---------------------------------------------------------------------- +pyshell = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAg5J" + "REFUOI2tkk1I03EYxz+//1+2Of9L52r24uYaBSXdutShlDp0CYzohbpY0cFDL3gWi7oUQmAl" + "QUJ18mAzmNjBoiDQELwoxWa25Qs5TciJNcZ0//+eLmrOF4roOT2/5/s83+/z8oP/aZebmsQX" + "CuUex2Lib2sToP1PNdoKv86f+inHu7qU0dvLpoYGOsPhM39PENxZd/LiJbW5upr32QUGIxHu" + "fpsS2/UrAtg2IlAAmsuVLOnvdxfriozA95kktnQaezqFVrmP2arDWIlJtWEHnndv3Ps/DzOj" + "6xgTCey6RuZGI5mWR1imhZjmerWS99oDosE0EDXankhZX49UfB0Xd/dLAQIrcx1HDonn/p3f" + "BHtLS+VBMLgc8L7tloovMfF8GBTN7xvIU3I6Q+6nrWv2IsDYoj9WNhQVfzwmRvM9AcqXF1bs" + "el0+OWGpkpLn680EgLu1RQIjcfEORQVNhVdiWzpfiLP+at7sWn45z4qqjqJrimxfD+TkRB4a" + "8OGqrQW4sFZaqdtbPw7kdo2PyI54XIDI6hTd650Oxj+J4+xpWRIvWMSMwvprjXangUIx392B" + "7eCBSmUU5Z/KNJmfGMV96yZT7aHdwHDBMriQYd6yyClFYc05CmvOw6r7iwhZy2TuYTNAAhZ/" + "4lIXuIwOtm87BlDsK2cuOYNud2DN/gCxIGvCyOgr4BSQWruHf7BfnoPGjBi/kJoAAAAASUVO" + "RK5CYII=") +index.append('pyshell') +catalog['pyshell'] = pyshell + +#---------------------------------------------------------------------- +recent = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAUBJ" + "REFUOI3t0j1rUwEUxvHfTW9rIHfRpd1cVBxc1MHsOhecHRXLLUVwMZ/AIXERQe4iCDppB8Gt" + "Szct6AeILYKm+BKHXN9SE4K9xyFa7ezaBw6c4TmH/3nhQEl03ESOAhPkwkPkEh/wFW8lCpVj" + "oKaukqspREcZozLi0YWIjn4M+9N8MowotyI+vox4tRpxO4tYuzqNtm4MuhF3FyIV6tI6i4+5" + "cyQzl7FwlsmQeyc+mcvmLfU4vcLR81Pu8ZeTZjN2+u9SVKJic5Vmq7E3XP0wV7bmjQa8fsqZ" + "FX6OmTnEuRaDLnTTvYK1pR3Xyr8Nxp+nBLyRzDRd/8H2OpPvHL/I/VNQ1Pat9EWb2cZ+gksb" + "TdXuSOzyrcf7Z9RSyk3JDU+SaLv1zxUaErlQSFxGDwPh+W/PA1R/PEnL8v8/woH8Ah0VioYI" + "i9+mAAAAAElFTkSuQmCC") +index.append('recent') +catalog['recent'] = recent + +#---------------------------------------------------------------------- +saveperspective = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAA1FJ" + "REFUOI1tk21MU3cUxp97WwqVS1tx0mLvaKtrYUB94SbjRaUms8bICg1RXGVQZgwuTRYTY9Rt" + "H5bgB8eWJbo4k82Ixrg4om4TMjuXofgWgcGQzW3oWlrWW0opb6Ug9NLy3xdrkHk+nl+eJ+fk" + "PEeEl5TD4WBMJlMbgLU+n68NwEKC2e12hdls/qSubt9Ft3sgm36ZQSAQ2rR9e1lJcckWB4DV" + "i5lKpTx+5MhHB+Ry9YpgMPh/g6qqqqK3bdWX4gugKcGXtEbDHkywmpoaQ17e+uq7937FiRPH" + "Z8bGRhpEi8W1tbWlFdZdTrksXT4R6MZ7jkrKmM9yvb0Daes3cEM7dpTf6enpU3xw9OD1wUHX" + "YQA/UQmxzWYzWa27WhgmXRYOdqC8YhNSGRVApnDt++sLvf3iWd4fSDl/7tTX8XjckdCJno1m" + "sliqWhhGIRvx/oK3LEVIU4gQnxnH/a4xiKUsRcWmJU1nTj6amHpqWTy1qL6+vtJSvvu7ZakM" + "M+q9jWx9OhixBJ2nnXAPzSGarkNf9yNsLlyBsq25K/sfPsnkQ1M/PjfQ6XT2ybCweWHqW7p6" + "pwrK18zw97pBBiKYfPgPXP7HqHhnI4RoEvKNORSXv5LrevAHG5x42ppYoaO15XIr7x9VFL4R" + "zaH4MDXaHYOWVUJwOvFvextyayth0EowO0PjVcPrFKeXFXj/fqLxBKeviUKhkADAPzI6dznW" + "Gd1XrN8o176yCp6ms3DNj0NdtxdqHcFyaQCDvgguOYPgCrTYWqzZ0PXgd70YAD4GxDINe8P6" + "4TE2Iy0V/BefgZ/mEW04A7YgC6zkL0TCEbCaLKz2/gZCa0CEOczH45zIDqRk6rTt7371ZalS" + "SlMTpz/HnZ4+nJelRLVqCb2NW0VNDvO42A7I4UXptjy4e/ph29/o+ZOP1KBBldE0dPUbEnNe" + "IeNlheSGSkpykpN9AN7UyunDraf2zgvDLeRm8yESfnyWdP3QSAwZjAdALgCgc49VID83k1hl" + "CbmlTCbrkpICAAoTZ1JK8f6VT/cIZLaddFw9RrIzlrkAGJ4H4eSazGG/2UiaVVJiENEuANzS" + "/1Az2N9YXzRnzFJ4AOhfgDlAkRG4KaeoCwDUS8WLImsGsHZp/z+rvEoNBUEjtAAAAABJRU5E" + "rkJggg==") +index.append('saveperspective') +catalog['saveperspective'] = saveperspective + +#---------------------------------------------------------------------- +customcontrol = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAnFJ" + "REFUOI2lkz2LlGcUhq/zPO/M7M7OTtaJu7K76kaIaKHiF341miqkCcTKdCkCAZv8AklnYyCE" + "/IJU2vgDRLTSWIghqPiBijDqiBtdM7uTmffrnGPxjiJCIODdHLjhuTj34X7gIyWLe86cOXTg" + "wPfmpZQlqApqoArFeGpB5VnlmQbSXL17+9fTyfbP1n118sSWmcEwZ5RBmsl4QlZAmsIogyyH" + "USqMCiiKwMqa8fzx/NGkNVPLFucbqNUxAzNAhAjkpeMmpKWjFjBz1AT3QK4JT+4mZVKrRRbm" + "W0y3m+9yvfin4Gq3YP9Sg2Hh7J1LAAc33B2AvIi0p4QEYOwBcOVRyo2e8kqFS/eWqU9McHip" + "ya5ZYetcIC8M9yqelmUFeF+X7/RZbrSor7zi5f0uT/ol1xY3s2/bBn45FnEBNa+iooT3H68M" + "lG7WYOOnkxw/OMfZU0f47eReFhrOlZ7y8/USLRXcMTVcPwAEgcs3e1x78JpRrUEQZ9/nTX78" + "chPr17V43De0NMwqgOEVQEQA+KQZ+f3bjXRqgYcDuPg00H3tTE0Fts0KVktYHni1gTuokkSE" + "GGPVKoFOu8a9Xp9HL4fs3zLN6tY2a5nTDhl/PHhO3LkeVRsfXqsjhlglcXeWOnW+2zkBqjzL" + "RjRtggt/LTMzM81PX3ToNCEtDDOpADGJ0qi/3UBoTQZ+ODYLppz7c0BIc77ePk1/VLJn0yRm" + "RhKdEAJEkaS/msvKmhAjaFk10VQxdw7NN8GURALukf5aiZkhAsNRxr+rwyixteObhc27jwdx" + "MX3bKEOBCKjmgI47XoIXgFIUBX/3bp3////2P/QGWsxIJsvdP+sAAAAASUVORK5CYII=") +index.append('customcontrol') +catalog['customcontrol'] = customcontrol + +agw = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAvdJ" + "REFUOI2NkX1I3HUcx1/f7+/B85yXpXa38o+ltIdzGRUUs4fpClaYi5iFERpkG6yQtkEEBZ0Q" + "QkW1GotVFEEQGcFkOIK2Nq1mszqJdeKdDzsU9fS86dx5nre78/vtj3ViBtH73/f7/eLzIFij" + "A8fHm6evmU/3+q1sbLT0efrEfM7Tvg9dZJOHVSi8V0Yj21VscViGB942c4Gd+/0lgaWyur4e" + "STaGyUSoFJgH0K2tLianT2UvnLzXTA21YSmHjBtNlKrXVwEu75bG7m4KsuMqSKHchr3VDQwB" + "MBY/TODMgyI/9III8/n1xkobgAlQu/9sRWRpw67E4MKCXZ7/c8bK26Znlm8DfgLgz9BelsOY" + "Y9fL+tlDZ5idg4s9WQlQoS74HCfuqK3fWPnE196HjhTSX4DJxtXjRMObIQPAZ08aV6b8R2s5" + "3/EI9sRF+VrdlmOVMV+Tac5aBim+DfrLqyvvq9lZ1PRUrj/uupwgo1m+wQq2zOyuK66v/oW8" + "QqY8Wos9XjMbtJpHRiI1x4g1f/TSA489PrjQ3ZlXmjLf32V8PBUke3VCt9RHVVwlpVvaHmUb" + "xo/xhsjdfyyoIU4fkHrA57XXvvNsMxWzHTK92G/o/n2G+v4Zu551Gus0TwfeknNyeobMrZ7R" + "PWvNh7/k0uQPso0eKLuTFYeRHlgPsG1uTsdJmoNR0eH5XX0x90FBqPjg0oDwceqmiLNoLnWt" + "6tdunbIPKsdXl8Vwxz6jutGTdTgkrxZNO1eMRLpqZEgcFQCv7BDfbS4Ruzfkyyvtvcql08ps" + "rJI9b+xQgXK/9eimmsztx++RHOnTVwOzwmotEc4bJ3Wg9xZ1l8iN1LIdtzBkwzdl1nMJrzWv" + "nca7aP0yAmHFlX1oMpk8Nybud1kkG4p1+4td6lMAsX43fK53AC/oMRBlwCiwFU0UgRulP+HN" + "xa5cXP4LsCqxCfT5vwEgcKP1IknnubWp/wAAWdH5T6Y4yXvRpf8L+I32+CUQwwBoVkjkd60P" + "/QWR0DSJqhvOegAAAABJRU5ErkJggg==") +index.append('agw') +catalog['agw'] = agw + + diff --git a/demo/agw/run.py b/demo/agw/run.py new file mode 100644 index 00000000..94f66a3b --- /dev/null +++ b/demo/agw/run.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python +#---------------------------------------------------------------------------- +# Name: run.py +# Purpose: Simple framework for running individual demos +# +# Author: Robin Dunn +# +# Created: 6-March-2000 +# RCS-ID: $Id: run.py 52991 2008-04-03 06:52:35Z RD $ +# Copyright: (c) 2000 by Total Control Software +# Licence: wxWindows license +#---------------------------------------------------------------------------- + +""" +This program will load and run one of the individual demos in this +directory within its own frame window. Just specify the module name +on the command line. +""" + +import wx +import wx.lib.inspection +import wx.lib.mixins.inspection +import sys, os + +# stuff for debugging +print "wx.version:", wx.version() +print "pid:", os.getpid() +##raw_input("Press Enter...") + +assertMode = wx.PYAPP_ASSERT_DIALOG +##assertMode = wx.PYAPP_ASSERT_EXCEPTION + + +#---------------------------------------------------------------------------- + +class Log: + def WriteText(self, text): + if text[-1:] == '\n': + text = text[:-1] + wx.LogMessage(text) + write = WriteText + + +class RunDemoApp(wx.App, wx.lib.mixins.inspection.InspectionMixin): + def __init__(self, name, module, useShell): + self.name = name + self.demoModule = module + self.useShell = useShell + wx.App.__init__(self, redirect=False) + + + def OnInit(self): + wx.Log_SetActiveTarget(wx.LogStderr()) + + self.SetAssertMode(assertMode) + self.InitInspection() # for the InspectionMixin base class + + frame = wx.Frame(None, -1, "RunDemo: " + self.name, pos=(50,50), size=(200,100), + style=wx.DEFAULT_FRAME_STYLE, name="run a sample") + frame.CreateStatusBar() + + menuBar = wx.MenuBar() + menu = wx.Menu() + item = menu.Append(-1, "&Widget Inspector\tF6", "Show the wxPython Widget Inspection Tool") + self.Bind(wx.EVT_MENU, self.OnWidgetInspector, item) + item = menu.Append(-1, "E&xit\tCtrl-Q", "Exit demo") + self.Bind(wx.EVT_MENU, self.OnExitApp, item) + menuBar.Append(menu, "&File") + + ns = {} + ns['wx'] = wx + ns['app'] = self + ns['module'] = self.demoModule + ns['frame'] = frame + + frame.SetMenuBar(menuBar) + frame.Show(True) + frame.Bind(wx.EVT_CLOSE, self.OnCloseFrame) + + win = self.demoModule.runTest(frame, frame, Log()) + + # a window will be returned if the demo does not create + # its own top-level window + if win: + # so set the frame to a good size for showing stuff + frame.SetSize((640, 480)) + win.SetFocus() + self.window = win + ns['win'] = win + frect = frame.GetRect() + + else: + # It was probably a dialog or something that is already + # gone, so we're done. + frame.Destroy() + return True + + self.SetTopWindow(frame) + self.frame = frame + #wx.Log_SetActiveTarget(wx.LogStderr()) + #wx.Log_SetTraceMask(wx.TraceMessages) + + if self.useShell: + # Make a PyShell window, and position it below our test window + from wx import py + shell = py.shell.ShellFrame(None, locals=ns) + frect.OffsetXY(0, frect.height) + frect.height = 400 + shell.SetRect(frect) + shell.Show() + + # Hook the close event of the test window so that we close + # the shell at the same time + def CloseShell(evt): + if shell: + shell.Close() + evt.Skip() + frame.Bind(wx.EVT_CLOSE, CloseShell) + + return True + + + def OnExitApp(self, evt): + self.frame.Close(True) + + + def OnCloseFrame(self, evt): + if hasattr(self, "window") and hasattr(self.window, "ShutdownDemo"): + self.window.ShutdownDemo() + evt.Skip() + + def OnWidgetInspector(self, evt): + wx.lib.inspection.InspectionTool().Show() + + +#---------------------------------------------------------------------------- + + +def main(argv): + useShell = False + for x in range(len(sys.argv)): + if sys.argv[x] in ['--shell', '-shell', '-s']: + useShell = True + del sys.argv[x] + break + + if len(argv) < 2: + print "Please specify a demo module name on the command-line" + raise SystemExit + + name, ext = os.path.splitext(argv[1]) + module = __import__(name) + + + app = RunDemoApp(name, module, useShell) + app.MainLoop() + + + +if __name__ == "__main__": + main(sys.argv) + + diff --git a/demo/bitmaps/AG00028_.gif b/demo/bitmaps/AG00028_.gif new file mode 100644 index 00000000..cf48cb72 Binary files /dev/null and b/demo/bitmaps/AG00028_.gif differ diff --git a/demo/bitmaps/AG00039_.gif b/demo/bitmaps/AG00039_.gif new file mode 100644 index 00000000..ecb3cc99 Binary files /dev/null and b/demo/bitmaps/AG00039_.gif differ diff --git a/demo/bitmaps/AG00178_.gif b/demo/bitmaps/AG00178_.gif new file mode 100644 index 00000000..64ebd3b7 Binary files /dev/null and b/demo/bitmaps/AG00178_.gif differ diff --git a/demo/bitmaps/AG00183_.gif b/demo/bitmaps/AG00183_.gif new file mode 100644 index 00000000..4c4ee304 Binary files /dev/null and b/demo/bitmaps/AG00183_.gif differ diff --git a/demo/bitmaps/AG00185_.gif b/demo/bitmaps/AG00185_.gif new file mode 100644 index 00000000..e4f0ae0e Binary files /dev/null and b/demo/bitmaps/AG00185_.gif differ diff --git a/demo/bitmaps/BD13656_.gif b/demo/bitmaps/BD13656_.gif new file mode 100644 index 00000000..3cf8d04a Binary files /dev/null and b/demo/bitmaps/BD13656_.gif differ diff --git a/demo/bitmaps/advancedsplash.png b/demo/bitmaps/advancedsplash.png new file mode 100644 index 00000000..0b2abe5e Binary files /dev/null and b/demo/bitmaps/advancedsplash.png differ diff --git a/demo/bitmaps/aquabutton.png b/demo/bitmaps/aquabutton.png new file mode 100644 index 00000000..9dc9f99d Binary files /dev/null and b/demo/bitmaps/aquabutton.png differ diff --git a/demo/bitmaps/aquachecked.ico b/demo/bitmaps/aquachecked.ico new file mode 100644 index 00000000..fd50f45b Binary files /dev/null and b/demo/bitmaps/aquachecked.ico differ diff --git a/demo/bitmaps/aquaflagged.ico b/demo/bitmaps/aquaflagged.ico new file mode 100644 index 00000000..b3b4816f Binary files /dev/null and b/demo/bitmaps/aquaflagged.ico differ diff --git a/demo/bitmaps/aquanotchecked.ico b/demo/bitmaps/aquanotchecked.ico new file mode 100644 index 00000000..28610339 Binary files /dev/null and b/demo/bitmaps/aquanotchecked.ico differ diff --git a/demo/bitmaps/aquanotflagged.ico b/demo/bitmaps/aquanotflagged.ico new file mode 100644 index 00000000..030dc1c7 Binary files /dev/null and b/demo/bitmaps/aquanotflagged.ico differ diff --git a/demo/bitmaps/canada.gif b/demo/bitmaps/canada.gif new file mode 100644 index 00000000..2afbb21f Binary files /dev/null and b/demo/bitmaps/canada.gif differ diff --git a/demo/bitmaps/checked.ico b/demo/bitmaps/checked.ico new file mode 100644 index 00000000..e63306ff Binary files /dev/null and b/demo/bitmaps/checked.ico differ diff --git a/demo/bitmaps/columns.png b/demo/bitmaps/columns.png new file mode 100644 index 00000000..33426b40 Binary files /dev/null and b/demo/bitmaps/columns.png differ diff --git a/demo/bitmaps/contexthelp-16.png b/demo/bitmaps/contexthelp-16.png new file mode 100644 index 00000000..aa69cc4c Binary files /dev/null and b/demo/bitmaps/contexthelp-16.png differ diff --git a/demo/bitmaps/contexthelp.png b/demo/bitmaps/contexthelp.png new file mode 100644 index 00000000..53b84f93 Binary files /dev/null and b/demo/bitmaps/contexthelp.png differ diff --git a/demo/bitmaps/copy.png b/demo/bitmaps/copy.png new file mode 100644 index 00000000..cfa9cb43 Binary files /dev/null and b/demo/bitmaps/copy.png differ diff --git a/demo/bitmaps/cut.png b/demo/bitmaps/cut.png new file mode 100644 index 00000000..79d2dcae Binary files /dev/null and b/demo/bitmaps/cut.png differ diff --git a/demo/bitmaps/editcopy.png b/demo/bitmaps/editcopy.png new file mode 100644 index 00000000..8df8201e Binary files /dev/null and b/demo/bitmaps/editcopy.png differ diff --git a/demo/bitmaps/editcut.png b/demo/bitmaps/editcut.png new file mode 100644 index 00000000..514bd97c Binary files /dev/null and b/demo/bitmaps/editcut.png differ diff --git a/demo/bitmaps/editpaste.png b/demo/bitmaps/editpaste.png new file mode 100644 index 00000000..8906e80f Binary files /dev/null and b/demo/bitmaps/editpaste.png differ diff --git a/demo/bitmaps/exit-16.png b/demo/bitmaps/exit-16.png new file mode 100644 index 00000000..fb510fbe Binary files /dev/null and b/demo/bitmaps/exit-16.png differ diff --git a/demo/bitmaps/exit.ico b/demo/bitmaps/exit.ico new file mode 100644 index 00000000..81b3d5d4 Binary files /dev/null and b/demo/bitmaps/exit.ico differ diff --git a/demo/bitmaps/ffwd.png b/demo/bitmaps/ffwd.png new file mode 100644 index 00000000..87421d52 Binary files /dev/null and b/demo/bitmaps/ffwd.png differ diff --git a/demo/bitmaps/ffwddisabled.png b/demo/bitmaps/ffwddisabled.png new file mode 100644 index 00000000..105b883d Binary files /dev/null and b/demo/bitmaps/ffwddisabled.png differ diff --git a/demo/bitmaps/field-16.png b/demo/bitmaps/field-16.png new file mode 100644 index 00000000..4a0ac4d4 Binary files /dev/null and b/demo/bitmaps/field-16.png differ diff --git a/demo/bitmaps/filenew.png b/demo/bitmaps/filenew.png new file mode 100644 index 00000000..4828b633 Binary files /dev/null and b/demo/bitmaps/filenew.png differ diff --git a/demo/bitmaps/fileopen.png b/demo/bitmaps/fileopen.png new file mode 100644 index 00000000..e3528f02 Binary files /dev/null and b/demo/bitmaps/fileopen.png differ diff --git a/demo/bitmaps/filesave.png b/demo/bitmaps/filesave.png new file mode 100644 index 00000000..82db5055 Binary files /dev/null and b/demo/bitmaps/filesave.png differ diff --git a/demo/bitmaps/flagged.ico b/demo/bitmaps/flagged.ico new file mode 100644 index 00000000..5edb063a Binary files /dev/null and b/demo/bitmaps/flagged.ico differ diff --git a/demo/bitmaps/folder_new.png b/demo/bitmaps/folder_new.png new file mode 100644 index 00000000..cf189f46 Binary files /dev/null and b/demo/bitmaps/folder_new.png differ diff --git a/demo/bitmaps/ghost.png b/demo/bitmaps/ghost.png new file mode 100644 index 00000000..8c8fbaeb Binary files /dev/null and b/demo/bitmaps/ghost.png differ diff --git a/demo/bitmaps/gradientbutton.png b/demo/bitmaps/gradientbutton.png new file mode 100644 index 00000000..8838345a Binary files /dev/null and b/demo/bitmaps/gradientbutton.png differ diff --git a/demo/bitmaps/help-16.png b/demo/bitmaps/help-16.png new file mode 100644 index 00000000..9f0c92f2 Binary files /dev/null and b/demo/bitmaps/help-16.png differ diff --git a/demo/bitmaps/help.ico b/demo/bitmaps/help.ico new file mode 100644 index 00000000..e8d18c4e Binary files /dev/null and b/demo/bitmaps/help.ico differ diff --git a/demo/bitmaps/image.bmp b/demo/bitmaps/image.bmp new file mode 100644 index 00000000..bbab4cd3 Binary files /dev/null and b/demo/bitmaps/image.bmp differ diff --git a/demo/bitmaps/image.gif b/demo/bitmaps/image.gif new file mode 100644 index 00000000..34b3e035 Binary files /dev/null and b/demo/bitmaps/image.gif differ diff --git a/demo/bitmaps/image.jpg b/demo/bitmaps/image.jpg new file mode 100644 index 00000000..8ec8f487 Binary files /dev/null and b/demo/bitmaps/image.jpg differ diff --git a/demo/bitmaps/image.png b/demo/bitmaps/image.png new file mode 100644 index 00000000..5a4ce74b Binary files /dev/null and b/demo/bitmaps/image.png differ diff --git a/demo/bitmaps/italy.gif b/demo/bitmaps/italy.gif new file mode 100644 index 00000000..f1102b5b Binary files /dev/null and b/demo/bitmaps/italy.gif differ diff --git a/demo/bitmaps/lbadd.png b/demo/bitmaps/lbadd.png new file mode 100644 index 00000000..18f0a81c Binary files /dev/null and b/demo/bitmaps/lbadd.png differ diff --git a/demo/bitmaps/lbcharge.png b/demo/bitmaps/lbcharge.png new file mode 100644 index 00000000..70e4126b Binary files /dev/null and b/demo/bitmaps/lbcharge.png differ diff --git a/demo/bitmaps/lbdecrypted.png b/demo/bitmaps/lbdecrypted.png new file mode 100644 index 00000000..2b49969a Binary files /dev/null and b/demo/bitmaps/lbdecrypted.png differ diff --git a/demo/bitmaps/lbnews.png b/demo/bitmaps/lbnews.png new file mode 100644 index 00000000..9299bbcc Binary files /dev/null and b/demo/bitmaps/lbnews.png differ diff --git a/demo/bitmaps/lbroll.png b/demo/bitmaps/lbroll.png new file mode 100644 index 00000000..19d88b00 Binary files /dev/null and b/demo/bitmaps/lbroll.png differ diff --git a/demo/bitmaps/minus1.ico b/demo/bitmaps/minus1.ico new file mode 100644 index 00000000..18893b14 Binary files /dev/null and b/demo/bitmaps/minus1.ico differ diff --git a/demo/bitmaps/minus2.ico b/demo/bitmaps/minus2.ico new file mode 100644 index 00000000..60dbadc0 Binary files /dev/null and b/demo/bitmaps/minus2.ico differ diff --git a/demo/bitmaps/minus3.ico b/demo/bitmaps/minus3.ico new file mode 100644 index 00000000..ea65ef84 Binary files /dev/null and b/demo/bitmaps/minus3.ico differ diff --git a/demo/bitmaps/minus4.ico b/demo/bitmaps/minus4.ico new file mode 100644 index 00000000..17f8d434 Binary files /dev/null and b/demo/bitmaps/minus4.ico differ diff --git a/demo/bitmaps/minus5.ico b/demo/bitmaps/minus5.ico new file mode 100644 index 00000000..e748ca58 Binary files /dev/null and b/demo/bitmaps/minus5.ico differ diff --git a/demo/bitmaps/month-16.png b/demo/bitmaps/month-16.png new file mode 100644 index 00000000..01a5f2a0 Binary files /dev/null and b/demo/bitmaps/month-16.png differ diff --git a/demo/bitmaps/new_file.png b/demo/bitmaps/new_file.png new file mode 100644 index 00000000..a71c1a25 Binary files /dev/null and b/demo/bitmaps/new_file.png differ diff --git a/demo/bitmaps/new_folder.png b/demo/bitmaps/new_folder.png new file mode 100644 index 00000000..dfc7a103 Binary files /dev/null and b/demo/bitmaps/new_folder.png differ diff --git a/demo/bitmaps/notchecked.ico b/demo/bitmaps/notchecked.ico new file mode 100644 index 00000000..d69bc99e Binary files /dev/null and b/demo/bitmaps/notchecked.ico differ diff --git a/demo/bitmaps/notflagged.ico b/demo/bitmaps/notflagged.ico new file mode 100644 index 00000000..d0ccc4cd Binary files /dev/null and b/demo/bitmaps/notflagged.ico differ diff --git a/demo/bitmaps/ok-16.png b/demo/bitmaps/ok-16.png new file mode 100644 index 00000000..ac479f25 Binary files /dev/null and b/demo/bitmaps/ok-16.png differ diff --git a/demo/bitmaps/open_folder.png b/demo/bitmaps/open_folder.png new file mode 100644 index 00000000..c0854974 Binary files /dev/null and b/demo/bitmaps/open_folder.png differ diff --git a/demo/bitmaps/paste.png b/demo/bitmaps/paste.png new file mode 100644 index 00000000..a192060b Binary files /dev/null and b/demo/bitmaps/paste.png differ diff --git a/demo/bitmaps/pause.png b/demo/bitmaps/pause.png new file mode 100644 index 00000000..88de2fcb Binary files /dev/null and b/demo/bitmaps/pause.png differ diff --git a/demo/bitmaps/pausedisabled.png b/demo/bitmaps/pausedisabled.png new file mode 100644 index 00000000..6518c553 Binary files /dev/null and b/demo/bitmaps/pausedisabled.png differ diff --git a/demo/bitmaps/play.png b/demo/bitmaps/play.png new file mode 100644 index 00000000..49fb0288 Binary files /dev/null and b/demo/bitmaps/play.png differ diff --git a/demo/bitmaps/playdisabled.png b/demo/bitmaps/playdisabled.png new file mode 100644 index 00000000..901c3c64 Binary files /dev/null and b/demo/bitmaps/playdisabled.png differ diff --git a/demo/bitmaps/plus1.ico b/demo/bitmaps/plus1.ico new file mode 100644 index 00000000..a7435fe8 Binary files /dev/null and b/demo/bitmaps/plus1.ico differ diff --git a/demo/bitmaps/plus2.ico b/demo/bitmaps/plus2.ico new file mode 100644 index 00000000..0cf031a9 Binary files /dev/null and b/demo/bitmaps/plus2.ico differ diff --git a/demo/bitmaps/plus3.ico b/demo/bitmaps/plus3.ico new file mode 100644 index 00000000..4ddbd455 Binary files /dev/null and b/demo/bitmaps/plus3.ico differ diff --git a/demo/bitmaps/plus4.ico b/demo/bitmaps/plus4.ico new file mode 100644 index 00000000..e61dbac6 Binary files /dev/null and b/demo/bitmaps/plus4.ico differ diff --git a/demo/bitmaps/plus5.ico b/demo/bitmaps/plus5.ico new file mode 100644 index 00000000..6acf059e Binary files /dev/null and b/demo/bitmaps/plus5.ico differ diff --git a/demo/bitmaps/record.png b/demo/bitmaps/record.png new file mode 100644 index 00000000..bc95ad3e Binary files /dev/null and b/demo/bitmaps/record.png differ diff --git a/demo/bitmaps/recorddisabled.png b/demo/bitmaps/recorddisabled.png new file mode 100644 index 00000000..2ef8d862 Binary files /dev/null and b/demo/bitmaps/recorddisabled.png differ diff --git a/demo/bitmaps/rewind.png b/demo/bitmaps/rewind.png new file mode 100644 index 00000000..5d082270 Binary files /dev/null and b/demo/bitmaps/rewind.png differ diff --git a/demo/bitmaps/rewinddisabled.png b/demo/bitmaps/rewinddisabled.png new file mode 100644 index 00000000..06b6f579 Binary files /dev/null and b/demo/bitmaps/rewinddisabled.png differ diff --git a/demo/bitmaps/round.png b/demo/bitmaps/round.png new file mode 100644 index 00000000..5995c31e Binary files /dev/null and b/demo/bitmaps/round.png differ diff --git a/demo/bitmaps/save.png b/demo/bitmaps/save.png new file mode 100644 index 00000000..55ca1ec2 Binary files /dev/null and b/demo/bitmaps/save.png differ diff --git a/demo/bitmaps/smfuel.ico b/demo/bitmaps/smfuel.ico new file mode 100644 index 00000000..cfdb96c0 Binary files /dev/null and b/demo/bitmaps/smfuel.ico differ diff --git a/demo/bitmaps/smpi.ico b/demo/bitmaps/smpi.ico new file mode 100644 index 00000000..c04c4f37 Binary files /dev/null and b/demo/bitmaps/smpi.ico differ diff --git a/demo/bitmaps/smtemp.ico b/demo/bitmaps/smtemp.ico new file mode 100644 index 00000000..9de6beb3 Binary files /dev/null and b/demo/bitmaps/smtemp.ico differ diff --git a/demo/bitmaps/splash.png b/demo/bitmaps/splash.png new file mode 100644 index 00000000..c55ed0b6 Binary files /dev/null and b/demo/bitmaps/splash.png differ diff --git a/demo/bitmaps/stop.png b/demo/bitmaps/stop.png new file mode 100644 index 00000000..750a8a72 Binary files /dev/null and b/demo/bitmaps/stop.png differ diff --git a/demo/bitmaps/stopdisabled.png b/demo/bitmaps/stopdisabled.png new file mode 100644 index 00000000..f5c096c6 Binary files /dev/null and b/demo/bitmaps/stopdisabled.png differ diff --git a/demo/bitmaps/sttbutton.png b/demo/bitmaps/sttbutton.png new file mode 100644 index 00000000..d73d0ab8 Binary files /dev/null and b/demo/bitmaps/sttbutton.png differ diff --git a/demo/bitmaps/sttfont.png b/demo/bitmaps/sttfont.png new file mode 100644 index 00000000..f1428836 Binary files /dev/null and b/demo/bitmaps/sttfont.png differ diff --git a/demo/bitmaps/sttheader.png b/demo/bitmaps/sttheader.png new file mode 100644 index 00000000..652f19de Binary files /dev/null and b/demo/bitmaps/sttheader.png differ diff --git a/demo/bitmaps/stthelp.png b/demo/bitmaps/stthelp.png new file mode 100644 index 00000000..28a0f9e5 Binary files /dev/null and b/demo/bitmaps/stthelp.png differ diff --git a/demo/bitmaps/toucan.png b/demo/bitmaps/toucan.png new file mode 100644 index 00000000..8a33e241 Binary files /dev/null and b/demo/bitmaps/toucan.png differ diff --git a/demo/bitmaps/view1.png b/demo/bitmaps/view1.png new file mode 100644 index 00000000..abb2830e Binary files /dev/null and b/demo/bitmaps/view1.png differ diff --git a/demo/bitmaps/view2.png b/demo/bitmaps/view2.png new file mode 100644 index 00000000..7688e8a0 Binary files /dev/null and b/demo/bitmaps/view2.png differ diff --git a/demo/bitmaps/view_choose.png b/demo/bitmaps/view_choose.png new file mode 100644 index 00000000..d12ece21 Binary files /dev/null and b/demo/bitmaps/view_choose.png differ diff --git a/demo/bitmaps/view_detailed.png b/demo/bitmaps/view_detailed.png new file mode 100644 index 00000000..78f40769 Binary files /dev/null and b/demo/bitmaps/view_detailed.png differ diff --git a/demo/bitmaps/view_icon.png b/demo/bitmaps/view_icon.png new file mode 100644 index 00000000..4a6426b0 Binary files /dev/null and b/demo/bitmaps/view_icon.png differ diff --git a/demo/bitmaps/view_multicolumn.png b/demo/bitmaps/view_multicolumn.png new file mode 100644 index 00000000..77e13e69 Binary files /dev/null and b/demo/bitmaps/view_multicolumn.png differ diff --git a/demo/bitmaps/viewmag-16.png b/demo/bitmaps/viewmag-16.png new file mode 100644 index 00000000..4909e4df Binary files /dev/null and b/demo/bitmaps/viewmag-16.png differ diff --git a/demo/bitmaps/viewmag-m-16.png b/demo/bitmaps/viewmag-m-16.png new file mode 100644 index 00000000..1a7c6d7f Binary files /dev/null and b/demo/bitmaps/viewmag-m-16.png differ diff --git a/demo/bitmaps/viewmag-p-16.png b/demo/bitmaps/viewmag-p-16.png new file mode 100644 index 00000000..81c1a93f Binary files /dev/null and b/demo/bitmaps/viewmag-p-16.png differ diff --git a/demo/bitmaps/viewmagfit-16.png b/demo/bitmaps/viewmagfit-16.png new file mode 100644 index 00000000..34b85d4f Binary files /dev/null and b/demo/bitmaps/viewmagfit-16.png differ diff --git a/demo/bmp_source/001.png b/demo/bmp_source/001.png new file mode 100644 index 00000000..01cbaae2 Binary files /dev/null and b/demo/bmp_source/001.png differ diff --git a/demo/bmp_source/002.png b/demo/bmp_source/002.png new file mode 100644 index 00000000..2882268c Binary files /dev/null and b/demo/bmp_source/002.png differ diff --git a/demo/bmp_source/003.png b/demo/bmp_source/003.png new file mode 100644 index 00000000..e118e993 Binary files /dev/null and b/demo/bmp_source/003.png differ diff --git a/demo/bmp_source/004.png b/demo/bmp_source/004.png new file mode 100644 index 00000000..0b78a351 Binary files /dev/null and b/demo/bmp_source/004.png differ diff --git a/demo/bmp_source/005.png b/demo/bmp_source/005.png new file mode 100644 index 00000000..8221ef89 Binary files /dev/null and b/demo/bmp_source/005.png differ diff --git a/demo/bmp_source/006.png b/demo/bmp_source/006.png new file mode 100644 index 00000000..d0053846 Binary files /dev/null and b/demo/bmp_source/006.png differ diff --git a/demo/bmp_source/007.png b/demo/bmp_source/007.png new file mode 100644 index 00000000..6aa13385 Binary files /dev/null and b/demo/bmp_source/007.png differ diff --git a/demo/bmp_source/008.png b/demo/bmp_source/008.png new file mode 100644 index 00000000..f443e9a3 Binary files /dev/null and b/demo/bmp_source/008.png differ diff --git a/demo/bmp_source/009.png b/demo/bmp_source/009.png new file mode 100644 index 00000000..2de31d90 Binary files /dev/null and b/demo/bmp_source/009.png differ diff --git a/demo/bmp_source/010.png b/demo/bmp_source/010.png new file mode 100644 index 00000000..f99a5719 Binary files /dev/null and b/demo/bmp_source/010.png differ diff --git a/demo/bmp_source/011.png b/demo/bmp_source/011.png new file mode 100644 index 00000000..e4ea809f Binary files /dev/null and b/demo/bmp_source/011.png differ diff --git a/demo/bmp_source/012.png b/demo/bmp_source/012.png new file mode 100644 index 00000000..b9b85b65 Binary files /dev/null and b/demo/bmp_source/012.png differ diff --git a/demo/bmp_source/013.png b/demo/bmp_source/013.png new file mode 100644 index 00000000..457e7a0e Binary files /dev/null and b/demo/bmp_source/013.png differ diff --git a/demo/bmp_source/014.png b/demo/bmp_source/014.png new file mode 100644 index 00000000..0cb6d8b3 Binary files /dev/null and b/demo/bmp_source/014.png differ diff --git a/demo/bmp_source/015.png b/demo/bmp_source/015.png new file mode 100644 index 00000000..f5422be0 Binary files /dev/null and b/demo/bmp_source/015.png differ diff --git a/demo/bmp_source/016.png b/demo/bmp_source/016.png new file mode 100644 index 00000000..d0053846 Binary files /dev/null and b/demo/bmp_source/016.png differ diff --git a/demo/bmp_source/017.png b/demo/bmp_source/017.png new file mode 100644 index 00000000..6aa13385 Binary files /dev/null and b/demo/bmp_source/017.png differ diff --git a/demo/bmp_source/018.png b/demo/bmp_source/018.png new file mode 100644 index 00000000..f443e9a3 Binary files /dev/null and b/demo/bmp_source/018.png differ diff --git a/demo/bmp_source/019.png b/demo/bmp_source/019.png new file mode 100644 index 00000000..2de31d90 Binary files /dev/null and b/demo/bmp_source/019.png differ diff --git a/demo/bmp_source/020.png b/demo/bmp_source/020.png new file mode 100644 index 00000000..f99a5719 Binary files /dev/null and b/demo/bmp_source/020.png differ diff --git a/demo/bmp_source/021.png b/demo/bmp_source/021.png new file mode 100644 index 00000000..e4ea809f Binary files /dev/null and b/demo/bmp_source/021.png differ diff --git a/demo/bmp_source/022.png b/demo/bmp_source/022.png new file mode 100644 index 00000000..b9b85b65 Binary files /dev/null and b/demo/bmp_source/022.png differ diff --git a/demo/bmp_source/023.png b/demo/bmp_source/023.png new file mode 100644 index 00000000..457e7a0e Binary files /dev/null and b/demo/bmp_source/023.png differ diff --git a/demo/bmp_source/024.png b/demo/bmp_source/024.png new file mode 100644 index 00000000..0cb6d8b3 Binary files /dev/null and b/demo/bmp_source/024.png differ diff --git a/demo/bmp_source/025.png b/demo/bmp_source/025.png new file mode 100644 index 00000000..f5422be0 Binary files /dev/null and b/demo/bmp_source/025.png differ diff --git a/demo/bmp_source/026.png b/demo/bmp_source/026.png new file mode 100644 index 00000000..4bdce914 Binary files /dev/null and b/demo/bmp_source/026.png differ diff --git a/demo/bmp_source/027.png b/demo/bmp_source/027.png new file mode 100644 index 00000000..eb966316 Binary files /dev/null and b/demo/bmp_source/027.png differ diff --git a/demo/bmp_source/028.png b/demo/bmp_source/028.png new file mode 100644 index 00000000..ba904b2f Binary files /dev/null and b/demo/bmp_source/028.png differ diff --git a/demo/bmp_source/029.png b/demo/bmp_source/029.png new file mode 100644 index 00000000..9c036ed8 Binary files /dev/null and b/demo/bmp_source/029.png differ diff --git a/demo/bmp_source/030.png b/demo/bmp_source/030.png new file mode 100644 index 00000000..8448239d Binary files /dev/null and b/demo/bmp_source/030.png differ diff --git a/demo/bmp_source/DbDec.bmp b/demo/bmp_source/DbDec.bmp new file mode 100644 index 00000000..970266ca Binary files /dev/null and b/demo/bmp_source/DbDec.bmp differ diff --git a/demo/bmp_source/DbInc.bmp b/demo/bmp_source/DbInc.bmp new file mode 100644 index 00000000..5f5dffac Binary files /dev/null and b/demo/bmp_source/DbInc.bmp differ diff --git a/demo/bmp_source/Dec.bmp b/demo/bmp_source/Dec.bmp new file mode 100644 index 00000000..64efbb3d Binary files /dev/null and b/demo/bmp_source/Dec.bmp differ diff --git a/demo/bmp_source/FRM_0.png b/demo/bmp_source/FRM_0.png new file mode 100644 index 00000000..bac21bbb Binary files /dev/null and b/demo/bmp_source/FRM_0.png differ diff --git a/demo/bmp_source/FRM_1.png b/demo/bmp_source/FRM_1.png new file mode 100644 index 00000000..92ca0412 Binary files /dev/null and b/demo/bmp_source/FRM_1.png differ diff --git a/demo/bmp_source/FRM_2.png b/demo/bmp_source/FRM_2.png new file mode 100644 index 00000000..c396ae13 Binary files /dev/null and b/demo/bmp_source/FRM_2.png differ diff --git a/demo/bmp_source/FRM_3.png b/demo/bmp_source/FRM_3.png new file mode 100644 index 00000000..2a45c2fa Binary files /dev/null and b/demo/bmp_source/FRM_3.png differ diff --git a/demo/bmp_source/FRM_4.png b/demo/bmp_source/FRM_4.png new file mode 100644 index 00000000..bb0dde46 Binary files /dev/null and b/demo/bmp_source/FRM_4.png differ diff --git a/demo/bmp_source/FRM_5.png b/demo/bmp_source/FRM_5.png new file mode 100644 index 00000000..2a45c2fa Binary files /dev/null and b/demo/bmp_source/FRM_5.png differ diff --git a/demo/bmp_source/FRM_6.png b/demo/bmp_source/FRM_6.png new file mode 100644 index 00000000..c396ae13 Binary files /dev/null and b/demo/bmp_source/FRM_6.png differ diff --git a/demo/bmp_source/FRM_7.png b/demo/bmp_source/FRM_7.png new file mode 100644 index 00000000..92ca0412 Binary files /dev/null and b/demo/bmp_source/FRM_7.png differ diff --git a/demo/bmp_source/FRM_8.png b/demo/bmp_source/FRM_8.png new file mode 100644 index 00000000..bac21bbb Binary files /dev/null and b/demo/bmp_source/FRM_8.png differ diff --git a/demo/bmp_source/GridBG.gif b/demo/bmp_source/GridBG.gif new file mode 100644 index 00000000..c1adaf0b Binary files /dev/null and b/demo/bmp_source/GridBG.gif differ diff --git a/demo/bmp_source/Inc.bmp b/demo/bmp_source/Inc.bmp new file mode 100644 index 00000000..8dd26498 Binary files /dev/null and b/demo/bmp_source/Inc.bmp differ diff --git a/demo/bmp_source/LB01.png b/demo/bmp_source/LB01.png new file mode 100644 index 00000000..9a917f02 Binary files /dev/null and b/demo/bmp_source/LB01.png differ diff --git a/demo/bmp_source/LB02.png b/demo/bmp_source/LB02.png new file mode 100644 index 00000000..99d0fff9 Binary files /dev/null and b/demo/bmp_source/LB02.png differ diff --git a/demo/bmp_source/LB03.png b/demo/bmp_source/LB03.png new file mode 100644 index 00000000..47947537 Binary files /dev/null and b/demo/bmp_source/LB03.png differ diff --git a/demo/bmp_source/LB04.png b/demo/bmp_source/LB04.png new file mode 100644 index 00000000..cf7e9c39 Binary files /dev/null and b/demo/bmp_source/LB04.png differ diff --git a/demo/bmp_source/LB05.png b/demo/bmp_source/LB05.png new file mode 100644 index 00000000..e96d6f79 Binary files /dev/null and b/demo/bmp_source/LB05.png differ diff --git a/demo/bmp_source/LB06.png b/demo/bmp_source/LB06.png new file mode 100644 index 00000000..a31a78e7 Binary files /dev/null and b/demo/bmp_source/LB06.png differ diff --git a/demo/bmp_source/LB07.png b/demo/bmp_source/LB07.png new file mode 100644 index 00000000..83b4d25a Binary files /dev/null and b/demo/bmp_source/LB07.png differ diff --git a/demo/bmp_source/LB08.png b/demo/bmp_source/LB08.png new file mode 100644 index 00000000..4e7073d1 Binary files /dev/null and b/demo/bmp_source/LB08.png differ diff --git a/demo/bmp_source/LB09.png b/demo/bmp_source/LB09.png new file mode 100644 index 00000000..0fe5d21e Binary files /dev/null and b/demo/bmp_source/LB09.png differ diff --git a/demo/bmp_source/LB10.png b/demo/bmp_source/LB10.png new file mode 100644 index 00000000..2aa1e38f Binary files /dev/null and b/demo/bmp_source/LB10.png differ diff --git a/demo/bmp_source/LB11.png b/demo/bmp_source/LB11.png new file mode 100644 index 00000000..2ee113f5 Binary files /dev/null and b/demo/bmp_source/LB11.png differ diff --git a/demo/bmp_source/LB12.png b/demo/bmp_source/LB12.png new file mode 100644 index 00000000..d6a002ef Binary files /dev/null and b/demo/bmp_source/LB12.png differ diff --git a/demo/bmp_source/Pt.bmp b/demo/bmp_source/Pt.bmp new file mode 100644 index 00000000..6c49461a Binary files /dev/null and b/demo/bmp_source/Pt.bmp differ diff --git a/demo/bmp_source/Vippi.png b/demo/bmp_source/Vippi.png new file mode 100644 index 00000000..032f75c8 Binary files /dev/null and b/demo/bmp_source/Vippi.png differ diff --git a/demo/bmp_source/backgrnd.png b/demo/bmp_source/backgrnd.png new file mode 100644 index 00000000..59349aa8 Binary files /dev/null and b/demo/bmp_source/backgrnd.png differ diff --git a/demo/bmp_source/book.png b/demo/bmp_source/book.png new file mode 100644 index 00000000..7d863f94 Binary files /dev/null and b/demo/bmp_source/book.png differ diff --git a/demo/bmp_source/book_blue.png b/demo/bmp_source/book_blue.png new file mode 100644 index 00000000..f20eb1ff Binary files /dev/null and b/demo/bmp_source/book_blue.png differ diff --git a/demo/bmp_source/book_green.png b/demo/bmp_source/book_green.png new file mode 100644 index 00000000..b1d9e881 Binary files /dev/null and b/demo/bmp_source/book_green.png differ diff --git a/demo/bmp_source/book_red.png b/demo/bmp_source/book_red.png new file mode 100644 index 00000000..1709d15e Binary files /dev/null and b/demo/bmp_source/book_red.png differ diff --git a/demo/bmp_source/bp_btn1.png b/demo/bmp_source/bp_btn1.png new file mode 100644 index 00000000..4148ab88 Binary files /dev/null and b/demo/bmp_source/bp_btn1.png differ diff --git a/demo/bmp_source/bp_btn2.png b/demo/bmp_source/bp_btn2.png new file mode 100644 index 00000000..b6e026a6 Binary files /dev/null and b/demo/bmp_source/bp_btn2.png differ diff --git a/demo/bmp_source/bp_btn3.png b/demo/bmp_source/bp_btn3.png new file mode 100644 index 00000000..ba62593e Binary files /dev/null and b/demo/bmp_source/bp_btn3.png differ diff --git a/demo/bmp_source/bp_btn4.png b/demo/bmp_source/bp_btn4.png new file mode 100644 index 00000000..0109cecd Binary files /dev/null and b/demo/bmp_source/bp_btn4.png differ diff --git a/demo/bmp_source/bulb1.bmp b/demo/bmp_source/bulb1.bmp new file mode 100644 index 00000000..515efa03 Binary files /dev/null and b/demo/bmp_source/bulb1.bmp differ diff --git a/demo/bmp_source/bulb2.bmp b/demo/bmp_source/bulb2.bmp new file mode 100644 index 00000000..79664791 Binary files /dev/null and b/demo/bmp_source/bulb2.bmp differ diff --git a/demo/bmp_source/carrot.png b/demo/bmp_source/carrot.png new file mode 100644 index 00000000..cf36ca31 Binary files /dev/null and b/demo/bmp_source/carrot.png differ diff --git a/demo/bmp_source/clipboard.png b/demo/bmp_source/clipboard.png new file mode 100644 index 00000000..8e8b106d Binary files /dev/null and b/demo/bmp_source/clipboard.png differ diff --git a/demo/bmp_source/code.png b/demo/bmp_source/code.png new file mode 100644 index 00000000..8fcf0f09 Binary files /dev/null and b/demo/bmp_source/code.png differ diff --git a/demo/bmp_source/core.png b/demo/bmp_source/core.png new file mode 100644 index 00000000..1bbc1d39 Binary files /dev/null and b/demo/bmp_source/core.png differ diff --git a/demo/bmp_source/custom.png b/demo/bmp_source/custom.png new file mode 100644 index 00000000..c1974cda Binary files /dev/null and b/demo/bmp_source/custom.png differ diff --git a/demo/bmp_source/customcontrol.png b/demo/bmp_source/customcontrol.png new file mode 100644 index 00000000..ef066abb Binary files /dev/null and b/demo/bmp_source/customcontrol.png differ diff --git a/demo/bmp_source/deletedocs.png b/demo/bmp_source/deletedocs.png new file mode 100644 index 00000000..42a8ae85 Binary files /dev/null and b/demo/bmp_source/deletedocs.png differ diff --git a/demo/bmp_source/deleteperspective.png b/demo/bmp_source/deleteperspective.png new file mode 100644 index 00000000..6d0d29d7 Binary files /dev/null and b/demo/bmp_source/deleteperspective.png differ diff --git a/demo/bmp_source/demo.png b/demo/bmp_source/demo.png new file mode 100644 index 00000000..47c73fc4 Binary files /dev/null and b/demo/bmp_source/demo.png differ diff --git a/demo/bmp_source/dialog.png b/demo/bmp_source/dialog.png new file mode 100644 index 00000000..bf025920 Binary files /dev/null and b/demo/bmp_source/dialog.png differ diff --git a/demo/bmp_source/exit.png b/demo/bmp_source/exit.png new file mode 100644 index 00000000..63232417 Binary files /dev/null and b/demo/bmp_source/exit.png differ diff --git a/demo/bmp_source/expansion.png b/demo/bmp_source/expansion.png new file mode 100644 index 00000000..477387c6 Binary files /dev/null and b/demo/bmp_source/expansion.png differ diff --git a/demo/bmp_source/find.png b/demo/bmp_source/find.png new file mode 100644 index 00000000..caa587d7 Binary files /dev/null and b/demo/bmp_source/find.png differ diff --git a/demo/bmp_source/findnext.png b/demo/bmp_source/findnext.png new file mode 100644 index 00000000..f5a4e1dc Binary files /dev/null and b/demo/bmp_source/findnext.png differ diff --git a/demo/bmp_source/floatcanvas.png b/demo/bmp_source/floatcanvas.png new file mode 100644 index 00000000..01feab65 Binary files /dev/null and b/demo/bmp_source/floatcanvas.png differ diff --git a/demo/bmp_source/frame.png b/demo/bmp_source/frame.png new file mode 100644 index 00000000..4f9be452 Binary files /dev/null and b/demo/bmp_source/frame.png differ diff --git a/demo/bmp_source/images.png b/demo/bmp_source/images.png new file mode 100644 index 00000000..cc4a4b92 Binary files /dev/null and b/demo/bmp_source/images.png differ diff --git a/demo/bmp_source/inspect.png b/demo/bmp_source/inspect.png new file mode 100644 index 00000000..1dd74bea Binary files /dev/null and b/demo/bmp_source/inspect.png differ diff --git a/demo/bmp_source/layout.png b/demo/bmp_source/layout.png new file mode 100644 index 00000000..b4aaad9a Binary files /dev/null and b/demo/bmp_source/layout.png differ diff --git a/demo/bmp_source/logo.png b/demo/bmp_source/logo.png new file mode 100644 index 00000000..5020c0a8 Binary files /dev/null and b/demo/bmp_source/logo.png differ diff --git a/demo/bmp_source/miscellaneous.png b/demo/bmp_source/miscellaneous.png new file mode 100644 index 00000000..f06e510d Binary files /dev/null and b/demo/bmp_source/miscellaneous.png differ diff --git a/demo/bmp_source/modifiedexists.png b/demo/bmp_source/modifiedexists.png new file mode 100644 index 00000000..99bec7a1 Binary files /dev/null and b/demo/bmp_source/modifiedexists.png differ diff --git a/demo/bmp_source/mondrian.ico b/demo/bmp_source/mondrian.ico new file mode 100644 index 00000000..2310c5d2 Binary files /dev/null and b/demo/bmp_source/mondrian.ico differ diff --git a/demo/bmp_source/morecontrols.png b/demo/bmp_source/morecontrols.png new file mode 100644 index 00000000..31d03a58 Binary files /dev/null and b/demo/bmp_source/morecontrols.png differ diff --git a/demo/bmp_source/moredialog.png b/demo/bmp_source/moredialog.png new file mode 100644 index 00000000..6e61e0e0 Binary files /dev/null and b/demo/bmp_source/moredialog.png differ diff --git a/demo/bmp_source/noicon.png b/demo/bmp_source/noicon.png new file mode 100644 index 00000000..0cbe8373 Binary files /dev/null and b/demo/bmp_source/noicon.png differ diff --git a/demo/bmp_source/overview.png b/demo/bmp_source/overview.png new file mode 100644 index 00000000..12ec79e4 Binary files /dev/null and b/demo/bmp_source/overview.png differ diff --git a/demo/bmp_source/pencil.png b/demo/bmp_source/pencil.png new file mode 100644 index 00000000..ab345baf Binary files /dev/null and b/demo/bmp_source/pencil.png differ diff --git a/demo/bmp_source/pointy.png b/demo/bmp_source/pointy.png new file mode 100644 index 00000000..32895dcb Binary files /dev/null and b/demo/bmp_source/pointy.png differ diff --git a/demo/bmp_source/process.png b/demo/bmp_source/process.png new file mode 100644 index 00000000..2206448e Binary files /dev/null and b/demo/bmp_source/process.png differ diff --git a/demo/bmp_source/pyshell.png b/demo/bmp_source/pyshell.png new file mode 100644 index 00000000..4eaa79a1 Binary files /dev/null and b/demo/bmp_source/pyshell.png differ diff --git a/demo/bmp_source/recent.png b/demo/bmp_source/recent.png new file mode 100644 index 00000000..6a9bf037 Binary files /dev/null and b/demo/bmp_source/recent.png differ diff --git a/demo/bmp_source/rest.png b/demo/bmp_source/rest.png new file mode 100644 index 00000000..9c394e56 Binary files /dev/null and b/demo/bmp_source/rest.png differ diff --git a/demo/bmp_source/robin.jpg b/demo/bmp_source/robin.jpg new file mode 100644 index 00000000..f559cad0 Binary files /dev/null and b/demo/bmp_source/robin.jpg differ diff --git a/demo/bmp_source/rt_alignleft.xpm b/demo/bmp_source/rt_alignleft.xpm new file mode 100644 index 00000000..78653a5d --- /dev/null +++ b/demo/bmp_source/rt_alignleft.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char *alignleft_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +". c #4D4D4D", +" c None", +/* pixels */ +" ", +" ", +" .............. ", +" ", +" .......... ", +" ", +" .............. ", +" ", +" .......... ", +" ", +" .............. ", +" ", +" .......... ", +" ", +" ", +" " +}; diff --git a/demo/bmp_source/rt_alignright.xpm b/demo/bmp_source/rt_alignright.xpm new file mode 100644 index 00000000..c5008e1d --- /dev/null +++ b/demo/bmp_source/rt_alignright.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char *alignright_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +". c #4D4D4D", +" c None", +/* pixels */ +" ", +" ", +" .............. ", +" ", +" .......... ", +" ", +" .............. ", +" ", +" .......... ", +" ", +" .............. ", +" ", +" .......... ", +" ", +" ", +" " +}; diff --git a/demo/bmp_source/rt_bold.xpm b/demo/bmp_source/rt_bold.xpm new file mode 100644 index 00000000..fb25642e --- /dev/null +++ b/demo/bmp_source/rt_bold.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char *bold_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +". c Black", +" c None", +/* pixels */ +" ", +" ", +" ", +" ........ ", +" ... ... ", +" ... ... ", +" ... ... ", +" ....... ", +" ... ... ", +" ... ... ", +" ... ... ", +" ........ ", +" ", +" ", +" ", +" " +}; diff --git a/demo/bmp_source/rt_centre.xpm b/demo/bmp_source/rt_centre.xpm new file mode 100644 index 00000000..17ca2896 --- /dev/null +++ b/demo/bmp_source/rt_centre.xpm @@ -0,0 +1,24 @@ +/* XPM */ +static char *centre_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 2 1", +". c #4D4D4D", +" c None", +/* pixels */ +" ", +" ", +" .............. ", +" ", +" .......... ", +" ", +" .............. ", +" ", +" .......... ", +" ", +" .............. ", +" ", +" .......... ", +" ", +" ", +" " +}; diff --git a/demo/bmp_source/rt_colour.xpm b/demo/bmp_source/rt_colour.xpm new file mode 100644 index 00000000..2dc11d53 --- /dev/null +++ b/demo/bmp_source/rt_colour.xpm @@ -0,0 +1,59 @@ +/* XPM */ +static char *rt_colour[] = { +/* columns rows colors chars-per-pixel */ +"16 16 37 1", +" c black", +". c #727D329BA5CF", +"X c #4CF6357BDDD0", +"o c #45CE2E66FA02", +"O c #45FF2D19FF52", +"+ c #45452C2FFFFF", +"@ c #47B22F3CFDC3", +"# c #45EF3E00EB43", +"$ c #456C3C9FF054", +"% c #45663A49F28D", +"& c #45B75BB5D2B6", +"* c #4B8899247615", +"= c #5F619039673F", +"- c #476EFFCA362C", +"; c #4747FFFF3633", +": c #4F3EF55734F1", +"> c #4899D8B04EEE", +", c #46F6DED055CF", +"< c #46EEDBB758C1", +"1 c #4720F01B4555", +"2 c #4724F1E8439E", +"3 c #5EEBE9D75212", +"4 c #46338EE4A1F3", +"5 c #ACF030145603", +"6 c #D9A917AD3776", +"7 c #DF82157232D4", +"8 c #FFD3091A193C", +"9 c #FFFF090A191B", +"0 c #FD590DB41D4A", +"q c #E46E13912EEF", +"w c #EC61108728A3", +"e c #C21E1CD652E5", +"r c #A38E1A6E8B66", +"t c #A37584C127AE", +"y c #A59D81DF2756", +"u c #B4A389EF830A", +"i c None", +/* pixels */ +"iiiiiiiiiiiiiiii", +"iiiiii999999iiii", +"iiiii999w9999iii", +"iiii9999999999ii", +"iiii9999999999ii", +"iiii9999999999ii", +"iiii9999999999ii", +"iiiituq999909iii", +"iii--*=567e.++++", +"ii--3>-:yrXo++++", +"i-------2$@+++++", +"--------,%@+++++", +"--------<#++++++", +"--------1&++++++", +"---------4++++++", +"i--------i++++++" +}; diff --git a/demo/bmp_source/rt_copy.xpm b/demo/bmp_source/rt_copy.xpm new file mode 100644 index 00000000..95ad4488 --- /dev/null +++ b/demo/bmp_source/rt_copy.xpm @@ -0,0 +1,44 @@ +/* XPM */ +static char *copy_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 15 23 1", +"o c #97C4E7", +"* c #FFFFFF", +"@ c #60A9DA", +"= c #D1E5F5", +"& c #C3DDF1", +". c #7EA6C0", +" c None", +"X c #2F93CD", +"O c #85BBE2", +", c #EFF6FC", +"; c #DEEDF8", +"+ c #72B2DD", +"3 c #F7FBFD", +"4 c #FAFCFE", +": c #DAEAF7", +"< c #E9F3FA", +"1 c #E2EFF8", +"- c #FDFDFE", +"% c #B6D5EE", +"$ c #A5CCEA", +"> c #E5F0F9", +"# c #AFD1EC", +"2 c #F4F9FD", +/* pixels */ +" .....XX ", +" .oO+@X#X ", +" .$oO+X##X ", +" .%$o........ ", +" .&%$.*=&#o.-. ", +" .=&%.*;=&#.--. ", +" .:=&.*>;=&.... ", +" .>:=.*,>;=&#o. ", +" .<1:.*2,>:=&#. ", +" .2<1.*32,>:=&. ", +" .32<.*432,>:=. ", +" .32<.*-432,>:. ", +" .....**-432,>. ", +" .***-432,. ", +" .......... " +}; diff --git a/demo/bmp_source/rt_cut.xpm b/demo/bmp_source/rt_cut.xpm new file mode 100644 index 00000000..8afa8f6d --- /dev/null +++ b/demo/bmp_source/rt_cut.xpm @@ -0,0 +1,46 @@ +/* XPM */ +static char *cut_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 15 25 1", +"6 c #D8BDC0", +": c #C3C3C4", +"- c #FFFFFF", +". c #6C6D70", +"2 c #AD3A45", +"o c #DBDBDB", +"# c #939495", +"< c #E42234", +"& c #C3C5C8", +"; c #C6CCD3", +"% c #B7B7B8", +" c None", +"* c #DFE0E2", +"5 c #B69596", +"3 c #9C2A35", +"1 c #CFCFD0", +", c #AB5C64", +"+ c #D2D3D4", +"$ c #BCBDBE", +"@ c #C6C8CA", +"> c #CDC0C1", +"O c #826F72", +"X c #979BA0", +"4 c #9B8687", +"= c #9FA0A0", +/* pixels */ +" .X .o ", +" O.+ @. ", +" O. .. ", +" O#$ %.& ", +" O.*.. ", +" #%#.. ", +" O=-.. ", +" #%#;. ", +" OO:=O ", +" >,,<, ,<,,1 ", +" ><23<1 1<32<1 ", +" ,2 4< <5 2, ", +" <, ,2 2, ,< ", +" 23,<5 5<,32 ", +" 6225 522> " +}; diff --git a/demo/bmp_source/rt_font.xpm b/demo/bmp_source/rt_font.xpm new file mode 100644 index 00000000..93f5991b --- /dev/null +++ b/demo/bmp_source/rt_font.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *font_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 3 1", +"X c #A6A6A6", +" c None", +". c #4D4DA6", +/* pixels */ +" ", +" ", +" . ", +" X.X ", +" ... ", +" X...X ", +" .. .. ", +" X. ..X ", +" ....... ", +" X. ..X ", +" .. X.. ", +" X. X..X ", +" .... ...... ", +" ", +" ", +" " +}; diff --git a/demo/bmp_source/rt_idea.xpm b/demo/bmp_source/rt_idea.xpm new file mode 100644 index 00000000..67b2bf76 --- /dev/null +++ b/demo/bmp_source/rt_idea.xpm @@ -0,0 +1,47 @@ +/* XPM */ +static char *idea_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 9 1", +"$ c Black", +"O c #FFFFFF", +"@ c #808080", +"+ c #000080", +"o c #E8EB01", +" c None", +"X c #FFFF40", +"# c #C0C0C0", +". c #ABAD01", +/* pixels */ +" ", +" ..... ", +" ..XXXXX.. ", +" ..XXXXXXXXo.. ", +" .XXXOXXXXXXXoo. ", +" .XOOXXX+XXXXXo. ", +" .XOOOXX+++XXXXoo. ", +" .XOOXXX+++XXXXXo. ", +" .XOOOXXX+++XXXXXXo. ", +" .XOOXXXX+++XXXXXXo. ", +" .XXXXXXX+++XXXXXXX. ", +" .XXXXXXX+++XXXXXXo. ", +" .XXXXXXX+++XXXXXoo. ", +" .XXXXXX+++XXXXXo. ", +" .XXXXXXX+XXXXXXo. ", +" .XXXXXXXXXXXXo. ", +" .XXXXX+++XXXoo. ", +" .XXXX+++XXoo. ", +" .XXXXXXXXo. ", +" ..XXXXXXo.. ", +" .XXXXXo.. ", +" @#######@ ", +" @@@@@@@@@ ", +" @#######@ ", +" @@@@@@@@@ ", +" @#######@ ", +" @@@@@@@ ", +" ### ", +" $$$ ", +" ", +" ", +" " +}; diff --git a/demo/bmp_source/rt_indentless.xpm b/demo/bmp_source/rt_indentless.xpm new file mode 100644 index 00000000..422b8080 --- /dev/null +++ b/demo/bmp_source/rt_indentless.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *indentless_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 3 1", +". c #4D4D4D", +" c None", +"X c #4D4DA6", +/* pixels */ +" . ", +" ", +" .... .........", +" ", +" X .........", +" XX .........", +"XXXXX ", +" XX ...... ", +" X ...... ", +" ", +" .... .........", +" ", +" .... .. ", +" ", +" . ", +" " +}; diff --git a/demo/bmp_source/rt_indentmore.xpm b/demo/bmp_source/rt_indentmore.xpm new file mode 100644 index 00000000..ac1e3366 --- /dev/null +++ b/demo/bmp_source/rt_indentmore.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *indentmore_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 3 1", +". c #4D4D4D", +" c None", +"X c #4D4DA6", +/* pixels */ +" . ", +" ", +" .... .........", +" ", +" X .........", +" XX .........", +"XXXXX ", +" XX ...... ", +" X ...... ", +" ", +" .... .........", +" ", +" .... .. ", +" ", +" . ", +" " +}; diff --git a/demo/bmp_source/rt_italic.xpm b/demo/bmp_source/rt_italic.xpm new file mode 100644 index 00000000..a9be5ac8 --- /dev/null +++ b/demo/bmp_source/rt_italic.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *italic_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 3 1", +". c Black", +"X c #A6A6A6", +" c None", +/* pixels */ +" ", +" ", +" ", +" ..... ", +" ..X ", +" X.. ", +" ..X ", +" X.. ", +" ..X ", +" X.. ", +" ..X ", +" ...... ", +" ", +" ", +" ", +" " +}; diff --git a/demo/bmp_source/rt_open.xpm b/demo/bmp_source/rt_open.xpm new file mode 100644 index 00000000..5a1b5552 --- /dev/null +++ b/demo/bmp_source/rt_open.xpm @@ -0,0 +1,57 @@ +/* XPM */ +static char *open_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 15 36 1", +"6 c #9BACC2", +"< c #9AEA53", +"9 c #94A5BD", +"5 c #839CB5", +"; c #4D7492", +". c #376485", +"$ c #7F99B4", +"r c #D1D9E5", +"7 c #EAEDF3", +"@ c #CAD2DC", +"% c #718BA7", +"t c #BECAD9", +"& c #65839D", +"0 c #DCE2EA", +"4 c #F5F6F7", +"w c #597B9A", +"O c #8DA0B9", +" c None", +"+ c #467291", +"u c #305F81", +"= c #B4C4D3", +"# c #CAE2AA", +"1 c #FAFCFE", +"3 c #A8B6CA", +"q c #E4E9ED", +"8 c #EEF1F3", +"X c #215579", +"2 c #7F97B0", +": c #B3BFD1", +"y c #7A90AC", +", c #C2CBDB", +"- c #ADD668", +"* c #B6D791", +"e c #CAD6E1", +"o c #DFF0D0", +"> c #BBC4D6", +/* pixels */ +" ", +" .... ", +"XXXXX .oo. ", +"XOOOO+@.#o. ", +"XOOOO$%&.*oXXX ", +"XOOOOOOO.*oX=X ", +"XOXXXX...-oXXXX;", +"XOX:>,.<<<<,.<<>.>.X0q7; ", +"Xw2O963:>>er0t; ", +"X&y2O963:>,er; ", +"uXXXXXXXXXXXX; ", +" " +}; diff --git a/demo/bmp_source/rt_paste.xpm b/demo/bmp_source/rt_paste.xpm new file mode 100644 index 00000000..57e7f2a5 --- /dev/null +++ b/demo/bmp_source/rt_paste.xpm @@ -0,0 +1,46 @@ +/* XPM */ +static char *paste_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 15 25 1", +"< c #FEECE4", +"> c #FEE3D7", +"O c #FFFFFF", +"o c #7B767D", +"% c #F79586", +"& c #CAE1F3", +"@ c #F08B62", +"# c #FCCBB8", +"- c #FDD8C9", +"4 c #FFF8F4", +"5 c #FFF5F0", +" c None", +"$ c #F8AA8F", +", c #EFF6FC", +"1 c #F7FBFD", +"2 c #FAFCFE", +"; c #DAEAF7", +": c #E9F3FA", +"6 c #FFFAF8", +". c #3C78A6", +"3 c #FFF1ED", +"X c #9B8687", +"+ c #FBBCA4", +"* c #B6D5EE", +"= c #F4F9FD", +/* pixels */ +" ...... ", +" .XoOOOOoo. ", +".+XOOOOOOX@. ", +".+XXXXXXXX@. ", +".#++$$%@..... ", +".##++$$%.&*.=. ", +".-##++$$.;&.==. ", +".--##++$.:;.... ", +".>--##++.,:;&*. ", +".<>--##+.1,:;&. ", +".<<>--##.21,:;. ", +".3<<>--#.O21=:. ", +".45<<>--....... ", +".6453<>----. ", +"............ " +}; diff --git a/demo/bmp_source/rt_redo.xpm b/demo/bmp_source/rt_redo.xpm new file mode 100644 index 00000000..442c1d03 --- /dev/null +++ b/demo/bmp_source/rt_redo.xpm @@ -0,0 +1,58 @@ +/* XPM */ +static char *redo_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 15 37 1", +"4 c #9BACC2", +"; c #4C7398", +"3 c #547B99", +"* c #547897", +"# c #5A89A6", +"8 c #3A749C", +"5 c #5A809C", +", c #7F99B4", +"& c #3F6F93", +"9 c #85A7BC", +"+ c #749BB4", +"> c #718BA7", +"e c #A5B3C8", +"w c #BECAD9", +": c #65839D", +"u c #E1E6EE", +"o c #236289", +"r c #ADBED2", +"= c #597B9A", +"2 c #8DA0B9", +" c None", +"% c #467291", +"1 c #7393AB", +"i c #4C809F", +"- c #A0BACB", +"O c #6591AE", +"X c #407598", +"6 c #6F90A6", +"t c #D2D9E0", +"7 c #ADBACE", +"@ c #326A8F", +"0 c #467A9C", +". c #ACC4D3", +"< c #7F97B0", +"y c #B3BFD1", +"q c #A2B3C5", +"$ c #8FB0C3", +/* pixels */ +" .XoooO ", +" +o@@@@@o# +", +" $@%%&@&%%&@ +o", +" X*=@+-+@*=;@#&@", +" @:=+ @=:=*:@", +" &>:$ @:>>>@", +" &,,,,&", +" +123 @<2222&", +" X44X #@56<44X", +" O1748 .9#&o", +" 0qwe8 ", +" 8rty8 ", +" 8wu+ ", +" i## ", +" " +}; diff --git a/demo/bmp_source/rt_sample.xpm b/demo/bmp_source/rt_sample.xpm new file mode 100644 index 00000000..aac05aa9 --- /dev/null +++ b/demo/bmp_source/rt_sample.xpm @@ -0,0 +1,44 @@ +/* XPM */ +static const char *sample_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 6 1", +" c black", +". c navy", +"X c red", +"o c yellow", +"O c gray100", +"+ c None", +/* pixels */ +"++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++", +"++++++++ ++++++++++", +"++++++++ ............ ++++++++++", +"++++++++ ............ ++++++++++", +"++++++++ .OO......... ++++++++++", +"++++++++ .OO......... ++++++++++", +"++++++++ .OO......... ++++++++++", +"++++++++ .OO...... ", +"++++++++ .OO...... oooooooooooo ", +" .OO...... oooooooooooo ", +" XXXXXXX .OO...... oOOooooooooo ", +" XXXXXXX .OO...... oOOooooooooo ", +" XOOXXXX ......... oOOooooooooo ", +" XOOXXXX ......... oOOooooooooo ", +" XOOXXXX oOOooooooooo ", +" XOOXXXXXXXXX ++++ oOOooooooooo ", +" XOOXXXXXXXXX ++++ oOOooooooooo ", +" XOOXXXXXXXXX ++++ oOOooooooooo ", +" XOOXXXXXXXXX ++++ oooooooooooo ", +" XOOXXXXXXXXX ++++ oooooooooooo ", +" XXXXXXXXXXXX ++++ ", +" XXXXXXXXXXXX ++++++++++++++++++", +" ++++++++++++++++++", +"++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++" +}; diff --git a/demo/bmp_source/rt_save.xpm b/demo/bmp_source/rt_save.xpm new file mode 100644 index 00000000..3bf3abb3 --- /dev/null +++ b/demo/bmp_source/rt_save.xpm @@ -0,0 +1,42 @@ +/* XPM */ +static char *save_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 15 21 1", +"O c #FFFFFF", +"> c #D5D6D8", +"; c #446A8C", +"1 c #CAD2DC", +": c #C0C7D1", +" c #5F666D", +"% c #A5B0BA", +"o c #65839D", +", c #DCE2EA", +"< c #C3C5C8", +"- c #E1E6EE", +"* c #C6CCD3", +". c None", +"$ c #305F81", +"2 c #D6DFE7", +"= c #D2D9E0", +"& c #B7BFC7", +"X c #1B4467", +"# c #BCBDBE", +"@ c #7A90AC", +"+ c #5D7C93", +/* pixels */ +" .", +" XoOOOOOOOOO+X .", +" @oO#######O+@ .", +" @oOOOOOOOOO+@ .", +" @oO#######O+@ .", +" @oOOOOOOOOO+@ .", +" @@+++++++++@@ .", +" @@@@@@@@@@@@@ .", +" @@@$$$$$$$$@@ .", +" @@$%%%&*=-O$@ .", +" @@$%X;;*=-O$@ .", +" @@$%X;;:>,O$@ .", +" @@$%X;;<12O$@ .", +" @@$<<2OOOOO$@ .", +". .." +}; diff --git a/demo/bmp_source/rt_smiley.xpm b/demo/bmp_source/rt_smiley.xpm new file mode 100644 index 00000000..94581089 --- /dev/null +++ b/demo/bmp_source/rt_smiley.xpm @@ -0,0 +1,42 @@ +/* XPM */ +static char *smiley_xpm[] = { +/* columns rows colors chars-per-pixel */ +"32 32 4 1", +". c Black", +"X c #FFFF00", +" c None", +"o c #C00000", +/* pixels */ +" ", +" ..... ", +" ...XXXXX... ", +" ..XXXXXXXXXXX.. ", +" .XXXXXXXXXXXXXXX. ", +" ..XXXXXXXXXXXXXXXXX.. ", +" .XXXXXXXXXXXXXXXXXXXX. ", +" .XXXXXX.XXXXXXX.XXXXXX. ", +" .XXXXXX.X.XXXXX.X.XXXXXX. ", +" .XXXXX.XXX.XXX.XXX.XXXXXX. ", +" .XXXXX.XXXXXXXXXXXXX.XXXXX. ", +" .XXXXXXXX.XXXXXXX.XXXXXXXX. ", +" .XXXXXXXX.XXXXXXX.XXXXXXXX. ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXX. ", +" .XXXXXXXXXXXXXXXXXXXXXXXXXXX. ", +" .XXXXXXX.XXXXXXXXXXX.XXXXXXX. ", +" .XXXXXX...XXXXXXX...XXXXXX. ", +" .XXXXXX.oo..XXX..oo.XXXXXX. ", +" .XXXXXXX.ooo...ooo.XXXXXXX. ", +" .XXXXXXX.ooooooo.XXXXXXXX. ", +" .XXXXXXXX..ooo..XXXXXXXX. ", +" .XXXXXXXXX...XXXXXXXXX. ", +" .XXXXXXXXXXXXXXXXXXXX. ", +" ..XXXXXXXXXXXXXXXXX.. ", +" .XXXXXXXXXXXXXXX. ", +" ..XXXXXXXXXXX.. ", +" ...XXXXX... ", +" ..... ", +" ", +" " +}; diff --git a/demo/bmp_source/rt_underline.xpm b/demo/bmp_source/rt_underline.xpm new file mode 100644 index 00000000..5513b39a --- /dev/null +++ b/demo/bmp_source/rt_underline.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static char *underline_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 16 3 1", +". c Black", +"X c #A6A6A6", +" c None", +/* pixels */ +" ", +" ", +" ", +" .... .... ", +" .. .. ", +" .. .. ", +" .. .. ", +" .. .. ", +" .. .. ", +" .. .. ", +" ..X X.. ", +" ..... ", +" ", +" ......... ", +" ", +" " +}; diff --git a/demo/bmp_source/rt_undo.xpm b/demo/bmp_source/rt_undo.xpm new file mode 100644 index 00000000..529123fc --- /dev/null +++ b/demo/bmp_source/rt_undo.xpm @@ -0,0 +1,58 @@ +/* XPM */ +static char *undo_xpm[] = { +/* columns rows colors chars-per-pixel */ +"16 15 37 1", +"4 c #9BACC2", +"* c #4C7398", +"2 c #547B99", +"- c #547897", +"@ c #5A89A6", +"8 c #3A749C", +"6 c #5A809C", +", c #7F99B4", +"$ c #3F6F93", +"7 c #85A7BC", +"+ c #749BB4", +"> c #718BA7", +"0 c #A5B3C8", +"q c #BECAD9", +": c #65839D", +"u c #E1E6EE", +"X c #236289", +"y c #ADBED2", +"= c #597B9A", +"1 c #8DA0B9", +" c None", +"% c #467291", +"3 c #7393AB", +"i c #4C809F", +"; c #A0BACB", +". c #6591AE", +"o c #407598", +"5 c #6F90A6", +"t c #D2D9E0", +"9 c #ADBACE", +"# c #326A8F", +"e c #467A9C", +"O c #ACC4D3", +"< c #7F97B0", +"r c #B3BFD1", +"w c #A2B3C5", +"& c #8FB0C3", +/* pixels */ +" .XXXoO ", +"+ @X#####X+ ", +"X+ #$%%$#$%%#& ", +"#$@#*=-#+;+#=-o ", +"#:-=:=# +=:# ", +"#>>>:# &:>$ ", +"$,,,>o o<,$ ", +"$1111<# 213+ ", +"o44<56#@ o44o ", +"X$@7O 8493. ", +" 80qwe ", +" 8rty8 ", +" +uq8 ", +" @@i ", +" " +}; diff --git a/demo/bmp_source/rt_zebra.xpm b/demo/bmp_source/rt_zebra.xpm new file mode 100644 index 00000000..3f76255f --- /dev/null +++ b/demo/bmp_source/rt_zebra.xpm @@ -0,0 +1,409 @@ +/* XPM */ +static char *zebra_xpm[] = { +/* columns rows colors chars-per-pixel */ +"200 167 236 2", +"` c #A68369", +" c #FCFEFC", +"). c #9AA45B", +"wX c #CBCEA4", +"0. c #C7CB71", +"aX c #5A7120", +"S. c #1E180D", +"+. c #D9CAAB", +"f. c #96A43B", +"L c #51501B", +"4. c #FAF2CF", +"tX c #401E0C", +"x. c #979459", +"&X c #B5835B", +"jX c #838D77", +"e c #3A3014", +"zX c #424734", +"z. c #DCBF7D", +"X. c #8E8D2F", +"o. c #939441", +"r. c #98785B", +"_. c #6E7828", +"W. c #748C28", +"E. c #D6C866", +"Z. c #ACAE61", +"T c #AAB460", +"yX c #3A3025", +"< c #D0BD89", +",. c #E6CDA4", +"/ c #A69147", +"^ c #97823C", +"qX c #4E4031", +"& c #998254", +"-X c #7C4829", +"P c #C5A287", +"kX c #54573D", +"8X c #ACBA94", +"%X c #A47150", +"'. c #7F7828", +"1. c #8C7056", +"U c #B9A088", +"Q. c #8F942E", +"B. c #C6A35F", +" . c #6A7818", +"X c #ECEDE1", +";X c #A77855", +"3X c #6E492C", +"$ c #95947A", +"bX c #142108", +"% c #99826B", +"vX c #1C2F0A", +"N. c #3A4710", +"[ c #A4B444", +"xX c #4A6012", +"w c #3E3816", +"9. c #9DAD31", +"m c #6E692B", +"x c #B5945B", +"H c #26310B", +"F. c #966644", +"3 c #D0B4A0", +"j. c #838F48", +"} c #A5BB39", +"M c #6F5029", +"F c #52680E", +"C. c #A6A544", +"; c #CEB18C", +"*. c #B4C748", +"= c #B8A175", +"=X c #603E1F", +"4 c #D9DBCC", +":X c #DCA47C", +"]. c #948C42", +"9 c #6E6028", +"I c #D1BEA3", +"s c #918B63", +"=. c #ACBC5E", +"R c #AABC49", +"l. c #4F351F", +"i. c #D8D06B", +"{ c #B6BE4F", +"v c #5F542F", +"|. c #F4E0C8", +"%. c #977052", +"A. c #939C3C", +".. c #44401B", +": c #E8D8B5", +"/. c #959C55", +"L. c #A69C45", +"c. c #BBC873", +"@ c #A8AB98", +"uX c #534F38", +"6 c #747D67", +"Y c #BBBF61", +"v. c #CEBF69", +"5 c #BCBEAC", +"K. c #7E7028", +"k. c #2D1D10", +"fX c #545F3F", +"k c #302712", +"+X c #C7CA8D", +"u c #96773F", +"p c #BAAC64", +"U. c #415010", +"y c #4E3F1F", +"4X c #81512C", +"<. c #8C785F", +", c #DEC1A2", +",X c #D1D8A8", +"J. c #44570E", +"6X c #6E5743", +"M. c #5F6517", +"7X c #727148", +"N c #A58354", +"lX c #2C3020", +"#. c #C1B399", +"R. c #9CA52B", +"t. c #737E43", +"+ c #C9CDC4", +"> c #E6CFB8", +"t c #6F6446", +"Y. c #59710E", +"dX c #5C7B10", +"W c #A1AC43", +"J c #7E7058", +"n c #836832", +"8 c #635F49", +"y. c #727161", +"z c #1E280B", +"2X c #DCB89A", +"q. c #81912B", +"u. c #BEC082", +"@X c #806149", +"2. c #F6DFB2", +"}. c #D49868", +":. c #728229", +"-. c #738C15", +"2 c #BFAD97", +"d. c #8E9D27", +"@. c #D9CB8A", +"~ c #5F5617", +"V. c #A1AC60", +"5. c #E6DA83", +"w. c #444815", +"C c #E8E9CD", +"K c #83684F", +"oX c #82783C", +"g. c #546113", +"b c #5E4931", +"f c #878259", +"`. c #6E8216", +"h c #89826F", +"OX c #B58D5E", +"5X c #C6905C", +"*X c #749314", +"8. c #9EB331", +"rX c #714025", +"#X c #7E583C", +"!. c #DCD8B1", +"| c #8FA426", +";. c #60632B", +"g c #A99179", +"E c #94AB37", +"eX c #5E402E", +"l c #3E2813", +"O c #D9CEBE", +"iX c #413828", +"S c #B9C75B", +"0 c #5F5643", +") c #E6CE8E", +"D. c #B5A448", +".X c #ECB684", +"I. c #819C18", +"{. c #7E9219", +"hX c #4A563A", +"0X c #80785B", +"i c #B7A15D", +". c #F5EFE2", +"h. c #1F200E", +"XX c #84A317", +"3. c #E9DEB3", +"1X c #9C9F8E", +"gX c #636748", +". c #806031", +"m. c #808326", +"7 c #6F6657", +"Q c #849D28", +"c c #6F572B", +"' c #E3E7BA", +"^. c #94B625", +"b. c #B9B562", +"p. c #B7B54D", +"V c #F6EACE", +"( c #CEAC63", +"# c #AB9C84", +"a. c #CDBF58", +"$X c #8C5F3C", +"] c #C9CE63", +">X c #4E2C15", +"1 c #C2B385", +"pX c #F0BE88", +"B c #C6A176", +"$. c #958C78", +"&. c #D5D98F", +"r c #5E481F", +"sX c #434032", +"A c #C9D487", +"P. c #DFB27C", +"~. c #94B336", +"_ c #B79275", +"6. c #D8D770", +"n. c #B7AC4E", +"T. c #94AD27", +"H. c #687017", +"s. c #C4BE52", +"cX c #14160B", +"D c #849A49", +"9X c #805135", +"Z c #DAE0B2", +"7. c #C7C85E", +"G c #383F10", +"a c #A8A059", +/* pixels */ +" . . . ", +" X X o O + @ # $ % & # * = # = - ; : > , < 1 2 < 3 O O o o o . . ", +" . 4 5 # 6 7 8 9 0 q w e e r t y q y r u * = i p # a s & d & & u s = f t & g g 3 : o . ", +" + 2 h 8 j w e k e l e w e z e e e y r w w y 9 9 x = * & t t c v b n d m c & & M N * B < , , : V > : V . ", +" C Z A S D F G k k H k e k e k e H e k e H e w e e r m r n J K 9 v L y e e y c b r n * i * x = P 3 , I ; P U , , > > o o X ", +" X A Y T R R R E W Q ! e e k k H k e k k e e e w k k e y ~ ^ v c v y b y y w e k e e e c / & u N x ( ) , ; # _ g g ; I < ; P ` g 3 I V ", +" ' Z ] S S W [ T { [ E R } | .G k k H k H k e z e H e w e ..X.o.O.q y r r e l k e l e k l y u u ^ & N N B ; +.@.U # = g ; #.= - = $.%.` _ ; > V ", +" C &.] S *.S S =.=.R { R R =.[ R W E -.G H k k l H k e k e k e e w w ;.:.e e e k l k k l k k e l y >.>.d d N i - = < ,.I = P = ; - = = = <.%.1.%._ P ,.2.3.O 4 . ", +" 4.3.5.5.6.7.7.{ S R [ 8.9.{ *.{ S 0.=.T W 9.q.w.k k k k k H k k k H k H w.L :.G k k k k k k k k k k e y q r r M & = = e.> 3.: a & = = = B - = = & * r.= ; < ,.2.Z t.y.@ C ", +" . Z ' u.7.7.i.] 7.S { ] 7.{ p.W W p.{ a.6.s.7.9.d.R f.g.H k k H k e k k k h.k w.~ j.G H k h.h.k.h.k.k k w l.q y ..y r ^ - = = z.@.) = N x = a & - < - = # 1.* B ,.) : 2.u.;.;.x.T o ", +" . A T W c.Y A A A i.v.Y s.7.b.i.v.i.Y p.n.n.{ p.T [ [ { Y =.m.G z k k z k z z z z e M.t.! N.h.k.e z k l ~ e M.w.L ....w.~ i z.< ; = B e.B.x i = < < 1 - - = x x.* % B , ) @.u.b.V.C.Z.1 u.o ", +" X &.c.[ E W =.=.{ Y =.=.S 7.Y s.{ Y 7.] i.7.{ { s.7.Y p.R [ ] ] ] A.G z k k k z k z G ! ;.O.M.w.z S.H w k q L M.! M.w...w.~ 9 x < e.B.D.e.x a i B.p ; ( p - p 1 # g ` d F.; u.b.b.a p = B = ; < ; : . ", +" . A ] c.S S R [ [ { Y 0.] S c.S =.R R { =.Y 7.i.0.] ] 0.S 0.{ { S { [ | D G z k z z z k G.G H.j.m.m.~ e e G k m.:.q. .F ! N.J.L K./ e.e.e.b.v.b.e.n.n.v.D.L./ / x @.z.1 <.d x , 1 b.p i _ i B.B.B.P.D.( < o . ", +" 4.&.7.0.7.] 0.S { { S { =.] S =.S S S *.R R *.S S 7.7.] ] 6.] 7.6.7.7.=.I.E =.q.N.G.~ w.U.! U.U. .m.m.X.-.Y.M.m.g.q.W f.T.q.d.m.m.R.X.n.p.b.e.E.Y p.[ T p.7.b.D.n.b.s.e.E.p x B.; < 1 ; e.e.( ( ( e.( ( ( B.B.( z.: ", +" 4.V 5.: &.7.c.T { =.=.Y 7.=.=.S V.R =.[ =.=.*.S ] *.R Y Y 7.7.] 7.Y A 6.] R Q [ S =.W :.W.f.Q.f.f.m.W f.[ f.d.W A.f.C.p.W f.[ W [ W [ Z.C.s.s.b.Y 7.T R [ 7.R 7.p.n.p.a.v.E.i.v.0.e.@.v.b.v.v.v.( ( ( z.( P.( ( e.E.z.z.E.3. ", +" . !.v.1 z.3.: &.Y =.[ T { T V.[ E V.~.[ =.R [ f.W E T.=.[ } R [ [ V.{ [ R =.c.=.8.8.8.^.R } [ =.W f.d.f.b.Y T R Y c.{ { { { R [ 9.[ [ W [ W [ Z.=.p.p.{ R 9.[ S p.Y Y Y Y 7.s.E.i.) i.0.7.Y p.p.p.{ a.E.n.a.( e.e.E.5.E.i.) e.v.@.V ", +" V u.p p p p @.: 2.3.@.=.[ T Z.{ T W =.T Y T b./.:.m.d.A.[ W E A.[ R 9.Y W =.[ [ [ ~.E E T.(.^.^.} R [ W =.c.S S Y *.c.R { R } R [ 8.[ 9.C.[ 9.W { W C.{ { W 9.{ 7.R.[ { { { p.=.{ { 7.a.7.a.i.i.E.a.s.s.s.n.s.a.E.E.E.i.) E.E.7.E.i.i.: 4. ", +" C 0.=./.o.u.=.W p.n.e.< @.5.u.p b.@.u.[ =.W R ).W.:.M.m.V.A.W =.[ R [ [ 9.} R ~.[ ~.[ } R } } R [ R { R R R Y S R } 8.R R R S [ [ 8.[ 8.W 9.9.p.{ W p.p.Z.L.p.p.p.{ { L.C.{ C.{ { Y 7.s.Y { 7.7.7.i.E.E.e.B.a.a.a.E.v.a.s.Q.^ p.a.e.a.a.v.s.7.3. ", +" . Z =.W W T | 9.[ W [ [ b.s.1 e.b.T a C.V.W T f.V.W /.f.E W { =.R R R R [ ~.} R } R } } } ~.[ [ } S *.{ E ~.8.R R =.E [ } R R *.*.R R E [ W W [ { Y S Z.R.C.p.p C.{ p.s.7.7.7.s.7.E.7.s.{ p.[ s.7.{ p.s.a.s.( L.B.i e.i.a.s.b.p.p.C.p.i L.E.s.C.7.s.# o ", +" X A =.W [ [ T E E =.f.q.f.f.Z.T V./.:.t._.o.W ).q.D f.[ R S *.} R R } R } } } [ } ~.R ^.^.~.8.~.^.8.} { R W | E E ~.[ [ [ R R S Y R *.{ R p.{ Y 7.s.{ s.S p.{ p.{ 7.{ s.s.{ a.i.] a.7.7.7.S p.C.C.n.a.a.s.s.{ p.( ; e.e.n.p p s.7.s.7.a.v.i.i.i.i.v./ 9 & : ", +" . #._.m.A.W A.C.f.f.q.D A.A.f.E E q.W.`.W.q.q.[ f.d.E 8.[ R R R R R } } [ R =.*.} R ^.~.} ^.} ^.} *.} ^.8.8.9.{ d.d.V.=.=.=.R *.} *.*.p.7.{ Z.[ W p.C.D.n.a.{ A.Q.A.R.{ } { { p.{ { 7.7.s.7.Y { { S p.n.e.s.9.p.p.a.a.p b.e.b.C./ L.L.p.p.p.a.E.7.a.s.u u d n u ,.. ", +" o $ '.].a Y Y { Y c.[ [ [ R =.R [ R R R R [ R [ [ R R R } R R } } } } 8.~.E R ~.E } ~.^.^.} *.^.} } *.*.R R *.{ 9.[ =.S R } { *.[ } 7.p.D.s.p.n.a X.d.m.^ '.^ m.[.K.m.K.Q.{.| D.a.9.C.C.p.{ s.S Y } { { { s.{ { s.7.7.7.s.{ Y Y { T b.i n.n.a.b.a.p.L.K.'.u n n >.}.) |. ", +" o p s.v.7.7.7.Y Y 7.i.7.c.*.{ { 8.[ R S *.=.=.} [ R } } } ~.~.[ [ R ~.~.(.(.E E ~.(.Q (.(.~.} ^.^.*.*.*.*.*.} R S { *.[ R [ 9.} R *.s.7.{ p.D.x / u r r ~ ~ M Xc >.c 9 ~ m.{.X.Q.D.n.C.C.{ { S Y *.} { { p.{ Y Y S 7.R Y Y Y S 7.{ p.s.e.v.b.s.n.a o.u n u / u '.>.u e..X@. ", +" : E.v.7.7.0.7.{ S Y s.a.S 7.W 9.f.8.*.*.S [ ~.[ } R R ~.~.} ~.} ~.E ~.~.~.(.| E | Q ~.Q (.(.XX} } ~.^.} ^.XX} } [ } R [ [ 9.| [ 9.8.} { *.*.] b.B.i B./ m.m.m.X.X.^ oXn ~ X.R.*.A./ b.Y p.C.[ 7.[ { { { { { { S s.7.{ S p.{ Y { { p.v.7.Y s.Y s.=.p.C.'.'.m.L.n.e.s.p./ B.v.B., . ", +" V < e.e.a.7.7.E.i.s.Y { p.W D.{ f.Z.8.8.=.R R 8.8.8.8.} } ~.} ~.^.*.~.~.E ~.[ ~.=.~.~.R (.E (.~.E ~.E 9.d.8.8.8.} R } [ R [ } 9.[ R R *.*.R } } { s.7.s.b.p.p.n.W W C.n.p.n.C.} [ p.C.C.C.{ { R { [ } } { Y { { s.Y s.{ p.{ 7.{ S 7.{ { { Y Y 7.{ Z.[ [ W R.9.W [ p.n.p.[ p.n.i e.e.@.o ", +" . < s.E.7.i.i.i.7.i.] S 7.S { p.[ R [ [ } R *.R } [ } ~.~.} ~.~.~.~.R ~.~.~.[ } R ~.} R [ E E W [ [ p.p = = p p p.} } *.Y Y [ } } } R *.R *.} { } p.R.n.p.W p.8.8.9.} } R.p.s.*.} 8.9.8.*.} *.{ { [ [ 8.[ [ W W { { { { R { { { { { { =.{ [ { R { R n.W d.d.E W R.R.W 9.W R.p.W L.D.p b.n.!. ", +" V 0.E.0.7.s.7.] ] 7.7.7.{ { { } } 8.W | 8.E 8.7.R } ~.8.} ^.~.8.~.~.8.[ } R R ~.~.} ~.~.} R [ V.i = OXOX` * OXOXOX_ i p.p.i.7.7.R =.W | 9.9.9.9.8.{ [ X.C.[ R.| 9.} ^.} } { *.} 8.*.*.*.*.R } *.R { C.d.Q.X./ ^ ^ D.a.p.p.{ [ [ A.C.W T W p.R [ p.p.{ { { p.W f.f.9.W W p.C.Q.L.C.R.X.Q.].X.A.+X. ", +" Z b.{ Y b.Y b.s.s.Y { { { R W 8.[ [ ~.8.R R E | ~.8.} ~.E XX} R ~.(.XX| E E E (.~.(.| [ T.} =./.r.u ` B , +.g @X#X$X$X%X&X; 5.1 Y T Z.f.R.W 9.[ d.Q.C.7.{ R [ 9.R.} } } } } 8.} 8.8.} [ R R | {.8.[ W ].'.K.M M r X XL.D.A.Q.A.f.W [ p.p.p.[ p.8.n.=.0.Z !.c.W W [ C.9.p.p.p.R.D.n.Q. .'.H.;.M.[.s . ", +" 3.W C.A.R.C.{ s.Y n.W n.[ 9.W 9.} W 8.} ~.~.^.E E ~.8.E ~.E } Q I.Q W.{.*X*X-.*XQ (.E | [ E f.A.i < : 2.4.4.4.I 7 b =X-X$X%X;X:Xo C : +Xu.C.A.o.n.C.L./ W R.D.*.[ } } 8.8.T.} 9.d.I.T.9.W W T f.q.d.A.x.<.9 v r y >Xr =X/ D.D.Q.L.m.C.a.s.s.S { W p.@.V C : o C ,XT C.W p.p.a.p.n.Q.o.m w...w e H e H 7 o ", +" !.{ A.A.q.Q.C.s.a.C.C.f.d.Q q.| W } 8.[ (.I.I.E T.XX(.Q XXQ I.q.XX| (.| | E ~.E [ ~.~.R ~.~.W W ) 4.4.2.2.: 4.4.3.5 g b .L.v.p.=.C.s.Y s.{ W p.s.a % g g 1X# I 4.&.7.a.p.p.a.C.m.9 g.w.G w H e m L w.k y.o ", +" u.q.d.d.d.A.Q.C.C.C.o.Q.q.{.m.| d.| W 8.R E (.XXXX| E E (.} ~.~.Q f.E } R =.*.*.=.~.[ R } } R { 5.2.@.B 2X2X,.z.> |.2.o @ @X3X-X4X$XF.5Xo o O O o V o +XD.p.n.p.{ 8.p.{ } } } 8.[ T.XXT.T.[ v. . X = f 7 v 0 @X0 t 6X0 K 6X>XM L.{ =.{ { s.a.s.n.e.7Xw k.k.l.0 y.1.I : v.i.E.5.o.;.L L G w q ..L '.o.[.o.G M.D C ", +" . 8Xd.{.q.Q.Q.| d.R.W d.d.d.Q.q.E [ 8.9.8.| ~.I.| Q E Q (.~.~.E ^.} [ } } } R [ [ [ R R ~.} ~.8.7.< ; P OX= B - P 3 ; +.V C V !.g #X-X9XF.F._ |.. > > o |.C 3.@.s.p.p.n.[ { Y S R R 8.T.8.^.8.R p !.O % 0Xt b qXb 0 @X8 t 0 t f e >Xn W C.p.p.b.s.v.E.a e k.k.k k k.k.k =Xx z.E.E.E.m.~ ~ M.q ~ L ~ M.C.p.C.C.C.f.d.T X ", +" ,XQ.W A.d.f.Q d.f.{.| `.X.-.d.f.R ~.~.E E XXf.d.`.-.| Q {.f.f.E 9.8.~.8.R } 8.8.E } R *.~.[ 9.0.; * & r.g _ _ B _ P > I ; > . . . wXr.#X$X$X%X&X> . : O > o X C 5 [.oX/ A.C.} } R 8.R ^.8.} 8.T & ` K @X3X8 qXl 0 b t 6XJ 7 8 % e e =XQ.p.[ D.p.v.v.b.t k k.>XeX3Xl.k.S.k.M a.a.E.E.p.Q.D.L.Q.X.L.p./ p.a.( C.{ { R.[ c.. ", +" ,XY E E f.| Q.d.{.{.{.{.{.`.{.f.Q Q Q.A.C.[ | R.C.W d.d.m.`.W.E 9.R { W W [ [ 8.} T.~.~.~.8.{ < - J @XK r.%.;XP % ; I g P o : 3 > 4.. o # @X$XF.%.&X2X. X o o o V . wX^ ^ Q.[ R } R } } R 8.E f.A.r >XrX9X#XM j k l.0 6X0 6 t 6Xh 6Xr >X^ p.s.s.p.7.a.f >XtX=X9X#X$X#XyXS.k.rXn.p.p.E.p.s.s.a.a.s.7.p.D.L.L.s.a.n.{ 9.{ 8.Y . ", +" Z ~.(.E f.XXQ *Xq.Q q.| 8.[ E E E | *XO.'./ C.f.9.T.9.f.f.| W 9.8.*.9.| L.].].m.`.{.W.`. .R.a B.U h 6Xt @X@X<.` r.; g ` +.O 2 3 : o I +.. . O %.@X$XF.;XP > o o |.X |.. C u.b.[ 8.[ R [ E W | Q Q.f l.tX.n.E.7.s.a.p.r e eX$X9X$XF.$Xl.k.k.M n.p.s.s.( E.s.( p.p.s.p.n.n.D.D.p.s.s.p.} W 9.A ", +" 4 ~.E | f.(.Q {.{.| E E ~.[ [ W f.E [ q.Y.m.A.[ 9.8.9.[ } W R p.*.8.R.I.{.X.X.K.;.M.M.J.w.'.V.* * s 6X6Xt K %.r.%.; r.` +.U g 3 o I 3 > |.+.o . O r.F.F.F.%X_ > X > > o . . V ,XA.A.X.[.m.m.A.C.A.o.[.l tX C O o o # K F.F.%X;X3 . . . . V 1 ].[.~ 9 [.oX]./ & @X>XtX>XXtXtX>XXK u %./ Z./ P _ _ ; 4. : d M.D.s.s.a.n.].N / B.n.n.n.E.E.i.] E.E.s.a.a.a.E.p.s.p.p.7.3. ", +" ).-.-.I.*X-.`.`.-.I.{.W.:.A.W [ V.E E T.(.| (.XXf.f.f.Q XXQ 9.[ [ [ R *.S } { W p.n.{ =.[ 8.} D v j 7 0 0 j qX3X@X6X6X2 @XK , % 1.; #.` 2 O # g , o 2 P |.. I % %.F.F.%X_ , X |.. V V V !.b.p ( p a a x.<.y l k.>XrX>.` 2X4.V g @Xj qXl.qXyXk.S.k. I g _ , |.O I o 2 r.F.F.%X&X_ O . . . . . V ,XY Y Y p <.K 6XyXy d s $.$ U +.> u %.6XqXqXb l.S.S.S.>X$XOXB , ; _ ` OX&X, ' =.} R p.{ { { 8.{ p.9.n.} { { s.R C.p.s.E.7.p.p.p.[ p.W p.n.[ W S ", +" 5 ! M. .{.-. .dXU.N.G H L q.E q.W. .q.{.:.`.q.Q f.~.~.R =.} E [ [ E R =.} R } E E 8.} 8.8.d.f.=.D fXuX0 uXsXqXsXqX8 yX@X8 l.U 7 eX_ # 3X` I @XK , U 1._ > I g P |.o 3 U g ;X1.%X&XP 3 > |.. X o V > u.b.a t b c 0 y v J s $.$.= ` F.5Xr.0 0 j qXk.S.S.>XF.2.,.4.I r.$XP ` 2X3.u.W [ n.{ 9.} 8.n.7.8.8.9.9.R R s.{ 7.s.s.b.a.s.{ p.p.[ R.p.8.p.C.p.A ", +" o gX~ A.Q.A.Q.q. .G G G w.O.Q W.`.Y.N.J.! J.H.d.[ E ~.[ } *.[ R R c.[ R *.R R ~.| E f.} *.[ | [ +XD hX0 j 0 uXj qXqX0 yX7 yX1.7 l.%.# eX$X2 6X3X3 # @X` > g % ; O 2 U : o P U _ ` ;X&X_ P > > V o o 3.3.I $ 6XqXiXb uXqXv J f <.K @X` r.eX7 uXj j k.S.tX>X%X> : > C +.- ,.|.+.b.[ 9.9.R.{ 8.{ 7.R ] S 8.p.{ { 8.{ { s.p.p.n.p.n.p.p.a.a.s.*.{ { p.p.[ !. ", +" jX..H.Q.^ x a A._.m w.~ m.q.`.`.H.J.H w.! N.:.E [ ~.R } R R *.=.9.S R [ Y } } [ E E E } c.=.dXD ).7X8 y 8 j qXqXuXj j 6XiXb J l.%.3 j eXP 7 rX_ 2 3X;X+.% K 3 I ` g > I 3 : O _ _ g ` &X_ P 3 > |.|.o > #.0XqXl yXl.j b v 0 0X9 6Xt K 1.0XJ uX6Xj iXk.tXtX-X; V |., > o 4. Z =.[ p.[ { S Y 7.7.R 7.{ R { } s.{ p.8.s.p.p.p.R s.a.a.a.E.a.p.s.7.7.s.p.a.. ", +" ,X'.K.X.X.m.Z.i Y C.X.X.o.C._.`.m.oXO.M.'.q.W.8.~.E (.[ } } ~.*.R [ *.[ [ } ~.~.E XXE Q R ~.W.f.V.E ;.w.8 yXuXuXsXqX8 sX6XiXJ iXF.2 7 eXP $. g _ > I I o 2 U _ _ P _ P P 3 3 3 # J qXiXiXiXiX7 j 8 v 7XJ 0Xf h $.h y.7 uXiXk.k.tX>X-X2X: o o +.: C b.=.R.n.W L.W C.9.s.{ { a.7.p.s.C.a.[ p.{ p.} p.p.E.E.s.p.a.a.s.C.X.9.a.s.s.i. ", +" . b.Z.p.R W [ Y } =.W T o.L.L./ / C.L./ q.f.W d.| E R ~.~.~.~.E 8.~.(.[ E ~.R [ E Q *X*Xq.~.[ E Q Q D fX8 sXt 0 qXj sX7 qXuX8 qXqX_ 7 eX_ # eX%.I <.%., % %.O U @X; I % _ I _ 3 O 3 > I % # , P U 3 3 3 I g J 0 qXj b j j j uXqX0 9 0Xf $.$ h y.8 sXyXS.k.>X>XrX; I O : C |.V c.T T R.C.o.X.d.Q.D.C.L.L./ L.C.[ p.7.7.s.s.p.p.} n.p.p.a.6.6.a.B.D.D.p.p.a.p.p.,X ", +" ,X[ R { R } R } } E [ 9.R.f.C.].L.L.C.T R R } ~.} 8.R ~.~.[ [ ~.8.~.(.| E =.=.~.E f.E E f.R [ E Q Q f.;.q 8 j qXj uXqX0 8 yX7 yX@X0 k.l.#.b eXU <.K 2X% % +.% 1.3 #.r.P 3 ` 3 U _ +.O U 3 o 2 U , 2 ; P g <.0 qX0 qXuXsXj j j iXuXj t f h $.h y.j uXyXl l >XeX$X_ 3 O #.I 3.+X=.=.{ [ { p.d.n.9.D.Q.K.~ K.'.L.W { s.0.s.p.n.R.n.D.D.p.a.i.E.E.a.n.a.E.s.s.p.9.W X ", +" C } 8.8.} } E (.~.} ~.8.R R R } } 8.W 8.R } ~.~.} ~.[ 7.[ } R ~.} 8.[ 8.[ E Q E ~.D {.E [ E [ (.E ~.[ ~.fXt iXw 0 qX0 qXb 7 qXj yXh k S.l.<.k eX$.3XP g 1., g K , U %.I #.* 3 % _ !.` ` +.O ` P I 2 ; _ % 1.0 uXuXj 0 sXb qXj uXl 0 qXq J s s y.uX8 iXiXyXyXl.F.` 3 I +.4 2 ,XT W R.[ [ [ { p.s.*.{ { C.].'.^ X.L.9.} p.7.e.b.C.n./ ^ D.a.i.E.a.E.a.n.p.s.s.s.W W A ", +" . c.E (.^.E ~.~.~.(.~.^.~.~.~.^.~.~.(.~.~.E XX(.T.E d.p.Y R ~.~.~.~.8.~.E E E | E E (.8.8.W Q E XX(.Q Q q.fXw t 7 qXj 0 j sX0 b yX6Xh S.S.b uXk.6Xb K g #X3 g @X2X# r.+.# U 2 1.; I %.P o # r.I U ; U U ` <.6X0 qX0 iXuXiXkXyXj uXk.0 w qX9 % $ kX0 j qXqXl.l.$X` OXP I : O o wXW R.W W W [ s.s.8.} 8.8.{ p.W L./ Q.p.[ { { T W p.a.v.z.) e.a.p.a.a.a.E.a.a.7.i.s.E.7.V ", +" ,XT.XX| q.(.R } ~.8.E 8.(.I.Q Q [ (.(.(.Q (.| Q f.E | W.d.E E W | T.E 8.E T.9.9.9.T.| | Q Q Q [ f.Q *X-.Q g.8 j lXj uX0 j sXkXb yXb y.S.S.#XzXk.7 yX% b g # #XP U 1.I _ 2 U %.I 2 1.; +.% N I g ; g _ ` <.0 uXj b iX0 iX0 sXyXqXuXh.b ..iX8 0X6 8 uXj qXj yXl.;X2 ` I g 2X+.o +X[ [ R { [ p.Y R } 8.T.8.8.{ 7.s.0.s.{ p.p.[ p.[ { v.v.) E.a.a.E.a.E.i.E.i.7.7.s.7.] { 0. ", +" =.E E E ~.[ ~.(.| 8.~.| | T.E Q Q XXXXQ XX(.(.Q Q | E E Q q.Q d.| E | | | | | {.XXm.d.q.Q I.Q D q.q.I.W.| gXw q 7 t 0 uXzXqXj qXyXqX0XS.S.@XsXk.7 qX0 eXU 6X;XI 6X; g ; # 1.> # K 2XwXK N +.% ; % U r.% b uX7 yX8 yX0 qX0 yXk iXiXiXw qXj 0 y.7 0 j sXj sXqXj %.3 U P # 2 I > wX[ [ p.{ [ R } 8.^.I.9.T.8.8.T f.[ { p.{ { { p.{ Y { s.a.p.( ( P.e.n.E.a.E.7.s.p.*.{ { { ' ", +" A } 8.E E E E XXI.E | Q | Q f.Q ~.XXE E ~.(.Q E E E D | f.:.{.f.E q.q.f.Q d.| {.`.`.M. .{.Q q.Q {.Q f.f.E E xXt 0 iXj 0 0 qXqXuXiXsXyX0XcXk.@XyXk 8 uXyXK uX3XU 6X_ ` # ` %.> # F.I #.#XU I 1.; 1._ J <.j 7 j 0 qXqXqXuXqX0 yXyXl k.j l iXuXb 0 7 j sXsXuXkXqX6X6X_ 2 % U * I +.+.=.[ [ R 8.8.^.[ R 7.} *.R R 8.W 9.R Y T p.7.7.7.7.s.s.n.n.n.a.( s.n.p.s.{ s.7.7.7.*.{ { 0. ", +" X [ ~.^.E XX*XXX(.E f.q.q.W.`.q.Q XXXXI.XXQ XXI.Q Q {.{.q.q.q.f.W | {.-.Q.Q.9.T.XXm.M.M.W.W.*X{.Q d.f.E ~.(.(.gXsXw e e 0 uXsXj 0 k 8 k.h S.S.y.lXk.0 qXqX7 k.J 6X9Xg ;X% #X< g @X< U 6X= I K P <.r.r.1.6X6XqX7 yX7 lX7 qXqXj iXiXk k j e qXqXuX0 fXiXqX0 j j K 8 @X` U U g _ 2 5 +.Z W [ } ~.} 8.} 8.R R R R R [ R Y R { =.{ 7.Y p.p.{ s.{ { s.s.p.p.} 8.{ } S *.*.} { } { } Z ", +" A Q I.XXE *X*XXXI.f.).A.A.`.`.H.-.{.Q *XQ -.-.*X`.-.*X`._.q.| 9.E Q XX*Xm.d.9.| R.{ R.q.Q {.-.{.[ E E E E (.E J.fX7X0X8 qX0 qX0 j yX8 k J h.k.<.h.l 0 k.6XiXyXJ l.J @X` qX_ ` M P U b ;XI 6X` g 6X$.b % iX7 iX0 qXj qXuXj j j sXsXk.yXiXyXsX..0 8 j sXqXy.iX0 6X%.K % <.% U U - ; I V =.[ } ~.[ } E [ R } [ 8.R R p.{ T p.[ s.b.Z.W Z.Z.s.{ { { *.[ { } } [ 8.p.s.[ 8.9.{ [ p.S ", +" X E *X*XXXQ I.| Q q.W R.9.9.q.q.*X{.Q Q -.`.`.dXdX{. .A.q.q.f.Q | (.(.XX| | d.| T.9.[ R d.W E E ~.E (.(.I.E E | j.uXe k.0 j qXuXuXiX0 b iXJ k k.h lXk 8 k y.k.7 sXl.0 @XqX3X% qX$X2 eX6XP 0 6X# l.<.qX% qX0 qX6XqX8 k 6XiXqX0 j yXqXk.j iXw sXiXj uXsXj qX0 b qX@XK @X7 3X6X%.P #.U +.V T E E 8.8.[ ~.8.[ 8.~.W [ [ [ R [ p.W T Y n.n.n.p.{ } p.[ [ [ } [ } } R 8.8.9.p.8.9.n.[ } Z ", +" u.W.I.Q Q Q Q Q I.d.| XXXXXXQ q.*XW.`.-.-.`.dX .:.Y.H.m.R.f.| | (.~.(.E T.A.{.d.| 9.8.{ R ~.E ~.~.~.E ~.(.~.} ~.t.N.sXw k 6XlXb uXiX8 yXk J lXk.% S.yX8 qXj k h k 0 qX7 yXJ qXeX$.0 yXr.7 >X% 0 J 0 b 6XqX7 yX7 iXuXiXuXuXyX0 0 S.j S.0 iXiXqXiXuXj sXsXj sXuXb K eXr.@X@X6X1.K ` - 2 o c.W E ~.(.E | (.T.E f.T.f.E W W C.[ n.p.p.Y s.p.W W C.} } 9.9.p.[ p.[ 9.[ 8.{ } 8.R.} { { Y ", +" . D q.XXE | Q Q {.I.(.I.XX(.| XX(.I.dXY. .F `.`.q.`.W.f.E f.E | (.(.| | d.| Q.X.{.| 8.~.[ ~.E XXXXE (.(.Q (.| =.E D 7XJ J uXw 8 >X0 uXqXsXS.7 yXk.h S.qX0 qXyXl.y.iXb 7 sXb y.k.6X<.k eX<.yX@X7 eX% qX7 k 7 sX0 sX8 yX0 yX0 k 0 8 S.j S.6XiXiXiXiXj sXj qXsXuXl.g b K K J @XM r.` b _ U : wX~.T.| | I.I.(.E 9.8.9.E f.| | 8.C.[ s.W 9.n.C.[ W 9.p.s.{ [ R.d.^ b.p C.C.p.n.p.R.R p.} } ' ", +" Z D Q | (.~.f.[ Q {.(.(.^.T.^.~.~.XX(.I.`.dX-.{.9.E f.f.{.I.-.{.Q XX(.I.`.`.m. .m.d.| Q XXXXQ I.| Q *X*X(.~.E ~.D D G.k.e 6Xy j uXk 7 k 7 S.b zXk 6 cXeXuXb yX0 7 k j y.k.y.sXyXh sXk.K zXyX% l.J qX0 j qX7 yX7 yX7 k 8 iXj iXqX7 S.j cXuXiXl.yXsXuXj sXzXuXyXr.<.@X@XJ @XK 6XK >.g r.U !.wX| E Q E -.XX| | | 8.[ [ | Q d.T.T.9.p.| Q.Q.L.R.C.R.9.R.n.} R.d.| A.z.< i e.C.W C.{ [ 9.8.] ", +" ).Q XXXX{.8.~.E Q I.XXXXXX^.(.I.I.^.~.(.(.8.T.(.d.9.f.XXdX`.dXdX`.-.T.(.9.9.9.p.f.`.*X*X*XI.*XI.Q XXI.(.D ~.R D E D O.uXk k b j 8 sXl.uX8 iXyXj yX7 S.6XsXuXyX8 sXk.K iXl.y.k.6Xy.k.qX0 k @Xj b y.k 7 yXJ yXb j 7 iXuXiX0 yX0 sX8 S.qXcXb yXzXiXiX0 kX7 yXk k 6X0 @XK 1.<.K @X;X% >._ % . Z D I.I.*XdX-.{.I.f.9.W W {.XXI.| T.9.8.R.X.X.'./ C.C.C.9.d.R.R.{.Q.q.'.1 ,.z.) p D.{ [ 8.9.R C ", +" C | 9.8.R ~.(.^.(.| *XI.I.XX(.(.I.I.8.~.} E E E E E E Q Q -.I.`.`.*X{.| E E E f.W A.-.Q *X*X*X-.*XI.(.~.*XQ ~.E (.(.*XhXt 8 w k y e t iX6XqXuXS.0 iX8 S.7 yX6XyX8 yXsXy.h.7 j k.h j k.7 yXiXy.k 7 j b 0 yXy.k 7 yXJ k 7 yX8 h.6Xj 0 S.j cXqXyXj j ..uX0 y.7 lXj yX6X@XJ % J 6X1.r.# # ` g % Z.f.I.T.~.E | | | q.d.A.f.| | d.XXT.T.T.9.C.Q./ X.X.R.R.R.Q.R.Q.`.`.X.X.f.@.: ,.) b.n.p.8.9.9.&. ", +" +X(.E } ~.~.XXXX(.(.I.XXXXI.XXXXI.T.~.~.[ ~.E E ~.(.~.~.(.(.(.I.{.| f.9.E ~.E E | Q *X*XI.XXXX*XXXXX(.(.Q E E Q I.-.`.L l y 7Xt sXh.l.7 qXiX7 S.0 qX0 k.J k 6XlX6Xk 0 0 k.<.yXl.h k yX7 k.6XuXl.y.k J yX6X8 qX0 b j yX0 qXsXk.7 0 uXS.j cXsXiXuX0 sXuXj y.kXqX8 sXb K 1.$.K qX@X` - U # t & /.XX(.9.R R =.R Y [ 9.{ [ [ R | R.} 9.R.9.[ C.X.L.Q.R.L.d.R.R.| Q.^ .Q.A.p.b.@.@.e.[ L.R.R.9.{ . ", +" X =.E E D | Q *X*XI.(.(.(.^.XXXXI.Q E E ~.} ~.~.[ =.| (.~.XXXX(.~.E ~.E [ ~.Q ^.T.~.=.T Q XX~.(.*XXXXX(.(.(.*X*XQ *X*X`._.L h.k.iXt t yXy 7Xk.0 sX0 j j k 7 k.y.lX0 k K sXyX7 S.7 kXk.6XsXyXy.yX6Xj sX8 k J yX0 qXy.S.0 sX8 h.yX7 8 qXcXqXS.qXiXuX8 zX0 kXj yX0 0 8 yX6X6X% J qXb U ` O +.f +.f.{.| 8.=.8.[ [ 8.R [ [ 9.R [ 8.9.R 8.I.Q.R.p.a.[ 9.[ C.d.X.R.p.Q.W.H.d.| W [ W f.| C.R.R.9.C.R.&. ", +" ,XW.aXdX:.W.:.W.Q XX~.~.XX(.(.A.A.L.E E f.~.E E q.~.Q {.I.XXI.(.^.~.| XXE [ XX*XXXQ E W.Q *XI.*XdX*X*XI.(.(.XXXX*X-.*Xq.gX9 fXiXk.k.j 7 yX0 0 k 8 qXuXj yX7 S.J k 0 k 7 k 6Xj k.h yXyXJ h.j 7 k.y.yX0 iXqX7 k 8 uXj k.7 yX8 k.b kX7 yXS.qXcXiXsX0 0 ..8 uXj e qX6Xj qX7 6Xg J qXl.* # I : - o D -.`.I.f.d.d.| I.T.~.8.[ [ 9.| 9.} 8.R.9.W [ p.{ R p.9.C.Q.m.Q.{ p.R.9.T.T.T.| | 9.f.R.9.9.9.| Y ", +" @ J.N.J.xXM.W.-.Q | [ 8.(.(.| m.o.[.A.Q W.`.dX-.`.| Q I.XXd.| XXI.q.I.Q -.q.E Q I.E E W.Y. .dXq.:.dX*X-.W.*XXX*X:.:.q.j.t.w iXv 8 ..k.iXj S.7 iX8 qXuXsXyX8 S.7 k.8 k 7 k J lXl.y.S.6X7 S.J qXiX7 k 7 h.7 j qXj 7 h.qX7 yXfXk.7 qXy.k cXqXS.l j 0 0 j uX0 kXj w 0 0 j 7 eX_ 0Xb b $.1 I 3.4.C D q.W.C.f.W f.| XX| | 9.~.} W C.9.[ [ } } { } { { { *.} { } A.L.n.Z.9.8.T.T.T.T.| | | d.d.9.9.| [ . ", +" X t.H H G U.M.`.I.:.m.-.o.Q 9.f.q.A.D W.q.`.*XQ {.-.q.[ Q {.Q.dX-.dX`.W.*XdX-.-.f.f.).o.].^ & [.& O.X.W.dXdXdXdXY.U.F M._.f gXe k.l.t 7XuXiXS.>X7 iX0 j j >X8 k.7 k 7 k 0 k J S.0 8 k.h sXk.h yX7 sXqX0 k 7 yX0 sX8 S.J j j sXyXy.yXy.k cXj S.k.b 0 8 b iXv 7X0 <.J 0 8 0 b g g 7 6X% I I V o +.T [ s.C.W f.d.| d.I.| 8.} 8.} p.} } p.} 8.} *.} } } R { *.{ p.C.W p.R.| T.T.| } 8.W [ 9.| T.9.9.W Z ", +" O ;.H e w ! M.`.j.q.H.;.M.o.=.A.q.:.:.:.W.Q Q | (.Q q.C.Y :.:.`.q.| W.dXXXQ *XQ d.x.m 9 M >.n XF.%.& d :.H.aXF J.F G.v s f gXt w.k k.b t J 8 z y 0 uXuXj iX0 k.8 yX0 yXj yX8 S.J sXyX<.lXl.6 yXJ S.7 iXyXK yX0 8 sXyXh yX0 yXiXh k 7 h.cXb S.k.uX0 8 qXj j zXb ;.J 7 8 j b 1.g <.@Xg I > V g !.).9.[ R.f.Q `.I.*X{.| | R.R.} 8.R.} 8.8.9.8.8.8.p.8.9.} } } } [ { =.[ [ 8.8.[ [ 8.8.9.E ~.T.9.[ W +X ", +" 1 x.K.n ~ H.'._._.Y.U.e r o.V._.m.:.| A.d.W.Q {.{.m.d.W W j.q.W.`.*X*X*X^.E ~.f.Q [.g._.;.v M & >.M v r O.D `.F N.J.N.7Xh 6 kXiX0 uXw S.h.l t t yXy 0 uXj iXkXk.0 iXuXiXj iXuXk.<.lXeXy.S.0 7 yXy.k.J yXqX8 sXqXJ k 7 kXk.y.h.qXy.S.7 k.cX0 S.S.j 8 0 sX8 ..0 8 8 0 7 8 0 0 7 % ` $.U 3 > V wX4 A.| T.| XX(.| I.(.q.d.{.{.m.Q.R.9.9.9.9.9.} 9.8.9.9.9.R.8.8.8.9.[ [ } 8.7.S R R E E E 9.| d.9.=.Y Y ", +" s OX/ N ^ L.o.[.M.G k k y ~ C.q.[.q.f.f.D m.M._.m.Q.W [ f.f.W.dXY.-.Q | XX*X[ =.E {.q.m.[.].N x b e l e k H.-.-.W.F .f h gXj e k.y 0 b e S.S.qX7 w qXkXzXiX0 k j l.j qXsXqXsXiXy.S.6X8 S.7 j qX8 yXy.h.0 uXkXqX7 yX<.sXyXJ k.j y.k.6XS.cXb S.S.qX0 b j 0 j 7X7 0 8 7 7 0 0 6X` _ P 3 +.,.V . !.f.9.| I.(.XXI.I.Q W.F . . . .m.m.X.Q.R.R.8.R [ } 8.R.R.XXR.T.XXQ.C.9.9.R { R 9.8.8.8.~.T.8.[ | W [ C ", +" ( K.n K.^ / OXo.M.w.L e ~ / C.A.{.W.m.o.m H.m.{.{.{.`.| [ E Q *XdX-.Q *X`.dXf.V.E f.| Q Q.'.~ >.%.n [.;.L m.q.Q | q.o.jXy.hXiX0 G k.k.qXv j k h.>Xt e r j qX0 k uXqXj j iXuXyXb 8 S.J zXk.h iX0 uXl.7 h.6Xj b uXsXj uX8 iXh k qX7 S.7 S.cX8 S.h.j 7 iX7 l.8 8 j 0 8 7 8 8 0 6Xg _ I , ,.+.3.. 5 f.T.~.I.I.^.I.| f.{.`.`.-.M.H.m.{.C.f.{.9.R.8.9.8.R.| XXXX| I.d.{.| d.R.9.9.9.| E E 8.T.9.T.8.8.[ } ,X ", +" V = L.).Q.L.L.C.o.A. .w.r u ^ p.[ E q.m.].m 9 C.W | R.d.q.d.D Q D Q Q W.dXdXm.j.:.W.*X:.W E D ! 3Xn / a ~ m '.Q.A.D /.$ f fXyXyXiXv q k k.k.y b w h.e 6Xy q sXv k j y j j iXuXyX0 sXS.h yXk.h k 6XsXqX8 S.8 uXj 7 yX7 qXkXyXJ k qX8 k 8 cXS.8 cXk.j 7 yXy.h.t 0 sX8 0 7 8 8 0 @X_ 2 > > > +.+.O 1 D | T.(.XX(.(.^.9.| d.q.d.m.Q.Q.d.C.f.R.9.8.8.9.| XXXX| | XX{.d.{.R.{.| | T.9.9.| 9.[ W (.f.| E 8.8.c. ", +" Z W T p.T Z.b.).X.o.L.L.'.m.L.=.W Q.L.].^ N & u ].D.Q.A.Q.Q d.-.q.W.W.W.:.q.q.:.F g.dX .f.W q.M.K.u n c c n a m.q.W /.jX6 sXlXyX....r v y k S.l b uXk.e y y iXj e j e uXj e 0 S.7 yXk.h k k h h.7 lXb kXS.6X0 iX7 k 7 8 qXiX7 yXj 0 k 0 S.k.8 cXS.uX8 k 7 yXw t 8 uX7 8 7 8 uX@XU ; +.V 3.O O # +Xq.Q | 8.T.^.T.(.8.} R { { Y s.[ W f.[ 9.W W 9.T.{.*XXX| XXd.{.Q.| { { W T.| | 9.8.W E 8.~.8.E | Q | =.. ", +" p C.C.9.C.8.W [ R.p.p.{ [ p.8.[ } W m.u >.^ r =X-X$Xn D.T.| d.9.{ f.f.f.=.D Q W A.W E W.o.W d.X.9 y y l rXn a o.A./.x.6 fXlXh.lX~ :.w k l.r y h.k.e 9 yXk.q y j iXuXl uXy yX0 h.t lXk h h.yX0Xk.y.lXb 0 S.b kXk.J qX0 7 0 qX6XsXqX0 qXkXcXk.7 cXS.0 8 yXqX8 h.b 8 t 0 7 0 0 0 7 3 , > V 4.!.4 - +Xf.T.| ^.8.T.8.^.} *.{ { 9.} 8.9.[ | W W R.9.{.d.-.{.*X| R.{. .{.R.C.9.I.| I.I.8.} 8.E (.T.8.R f.d.{.E X ", +" . f K.m.{.d.W [ W p.n.b.7.{ [ { [ [ A.^ c >.X.L l e M >.Q.8.| W W =.V.=.T =.f.[ *.R S R [ | d.A.^ / oXoX9 '.i b.A.A./.6 7XsXh.h.w m.D M.w.k k.l =Xw k l v ..e r ..q uXe uXiXw 0 k 8 k yX0XS.l.7 k.7 h.qXkXS.qX8 k.0XqX0 8 qXqX0 j qXkXj uXcXk 7 cXS.uX0 sXh.J sXz 0 y 8 gX7 uX7 6XP > |.4.. o O I =.[ T.(.T.9.8.8.9.T.} { p.T.T.^.(.T.| T.9.E 9.| {.I.XXI.(.T.L.A.A.W W W 9.f.q.d.d.| d.XXT.(.(.9.d.q.m.q.,X ", +" X t ~ '.`.X.R.n.C.Z.a p.{ W C.p.9.A.K.3Xr rXoX>.L ~ K.X.d.| Q.| R 9.E [ [ { [ =.=.[ R { E | d.o./ ^ / OX^ b.b.Z.Z.f.j.f hXvXh.h.L C.| _.q L y e h.l y e e q ..q w.uXy ..j iXiX0 k.7 k yX7 h.uX0 k.7Xh.qXt cXl.7Xk y.qX8 qX8 kXqXuXqX0 qXuXcXyXy.cXcX0 qX8 S.y 7Xk v iX..uX7 8 6X7 3 > 4. 4.O 1 =.R (.8.T.8.~.9.T.T.R.p.} 9.(.T.T.^.T.~.| T.T.8.| R.9.T.T.8.R.C.} 8.8.8.9.d.d.{.{.`.I.I.| (.(.^.T.d.Q.m.< ", +" C ].H.{.Q.L.n.Z.p.[ { { R 8.C.{ a o.g.l.>.n K.'.X.R.f.| E 8.| d.| E ~.W f.[ [ [ R { W R p.8.9.Q.R.Q.L.C.L.V.C.f.Z.).j.7XlXk z e m.| | q.g.l e y =Xw k.h.l y r q ~ v ..uXiXw uXj e t yXe 7 S.t sXiXt h.l.7XS.e y.k t qX7 7 sX8 k 0 qX0 sX0 cXtX6 S.S.0 yX0XlXS.t gXw j 0Xj 0 7 7 <.3 : 4. o +X| 9.T.T.T.8.T.^.T.| 9.{ R.I.(.^.^.T.| 8.T.9.E W E W f.| [ [ 8.R.9.I.d.d.{.| W 9.R.{.{.q.d.| (.8.| XXR.X.u. ", +" o [ [ 9.W | [ 9.9.W [ [ } [ 9.C.f.L.m.m M.^ A.W W E d.d.| XX| (.9.E | {.[ W W [ R W { A.X.L.p.W f.].^ L.n.[ C.f.f./.t.zXlXz k ! q.d.f.[ Q L ..l k l r w y y w w L O.q v w j 0 y iX0 w k 7 k.t k 0 7XS.l.7Xh.l 0Xw 8 j 8 kXyX8 l 8 j uXiX8 cXk.h h.S.0 iX0 8 S.l f kXw 7 h v 7 y.% , |.V 4.+Xo.| d.| I.(.XXXXI.XXR.9.E d.XX8.(.T.^.T.^.T.T.| Q E f.f.R E E (.E | 8.8.| T.9.[ 9.T.XX(.XXXXXX^.(.9.| d.b. ", +" Z } W 9.9.[ 8.f.[ 8.[ R 8.E T.(.| | d.R.W W T [ [ 8.R f.Q Q 9.8.[ R E A.[ [ R b.=.f.W [ A.T T [ W A.d.W T R [ f.j.x.aXG e e L X.A.d.W W E g.e y y k l M L ......~ [.m.v ..0 b iXuXy j k.J h.t k b t S.w 0Xe h.t iXqXv t uX7 0 yX7 b uXyX8 S.S.h yXcXk 8 yXf k S.y f 8 uXs 7 7 6 r.2X2.: 4. X u.[.A.d.X.{.d.{.{.Q.d.W W | {.XX8.T.XX(.(.I.T.^.(.(.(.[ 9.| I.(.XX(.(.E 8.(.| 8.T.I.d.| T.XX(.(.(.(.^.8.8.c. ", +" &.[ [ W f.R.f.[ R [ [ [ E | (.~.^.(.E 8.S S *.R R R } f.[ 8.| (.8.R R =.=.=.b.[ =.T R.9.[ R 9.9.R W W W =.8.E | f.j.! U.G ! m.A.| 9.8.} R :.L e tXy y k l.q y w.Q.C.x.;.uX8 q j 0 e 0 h.K lX0 e q t S.>X0XsXS.c kXk t 0 j 0 j iX8 b 0 iX7 cXS.% hXcXcX0 yX0 8 S.S.r f oXuXf 7Xh r.3 |.|.4. V !.Z.A.C.A.A.C.X.Q.L.d.R.W | d.{.I.| XX| T.T.T.9.8.^.^.^.(.~.XXXXT.| | (.| | I.{.T.9.-.dX{.T.9.(.XXXX(.^.} [ S X ", +" c.[ W | I.| [ C.{ R Q (.| ~.E T.8.[ 8.} R *.=.*.R { =.8.[ E T.| 9.9.} Y R T S =.=.Y [ E [ E f.E f.~.~.[ ~.| | | f.:.g.;.U.m.f.C.{ R [ W E W.e ..y e e r r ..y m.[ ).j.t 9 ;.j v uXw 8 e b j w uXe 7 h.k 0XkXS.y 0Xk.9 uXt uXj j 0 j 8 yXy.S.cXy.y.cXcXl t iX6 ..S.S.y d t 8 h h K U |.|.2.|.o - C.f.n.R.R.8.R.d.R.d.d.| XXT.8.| T.8.T.T.9.*.} {.-.T.XX(.XXT.T.| I.| (.XXXXI.XX| I.(.| XXd.T.9.T.XXXXT.^.9.=.X ", +" c.T.9.| | d.R.9.R.f.Q.W 9.R } 9.9.R E 9.8.} 8.R } R } R R } } 8.9.[ =.{ W W R { { S [ [ [ W E E E E R [ ~.D ~.V.Q aXM.U. .| W T { [ E E q.D ..h.k y y w e w w.R.8.W ;.b 9 ;.v ;.y 0 j hXw 8 e t k 9 iXS.>.7Xz >Xf zXb t kX0 j j 0 sX7 k.7 S.S.6Xh sXcXcXk l b 0X..cXS.k d 7X7 0XqX%.> |.pX,.o +Xf.W f.| | | R.9.9.R.d.I.{.d.8.8.} } 9.{ R.R.n.T.d.| | T.T.^.| T.T.T.9.{.| {.d.I.d.I.d.R.9.| [ [ T.XXXXXX8.[ C ", +" c.| 8.9.8.T.d.XXd.m.C.S =.S T E I.q.{.f.E f.[ } 8.} } } } ~.} 8.} { Y c.A.| 9.R.T R [ R [ R =.[ [ 8.~.[ [ [ T E m.H.g.H.A.| f.W [ =.V.E [ :.8 v e k.l y q w ~ R.f.q.w v l.t d v v t ..7Xe 7 w t e qX7Xh.y 0XiXk J gX..d hXuXuXuX8 yXJ k y.h.S.yXh 7 cXcXcXcXS.j 0XhXh.S.k j qXK l.9X:X, .XpX4.!.T 9.9.T.| d.| T.R.9.9.9.d.I.d.E W W 9.).Q.R.d.R.Q.R.R.| 8.8.(.T.8.9.9. .m.d.W d.I.| T.9.R [ R T.T.XXI.I.| 8.' ", +" c.| 9.R.9.d.X.H.~ L.R [ Y =.E W d.| Q.A.-.-.{.T.[ ^.| 8.^.8.8.~.} } 9.[ | Q d.A.C.[ W [ T.8.[ ~.=.[ ~.[ ~.E [ f.t.M.H.R.W C.W Y [ V.| } R D G b v kXq y y w.M.| q._.d q uXe v m 7Xv v v v v 0 v gXe f ..e oXgXk J 0X..0X7X0 0 0 0 yXJ yXh lXcXS.J jXzXcXcXcXcXcXk t 9 w S.uX7Xy.l.Xl.9XF.}..XV +Xp f.d.9.R.9.W f.f.9.} E 9.[ 8.E [ E W W W [ A.9.9.d.R.Q.Q.d.| d.| | d.A.Q.Q | E f.| q. .f.A.d.| 8.8.R } E [ Z ", +" =.[ E R.L.C.p.{ V.Q.d.[ W [ f.W 8.} } [ R W C.C.R.9.[ E ~.E E W ~.W [ [ ).A.f.d.W 9.[ E ~.W [ f.E D Q Q ~.| f.:.`.{.9.~.8.E R [ { c.[ [ R ~.fXv w k k w q ~ A.[ o.gXy r q y 7Xt m m d d oX7Xt t 0Xt 0 t.b 0Xf 7Xv s 7X0X7 8 j 8 b uX0 uX0 7 S.cXk.J h $.gXiXS.S.cXS.S.w c v 7 J l.>XX>Xl.XrXF.F..X2.E.R 9.d.R.p.9.C.f.W Q Q Q I.`.`.{.8.9.E E f.W E T.(.XX8.| 8.W [ d.f.E E E E f.E | E Q.W ).Q.A.f.q.f.q.{.I.I.A ", +". { C.} [ S S Y Y R { { ~.T.[ [ 8.E 8.[ R { R W f.W =.[ =.{ 9.9.9.W Y [ [ 9.| | | [ ~.8.R } (.(.^.E 8.~.E ~.E ~.E 8.8.R 8.[ E 8.E [ W *.[ =.aX..y q v 0 L w m ).m r iXb j qX;.7XgXkX~ `.Q f.q.j.[.[.oXoXd d oXf & s s f f 8 uX0 v fXb uX7 j 7 j yXcXS.S.eXf s f j.f f oXK.O.7Xy.qXl e X'.Q.| | Q j.t v v b X* o.m.K.'.[.A.q.C.W f.(.Q (.Q (.XXE Q E XX(.(.(.*XsXv y.7X0 j t 7XoXt.[.m.| | Q.O.m m oXd m t 7XoX7Xa o.[.Q.-.d.R.W [ R [ f.f.f.A.Q {.| 9.9.C.C.D.T R.A.C.Z.Q.9.q.d.9.{ Y p.{ =.9.R | | 9.f.q.`.m.W A.q.f.R R 8.E (.(.^.} *. ", +" X .'.'.'.^ ]./ C.p.).Q.C.o.p ^ ]./ p p.0.Y Y Y u.wXb.D.[ 9.W A.A.W W p.T W =.9.8.d.| Q.R.9.C.Q.{ R { p.} } p.} 9.{ s.W W 9.9.[ W 9.9.Q I.d.f.O.uXe e m.Q Q q.f.V.gXj w l.$Xx [.H.9 K.oX].m.f.E Q Q I.I.XXE Q E Q q.q.W E | Q ;.uXe iXsXyXe ..;.t.q.| T.| D oXm m 7XoX7X8 q iXd Z.C.Q.Z.A.q.Q.C.f.9.W Q d.A.A.W.d.D.e.L.p.n.L.Z.d.C.C.f.W 9.f.9.[ [ 9.W W [ 8.[ R [ R [ W | A.V.o.q.m.I.8.~.(.(.XXXX(.A ", +" W.M.~ u ^ L.C.C.V.A.C.o.o.Q.o.^ L.C.{ Y =.R 8.C.A.a C.n.R [ [ [ W W =.8.~.9.9.9.W [ [ W d.n.C.Q.m.m.{.R.} 9.R.XXQ.d.W [ 9.9.E 9.R.[ d.d.W T t.G e e '.R.=.R W E t.m 0 w XOX[.X.].m.^ '.d.d.| f.W.I.(.XXI.| E [ q.d.[ I.I.Q U.y 8 t J 0Xf f 7Xd o.| XX[ /.oX7XO.oXt L j q q /.f.[ T A.R.{ [ W W Y [ W W E E -.].L.D.n.[ p.Q.Q.8.9.} } R [ } 8.} } R } 8.8.8.W R R ~.} [ E T [ V.d.d.| T.(.| {.| {.I.Z ", +" Z.^ m.^ L.^ n.f.d.X.o.A.W Q.C.D.W R [ 8.p.[ W W V.o.L.a b.b.).A.| C.[ (.| | | 9.d.[ d.C.W 9.A.X.H.m. .X.R.W q.m.d.C.[ [ f.W [ | E f.W W W =.aXv w e O.9.[ [ E 8.s v v b 3Xu Z.d.Q.q.Q.j.m.Q D f.| XX(.XXXXXX| [ [ E {.(.XXI.;.kX..e k e G uX7X[.E T.9.9.Q.t.t oX7Xt 8 v 0 m W 9.T.8.~.[ R [ =.R [ ~.[ | f.9.d.[.L.f.C.[ R [ | 9.R 8.8.9.8.T.T.^.^.^.T.(.T.| 8.8.9.E | 8.[ { [ { ).f.| T.8.E m.q.W.`.X ", +" !./.Q.Q.Q.].C.9.9.9.W T C.oXL.Z.W =.q.j.Q.^ ].n.b.( 5.< Y e.Y C.A.d.d.C.8.T.| E f.d.d.9.[ 9.W Z.Z.A.C.R.f.Z.A.Q.A.f.f.d.q.{.E `.| 8.[ T =.E :.sXe l.9 R.T.T.E ~.o.t y w l F.Z.| 8.f.).[ f.Q | E f.XX(.^.^.(.^.8.[ ~.I.XX*X`.F G y j q t 7Xt gXD | T.| (.| 0Xm 0X0X7Xv q q [.f.| (.(.XX| T.W [ 9.8.} [ 9.[ } } W [ E | | 9.T.| | f.Q I.T.I.{.-.XXXXI.T.(.| 9.| [ d.E q.I.8.[ 9.8.T.} [ =.c.f.A.A.b.Y ", +" X f.| | d.Q.d.W 8.8.[ Y T [.o.C.q.m.M.x.;.>.;XB.B.x - L.C.9.9.[ T f.A.Q.9.9.E | `.-.Q.| 9.| W R.[ W [ f.f.W d.| q.Q.m.o.Q Q A.W.| ).W W d.W.:.L y l ~ d.9.| d.XX*X..j j l.&Xp | 8.9.8.[ [ [ W R R 9.8.8.(.T.8.XXf.E | {.{.H.O.uXq w k e ..gXoXq.Q (.T.| d.7Xd f t.t y 0 t o.I.*XI.d.| I.C.8.8.R } T.T.E 8.8.[ [ f.| ~.8.T.8.(.f.d.`.`.8.*X`.-.I.-.*XXXT.XX| R.| q.f.q.Q d.9.8.[ 8.W [ 0.Z.Y b.Z.b.wX ", +" R E 9.W 8.| 8.T.9.[ Z.A.).A.A.j.m.m /.o.N N / u / p o.A.R.C.W [ [ f.R T W [ T [ (.T.| T.8.8.| W R W W W 8.| | :.H.:.A.d.E E E E [ W f.E I.:...k e r m.Q.Q.d.Q A.t.v y y 3Xp Q (.(.T.E E T p.B.p.W 9.[ Q `.{.:.Q :.f.Q.d.X.m.q w w q j j sXgXf.E | W E Q m gX0Xt uX8 uXO.V.E | {.9.W W W R } [ E | | XXT.| T.| d.9.| | E ^.E f.=.C.o.X.-.{.{.`.*XI.{.| | I.R.A.R.W f.W =.[ [ E [ R 9.W } { [ T [ X ", +" A | E f.| {.| } } R 8.R =.[ f.V.=.A.C.L.N L.[.A.[ R [ p.W [ Q.W W d.f.9.f.E E E E 8.[ I.8.=.E E =.=.9.} 8.E E f.Q Q Q | Q ~.(.| 8.E E f.d.W.q y w M ^ [.X.o.Q.f.O.uXy l $X; E XX| E | f.f.L.].].f.W E | Q aX:.*X-.m.R.L.[.Q.H.j q j q 0 7X;.A.8.E E Q q.v J t.v 8 w j ].W [ [ | W W W W [ W [ E E E (.T.T.d.| | | d.| W R W W T j.q.o. . .F Y. .`.-.-.T.d.W C.C.C.D.p.T f.| ~.8.} 8.f.9.E [ R [ ", +" C [ [ d.T A.d.C.[ f.9.} [ [ f.9.s.Y R p.Z.n.[ [ s.{ [ f.[ W f.q.| W V.W A.f.V.W {.9.XX*Xd.[ [ [ Y =.[ [ 8.~.~.E Q 8.f.E E Q XX*X{.| A.W q.:...e e rXC.C.L.o.o.o.[.uXq e l.N Z.[ E [ Y =.f.W f.m.Q.9.f.f.f.q.-.q.Q | f.q.H.m.t.q q G e e kX0XA.f.[ E W.d.gXd t t qX8 9 [.W E A.I.E | | 9.E E 8.8.~.~.~.^.(.| I.(.9.E Q | E 8.9.9.d.f.:.m.:.H._.H.m.Q.`.{.m.Q.A.'.N ].o.W R T.~.} ^.} T.d.q.8.T.+X ", +" T D V.o.D )./.s ^ C.p.{ [ W R.7.R 8.[ [ W C.Z.Y =.f.A.f.q.f.Q E f.f.E E f.E f.q.q.A.Q f.~.[ W [ R ~.E (.I.T.~.~.| E Q D Q dX{.d.{.o.f.o.W q w w c D.Z.T f.d.Q j.9 v e =XOXY [ c.W =.V.E { R [ 9.{ W f.d.:.q.Q.f.f.E | d.Q A.! y j uXb uXL D } E E D q.oXgXt uXuXb d T Q [ Q {.d.I.| 9.[ } } 8.T.T.T.^.(.XXXXXXT.^.(.(.XX{.| (.| 9.T D f.m.M.m. .H.{.{.X.L.].'.m.X.W R T.XX(.(.| T.} T.9.R.f.' ", +" I ].b.f.T _.t.[.q >.'.Q.R.A.A.W W 8.[ R T R b.=.a W W D W.q.d.T.T.T.T.T.E W f.q.A.E q.q.W./.f.f.E [ | ~.(.T.| } ~.E (.(.D dX`.-.m.[.b.T D q w l. Xp W T.8.| *XQ w.qXe l.u < E E 8.E [ [ =.[ [ W f.E E f.Q E f.E XXQ | XXT.| m uXkXL uX8 t o.9.9.E f.o.gX0Xj 0 v j * p.d.=.E {.{.*XXX9.{ [ W 9.| d.XXXXT.(.E XX| (.XX(.XXI.I.I.| | =.C.T ).f.D f.Q.d.R.D.C.C.{ W 8.T.9.I.I.XXXXXXXXT.XX| [ b.. ", +" o / = b.).D O.:.'.L.o.'.R.X.d.W W ).f.Y Z.C.[ { S c.R 9.E d.| d.T.| | ~.[ R E Q D f.f.o.o.W.f.=.E ~.} ^.R R R =.[ E (.E (.q.Q A.f.q.V.[ D w e y c p Q | XXE *Xo.;.b y y $X< (.(.(.8.~.E [ f.8.[ W [ T f.| I.Q I.{.{.XX| T.Q :...qXw e w fX[.9.d.C.f.x.7Xv j 0 b y * V.f.} | XXI.{.d.R.A.^ A.Q.X.Q.{.I.I.| E (.~.(.~.E ~.(.XXE 9.W C.f.[ T b.Z.W W d.9.R.C.L.f.d.`.{.XXI.*XI.XX*XXX| d.| [ ,X ", +" u.C./.o.D q.C.).W D.C.A.X.Q.W W /.A.C.W W A.R.W R [ R 9.W d.{.| XXd.Q c.=.R *.R =.=.=.[ R [ [ E T.^.~.} ~.~.~.[ E E ~.~.~.E f.[ f.W [ /...e l.4Xe.f.f.q.`.A.W v b w l.$X@.[ E (.8.} [ E I.8.[ W [ [ f.Q I.I.Q *Xf.Q | | | q.;.uXq v t 0 d C.A.L./.K.d ..8 y uX=X* a -.| | XX9.R.R.9.Q.X.X.Q.d.q.XXXXXXXX*XXXXX(.8.E ~.E | E E V.W [ C.W /.C.f.Q.`.A.f.W f.:.g.Y.:._.dXY.-.*X-.| d.o.o.C.. ", +" 4 d.A.9.W E | f.W p.@.u.V.f.f.o.o.1 /./.A.f.R C.[ [ } { [ f.f.| T.E f.E [ *.S R =.E W } [ [ | ~.(.(.XXT.(.T.8.} [ } R } [ [ ~.[ =.[ =.t.j y e 3XI T E E A.Q m.L y y =XF.2Xu.| d.| [ E f.:.A.q.f.W j.A.f.f.E E | f.Q XX{.-.`.v j q iXe y t L.b.n./ oXm 8 j q j v g b.q.I.{.XXR.T.R.9.R.d.W Q.| I.{.I.T.(.(.I.{.I.q.W =.E f.[ [ | R.W 9.R.C.A.d.| Q.C.W V.f.D `.g.g.N.M.`.F Y. .o._.m.o.u. ", +" c.=.[ [ R [ 9.[ W A S [ 9.9.[ { /.m.W.m.Y T C.[ { } S S E E E | 8.[ [ R c.R [ W [ E E (.XX(.| (.XX*XI.I.I.Q./ L.C.8.~.8.8.8.R ~.} } aXw qXqX=X5X- f.W W =.j.kXy y =XF.B b.Q.9.Q.C.)._.[.^ O._.[.:.f.f.E E Q D Q Q q.{.-.`.;.uXw j v j t L.a L.x.[.v t ..qXy c * @ q.d.`.-.{.9.d.R.W f.A.| Q Q `.I.XXXX| | d.f.j.Q.d.f.E E (.| | | T.[ E 9.Q.{.d.C.n.C.W W A.:. .F U.! ! H. .m.t._.o.4 ", +" 3.T *.8.[ [ 8.d.R./ W 9.W d.d.f.f.T /.q.W D q.f.R f.R [ Q | } ~.E } R } R R =.E f.(.8.~.~.~.I.E [ I.{.m.K.N N N x.o.| E (.8.} (.} ~.U.e e e l.& a =.[ W Y ).v iXqXl.>.* U a Y m.m.q.]./ & ].]./.o.Z.f.q.Q Q Q *X*XQ Q `.M.O.y j w iXb v ].x.Z.Z.j.;.qXuXq j eXN p ).A.| | d.f.W T f.W E f.f.q.| `.-.{.{.| A.d.W W d.XX| | T.^.[ | d.[ f.R.R.Q.A.X.X./ b.[ V.V.f._.H.M.o.f.).W ).o.Z. ", +" Y [ [ 9.8.9.q.m.'.L.L.f.m.q.q.f.f.E V.[ V.W E W E E E Q q.| | E f.~.E [ R ~.).W.q.W.{.*X-.*XE I.Q q.9 3XrXM %.K.W.I.(.| 9.E -.(.R aX..yXl iX%.p S R W T /.G e e iXr ;X; x.].o.j.[.oX].u ^ x.o.A.f.f.| Q | | | D f.f.q.:.t.zXw b v j v f Z.[ R.j.v j qXj q M ` ; C.C.[ [ 9.[ W | W E f.W R f.).R.m.W q.q.d.f.d.{.-.{.{.{.{.I.| 9.9.W W f.| | Q.C.A.C.p.W [ [ =.W T ).9.[ Y S =.c.C ", +" 4 W | d.-.f.`.Q.X.oX/ f.q.Q A.[ E ~.V.f.f.d.f.E E E V.f.{.D Q A.A.W Z.T V.W ).m.;.w.{.(.XX{.XX| [ W.N.k e k rXL.A.d.E f.Q.H.{.T.=.V.N.e e l.* 1 E R 8.[ ).;.iXe e l.%.< u.A.q./.X.X.].].x.L./.V.A.f.W Q Q Q E V.E V.f.E j.q y w qXL gX7Xf.R f.D w.b y qXuXr r.= C.C.A.R.9.W R.R.9.T.E E 9.f.[ T.(.f.W d.Q Q q.q.`.q.{.`. .M.`.d.f.f.W ).f.[ A.A.n.p.W W [ p.[ { 8.9.T 9.T [ Z.c. ", +" Z.f.A.f.p.o./ A.A.A.E I.I.I.Q d.A.E f.D q.q.A.f.E E E D f./.o.o.'.[.^ L.n 9 O.j.O.:.-.XXd.q.d.9.H.G.h.q S.k K.A.).W V.A.f.E 9.Y [ W.sXiXeX_ ,.V.~.[ | T [...y y y F.P < V.A.f.f.f.f.L.W W C.0.f.E Q W.`.Q q.A.f.D q.q.t...iXqXj b g f A.R.E /.g.iXb y y b N = p.W Q.A.p.Z.9.R.9.9.9.T.8.E Q T.E T.| I.d.d.d.f./.q.Q q.Y. .`.R.A.A.A.| [ T W T A.C.).R.C.[ 9.R.[ { { W C.d.C.C ", +" X A.j.f.L.a C.C.W 9.=.Q Q {.E 9.[ [ [ f.D m.q.q.I.Q Q I.:.'.o.d ^ ;Xu OXN oX=Xy ! m ~ :.E [ q.A.O.z h.h.k q X.C.W W p [ b.T /.D o.Q.kXe yX3XP T f.E d.W V.q.;.j iXrX%.` x.d.| W V.d.C.p.T =.W W f.Q Q d.q.Q.d.A.).Q {._...l.e y b x - f [ E f.L w y y y j u i f.9.[ A.Q.T.9.| R.n.9.| f.[ R 8.f.I.I.d.f.f.A.).W ).f.W 9.f.W A.X.'.m.X.W W f.{ R W A.d.[ C.W R.C.W C.d.f.d.+X ", +" u.A.a V.o.Q.q.[ E [ f.[ } f.Z.W p.[ R E f.).D q. .`.`.q.m.q.oX^ n u & * ^ t 9 ;.w.G m.D f.V.W j.J.w c [.[.X./.].X.f.C.V.W.H.m.K.m.m z k.k.>X% o.| d.W C.f./.kXe l.6X@X1.x.W f.E f.q.d.Z.[ 8.f.I.f.f.W Y Q.R.C.R.f.D ;.w w qXy q r.1 1 T =.~.;.q y y qXr & a d.9.R.Q.9.[ W p.C.C.d.d.d.E [ E E | | {.| q.d.d.d.f.| E | [ T [ X.'.! H.[.'.Q.b.=.Z.9.W W W A.f.f.W {.d.| 9.X ", +" o ).].j.Q.q.q.| 8.9.T.[ W X./ L.A.R 8.E | E A.W.j.q.`.M.m.X.X.x.X.A.C.L.a ].[.[.j.g.:.A.f.E Q f.o.'.x 1 D o.]./.m./.A.D H.M.w...M.;.h.cXcXS.l.x.W.m.q.q.q.D g.k l eX@X% - +XQ Q Q Q Q I.f.E E E A.o.x.].K.m.Z.W c.).;.w iXk sXb $X= +.T W W aXq l.y e r n Q.Q.d.d.C.a Q.a L.C.W o.A.8.~.E f.E E f.Q f.d.j.f.| d.XXQ Q [ W =.).f.'.m.].X.X.o.Q.f.d.[ W { A.[ 9.E {.Q q.c. ", +" wX].x.Z.f.-.H.A.Q.A.L.'.oX9 K.'.`.d.(.| Q q.W A.V.).[.o.f.Z.R W f.E W [ f.T f.Q.q.f.W q.Q Q f.~.D A.n.p V.W T Q.X./.:.xXH e k w.w h.S.k.yXqX>.x.W.H.:.H.m.O.z yX3X&X,.2.!.A.f.f.[ f.E Q {.d.f.D a / x.].m.Q.n.Y D ;.k iXw y qX6X_ = T E } Q ..y e l.w 9 A.{.q.d.Q.X.L.n.b.a { p.{ [ R.8.[ } ~.~.R T ).f.9.=.W | f.Q (.| [ ~.[ ).W ).a X.).C.[.d.[ [ [ p.T [ [ R E V.. ", +" . p ].L.A.d.x.C.C.L.L.^ u ^ o.m.{.R.W 9.d.X.W f.[ T f.f.o.o.C.Z.W | Q f.Q.f.A.f.9.o.d.d.d.j.Q A.A.f.).W [ [.D j.[.F m M.U.G.e w H h.yXiXyXe l._. .! ! xXH.N.k w r M N :Xz.f.| D f.W =.V.:.A.Q.X.oXoXL.W C.9.C.n.Y gXw iXy iXy r * = o.[ E f.! y y e y ^ C.A.W.m.o.A.W C.b.n.[ b.C.f.m.| E [ } [ R =.[ } [ [ [ ~.~.Q | | E 8.8.[ [ A.o.o.f.).q.f.c.0.{ { c.R R [ =.' ", +" 4 o.X.L.f.f.f.A.m./ / / oXA.Q.Q.R.p.p.C.R.W f.f.C.).:.w.w y oXo.o.q. . .m.X.Q.f.W.`.W.Q.Q.q.m.:.W.[.[.;.J.! hXJ.N.G G.N.G U.N.G k e w.lXk w L H.U.F H._.F U...y l.%X( , /.R.).A.A.b.Z.b.V.q.m.d ^ R.9.A.L./ L.L.0Xe e e iXy M _ i A.9.| d.m ~ r y r N o.C.a L.V.f.9.W n.A.o.W ).f.f.o.f.[ [ [ T { { W [ 8.T.[ E Q | W Y =.R R R W /.C.C.T V.T c.Y [ =.9.E [ 8.A ", +" . u.C.f.f.E R.d.m.m ^ ].a V.R.R.L.D.p.n.A.C.q.x.hXO.L H z k e q ! M.N.G.G ..J.M.O.m.[.O.L ~ w.w.w.w H lXlXG U.aXN.U.;.xXxX_.g.xXN.U.N.w lXG m g.'.Q.f.W.q. .H.J.~ K./ i o.q.A.q.I.A.A.A.f.q.X.oXX.q. .~ d m.9 =Xl.e l iXw l.y F.L.| | q.{.m y y w M = L.p Y b.{ W W R { =.Y [ [ { b.V.Q.A.R.R.C.T d.Q.| T.^.^.T.8.E [ C.p.S S S R R.W W Y { p.Y T A.C.d.T.| f.C ", +" C f.f.W R C.C.p /.A.f.C.W W C.A.Q.m.m._.H.w.e H e H H H H H H e G.H H vXH H k k H w lXz h.z z k vXz e G F H.-.W.q.D -.-.D W.D A.D W.xXM.O.j.H.m Q.q.W.W E f.d.Q {.f.f.A.d.{.`.Q I.| Q f.f.d.A.Q.q.A.t.w.~ w k k e H l l e e >.R.R.[ f.9.j.m v c u p b.[ Z.W [ R [ W [ [ 8.R =.9.f.E f.f.X.X.m.D.f.f.| T.8.8.| | (.8.[ f.T.} } R *.{ p.T { R p.T { [ 8.8.[ &. ", +" wXA.[.o.[.s x./ j.[.:.q.f.q.m.:.M.U.G H z z H h.h.k H H H H G.H vXvXH z k z z z h.bXh.h.z z H z H G xXq.d.W.K.L.{.{.I.q.f.f.Q f.Q :.q.`.j.q.m.q.:.W.Q f.d.E f.Y R W [ E E f.(.(.E f.E f.f.[ A.d.A._.O.~ ! w.U.;.e e e e w u W f.D.W | o.t v w c p V.A.C.X.Q.9.[ } 9.d.f.9.f.Q.| d.{.Q.a A.Q.W [ 8.8.} } } } E (.(.| | T.8.T.T.T.[ ] Y W f.R.R.[ { 8.R c. ", +" $ G G G e G ..G G w.'.Q.{.H.! G.H vXz h.h.k.S.S.S.h.H H vXz vXvXH H k k k H H z h.h.h.H w H k H g.`.{.d.:.~ Q.q.| *X{.XXQ A.[ E E f.).f.D q.q.q.d.| Q Q E f.[ W E 8.E ~.| E T.T.9.[ | R.9.R.f.A.T V.O.m.A.[.j.! w w e M C.C.o.o.d.Q [.q b M K 1 p.C.f.[ | d.R f.W d.X.L.L.[.Q.W A.W C.p.{ } 8.9.} *.^.^.^.^.^.T.T.9.[ 8.8.T.{.d.[ S p.S { R.R.Q.R b.X ", +" X hXz bXh.z z H z H ..m O.! H h.h.S.S.cXcXS.S.S.k.H h.h.z z z h.h.h.h.h.h.H H H H H z z e 8 m '.o.m.W.m.X.m.Q.q.{.{.q.d.W f.f.V.j.A.W | Q | Q W E } R [ Y Y T f.f.8.8.8.T.| 8.8.[ [ R.C.f.W W [ { b.C.V.W [ f.:...w y m X.I.I.R.f.W A.oXb .. XL.W } W =.[ T W [ E Q.m.u * & / f.C.9.{ 9.} 9.(.T.T.8.9.} T.XX(.| 9.[ [ f.W E T.{.{.9.f.n.[ C.L.o._.C ", +" + G bXh.z z z z z z k e z h.cXcXcXcXcXcXcXS.S.h.h.cXh.h.k.k.h.S.k.S.S.h.z H H H H G.H G N.O.].m.L./.oXL.A.A./.q.m.Q D q.f.Q.Q.q.q.| XX| f.| R.[ p.W W A./.'.o.C.=.8.8.[ 8.[ [ 9.W [ f.C.W R.W C.C.V.9.[ E | d.uXq y & | | | T.| d./.;.v b c i | R.[ [ 9.| 9.R W Q.q.X.N N / a f.d.| I.T.T.(.T.R.| | 9.8.T.d.[ f.{.d.E (.T.} W Q.C.f._.X.V.[.q.+X ", +" 1XH z z H h.z h.h.bXS.cXcXcXcXcXS.cXcXcXcXS.h.bXS.h.S.h.k h.S.S.bXh.S.h.z vXH vXG.N.j.f.o.j.[.[.o.X.A.A.A.f.).A.q.D f.{.Y.X.Q.-.-.q.| f.f.-.C.].:.o.X.j.O.t.'.p p.Y *.8.{ { R 9.C.A.Q.W f.i C.Z.C.A.A.Q.{.Q.g.j b a W XXT.8.~.(.A.0Xc b q & d.m.X.A.d.m.Q.C.9.| Q.]./ N oXa f.Q E d.XXXX| | ^.| 9.} E | d.R f.| E | | f.R [ W. .j.m.[.C.A.T ", +" $ H H H H z h.h.h.h.S.S.cXcXh.h.z S.S.cXS.S.cXS.h.S.h.h.h.S.S.h.bXbXz bXz H vXH g.j.O.q.f.Z./.o.q.q.A.j.Q.f.q.D W f.I.{.{.d.m.'.'.q.W.`.M.[.L ~ g.m._.;.`.[.o.W f.[ 9.9.C.9.R.R.R.C.Z.C.A.o.X.K.Q.C.q.m. .;.b r N T f.d.W R } W v ;.0 r a C.m._.H.A.Q.X.R.R.f.A.]./ N / N X.d.f.T.I.I.XXXX(.T.8.[ 8.8.W [ f.[ ~.E E E E =.d.:.q.f.D { b.X ", +" X 6 H H H H h.bXbXcXh.h.h.z z z z z cXcXcXcXcXh.S.h.S.h.cXh.h.z h.h.h.h.z vXvXH G G M._.o.o.:.[.q._.'.H.o.:.W.o.q.-.{.I.m.Q._._.m.q.q. .xXH G U.m q.q.m.R.W =.f.W C.A.C.X.Q.m.d.f.9.9.f.f.f.f.m.d.W d.f.q.gX..y * ].O.m.d.A.d.o.f t b 3X* p C.x./ a L.A.C.W W | C.Q.X./ oXm.{.I.d.XX(.| { T.8.T.| (.I.(.| 8.[ | E E 8.[ [ E Q f.W W c.X ", +" X gXvXH H H z h.h.h.z z H z h.z h.bXcXcXh.S.h.h.h.S.bXh.z z z h.cXbXbXz z z z vXvXH G G G G w.w.J.M.m.:.q.o.m.Q :.{.| W [ W T.f.f.V.W._.N.N.O.oXo.).W 9.9.W | E [ 9.W W f.{.| T [ 9.9.9.d.| f.9.R A.9.f.:...b & x._.R.R.A.W [.t v c r N & u ^ ].].o.L.L.n.f.d.XX| R.A.X.o.A.T.{.| T.T.T.T.XX| | ~.*XI.I.I.XX| 8.9.[ E 8.[ V.[ [ E C ", +" 4 8 vXvXH z z z z h.h.bXh.bXh.h.cXh.cXcXcXS.k.z z z z H z z z bXcXh.z cXh.h.z z z z h.h.z z H H H G `.`.q.W.q.-.*Xf.| f.| | d.E T E q.D W.m.X.o./ s.T 9.| | | T.[ [ T [ D A.| f.[ d.d.q.I.{.{.Q {.d.| W.q b 1.b.d.d.R.f.[ o.v 8 y y ;Xx.'.m.X.A.^ ^ K.u i C.I.| R.W ).d.d.9.T.8.T.T.T.8.T.(.XX(.E Q XXQ Q Q R [ E [ [ E Q [ [ Z ", +" 4 hXz vXvXvXz lXh.h.h.h.z bXcXbXS.cXS.cXz z h.lXz z z H z z z bXcXbXcXcXbXz z z bXbXz vXH z z H H G w.! xXF xX`.-.q.E f.E I.| W W 9.f.W T W m.K.x 1 A.q.f.| | 9.E f.E | | Q q.D m.`.`.{.`. .d.{.d.| W.j v u p f.d.XXd.f.[.8 b 3XM OX- ).R.f.R.Q./.`.{.X.q.| | | 9.W d.d.f.T.~.T.T.T.~.} ~.~.~.E T.Q ~.E f.[ V.~.f.D Q | E ,X ", +" + G H H H z bXz vXz vXH z z z bXbXcXcXh.H z h.h.z z H H vXz bXbXbXbXbXbXbXh.z z z H vXH H z z H H H G.G.G.N.xXF :.A.Q {.Q d.d.d.Q.W A.].K.M. .^ n.Z.D Q d.| | q.Q | {.Q Q q. .o.H.m.q.d.Q.{.X.R.d.q.L r ;XT f.d.XX| q.! b eXqX3Xr.= b.E | | T f.q.| T.Q | T.^.E E Q Q | T.| | E ~.} } E ~.(.^.^.(.} 8.~.E =.[ Q W Q Q +X ", +" 5 sXvXH H H vXvXvXvXvXH H vXh.bXbXh.vXz z h.h.k z lXz z vXz z vXz bXvXz z z z z H z z H vXz z H H H H H H G.G xXH. .`.-.Q.Q. . .q.`.W.L -.{.q.q.R.W A.E f.W E | | | | E | q.o._.m.X.q.Q.X.A.A.Q.f.y b N u.Q.I.T.9.| ;.q l.y l.%.` V.d.| (.| E 8.XXT.(.(.(.(.^.Q (.I.Q Q | XXXXE [ ~.(.^.(.XX^.^.} } ~.E [ [ ~.V.E c. ", +" + fXH vXvXG.vXvXH H vXvXH vXz bXz z z bXbXz z vXbXvXz z z z vXz h.z H z z H z z z vXvXH vXH vXH G.H vXvXvXH G.N.g.Y.H.`.d.[ :.m.Q.T `. . .A.W.{.f.A.).f.W | I.T.f.d.Q.f.A.W V.A.q.Q.o.'.oXq.Q.t.uXM * 1 d.{.d.| Q :.w l.e iX=X& V.T.(.(.| f.Q XXXX(.XXI.(.XX*X(.(.Q | Q Q Q ~.E ~.T.^.^.XXI.T.T.~.~.(.~.=.~.(.,X ", +" 4 fXvXH vXvXz z z bXz H z bXz bXbXbXh.bXh.z z bXz z bXvXbXz bXh.z h.z H z H vXz H z H G.vXvXvXz vXz z z z z G.G G G J.'.q. .Y.Q.W f.[ W f.A.W [ f.T W f.Q d.| A.A.d.d.R.W W W T A.o.X.'.X.Q.m q b OX,.E q.`.`.{.Y.g.w.y r uX` 1 Q | I.(.(.XX-.*XXX*X-.XXXX*X*XI.Q *X{.| E E I.(.(.XXXX(.XXXXXX(.T.XX8.} [ ,X ", +" X fXvXz vXvXh.bXh.z z bXz z bXz bXbXcXbXbXz bXz bXbXvXbXz z bXz z z z H z vXvXH vXvXvXG.vXvXz z z z bXz z vXH vXH G N.F xXF d.q.d.d.d.[ Z.[ R { ).d.d.q.q.f.R.R.| {.A.A.A.9.{ =.C.p f.f.A.g.qXl.%X,.+XA.`.H.! U.H. .L b b r.I W | I.I.XXI.XX*X*X-.dX*XXXXX-.`.*XI.dXq.E E Q Q I.I.XX8.^.(.XXI.| E E [ ,X ", +" X y.vXvXvXbXz bXz bXvXvXbXz z bXbXbXh.h.z bXz z z bXbXvXbXz bXbXbXh.z z z vXH H H z vXH vXvXvXvXvXbXz bXz H z z z H G.G.F I.{.I.{.{.f.W W 9.p.| | | f.9.f.d.f.f.W A.! Q.o.u.Y b.Z.f.9.).w.qXl.$XB < x.X.H.w.J.! M.~ j j %._ 2 ).(.-.I.I.| `.-.dXxXF xX-.Q -.-.Q :.o.j.q.q.:. .d.T.I.XX^.XXI.| T.[ Z ", +" X jXvXvXvXz vXz vXz vXz z bXbXbXbXbXbXz bXbXbXbXbXbXbXbXbXbXbXbXbXz bXz z z h.h.h.z vXH vXG.H vXbXz bXh.z bXz bXz z G.dX*X`.*XXXXXW 9.R.f.| f.| d.| Q | Q m.{.q.Q.M.X./ ].o.V./.[ [ D q w iX3X` ; / N K.[.m :.U.;...y 0 r.g = ).dX`.*X`.W.W.`.g.U.G :.H.M.m.`.`.M.O.~ ~ w.H.A.f.8.(.(.I.-.I.~.' ", +" jXG.H bXbXz bXz bXz vXz z bXbXcXcXz bXbXbXbXbXbXbXcXbXbXz z bXbXbXbXS.cXbXcXcXS.h.bXz H H H H vXH z z bXz z z vXG.F `.-.XXXX(.| [ | Q q.f.Q I.| d.9.| f.q.W.A.o.M.Q.[.o.o.f.b.V.).J.k yX=X1.= d u u L.[.o._.g.k yX6XJ % # = j.-.-.`.Y.M.U.aX_.aXt.aXG ..M.`.M.~ '.~ L 9 [.'.q.*X| (.{.E X ", +" 5 fXbXbXbXbXz bXz z z z z bXcXcXbXz bXbXbXh.z bXbXbXz z z cXbXcXbXcXcXS.S.S.S.cXbXh.h.z vXH H H vXbXz bXbXz H J.F Y.F -.-.(.XX| | {.Q -.-.-.{.`.Q f.f.f.Z.Z.=.`.-.W =.q.A.W.).j.aXiXe b _ wX[.'.O._.o./.:.k h.l.b @Xr._ - p A.Q :.W._.xX;._.t.;.:.J.G M.H.m O.K.d 9 M M m m.d.XX~.A . ", +" C gXz bXbXbXbXz bXbXz h.cXS.cXh.h.bXbXh.z z bXbXbXz bXcXcXcXcXcXbXcXh.S.h.h.h.cXcXh.z z z z bXbXbXbXbXbXz G.xXxXJ.xXY.-.I.d.XX| Q *XW.`.*X{.`.m.V.V.{ [ [ A.m.Q.Q. .M.M.g.! M.O.w.iX#XP I j. .M._.m.W.gXe lXk e qX4Xu B Y W Q W.f.D j.[.:.q.aXW. . .-.q.L M.'.v q ! ..m M.:.d.,X ", +" X jXH bXbXbXbXbXbXbXbXh.bXh.bXbXbXh.bXz z vXvXvXz cXbXcXbXcXcXcXcXcXcXS.h.S.h.S.h.h.h.z z h.bXbXcXbXz z J.q.dXY.dX{.-.m.d.{.{.q.W. .`.A. .`.:.A.f.A./.]. .M.M.! N.G H G.G H N.q w #XU +.j.H.J.J. .! U.H k w w w r u N L.| XXQ f.A.V.E ).~.| E V.f.A.d.dX .m._.F H.M.q.A.T Z ", +" 5 G z bXbXz z z bXz z h.h.bXz z z vXz vXvXvXvXbXbXbXcXcXcXcXcXcXcXcXh.S.h.h.h.h.h.h.z bXS.bXbXbXh.H U.U.F Y.M.H.O.L m.`.F F :.M._.H. .q.Q.f.j.[.a [.M...e G.H G.z k U.G.J.! sX@X_ I ).:.dX:.dXJ.U.G.H J.w.! ~ oX/ W E } ~.E ).[ V.V.f.f.E R [ ~.Q | Q V.D W.`.:.A.u.X ", +" . jXN.z z bXz vXH H H vXh.h.z z H vXH H vXvXz bXcXcXcXcXcXcXS.h.z lXh.z z h.h.h.z z z bXh.h.bXh.N. .:.q.q.m.m.H.K.[.t.~ m ! N.G G g.m [.O.m ! w.N.G G.G.J.J.xXJ.H Y.`.-.N.r <.$ U #.D Q Q ~.I.-.dXdXY.`.{.{.X.Q.f.[ | E ~.E W Y b.D d.Q f.D :.Q f.E V.W D f.=.' ", +" 5 hXvXvXH z z vXH vXvXbXvXH H vXH vXvXz bXbXbXcXcXcXcXcXh.z z H z z z z h.h.z lXlXz z vXz H U.H.Y.H.;.m oXr ~ 9 w.H lXH vXH vXH G w.N.U.N.N.U.N.J.N. .:.q._.F `.`. .M.t.& & g 2 @ q.| XXI.Q d.-.-.I.I.{.d.{.Q.A.o.Q.q.).H.D T [ Q D A.f.Q D E [ W f.W u.X ", +" X jXG H z z z z H vXvXz H H vXvXlXvXvXvXbXbXbXcXcXcXcXbXz bXbXh.z h.h.z vXz vXvXH vXH H H .._._.g.w.r v k y w H k z z vXH G.G G.G.U.J.J.Y.W.dXdXY.`.q.f.Q W.`.-.`._.m.j.[.# ( < D Q XXd.| f.E {.{.XX{.q.Q./.a /.L _.o.q.V.=.S ).f.f.E =.R E E E V.,X ", +" + fXH H H vXz z vXvXz bXvXz vXz vXvXz bXbXcXcXcXcXh.h.bXcXbXz bXz z z z vXlXvXG.vXvXe M.[.9 ~ '.m G z k h.z z z z z H G.U.xXvXF dXdX*X{.| Q *X*Xq.Q E E | | E Q -.q.m.f.x @.A.{.I.Q f.9.f.W f.d.W { D s e./.t.b.).W.[.f.T =.[ V.[ R V.| [ +X ", +" X @ hXH H H vXvXvXz z vXvXvXz z vXvXvXbXz bXbXh.h.z z h.z H z vXH H z z vXvXvXH H H ..q ;.G oXd t lXz z z H bXvXz H J.F :.dX-.I.XX{.-.{.q.Q Q Q | {.`.-.| 9.{.I.{.d.9.9.v.[ Q I.E | W E =.Y ).W v././.[ Z.b.p V.o.q.q.).f.W f.A.E E V.Z ", +" 4 jXN.H H vXH vXvXz z bXz z z vXvXvXvXlXlXH lXlXH z z vXH vXH H vXz H z H z vXH H z H w q q w H H z z H z G.N.J.W.q.Q Q Q (.I.-.-.*X{.{.d.f.Q.| Q.-.{.I.{.| I.I.XX9.8.T.| ~.E E =.[ Y V.[ W b.{ b.Z.p a L.a o.[.[.^ K._.O.g.j.,X. ", +" 4 y.G.vXvXvXvXvXvXvXbXz vXvXvXz H z H lXe lXlXz z z z z vXH vXz vXbXz z bXbXz z h.z H H H H k h.z H H U.W.E E f.W.Q I.I.8.| *XY.`.d.A.d.Q.X.R.m.X.d.Q XX*XI.I.XXXX| | | f.f.b.Y D [ W 9.f.Z.p.=.v.o.L.L.C.o.K.K.9 ;.7X@ X ", +" 5 y.G.vXvXvXvXvXz bXz bXbXcXbXh.k k z z h.h.cXbXh.bXh.bXz vXz z z bXz bXbXbXbXz z z z H H H H H G. .Q E Q I.Q W.`. .`.`.Y.-.{.m.M.'.Q.'.X.m.X.{.W.q.I.I.-.I.I.| d.f.V.T u.A.f.Y [ E Q f.p.b.W 9.d.C.C.Q.'.m d - X ", +" . + 6 zXH z z bXbXbXh.cXcXS.h.S.h.S.h.S.h.z h.bXh.bXbXh.vXvXvXz vXbXz bXbXh.z z z z z H G.U.J.F q.{.I.| E D W.:. .Y.*XY.m.[.H.g.~ m.X.m.'.X.q.:.`.*X-.`.I.| [ ).Q A.A.T o.9.[ E [ W f.[ [ | R.d.R.9.C.).I X ", +" + jXG.z bXcXbXh.bXcXcXS.cXcXcXS.S.z h.h.z z bXbXbXz vXz z bXvXbXvXz z vXH vXvXG.N.xXF `.d.W f.Q ).A.D q.q.W. .f.q.*XW.:.-.`.Q.{.m.m.H. ._.! :.F dX*X| Q q.Q | A.[ {.| T.d.8.| | Q.d.I.I.d.Q.{ ,X. ", +" X @ fXvXz z H z h.bXcXcXcXcXS.h.h.h.z vXvXvXH bXbXbXvXvXvXvXG.G.z H vXvXU.`.`.-.*X| Q (.| | Q o.d.d.W f.8.XXd.~.Q W.q. .8.d.X.Q.X.H. .xX:.q.`.`.W.q.f.Q | E R } (.E f.q.W Q 9.8.[ f.c.Z ", +" X 5 6 sXvXvXz vXz z lXz bXz h.bXvXz z z H vXz z vXvXvXH N.N.G.H G.U.xX-.Q Q Q E 9.9.d.| 9.[ [ [ R Q XXXX| | | D W.f.[ W Q.{.Q.{.Q.`.H.q.:.m.q.q.{.Q Q ~.[ | E =.E f.E [ f.+X,XX ", +" 4 $ hXH H z lXz vXlXlXlXlXlXh.h.h.z G.H vXvXG.G.F F xXF F F `.W.Q E f.Q | W 8.| f.R [ ~.=.*.E | {.{.f.E Q D .C.R.R.X.-.d.d.d. .:.A.q.q. .q.Q I.XXE (.E 9.[ f.E u.' . ", +" + $ kXlXlXz z vXz z lXbXbXz z z G.G.G.xXF `.*X-.*X*XXXD Q W.f.D Q I.Q {.E f.d.| W ~.[ R ~.T.[ c.E W | q.f.Q.R.8.d.| | W Q.d.A.Q.A.q.*XW.{.XXQ | Q | =.,XX ", +" X 4 1XgXzXvXz vXlXvXvXz vXz H G.G Y.W.Q E (.~.E | f.Q V.~.E *X*XXX| d.8.E [ R =.R R 8.[ [ =.| T.| E A.m.A.A.W T f.d.W d.f.q.d.f.| {.{.| [ 8X,XX ", +" . 4 8XjXfXN.lXlXH vXlXH G.g.{.| E f.[ c.T Q Q Q V.D XXQ Q *XI.Q Q f.d.[ R 8.[ ^.} R { E T.| | A.q.Q q.A.W | f.q.E T.{.Q f.T T A ' X ", +" 4 5 jXgXzXH N.! `.I.| d.Q E [ D | f.I.E XX^.^.*X{.E W D `.M.q.f.d.| | 9.} T.XXI.| ~.[ A.| Q Q Q | V.E | V.=.A C . ", +" X 4 5 u.V.C.| | | T.8.(.E | Q I.-.| XXXXI.f.A.Q.f.f.q.| W.-.-.d.XX| XXI.| 9.[ E V.~.~.).8XA Z X ", +" X X ' Z A A Y =.V.=.T E Q (.(.`.q.q.j.:.f.f.| q.d.| E | 8.V.f.).,XwX,XZ X X X ", +" X X X C ' ' + wXwXwXO Z Z 4 ,X' C X X X . " +}; diff --git a/demo/bmp_source/saveperspective.png b/demo/bmp_source/saveperspective.png new file mode 100644 index 00000000..8d8bd6fe Binary files /dev/null and b/demo/bmp_source/saveperspective.png differ diff --git a/demo/bmp_source/sm_down.bmp b/demo/bmp_source/sm_down.bmp new file mode 100644 index 00000000..df9e6243 Binary files /dev/null and b/demo/bmp_source/sm_down.bmp differ diff --git a/demo/bmp_source/sm_up.bmp b/demo/bmp_source/sm_up.bmp new file mode 100644 index 00000000..8935c9f4 Binary files /dev/null and b/demo/bmp_source/sm_up.bmp differ diff --git a/demo/bmp_source/smiles2.bmp b/demo/bmp_source/smiles2.bmp new file mode 100644 index 00000000..30317321 Binary files /dev/null and b/demo/bmp_source/smiles2.bmp differ diff --git a/demo/bmp_source/test2.bmp b/demo/bmp_source/test2.bmp new file mode 100644 index 00000000..6f57c102 Binary files /dev/null and b/demo/bmp_source/test2.bmp differ diff --git a/demo/bmp_source/testmask.bmp b/demo/bmp_source/testmask.bmp new file mode 100644 index 00000000..f0810f84 Binary files /dev/null and b/demo/bmp_source/testmask.bmp differ diff --git a/demo/bmp_source/teststar.png b/demo/bmp_source/teststar.png new file mode 100644 index 00000000..0d746b5b Binary files /dev/null and b/demo/bmp_source/teststar.png differ diff --git a/demo/bmp_source/thekid.png b/demo/bmp_source/thekid.png new file mode 100644 index 00000000..652da99a Binary files /dev/null and b/demo/bmp_source/thekid.png differ diff --git a/demo/bmp_source/tog1.bmp b/demo/bmp_source/tog1.bmp new file mode 100644 index 00000000..75f6e7c4 Binary files /dev/null and b/demo/bmp_source/tog1.bmp differ diff --git a/demo/bmp_source/tog2.bmp b/demo/bmp_source/tog2.bmp new file mode 100644 index 00000000..f7f924c1 Binary files /dev/null and b/demo/bmp_source/tog2.bmp differ diff --git a/demo/bmp_source/wiztest1.bmp b/demo/bmp_source/wiztest1.bmp new file mode 100644 index 00000000..912ea371 Binary files /dev/null and b/demo/bmp_source/wiztest1.bmp differ diff --git a/demo/bmp_source/wiztest2.bmp b/demo/bmp_source/wiztest2.bmp new file mode 100644 index 00000000..9e7858d8 Binary files /dev/null and b/demo/bmp_source/wiztest2.bmp differ diff --git a/demo/bmp_source/wxpdemo.ico b/demo/bmp_source/wxpdemo.ico new file mode 100644 index 00000000..3ed4f08c Binary files /dev/null and b/demo/bmp_source/wxpdemo.ico differ diff --git a/demo/data/Asteroid_blaster.swf b/demo/data/Asteroid_blaster.swf new file mode 100644 index 00000000..ffc57312 Binary files /dev/null and b/demo/data/Asteroid_blaster.swf differ diff --git a/demo/data/anykey.wav b/demo/data/anykey.wav new file mode 100644 index 00000000..fa323b6e Binary files /dev/null and b/demo/data/anykey.wav differ diff --git a/demo/data/echo.py b/demo/data/echo.py new file mode 100644 index 00000000..0b3ea581 --- /dev/null +++ b/demo/data/echo.py @@ -0,0 +1,25 @@ + + +""" +This is a simple little echo program that is used by the wxProcess +demo. It reads lines from stdin and echos them back to stdout, until +there is an EOF on stdin. + +Enter text in the field below to send to the stdin of the echo +process. Clicking on 'Close Stream' will close the stream in the +demo, and then echo.py should terminate too... +""" + +import sys + +sys.stdout.write( __doc__) +sys.stdout.flush() + +line = sys.stdin.readline() +while line: + line = line[:-1] + sys.stdout.write('\nYou typed "%s"\n' % line) + line = sys.stdin.readline() + + +sys.stdout.write('\nExiting...\n') diff --git a/demo/data/imagemap.htm b/demo/data/imagemap.htm new file mode 100644 index 00000000..edebd33b --- /dev/null +++ b/demo/data/imagemap.htm @@ -0,0 +1,20 @@ + + +ImageMap Test + + + + +This is test. + + + + + + + + + + + + diff --git a/demo/data/imagemap.png b/demo/data/imagemap.png new file mode 100644 index 00000000..2307eaed Binary files /dev/null and b/demo/data/imagemap.png differ diff --git a/demo/data/locale-src/af.po b/demo/data/locale-src/af.po new file mode 100644 index 00000000..afad30dd --- /dev/null +++ b/demo/data/locale-src/af.po @@ -0,0 +1,23 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: wxPython i18n demo\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-12-01 09:52-0800\n" +"PO-Revision-Date: 2006-12-01 11:11-0800\n" +"Last-Translator: Robin Dunn \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Afrikaans\n" +"X-Poedit-Country: SOUTH AFRICA\n" + +#: I18N.py:9 +msgid "the quick brown fox jumps over the lazy dog" +msgstr "die vinnige bruin vos spring oor die lui hond" + diff --git a/demo/data/locale-src/de.po b/demo/data/locale-src/de.po new file mode 100644 index 00000000..d88cec2d --- /dev/null +++ b/demo/data/locale-src/de.po @@ -0,0 +1,23 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: wxPython i18n demo\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-12-01 09:52-0800\n" +"PO-Revision-Date: 2006-12-01 11:16-0800\n" +"Last-Translator: Robin Dunn \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: German\n" +"X-Poedit-Country: GERMANY\n" + +#: I18N.py:9 +msgid "the quick brown fox jumps over the lazy dog" +msgstr "der schnelle braune Fuchs sprang über den faulen Hund" + diff --git a/demo/data/locale-src/es.po b/demo/data/locale-src/es.po new file mode 100644 index 00000000..06cb92ce --- /dev/null +++ b/demo/data/locale-src/es.po @@ -0,0 +1,22 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: wxPython i18n demo\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-12-01 09:52-0800\n" +"PO-Revision-Date: 2006-12-01 11:25-0800\n" +"Last-Translator: Robin Dunn \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Spanish\n" + +#: I18N.py:9 +msgid "the quick brown fox jumps over the lazy dog" +msgstr "el zorro marrón rápido saltó sobre el perro perezoso" + diff --git a/demo/data/locale-src/fr.po b/demo/data/locale-src/fr.po new file mode 100644 index 00000000..b99578a6 --- /dev/null +++ b/demo/data/locale-src/fr.po @@ -0,0 +1,22 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: wxPython i18n demo\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-12-01 09:52-0800\n" +"PO-Revision-Date: 2006-12-01 11:14-0800\n" +"Last-Translator: Robin Dunn \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: French\n" + +#: I18N.py:9 +msgid "the quick brown fox jumps over the lazy dog" +msgstr "le renard brun rapide a sauté par-dessus le chien paresseux" + diff --git a/demo/data/locale-src/install b/demo/data/locale-src/install new file mode 100755 index 00000000..ee95d102 --- /dev/null +++ b/demo/data/locale-src/install @@ -0,0 +1,15 @@ +#!/bin/bash +#---------------------------------------------------------------------- +# Run msgfmt on all the .po files, and install them to ../locale +#---------------------------------------------------------------------- + +DEST=../locale +NAME=wxpydemo + +for po in ??.po ??_??.po; do + echo compiling message catalog for $po + BASE=`basename $po .po` + mkdir -p $DEST/$BASE/LC_MESSAGES + msgfmt -o $DEST/$BASE/LC_MESSAGES/$NAME.mo $po +done + diff --git a/demo/data/locale-src/it.po b/demo/data/locale-src/it.po new file mode 100644 index 00000000..dfc31aec --- /dev/null +++ b/demo/data/locale-src/it.po @@ -0,0 +1,23 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: wxPython i18n demo\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-12-01 09:52-0800\n" +"PO-Revision-Date: 2006-12-01 11:17-0800\n" +"Last-Translator: Robin Dunn \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Italian\n" +"X-Poedit-Country: ITALY\n" + +#: I18N.py:9 +msgid "the quick brown fox jumps over the lazy dog" +msgstr "la volpe marrone rapida ha saltato sopra il cane pigro" + diff --git a/demo/data/locale-src/wxpydemo.po b/demo/data/locale-src/wxpydemo.po new file mode 100644 index 00000000..dc6a4551 --- /dev/null +++ b/demo/data/locale-src/wxpydemo.po @@ -0,0 +1,21 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +msgid "" +msgstr "" +"Project-Id-Version: wxPython i18n demo\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2006-12-01 09:52-0800\n" +"PO-Revision-Date: 2006-12-01 11:08-0800\n" +"Last-Translator: Robin Dunn \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: I18N.py:9 +msgid "the quick brown fox jumps over the lazy dog" +msgstr "" + diff --git a/demo/data/locale/af/LC_MESSAGES/wxpydemo.mo b/demo/data/locale/af/LC_MESSAGES/wxpydemo.mo new file mode 100644 index 00000000..baeda6a5 Binary files /dev/null and b/demo/data/locale/af/LC_MESSAGES/wxpydemo.mo differ diff --git a/demo/data/locale/de/LC_MESSAGES/wxpydemo.mo b/demo/data/locale/de/LC_MESSAGES/wxpydemo.mo new file mode 100644 index 00000000..34db3ac5 Binary files /dev/null and b/demo/data/locale/de/LC_MESSAGES/wxpydemo.mo differ diff --git a/demo/data/locale/es/LC_MESSAGES/wxpydemo.mo b/demo/data/locale/es/LC_MESSAGES/wxpydemo.mo new file mode 100644 index 00000000..e0d4cc20 Binary files /dev/null and b/demo/data/locale/es/LC_MESSAGES/wxpydemo.mo differ diff --git a/demo/data/locale/fr/LC_MESSAGES/wxpydemo.mo b/demo/data/locale/fr/LC_MESSAGES/wxpydemo.mo new file mode 100644 index 00000000..b8e77346 Binary files /dev/null and b/demo/data/locale/fr/LC_MESSAGES/wxpydemo.mo differ diff --git a/demo/data/locale/it/LC_MESSAGES/wxpydemo.mo b/demo/data/locale/it/LC_MESSAGES/wxpydemo.mo new file mode 100644 index 00000000..7d4066e7 Binary files /dev/null and b/demo/data/locale/it/LC_MESSAGES/wxpydemo.mo differ diff --git a/demo/data/pic.png b/demo/data/pic.png new file mode 100644 index 00000000..8f6d4bc2 Binary files /dev/null and b/demo/data/pic.png differ diff --git a/demo/data/pic2.bmp b/demo/data/pic2.bmp new file mode 100644 index 00000000..23ebd0cf Binary files /dev/null and b/demo/data/pic2.bmp differ diff --git a/demo/data/plan.wav b/demo/data/plan.wav new file mode 100644 index 00000000..c76cb231 Binary files /dev/null and b/demo/data/plan.wav differ diff --git a/demo/data/proclamation.txt b/demo/data/proclamation.txt new file mode 100644 index 00000000..5d305e49 --- /dev/null +++ b/demo/data/proclamation.txt @@ -0,0 +1,115 @@ +EMANCIPATION PROCLAMATION: +By the President of the United States of America: +A PROCLAMATION + + Whereas on the 22nd day of September, A.D. 1862, a proclamation +was issued by the President of the United States, containing, +among other things, the following, to wit: + + "That on the 1st day of January, A.D. 1863, all persons held as +slaves within any State or designated part of a State the people +whereof shall then be in rebellion against the United States shall +be then, thenceforward, and forever free; and the executive +government of the United States, including the military and naval +authority thereof, will recognize and maintain the freedom of such +persons and will do no act or acts to repress such persons, or any +of them, in any efforts they may make for their actual freedom. + + "That the executive will on the 1st day of January aforesaid, +by proclamation, designate the States and parts of States, if any, +in which the people thereof, respectively, shall then be in +rebellion against the United States; and the fact that any State +or the people thereof shall on that day be in good faith +represented in the Congress of the United States by members +chosen thereto at elections wherein a majority of the qualified +voters of such States shall have participated shall, in the +absence of strong countervailing testimony, be deemed conclusive +evidence that such State and the people thereof are not then +in rebellion against the United States." + + Now, therefore, I, Abraham Lincoln, President of the United +States, by virtue of the power in me vested as Commander-In-Chief +of the Army and Navy of the United States in time of actual armed +rebellion against the authority and government of the United States, +and as a fit and necessary war measure for supressing said +rebellion, do, on this 1st day of January, A.D. 1863, and in +accordance with my purpose so to do, publicly proclaimed for the +full period of one hundred days from the first day above mentioned, +order and designate as the States and parts of States wherein the +people thereof, respectively, are this day in rebellion against +the United States the following, to wit: + + Arkansas, Texas, Louisiana (except the parishes of St. Bernard, +Palquemines, Jefferson, St. John, St. Charles, St. James, Ascension, +Assumption, Terrebone, Lafourche, St. Mary, St. Martin, and Orleans, +including the city of New Orleans), Mississippi, Alabama, Florida, +Georgia, South Carolina, North Carolina, and Virginia (except the +forty-eight counties designated as West Virginia, and also the +counties of Berkeley, Accomac, Morthhampton, Elizabeth City, York, +Princess Anne, and Norfolk, including the cities of Norfolk and +Portsmouth), and which excepted parts are for the present left +precisely as if this proclamation were not issued. + + And by virtue of the power and for the purpose aforesaid, I do +order and declare that all persons held as slaves within said +designated States and parts of States are, and henceforward shall +be, free; and that the Executive Government of the United States, +including the military and naval authorities thereof, will +recognize and maintain the freedom of said persons. + + And I hereby enjoin upon the people so declared to be free to +abstain from all violence, unless in necessary self-defence; and +I recommend to them that, in all case when allowed, they labor +faithfully for reasonable wages. + + And I further declare and make known that such persons of +suitable condition will be received into the armed service of +the United States to garrison forts, positions, stations, and +other places, and to man vessels of all sorts in said service. + + And upon this act, sincerely believed to be an act of justice, +warranted by the Constitution upon military necessity, I invoke +the considerate judgment of mankind and the gracious favor +of Almighty God. + +(signed) +ABRAHAM LINCOLN +------------------------------------- + +On Jan. 1, 1863, U.S. President Abraham Lincoln declared free +all slaves residing in territory in rebellion against the federal +government. This Emancipation Proclamation actually freed few +people. It did not apply to slaves in border states fighting on +the Union side; nor did it affect slaves in southern areas already +under Union control. Naturally, the states in rebellion did not +act on Lincoln's order. But the proclamation did show Americans-- +and the world--that the civil war was now being fought to end slavery. + +Lincoln had been reluctant to come to this position. A believer +in white supremacy, he initially viewed the war only in terms of +preserving the Union. As pressure for abolition mounted in +Congress and the country, however, Lincoln became more sympathetic +to the idea. On Sept. 22, 1862, he issued a preliminary proclamation +announcing that emancipation would become effective on Jan. 1, 1863, +in those states still in rebellion. Although the Emancipation +Proclamation did not end slavery in America--this was achieved +by the passage of the 13TH Amendment to the Constitution on Dec. +18, 1865--it did make that accomplishment a basic war goal and +a virtual certainty. + +DOUGLAS T. MILLER + +Bibliography: Commager, Henry Steele, The Great Proclamation +(1960); Donovan, Frank, Mr. Lincoln's Proclamation (1964); +Franklin, John Hope, ed., The Emancipation Proclamation (1964). + +------------------------------------- + +Prepared by Gerald Murphy (The Cleveland Free-Net - aa300) +Distributed by the Cybercasting Services Division of the + National Public Telecomputing Network (NPTN). + +Permission is hereby granted to download, reprint, and/or otherwise + redistribute this file, provided appropriate point of origin + credit is given to the preparer(s) and the National Public + Telecomputing Network. diff --git a/demo/data/resource.wdr b/demo/data/resource.wdr new file mode 100644 index 00000000..55d91a64 Binary files /dev/null and b/demo/data/resource.wdr differ diff --git a/demo/data/resource_wdr.xrc b/demo/data/resource_wdr.xrc new file mode 100644 index 00000000..354bb669 --- /dev/null +++ b/demo/data/resource_wdr.xrc @@ -0,0 +1,146 @@ + + + + + 0 + 0 + + 0,0 + 4,1 + + 2 + 0 + 0 + 0 + + wxTOP|wxLEFT|wxRIGHT|wxALL|wxALIGN_RIGHT|wxALIGN_CENTRE_VERTICAL + 5 + + + + + + wxTOP|wxLEFT|wxRIGHT|wxEXPAND|wxGROW|wxALIGN_CENTRE_VERTICAL + 5 + + 100,-1 + + + + + wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP + 5 + + + + + + wxGROW|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP + 5 + + 100,-1 + + + + + 20,20 + + + wxGROW|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP + 5 + + 100,-1 + + + + + wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP + 5 + + + + + + wxGROW|wxALIGN_CENTER_VERTICAL + 5 + + wxHORIZONTAL + + wxALIGN_CENTRE|wxLEFT|wxTOP + 5 + + 100,-1 + + + + + wxALIGN_CENTRE|wxLEFT|wxTOP + 5 + + 30,-1 + + + + + wxALIGN_CENTRE|wxLEFT|wxRIGHT|wxTOP + 5 + + 50,-1 + + + + + + + wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + + + + wxGROW|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP + 5 + + 100,-1 + + + + + wxALIGN_RIGHT|wxALIGN_CENTER_VERTICAL|wxALL + 5 + + + + + + wxGROW|wxALIGN_CENTER_VERTICAL|wxLEFT|wxRIGHT|wxTOP + 5 + + 100,-1 + + + + + + + wxALIGN_CENTRE|wxALL + 5 + 20,20 + 0,1 + + + 1,2 + + + + + + 2,2 + + + + + + + \ No newline at end of file diff --git a/demo/data/romedalen.png b/demo/data/romedalen.png new file mode 100644 index 00000000..0c41eb0c Binary files /dev/null and b/demo/data/romedalen.png differ diff --git a/demo/data/stc.h.html b/demo/data/stc.h.html new file mode 100644 index 00000000..ca9e58e3 --- /dev/null +++ b/demo/data/stc.h.html @@ -0,0 +1,3544 @@ + + +/home/work/projects/wx2.7/contrib/include/wx/stc/stc.h.html + + + + +

    +////////////////////////////////////////////////////////////////////////////
    +// Name:        stc.h
    +// Purpose:     A wxWidgets implementation of Scintilla.  This class is the
    +//              one meant to be used directly by wx applications.  It does not
    +//              derive directly from the Scintilla classes, and in fact there
    +//              is no mention of Scintilla classes at all in this header.
    +//              This class delegates all method calls and events to the
    +//              Scintilla objects and so forth.  This allows the use of
    +//              Scintilla without polluting the namespace with all the
    +//              classes and itentifiers from Scintilla.
    +//
    +// Author:      Robin Dunn
    +//
    +// Created:     13-Jan-2000
    +// RCS-ID:      $Id$
    +// Copyright:   (c) 2000 by Total Control Software
    +// Licence:     wxWindows license
    +/////////////////////////////////////////////////////////////////////////////
    +
    +#ifndef __stc_h__
    +#define __stc_h__
    +
    +
    +#include "wx/wx.h"
    +#include "wx/dnd.h"
    +
    +
    +#ifdef WXMAKINGDLL_STC
    +    #define WXDLLIMPEXP_STC WXEXPORT
    +#elif defined(WXUSINGDLL)
    +    #define WXDLLIMPEXP_STC WXIMPORT
    +#else // not making nor using DLL
    +    #define WXDLLIMPEXP_STC
    +#endif
    +
    +
    +// SWIG can't handle "#if" type of conditionals, only "#ifdef"
    +#ifdef SWIG
    +#define STC_USE_DND 1
    +#else
    +#if wxUSE_DRAG_AND_DROP
    +#define STC_USE_DND 1
    +#endif
    +#endif
    +
    +//----------------------------------------------------------------------
    +
    +// Should a wxPopupWindow be used for the call tips and autocomplete windows?
    +#ifndef wxSTC_USE_POPUP
    +#define wxSTC_USE_POPUP 1
    +#endif
    +
    +//----------------------------------------------------------------------
    +// BEGIN generated section.  The following code is automatically generated
    +//       by gen_iface.py.  Do not edit this file.  Edit stc.h.in instead
    +//       and regenerate
    +
    +#define wxSTC_INVALID_POSITION -1
    +
    +// Define start of Scintilla messages to be greater than all Windows edit (EM_*) messages
    +// as many EM_ messages can be used although that use is deprecated.
    +#define wxSTC_START 2000
    +#define wxSTC_OPTIONAL_START 3000
    +#define wxSTC_LEXER_START 4000
    +#define wxSTC_WS_INVISIBLE 0
    +#define wxSTC_WS_VISIBLEALWAYS 1
    +#define wxSTC_WS_VISIBLEAFTERINDENT 2
    +#define wxSTC_EOL_CRLF 0
    +#define wxSTC_EOL_CR 1
    +#define wxSTC_EOL_LF 2
    +
    +// The SC_CP_UTF8 value can be used to enter Unicode mode.
    +// This is the same value as CP_UTF8 in Windows
    +#define wxSTC_CP_UTF8 65001
    +
    +// The SC_CP_DBCS value can be used to indicate a DBCS mode for GTK+.
    +#define wxSTC_CP_DBCS 1
    +#define wxSTC_MARKER_MAX 31
    +#define wxSTC_MARK_CIRCLE 0
    +#define wxSTC_MARK_ROUNDRECT 1
    +#define wxSTC_MARK_ARROW 2
    +#define wxSTC_MARK_SMALLRECT 3
    +#define wxSTC_MARK_SHORTARROW 4
    +#define wxSTC_MARK_EMPTY 5
    +#define wxSTC_MARK_ARROWDOWN 6
    +#define wxSTC_MARK_MINUS 7
    +#define wxSTC_MARK_PLUS 8
    +
    +// Shapes used for outlining column.
    +#define wxSTC_MARK_VLINE 9
    +#define wxSTC_MARK_LCORNER 10
    +#define wxSTC_MARK_TCORNER 11
    +#define wxSTC_MARK_BOXPLUS 12
    +#define wxSTC_MARK_BOXPLUSCONNECTED 13
    +#define wxSTC_MARK_BOXMINUS 14
    +#define wxSTC_MARK_BOXMINUSCONNECTED 15
    +#define wxSTC_MARK_LCORNERCURVE 16
    +#define wxSTC_MARK_TCORNERCURVE 17
    +#define wxSTC_MARK_CIRCLEPLUS 18
    +#define wxSTC_MARK_CIRCLEPLUSCONNECTED 19
    +#define wxSTC_MARK_CIRCLEMINUS 20
    +#define wxSTC_MARK_CIRCLEMINUSCONNECTED 21
    +
    +// Invisible mark that only sets the line background color.
    +#define wxSTC_MARK_BACKGROUND 22
    +#define wxSTC_MARK_DOTDOTDOT 23
    +#define wxSTC_MARK_ARROWS 24
    +#define wxSTC_MARK_PIXMAP 25
    +#define wxSTC_MARK_FULLRECT 26
    +#define wxSTC_MARK_CHARACTER 10000
    +
    +// Markers used for outlining column.
    +#define wxSTC_MARKNUM_FOLDEREND 25
    +#define wxSTC_MARKNUM_FOLDEROPENMID 26
    +#define wxSTC_MARKNUM_FOLDERMIDTAIL 27
    +#define wxSTC_MARKNUM_FOLDERTAIL 28
    +#define wxSTC_MARKNUM_FOLDERSUB 29
    +#define wxSTC_MARKNUM_FOLDER 30
    +#define wxSTC_MARKNUM_FOLDEROPEN 31
    +#define wxSTC_MASK_FOLDERS 0xFE000000
    +#define wxSTC_MARGIN_SYMBOL 0
    +#define wxSTC_MARGIN_NUMBER 1
    +
    +// Styles in range 32..37 are predefined for parts of the UI and are not used as normal styles.
    +// Styles 38 and 39 are for future use.
    +#define wxSTC_STYLE_DEFAULT 32
    +#define wxSTC_STYLE_LINENUMBER 33
    +#define wxSTC_STYLE_BRACELIGHT 34
    +#define wxSTC_STYLE_BRACEBAD 35
    +#define wxSTC_STYLE_CONTROLCHAR 36
    +#define wxSTC_STYLE_INDENTGUIDE 37
    +#define wxSTC_STYLE_LASTPREDEFINED 39
    +#define wxSTC_STYLE_MAX 127
    +
    +// Character set identifiers are used in StyleSetCharacterSet.
    +// The values are the same as the Windows *_CHARSET values.
    +#define wxSTC_CHARSET_ANSI 0
    +#define wxSTC_CHARSET_DEFAULT 1
    +#define wxSTC_CHARSET_BALTIC 186
    +#define wxSTC_CHARSET_CHINESEBIG5 136
    +#define wxSTC_CHARSET_EASTEUROPE 238
    +#define wxSTC_CHARSET_GB2312 134
    +#define wxSTC_CHARSET_GREEK 161
    +#define wxSTC_CHARSET_HANGUL 129
    +#define wxSTC_CHARSET_MAC 77
    +#define wxSTC_CHARSET_OEM 255
    +#define wxSTC_CHARSET_RUSSIAN 204
    +#define wxSTC_CHARSET_CYRILLIC 1251
    +#define wxSTC_CHARSET_SHIFTJIS 128
    +#define wxSTC_CHARSET_SYMBOL 2
    +#define wxSTC_CHARSET_TURKISH 162
    +#define wxSTC_CHARSET_JOHAB 130
    +#define wxSTC_CHARSET_HEBREW 177
    +#define wxSTC_CHARSET_ARABIC 178
    +#define wxSTC_CHARSET_VIETNAMESE 163
    +#define wxSTC_CHARSET_THAI 222
    +#define wxSTC_CHARSET_8859_15 1000
    +#define wxSTC_CASE_MIXED 0
    +#define wxSTC_CASE_UPPER 1
    +#define wxSTC_CASE_LOWER 2
    +#define wxSTC_INDIC_MAX 7
    +#define wxSTC_INDIC_PLAIN 0
    +#define wxSTC_INDIC_SQUIGGLE 1
    +#define wxSTC_INDIC_TT 2
    +#define wxSTC_INDIC_DIAGONAL 3
    +#define wxSTC_INDIC_STRIKE 4
    +#define wxSTC_INDIC_HIDDEN 5
    +#define wxSTC_INDIC_BOX 6
    +#define wxSTC_INDIC0_MASK 0x20
    +#define wxSTC_INDIC1_MASK 0x40
    +#define wxSTC_INDIC2_MASK 0x80
    +#define wxSTC_INDICS_MASK 0xE0
    +
    +// PrintColourMode - use same colours as screen.
    +#define wxSTC_PRINT_NORMAL 0
    +
    +// PrintColourMode - invert the light value of each style for printing.
    +#define wxSTC_PRINT_INVERTLIGHT 1
    +
    +// PrintColourMode - force black text on white background for printing.
    +#define wxSTC_PRINT_BLACKONWHITE 2
    +
    +// PrintColourMode - text stays coloured, but all background is forced to be white for printing.
    +#define wxSTC_PRINT_COLOURONWHITE 3
    +
    +// PrintColourMode - only the default-background is forced to be white for printing.
    +#define wxSTC_PRINT_COLOURONWHITEDEFAULTBG 4
    +#define wxSTC_FIND_WHOLEWORD 2
    +#define wxSTC_FIND_MATCHCASE 4
    +#define wxSTC_FIND_WORDSTART 0x00100000
    +#define wxSTC_FIND_REGEXP 0x00200000
    +#define wxSTC_FIND_POSIX 0x00400000
    +#define wxSTC_FOLDLEVELBASE 0x400
    +#define wxSTC_FOLDLEVELWHITEFLAG 0x1000
    +#define wxSTC_FOLDLEVELHEADERFLAG 0x2000
    +#define wxSTC_FOLDLEVELBOXHEADERFLAG 0x4000
    +#define wxSTC_FOLDLEVELBOXFOOTERFLAG 0x8000
    +#define wxSTC_FOLDLEVELCONTRACTED 0x10000
    +#define wxSTC_FOLDLEVELUNINDENT 0x20000
    +#define wxSTC_FOLDLEVELNUMBERMASK 0x0FFF
    +#define wxSTC_FOLDFLAG_LINEBEFORE_EXPANDED 0x0002
    +#define wxSTC_FOLDFLAG_LINEBEFORE_CONTRACTED 0x0004
    +#define wxSTC_FOLDFLAG_LINEAFTER_EXPANDED 0x0008
    +#define wxSTC_FOLDFLAG_LINEAFTER_CONTRACTED 0x0010
    +#define wxSTC_FOLDFLAG_LEVELNUMBERS 0x0040
    +#define wxSTC_FOLDFLAG_BOX 0x0001
    +#define wxSTC_TIME_FOREVER 10000000
    +#define wxSTC_WRAP_NONE 0
    +#define wxSTC_WRAP_WORD 1
    +#define wxSTC_WRAP_CHAR 2
    +#define wxSTC_WRAPVISUALFLAG_NONE 0x0000
    +#define wxSTC_WRAPVISUALFLAG_END 0x0001
    +#define wxSTC_WRAPVISUALFLAG_START 0x0002
    +#define wxSTC_WRAPVISUALFLAGLOC_DEFAULT 0x0000
    +#define wxSTC_WRAPVISUALFLAGLOC_END_BY_TEXT 0x0001
    +#define wxSTC_WRAPVISUALFLAGLOC_START_BY_TEXT 0x0002
    +#define wxSTC_CACHE_NONE 0
    +#define wxSTC_CACHE_CARET 1
    +#define wxSTC_CACHE_PAGE 2
    +#define wxSTC_CACHE_DOCUMENT 3
    +#define wxSTC_EDGE_NONE 0
    +#define wxSTC_EDGE_LINE 1
    +#define wxSTC_EDGE_BACKGROUND 2
    +#define wxSTC_CURSORNORMAL -1
    +#define wxSTC_CURSORWAIT 4
    +
    +// Constants for use with SetVisiblePolicy, similar to SetCaretPolicy.
    +#define wxSTC_VISIBLE_SLOP 0x01
    +#define wxSTC_VISIBLE_STRICT 0x04
    +
    +// Caret policy, used by SetXCaretPolicy and SetYCaretPolicy.
    +// If CARET_SLOP is set, we can define a slop value: caretSlop.
    +// This value defines an unwanted zone (UZ) where the caret is... unwanted.
    +// This zone is defined as a number of pixels near the vertical margins,
    +// and as a number of lines near the horizontal margins.
    +// By keeping the caret away from the edges, it is seen within its context,
    +// so it is likely that the identifier that the caret is on can be completely seen,
    +// and that the current line is seen with some of the lines following it which are
    +// often dependent on that line.
    +#define wxSTC_CARET_SLOP 0x01
    +
    +// If CARET_STRICT is set, the policy is enforced... strictly.
    +// The caret is centred on the display if slop is not set,
    +// and cannot go in the UZ if slop is set.
    +#define wxSTC_CARET_STRICT 0x04
    +
    +// If CARET_JUMPS is set, the display is moved more energetically
    +// so the caret can move in the same direction longer before the policy is applied again.
    +#define wxSTC_CARET_JUMPS 0x10
    +
    +// If CARET_EVEN is not set, instead of having symmetrical UZs,
    +// the left and bottom UZs are extended up to right and top UZs respectively.
    +// This way, we favour the displaying of useful information: the begining of lines,
    +// where most code reside, and the lines after the caret, eg. the body of a function.
    +#define wxSTC_CARET_EVEN 0x08
    +
    +// Selection modes
    +#define wxSTC_SEL_STREAM 0
    +#define wxSTC_SEL_RECTANGLE 1
    +#define wxSTC_SEL_LINES 2
    +
    +// Maximum value of keywordSet parameter of SetKeyWords.
    +#define wxSTC_KEYWORDSET_MAX 8
    +
    +// Notifications
    +// Type of modification and the action which caused the modification.
    +// These are defined as a bit mask to make it easy to specify which notifications are wanted.
    +// One bit is set from each of SC_MOD_* and SC_PERFORMED_*.
    +#define wxSTC_MOD_INSERTTEXT 0x1
    +#define wxSTC_MOD_DELETETEXT 0x2
    +#define wxSTC_MOD_CHANGESTYLE 0x4
    +#define wxSTC_MOD_CHANGEFOLD 0x8
    +#define wxSTC_PERFORMED_USER 0x10
    +#define wxSTC_PERFORMED_UNDO 0x20
    +#define wxSTC_PERFORMED_REDO 0x40
    +#define wxSTC_MULTISTEPUNDOREDO 0x80
    +#define wxSTC_LASTSTEPINUNDOREDO 0x100
    +#define wxSTC_MOD_CHANGEMARKER 0x200
    +#define wxSTC_MOD_BEFOREINSERT 0x400
    +#define wxSTC_MOD_BEFOREDELETE 0x800
    +#define wxSTC_MULTILINEUNDOREDO 0x1000
    +#define wxSTC_MODEVENTMASKALL 0x1FFF
    +
    +// Symbolic key codes and modifier flags.
    +// ASCII and other printable characters below 256.
    +// Extended keys above 300.
    +#define wxSTC_KEY_DOWN 300
    +#define wxSTC_KEY_UP 301
    +#define wxSTC_KEY_LEFT 302
    +#define wxSTC_KEY_RIGHT 303
    +#define wxSTC_KEY_HOME 304
    +#define wxSTC_KEY_END 305
    +#define wxSTC_KEY_PRIOR 306
    +#define wxSTC_KEY_NEXT 307
    +#define wxSTC_KEY_DELETE 308
    +#define wxSTC_KEY_INSERT 309
    +#define wxSTC_KEY_ESCAPE 7
    +#define wxSTC_KEY_BACK 8
    +#define wxSTC_KEY_TAB 9
    +#define wxSTC_KEY_RETURN 13
    +#define wxSTC_KEY_ADD 310
    +#define wxSTC_KEY_SUBTRACT 311
    +#define wxSTC_KEY_DIVIDE 312
    +#define wxSTC_SCMOD_NORM 0
    +#define wxSTC_SCMOD_SHIFT 1
    +#define wxSTC_SCMOD_CTRL 2
    +#define wxSTC_SCMOD_ALT 4
    +
    +// For SciLexer.h
    +#define wxSTC_LEX_CONTAINER 0
    +#define wxSTC_LEX_NULL 1
    +#define wxSTC_LEX_PYTHON 2
    +#define wxSTC_LEX_CPP 3
    +#define wxSTC_LEX_HTML 4
    +#define wxSTC_LEX_XML 5
    +#define wxSTC_LEX_PERL 6
    +#define wxSTC_LEX_SQL 7
    +#define wxSTC_LEX_VB 8
    +#define wxSTC_LEX_PROPERTIES 9
    +#define wxSTC_LEX_ERRORLIST 10
    +#define wxSTC_LEX_MAKEFILE 11
    +#define wxSTC_LEX_BATCH 12
    +#define wxSTC_LEX_XCODE 13
    +#define wxSTC_LEX_LATEX 14
    +#define wxSTC_LEX_LUA 15
    +#define wxSTC_LEX_DIFF 16
    +#define wxSTC_LEX_CONF 17
    +#define wxSTC_LEX_PASCAL 18
    +#define wxSTC_LEX_AVE 19
    +#define wxSTC_LEX_ADA 20
    +#define wxSTC_LEX_LISP 21
    +#define wxSTC_LEX_RUBY 22
    +#define wxSTC_LEX_EIFFEL 23
    +#define wxSTC_LEX_EIFFELKW 24
    +#define wxSTC_LEX_TCL 25
    +#define wxSTC_LEX_NNCRONTAB 26
    +#define wxSTC_LEX_BULLANT 27
    +#define wxSTC_LEX_VBSCRIPT 28
    +#define wxSTC_LEX_BAAN 31
    +#define wxSTC_LEX_MATLAB 32
    +#define wxSTC_LEX_SCRIPTOL 33
    +#define wxSTC_LEX_ASM 34
    +#define wxSTC_LEX_CPPNOCASE 35
    +#define wxSTC_LEX_FORTRAN 36
    +#define wxSTC_LEX_F77 37
    +#define wxSTC_LEX_CSS 38
    +#define wxSTC_LEX_POV 39
    +#define wxSTC_LEX_LOUT 40
    +#define wxSTC_LEX_ESCRIPT 41
    +#define wxSTC_LEX_PS 42
    +#define wxSTC_LEX_NSIS 43
    +#define wxSTC_LEX_MMIXAL 44
    +#define wxSTC_LEX_CLW 45
    +#define wxSTC_LEX_CLWNOCASE 46
    +#define wxSTC_LEX_LOT 47
    +#define wxSTC_LEX_YAML 48
    +#define wxSTC_LEX_TEX 49
    +#define wxSTC_LEX_METAPOST 50
    +#define wxSTC_LEX_POWERBASIC 51
    +#define wxSTC_LEX_FORTH 52
    +#define wxSTC_LEX_ERLANG 53
    +#define wxSTC_LEX_OCTAVE 54
    +#define wxSTC_LEX_MSSQL 55
    +#define wxSTC_LEX_VERILOG 56
    +#define wxSTC_LEX_KIX 57
    +#define wxSTC_LEX_GUI4CLI 58
    +#define wxSTC_LEX_SPECMAN 59
    +#define wxSTC_LEX_AU3 60
    +#define wxSTC_LEX_APDL 61
    +#define wxSTC_LEX_BASH 62
    +#define wxSTC_LEX_ASN1 63
    +#define wxSTC_LEX_VHDL 64
    +#define wxSTC_LEX_CAML 65
    +#define wxSTC_LEX_BLITZBASIC 66
    +#define wxSTC_LEX_PUREBASIC 67
    +#define wxSTC_LEX_HASKELL 68
    +#define wxSTC_LEX_PHPSCRIPT 69
    +#define wxSTC_LEX_TADS3 70
    +#define wxSTC_LEX_REBOL 71
    +#define wxSTC_LEX_SMALLTALK 72
    +#define wxSTC_LEX_FLAGSHIP 73
    +#define wxSTC_LEX_CSOUND 74
    +#define wxSTC_LEX_FREEBASIC 75
    +
    +// These are deprecated, STC_LEX_HTML should be used instead.
    +#define wxSTC_LEX_ASP 29
    +#define wxSTC_LEX_PHP 30
    +
    +// When a lexer specifies its language as SCLEX_AUTOMATIC it receives a
    +// value assigned in sequence from SCLEX_AUTOMATIC+1.
    +#define wxSTC_LEX_AUTOMATIC 1000
    +
    +// Lexical states for SCLEX_PYTHON
    +#define wxSTC_P_DEFAULT 0
    +#define wxSTC_P_COMMENTLINE 1
    +#define wxSTC_P_NUMBER 2
    +#define wxSTC_P_STRING 3
    +#define wxSTC_P_CHARACTER 4
    +#define wxSTC_P_WORD 5
    +#define wxSTC_P_TRIPLE 6
    +#define wxSTC_P_TRIPLEDOUBLE 7
    +#define wxSTC_P_CLASSNAME 8
    +#define wxSTC_P_DEFNAME 9
    +#define wxSTC_P_OPERATOR 10
    +#define wxSTC_P_IDENTIFIER 11
    +#define wxSTC_P_COMMENTBLOCK 12
    +#define wxSTC_P_STRINGEOL 13
    +#define wxSTC_P_WORD2 14
    +#define wxSTC_P_DECORATOR 15
    +
    +// Lexical states for SCLEX_CPP
    +#define wxSTC_C_DEFAULT 0
    +#define wxSTC_C_COMMENT 1
    +#define wxSTC_C_COMMENTLINE 2
    +#define wxSTC_C_COMMENTDOC 3
    +#define wxSTC_C_NUMBER 4
    +#define wxSTC_C_WORD 5
    +#define wxSTC_C_STRING 6
    +#define wxSTC_C_CHARACTER 7
    +#define wxSTC_C_UUID 8
    +#define wxSTC_C_PREPROCESSOR 9
    +#define wxSTC_C_OPERATOR 10
    +#define wxSTC_C_IDENTIFIER 11
    +#define wxSTC_C_STRINGEOL 12
    +#define wxSTC_C_VERBATIM 13
    +#define wxSTC_C_REGEX 14
    +#define wxSTC_C_COMMENTLINEDOC 15
    +#define wxSTC_C_WORD2 16
    +#define wxSTC_C_COMMENTDOCKEYWORD 17
    +#define wxSTC_C_COMMENTDOCKEYWORDERROR 18
    +#define wxSTC_C_GLOBALCLASS 19
    +
    +// Lexical states for SCLEX_HTML, SCLEX_XML
    +#define wxSTC_H_DEFAULT 0
    +#define wxSTC_H_TAG 1
    +#define wxSTC_H_TAGUNKNOWN 2
    +#define wxSTC_H_ATTRIBUTE 3
    +#define wxSTC_H_ATTRIBUTEUNKNOWN 4
    +#define wxSTC_H_NUMBER 5
    +#define wxSTC_H_DOUBLESTRING 6
    +#define wxSTC_H_SINGLESTRING 7
    +#define wxSTC_H_OTHER 8
    +#define wxSTC_H_COMMENT 9
    +#define wxSTC_H_ENTITY 10
    +
    +// XML and ASP
    +#define wxSTC_H_TAGEND 11
    +#define wxSTC_H_XMLSTART 12
    +#define wxSTC_H_XMLEND 13
    +#define wxSTC_H_SCRIPT 14
    +#define wxSTC_H_ASP 15
    +#define wxSTC_H_ASPAT 16
    +#define wxSTC_H_CDATA 17
    +#define wxSTC_H_QUESTION 18
    +
    +// More HTML
    +#define wxSTC_H_VALUE 19
    +
    +// X-Code
    +#define wxSTC_H_XCCOMMENT 20
    +
    +// SGML
    +#define wxSTC_H_SGML_DEFAULT 21
    +#define wxSTC_H_SGML_COMMAND 22
    +#define wxSTC_H_SGML_1ST_PARAM 23
    +#define wxSTC_H_SGML_DOUBLESTRING 24
    +#define wxSTC_H_SGML_SIMPLESTRING 25
    +#define wxSTC_H_SGML_ERROR 26
    +#define wxSTC_H_SGML_SPECIAL 27
    +#define wxSTC_H_SGML_ENTITY 28
    +#define wxSTC_H_SGML_COMMENT 29
    +#define wxSTC_H_SGML_1ST_PARAM_COMMENT 30
    +#define wxSTC_H_SGML_BLOCK_DEFAULT 31
    +
    +// Embedded Javascript
    +#define wxSTC_HJ_START 40
    +#define wxSTC_HJ_DEFAULT 41
    +#define wxSTC_HJ_COMMENT 42
    +#define wxSTC_HJ_COMMENTLINE 43
    +#define wxSTC_HJ_COMMENTDOC 44
    +#define wxSTC_HJ_NUMBER 45
    +#define wxSTC_HJ_WORD 46
    +#define wxSTC_HJ_KEYWORD 47
    +#define wxSTC_HJ_DOUBLESTRING 48
    +#define wxSTC_HJ_SINGLESTRING 49
    +#define wxSTC_HJ_SYMBOLS 50
    +#define wxSTC_HJ_STRINGEOL 51
    +#define wxSTC_HJ_REGEX 52
    +
    +// ASP Javascript
    +#define wxSTC_HJA_START 55
    +#define wxSTC_HJA_DEFAULT 56
    +#define wxSTC_HJA_COMMENT 57
    +#define wxSTC_HJA_COMMENTLINE 58
    +#define wxSTC_HJA_COMMENTDOC 59
    +#define wxSTC_HJA_NUMBER 60
    +#define wxSTC_HJA_WORD 61
    +#define wxSTC_HJA_KEYWORD 62
    +#define wxSTC_HJA_DOUBLESTRING 63
    +#define wxSTC_HJA_SINGLESTRING 64
    +#define wxSTC_HJA_SYMBOLS 65
    +#define wxSTC_HJA_STRINGEOL 66
    +#define wxSTC_HJA_REGEX 67
    +
    +// Embedded VBScript
    +#define wxSTC_HB_START 70
    +#define wxSTC_HB_DEFAULT 71
    +#define wxSTC_HB_COMMENTLINE 72
    +#define wxSTC_HB_NUMBER 73
    +#define wxSTC_HB_WORD 74
    +#define wxSTC_HB_STRING 75
    +#define wxSTC_HB_IDENTIFIER 76
    +#define wxSTC_HB_STRINGEOL 77
    +
    +// ASP VBScript
    +#define wxSTC_HBA_START 80
    +#define wxSTC_HBA_DEFAULT 81
    +#define wxSTC_HBA_COMMENTLINE 82
    +#define wxSTC_HBA_NUMBER 83
    +#define wxSTC_HBA_WORD 84
    +#define wxSTC_HBA_STRING 85
    +#define wxSTC_HBA_IDENTIFIER 86
    +#define wxSTC_HBA_STRINGEOL 87
    +
    +// Embedded Python
    +#define wxSTC_HP_START 90
    +#define wxSTC_HP_DEFAULT 91
    +#define wxSTC_HP_COMMENTLINE 92
    +#define wxSTC_HP_NUMBER 93
    +#define wxSTC_HP_STRING 94
    +#define wxSTC_HP_CHARACTER 95
    +#define wxSTC_HP_WORD 96
    +#define wxSTC_HP_TRIPLE 97
    +#define wxSTC_HP_TRIPLEDOUBLE 98
    +#define wxSTC_HP_CLASSNAME 99
    +#define wxSTC_HP_DEFNAME 100
    +#define wxSTC_HP_OPERATOR 101
    +#define wxSTC_HP_IDENTIFIER 102
    +
    +// PHP
    +#define wxSTC_HPHP_COMPLEX_VARIABLE 104
    +
    +// ASP Python
    +#define wxSTC_HPA_START 105
    +#define wxSTC_HPA_DEFAULT 106
    +#define wxSTC_HPA_COMMENTLINE 107
    +#define wxSTC_HPA_NUMBER 108
    +#define wxSTC_HPA_STRING 109
    +#define wxSTC_HPA_CHARACTER 110
    +#define wxSTC_HPA_WORD 111
    +#define wxSTC_HPA_TRIPLE 112
    +#define wxSTC_HPA_TRIPLEDOUBLE 113
    +#define wxSTC_HPA_CLASSNAME 114
    +#define wxSTC_HPA_DEFNAME 115
    +#define wxSTC_HPA_OPERATOR 116
    +#define wxSTC_HPA_IDENTIFIER 117
    +
    +// PHP
    +#define wxSTC_HPHP_DEFAULT 118
    +#define wxSTC_HPHP_HSTRING 119
    +#define wxSTC_HPHP_SIMPLESTRING 120
    +#define wxSTC_HPHP_WORD 121
    +#define wxSTC_HPHP_NUMBER 122
    +#define wxSTC_HPHP_VARIABLE 123
    +#define wxSTC_HPHP_COMMENT 124
    +#define wxSTC_HPHP_COMMENTLINE 125
    +#define wxSTC_HPHP_HSTRING_VARIABLE 126
    +#define wxSTC_HPHP_OPERATOR 127
    +
    +// Lexical states for SCLEX_PERL
    +#define wxSTC_PL_DEFAULT 0
    +#define wxSTC_PL_ERROR 1
    +#define wxSTC_PL_COMMENTLINE 2
    +#define wxSTC_PL_POD 3
    +#define wxSTC_PL_NUMBER 4
    +#define wxSTC_PL_WORD 5
    +#define wxSTC_PL_STRING 6
    +#define wxSTC_PL_CHARACTER 7
    +#define wxSTC_PL_PUNCTUATION 8
    +#define wxSTC_PL_PREPROCESSOR 9
    +#define wxSTC_PL_OPERATOR 10
    +#define wxSTC_PL_IDENTIFIER 11
    +#define wxSTC_PL_SCALAR 12
    +#define wxSTC_PL_ARRAY 13
    +#define wxSTC_PL_HASH 14
    +#define wxSTC_PL_SYMBOLTABLE 15
    +#define wxSTC_PL_VARIABLE_INDEXER 16
    +#define wxSTC_PL_REGEX 17
    +#define wxSTC_PL_REGSUBST 18
    +#define wxSTC_PL_LONGQUOTE 19
    +#define wxSTC_PL_BACKTICKS 20
    +#define wxSTC_PL_DATASECTION 21
    +#define wxSTC_PL_HERE_DELIM 22
    +#define wxSTC_PL_HERE_Q 23
    +#define wxSTC_PL_HERE_QQ 24
    +#define wxSTC_PL_HERE_QX 25
    +#define wxSTC_PL_STRING_Q 26
    +#define wxSTC_PL_STRING_QQ 27
    +#define wxSTC_PL_STRING_QX 28
    +#define wxSTC_PL_STRING_QR 29
    +#define wxSTC_PL_STRING_QW 30
    +#define wxSTC_PL_POD_VERB 31
    +
    +// Lexical states for SCLEX_RUBY
    +#define wxSTC_RB_DEFAULT 0
    +#define wxSTC_RB_ERROR 1
    +#define wxSTC_RB_COMMENTLINE 2
    +#define wxSTC_RB_POD 3
    +#define wxSTC_RB_NUMBER 4
    +#define wxSTC_RB_WORD 5
    +#define wxSTC_RB_STRING 6
    +#define wxSTC_RB_CHARACTER 7
    +#define wxSTC_RB_CLASSNAME 8
    +#define wxSTC_RB_DEFNAME 9
    +#define wxSTC_RB_OPERATOR 10
    +#define wxSTC_RB_IDENTIFIER 11
    +#define wxSTC_RB_REGEX 12
    +#define wxSTC_RB_GLOBAL 13
    +#define wxSTC_RB_SYMBOL 14
    +#define wxSTC_RB_MODULE_NAME 15
    +#define wxSTC_RB_INSTANCE_VAR 16
    +#define wxSTC_RB_CLASS_VAR 17
    +#define wxSTC_RB_BACKTICKS 18
    +#define wxSTC_RB_DATASECTION 19
    +#define wxSTC_RB_HERE_DELIM 20
    +#define wxSTC_RB_HERE_Q 21
    +#define wxSTC_RB_HERE_QQ 22
    +#define wxSTC_RB_HERE_QX 23
    +#define wxSTC_RB_STRING_Q 24
    +#define wxSTC_RB_STRING_QQ 25
    +#define wxSTC_RB_STRING_QX 26
    +#define wxSTC_RB_STRING_QR 27
    +#define wxSTC_RB_STRING_QW 28
    +#define wxSTC_RB_WORD_DEMOTED 29
    +#define wxSTC_RB_STDIN 30
    +#define wxSTC_RB_STDOUT 31
    +#define wxSTC_RB_STDERR 40
    +#define wxSTC_RB_UPPER_BOUND 41
    +
    +// Lexical states for SCLEX_VB, SCLEX_VBSCRIPT, SCLEX_POWERBASIC
    +#define wxSTC_B_DEFAULT 0
    +#define wxSTC_B_COMMENT 1
    +#define wxSTC_B_NUMBER 2
    +#define wxSTC_B_KEYWORD 3
    +#define wxSTC_B_STRING 4
    +#define wxSTC_B_PREPROCESSOR 5
    +#define wxSTC_B_OPERATOR 6
    +#define wxSTC_B_IDENTIFIER 7
    +#define wxSTC_B_DATE 8
    +#define wxSTC_B_STRINGEOL 9
    +#define wxSTC_B_KEYWORD2 10
    +#define wxSTC_B_KEYWORD3 11
    +#define wxSTC_B_KEYWORD4 12
    +#define wxSTC_B_CONSTANT 13
    +#define wxSTC_B_ASM 14
    +#define wxSTC_B_LABEL 15
    +#define wxSTC_B_ERROR 16
    +#define wxSTC_B_HEXNUMBER 17
    +#define wxSTC_B_BINNUMBER 18
    +
    +// Lexical states for SCLEX_PROPERTIES
    +#define wxSTC_PROPS_DEFAULT 0
    +#define wxSTC_PROPS_COMMENT 1
    +#define wxSTC_PROPS_SECTION 2
    +#define wxSTC_PROPS_ASSIGNMENT 3
    +#define wxSTC_PROPS_DEFVAL 4
    +
    +// Lexical states for SCLEX_LATEX
    +#define wxSTC_L_DEFAULT 0
    +#define wxSTC_L_COMMAND 1
    +#define wxSTC_L_TAG 2
    +#define wxSTC_L_MATH 3
    +#define wxSTC_L_COMMENT 4
    +
    +// Lexical states for SCLEX_LUA
    +#define wxSTC_LUA_DEFAULT 0
    +#define wxSTC_LUA_COMMENT 1
    +#define wxSTC_LUA_COMMENTLINE 2
    +#define wxSTC_LUA_COMMENTDOC 3
    +#define wxSTC_LUA_NUMBER 4
    +#define wxSTC_LUA_WORD 5
    +#define wxSTC_LUA_STRING 6
    +#define wxSTC_LUA_CHARACTER 7
    +#define wxSTC_LUA_LITERALSTRING 8
    +#define wxSTC_LUA_PREPROCESSOR 9
    +#define wxSTC_LUA_OPERATOR 10
    +#define wxSTC_LUA_IDENTIFIER 11
    +#define wxSTC_LUA_STRINGEOL 12
    +#define wxSTC_LUA_WORD2 13
    +#define wxSTC_LUA_WORD3 14
    +#define wxSTC_LUA_WORD4 15
    +#define wxSTC_LUA_WORD5 16
    +#define wxSTC_LUA_WORD6 17
    +#define wxSTC_LUA_WORD7 18
    +#define wxSTC_LUA_WORD8 19
    +
    +// Lexical states for SCLEX_ERRORLIST
    +#define wxSTC_ERR_DEFAULT 0
    +#define wxSTC_ERR_PYTHON 1
    +#define wxSTC_ERR_GCC 2
    +#define wxSTC_ERR_MS 3
    +#define wxSTC_ERR_CMD 4
    +#define wxSTC_ERR_BORLAND 5
    +#define wxSTC_ERR_PERL 6
    +#define wxSTC_ERR_NET 7
    +#define wxSTC_ERR_LUA 8
    +#define wxSTC_ERR_CTAG 9
    +#define wxSTC_ERR_DIFF_CHANGED 10
    +#define wxSTC_ERR_DIFF_ADDITION 11
    +#define wxSTC_ERR_DIFF_DELETION 12
    +#define wxSTC_ERR_DIFF_MESSAGE 13
    +#define wxSTC_ERR_PHP 14
    +#define wxSTC_ERR_ELF 15
    +#define wxSTC_ERR_IFC 16
    +#define wxSTC_ERR_IFORT 17
    +#define wxSTC_ERR_ABSF 18
    +#define wxSTC_ERR_TIDY 19
    +#define wxSTC_ERR_JAVA_STACK 20
    +
    +// Lexical states for SCLEX_BATCH
    +#define wxSTC_BAT_DEFAULT 0
    +#define wxSTC_BAT_COMMENT 1
    +#define wxSTC_BAT_WORD 2
    +#define wxSTC_BAT_LABEL 3
    +#define wxSTC_BAT_HIDE 4
    +#define wxSTC_BAT_COMMAND 5
    +#define wxSTC_BAT_IDENTIFIER 6
    +#define wxSTC_BAT_OPERATOR 7
    +
    +// Lexical states for SCLEX_MAKEFILE
    +#define wxSTC_MAKE_DEFAULT 0
    +#define wxSTC_MAKE_COMMENT 1
    +#define wxSTC_MAKE_PREPROCESSOR 2
    +#define wxSTC_MAKE_IDENTIFIER 3
    +#define wxSTC_MAKE_OPERATOR 4
    +#define wxSTC_MAKE_TARGET 5
    +#define wxSTC_MAKE_IDEOL 9
    +
    +// Lexical states for SCLEX_DIFF
    +#define wxSTC_DIFF_DEFAULT 0
    +#define wxSTC_DIFF_COMMENT 1
    +#define wxSTC_DIFF_COMMAND 2
    +#define wxSTC_DIFF_HEADER 3
    +#define wxSTC_DIFF_POSITION 4
    +#define wxSTC_DIFF_DELETED 5
    +#define wxSTC_DIFF_ADDED 6
    +
    +// Lexical states for SCLEX_CONF (Apache Configuration Files Lexer)
    +#define wxSTC_CONF_DEFAULT 0
    +#define wxSTC_CONF_COMMENT 1
    +#define wxSTC_CONF_NUMBER 2
    +#define wxSTC_CONF_IDENTIFIER 3
    +#define wxSTC_CONF_EXTENSION 4
    +#define wxSTC_CONF_PARAMETER 5
    +#define wxSTC_CONF_STRING 6
    +#define wxSTC_CONF_OPERATOR 7
    +#define wxSTC_CONF_IP 8
    +#define wxSTC_CONF_DIRECTIVE 9
    +
    +// Lexical states for SCLEX_AVE, Avenue
    +#define wxSTC_AVE_DEFAULT 0
    +#define wxSTC_AVE_COMMENT 1
    +#define wxSTC_AVE_NUMBER 2
    +#define wxSTC_AVE_WORD 3
    +#define wxSTC_AVE_STRING 6
    +#define wxSTC_AVE_ENUM 7
    +#define wxSTC_AVE_STRINGEOL 8
    +#define wxSTC_AVE_IDENTIFIER 9
    +#define wxSTC_AVE_OPERATOR 10
    +#define wxSTC_AVE_WORD1 11
    +#define wxSTC_AVE_WORD2 12
    +#define wxSTC_AVE_WORD3 13
    +#define wxSTC_AVE_WORD4 14
    +#define wxSTC_AVE_WORD5 15
    +#define wxSTC_AVE_WORD6 16
    +
    +// Lexical states for SCLEX_ADA
    +#define wxSTC_ADA_DEFAULT 0
    +#define wxSTC_ADA_WORD 1
    +#define wxSTC_ADA_IDENTIFIER 2
    +#define wxSTC_ADA_NUMBER 3
    +#define wxSTC_ADA_DELIMITER 4
    +#define wxSTC_ADA_CHARACTER 5
    +#define wxSTC_ADA_CHARACTEREOL 6
    +#define wxSTC_ADA_STRING 7
    +#define wxSTC_ADA_STRINGEOL 8
    +#define wxSTC_ADA_LABEL 9
    +#define wxSTC_ADA_COMMENTLINE 10
    +#define wxSTC_ADA_ILLEGAL 11
    +
    +// Lexical states for SCLEX_BAAN
    +#define wxSTC_BAAN_DEFAULT 0
    +#define wxSTC_BAAN_COMMENT 1
    +#define wxSTC_BAAN_COMMENTDOC 2
    +#define wxSTC_BAAN_NUMBER 3
    +#define wxSTC_BAAN_WORD 4
    +#define wxSTC_BAAN_STRING 5
    +#define wxSTC_BAAN_PREPROCESSOR 6
    +#define wxSTC_BAAN_OPERATOR 7
    +#define wxSTC_BAAN_IDENTIFIER 8
    +#define wxSTC_BAAN_STRINGEOL 9
    +#define wxSTC_BAAN_WORD2 10
    +
    +// Lexical states for SCLEX_LISP
    +#define wxSTC_LISP_DEFAULT 0
    +#define wxSTC_LISP_COMMENT 1
    +#define wxSTC_LISP_NUMBER 2
    +#define wxSTC_LISP_KEYWORD 3
    +#define wxSTC_LISP_KEYWORD_KW 4
    +#define wxSTC_LISP_SYMBOL 5
    +#define wxSTC_LISP_STRING 6
    +#define wxSTC_LISP_STRINGEOL 8
    +#define wxSTC_LISP_IDENTIFIER 9
    +#define wxSTC_LISP_OPERATOR 10
    +#define wxSTC_LISP_SPECIAL 11
    +#define wxSTC_LISP_MULTI_COMMENT 12
    +
    +// Lexical states for SCLEX_EIFFEL and SCLEX_EIFFELKW
    +#define wxSTC_EIFFEL_DEFAULT 0
    +#define wxSTC_EIFFEL_COMMENTLINE 1
    +#define wxSTC_EIFFEL_NUMBER 2
    +#define wxSTC_EIFFEL_WORD 3
    +#define wxSTC_EIFFEL_STRING 4
    +#define wxSTC_EIFFEL_CHARACTER 5
    +#define wxSTC_EIFFEL_OPERATOR 6
    +#define wxSTC_EIFFEL_IDENTIFIER 7
    +#define wxSTC_EIFFEL_STRINGEOL 8
    +
    +// Lexical states for SCLEX_NNCRONTAB (nnCron crontab Lexer)
    +#define wxSTC_NNCRONTAB_DEFAULT 0
    +#define wxSTC_NNCRONTAB_COMMENT 1
    +#define wxSTC_NNCRONTAB_TASK 2
    +#define wxSTC_NNCRONTAB_SECTION 3
    +#define wxSTC_NNCRONTAB_KEYWORD 4
    +#define wxSTC_NNCRONTAB_MODIFIER 5
    +#define wxSTC_NNCRONTAB_ASTERISK 6
    +#define wxSTC_NNCRONTAB_NUMBER 7
    +#define wxSTC_NNCRONTAB_STRING 8
    +#define wxSTC_NNCRONTAB_ENVIRONMENT 9
    +#define wxSTC_NNCRONTAB_IDENTIFIER 10
    +
    +// Lexical states for SCLEX_FORTH (Forth Lexer)
    +#define wxSTC_FORTH_DEFAULT 0
    +#define wxSTC_FORTH_COMMENT 1
    +#define wxSTC_FORTH_COMMENT_ML 2
    +#define wxSTC_FORTH_IDENTIFIER 3
    +#define wxSTC_FORTH_CONTROL 4
    +#define wxSTC_FORTH_KEYWORD 5
    +#define wxSTC_FORTH_DEFWORD 6
    +#define wxSTC_FORTH_PREWORD1 7
    +#define wxSTC_FORTH_PREWORD2 8
    +#define wxSTC_FORTH_NUMBER 9
    +#define wxSTC_FORTH_STRING 10
    +#define wxSTC_FORTH_LOCALE 11
    +
    +// Lexical states for SCLEX_MATLAB
    +#define wxSTC_MATLAB_DEFAULT 0
    +#define wxSTC_MATLAB_COMMENT 1
    +#define wxSTC_MATLAB_COMMAND 2
    +#define wxSTC_MATLAB_NUMBER 3
    +#define wxSTC_MATLAB_KEYWORD 4
    +
    +// single quoted string
    +#define wxSTC_MATLAB_STRING 5
    +#define wxSTC_MATLAB_OPERATOR 6
    +#define wxSTC_MATLAB_IDENTIFIER 7
    +#define wxSTC_MATLAB_DOUBLEQUOTESTRING 8
    +
    +// Lexical states for SCLEX_SCRIPTOL
    +#define wxSTC_SCRIPTOL_DEFAULT 0
    +#define wxSTC_SCRIPTOL_WHITE 1
    +#define wxSTC_SCRIPTOL_COMMENTLINE 2
    +#define wxSTC_SCRIPTOL_PERSISTENT 3
    +#define wxSTC_SCRIPTOL_CSTYLE 4
    +#define wxSTC_SCRIPTOL_COMMENTBLOCK 5
    +#define wxSTC_SCRIPTOL_NUMBER 6
    +#define wxSTC_SCRIPTOL_STRING 7
    +#define wxSTC_SCRIPTOL_CHARACTER 8
    +#define wxSTC_SCRIPTOL_STRINGEOL 9
    +#define wxSTC_SCRIPTOL_KEYWORD 10
    +#define wxSTC_SCRIPTOL_OPERATOR 11
    +#define wxSTC_SCRIPTOL_IDENTIFIER 12
    +#define wxSTC_SCRIPTOL_TRIPLE 13
    +#define wxSTC_SCRIPTOL_CLASSNAME 14
    +#define wxSTC_SCRIPTOL_PREPROCESSOR 15
    +
    +// Lexical states for SCLEX_ASM
    +#define wxSTC_ASM_DEFAULT 0
    +#define wxSTC_ASM_COMMENT 1
    +#define wxSTC_ASM_NUMBER 2
    +#define wxSTC_ASM_STRING 3
    +#define wxSTC_ASM_OPERATOR 4
    +#define wxSTC_ASM_IDENTIFIER 5
    +#define wxSTC_ASM_CPUINSTRUCTION 6
    +#define wxSTC_ASM_MATHINSTRUCTION 7
    +#define wxSTC_ASM_REGISTER 8
    +#define wxSTC_ASM_DIRECTIVE 9
    +#define wxSTC_ASM_DIRECTIVEOPERAND 10
    +#define wxSTC_ASM_COMMENTBLOCK 11
    +#define wxSTC_ASM_CHARACTER 12
    +#define wxSTC_ASM_STRINGEOL 13
    +#define wxSTC_ASM_EXTINSTRUCTION 14
    +
    +// Lexical states for SCLEX_FORTRAN
    +#define wxSTC_F_DEFAULT 0
    +#define wxSTC_F_COMMENT 1
    +#define wxSTC_F_NUMBER 2
    +#define wxSTC_F_STRING1 3
    +#define wxSTC_F_STRING2 4
    +#define wxSTC_F_STRINGEOL 5
    +#define wxSTC_F_OPERATOR 6
    +#define wxSTC_F_IDENTIFIER 7
    +#define wxSTC_F_WORD 8
    +#define wxSTC_F_WORD2 9
    +#define wxSTC_F_WORD3 10
    +#define wxSTC_F_PREPROCESSOR 11
    +#define wxSTC_F_OPERATOR2 12
    +#define wxSTC_F_LABEL 13
    +#define wxSTC_F_CONTINUATION 14
    +
    +// Lexical states for SCLEX_CSS
    +#define wxSTC_CSS_DEFAULT 0
    +#define wxSTC_CSS_TAG 1
    +#define wxSTC_CSS_CLASS 2
    +#define wxSTC_CSS_PSEUDOCLASS 3
    +#define wxSTC_CSS_UNKNOWN_PSEUDOCLASS 4
    +#define wxSTC_CSS_OPERATOR 5
    +#define wxSTC_CSS_IDENTIFIER 6
    +#define wxSTC_CSS_UNKNOWN_IDENTIFIER 7
    +#define wxSTC_CSS_VALUE 8
    +#define wxSTC_CSS_COMMENT 9
    +#define wxSTC_CSS_ID 10
    +#define wxSTC_CSS_IMPORTANT 11
    +#define wxSTC_CSS_DIRECTIVE 12
    +#define wxSTC_CSS_DOUBLESTRING 13
    +#define wxSTC_CSS_SINGLESTRING 14
    +#define wxSTC_CSS_IDENTIFIER2 15
    +#define wxSTC_CSS_ATTRIBUTE 16
    +
    +// Lexical states for SCLEX_POV
    +#define wxSTC_POV_DEFAULT 0
    +#define wxSTC_POV_COMMENT 1
    +#define wxSTC_POV_COMMENTLINE 2
    +#define wxSTC_POV_NUMBER 3
    +#define wxSTC_POV_OPERATOR 4
    +#define wxSTC_POV_IDENTIFIER 5
    +#define wxSTC_POV_STRING 6
    +#define wxSTC_POV_STRINGEOL 7
    +#define wxSTC_POV_DIRECTIVE 8
    +#define wxSTC_POV_BADDIRECTIVE 9
    +#define wxSTC_POV_WORD2 10
    +#define wxSTC_POV_WORD3 11
    +#define wxSTC_POV_WORD4 12
    +#define wxSTC_POV_WORD5 13
    +#define wxSTC_POV_WORD6 14
    +#define wxSTC_POV_WORD7 15
    +#define wxSTC_POV_WORD8 16
    +
    +// Lexical states for SCLEX_LOUT
    +#define wxSTC_LOUT_DEFAULT 0
    +#define wxSTC_LOUT_COMMENT 1
    +#define wxSTC_LOUT_NUMBER 2
    +#define wxSTC_LOUT_WORD 3
    +#define wxSTC_LOUT_WORD2 4
    +#define wxSTC_LOUT_WORD3 5
    +#define wxSTC_LOUT_WORD4 6
    +#define wxSTC_LOUT_STRING 7
    +#define wxSTC_LOUT_OPERATOR 8
    +#define wxSTC_LOUT_IDENTIFIER 9
    +#define wxSTC_LOUT_STRINGEOL 10
    +
    +// Lexical states for SCLEX_ESCRIPT
    +#define wxSTC_ESCRIPT_DEFAULT 0
    +#define wxSTC_ESCRIPT_COMMENT 1
    +#define wxSTC_ESCRIPT_COMMENTLINE 2
    +#define wxSTC_ESCRIPT_COMMENTDOC 3
    +#define wxSTC_ESCRIPT_NUMBER 4
    +#define wxSTC_ESCRIPT_WORD 5
    +#define wxSTC_ESCRIPT_STRING 6
    +#define wxSTC_ESCRIPT_OPERATOR 7
    +#define wxSTC_ESCRIPT_IDENTIFIER 8
    +#define wxSTC_ESCRIPT_BRACE 9
    +#define wxSTC_ESCRIPT_WORD2 10
    +#define wxSTC_ESCRIPT_WORD3 11
    +
    +// Lexical states for SCLEX_PS
    +#define wxSTC_PS_DEFAULT 0
    +#define wxSTC_PS_COMMENT 1
    +#define wxSTC_PS_DSC_COMMENT 2
    +#define wxSTC_PS_DSC_VALUE 3
    +#define wxSTC_PS_NUMBER 4
    +#define wxSTC_PS_NAME 5
    +#define wxSTC_PS_KEYWORD 6
    +#define wxSTC_PS_LITERAL 7
    +#define wxSTC_PS_IMMEVAL 8
    +#define wxSTC_PS_PAREN_ARRAY 9
    +#define wxSTC_PS_PAREN_DICT 10
    +#define wxSTC_PS_PAREN_PROC 11
    +#define wxSTC_PS_TEXT 12
    +#define wxSTC_PS_HEXSTRING 13
    +#define wxSTC_PS_BASE85STRING 14
    +#define wxSTC_PS_BADSTRINGCHAR 15
    +
    +// Lexical states for SCLEX_NSIS
    +#define wxSTC_NSIS_DEFAULT 0
    +#define wxSTC_NSIS_COMMENT 1
    +#define wxSTC_NSIS_STRINGDQ 2
    +#define wxSTC_NSIS_STRINGLQ 3
    +#define wxSTC_NSIS_STRINGRQ 4
    +#define wxSTC_NSIS_FUNCTION 5
    +#define wxSTC_NSIS_VARIABLE 6
    +#define wxSTC_NSIS_LABEL 7
    +#define wxSTC_NSIS_USERDEFINED 8
    +#define wxSTC_NSIS_SECTIONDEF 9
    +#define wxSTC_NSIS_SUBSECTIONDEF 10
    +#define wxSTC_NSIS_IFDEFINEDEF 11
    +#define wxSTC_NSIS_MACRODEF 12
    +#define wxSTC_NSIS_STRINGVAR 13
    +#define wxSTC_NSIS_NUMBER 14
    +#define wxSTC_NSIS_SECTIONGROUP 15
    +#define wxSTC_NSIS_PAGEEX 16
    +#define wxSTC_NSIS_FUNCTIONDEF 17
    +#define wxSTC_NSIS_COMMENTBOX 18
    +
    +// Lexical states for SCLEX_MMIXAL
    +#define wxSTC_MMIXAL_LEADWS 0
    +#define wxSTC_MMIXAL_COMMENT 1
    +#define wxSTC_MMIXAL_LABEL 2
    +#define wxSTC_MMIXAL_OPCODE 3
    +#define wxSTC_MMIXAL_OPCODE_PRE 4
    +#define wxSTC_MMIXAL_OPCODE_VALID 5
    +#define wxSTC_MMIXAL_OPCODE_UNKNOWN 6
    +#define wxSTC_MMIXAL_OPCODE_POST 7
    +#define wxSTC_MMIXAL_OPERANDS 8
    +#define wxSTC_MMIXAL_NUMBER 9
    +#define wxSTC_MMIXAL_REF 10
    +#define wxSTC_MMIXAL_CHAR 11
    +#define wxSTC_MMIXAL_STRING 12
    +#define wxSTC_MMIXAL_REGISTER 13
    +#define wxSTC_MMIXAL_HEX 14
    +#define wxSTC_MMIXAL_OPERATOR 15
    +#define wxSTC_MMIXAL_SYMBOL 16
    +#define wxSTC_MMIXAL_INCLUDE 17
    +
    +// Lexical states for SCLEX_CLW
    +#define wxSTC_CLW_DEFAULT 0
    +#define wxSTC_CLW_LABEL 1
    +#define wxSTC_CLW_COMMENT 2
    +#define wxSTC_CLW_STRING 3
    +#define wxSTC_CLW_USER_IDENTIFIER 4
    +#define wxSTC_CLW_INTEGER_CONSTANT 5
    +#define wxSTC_CLW_REAL_CONSTANT 6
    +#define wxSTC_CLW_PICTURE_STRING 7
    +#define wxSTC_CLW_KEYWORD 8
    +#define wxSTC_CLW_COMPILER_DIRECTIVE 9
    +#define wxSTC_CLW_RUNTIME_EXPRESSIONS 10
    +#define wxSTC_CLW_BUILTIN_PROCEDURES_FUNCTION 11
    +#define wxSTC_CLW_STRUCTURE_DATA_TYPE 12
    +#define wxSTC_CLW_ATTRIBUTE 13
    +#define wxSTC_CLW_STANDARD_EQUATE 14
    +#define wxSTC_CLW_ERROR 15
    +#define wxSTC_CLW_DEPRECATED 16
    +
    +// Lexical states for SCLEX_LOT
    +#define wxSTC_LOT_DEFAULT 0
    +#define wxSTC_LOT_HEADER 1
    +#define wxSTC_LOT_BREAK 2
    +#define wxSTC_LOT_SET 3
    +#define wxSTC_LOT_PASS 4
    +#define wxSTC_LOT_FAIL 5
    +#define wxSTC_LOT_ABORT 6
    +
    +// Lexical states for SCLEX_YAML
    +#define wxSTC_YAML_DEFAULT 0
    +#define wxSTC_YAML_COMMENT 1
    +#define wxSTC_YAML_IDENTIFIER 2
    +#define wxSTC_YAML_KEYWORD 3
    +#define wxSTC_YAML_NUMBER 4
    +#define wxSTC_YAML_REFERENCE 5
    +#define wxSTC_YAML_DOCUMENT 6
    +#define wxSTC_YAML_TEXT 7
    +#define wxSTC_YAML_ERROR 8
    +
    +// Lexical states for SCLEX_TEX
    +#define wxSTC_TEX_DEFAULT 0
    +#define wxSTC_TEX_SPECIAL 1
    +#define wxSTC_TEX_GROUP 2
    +#define wxSTC_TEX_SYMBOL 3
    +#define wxSTC_TEX_COMMAND 4
    +#define wxSTC_TEX_TEXT 5
    +#define wxSTC_METAPOST_DEFAULT 0
    +#define wxSTC_METAPOST_SPECIAL 1
    +#define wxSTC_METAPOST_GROUP 2
    +#define wxSTC_METAPOST_SYMBOL 3
    +#define wxSTC_METAPOST_COMMAND 4
    +#define wxSTC_METAPOST_TEXT 5
    +#define wxSTC_METAPOST_EXTRA 6
    +
    +// Lexical states for SCLEX_ERLANG
    +#define wxSTC_ERLANG_DEFAULT 0
    +#define wxSTC_ERLANG_COMMENT 1
    +#define wxSTC_ERLANG_VARIABLE 2
    +#define wxSTC_ERLANG_NUMBER 3
    +#define wxSTC_ERLANG_KEYWORD 4
    +#define wxSTC_ERLANG_STRING 5
    +#define wxSTC_ERLANG_OPERATOR 6
    +#define wxSTC_ERLANG_ATOM 7
    +#define wxSTC_ERLANG_FUNCTION_NAME 8
    +#define wxSTC_ERLANG_CHARACTER 9
    +#define wxSTC_ERLANG_MACRO 10
    +#define wxSTC_ERLANG_RECORD 11
    +#define wxSTC_ERLANG_SEPARATOR 12
    +#define wxSTC_ERLANG_NODE_NAME 13
    +#define wxSTC_ERLANG_UNKNOWN 31
    +
    +// Lexical states for SCLEX_OCTAVE are identical to MatLab
    +// Lexical states for SCLEX_MSSQL
    +#define wxSTC_MSSQL_DEFAULT 0
    +#define wxSTC_MSSQL_COMMENT 1
    +#define wxSTC_MSSQL_LINE_COMMENT 2
    +#define wxSTC_MSSQL_NUMBER 3
    +#define wxSTC_MSSQL_STRING 4
    +#define wxSTC_MSSQL_OPERATOR 5
    +#define wxSTC_MSSQL_IDENTIFIER 6
    +#define wxSTC_MSSQL_VARIABLE 7
    +#define wxSTC_MSSQL_COLUMN_NAME 8
    +#define wxSTC_MSSQL_STATEMENT 9
    +#define wxSTC_MSSQL_DATATYPE 10
    +#define wxSTC_MSSQL_SYSTABLE 11
    +#define wxSTC_MSSQL_GLOBAL_VARIABLE 12
    +#define wxSTC_MSSQL_FUNCTION 13
    +#define wxSTC_MSSQL_STORED_PROCEDURE 14
    +#define wxSTC_MSSQL_DEFAULT_PREF_DATATYPE 15
    +#define wxSTC_MSSQL_COLUMN_NAME_2 16
    +
    +// Lexical states for SCLEX_VERILOG
    +#define wxSTC_V_DEFAULT 0
    +#define wxSTC_V_COMMENT 1
    +#define wxSTC_V_COMMENTLINE 2
    +#define wxSTC_V_COMMENTLINEBANG 3
    +#define wxSTC_V_NUMBER 4
    +#define wxSTC_V_WORD 5
    +#define wxSTC_V_STRING 6
    +#define wxSTC_V_WORD2 7
    +#define wxSTC_V_WORD3 8
    +#define wxSTC_V_PREPROCESSOR 9
    +#define wxSTC_V_OPERATOR 10
    +#define wxSTC_V_IDENTIFIER 11
    +#define wxSTC_V_STRINGEOL 12
    +#define wxSTC_V_USER 19
    +
    +// Lexical states for SCLEX_KIX
    +#define wxSTC_KIX_DEFAULT 0
    +#define wxSTC_KIX_COMMENT 1
    +#define wxSTC_KIX_STRING1 2
    +#define wxSTC_KIX_STRING2 3
    +#define wxSTC_KIX_NUMBER 4
    +#define wxSTC_KIX_VAR 5
    +#define wxSTC_KIX_MACRO 6
    +#define wxSTC_KIX_KEYWORD 7
    +#define wxSTC_KIX_FUNCTIONS 8
    +#define wxSTC_KIX_OPERATOR 9
    +#define wxSTC_KIX_IDENTIFIER 31
    +
    +// Lexical states for SCLEX_GUI4CLI
    +#define wxSTC_GC_DEFAULT 0
    +#define wxSTC_GC_COMMENTLINE 1
    +#define wxSTC_GC_COMMENTBLOCK 2
    +#define wxSTC_GC_GLOBAL 3
    +#define wxSTC_GC_EVENT 4
    +#define wxSTC_GC_ATTRIBUTE 5
    +#define wxSTC_GC_CONTROL 6
    +#define wxSTC_GC_COMMAND 7
    +#define wxSTC_GC_STRING 8
    +#define wxSTC_GC_OPERATOR 9
    +
    +// Lexical states for SCLEX_SPECMAN
    +#define wxSTC_SN_DEFAULT 0
    +#define wxSTC_SN_CODE 1
    +#define wxSTC_SN_COMMENTLINE 2
    +#define wxSTC_SN_COMMENTLINEBANG 3
    +#define wxSTC_SN_NUMBER 4
    +#define wxSTC_SN_WORD 5
    +#define wxSTC_SN_STRING 6
    +#define wxSTC_SN_WORD2 7
    +#define wxSTC_SN_WORD3 8
    +#define wxSTC_SN_PREPROCESSOR 9
    +#define wxSTC_SN_OPERATOR 10
    +#define wxSTC_SN_IDENTIFIER 11
    +#define wxSTC_SN_STRINGEOL 12
    +#define wxSTC_SN_REGEXTAG 13
    +#define wxSTC_SN_SIGNAL 14
    +#define wxSTC_SN_USER 19
    +
    +// Lexical states for SCLEX_AU3
    +#define wxSTC_AU3_DEFAULT 0
    +#define wxSTC_AU3_COMMENT 1
    +#define wxSTC_AU3_COMMENTBLOCK 2
    +#define wxSTC_AU3_NUMBER 3
    +#define wxSTC_AU3_FUNCTION 4
    +#define wxSTC_AU3_KEYWORD 5
    +#define wxSTC_AU3_MACRO 6
    +#define wxSTC_AU3_STRING 7
    +#define wxSTC_AU3_OPERATOR 8
    +#define wxSTC_AU3_VARIABLE 9
    +#define wxSTC_AU3_SENT 10
    +#define wxSTC_AU3_PREPROCESSOR 11
    +#define wxSTC_AU3_SPECIAL 12
    +#define wxSTC_AU3_EXPAND 13
    +#define wxSTC_AU3_COMOBJ 14
    +
    +// Lexical states for SCLEX_APDL
    +#define wxSTC_APDL_DEFAULT 0
    +#define wxSTC_APDL_COMMENT 1
    +#define wxSTC_APDL_COMMENTBLOCK 2
    +#define wxSTC_APDL_NUMBER 3
    +#define wxSTC_APDL_STRING 4
    +#define wxSTC_APDL_OPERATOR 5
    +#define wxSTC_APDL_WORD 6
    +#define wxSTC_APDL_PROCESSOR 7
    +#define wxSTC_APDL_COMMAND 8
    +#define wxSTC_APDL_SLASHCOMMAND 9
    +#define wxSTC_APDL_STARCOMMAND 10
    +#define wxSTC_APDL_ARGUMENT 11
    +#define wxSTC_APDL_FUNCTION 12
    +
    +// Lexical states for SCLEX_BASH
    +#define wxSTC_SH_DEFAULT 0
    +#define wxSTC_SH_ERROR 1
    +#define wxSTC_SH_COMMENTLINE 2
    +#define wxSTC_SH_NUMBER 3
    +#define wxSTC_SH_WORD 4
    +#define wxSTC_SH_STRING 5
    +#define wxSTC_SH_CHARACTER 6
    +#define wxSTC_SH_OPERATOR 7
    +#define wxSTC_SH_IDENTIFIER 8
    +#define wxSTC_SH_SCALAR 9
    +#define wxSTC_SH_PARAM 10
    +#define wxSTC_SH_BACKTICKS 11
    +#define wxSTC_SH_HERE_DELIM 12
    +#define wxSTC_SH_HERE_Q 13
    +
    +// Lexical states for SCLEX_ASN1
    +#define wxSTC_ASN1_DEFAULT 0
    +#define wxSTC_ASN1_COMMENT 1
    +#define wxSTC_ASN1_IDENTIFIER 2
    +#define wxSTC_ASN1_STRING 3
    +#define wxSTC_ASN1_OID 4
    +#define wxSTC_ASN1_SCALAR 5
    +#define wxSTC_ASN1_KEYWORD 6
    +#define wxSTC_ASN1_ATTRIBUTE 7
    +#define wxSTC_ASN1_DESCRIPTOR 8
    +#define wxSTC_ASN1_TYPE 9
    +#define wxSTC_ASN1_OPERATOR 10
    +
    +// Lexical states for SCLEX_VHDL
    +#define wxSTC_VHDL_DEFAULT 0
    +#define wxSTC_VHDL_COMMENT 1
    +#define wxSTC_VHDL_COMMENTLINEBANG 2
    +#define wxSTC_VHDL_NUMBER 3
    +#define wxSTC_VHDL_STRING 4
    +#define wxSTC_VHDL_OPERATOR 5
    +#define wxSTC_VHDL_IDENTIFIER 6
    +#define wxSTC_VHDL_STRINGEOL 7
    +#define wxSTC_VHDL_KEYWORD 8
    +#define wxSTC_VHDL_STDOPERATOR 9
    +#define wxSTC_VHDL_ATTRIBUTE 10
    +#define wxSTC_VHDL_STDFUNCTION 11
    +#define wxSTC_VHDL_STDPACKAGE 12
    +#define wxSTC_VHDL_STDTYPE 13
    +#define wxSTC_VHDL_USERWORD 14
    +
    +// Lexical states for SCLEX_CAML
    +#define wxSTC_CAML_DEFAULT 0
    +#define wxSTC_CAML_IDENTIFIER 1
    +#define wxSTC_CAML_TAGNAME 2
    +#define wxSTC_CAML_KEYWORD 3
    +#define wxSTC_CAML_KEYWORD2 4
    +#define wxSTC_CAML_KEYWORD3 5
    +#define wxSTC_CAML_LINENUM 6
    +#define wxSTC_CAML_OPERATOR 7
    +#define wxSTC_CAML_NUMBER 8
    +#define wxSTC_CAML_CHAR 9
    +#define wxSTC_CAML_STRING 11
    +#define wxSTC_CAML_COMMENT 12
    +#define wxSTC_CAML_COMMENT1 13
    +#define wxSTC_CAML_COMMENT2 14
    +#define wxSTC_CAML_COMMENT3 15
    +
    +// Lexical states for SCLEX_HASKELL
    +#define wxSTC_HA_DEFAULT 0
    +#define wxSTC_HA_IDENTIFIER 1
    +#define wxSTC_HA_KEYWORD 2
    +#define wxSTC_HA_NUMBER 3
    +#define wxSTC_HA_STRING 4
    +#define wxSTC_HA_CHARACTER 5
    +#define wxSTC_HA_CLASS 6
    +#define wxSTC_HA_MODULE 7
    +#define wxSTC_HA_CAPITAL 8
    +#define wxSTC_HA_DATA 9
    +#define wxSTC_HA_IMPORT 10
    +#define wxSTC_HA_OPERATOR 11
    +#define wxSTC_HA_INSTANCE 12
    +#define wxSTC_HA_COMMENTLINE 13
    +#define wxSTC_HA_COMMENTBLOCK 14
    +#define wxSTC_HA_COMMENTBLOCK2 15
    +#define wxSTC_HA_COMMENTBLOCK3 16
    +
    +// Lexical states of SCLEX_TADS3
    +#define wxSTC_T3_DEFAULT 0
    +#define wxSTC_T3_X_DEFAULT 1
    +#define wxSTC_T3_PREPROCESSOR 2
    +#define wxSTC_T3_BLOCK_COMMENT 3
    +#define wxSTC_T3_LINE_COMMENT 4
    +#define wxSTC_T3_OPERATOR 5
    +#define wxSTC_T3_KEYWORD 6
    +#define wxSTC_T3_NUMBER 7
    +#define wxSTC_T3_IDENTIFIER 8
    +#define wxSTC_T3_S_STRING 9
    +#define wxSTC_T3_D_STRING 10
    +#define wxSTC_T3_X_STRING 11
    +#define wxSTC_T3_LIB_DIRECTIVE 12
    +#define wxSTC_T3_MSG_PARAM 13
    +#define wxSTC_T3_HTML_TAG 14
    +#define wxSTC_T3_HTML_DEFAULT 15
    +#define wxSTC_T3_HTML_STRING 16
    +#define wxSTC_T3_USER1 17
    +#define wxSTC_T3_USER2 18
    +#define wxSTC_T3_USER3 19
    +
    +// Lexical states for SCLEX_REBOL
    +#define wxSTC_REBOL_DEFAULT 0
    +#define wxSTC_REBOL_COMMENTLINE 1
    +#define wxSTC_REBOL_COMMENTBLOCK 2
    +#define wxSTC_REBOL_PREFACE 3
    +#define wxSTC_REBOL_OPERATOR 4
    +#define wxSTC_REBOL_CHARACTER 5
    +#define wxSTC_REBOL_QUOTEDSTRING 6
    +#define wxSTC_REBOL_BRACEDSTRING 7
    +#define wxSTC_REBOL_NUMBER 8
    +#define wxSTC_REBOL_PAIR 9
    +#define wxSTC_REBOL_TUPLE 10
    +#define wxSTC_REBOL_BINARY 11
    +#define wxSTC_REBOL_MONEY 12
    +#define wxSTC_REBOL_ISSUE 13
    +#define wxSTC_REBOL_TAG 14
    +#define wxSTC_REBOL_FILE 15
    +#define wxSTC_REBOL_EMAIL 16
    +#define wxSTC_REBOL_URL 17
    +#define wxSTC_REBOL_DATE 18
    +#define wxSTC_REBOL_TIME 19
    +#define wxSTC_REBOL_IDENTIFIER 20
    +#define wxSTC_REBOL_WORD 21
    +#define wxSTC_REBOL_WORD2 22
    +#define wxSTC_REBOL_WORD3 23
    +#define wxSTC_REBOL_WORD4 24
    +#define wxSTC_REBOL_WORD5 25
    +#define wxSTC_REBOL_WORD6 26
    +#define wxSTC_REBOL_WORD7 27
    +#define wxSTC_REBOL_WORD8 28
    +
    +// Lexical states for SCLEX_SQL
    +#define wxSTC_SQL_DEFAULT 0
    +#define wxSTC_SQL_COMMENT 1
    +#define wxSTC_SQL_COMMENTLINE 2
    +#define wxSTC_SQL_COMMENTDOC 3
    +#define wxSTC_SQL_NUMBER 4
    +#define wxSTC_SQL_WORD 5
    +#define wxSTC_SQL_STRING 6
    +#define wxSTC_SQL_CHARACTER 7
    +#define wxSTC_SQL_SQLPLUS 8
    +#define wxSTC_SQL_SQLPLUS_PROMPT 9
    +#define wxSTC_SQL_OPERATOR 10
    +#define wxSTC_SQL_IDENTIFIER 11
    +#define wxSTC_SQL_SQLPLUS_COMMENT 13
    +#define wxSTC_SQL_COMMENTLINEDOC 15
    +#define wxSTC_SQL_WORD2 16
    +#define wxSTC_SQL_COMMENTDOCKEYWORD 17
    +#define wxSTC_SQL_COMMENTDOCKEYWORDERROR 18
    +#define wxSTC_SQL_USER1 19
    +#define wxSTC_SQL_USER2 20
    +#define wxSTC_SQL_USER3 21
    +#define wxSTC_SQL_USER4 22
    +#define wxSTC_SQL_QUOTEDIDENTIFIER 23
    +
    +// Lexical states for SCLEX_SMALLTALK
    +#define wxSTC_ST_DEFAULT 0
    +#define wxSTC_ST_STRING 1
    +#define wxSTC_ST_NUMBER 2
    +#define wxSTC_ST_COMMENT 3
    +#define wxSTC_ST_SYMBOL 4
    +#define wxSTC_ST_BINARY 5
    +#define wxSTC_ST_BOOL 6
    +#define wxSTC_ST_SELF 7
    +#define wxSTC_ST_SUPER 8
    +#define wxSTC_ST_NIL 9
    +#define wxSTC_ST_GLOBAL 10
    +#define wxSTC_ST_RETURN 11
    +#define wxSTC_ST_SPECIAL 12
    +#define wxSTC_ST_KWSEND 13
    +#define wxSTC_ST_ASSIGN 14
    +#define wxSTC_ST_CHARACTER 15
    +#define wxSTC_ST_SPEC_SEL 16
    +
    +// Lexical states for SCLEX_FLAGSHIP (clipper)
    +#define wxSTC_FS_DEFAULT 0
    +#define wxSTC_FS_COMMENT 1
    +#define wxSTC_FS_COMMENTLINE 2
    +#define wxSTC_FS_COMMENTDOC 3
    +#define wxSTC_FS_COMMENTLINEDOC 4
    +#define wxSTC_FS_COMMENTDOCKEYWORD 5
    +#define wxSTC_FS_COMMENTDOCKEYWORDERROR 6
    +#define wxSTC_FS_KEYWORD 7
    +#define wxSTC_FS_KEYWORD2 8
    +#define wxSTC_FS_KEYWORD3 9
    +#define wxSTC_FS_KEYWORD4 10
    +#define wxSTC_FS_NUMBER 11
    +#define wxSTC_FS_STRING 12
    +#define wxSTC_FS_PREPROCESSOR 13
    +#define wxSTC_FS_OPERATOR 14
    +#define wxSTC_FS_IDENTIFIER 15
    +#define wxSTC_FS_DATE 16
    +#define wxSTC_FS_STRINGEOL 17
    +#define wxSTC_FS_CONSTANT 18
    +#define wxSTC_FS_ASM 19
    +#define wxSTC_FS_LABEL 20
    +#define wxSTC_FS_ERROR 21
    +#define wxSTC_FS_HEXNUMBER 22
    +#define wxSTC_FS_BINNUMBER 23
    +
    +// Lexical states for SCLEX_CSOUND
    +#define wxSTC_CSOUND_DEFAULT 0
    +#define wxSTC_CSOUND_COMMENT 1
    +#define wxSTC_CSOUND_NUMBER 2
    +#define wxSTC_CSOUND_OPERATOR 3
    +#define wxSTC_CSOUND_INSTR 4
    +#define wxSTC_CSOUND_IDENTIFIER 5
    +#define wxSTC_CSOUND_OPCODE 6
    +#define wxSTC_CSOUND_HEADERSTMT 7
    +#define wxSTC_CSOUND_USERKEYWORD 8
    +#define wxSTC_CSOUND_COMMENTBLOCK 9
    +#define wxSTC_CSOUND_PARAM 10
    +#define wxSTC_CSOUND_ARATE_VAR 11
    +#define wxSTC_CSOUND_KRATE_VAR 12
    +#define wxSTC_CSOUND_IRATE_VAR 13
    +#define wxSTC_CSOUND_GLOBAL_VAR 14
    +#define wxSTC_CSOUND_STRINGEOL 15
    +
    +
    +//-----------------------------------------
    +// Commands that can be bound to keystrokes
    +
    +
    +// Redoes the next action on the undo history.
    +#define wxSTC_CMD_REDO 2011
    +
    +// Select all the text in the document.
    +#define wxSTC_CMD_SELECTALL 2013
    +
    +// Undo one action in the undo history.
    +#define wxSTC_CMD_UNDO 2176
    +
    +// Cut the selection to the clipboard.
    +#define wxSTC_CMD_CUT 2177
    +
    +// Copy the selection to the clipboard.
    +#define wxSTC_CMD_COPY 2178
    +
    +// Paste the contents of the clipboard into the document replacing the selection.
    +#define wxSTC_CMD_PASTE 2179
    +
    +// Clear the selection.
    +#define wxSTC_CMD_CLEAR 2180
    +
    +// Move caret down one line.
    +#define wxSTC_CMD_LINEDOWN 2300
    +
    +// Move caret down one line extending selection to new caret position.
    +#define wxSTC_CMD_LINEDOWNEXTEND 2301
    +
    +// Move caret up one line.
    +#define wxSTC_CMD_LINEUP 2302
    +
    +// Move caret up one line extending selection to new caret position.
    +#define wxSTC_CMD_LINEUPEXTEND 2303
    +
    +// Move caret left one character.
    +#define wxSTC_CMD_CHARLEFT 2304
    +
    +// Move caret left one character extending selection to new caret position.
    +#define wxSTC_CMD_CHARLEFTEXTEND 2305
    +
    +// Move caret right one character.
    +#define wxSTC_CMD_CHARRIGHT 2306
    +
    +// Move caret right one character extending selection to new caret position.
    +#define wxSTC_CMD_CHARRIGHTEXTEND 2307
    +
    +// Move caret left one word.
    +#define wxSTC_CMD_WORDLEFT 2308
    +
    +// Move caret left one word extending selection to new caret position.
    +#define wxSTC_CMD_WORDLEFTEXTEND 2309
    +
    +// Move caret right one word.
    +#define wxSTC_CMD_WORDRIGHT 2310
    +
    +// Move caret right one word extending selection to new caret position.
    +#define wxSTC_CMD_WORDRIGHTEXTEND 2311
    +
    +// Move caret to first position on line.
    +#define wxSTC_CMD_HOME 2312
    +
    +// Move caret to first position on line extending selection to new caret position.
    +#define wxSTC_CMD_HOMEEXTEND 2313
    +
    +// Move caret to last position on line.
    +#define wxSTC_CMD_LINEEND 2314
    +
    +// Move caret to last position on line extending selection to new caret position.
    +#define wxSTC_CMD_LINEENDEXTEND 2315
    +
    +// Move caret to first position in document.
    +#define wxSTC_CMD_DOCUMENTSTART 2316
    +
    +// Move caret to first position in document extending selection to new caret position.
    +#define wxSTC_CMD_DOCUMENTSTARTEXTEND 2317
    +
    +// Move caret to last position in document.
    +#define wxSTC_CMD_DOCUMENTEND 2318
    +
    +// Move caret to last position in document extending selection to new caret position.
    +#define wxSTC_CMD_DOCUMENTENDEXTEND 2319
    +
    +// Move caret one page up.
    +#define wxSTC_CMD_PAGEUP 2320
    +
    +// Move caret one page up extending selection to new caret position.
    +#define wxSTC_CMD_PAGEUPEXTEND 2321
    +
    +// Move caret one page down.
    +#define wxSTC_CMD_PAGEDOWN 2322
    +
    +// Move caret one page down extending selection to new caret position.
    +#define wxSTC_CMD_PAGEDOWNEXTEND 2323
    +
    +// Switch from insert to overtype mode or the reverse.
    +#define wxSTC_CMD_EDITTOGGLEOVERTYPE 2324
    +
    +// Cancel any modes such as call tip or auto-completion list display.
    +#define wxSTC_CMD_CANCEL 2325
    +
    +// Delete the selection or if no selection, the character before the caret.
    +#define wxSTC_CMD_DELETEBACK 2326
    +
    +// If selection is empty or all on one line replace the selection with a tab character.
    +// If more than one line selected, indent the lines.
    +#define wxSTC_CMD_TAB 2327
    +
    +// Dedent the selected lines.
    +#define wxSTC_CMD_BACKTAB 2328
    +
    +// Insert a new line, may use a CRLF, CR or LF depending on EOL mode.
    +#define wxSTC_CMD_NEWLINE 2329
    +
    +// Insert a Form Feed character.
    +#define wxSTC_CMD_FORMFEED 2330
    +
    +// Move caret to before first visible character on line.
    +// If already there move to first character on line.
    +#define wxSTC_CMD_VCHOME 2331
    +
    +// Like VCHome but extending selection to new caret position.
    +#define wxSTC_CMD_VCHOMEEXTEND 2332
    +
    +// Magnify the displayed text by increasing the sizes by 1 point.
    +#define wxSTC_CMD_ZOOMIN 2333
    +
    +// Make the displayed text smaller by decreasing the sizes by 1 point.
    +#define wxSTC_CMD_ZOOMOUT 2334
    +
    +// Delete the word to the left of the caret.
    +#define wxSTC_CMD_DELWORDLEFT 2335
    +
    +// Delete the word to the right of the caret.
    +#define wxSTC_CMD_DELWORDRIGHT 2336
    +
    +// Cut the line containing the caret.
    +#define wxSTC_CMD_LINECUT 2337
    +
    +// Delete the line containing the caret.
    +#define wxSTC_CMD_LINEDELETE 2338
    +
    +// Switch the current line with the previous.
    +#define wxSTC_CMD_LINETRANSPOSE 2339
    +
    +// Duplicate the current line.
    +#define wxSTC_CMD_LINEDUPLICATE 2404
    +
    +// Transform the selection to lower case.
    +#define wxSTC_CMD_LOWERCASE 2340
    +
    +// Transform the selection to upper case.
    +#define wxSTC_CMD_UPPERCASE 2341
    +
    +// Scroll the document down, keeping the caret visible.
    +#define wxSTC_CMD_LINESCROLLDOWN 2342
    +
    +// Scroll the document up, keeping the caret visible.
    +#define wxSTC_CMD_LINESCROLLUP 2343
    +
    +// Delete the selection or if no selection, the character before the caret.
    +// Will not delete the character before at the start of a line.
    +#define wxSTC_CMD_DELETEBACKNOTLINE 2344
    +
    +// Move caret to first position on display line.
    +#define wxSTC_CMD_HOMEDISPLAY 2345
    +
    +// Move caret to first position on display line extending selection to
    +// new caret position.
    +#define wxSTC_CMD_HOMEDISPLAYEXTEND 2346
    +
    +// Move caret to last position on display line.
    +#define wxSTC_CMD_LINEENDDISPLAY 2347
    +
    +// Move caret to last position on display line extending selection to new
    +// caret position.
    +#define wxSTC_CMD_LINEENDDISPLAYEXTEND 2348
    +
    +// These are like their namesakes Home(Extend)?, LineEnd(Extend)?, VCHome(Extend)?
    +// except they behave differently when word-wrap is enabled:
    +// They go first to the start / end of the display line, like (Home|LineEnd)Display
    +// The difference is that, the cursor is already at the point, it goes on to the start
    +// or end of the document line, as appropriate for (Home|LineEnd|VCHome)(Extend)?.
    +#define wxSTC_CMD_HOMEWRAP 2349
    +#define wxSTC_CMD_HOMEWRAPEXTEND 2450
    +#define wxSTC_CMD_LINEENDWRAP 2451
    +#define wxSTC_CMD_LINEENDWRAPEXTEND 2452
    +#define wxSTC_CMD_VCHOMEWRAP 2453
    +#define wxSTC_CMD_VCHOMEWRAPEXTEND 2454
    +
    +// Copy the line containing the caret.
    +#define wxSTC_CMD_LINECOPY 2455
    +
    +// Move to the previous change in capitalisation.
    +#define wxSTC_CMD_WORDPARTLEFT 2390
    +
    +// Move to the previous change in capitalisation extending selection
    +// to new caret position.
    +#define wxSTC_CMD_WORDPARTLEFTEXTEND 2391
    +
    +// Move to the change next in capitalisation.
    +#define wxSTC_CMD_WORDPARTRIGHT 2392
    +
    +// Move to the next change in capitalisation extending selection
    +// to new caret position.
    +#define wxSTC_CMD_WORDPARTRIGHTEXTEND 2393
    +
    +// Delete back from the current position to the start of the line.
    +#define wxSTC_CMD_DELLINELEFT 2395
    +
    +// Delete forwards from the current position to the end of the line.
    +#define wxSTC_CMD_DELLINERIGHT 2396
    +
    +// Move caret between paragraphs (delimited by empty lines).
    +#define wxSTC_CMD_PARADOWN 2413
    +#define wxSTC_CMD_PARADOWNEXTEND 2414
    +#define wxSTC_CMD_PARAUP 2415
    +#define wxSTC_CMD_PARAUPEXTEND 2416
    +
    +// Move caret down one line, extending rectangular selection to new caret position.
    +#define wxSTC_CMD_LINEDOWNRECTEXTEND 2426
    +
    +// Move caret up one line, extending rectangular selection to new caret position.
    +#define wxSTC_CMD_LINEUPRECTEXTEND 2427
    +
    +// Move caret left one character, extending rectangular selection to new caret position.
    +#define wxSTC_CMD_CHARLEFTRECTEXTEND 2428
    +
    +// Move caret right one character, extending rectangular selection to new caret position.
    +#define wxSTC_CMD_CHARRIGHTRECTEXTEND 2429
    +
    +// Move caret to first position on line, extending rectangular selection to new caret position.
    +#define wxSTC_CMD_HOMERECTEXTEND 2430
    +
    +// Move caret to before first visible character on line.
    +// If already there move to first character on line.
    +// In either case, extend rectangular selection to new caret position.
    +#define wxSTC_CMD_VCHOMERECTEXTEND 2431
    +
    +// Move caret to last position on line, extending rectangular selection to new caret position.
    +#define wxSTC_CMD_LINEENDRECTEXTEND 2432
    +
    +// Move caret one page up, extending rectangular selection to new caret position.
    +#define wxSTC_CMD_PAGEUPRECTEXTEND 2433
    +
    +// Move caret one page down, extending rectangular selection to new caret position.
    +#define wxSTC_CMD_PAGEDOWNRECTEXTEND 2434
    +
    +// Move caret to top of page, or one page up if already at top of page.
    +#define wxSTC_CMD_STUTTEREDPAGEUP 2435
    +
    +// Move caret to top of page, or one page up if already at top of page, extending selection to new caret position.
    +#define wxSTC_CMD_STUTTEREDPAGEUPEXTEND 2436
    +
    +// Move caret to bottom of page, or one page down if already at bottom of page.
    +#define wxSTC_CMD_STUTTEREDPAGEDOWN 2437
    +
    +// Move caret to bottom of page, or one page down if already at bottom of page, extending selection to new caret position.
    +#define wxSTC_CMD_STUTTEREDPAGEDOWNEXTEND 2438
    +
    +// Move caret left one word, position cursor at end of word.
    +#define wxSTC_CMD_WORDLEFTEND 2439
    +
    +// Move caret left one word, position cursor at end of word, extending selection to new caret position.
    +#define wxSTC_CMD_WORDLEFTENDEXTEND 2440
    +
    +// Move caret right one word, position cursor at end of word.
    +#define wxSTC_CMD_WORDRIGHTEND 2441
    +
    +// Move caret right one word, position cursor at end of word, extending selection to new caret position.
    +#define wxSTC_CMD_WORDRIGHTENDEXTEND 2442
    +
    +
    +// END of generated section
    +//----------------------------------------------------------------------
    +
    +class  ScintillaWX;                      // forward declare
    +class  WordList;
    +struct SCNotification;
    +
    +#ifndef SWIG
    +extern WXDLLIMPEXP_STC const wxChar* wxSTCNameStr;
    +class  WXDLLIMPEXP_STC wxStyledTextCtrl;
    +class  WXDLLIMPEXP_STC wxStyledTextEvent;
    +#endif
    +
    +//----------------------------------------------------------------------
    +
    +class WXDLLIMPEXP_STC wxStyledTextCtrl : public wxControl {
    +public:
    +
    +#ifdef SWIG
    +    %pythonAppend wxStyledTextCtrl   "self._setOORInfo(self)"
    +    %pythonAppend wxStyledTextCtrl() ""
    +
    +    wxStyledTextCtrl(wxWindow *parent, wxWindowID id=wxID_ANY,
    +                     const wxPoint& pos = wxDefaultPosition,
    +                     const wxSize& size = wxDefaultSize, long style = 0,
    +                     const wxString& name = wxPySTCNameStr);
    +    %RenameCtor(PreStyledTextCtrl,  wxStyledTextCtrl());
    +
    +#else
    +    wxStyledTextCtrl(wxWindow *parent, wxWindowID id=wxID_ANY,
    +                     const wxPoint& pos = wxDefaultPosition,
    +                     const wxSize& size = wxDefaultSize, long style = 0,
    +                     const wxString& name = wxSTCNameStr);
    +    wxStyledTextCtrl() { m_swx = NULL; }
    +    ~wxStyledTextCtrl();
    +
    +#endif
    +
    +    bool Create(wxWindow *parent, wxWindowID id=wxID_ANY,
    +                const wxPoint& pos = wxDefaultPosition,
    +                const wxSize& size = wxDefaultSize, long style = 0,
    +                const wxString& name = wxSTCNameStr);
    +
    +
    +//----------------------------------------------------------------------
    +// BEGIN generated section.  The following code is automatically generated
    +//       by gen_iface.py.  Do not edit this file.  Edit stc.h.in instead
    +//       and regenerate
    +
    +
    +    // Add text to the document at current position.
    +    void AddText(const wxString& text);
    +
    +    // Add array of cells to document.
    +    void AddStyledText(const wxMemoryBuffer& data);
    +
    +    // Insert string at a position.
    +    void InsertText(int pos, const wxString& text);
    +
    +    // Delete all text in the document.
    +    void ClearAll();
    +
    +    // Set all style bytes to 0, remove all folding information.
    +    void ClearDocumentStyle();
    +
    +    // Returns the number of characters in the document.
    +    int GetLength();
    +
    +    // Returns the character byte at the position.
    +    int GetCharAt(int pos);
    +
    +    // Returns the position of the caret.
    +    int GetCurrentPos();
    +
    +    // Returns the position of the opposite end of the selection to the caret.
    +    int GetAnchor();
    +
    +    // Returns the style byte at the position.
    +    int GetStyleAt(int pos);
    +
    +    // Redoes the next action on the undo history.
    +    void Redo();
    +
    +    // Choose between collecting actions into the undo
    +    // history and discarding them.
    +    void SetUndoCollection(bool collectUndo);
    +
    +    // Select all the text in the document.
    +    void SelectAll();
    +
    +    // Remember the current position in the undo history as the position
    +    // at which the document was saved.
    +    void SetSavePoint();
    +
    +    // Retrieve a buffer of cells.
    +    wxMemoryBuffer GetStyledText(int startPos, int endPos);
    +
    +    // Are there any redoable actions in the undo history?
    +    bool CanRedo();
    +
    +    // Retrieve the line number at which a particular marker is located.
    +    int MarkerLineFromHandle(int handle);
    +
    +    // Delete a marker.
    +    void MarkerDeleteHandle(int handle);
    +
    +    // Is undo history being collected?
    +    bool GetUndoCollection();
    +
    +    // Are white space characters currently visible?
    +    // Returns one of SCWS_* constants.
    +    int GetViewWhiteSpace();
    +
    +    // Make white space characters invisible, always visible or visible outside indentation.
    +    void SetViewWhiteSpace(int viewWS);
    +
    +    // Find the position from a point within the window.
    +    int PositionFromPoint(wxPoint pt);
    +
    +    // Find the position from a point within the window but return
    +    // INVALID_POSITION if not close to text.
    +    int PositionFromPointClose(int x, int y);
    +
    +    // Set caret to start of a line and ensure it is visible.
    +    void GotoLine(int line);
    +
    +    // Set caret to a position and ensure it is visible.
    +    void GotoPos(int pos);
    +
    +    // Set the selection anchor to a position. The anchor is the opposite
    +    // end of the selection from the caret.
    +    void SetAnchor(int posAnchor);
    +
    +    // Retrieve the text of the line containing the caret.
    +    // Returns the index of the caret on the line.
    +    #ifdef SWIG
    +    wxString GetCurLine(int* OUTPUT);
    +#else
    +    wxString GetCurLine(int* linePos=NULL);
    +#endif
    +
    +    // Retrieve the position of the last correctly styled character.
    +    int GetEndStyled();
    +
    +    // Convert all line endings in the document to one mode.
    +    void ConvertEOLs(int eolMode);
    +
    +    // Retrieve the current end of line mode - one of CRLF, CR, or LF.
    +    int GetEOLMode();
    +
    +    // Set the current end of line mode.
    +    void SetEOLMode(int eolMode);
    +
    +    // Set the current styling position to pos and the styling mask to mask.
    +    // The styling mask can be used to protect some bits in each styling byte from modification.
    +    void StartStyling(int pos, int mask);
    +
    +    // Change style from current styling position for length characters to a style
    +    // and move the current styling position to after this newly styled segment.
    +    void SetStyling(int length, int style);
    +
    +    // Is drawing done first into a buffer or direct to the screen?
    +    bool GetBufferedDraw();
    +
    +    // If drawing is buffered then each line of text is drawn into a bitmap buffer
    +    // before drawing it to the screen to avoid flicker.
    +    void SetBufferedDraw(bool buffered);
    +
    +    // Change the visible size of a tab to be a multiple of the width of a space character.
    +    void SetTabWidth(int tabWidth);
    +
    +    // Retrieve the visible size of a tab.
    +    int GetTabWidth();
    +
    +    // Set the code page used to interpret the bytes of the document as characters.
    +    void SetCodePage(int codePage);
    +
    +    // Set the symbol used for a particular marker number,
    +    // and optionally the fore and background colours.
    +    void MarkerDefine(int markerNumber, int markerSymbol,
    +                const wxColour& foreground = wxNullColour,
    +                const wxColour& background = wxNullColour);
    +
    +    // Set the foreground colour used for a particular marker number.
    +    void MarkerSetForeground(int markerNumber, const wxColour& fore);
    +
    +    // Set the background colour used for a particular marker number.
    +    void MarkerSetBackground(int markerNumber, const wxColour& back);
    +
    +    // Add a marker to a line, returning an ID which can be used to find or delete the marker.
    +    int MarkerAdd(int line, int markerNumber);
    +
    +    // Delete a marker from a line.
    +    void MarkerDelete(int line, int markerNumber);
    +
    +    // Delete all markers with a particular number from all lines.
    +    void MarkerDeleteAll(int markerNumber);
    +
    +    // Get a bit mask of all the markers set on a line.
    +    int MarkerGet(int line);
    +
    +    // Find the next line after lineStart that includes a marker in mask.
    +    int MarkerNext(int lineStart, int markerMask);
    +
    +    // Find the previous line before lineStart that includes a marker in mask.
    +    int MarkerPrevious(int lineStart, int markerMask);
    +
    +    // Define a marker from a bitmap
    +    void MarkerDefineBitmap(int markerNumber, const wxBitmap& bmp);
    +
    +    // Add a set of markers to a line.
    +    void MarkerAddSet(int line, int set);
    +
    +    // Set a margin to be either numeric or symbolic.
    +    void SetMarginType(int margin, int marginType);
    +
    +    // Retrieve the type of a margin.
    +    int GetMarginType(int margin);
    +
    +    // Set the width of a margin to a width expressed in pixels.
    +    void SetMarginWidth(int margin, int pixelWidth);
    +
    +    // Retrieve the width of a margin in pixels.
    +    int GetMarginWidth(int margin);
    +
    +    // Set a mask that determines which markers are displayed in a margin.
    +    void SetMarginMask(int margin, int mask);
    +
    +    // Retrieve the marker mask of a margin.
    +    int GetMarginMask(int margin);
    +
    +    // Make a margin sensitive or insensitive to mouse clicks.
    +    void SetMarginSensitive(int margin, bool sensitive);
    +
    +    // Retrieve the mouse click sensitivity of a margin.
    +    bool GetMarginSensitive(int margin);
    +
    +    // Clear all the styles and make equivalent to the global default style.
    +    void StyleClearAll();
    +
    +    // Set the foreground colour of a style.
    +    void StyleSetForeground(int style, const wxColour& fore);
    +
    +    // Set the background colour of a style.
    +    void StyleSetBackground(int style, const wxColour& back);
    +
    +    // Set a style to be bold or not.
    +    void StyleSetBold(int style, bool bold);
    +
    +    // Set a style to be italic or not.
    +    void StyleSetItalic(int style, bool italic);
    +
    +    // Set the size of characters of a style.
    +    void StyleSetSize(int style, int sizePoints);
    +
    +    // Set the font of a style.
    +    void StyleSetFaceName(int style, const wxString& fontName);
    +
    +    // Set a style to have its end of line filled or not.
    +    void StyleSetEOLFilled(int style, bool filled);
    +
    +    // Reset the default style to its state at startup
    +    void StyleResetDefault();
    +
    +    // Set a style to be underlined or not.
    +    void StyleSetUnderline(int style, bool underline);
    +
    +    // Set a style to be mixed case, or to force upper or lower case.
    +    void StyleSetCase(int style, int caseForce);
    +
    +    // Set a style to be a hotspot or not.
    +    void StyleSetHotSpot(int style, bool hotspot);
    +
    +    // Set the foreground colour of the selection and whether to use this setting.
    +    void SetSelForeground(bool useSetting, const wxColour& fore);
    +
    +    // Set the background colour of the selection and whether to use this setting.
    +    void SetSelBackground(bool useSetting, const wxColour& back);
    +
    +    // Set the foreground colour of the caret.
    +    void SetCaretForeground(const wxColour& fore);
    +
    +    // When key+modifier combination km is pressed perform msg.
    +    void CmdKeyAssign(int key, int modifiers, int cmd);
    +
    +    // When key+modifier combination km is pressed do nothing.
    +    void CmdKeyClear(int key, int modifiers);
    +
    +    // Drop all key mappings.
    +    void CmdKeyClearAll();
    +
    +    // Set the styles for a segment of the document.
    +    void SetStyleBytes(int length, char* styleBytes);
    +
    +    // Set a style to be visible or not.
    +    void StyleSetVisible(int style, bool visible);
    +
    +    // Get the time in milliseconds that the caret is on and off.
    +    int GetCaretPeriod();
    +
    +    // Get the time in milliseconds that the caret is on and off. 0 = steady on.
    +    void SetCaretPeriod(int periodMilliseconds);
    +
    +    // Set the set of characters making up words for when moving or selecting by word.
    +    // First sets deaults like SetCharsDefault.
    +    void SetWordChars(const wxString& characters);
    +
    +    // Start a sequence of actions that is undone and redone as a unit.
    +    // May be nested.
    +    void BeginUndoAction();
    +
    +    // End a sequence of actions that is undone and redone as a unit.
    +    void EndUndoAction();
    +
    +    // Set an indicator to plain, squiggle or TT.
    +    void IndicatorSetStyle(int indic, int style);
    +
    +    // Retrieve the style of an indicator.
    +    int IndicatorGetStyle(int indic);
    +
    +    // Set the foreground colour of an indicator.
    +    void IndicatorSetForeground(int indic, const wxColour& fore);
    +
    +    // Retrieve the foreground colour of an indicator.
    +    wxColour IndicatorGetForeground(int indic);
    +
    +    // Set the foreground colour of all whitespace and whether to use this setting.
    +    void SetWhitespaceForeground(bool useSetting, const wxColour& fore);
    +
    +    // Set the background colour of all whitespace and whether to use this setting.
    +    void SetWhitespaceBackground(bool useSetting, const wxColour& back);
    +
    +    // Divide each styling byte into lexical class bits (default: 5) and indicator
    +    // bits (default: 3). If a lexer requires more than 32 lexical states, then this
    +    // is used to expand the possible states.
    +    void SetStyleBits(int bits);
    +
    +    // Retrieve number of bits in style bytes used to hold the lexical state.
    +    int GetStyleBits();
    +
    +    // Used to hold extra styling information for each line.
    +    void SetLineState(int line, int state);
    +
    +    // Retrieve the extra styling information for a line.
    +    int GetLineState(int line);
    +
    +    // Retrieve the last line number that has line state.
    +    int GetMaxLineState();
    +
    +    // Is the background of the line containing the caret in a different colour?
    +    bool GetCaretLineVisible();
    +
    +    // Display the background of the line containing the caret in a different colour.
    +    void SetCaretLineVisible(bool show);
    +
    +    // Get the colour of the background of the line containing the caret.
    +    wxColour GetCaretLineBack();
    +
    +    // Set the colour of the background of the line containing the caret.
    +    void SetCaretLineBack(const wxColour& back);
    +
    +    // Set a style to be changeable or not (read only).
    +    // Experimental feature, currently buggy.
    +    void StyleSetChangeable(int style, bool changeable);
    +
    +    // Display a auto-completion list.
    +    // The lenEntered parameter indicates how many characters before
    +    // the caret should be used to provide context.
    +    void AutoCompShow(int lenEntered, const wxString& itemList);
    +
    +    // Remove the auto-completion list from the screen.
    +    void AutoCompCancel();
    +
    +    // Is there an auto-completion list visible?
    +    bool AutoCompActive();
    +
    +    // Retrieve the position of the caret when the auto-completion list was displayed.
    +    int AutoCompPosStart();
    +
    +    // User has selected an item so remove the list and insert the selection.
    +    void AutoCompComplete();
    +
    +    // Define a set of character that when typed cancel the auto-completion list.
    +    void AutoCompStops(const wxString& characterSet);
    +
    +    // Change the separator character in the string setting up an auto-completion list.
    +    // Default is space but can be changed if items contain space.
    +    void AutoCompSetSeparator(int separatorCharacter);
    +
    +    // Retrieve the auto-completion list separator character.
    +    int AutoCompGetSeparator();
    +
    +    // Select the item in the auto-completion list that starts with a string.
    +    void AutoCompSelect(const wxString& text);
    +
    +    // Should the auto-completion list be cancelled if the user backspaces to a
    +    // position before where the box was created.
    +    void AutoCompSetCancelAtStart(bool cancel);
    +
    +    // Retrieve whether auto-completion cancelled by backspacing before start.
    +    bool AutoCompGetCancelAtStart();
    +
    +    // Define a set of characters that when typed will cause the autocompletion to
    +    // choose the selected item.
    +    void AutoCompSetFillUps(const wxString& characterSet);
    +
    +    // Should a single item auto-completion list automatically choose the item.
    +    void AutoCompSetChooseSingle(bool chooseSingle);
    +
    +    // Retrieve whether a single item auto-completion list automatically choose the item.
    +    bool AutoCompGetChooseSingle();
    +
    +    // Set whether case is significant when performing auto-completion searches.
    +    void AutoCompSetIgnoreCase(bool ignoreCase);
    +
    +    // Retrieve state of ignore case flag.
    +    bool AutoCompGetIgnoreCase();
    +
    +    // Display a list of strings and send notification when user chooses one.
    +    void UserListShow(int listType, const wxString& itemList);
    +
    +    // Set whether or not autocompletion is hidden automatically when nothing matches.
    +    void AutoCompSetAutoHide(bool autoHide);
    +
    +    // Retrieve whether or not autocompletion is hidden automatically when nothing matches.
    +    bool AutoCompGetAutoHide();
    +
    +    // Set whether or not autocompletion deletes any word characters
    +    // after the inserted text upon completion.
    +    void AutoCompSetDropRestOfWord(bool dropRestOfWord);
    +
    +    // Retrieve whether or not autocompletion deletes any word characters
    +    // after the inserted text upon completion.
    +    bool AutoCompGetDropRestOfWord();
    +
    +    // Register an image for use in autocompletion lists.
    +    void RegisterImage(int type, const wxBitmap& bmp);
    +
    +    // Clear all the registered images.
    +    void ClearRegisteredImages();
    +
    +    // Retrieve the auto-completion list type-separator character.
    +    int AutoCompGetTypeSeparator();
    +
    +    // Change the type-separator character in the string setting up an auto-completion list.
    +    // Default is '?' but can be changed if items contain '?'.
    +    void AutoCompSetTypeSeparator(int separatorCharacter);
    +
    +    // Set the maximum width, in characters, of auto-completion and user lists.
    +    // Set to 0 to autosize to fit longest item, which is the default.
    +    void AutoCompSetMaxWidth(int characterCount);
    +
    +    // Get the maximum width, in characters, of auto-completion and user lists.
    +    int AutoCompGetMaxWidth();
    +
    +    // Set the maximum height, in rows, of auto-completion and user lists.
    +    // The default is 5 rows.
    +    void AutoCompSetMaxHeight(int rowCount);
    +
    +    // Set the maximum height, in rows, of auto-completion and user lists.
    +    int AutoCompGetMaxHeight();
    +
    +    // Set the number of spaces used for one level of indentation.
    +    void SetIndent(int indentSize);
    +
    +    // Retrieve indentation size.
    +    int GetIndent();
    +
    +    // Indentation will only use space characters if useTabs is false, otherwise
    +    // it will use a combination of tabs and spaces.
    +    void SetUseTabs(bool useTabs);
    +
    +    // Retrieve whether tabs will be used in indentation.
    +    bool GetUseTabs();
    +
    +    // Change the indentation of a line to a number of columns.
    +    void SetLineIndentation(int line, int indentSize);
    +
    +    // Retrieve the number of columns that a line is indented.
    +    int GetLineIndentation(int line);
    +
    +    // Retrieve the position before the first non indentation character on a line.
    +    int GetLineIndentPosition(int line);
    +
    +    // Retrieve the column number of a position, taking tab width into account.
    +    int GetColumn(int pos);
    +
    +    // Show or hide the horizontal scroll bar.
    +    void SetUseHorizontalScrollBar(bool show);
    +
    +    // Is the horizontal scroll bar visible?
    +    bool GetUseHorizontalScrollBar();
    +
    +    // Show or hide indentation guides.
    +    void SetIndentationGuides(bool show);
    +
    +    // Are the indentation guides visible?
    +    bool GetIndentationGuides();
    +
    +    // Set the highlighted indentation guide column.
    +    // 0 = no highlighted guide.
    +    void SetHighlightGuide(int column);
    +
    +    // Get the highlighted indentation guide column.
    +    int GetHighlightGuide();
    +
    +    // Get the position after the last visible characters on a line.
    +    int GetLineEndPosition(int line);
    +
    +    // Get the code page used to interpret the bytes of the document as characters.
    +    int GetCodePage();
    +
    +    // Get the foreground colour of the caret.
    +    wxColour GetCaretForeground();
    +
    +    // In read-only mode?
    +    bool GetReadOnly();
    +
    +    // Sets the position of the caret.
    +    void SetCurrentPos(int pos);
    +
    +    // Sets the position that starts the selection - this becomes the anchor.
    +    void SetSelectionStart(int pos);
    +
    +    // Returns the position at the start of the selection.
    +    int GetSelectionStart();
    +
    +    // Sets the position that ends the selection - this becomes the currentPosition.
    +    void SetSelectionEnd(int pos);
    +
    +    // Returns the position at the end of the selection.
    +    int GetSelectionEnd();
    +
    +    // Sets the print magnification added to the point size of each style for printing.
    +    void SetPrintMagnification(int magnification);
    +
    +    // Returns the print magnification.
    +    int GetPrintMagnification();
    +
    +    // Modify colours when printing for clearer printed text.
    +    void SetPrintColourMode(int mode);
    +
    +    // Returns the print colour mode.
    +    int GetPrintColourMode();
    +
    +    // Find some text in the document.
    +    int FindText(int minPos, int maxPos, const wxString& text, int flags=0);
    +
    +    // On Windows, will draw the document into a display context such as a printer.
    +    int FormatRange(bool   doDraw,
    +               int    startPos,
    +               int    endPos,
    +               wxDC*  draw,
    +               wxDC*  target,
    +               wxRect renderRect,
    +               wxRect pageRect);
    +
    +    // Retrieve the display line at the top of the display.
    +    int GetFirstVisibleLine();
    +
    +    // Retrieve the contents of a line.
    +    wxString GetLine(int line);
    +
    +    // Returns the number of lines in the document. There is always at least one.
    +    int GetLineCount();
    +
    +    // Sets the size in pixels of the left margin.
    +    void SetMarginLeft(int pixelWidth);
    +
    +    // Returns the size in pixels of the left margin.
    +    int GetMarginLeft();
    +
    +    // Sets the size in pixels of the right margin.
    +    void SetMarginRight(int pixelWidth);
    +
    +    // Returns the size in pixels of the right margin.
    +    int GetMarginRight();
    +
    +    // Is the document different from when it was last saved?
    +    bool GetModify();
    +
    +    // Select a range of text.
    +    void SetSelection(int start, int end);
    +
    +    // Retrieve the selected text.
    +    wxString GetSelectedText();
    +
    +    // Retrieve a range of text.
    +    wxString GetTextRange(int startPos, int endPos);
    +
    +    // Draw the selection in normal style or with selection highlighted.
    +    void HideSelection(bool normal);
    +
    +    // Retrieve the line containing a position.
    +    int LineFromPosition(int pos);
    +
    +    // Retrieve the position at the start of a line.
    +    int PositionFromLine(int line);
    +
    +    // Scroll horizontally and vertically.
    +    void LineScroll(int columns, int lines);
    +
    +    // Ensure the caret is visible.
    +    void EnsureCaretVisible();
    +
    +    // Replace the selected text with the argument text.
    +    void ReplaceSelection(const wxString& text);
    +
    +    // Set to read only or read write.
    +    void SetReadOnly(bool readOnly);
    +
    +    // Will a paste succeed?
    +    bool CanPaste();
    +
    +    // Are there any undoable actions in the undo history?
    +    bool CanUndo();
    +
    +    // Delete the undo history.
    +    void EmptyUndoBuffer();
    +
    +    // Undo one action in the undo history.
    +    void Undo();
    +
    +    // Cut the selection to the clipboard.
    +    void Cut();
    +
    +    // Copy the selection to the clipboard.
    +    void Copy();
    +
    +    // Paste the contents of the clipboard into the document replacing the selection.
    +    void Paste();
    +
    +    // Clear the selection.
    +    void Clear();
    +
    +    // Replace the contents of the document with the argument text.
    +    void SetText(const wxString& text);
    +
    +    // Retrieve all the text in the document.
    +    wxString GetText();
    +
    +    // Retrieve the number of characters in the document.
    +    int GetTextLength();
    +
    +    // Set to overtype (true) or insert mode.
    +    void SetOvertype(bool overtype);
    +
    +    // Returns true if overtype mode is active otherwise false is returned.
    +    bool GetOvertype();
    +
    +    // Set the width of the insert mode caret.
    +    void SetCaretWidth(int pixelWidth);
    +
    +    // Returns the width of the insert mode caret.
    +    int GetCaretWidth();
    +
    +    // Sets the position that starts the target which is used for updating the
    +    // document without affecting the scroll position.
    +    void SetTargetStart(int pos);
    +
    +    // Get the position that starts the target.
    +    int GetTargetStart();
    +
    +    // Sets the position that ends the target which is used for updating the
    +    // document without affecting the scroll position.
    +    void SetTargetEnd(int pos);
    +
    +    // Get the position that ends the target.
    +    int GetTargetEnd();
    +
    +    // Replace the target text with the argument text.
    +    // Text is counted so it can contain NULs.
    +    // Returns the length of the replacement text.
    +    int ReplaceTarget(const wxString& text);
    +
    +    // Replace the target text with the argument text after \d processing.
    +    // Text is counted so it can contain NULs.
    +    // Looks for \d where d is between 1 and 9 and replaces these with the strings
    +    // matched in the last search operation which were surrounded by \( and \).
    +    // Returns the length of the replacement text including any change
    +    // caused by processing the \d patterns.
    +    int ReplaceTargetRE(const wxString& text);
    +
    +    // Search for a counted string in the target and set the target to the found
    +    // range. Text is counted so it can contain NULs.
    +    // Returns length of range or -1 for failure in which case target is not moved.
    +    int SearchInTarget(const wxString& text);
    +
    +    // Set the search flags used by SearchInTarget.
    +    void SetSearchFlags(int flags);
    +
    +    // Get the search flags used by SearchInTarget.
    +    int GetSearchFlags();
    +
    +    // Show a call tip containing a definition near position pos.
    +    void CallTipShow(int pos, const wxString& definition);
    +
    +    // Remove the call tip from the screen.
    +    void CallTipCancel();
    +
    +    // Is there an active call tip?
    +    bool CallTipActive();
    +
    +    // Retrieve the position where the caret was before displaying the call tip.
    +    int CallTipPosAtStart();
    +
    +    // Highlight a segment of the definition.
    +    void CallTipSetHighlight(int start, int end);
    +
    +    // Set the background colour for the call tip.
    +    void CallTipSetBackground(const wxColour& back);
    +
    +    // Set the foreground colour for the call tip.
    +    void CallTipSetForeground(const wxColour& fore);
    +
    +    // Set the foreground colour for the highlighted part of the call tip.
    +    void CallTipSetForegroundHighlight(const wxColour& fore);
    +
    +    // Find the display line of a document line taking hidden lines into account.
    +    int VisibleFromDocLine(int line);
    +
    +    // Find the document line of a display line taking hidden lines into account.
    +    int DocLineFromVisible(int lineDisplay);
    +
    +    // The number of display lines needed to wrap a document line
    +    int WrapCount(int line);
    +
    +    // Set the fold level of a line.
    +    // This encodes an integer level along with flags indicating whether the
    +    // line is a header and whether it is effectively white space.
    +    void SetFoldLevel(int line, int level);
    +
    +    // Retrieve the fold level of a line.
    +    int GetFoldLevel(int line);
    +
    +    // Find the last child line of a header line.
    +    int GetLastChild(int line, int level);
    +
    +    // Find the parent line of a child line.
    +    int GetFoldParent(int line);
    +
    +    // Make a range of lines visible.
    +    void ShowLines(int lineStart, int lineEnd);
    +
    +    // Make a range of lines invisible.
    +    void HideLines(int lineStart, int lineEnd);
    +
    +    // Is a line visible?
    +    bool GetLineVisible(int line);
    +
    +    // Show the children of a header line.
    +    void SetFoldExpanded(int line, bool expanded);
    +
    +    // Is a header line expanded?
    +    bool GetFoldExpanded(int line);
    +
    +    // Switch a header line between expanded and contracted.
    +    void ToggleFold(int line);
    +
    +    // Ensure a particular line is visible by expanding any header line hiding it.
    +    void EnsureVisible(int line);
    +
    +    // Set some style options for folding.
    +    void SetFoldFlags(int flags);
    +
    +    // Ensure a particular line is visible by expanding any header line hiding it.
    +    // Use the currently set visibility policy to determine which range to display.
    +    void EnsureVisibleEnforcePolicy(int line);
    +
    +    // Sets whether a tab pressed when caret is within indentation indents.
    +    void SetTabIndents(bool tabIndents);
    +
    +    // Does a tab pressed when caret is within indentation indent?
    +    bool GetTabIndents();
    +
    +    // Sets whether a backspace pressed when caret is within indentation unindents.
    +    void SetBackSpaceUnIndents(bool bsUnIndents);
    +
    +    // Does a backspace pressed when caret is within indentation unindent?
    +    bool GetBackSpaceUnIndents();
    +
    +    // Sets the time the mouse must sit still to generate a mouse dwell event.
    +    void SetMouseDwellTime(int periodMilliseconds);
    +
    +    // Retrieve the time the mouse must sit still to generate a mouse dwell event.
    +    int GetMouseDwellTime();
    +
    +    // Get position of start of word.
    +    int WordStartPosition(int pos, bool onlyWordCharacters);
    +
    +    // Get position of end of word.
    +    int WordEndPosition(int pos, bool onlyWordCharacters);
    +
    +    // Sets whether text is word wrapped.
    +    void SetWrapMode(int mode);
    +
    +    // Retrieve whether text is word wrapped.
    +    int GetWrapMode();
    +
    +    // Set the display mode of visual flags for wrapped lines.
    +    void SetWrapVisualFlags(int wrapVisualFlags);
    +
    +    // Retrive the display mode of visual flags for wrapped lines.
    +    int GetWrapVisualFlags();
    +
    +    // Set the location of visual flags for wrapped lines.
    +    void SetWrapVisualFlagsLocation(int wrapVisualFlagsLocation);
    +
    +    // Retrive the location of visual flags for wrapped lines.
    +    int GetWrapVisualFlagsLocation();
    +
    +    // Set the start indent for wrapped lines.
    +    void SetWrapStartIndent(int indent);
    +
    +    // Retrive the start indent for wrapped lines.
    +    int GetWrapStartIndent();
    +
    +    // Sets the degree of caching of layout information.
    +    void SetLayoutCache(int mode);
    +
    +    // Retrieve the degree of caching of layout information.
    +    int GetLayoutCache();
    +
    +    // Sets the document width assumed for scrolling.
    +    void SetScrollWidth(int pixelWidth);
    +
    +    // Retrieve the document width assumed for scrolling.
    +    int GetScrollWidth();
    +
    +    // Measure the pixel width of some text in a particular style.
    +    // NUL terminated text argument.
    +    // Does not handle tab or control characters.
    +    int TextWidth(int style, const wxString& text);
    +
    +    // Sets the scroll range so that maximum scroll position has
    +    // the last line at the bottom of the view (default).
    +    // Setting this to false allows scrolling one page below the last line.
    +    void SetEndAtLastLine(bool endAtLastLine);
    +
    +    // Retrieve whether the maximum scroll position has the last
    +    // line at the bottom of the view.
    +    bool GetEndAtLastLine();
    +
    +    // Retrieve the height of a particular line of text in pixels.
    +    int TextHeight(int line);
    +
    +    // Show or hide the vertical scroll bar.
    +    void SetUseVerticalScrollBar(bool show);
    +
    +    // Is the vertical scroll bar visible?
    +    bool GetUseVerticalScrollBar();
    +
    +    // Append a string to the end of the document without changing the selection.
    +    void AppendText(const wxString& text);
    +
    +    // Is drawing done in two phases with backgrounds drawn before foregrounds?
    +    bool GetTwoPhaseDraw();
    +
    +    // In twoPhaseDraw mode, drawing is performed in two phases, first the background
    +    // and then the foreground. This avoids chopping off characters that overlap the next run.
    +    void SetTwoPhaseDraw(bool twoPhase);
    +
    +    // Make the target range start and end be the same as the selection range start and end.
    +    void TargetFromSelection();
    +
    +    // Join the lines in the target.
    +    void LinesJoin();
    +
    +    // Split the lines in the target into lines that are less wide than pixelWidth
    +    // where possible.
    +    void LinesSplit(int pixelWidth);
    +
    +    // Set the colours used as a chequerboard pattern in the fold margin
    +    void SetFoldMarginColour(bool useSetting, const wxColour& back);
    +    void SetFoldMarginHiColour(bool useSetting, const wxColour& fore);
    +
    +    // Move caret down one line.
    +    void LineDown();
    +
    +    // Move caret down one line extending selection to new caret position.
    +    void LineDownExtend();
    +
    +    // Move caret up one line.
    +    void LineUp();
    +
    +    // Move caret up one line extending selection to new caret position.
    +    void LineUpExtend();
    +
    +    // Move caret left one character.
    +    void CharLeft();
    +
    +    // Move caret left one character extending selection to new caret position.
    +    void CharLeftExtend();
    +
    +    // Move caret right one character.
    +    void CharRight();
    +
    +    // Move caret right one character extending selection to new caret position.
    +    void CharRightExtend();
    +
    +    // Move caret left one word.
    +    void WordLeft();
    +
    +    // Move caret left one word extending selection to new caret position.
    +    void WordLeftExtend();
    +
    +    // Move caret right one word.
    +    void WordRight();
    +
    +    // Move caret right one word extending selection to new caret position.
    +    void WordRightExtend();
    +
    +    // Move caret to first position on line.
    +    void Home();
    +
    +    // Move caret to first position on line extending selection to new caret position.
    +    void HomeExtend();
    +
    +    // Move caret to last position on line.
    +    void LineEnd();
    +
    +    // Move caret to last position on line extending selection to new caret position.
    +    void LineEndExtend();
    +
    +    // Move caret to first position in document.
    +    void DocumentStart();
    +
    +    // Move caret to first position in document extending selection to new caret position.
    +    void DocumentStartExtend();
    +
    +    // Move caret to last position in document.
    +    void DocumentEnd();
    +
    +    // Move caret to last position in document extending selection to new caret position.
    +    void DocumentEndExtend();
    +
    +    // Move caret one page up.
    +    void PageUp();
    +
    +    // Move caret one page up extending selection to new caret position.
    +    void PageUpExtend();
    +
    +    // Move caret one page down.
    +    void PageDown();
    +
    +    // Move caret one page down extending selection to new caret position.
    +    void PageDownExtend();
    +
    +    // Switch from insert to overtype mode or the reverse.
    +    void EditToggleOvertype();
    +
    +    // Cancel any modes such as call tip or auto-completion list display.
    +    void Cancel();
    +
    +    // Delete the selection or if no selection, the character before the caret.
    +    void DeleteBack();
    +
    +    // If selection is empty or all on one line replace the selection with a tab character.
    +    // If more than one line selected, indent the lines.
    +    void Tab();
    +
    +    // Dedent the selected lines.
    +    void BackTab();
    +
    +    // Insert a new line, may use a CRLF, CR or LF depending on EOL mode.
    +    void NewLine();
    +
    +    // Insert a Form Feed character.
    +    void FormFeed();
    +
    +    // Move caret to before first visible character on line.
    +    // If already there move to first character on line.
    +    void VCHome();
    +
    +    // Like VCHome but extending selection to new caret position.
    +    void VCHomeExtend();
    +
    +    // Magnify the displayed text by increasing the sizes by 1 point.
    +    void ZoomIn();
    +
    +    // Make the displayed text smaller by decreasing the sizes by 1 point.
    +    void ZoomOut();
    +
    +    // Delete the word to the left of the caret.
    +    void DelWordLeft();
    +
    +    // Delete the word to the right of the caret.
    +    void DelWordRight();
    +
    +    // Cut the line containing the caret.
    +    void LineCut();
    +
    +    // Delete the line containing the caret.
    +    void LineDelete();
    +
    +    // Switch the current line with the previous.
    +    void LineTranspose();
    +
    +    // Duplicate the current line.
    +    void LineDuplicate();
    +
    +    // Transform the selection to lower case.
    +    void LowerCase();
    +
    +    // Transform the selection to upper case.
    +    void UpperCase();
    +
    +    // Scroll the document down, keeping the caret visible.
    +    void LineScrollDown();
    +
    +    // Scroll the document up, keeping the caret visible.
    +    void LineScrollUp();
    +
    +    // Delete the selection or if no selection, the character before the caret.
    +    // Will not delete the character before at the start of a line.
    +    void DeleteBackNotLine();
    +
    +    // Move caret to first position on display line.
    +    void HomeDisplay();
    +
    +    // Move caret to first position on display line extending selection to
    +    // new caret position.
    +    void HomeDisplayExtend();
    +
    +    // Move caret to last position on display line.
    +    void LineEndDisplay();
    +
    +    // Move caret to last position on display line extending selection to new
    +    // caret position.
    +    void LineEndDisplayExtend();
    +
    +    // These are like their namesakes Home(Extend)?, LineEnd(Extend)?, VCHome(Extend)?
    +    // except they behave differently when word-wrap is enabled:
    +    // They go first to the start / end of the display line, like (Home|LineEnd)Display
    +    // The difference is that, the cursor is already at the point, it goes on to the start
    +    // or end of the document line, as appropriate for (Home|LineEnd|VCHome)(Extend)?.
    +    void HomeWrap();
    +    void HomeWrapExtend();
    +    void LineEndWrap();
    +    void LineEndWrapExtend();
    +    void VCHomeWrap();
    +    void VCHomeWrapExtend();
    +
    +    // Copy the line containing the caret.
    +    void LineCopy();
    +
    +    // Move the caret inside current view if it's not there already.
    +    void MoveCaretInsideView();
    +
    +    // How many characters are on a line, not including end of line characters?
    +    int LineLength(int line);
    +
    +    // Highlight the characters at two positions.
    +    void BraceHighlight(int pos1, int pos2);
    +
    +    // Highlight the character at a position indicating there is no matching brace.
    +    void BraceBadLight(int pos);
    +
    +    // Find the position of a matching brace or INVALID_POSITION if no match.
    +    int BraceMatch(int pos);
    +
    +    // Are the end of line characters visible?
    +    bool GetViewEOL();
    +
    +    // Make the end of line characters visible or invisible.
    +    void SetViewEOL(bool visible);
    +
    +    // Retrieve a pointer to the document object.
    +    void* GetDocPointer();
    +
    +    // Change the document object used.
    +    void SetDocPointer(void* docPointer);
    +
    +    // Set which document modification events are sent to the container.
    +    void SetModEventMask(int mask);
    +
    +    // Retrieve the column number which text should be kept within.
    +    int GetEdgeColumn();
    +
    +    // Set the column number of the edge.
    +    // If text goes past the edge then it is highlighted.
    +    void SetEdgeColumn(int column);
    +
    +    // Retrieve the edge highlight mode.
    +    int GetEdgeMode();
    +
    +    // The edge may be displayed by a line (EDGE_LINE) or by highlighting text that
    +    // goes beyond it (EDGE_BACKGROUND) or not displayed at all (EDGE_NONE).
    +    void SetEdgeMode(int mode);
    +
    +    // Retrieve the colour used in edge indication.
    +    wxColour GetEdgeColour();
    +
    +    // Change the colour used in edge indication.
    +    void SetEdgeColour(const wxColour& edgeColour);
    +
    +    // Sets the current caret position to be the search anchor.
    +    void SearchAnchor();
    +
    +    // Find some text starting at the search anchor.
    +    // Does not ensure the selection is visible.
    +    int SearchNext(int flags, const wxString& text);
    +
    +    // Find some text starting at the search anchor and moving backwards.
    +    // Does not ensure the selection is visible.
    +    int SearchPrev(int flags, const wxString& text);
    +
    +    // Retrieves the number of lines completely visible.
    +    int LinesOnScreen();
    +
    +    // Set whether a pop up menu is displayed automatically when the user presses
    +    // the wrong mouse button.
    +    void UsePopUp(bool allowPopUp);
    +
    +    // Is the selection rectangular? The alternative is the more common stream selection.
    +    bool SelectionIsRectangle();
    +
    +    // Set the zoom level. This number of points is added to the size of all fonts.
    +    // It may be positive to magnify or negative to reduce.
    +    void SetZoom(int zoom);
    +
    +    // Retrieve the zoom level.
    +    int GetZoom();
    +
    +    // Create a new document object.
    +    // Starts with reference count of 1 and not selected into editor.
    +    void* CreateDocument();
    +
    +    // Extend life of document.
    +    void AddRefDocument(void* docPointer);
    +
    +    // Release a reference to the document, deleting document if it fades to black.
    +    void ReleaseDocument(void* docPointer);
    +
    +    // Get which document modification events are sent to the container.
    +    int GetModEventMask();
    +
    +    // Change internal focus flag.
    +    void SetSTCFocus(bool focus);
    +
    +    // Get internal focus flag.
    +    bool GetSTCFocus();
    +
    +    // Change error status - 0 = OK.
    +    void SetStatus(int statusCode);
    +
    +    // Get error status.
    +    int GetStatus();
    +
    +    // Set whether the mouse is captured when its button is pressed.
    +    void SetMouseDownCaptures(bool captures);
    +
    +    // Get whether mouse gets captured.
    +    bool GetMouseDownCaptures();
    +
    +    // Sets the cursor to one of the SC_CURSOR* values.
    +    void SetSTCCursor(int cursorType);
    +
    +    // Get cursor type.
    +    int GetSTCCursor();
    +
    +    // Change the way control characters are displayed:
    +    // If symbol is < 32, keep the drawn way, else, use the given character.
    +    void SetControlCharSymbol(int symbol);
    +
    +    // Get the way control characters are displayed.
    +    int GetControlCharSymbol();
    +
    +    // Move to the previous change in capitalisation.
    +    void WordPartLeft();
    +
    +    // Move to the previous change in capitalisation extending selection
    +    // to new caret position.
    +    void WordPartLeftExtend();
    +
    +    // Move to the change next in capitalisation.
    +    void WordPartRight();
    +
    +    // Move to the next change in capitalisation extending selection
    +    // to new caret position.
    +    void WordPartRightExtend();
    +
    +    // Set the way the display area is determined when a particular line
    +    // is to be moved to by Find, FindNext, GotoLine, etc.
    +    void SetVisiblePolicy(int visiblePolicy, int visibleSlop);
    +
    +    // Delete back from the current position to the start of the line.
    +    void DelLineLeft();
    +
    +    // Delete forwards from the current position to the end of the line.
    +    void DelLineRight();
    +
    +    // Get and Set the xOffset (ie, horizonal scroll position).
    +    void SetXOffset(int newOffset);
    +    int GetXOffset();
    +
    +    // Set the last x chosen value to be the caret x position.
    +    void ChooseCaretX();
    +
    +    // Set the way the caret is kept visible when going sideway.
    +    // The exclusion zone is given in pixels.
    +    void SetXCaretPolicy(int caretPolicy, int caretSlop);
    +
    +    // Set the way the line the caret is on is kept visible.
    +    // The exclusion zone is given in lines.
    +    void SetYCaretPolicy(int caretPolicy, int caretSlop);
    +
    +    // Set printing to line wrapped (SC_WRAP_WORD) or not line wrapped (SC_WRAP_NONE).
    +    void SetPrintWrapMode(int mode);
    +
    +    // Is printing line wrapped?
    +    int GetPrintWrapMode();
    +
    +    // Set a fore colour for active hotspots.
    +    void SetHotspotActiveForeground(bool useSetting, const wxColour& fore);
    +
    +    // Set a back colour for active hotspots.
    +    void SetHotspotActiveBackground(bool useSetting, const wxColour& back);
    +
    +    // Enable / Disable underlining active hotspots.
    +    void SetHotspotActiveUnderline(bool underline);
    +
    +    // Limit hotspots to single line so hotspots on two lines don't merge.
    +    void SetHotspotSingleLine(bool singleLine);
    +
    +    // Move caret between paragraphs (delimited by empty lines).
    +    void ParaDown();
    +    void ParaDownExtend();
    +    void ParaUp();
    +    void ParaUpExtend();
    +
    +    // Given a valid document position, return the previous position taking code
    +    // page into account. Returns 0 if passed 0.
    +    int PositionBefore(int pos);
    +
    +    // Given a valid document position, return the next position taking code
    +    // page into account. Maximum value returned is the last position in the document.
    +    int PositionAfter(int pos);
    +
    +    // Copy a range of text to the clipboard. Positions are clipped into the document.
    +    void CopyRange(int start, int end);
    +
    +    // Copy argument text to the clipboard.
    +    void CopyText(int length, const wxString& text);
    +
    +    // Set the selection mode to stream (SC_SEL_STREAM) or rectangular (SC_SEL_RECTANGLE) or
    +    // by lines (SC_SEL_LINES).
    +    void SetSelectionMode(int mode);
    +
    +    // Get the mode of the current selection.
    +    int GetSelectionMode();
    +
    +    // Retrieve the position of the start of the selection at the given line (INVALID_POSITION if no selection on this line).
    +    int GetLineSelStartPosition(int line);
    +
    +    // Retrieve the position of the end of the selection at the given line (INVALID_POSITION if no selection on this line).
    +    int GetLineSelEndPosition(int line);
    +
    +    // Move caret down one line, extending rectangular selection to new caret position.
    +    void LineDownRectExtend();
    +
    +    // Move caret up one line, extending rectangular selection to new caret position.
    +    void LineUpRectExtend();
    +
    +    // Move caret left one character, extending rectangular selection to new caret position.
    +    void CharLeftRectExtend();
    +
    +    // Move caret right one character, extending rectangular selection to new caret position.
    +    void CharRightRectExtend();
    +
    +    // Move caret to first position on line, extending rectangular selection to new caret position.
    +    void HomeRectExtend();
    +
    +    // Move caret to before first visible character on line.
    +    // If already there move to first character on line.
    +    // In either case, extend rectangular selection to new caret position.
    +    void VCHomeRectExtend();
    +
    +    // Move caret to last position on line, extending rectangular selection to new caret position.
    +    void LineEndRectExtend();
    +
    +    // Move caret one page up, extending rectangular selection to new caret position.
    +    void PageUpRectExtend();
    +
    +    // Move caret one page down, extending rectangular selection to new caret position.
    +    void PageDownRectExtend();
    +
    +    // Move caret to top of page, or one page up if already at top of page.
    +    void StutteredPageUp();
    +
    +    // Move caret to top of page, or one page up if already at top of page, extending selection to new caret position.
    +    void StutteredPageUpExtend();
    +
    +    // Move caret to bottom of page, or one page down if already at bottom of page.
    +    void StutteredPageDown();
    +
    +    // Move caret to bottom of page, or one page down if already at bottom of page, extending selection to new caret position.
    +    void StutteredPageDownExtend();
    +
    +    // Move caret left one word, position cursor at end of word.
    +    void WordLeftEnd();
    +
    +    // Move caret left one word, position cursor at end of word, extending selection to new caret position.
    +    void WordLeftEndExtend();
    +
    +    // Move caret right one word, position cursor at end of word.
    +    void WordRightEnd();
    +
    +    // Move caret right one word, position cursor at end of word, extending selection to new caret position.
    +    void WordRightEndExtend();
    +
    +    // Set the set of characters making up whitespace for when moving or selecting by word.
    +    // Should be called after SetWordChars.
    +    void SetWhitespaceChars(const wxString& characters);
    +
    +    // Reset the set of characters for whitespace and word characters to the defaults.
    +    void SetCharsDefault();
    +
    +    // Get currently selected item position in the auto-completion list
    +    int AutoCompGetCurrent();
    +
    +    // Enlarge the document to a particular size of text bytes.
    +    void Allocate(int bytes);
    +
    +    // Find the position of a column on a line taking into account tabs and
    +    // multi-byte characters. If beyond end of line, return line end position.
    +    int FindColumn(int line, int column);
    +
    +    // Can the caret preferred x position only be changed by explicit movement commands?
    +    bool GetCaretSticky();
    +
    +    // Stop the caret preferred x position changing when the user types.
    +    void SetCaretSticky(bool useCaretStickyBehaviour);
    +
    +    // Switch between sticky and non-sticky: meant to be bound to a key.
    +    void ToggleCaretSticky();
    +
    +    // Enable/Disable convert-on-paste for line endings
    +    void SetPasteConvertEndings(bool convert);
    +
    +    // Get convert-on-paste setting
    +    bool GetPasteConvertEndings();
    +
    +    // Duplicate the selection. If selection empty duplicate the line containing the caret.
    +    void SelectionDuplicate();
    +
    +    // Start notifying the container of all key presses and commands.
    +    void StartRecord();
    +
    +    // Stop notifying the container of all key presses and commands.
    +    void StopRecord();
    +
    +    // Set the lexing language of the document.
    +    void SetLexer(int lexer);
    +
    +    // Retrieve the lexing language of the document.
    +    int GetLexer();
    +
    +    // Colourise a segment of the document using the current lexing language.
    +    void Colourise(int start, int end);
    +
    +    // Set up a value that may be used by a lexer for some optional feature.
    +    void SetProperty(const wxString& key, const wxString& value);
    +
    +    // Set up the key words used by the lexer.
    +    void SetKeyWords(int keywordSet, const wxString& keyWords);
    +
    +    // Set the lexing language of the document based on string name.
    +    void SetLexerLanguage(const wxString& language);
    +
    +    // Retrieve a 'property' value previously set with SetProperty.
    +    wxString GetProperty(const wxString& key);
    +
    +    // Retrieve a 'property' value previously set with SetProperty,
    +    // with '$()' variable replacement on returned buffer.
    +    wxString GetPropertyExpanded(const wxString& key);
    +
    +    // Retrieve a 'property' value previously set with SetProperty,
    +    // interpreted as an int AFTER any '$()' variable replacement.
    +    int GetPropertyInt(const wxString& key);
    +
    +    // Retrieve the number of bits the current lexer needs for styling.
    +    int GetStyleBitsNeeded();
    +
    +// END of generated section
    +//----------------------------------------------------------------------
    +// Others...
    +
    +
    +    // Returns the line number of the line with the caret.
    +    int GetCurrentLine();
    +
    +    // Extract style settings from a spec-string which is composed of one or
    +    // more of the following comma separated elements:
    +    //
    +    //      bold                    turns on bold
    +    //      italic                  turns on italics
    +    //      fore:[name or #RRGGBB]  sets the foreground colour
    +    //      back:[name or #RRGGBB]  sets the background colour
    +    //      face:[facename]         sets the font face name to use
    +    //      size:[num]              sets the font size in points
    +    //      eol                     turns on eol filling
    +    //      underline               turns on underlining
    +    //
    +    void StyleSetSpec(int styleNum, const wxString& spec);
    +
    +
    +
    +    // Set style size, face, bold, italic, and underline attributes from
    +    // a wxFont's attributes.
    +    void StyleSetFont(int styleNum, wxFont& font);
    +
    +
    +
    +    // Set all font style attributes at once.
    +    void StyleSetFontAttr(int styleNum, int size,
    +                          const wxString& faceName,
    +                          bool bold, bool italic,
    +                          bool underline,
    +                          wxFontEncoding encoding=wxFONTENCODING_DEFAULT);
    +
    +
    +    // Set the character set of the font in a style.  Converts the Scintilla
    +    // character set values to a wxFontEncoding.
    +    void StyleSetCharacterSet(int style, int characterSet);
    +
    +    // Set the font encoding to be used by a style.
    +    void StyleSetFontEncoding(int style, wxFontEncoding encoding);
    +
    +
    +    // Perform one of the operations defined by the wxSTC_CMD_* constants.
    +    void CmdKeyExecute(int cmd);
    +
    +
    +    // Set the left and right margin in the edit area, measured in pixels.
    +    void SetMargins(int left, int right);
    +
    +
    +    // Retrieve the start and end positions of the current selection.
    +#ifdef SWIG
    +    void GetSelection(int* OUTPUT, int* OUTPUT);
    +#else
    +    void GetSelection(int* startPos, int* endPos);
    +#endif
    +
    +    // Retrieve the point in the window where a position is displayed.
    +    wxPoint PointFromPosition(int pos);
    +
    +
    +    // Scroll enough to make the given line visible
    +    void ScrollToLine(int line);
    +
    +
    +    // Scroll enough to make the given column visible
    +    void ScrollToColumn(int column);
    +
    +
    +    // Send a message to Scintilla
    +    long SendMsg(int msg, long wp=0, long lp=0);
    +
    +
    +    // Set the vertical scrollbar to use instead of the ont that's built-in.
    +    void SetVScrollBar(wxScrollBar* bar);
    +
    +
    +    // Set the horizontal scrollbar to use instead of the ont that's built-in.
    +    void SetHScrollBar(wxScrollBar* bar);
    +
    +    // Can be used to prevent the EVT_CHAR handler from adding the char
    +    bool GetLastKeydownProcessed() { return m_lastKeyDownConsumed; }
    +    void SetLastKeydownProcessed(bool val) { m_lastKeyDownConsumed = val; }
    +
    +    // Write the contents of the editor to filename
    +    bool SaveFile(const wxString& filename);
    +
    +    // Load the contents of filename into the editor
    +    bool LoadFile(const wxString& filename);
    +
    +#ifdef STC_USE_DND
    +    // Allow for simulating a DnD DragOver
    +    wxDragResult DoDragOver(wxCoord x, wxCoord y, wxDragResult def);
    +
    +    // Allow for simulating a DnD DropText
    +    bool DoDropText(long x, long y, const wxString& data);
    +#endif
    +
    +    // Specify whether anti-aliased fonts should be used.  Will have no effect
    +    // on some platforms, but on some (wxMac for example) can greatly improve
    +    // performance.
    +    void SetUseAntiAliasing(bool useAA);
    +
    +    // Returns the current UseAntiAliasing setting.
    +    bool GetUseAntiAliasing();
    +
    +
    +
    +    // The following methods are nearly equivallent to their similarly named
    +    // cousins above.  The difference is that these methods bypass wxString
    +    // and always use a char* even if used in a unicode build of wxWidgets.
    +    // In that case the character data will be utf-8 encoded since that is
    +    // what is used internally by Scintilla in unicode builds.
    +
    +    // Add text to the document at current position.
    +    void AddTextRaw(const char* text);
    +
    +    // Insert string at a position.
    +    void InsertTextRaw(int pos, const char* text);
    +
    +    // Retrieve the text of the line containing the caret.
    +    // Returns the index of the caret on the line.
    +#ifdef SWIG
    +    wxCharBuffer GetCurLineRaw(int* OUTPUT);
    +#else
    +    wxCharBuffer GetCurLineRaw(int* linePos=NULL);
    +#endif
    +
    +    // Retrieve the contents of a line.
    +    wxCharBuffer GetLineRaw(int line);
    +
    +    // Retrieve the selected text.
    +    wxCharBuffer GetSelectedTextRaw();
    +
    +    // Retrieve a range of text.
    +    wxCharBuffer GetTextRangeRaw(int startPos, int endPos);
    +
    +    // Replace the contents of the document with the argument text.
    +    void SetTextRaw(const char* text);
    +
    +    // Retrieve all the text in the document.
    +    wxCharBuffer GetTextRaw();
    +
    +    // Append a string to the end of the document without changing the selection.
    +    void AppendTextRaw(const char* text);
    +
    +#ifdef SWIG
    +    %pythoncode "_stc_utf8_methods.py"
    +#endif
    +//----------------------------------------------------------------------
    +
    +
    +#ifndef SWIG
    +protected:
    +    // Event handlers
    +    void OnPaint(wxPaintEvent& evt);
    +    void OnScrollWin(wxScrollWinEvent& evt);
    +    void OnScroll(wxScrollEvent& evt);
    +    void OnSize(wxSizeEvent& evt);
    +    void OnMouseLeftDown(wxMouseEvent& evt);
    +    void OnMouseMove(wxMouseEvent& evt);
    +    void OnMouseLeftUp(wxMouseEvent& evt);
    +    void OnMouseRightUp(wxMouseEvent& evt);
    +    void OnMouseMiddleUp(wxMouseEvent& evt);
    +    void OnContextMenu(wxContextMenuEvent& evt);
    +    void OnMouseWheel(wxMouseEvent& evt);
    +    void OnChar(wxKeyEvent& evt);
    +    void OnKeyDown(wxKeyEvent& evt);
    +    void OnLoseFocus(wxFocusEvent& evt);
    +    void OnGainFocus(wxFocusEvent& evt);
    +    void OnSysColourChanged(wxSysColourChangedEvent& evt);
    +    void OnEraseBackground(wxEraseEvent& evt);
    +    void OnMenu(wxCommandEvent& evt);
    +    void OnListBox(wxCommandEvent& evt);
    +    void OnIdle(wxIdleEvent& evt);
    +
    +    virtual wxSize DoGetBestSize() const;
    +
    +    // Turn notifications from Scintilla into events
    +    void NotifyChange();
    +    void NotifyParent(SCNotification* scn);
    +
    +private:
    +    DECLARE_EVENT_TABLE()
    +    DECLARE_DYNAMIC_CLASS(wxStyledTextCtrl)
    +
    +protected:
    +
    +    ScintillaWX*        m_swx;
    +    wxStopWatch         m_stopWatch;
    +    wxScrollBar*        m_vScrollBar;
    +    wxScrollBar*        m_hScrollBar;
    +
    +    bool                m_lastKeyDownConsumed;
    +
    +    friend class ScintillaWX;
    +    friend class Platform;
    +#endif
    +};
    +
    +//----------------------------------------------------------------------
    +
    +class WXDLLIMPEXP_STC wxStyledTextEvent : public wxCommandEvent {
    +public:
    +    wxStyledTextEvent(wxEventType commandType=0, int id=0);
    +#ifndef SWIG
    +    wxStyledTextEvent(const wxStyledTextEvent& event);
    +#endif
    +    ~wxStyledTextEvent() {}
    +
    +    void SetPosition(int pos)             { m_position = pos; }
    +    void SetKey(int k)                    { m_key = k; }
    +    void SetModifiers(int m)              { m_modifiers = m; }
    +    void SetModificationType(int t)       { m_modificationType = t; }
    +    void SetText(const wxString& t)       { m_text = t; }
    +    void SetLength(int len)               { m_length = len; }
    +    void SetLinesAdded(int num)           { m_linesAdded = num; }
    +    void SetLine(int val)                 { m_line = val; }
    +    void SetFoldLevelNow(int val)         { m_foldLevelNow = val; }
    +    void SetFoldLevelPrev(int val)        { m_foldLevelPrev = val; }
    +    void SetMargin(int val)               { m_margin = val; }
    +    void SetMessage(int val)              { m_message = val; }
    +    void SetWParam(int val)               { m_wParam = val; }
    +    void SetLParam(int val)               { m_lParam = val; }
    +    void SetListType(int val)             { m_listType = val; }
    +    void SetX(int val)                    { m_x = val; }
    +    void SetY(int val)                    { m_y = val; }
    +    void SetDragText(const wxString& val) { m_dragText = val; }
    +    void SetDragAllowMove(bool val)       { m_dragAllowMove = val; }
    +#ifdef  STC_USE_DND
    +    void SetDragResult(wxDragResult val)  { m_dragResult = val; }
    +#endif
    +
    +    int  GetPosition() const         { return m_position; }
    +    int  GetKey()  const             { return m_key; }
    +    int  GetModifiers() const        { return m_modifiers; }
    +    int  GetModificationType() const { return m_modificationType; }
    +    wxString GetText() const         { return m_text; }
    +    int  GetLength() const           { return m_length; }
    +    int  GetLinesAdded() const       { return m_linesAdded; }
    +    int  GetLine() const             { return m_line; }
    +    int  GetFoldLevelNow() const     { return m_foldLevelNow; }
    +    int  GetFoldLevelPrev() const    { return m_foldLevelPrev; }
    +    int  GetMargin() const           { return m_margin; }
    +    int  GetMessage() const          { return m_message; }
    +    int  GetWParam() const           { return m_wParam; }
    +    int  GetLParam() const           { return m_lParam; }
    +    int  GetListType() const         { return m_listType; }
    +    int  GetX() const                { return m_x; }
    +    int  GetY() const                { return m_y; }
    +    wxString GetDragText()           { return m_dragText; }
    +    bool GetDragAllowMove()          { return m_dragAllowMove; }
    +#ifdef STC_USE_DND
    +    wxDragResult GetDragResult()     { return m_dragResult; }
    +#endif
    +
    +    bool GetShift() const;
    +    bool GetControl() const;
    +    bool GetAlt() const;
    +
    +    virtual wxEvent* Clone() const { return new wxStyledTextEvent(*this); }
    +
    +#ifndef SWIG
    +private:
    +    DECLARE_DYNAMIC_CLASS(wxStyledTextEvent)
    +
    +    int  m_position;
    +    int  m_key;
    +    int  m_modifiers;
    +
    +    int  m_modificationType;    // wxEVT_STC_MODIFIED
    +    wxString m_text;
    +    int  m_length;
    +    int  m_linesAdded;
    +    int  m_line;
    +    int  m_foldLevelNow;
    +    int  m_foldLevelPrev;
    +
    +    int  m_margin;              // wxEVT_STC_MARGINCLICK
    +
    +    int  m_message;             // wxEVT_STC_MACRORECORD
    +    int  m_wParam;
    +    int  m_lParam;
    +
    +    int m_listType;
    +    int m_x;
    +    int m_y;
    +
    +    wxString m_dragText;        // wxEVT_STC_START_DRAG, wxEVT_STC_DO_DROP
    +    bool     m_dragAllowMove;   // wxEVT_STC_START_DRAG
    +
    +#if wxUSE_DRAG_AND_DROP
    +    wxDragResult m_dragResult; // wxEVT_STC_DRAG_OVER,wxEVT_STC_DO_DROP
    +#endif
    +#endif
    +};
    +
    +
    +
    +#ifndef SWIG
    +BEGIN_DECLARE_EVENT_TYPES()
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_CHANGE,             1650)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_STYLENEEDED,        1651)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_CHARADDED,          1652)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_SAVEPOINTREACHED,   1653)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_SAVEPOINTLEFT,      1654)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_ROMODIFYATTEMPT,    1655)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_KEY,                1656)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_DOUBLECLICK,        1657)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_UPDATEUI,           1658)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_MODIFIED,           1659)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_MACRORECORD,        1660)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_MARGINCLICK,        1661)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_NEEDSHOWN,          1662)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_PAINTED,            1664)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_USERLISTSELECTION,  1665)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_URIDROPPED,         1666)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_DWELLSTART,         1667)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_DWELLEND,           1668)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_START_DRAG,         1669)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_DRAG_OVER,          1670)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_DO_DROP,            1671)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_ZOOM,               1672)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_HOTSPOT_CLICK,      1673)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_HOTSPOT_DCLICK,     1674)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_CALLTIP_CLICK,      1675)
    +    DECLARE_EXPORTED_EVENT_TYPE(WXDLLIMPEXP_STC, wxEVT_STC_AUTOCOMP_SELECTION, 1676)
    +END_DECLARE_EVENT_TYPES()
    +#else
    +    enum {
    +        wxEVT_STC_CHANGE,
    +        wxEVT_STC_STYLENEEDED,
    +        wxEVT_STC_CHARADDED,
    +        wxEVT_STC_SAVEPOINTREACHED,
    +        wxEVT_STC_SAVEPOINTLEFT,
    +        wxEVT_STC_ROMODIFYATTEMPT,
    +        wxEVT_STC_KEY,
    +        wxEVT_STC_DOUBLECLICK,
    +        wxEVT_STC_UPDATEUI,
    +        wxEVT_STC_MODIFIED,
    +        wxEVT_STC_MACRORECORD,
    +        wxEVT_STC_MARGINCLICK,
    +        wxEVT_STC_NEEDSHOWN,
    +        wxEVT_STC_PAINTED,
    +        wxEVT_STC_USERLISTSELECTION,
    +        wxEVT_STC_URIDROPPED,
    +        wxEVT_STC_DWELLSTART,
    +        wxEVT_STC_DWELLEND,
    +        wxEVT_STC_START_DRAG,
    +        wxEVT_STC_DRAG_OVER,
    +        wxEVT_STC_DO_DROP,
    +        wxEVT_STC_ZOOM,
    +        wxEVT_STC_HOTSPOT_CLICK,
    +        wxEVT_STC_HOTSPOT_DCLICK,
    +        wxEVT_STC_CALLTIP_CLICK,
    +        wxEVT_STC_AUTOCOMP_SELECTION
    +    };
    +#endif
    +
    +
    +
    +#ifndef SWIG
    +typedef void (wxEvtHandler::*wxStyledTextEventFunction)(wxStyledTextEvent&);
    +
    +#define EVT_STC_CHANGE(id, fn)             DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_CHANGE,                id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_STYLENEEDED(id, fn)        DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_STYLENEEDED,           id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_CHARADDED(id, fn)          DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_CHARADDED,             id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_SAVEPOINTREACHED(id, fn)   DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_SAVEPOINTREACHED,      id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_SAVEPOINTLEFT(id, fn)      DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_SAVEPOINTLEFT,         id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_ROMODIFYATTEMPT(id, fn)    DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_ROMODIFYATTEMPT,       id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_KEY(id, fn)                DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_KEY,                   id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_DOUBLECLICK(id, fn)        DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_DOUBLECLICK,           id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_UPDATEUI(id, fn)           DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_UPDATEUI,              id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_MODIFIED(id, fn)           DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_MODIFIED,              id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_MACRORECORD(id, fn)        DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_MACRORECORD,           id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_MARGINCLICK(id, fn)        DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_MARGINCLICK,           id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_NEEDSHOWN(id, fn)          DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_NEEDSHOWN,             id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_PAINTED(id, fn)            DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_PAINTED,               id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_USERLISTSELECTION(id, fn)  DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_USERLISTSELECTION,     id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_URIDROPPED(id, fn)         DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_URIDROPPED,            id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_DWELLSTART(id, fn)         DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_DWELLSTART,            id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_DWELLEND(id, fn)           DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_DWELLEND,              id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_START_DRAG(id, fn)         DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_START_DRAG,            id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_DRAG_OVER(id, fn)          DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_DRAG_OVER,             id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_DO_DROP(id, fn)            DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_DO_DROP,               id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_ZOOM(id, fn)               DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_ZOOM,                  id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_HOTSPOT_CLICK(id, fn)      DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_HOTSPOT_CLICK,         id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_HOTSPOT_DCLICK(id, fn)     DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_HOTSPOT_DCLICK,        id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_CALLTIP_CLICK(id, fn))     DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_CALLTIP_CLICK          id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#define EVT_STC_AUTOCOMP_SELECTION(id, fn) DECLARE_EVENT_TABLE_ENTRY( wxEVT_STC_AUTOCOMP_SELECTION     id, wxID_ANY, (wxObjectEventFunction) (wxEventFunction)  wxStaticCastEvent( wxStyledTextEventFunction, & fn ), (wxObject *) NULL ),
    +#endif
    +
    +//----------------------------------------------------------------------
    +// Utility functions used within wxSTC
    +
    +#ifndef SWIG
    +#if wxUSE_UNICODE
    +
    +WXDLLIMPEXP_STC wxString stc2wx(const char* str);
    +WXDLLIMPEXP_STC wxString stc2wx(const char* str, size_t len);
    +WXDLLIMPEXP_STC const wxWX2MBbuf wx2stc(const wxString& str);
    +
    +#else // not UNICODE
    +
    +inline wxString stc2wx(const char* str) {
    +    return wxString(str);
    +}
    +inline wxString stc2wx(const char* str, size_t len) {
    +    return wxString(str, len);
    +}
    +inline const wxWX2MBbuf wx2stc(const wxString& str) {
    +    return str.mbc_str();
    +}
    +
    +#endif // UNICODE
    +#endif // SWIG
    +
    +//----------------------------------------------------------------------
    +#endif
    +
    +
    +
    + + diff --git a/demo/data/tables.htm b/demo/data/tables.htm new file mode 100644 index 00000000..2d1b7cb0 --- /dev/null +++ b/demo/data/tables.htm @@ -0,0 +1,119 @@ + + + + + + + + +

    +This is TABLES +tests page...

    + + +(yes, really, see bellow:) +
    Click here to go to original testing page... +
    Click +here +to go to manuals... + +
      +
    + + + + + + + + + + + +
    Top left +
    (two lines expression) +

    paragraph done

    Top right
    Bottom leftBottom right
    + +

    Subsampling is shown there: +
      + + + + + + + + + + + + +
    + + + + + + + + + + + + + +
    ab
    cd
    +
    2
    3 dflkj lkjfl dkjldkfjl flk jflkf lkjflkj ljlf ajlfj alff h khg hgj +gjg jg gjhfg fg gjh gjf jgf jgj f gjfgj kfajg 4 +
    gh +
    gfh +
    gh +
    hg +
    5
    + +

    This is "default" table - with no sizes givev: +
      + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Hellolkfdsjlk fj dlfj lkfj lkjflk jlfk lk fjlk elwkf lkejflek f jlekjflkj +ljlk lk jlkf lefjl j flkj ljl lf lfj lfjl lj lwe lekf;eh kfejh lkh kjh +kjhkj hkj hkj lkh kjh kjlh kjshortebn formo lr lkdjsf lkjlf poer oi pjr po kpk 
    abcd
    123
    AB
    + + + + + + + diff --git a/demo/data/test.htm b/demo/data/test.htm new file mode 100644 index 00000000..37ffc1e7 --- /dev/null +++ b/demo/data/test.htm @@ -0,0 +1,250 @@ + + + + + +wxPython does wxHTML! + + + +click here to go to tables test page! +

    +click here to go to IMAGEMAPs test page! + +

    +This is - - default text, now switching to +

    +

    center, now still ctr, now exiting

    +exited!.[link to down] +

    Hello, this *is* default charset (helvetica, probably) and it is displayed +with one  COLOR CHANGE. Of course we +can have as many color changes as we can, what about this MADNESS? +

    There was a space above. +
    +


    This was a line. (BTW we are in fixed font +/ typewriter font right now :-) +
    This is in BOLD face. This is ITALIC. This is E +V E R Y T H I N G. +
      +


    +

    +

    Right now, centered REALLY Big Text, +how do you like (space) it?

    + +
    RIGHT: text-2, text-1, +text+0, +text+1, +text+2, +text+3, +text+4 +
    we are right now
    + +
    we are center now
    +we are left now. +

    Blue italic text is displayed there.... +

    + +
    This is heading one.

    +this is normal +
    +

    +This is CENTERED heading one

    +Yes, hmmmmmmmmm........, right now, we should +display some tiny nice image, he? +
    Testing image imageand this is text...... +

    Testing image imageand +this is text...... +
    Testing image image (try clicking on the image :-) and +this is text...... + +
    +
      +
      +

      +
    • +item 1
    • + +
    • +item 2
    • + +
        +
      • +nested item
      • + +
      • +nested item 2
      • +
      + +
    • +item 3
    • +
    + +
      +
    1. +item one
    2. + +
    3. +item two
    4. + +
        +
      1. +nsted item
      2. +
      + +
    5. +last numbered item
    6. +
    + +

    +Heading 1

    +Italic text now... +

    +Heading 2

    +and now? +

    +Heading 3

    + +

    +Heading 4

    + +
    +Heading 5
    + +
    +Heading 6
    +And this is normal text, once again :-) +
      +
      +
      +
      +
      +
      +

    And yes, we're in HTML DOCUMENT +

    hello? +
      +


    +

    +

    This is centered paragraph

    + +

    This is new par? +

    We switched to BOLD +

    This is new paragraph Bold is off now. +

    new par +

      ----------- +

    Hello +

      this is standalone :-) +
    1. +This is item number one. iti lkdjfdl kjd lk jlkjdl kjlk jlf +jflkj d lfkjlkf jl jflkj flkwe lkhelf ;fk;fl kw;lfke ;ffj lkjflk wj lfjl +fkw ;k;ekf;lkfe ;kf;lk; ;j ;lrj;wfj;f ;eljfw; lfj;ewlfj dagdja gdj chga +kjegiquw iuqdb qiud iquwd hurray googoo.
    2. + +
    3. +two two two two two two twotwo TWO two two two two two two +twotwo TWO two two two two two two twotwo TWO two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO
    4. + +
      (blockquote)two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +
      two two two two two two twotwo TWO two two two
      +two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO
      +two two two two two two twotwo TWO two two two two two two +twotwo TWO +
    5. +This is item nyumber 3.
    6. + +
    7. +This is item number one. iti lkdjfdl kjd lk jlkjdl kjlk jlf +jflkj d lfkjlkf jl jflkj flkwe lkhelf ;fk;fl kw;lfke ;ffj lkjflk wj lfjl +fkw ;k;ekf;lkfe ;kf;lk; ;j ;lrj;wfj;f ;eljfw; lfj;ewlfj dagdja gdj chga +kjegiquw iuqdb qiud iquwd hurray googoo.
    8. + +
    9. +two two two two two two twotwo TWO two two two two two two +twotwo TWO two two two two two two twotwo TWO two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO two two two two two two twotwo TWO two +two two two two two twotwo TWO two two two two two two twotwo TWO two two +two two two two twotwo TWO two two two two two two twotwo TWO two two two +two two two twotwo TWO two two two two two two twotwo TWO two two two two +two two twotwo TWO two two two two two two twotwo TWO
    10. + +
    11. +This is item nyumber 3.
    12. + +
    13. +This is item number one. iti lkdjfdl kjd lk jlkjdl kjlk jlf +jflkj d lfkjlkf jl jflkj flkwe lkhelf ;fk;fl kw;lfke ;ffj lkjflk wj lfjl +fkw ;k;ekf;lkfe ;kf;lk; ;j ;lrj;wfj;f ;eljfw; lfj;ewlfj dagdja gdj chga +kjegiquw iuqdb qiud iquwd hurray googoo.
    14. + +
    15. +two two two two two two twotwo TWO two two two two two two +twotwo TWO two two two two two two twotwo TWO two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO two two two two two two twotwo TWO two +two two two two two twotwo TWO two two two two two two twotwo TWO two two +two two two two twotwo TWO two two two two two two twotwo TWO two two two +two two two twotwo TWO two two two two two two twotwo TWO two two two two +two two twotwo TWO two two two two two two twotwo TWO
    16. + +
    17. +This is item nyumber 3.
    18. + +
    19. +This is item number one. iti lkdjfdl kjd lk jlkjdl kjlk jlf +jflkj d lfkjlkf jl jflkj flkwe lkhelf ;fk;fl kw;lfke ;ffj lkjflk wj lfjl +fkw ;k;ekf;lkfe ;kf;lk; ;j ;lrj;wfj;f ;eljfw; lfj;ewlfj dagdja gdj chga +kjegiquw iuqdb qiud iquwd hurray googoo.
    20. + +
    21. +two two two two two two twotwo TWO two two two two two two +twotwo TWO two two two two two two twotwo TWO two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO two two two two two two twotwo TWO two +two two two two two twotwo TWO two two two two two two twotwo TWO two two +two two two two twotwo TWO two two two two two two twotwo TWO two two two +two two two twotwo TWO two two two two two two twotwo TWO two two two two +two two twotwo TWO two two two two two two twotwo TWO
    22. + +
    23. +This is item nyumber 3.
    24. + +
    25. +This is item number one. iti lkdjfdl kjd lk jlkjdl kjlk jlf +jflkj d lfkjlkf jl jflkj flkwe lkhelf ;fk;fl kw;lfke ;ffj lkjflk wj lfjl +fkw ;k;ekf;lkfe ;kf;lk; ;j ;lrj;wfj;f ;eljfw; lfj;ewlfj dagdja gdj chga +kjegiquw iuqdb qiud iquwd hurray googoo.
    26. + +
    27. +two two two two two two twotwo TWO two two two two two two +twotwo TWO two two two two two two twotwo TWO two two two two two two twotwo +TWO two two two two two two twotwo TWO two two two two two two twotwo TWO +two two two two two two twotwo TWO two two two two two two twotwo TWO
    28. + +


      two two two two two two twotwo TWO two two two two +two two twotwo TWO two two two two two two twotwo TWO two two two two two +two twotwo TWO +

      two two two two two two twotwo TWO two two two two two +two twotwo TWO two two two two two two twotwo TWO two two two two two two +twotwo TWO +

    29. +This is item nyumber 3.
    30. +
    +Now, you will see some PRE text:

    +

    // This is sample C++ code:
    +
    +void main(int argc, char *argv[])
    +{
    +    printf("Go away, man!\n");
    +    i = 666;
    +    printf("\n\n\nCRASH\n  DOWN NOW. . .  \n");
    +}
    + + + + + diff --git a/demo/data/testmovie.mpg b/demo/data/testmovie.mpg new file mode 100644 index 00000000..b95237d0 Binary files /dev/null and b/demo/data/testmovie.mpg differ diff --git a/demo/data/testtable.txt b/demo/data/testtable.txt new file mode 100644 index 00000000..dec973e7 --- /dev/null +++ b/demo/data/testtable.txt @@ -0,0 +1,38 @@ +Name Type Platform Location Availability Description +WebReuser Development Windows 95, Windows NT, HPUX 9.05 and 10.2, Solaris 2.4 and 2.5 http://www.stablesoft.com Evaluation WebReuser is a re-use tool from Hitachi Europe Limited. WebReuser is a tool that simplifies software reuse. Its ability to track, schematize and search documents makes it the ideal way to understand C++ code. These features also make WebReuser an ideal tool to classify any Web resource. WebReuser can even be used for more general documentation management tasks. +MacAnova Development Windows, Motif, Mac http://www.stat.umn.edu/~gary/macanova/macanova.home.html Free A large statistical application from the School of Statistics, University of Minnesota. It is based on a modified version of wxWindows 1.65. +Hardy Development Win 3.1, WIN32, Motif (Sun only) http://www.aiai.ed.ac.uk/~hardy/ Freeware for personal and academic use A hypertext-based diagramming and knowledge-based system development tool, with NASA's CLIPS built-in. It is a superset of wxCLIPS. +wxCLIPS Development Win 3.1, WIN32, Motif, XView http://web.ukonline.co.uk/julian.smart/wxclips Freeware A GUI development environment for CLIPS applications. +wxPython Development wxWindows 2 for the new version http://alldunn.com/wxPython/ Freeware Python/wxWindows combination by Robin Dunn and Harri Pasanen. Python is an elegant object-oriented, interpreted language that runs on many platforms. +MrEd Development Win 3.1, WIN32, Motif, XView http://www.cs.rice.edu/CS/PLT/packages/mred/ Freeware MrEd is a combined editor and Scheme development environment by Matthew Flatt. +WXLisp Development Win 3.1, WIN32, Motif, XView http://www.cadlab.de/~lipuser/wxlisp/wxlisp.html Freeware A combination of wxWindows and XLisp. +Scriptum Development Motif http://www.isoft.com.ar/eng/products/system/scriptum.html Freeware Graphical editor with visual highlighting, navigation/browsing, undo, class browser for C++ and Java, source code management, file locking, remote editing using ftp, configurable. +WipeOut Development XView/Linux http://www.softwarebuero.de/wipeout-eng.html Giftware WipeOut is an integrated development environment for C++ projects, available for Linux/XView. The authors are working on versions for SunOS/Solaris. Source is available for porting to other platforms. +OPL Development Win 3.1, WIN32, Motif, XView http://www.ozemail.com.au/~adavison/ Freeware Object Prolog is a portable implementation of Prolog by Andrew Davison, with object-oriented extensions, entirely written in C++. In the initial version, a binding to wxWindows is available. In the revamped version, this binding has not been written yet. +Dataplore Graphics and sound Windows, other? http://www.datan.de/dataplore Commercial Data visualisation tool, from Datan +VCG Tool Graphics and sound Win 3.1, WIN32, Motif, XView http://www.cs.uni-sb.de:80/RW/users/sander/html/gsvcg1.html Freeware A graph layout tool similar to GraphPlace, but with extensions. Very nice indeed! +Y.E.S. Graphics and sound Win 3.1, WIN32, XView (Linux) ftp://ftp.musik.uni-essen.de/pub/EsAC/program/ Shareware Monophonic notation program. +JAZZ Graphics and sound XView (Linux) http://rokke.aug.hiagder.no/per/jazz.html Freeware A MIDI sequencer for Linux. +ISP Graphics and sound Win 3.1, WIN32, Motif, XView ftp://www.remstar.com/pub/wxwin/contrib/isp-100/ Freeware Image and sound player educational tool. +ClockWorks Graphics and sound Win 3.1, WIN32, Motif, XView http://web.ukonline.co.uk/Members/julian.smart/freesoft.html#clockworks Freeware A configurable analogue clock, with a collection of 'fine art' faces. By Julian Smart. +M Miscellaneous Windows 95, Windows NT, Linux http://www.phy.hw.ac.uk/~karsten/M/index.html GPL M is a cross-platform e-mail application. It will be available for X11/Unix and Windows platforms, supporting a wide range of e-mail transfer protocols as well as including full MIME support. M's wealth of features and ease of use make it one of the most powerful MUAs available, providing a consistent and intuitive interface across all platforms. +Boolean Miscellaneous Windows 95, Windows NT, Solaris http://www.xs4all.nl/~kholwerd/bool.html Freeware A GDSII CAD file format viewer, and program to perform boolean operations on sets of 2D polygons. By Klaas Holwerda. +TimeMan Miscellaneous wxGTK, Unix http://www.bgif.no/neureka/TimeMan/ Freeware A time manager, written using wxGTK +Forty Thieves Miscellaneous Motif, Windows apps/forty/forty.htm Freeware A fiendish patience game, by Chris Breeze. A nice demo of what's possible with wxWindows. +Lean Integration Platform Miscellaneous Windows NT, various flavours of UNIX http://www.c-lab.de/~lipuser/lip To be decided LIP is a workflow-oriented tool integration system which uses wxLisp (and thus wxWindows) as an implementation basis. Lisp combined with the wxWindows bindings make up the compatible extension language platform of the system. +wxWeb Miscellaneous Win 3.1, WIN32, Motif ftp://www.remstar.com/pub/wxwin/contrib/wxweb Freeware Andrew Davison's Web browser, with SimSock portable socket library and wxHtml canvas. Includes an http server for UNIX and Windows. +SANTIS Miscellaneous Win 3.1, Windows 95, Linux, Solaris OpenLook and Motif, Silicon Graphics http://www.physiology.rwth-aachen.de/bs/santis/ Free for non-commercial use SANTIS is a software tool designed for the analysis of signals and time series data of any kind, in particular for scientific purposes. It was developed at the Laboratory of Biomedical Systems Analysis, Institute of Physiology at the University of Aachen, Germany. +Xbaies Miscellaneous Win 3.1, WIN32, Motif, XView xbaies.htm Freeware A shell for building Bayesian network models, by Robert Cowell. +wxTinyBB Miscellaneous Win 3.1, WIN32, Motif, XView ftp://www.remstar.com/pub/wxwin/contrib/wxtinybb Freeware/commercial A tiny blackboard shell demo showing an embedded (commercial) Prolog engine. Demo written by Arvindra Sehmi. A good example of a nice interface using wxWindows. +Gambit Miscellaneous Win 3.1, WIN32, Motif, XView http://www.hss.caltech.edu/~gambit/Gambit.html Freeware A large wxWindows application with source, and features such as a table control with printing. +Tex2RTF Miscellaneous Win 3.1, WIN32, Motif, XView http://web.ukonline.co.uk/julian.smart/tex2rtf Freeware Converts subset of LaTeX syntax to WinHelp, wordprocessor RTF, HTML, and wxHelp. As used for wxWindows documentation. +wxPoem Miscellaneous Win 3.1, WIN32, Motif, XView none.htm Freeware A poetry display program for wxWindows. Included as a sample in the wxWindows distribution. +Sonar tracking software Miscellaneous See Web site http://www.desertstar.com Demonstration Miscellaneous sonar tracking software from Desert Star Systems, who use wxWindows for all their Windows-based software. +Name Research software Platform Location Availability Description +DisCo Research software N/A http://www.cs.tut.fi/laitos/DisCo/tool.fm.html N/A A tool for specification of reactive systems. +CAFE Research software N/A cafe.htm N/A Cellular Analysis of Fire and Extinction +CODA Research software See Web site http://www.ozemail.com.au/~mbedward/coda/coda.html See Web site CODA assists in the design of networks of nature reserves or protected areas. It has been used for major reserve planning studies, as a teaching resource and for research into conservation planning methods. +EGRESS Research software N/A http://www.aiai.ed.ac.uk/~jimd/Egress2/projInfo_contents.html N/A An evacuation decision model. +ACT Research software N/A none.htm N/A A general process and tracker and automator being built at NASA. +Rectangular nesting program Research software N/A http://www.elec-eng.leeds.ac.uk/een5mpd/research.html N/A Optimized layout of rectangles on a page. +Finite element post processor Research software N/A http://www.ime.auc.dk/afd3/odessy/manuals/index.htm N/A Finite element postprocessor, produced at Aalborg University in Denmark by John Rasmussen and Erik Lund. diff --git a/demo/data/tips.txt b/demo/data/tips.txt new file mode 100644 index 00000000..669f4a9b --- /dev/null +++ b/demo/data/tips.txt @@ -0,0 +1,73 @@ +Each of the leaf items in the tree is a separate demo. Click and learn! +Use the source Luke! +Many of the demos have some helpful overview text associated with them. Simply click on the first tab in the notebook control after selecting the demo. You can switch back and forth to the demo page as often as you like. +You can also view the source code for each demo by clicking on the second notebook tab. +This demo is a teaching tool. The source code for each sample can be modified and you can see the results immediately! +Be sure to subscribe to the mail list. Go to http://wxpython.org/maillist.php today! +The wxPyWiki is a place where wxPython users can help other users, and is a colaborative documentation system. See http://wiki.wxpython.org. +You shouldn't pee on an electric fence! +The whole world is a tuxedo and you are a pair of brown shoes. +Cold hands, no gloves. +Learn to pause -- or nothing worthwhile can catch up to you. +Don't kiss an elephant on the lips today. +Grief can take care of itself; but to get the full value of a joy you must have somebody to divide it with. -- Mark Twain +Stay away from hurricanes for a while. +Beware of a dark-haired man with a loud tie. +Don't ask Robin what these quotes mean, he doesn't remember. +Your lucky number has been disconnected. +You single-handedly fought your way into this hopeless mess. +A few hours grace before the madness begins again. +Your fly might be open (but don't check it just now). +Never commit yourself! Let someone else commit you. +Noise proves nothing. Often a hen who has merely laid an egg cackles as if she laid an asteroid. -- Mark Twain +The very ink with which all history is written is merely fluid prejudice. -- Mark Twain +Excellent time to become a missing person. +Stay away from flying saucers today. +Look afar and see the end from the beginning. +Tomorrow, this will be part of the unchangeable past but fortunately, it can still be changed today. +It has long been an axiom of mine that the little things are infinitely the most important. -- Sir Arthur Conan Doyle +I don't know half of you half as well as I should like; and I like less than half of you half as well as you deserve. -- J. R. R. Tolkien +You are only young once, but you can stay immature indefinitely. +You look like a million dollars. All green and wrinkled. +The difference between the right word and the almost right word is the difference between lightning and the lightning bug. -- Mark Twain +The countdown had stalled at 'T' minus 69 seconds when Desiree, the first female ape to go up in space, winked at me slyly and pouted her thick, rubbery lips unmistakably -- the first of many such advances during what would prove to be the longest, and most memorable, space voyage of my career. -- Winning sentence, 1985 Bulwer-Lytton bad fiction contest. +Q: Why haven't you graduated yet? A: Well, Dad, I could have finished years ago, but I wanted my dissertation to rhyme. +You are scrupulously honest, frank, and straightforward. Therefore you have few friends. +Don't you wish you had more energy... or less ambition? +Are you making all this up as you go along? I am. +Kindness is a language which the deaf can hear and the blind can read. -- Mark Twain +Don't let your mind wander -- it's too little to be let out alone. +Change your thoughts and you change your world. +Don't you feel more like you do now than you did when you came in? +Today is the tomorrow you worried about yesterday. +Caution: breathing may be hazardous to your health. +You will soon forget this. +Go not to the elves for counsel, for they will say both yes and no. -- J.R.R. Tolkien +Today is the first day of the rest of your life. +Cheer Up! Things are getting worse at a slower rate. +You are the only person to ever get this message. +You're almost as happy as you think you are. +Ships are safe in harbor, but they were never meant to stay there. +I must have a prodigious quantity of mind; it takes me as much as a week sometimes to make it up. -- Mark Twain +If you stand on your head, you will get footprints in your hair. +All generalizations are false, including this one. -- Mark Twain +You have the body of a 19 year old. Please return it before it gets wrinkled. +Your ignorance cramps my conversation. +The brain is a wonderful organ; it starts working the moment you get up in the morning and does not stop until you get into the office. -- Robert Frost +By working faithfully eight hours a day, you may get to be a boss and work twelve hours a day. -- Robert Frost +In three words I can sum up everything I've learned about life: it goes on. -- Robert Frost +If we get involved in a nuclear war, would the electromagnetic pulses from exploding bombs damage my videotapes? +The earth? Oh the earth will be gone in a few seconds...I'm going to blow it up. It's obstructing my view of Venus. -- Marvin the Martian +There's that word again, 'heavy'. Why are things so heavy in the future? Is there a problem with the earth's gravitational pull? -- Dr Emmet Brown, "Back To The Future" +I'm Luke Skywalker, I'm here to rescue you. +It is good to have an end to journey towards; but it is the journey that matters, in the end. -- Ursula K. Le Guin, "The Left Hand of Darkness" +I was ready for everything -- except what actually happened. +Flying is simple. You just throw yourself at the ground and miss. -- Douglas Adams, "So Long, and Thanks for the Fish" +Man has always assumed that he is more intelligent than dolphins because he has achieved so much--the wheel, New York, wars and so on -- while all the dolphins had ever done was muck about in the water having a good time. But, conversely, the dolphins had always believed that they were far more intelligent than man -- for precisely the same reasons. -- Douglas Adams, "So Long, and Thanks for the Fish" +I think animal testing is a terrible idea; they get all nervous and give the wrong answers. --A Bit of Fry and Laurie +All right, brain. You don't like me and I don't like you, but let's just do this and I can get back to killing you with beer. -- Homer Simpson +The most exciting phrase to hear in science, the one that heralds new discoveries, is not 'Eureka!' (I found it!) but 'That's funny ...' --Isaac Asimov +Always listen to experts. They'll tell you what can't be done and why. Then do it. --Robert Heinlein +Still waters run deep. +Premature optimization is the root of all evil. -- Donald Knuth +If at first you don't succeed, you must be a programmer. diff --git a/demo/data/widgetTest.htm b/demo/data/widgetTest.htm new file mode 100644 index 00000000..ae27d62e --- /dev/null +++ b/demo/data/widgetTest.htm @@ -0,0 +1,70 @@ + + + + + +wxHTML does wxPython! + + +

    Mixing wxPython and wxHTML

    + +The widgets on this page were created dynamically on the fly by a +custom wxTagHandler found in wxPython.lib.wxpTag. You can look at the +sources and doc-string in the wxPython library at wx/lib/wxpTag.py. + +

    +The button below is added to the page like this: + +

    +<center><wxp module="wx" class="Button" width="50%">
    +    <param name="label" value="It works!">
    +    <param name="id"    value="ID_OK">
    +</wxp></center>
    +
    + +
    + +
    + + + + +
    + +

    +Notice that the button click event is actually caught by the panel +that contains this window, which then logs it in the window below. +

    +


    +

    +This is the same widget reused three times, each with a different +parameter value. Source code is here. +

    + + + + + + + + + + + + +


    + +Recognize this one?
    + + + +


    +You can also embed other wxHtmlWindows!
    +

    + + +
    + diff --git a/demo/data/world.dat b/demo/data/world.dat new file mode 100644 index 00000000..2c445828 --- /dev/null +++ b/demo/data/world.dat @@ -0,0 +1,24055 @@ +# -b +0.192440 5.669954 +-0.657114 5.195893 +-1.417488 5.008146 +-1.936139 4.686630 +-2.595600 4.930701 +-3.003949 4.975290 +-3.832382 5.184159 +-5.198240 5.041002 +-5.585468 4.984678 +-6.223807 4.754688 +-6.787047 4.543473 +-7.293964 4.278280 +-7.735169 4.334604 +-8.835834 4.808665 +-9.807424 5.681688 +-10.412907 6.078303 +-10.800135 6.364617 +-11.095836 6.496040 +-11.196750 6.594607 +-11.163895 6.672052 +-11.461943 6.892655 +-12.299763 7.256414 +-12.562608 7.641295 +-12.794945 8.035563 +-13.069525 8.265553 +-12.982692 8.495543 +-13.092993 8.802979 +-13.179826 9.011847 +-13.325330 9.262958 +-13.555320 9.612637 +-13.919079 9.938847 +-14.029380 9.971702 +# -b +-12.431186 7.498138 +-12.651788 7.486404 +-12.586077 7.366715 +-12.431186 7.498138 +# -b +-49.917183 -0.018775 +-49.863206 0.225296 +-49.863206 0.225296 +# -b +-50.027484 0.957509 +-49.961773 1.300147 +-49.863206 1.731964 +# -b +-59.708179 8.277287 +-59.773891 8.310143 +-59.905313 8.462687 +# -b +-57.060949 5.791989 +-57.272164 6.266050 +-57.657045 6.585219 +-58.208552 6.871533 +-58.518334 6.803475 +-58.462010 7.155500 +-58.649757 7.606093 +-59.168407 8.023829 +-59.642468 8.375855 +-59.696445 8.298409 +-59.708179 8.277287 +# -b +-54.028838 5.482207 +-53.986595 5.791989 +-55.000428 5.968002 +-55.307863 5.890556 +-55.903960 5.801376 +-56.500056 5.902290 +-56.929527 5.956268 +-57.060949 5.791989 +# -b +-51.592823 4.069412 +-51.759449 4.531739 +-52.165451 4.841521 +-52.740426 5.261604 +-53.512535 5.538531 +-53.798848 5.723931 +-54.028838 5.482207 +# -b +-50.194110 0.457633 +-50.337267 0.204175 +-50.048606 0.037549 +# -b +-49.863206 0.225296 +-50.194110 0.457633 +-50.194110 0.457633 +# -b +-50.931016 -0.007041 +-50.435834 0.525691 +-50.027484 0.957509 +-50.027484 0.957509 +# -b +-49.863206 1.731964 +-50.445221 1.910324 +-50.665824 2.619068 +-50.963872 3.625860 +-51.196208 4.135123 +-51.383955 4.290015 +-51.592823 4.069412 +-51.592823 4.069412 +# -b +-59.905313 8.462687 +-60.280807 8.584723 +-60.778336 8.486156 +-60.820579 8.584723 +-60.733746 8.758389 +-60.921493 9.415503 +-61.395554 9.600903 +-61.649012 9.765181 +-61.792169 9.852014 +-62.022159 9.875482 +-62.409387 9.896604 +-62.409387 9.896604 +# -b +-80.038812 9.065824 +-79.851065 9.239490 +-79.487306 9.612637 +-79.111812 9.546925 +-78.527450 9.415503 +-77.954822 9.131535 +-77.569942 8.781857 +-77.569942 8.781857 +# -b +-77.900845 7.244680 +-78.363172 7.904141 +-78.196546 8.375855 +-78.440617 8.429832 +-79.078957 8.922667 +-79.740764 8.683290 +-79.907389 8.429832 +# -b +-77.900845 7.244680 +-77.745954 6.937245 +-77.480762 6.672052 +-77.424438 6.266050 +-77.370461 5.791989 +-77.525352 5.526797 +-77.447906 5.008146 +-77.370461 4.477761 +-77.459640 3.935643 +-77.084147 3.902787 +-77.138124 3.682184 +-77.480762 3.294957 +-77.680243 2.907729 +-78.032268 2.607334 +-78.461739 2.562744 +-78.682341 2.121539 +-78.628364 1.800023 +-78.968655 1.633397 +-78.924065 1.412795 +-78.881822 1.377592 +# -b +-78.870088 1.377592 +-79.189258 1.112400 +-79.642197 0.812005 +-79.829944 0.823739 +# -b +-75.671352 10.016292 +-75.683086 9.666614 +-75.981134 9.415503 +-76.344894 8.988379 +-76.884666 8.650434 +-76.764977 8.420444 +-76.753243 8.056685 +-76.962111 7.981586 +-77.138124 8.342999 +-77.415050 8.650434 +-77.569942 8.781857 +# -b +-71.317973 10.114859 +-71.064515 9.481214 +-71.261649 9.065824 +-71.669998 9.251224 +-71.979780 9.720591 +-72.012636 9.875482 +# -b +-81.803632 7.707007 +-81.878731 7.584971 +-81.726187 7.486404 +-81.803632 7.707007 +# -b +-83.235202 10.114859 +-82.718898 9.678348 +-82.376260 9.328670 +-82.155657 9.328670 +-81.935055 9.000113 +-81.284982 8.835834 +-80.733475 9.044703 +-80.092789 9.328670 +-80.038812 9.065824 +# -b +-79.907389 8.429832 +-80.435427 8.166986 +-80.259415 7.728128 +-80.203091 7.432427 +-80.766331 7.211824 +-80.954078 7.420693 +-81.064379 7.772718 +-81.228657 7.596705 +-81.592417 7.871285 +-81.693331 8.035563 +-82.188513 8.265553 +-82.617984 8.319531 +-82.916032 8.232698 +-83.026333 8.310143 +-83.157756 8.605844 +-83.390093 8.561255 +-83.720996 8.638700 +-83.986189 9.295814 +-84.558817 9.579781 +-84.791153 9.938847 +-84.791153 9.938847 +# -b +-85.176034 10.016292 +-85.021143 9.753447 +-85.396637 9.863748 +-85.694685 9.962315 +# -b +-79.829944 0.823739 +-80.071668 0.359066 +-80.059934 0.171319 +# -b +-91.383413 0.147851 +-91.371679 0.103261 +# -b +-91.526570 -0.051630 +-91.383413 0.147851 +-91.383413 0.147851 +# -b +-157.343561 2.013585 +-157.254381 1.968995 +-157.144080 1.769514 +-156.989189 1.591154 +-157.364683 1.680334 +-157.421007 1.778901 +-157.275503 1.868081 +-157.343561 1.990116 +-157.343561 2.013585 +# -b +-162.079475 5.937493 +-162.079475 5.892903 +-162.079475 5.937493 +# -b +-176.564141 0.227643 +-176.564141 0.227643 +-176.564141 0.227643 +-176.564141 0.227643 +# -b +170.884800 8.861649 +170.962245 8.807672 +171.117137 8.718493 +171.149992 8.511971 +170.995101 8.554214 +170.861332 8.718493 +170.828476 8.849915 +170.884800 8.861649 +# -b +172.860835 1.891549 +172.926546 1.835225 +172.971136 1.501974 +173.048582 1.281372 +172.905425 1.447997 +172.881957 1.769514 +172.860835 1.891549 +# -b +163.112082 5.364865 +163.058105 5.308541 +163.013515 5.364865 +163.112082 5.364865 +# -b +166.909261 9.288773 +167.031297 9.277039 +167.240165 9.255918 +167.439646 9.300508 +167.639127 8.993072 +167.627393 8.697371 +167.505357 8.939095 +167.240165 9.157351 +166.998441 9.190206 +166.909261 9.288773 +166.909261 9.288773 +# -b +169.549451 5.993817 +169.493127 6.014938 +169.549451 5.993817 +# -b +152.126547 7.115604 +152.138281 7.115604 +152.126547 7.115604 +# -b +153.661377 5.606589 +153.717701 5.606589 +153.661377 5.606589 +153.661377 5.606589 +# -b +158.286989 7.005303 +158.397290 6.873880 +158.277602 6.873880 +158.286989 7.005303 +158.286989 7.005303 +# -b +134.729458 7.664764 +134.738845 7.512219 +134.595688 7.455895 +134.694255 7.655376 +134.729458 7.664764 +# -b +138.240323 9.584475 +138.282566 9.528151 +138.240323 9.584475 +138.240323 9.584475 +# -b +123.368429 10.215773 +123.180682 9.725285 +123.237006 9.342751 +122.903756 9.190206 +122.539996 9.528151 +122.563465 9.964662 +122.563465 9.964662 +# -b +125.687102 10.161796 +125.687102 9.812118 +125.654246 9.943540 +# -b +126.018006 9.997518 +126.116573 9.790996 +126.018006 9.997518 +126.018006 9.997518 +# -b +123.699333 10.020986 +123.490464 9.518763 +123.368429 9.856708 +123.368429 9.856708 +# -b +123.833102 9.844973 +123.985647 9.955275 +123.985647 9.955275 +# -b +124.572355 10.020986 +124.548887 9.737019 +124.250839 9.593862 +123.908201 9.683042 +123.833102 9.844973 +# -b +125.421910 9.713551 +125.499355 9.746406 +125.719958 9.561006 +126.029740 9.277039 +126.316054 8.894505 +126.161163 8.587070 +126.348910 8.258513 +126.447477 7.852510 +126.581246 7.324472 +126.370031 6.963060 +126.271464 6.366964 +126.071983 6.995916 +125.818525 7.357328 +125.576801 7.038159 +125.543945 6.488999 +125.698836 5.970349 +125.344464 5.672301 +125.123862 5.904637 +124.572355 6.014938 +124.131150 6.444409 +124.009115 7.017037 +124.217983 7.446508 +123.699333 7.852510 +123.424753 7.566196 +123.290983 7.533341 +123.082115 7.566196 +122.915490 7.336207 +122.662032 7.709353 +122.385105 7.303351 +122.119913 6.906736 +122.000224 7.282229 +122.152768 7.840776 +122.673766 8.127090 +123.091503 8.488503 +123.478730 8.676249 +123.743923 8.061379 +124.131150 8.192801 +124.593477 8.533093 +124.814079 8.960217 +125.112128 8.939095 +125.466500 9.025928 +125.475887 9.333363 +125.421910 9.671308 +125.421910 9.713551 +# -b +121.833599 6.632156 +122.253682 6.643890 +122.000224 6.432675 +121.833599 6.632156 +# -b +120.951189 5.871781 +121.106080 6.036060 +121.425250 5.949227 +121.049756 5.860047 +120.951189 5.871781 +# -b +119.967865 5.186506 +120.254179 5.144263 +120.134490 5.099673 +# -b +121.115467 1.325962 +121.446371 1.302493 +121.735032 1.081891 +122.152768 1.103013 +122.584586 1.025567 +122.861513 0.882410 +123.246394 0.980977 +123.788513 0.903532 +124.274307 1.058423 +124.692044 1.436263 +125.135596 1.713190 +125.189573 1.370552 +124.804692 0.882410 +124.262573 0.361413 +123.556176 0.305089 +122.903756 0.492835 +122.363984 0.483448 +121.767887 0.492835 +121.368926 0.516304 +120.906599 0.427124 +120.331624 0.272233 +120.188467 0.028162 +# -b +119.956131 0.471714 +120.265913 0.903532 +120.608551 0.816699 +120.927721 1.302493 +121.115467 1.325962 +# -b +125.433644 3.717387 +125.576801 3.541374 +125.543945 3.541374 +125.433644 3.717387 +# -b +126.768993 4.536432 +126.867560 4.348685 +126.822970 4.027169 +126.768993 4.536432 +126.768993 4.536432 +# -b +128.557282 2.654271 +128.667583 2.433668 +128.611259 2.201331 +128.303823 2.189597 +128.381269 2.555703 +128.500957 2.654271 +# -b +127.937717 2.222453 +128.026897 2.112152 +127.862618 1.846959 +128.026897 1.415142 +127.785173 1.025567 +127.794560 0.849554 +128.148932 1.248516 +128.601871 1.525443 +128.723907 1.093625 +128.324945 0.804964 +128.634727 0.549159 +128.834208 0.260499 +128.226378 0.406002 +127.928330 0.061018 +127.928330 0.061018 +# -b +127.749970 -0.269886 +127.597426 0.537425 +127.475391 0.992711 +127.419066 1.347083 +127.651403 1.957260 +127.937717 2.222453 +# -b +109.965654 1.835225 +110.329413 1.769514 +110.660317 1.680334 +111.080400 1.602888 +111.157846 1.736658 +111.223557 1.957260 +111.268147 2.245921 +111.455894 2.356222 +111.479362 2.588559 +111.643641 2.842017 +111.920567 2.919463 +112.084846 2.964053 +112.185760 2.987521 +112.526051 3.020377 +112.868689 3.086088 +113.145615 3.395870 +113.321628 3.595351 +113.509375 3.884012 +113.729977 4.060025 +113.905990 4.280627 +113.974048 4.480108 +114.006904 4.590410 +114.105471 4.634999 +114.382397 4.691323 +114.725035 4.888458 +114.955025 5.076204 +115.055939 4.933047 +115.175628 4.944782 +115.276542 4.933047 +115.530000 5.144263 +115.419698 5.353131 +115.661422 5.496288 +116.004060 5.782602 +116.114362 6.092384 +116.367820 6.390432 +116.567301 6.599300 +116.743313 6.951326 +116.799638 6.829290 +116.766782 6.542976 +116.963916 6.787047 +117.207987 6.873880 +117.351144 6.575832 +117.571746 6.533589 +117.705516 6.324721 +117.660926 6.026673 +117.771227 5.925759 +118.036420 5.970349 +118.003564 5.716890 +118.245288 5.773214 +118.609047 5.585468 +119.019744 5.409455 +119.273202 5.209974 +118.930564 4.977637 +118.543336 4.867336 +118.245288 4.757035 +118.400179 4.545820 +118.599660 4.390929 +118.245288 4.292361 +117.926118 4.238384 +117.705516 4.336951 +117.660926 4.160939 +117.449711 4.048291 +117.825204 3.851156 +117.595215 3.672797 +117.318288 3.607086 +117.383999 3.353627 +117.407468 3.187002 +117.649192 2.919463 +117.958974 2.412547 +117.970708 2.112152 +117.947240 1.891549 +118.477625 1.424529 +118.975154 0.992711 +118.587926 0.837820 +118.191311 0.894144 +118.003564 0.980977 +117.848673 0.704051 +117.583480 0.215909 +117.583480 0.007041 +# -b +119.130045 10.009252 +118.754551 9.593862 +118.146721 9.037662 +117.604602 8.643394 +117.240843 8.434525 +117.562359 9.025928 +118.102131 9.420196 +118.510480 9.844973 +# -b +119.878685 4.989371 +119.967865 5.186506 +119.967865 5.186506 +# -b +120.134490 5.099673 +119.979599 5.043349 +119.878685 4.989371 +# -b +119.791852 -0.049284 +119.956131 0.471714 +119.956131 0.471714 +# -b +104.049282 1.436263 +104.037548 1.525443 +104.016427 1.546564 +103.816946 1.501974 +103.870923 1.325962 +104.049282 1.436263 +# -b +100.207513 6.444409 +100.073744 6.676746 +# -b +102.216404 6.190951 +102.678731 5.925759 +103.087080 5.618323 +103.495429 4.977637 +103.507163 4.193794 +103.507163 3.496784 +103.760622 2.799774 +104.213561 2.055828 +104.201827 1.447997 +103.805211 1.647478 +103.572875 1.403407 +103.650320 1.391673 +103.507163 1.501974 +102.988513 1.802369 +102.293850 2.189597 +101.608574 2.731716 +101.298792 3.374749 +100.803609 4.006048 +100.693308 4.602144 +100.470359 5.120794 +100.371792 5.949227 +100.207513 6.444409 +100.207513 6.444409 +# -b +99.909465 9.244184 +100.130068 8.500237 +100.470359 7.819655 +100.625250 7.315085 +101.265936 6.930204 +102.061513 6.432675 +102.216404 6.190951 +# -b +106.630801 10.086697 +106.609679 9.988130 +# -b +106.499378 10.009252 +106.478257 9.572740 +106.013583 9.943540 +106.145006 9.429584 +105.903282 9.288773 +105.340042 8.784204 +104.887102 8.676249 +104.842513 9.190206 +104.865981 9.692429 +104.997404 9.868442 +# -b +99.885997 3.130678 +100.228635 2.731716 +100.604128 2.323367 +100.923298 2.091030 +101.155635 2.255309 +101.399705 1.912671 +101.519394 1.736658 +101.796321 1.647478 +102.094369 1.492587 +102.282115 1.203926 +102.371295 1.358818 +102.669343 1.081891 +103.164525 1.025567 +103.176260 0.870676 +103.065958 0.682929 +103.131670 0.560894 +102.911067 0.305089 +103.042490 0.293354 +103.408596 0.492835 +103.739500 0.328557 +103.838067 0.072752 +# -b +101.817442 1.790635 +101.697753 1.835225 +101.552250 1.968995 +101.620308 2.067562 +101.840910 2.079296 +101.894888 1.879815 +101.817442 1.790635 +101.817442 1.790635 +# -b +102.160080 1.668600 +102.303237 1.624010 +102.523839 1.614623 +102.580163 1.347083 +102.371295 1.480853 +102.160080 1.668600 +102.160080 1.668600 +# -b +104.666500 1.171071 +104.732211 0.894144 +104.544464 1.070157 +104.445897 1.213314 +104.666500 1.171071 +104.666500 1.171071 +# -b +109.623016 2.055828 +109.745051 2.055828 +109.965654 1.835225 +109.965654 1.835225 +# -b +109.202932 -0.082139 +109.026920 0.382534 +108.994064 0.816699 +109.059775 1.225048 +109.336702 1.724924 +109.623016 2.055828 +109.623016 2.055828 +# -b +100.073744 6.676746 +99.686516 7.225905 +99.212455 7.807920 +98.738394 8.258513 +98.330045 8.389936 +98.440346 9.255918 +98.639827 9.964662 +98.639827 9.964662 +# -b +99.191334 10.009252 +99.322756 9.244184 +99.909465 9.244184 +99.909465 9.244184 +# -b +98.384022 8.115356 +98.384022 7.840776 +98.419225 8.148212 +98.384022 8.115356 +# -b +93.847590 7.282229 +93.680965 7.028771 +93.892180 7.181315 +93.758410 7.303351 +# -b +95.326096 5.606589 +95.436397 5.606589 +95.525577 5.630057 +95.614757 5.630057 +95.933926 5.552612 +96.210853 5.332009 +96.562878 5.263951 +96.982962 5.287420 +97.534468 5.198240 +97.975673 4.933047 +98.130564 4.590410 +98.395756 4.292361 +98.672683 3.982579 +99.090420 3.661063 +99.644273 3.330159 +99.885997 3.130678 +# -b +99.963442 -0.147851 +99.543359 0.251111 +99.355612 0.293354 +99.212455 0.849554 +98.937875 1.501974 +98.604625 2.046440 +98.076587 2.299898 +97.755070 2.710595 +97.557936 2.987521 +97.334987 3.297303 +96.884395 3.740855 +96.354010 4.104615 +95.901071 4.491842 +95.546699 4.900192 +95.370686 5.332009 +95.326096 5.606589 +95.326096 5.606589 +# -b +95.868215 2.809162 +95.922192 2.919463 +96.342276 2.644883 +96.551144 2.377344 +96.231974 2.532235 +95.868215 2.809162 +95.868215 2.809162 +# -b +97.302131 1.403407 +97.424167 1.513709 +97.755070 1.257904 +98.041384 0.971590 +98.053119 0.694663 +97.820782 0.793230 +97.534468 1.081891 +97.334987 1.370552 +97.302131 1.403407 +# -b +80.024731 9.812118 +80.024731 9.812118 +# -b +79.926164 9.746406 +80.278189 9.462439 +80.048199 9.112761 +80.048199 9.112761 +# -b +79.893308 6.510121 +80.510526 5.958614 +81.240392 6.223807 +81.791898 7.160194 +81.658128 7.732822 +81.371814 8.455647 +81.195802 8.697371 +81.040911 8.894505 +80.665417 9.408462 +80.179622 9.802730 +80.024731 9.812118 +# -b +79.186911 10.096085 +78.900597 9.617330 +78.900597 9.265305 +78.391334 9.136229 +78.126141 8.849915 +78.027574 8.479115 +77.795238 8.303103 +77.330564 8.105969 +76.603045 8.981338 +76.337853 9.746406 +# -b +80.024731 9.812118 +79.926164 9.746406 +# -b +80.048199 9.112761 +79.869840 8.544827 +79.726683 8.148212 +79.726683 7.413652 +79.893308 6.510121 +79.893308 6.510121 +# -b +50.832449 10.159449 +50.722148 9.403768 +50.402978 8.856956 +50.072074 8.211576 +49.806882 7.880672 +49.553424 7.244680 +49.168543 6.606341 +49.067629 6.341149 +48.804783 5.613630 +48.142976 4.984678 +47.767482 4.266546 +47.194854 3.637594 +46.819361 3.205777 +46.422746 2.917116 +46.047252 2.452443 +45.507480 2.032359 +44.845672 1.743699 +44.416202 1.412795 +44.007852 1.067810 +43.500936 0.570281 +43.137177 0.192440 +43.137177 0.192440 +# -b +36.101365 4.522351 +36.300846 4.179713 +36.289112 3.637594 +36.521448 2.863139 +36.742051 2.508767 +36.631750 2.520501 +36.211666 2.985174 +35.969942 3.593005 +35.958208 4.388582 +35.991064 4.522351 +# -b +34.029109 0.237030 +34.019722 0.114995 +# -b +34.073699 0.237030 +33.665350 0.192440 +33.203023 0.237030 +32.740697 0.147851 +32.529482 0.058671 +32.419180 0.103261 +# -b +5.001106 5.824845 +4.592756 6.221460 +4.074106 6.364617 +3.248020 6.352883 +2.795081 6.320027 +2.332754 6.275437 +1.825838 6.221460 +1.274331 6.054835 +1.009139 5.747399 +0.621911 5.747399 +0.192440 5.669954 +# -b +5.001106 5.824845 +5.186506 5.637098 +5.451698 5.404761 +5.451698 4.796931 +5.761480 4.421437 +6.212073 4.212569 +6.566445 4.343992 +6.787047 4.379194 +6.963060 4.498883 +7.249374 4.599797 +7.932303 4.498883 +8.242085 4.864989 +8.396976 4.742954 +# -b +9.232449 -0.194787 +9.420196 0.147851 +9.840280 0.136116 +9.476520 0.314476 +9.342751 0.603137 +9.521110 0.880063 +9.575087 1.023220 +9.342751 1.290759 +9.553966 1.755433 +9.685389 2.231840 +9.762834 2.795081 +9.884870 3.238632 +9.631411 3.560149 +9.607943 3.769017 +9.575087 4.045944 +9.342751 3.947377 +8.892158 4.266546 +8.725533 4.543473 +8.439219 4.566941 +8.396976 4.742954 +8.396976 4.742954 +# -b +8.605844 3.813607 +8.814713 3.703306 +8.793591 3.337200 +8.418098 3.393524 +8.582376 3.747896 +8.605844 3.813607 +# -b +6.488999 0.314476 +6.444409 0.082139 +6.632156 0.302742 +6.488999 0.314476 +# -b +-14.029380 9.971702 +-14.437730 10.311994 +-14.491707 10.659325 +-14.670066 10.746158 +-14.747512 10.952680 +-14.968114 10.746158 +-15.054947 11.051247 +-15.275550 11.095836 +-15.352995 11.431434 +-15.430441 11.703667 +-15.043213 11.844477 +-15.043213 11.919576 +-15.672165 11.736522 +-15.892767 11.877333 +-16.256527 11.985287 +-16.432540 12.191808 +-16.718853 12.548527 +-16.697732 13.013201 +-16.676610 13.391041 +-16.444274 13.261965 +-16.378562 13.358186 +-16.500598 13.691436 +-16.763443 14.186618 +-17.183527 14.679454 +-17.150671 14.841385 +-16.521719 15.686246 +-16.399684 15.942051 +-16.333972 16.939456 +-15.991335 18.122261 +-16.101636 19.016405 +-16.444274 19.413020 +-16.345707 19.528015 +-16.202550 19.934018 +# -b +-15.881033 11.095836 +-16.092248 10.943292 +-15.881033 11.095836 +# -b +-24.989100 17.141284 +-25.275414 16.951190 +-24.967979 17.035676 +-24.989100 17.141284 +# -b +-23.930678 16.556922 +-24.249847 16.610899 +-24.282703 16.472436 +-24.029245 16.535800 +-23.930678 16.556922 +# -b +-22.893377 16.887826 +-22.926232 16.632021 +-22.883989 16.866704 +-22.893377 16.887826 +# -b +-22.872255 16.122757 +-22.639918 15.984294 +-22.883989 15.972560 +-22.872255 16.122757 +# -b +-23.698341 15.247388 +-23.721809 14.883628 +-23.390906 15.000970 +-23.698341 15.247388 +-23.698341 15.247388 +# -b +-24.339027 14.916484 +-24.458716 14.820264 +-24.273316 14.829651 +-24.339027 14.916484 +# -b +-70.060069 18.385106 +-69.532031 18.439084 +-68.924201 18.385106 +-68.527586 18.354598 +-68.506464 18.744172 +-68.825634 19.004671 +-69.201127 19.058648 +-69.597743 19.161909 +-69.233983 19.255782 +-69.839467 19.464651 +-69.949768 19.643010 +# -b +-66.046981 18.502448 +-65.760667 18.385106 +-65.981270 18.007266 +-66.621956 17.995532 +-67.203971 18.007266 +-67.248561 18.439084 +-66.697054 18.532957 +-66.046981 18.502448 +-66.046981 18.502448 +# -b +-64.934581 18.406228 +-64.934581 18.312355 +-64.934581 18.406228 +# -b +-64.845401 17.765542 +-64.735100 17.786663 +-64.845401 17.765542 +# -b +-62.409387 9.896604 +-62.597133 10.222814 +-62.871713 10.365971 +-62.716822 10.551371 +-62.353063 10.527902 +-61.979916 10.680447 +-62.287351 10.746158 +-62.618255 10.713302 +-63.125171 10.757892 +-63.831569 10.692181 +-64.228184 10.671059 +-64.139004 10.572492 +-63.721267 10.539637 +-64.183594 10.473925 +-64.547353 10.246282 +-65.274872 10.147715 +-65.540065 10.168837 +-66.025860 10.464538 +-66.046981 10.518515 +-66.366151 10.671059 +-67.293150 10.572492 +-67.889247 10.485659 +-68.264740 10.800135 +-68.241272 10.889315 +-68.560441 11.302358 +-68.992259 11.431434 +-69.189393 11.508879 +-69.266839 11.518267 +-69.487441 11.530001 +-69.630598 11.595712 +-69.729165 11.757644 +-69.940381 12.245786 +-69.940381 12.245786 +# -b +-70.017826 11.637955 +-69.818345 11.551123 +-69.982624 11.431434 +# -b +-69.046236 12.299763 +-69.111948 12.288029 +-68.804512 12.093241 +-69.046236 12.299763 +-69.046236 12.299763 +# -b +-68.375041 12.288029 +-68.318717 12.180074 +-68.220150 12.224664 +-68.375041 12.288029 +# -b +-63.897280 11.170935 +-63.897280 10.943292 +-64.162472 10.943292 +-64.293895 11.095836 +-63.974726 11.126345 +-63.897280 11.170935 +# -b +-61.548098 12.180074 +-61.702989 11.985287 +-61.548098 12.180074 +# -b +-61.031794 13.304208 +-61.074037 13.067178 +-61.031794 13.304208 +-61.031794 13.304208 +# -b +-60.921493 14.036421 +-60.998939 13.736026 +-60.853435 13.841634 +-60.921493 14.036421 +# -b +-61.196073 14.904750 +-60.930880 14.627823 +-60.998939 14.433036 +-61.184339 14.754552 +-61.196073 14.904750 +# -b +-61.318108 15.620535 +-61.372085 15.355342 +-61.207807 15.343608 +-61.318108 15.620535 +-61.318108 15.620535 +# -b +-61.416675 16.505291 +-61.548098 16.345707 +-61.803903 16.186122 +-61.583301 16.186122 +-61.252397 16.282342 +-61.416675 16.505291 +-61.416675 16.505291 +# -b +-61.825025 17.153018 +-61.869615 17.002821 +-61.702989 17.087307 +-61.825025 17.153018 +# -b +-62.784880 17.427598 +-62.794268 17.289134 +-62.784880 17.427598 +-62.784880 17.427598 +# -b +-60.513144 11.344601 +-60.722012 11.224912 +-60.590589 11.248381 +-60.513144 11.344601 +# -b +-60.942615 10.832991 +-61.693602 10.671059 +-61.759313 10.093738 +-61.031794 10.159449 +-60.987204 10.647591 +-60.942615 10.832991 +-60.942615 10.832991 +# -b +-74.955567 20.006769 +-75.781653 19.945752 +-76.598352 19.976261 +-77.337605 19.861266 +-77.656774 19.840144 +# -b +-77.149858 18.469592 +-76.908134 18.375719 +-76.422339 18.248990 +-76.466929 17.892271 +-77.095881 17.892271 +-77.469028 17.871150 +-78.020534 18.155117 +-78.306848 18.427349 +-77.900845 18.565813 +-77.447906 18.502448 +-77.149858 18.469592 +# -b +-73.047590 18.962428 +-72.862190 18.732438 +-73.324517 18.941306 +-73.047590 18.962428 +# -b +-71.803768 19.797901 +-72.364661 19.758005 +-73.202481 19.945752 +-73.258805 19.652397 +-72.794132 19.382511 +-72.761276 18.995284 +-72.453841 18.575200 +-73.258805 18.481327 +-73.819699 18.584587 +-74.427529 18.439084 +-73.908879 18.058896 +-73.378494 18.260724 +-72.784745 18.143382 +-72.320071 18.270111 +-71.768565 18.049509 +-71.616021 17.765542 +-71.252261 17.943901 +-70.876768 18.363985 +-70.524742 18.206747 +-70.060069 18.385106 +# -b +-69.949768 19.643010 +-70.667899 19.830757 +-71.306239 19.873000 +-71.803768 19.797901 +-71.803768 19.797901 +# -b +-71.306239 11.823355 +-71.195937 12.147219 +-71.362563 12.374862 +-71.693466 12.503938 +-71.911722 12.365474 +-72.066613 12.212930 +-72.287216 11.877333 +-72.728421 11.649690 +-72.960757 11.518267 +-73.235337 11.365723 +-73.753988 11.278890 +-74.007446 11.323479 +-74.371205 10.997269 +-74.800676 10.985535 +-75.187904 10.877581 +-75.629109 10.518515 +-75.671352 10.016292 +-75.671352 10.016292 +# -b +-69.940381 12.245786 +-70.280672 11.886720 +-70.017826 11.637955 +-70.017826 11.637955 +# -b +-69.982624 11.431434 +-70.623310 11.278890 +-71.350828 10.952680 +-71.461130 10.527902 +-71.317973 10.114859 +# -b +-72.012636 9.875482 +-71.714588 10.387092 +-71.550309 10.692181 +-71.625408 11.018391 +-71.890601 11.530001 +-71.493985 11.670811 +-71.306239 11.823355 +-71.306239 11.823355 +# -b +-87.492360 20.018504 +-87.546338 19.643010 +-87.602662 19.361390 +-87.689495 18.859167 +-87.832652 18.291233 +-87.987543 18.206747 +-88.086110 18.532957 +-88.064988 18.816924 +-88.395892 18.575200 +-88.285591 18.396841 +-88.264469 17.774929 +-88.318446 16.845583 +-88.560170 16.387950 +-88.923930 15.909195 +-88.804241 15.812975 +-88.517927 15.834097 +-88.616494 15.834097 +-88.339568 15.728489 +# -b +-88.285591 15.728489 +-88.020398 15.782466 +-87.337469 15.791854 +-86.544239 15.845831 +-85.992733 15.993681 +-85.539794 15.876340 +-85.000022 15.942051 +-84.460249 15.834097 +-84.096490 15.632269 +-83.699875 15.355342 +-83.303260 15.076069 +-83.268057 14.369671 +-83.577839 13.046056 +-83.655285 12.482816 +-83.699875 11.832743 +-83.864153 11.344601 +-83.655285 10.769626 +-83.235202 10.114859 +-83.235202 10.114859 +# -b +-84.791153 9.938847 +-85.154913 10.159449 +-85.176034 10.016292 +# -b +-85.694685 9.962315 +-85.894166 10.527902 +-85.804986 10.856459 +-85.793252 11.051247 +-86.079566 11.464290 +-86.696783 12.060386 +-87.248290 12.560262 +-87.623783 12.938102 +-87.403181 12.959224 +-87.501748 13.238497 +-87.668373 13.400429 +-87.975808 13.238497 +-88.848831 13.261965 +-89.585737 13.520117 +-89.806340 13.562360 +# -b +-85.551528 11.248381 +-85.816720 11.595712 +-85.849576 12.158953 +-85.396637 11.865598 +-85.077467 11.595712 +-84.856865 11.126345 +-84.856865 11.126345 +# -b +-96.457271 20.002076 +-96.325848 19.720456 +-96.170957 19.377818 +-96.138101 19.220580 +-96.070043 19.199458 +-95.905764 19.032833 +-95.739139 18.863861 +-95.375380 18.706623 +-94.999886 18.647952 +-94.999886 18.647952 +# -b +-100.045582 16.944150 +-99.681822 16.775178 +-99.273473 16.648448 +-98.829921 16.488864 +-98.632787 16.488864 +-98.355860 16.265914 +-97.992101 16.073474 +-97.780886 16.000722 +-97.473450 15.892767 +-97.065101 15.862259 +-96.865620 15.787160 +-96.600428 15.700327 +-96.192078 15.615841 +-95.882296 15.744917 +-95.518537 15.862259 +-95.143043 16.115717 +-95.044476 16.148573 +# -b +-94.999886 18.647952 +-94.725306 18.375719 +-94.063499 18.312355 +-93.312512 18.523570 +-92.718762 18.669073 +-91.967775 18.711316 +-91.791762 18.502448 +-91.296580 18.690195 +-91.075978 19.131400 +-90.745074 19.746271 +-90.634773 19.891775 +# -b +-89.806340 13.562360 +-90.435292 13.895611 +-91.031388 13.940201 +-91.845740 14.303960 +-92.244702 14.594968 +-92.695294 14.970461 +-93.202210 15.460950 +-93.765451 15.888074 +-94.370934 16.132145 +-94.922440 16.195509 +-94.999886 16.186122 +# -b +-105.356469 20.044319 +-105.279024 19.753311 +-104.924652 19.450570 +-104.614870 19.178337 +-104.197133 19.072729 +-103.899085 18.833352 +-103.601037 18.654992 +-103.565834 18.528263 +-103.434411 18.413268 +-103.180953 18.244296 +-102.936882 18.171544 +-102.749136 18.087058 +-102.408845 17.990838 +-101.965293 17.896965 +-101.702447 17.842987 +-101.479498 17.643506 +-101.336341 17.516777 +-100.951460 17.326684 +-100.829424 17.167099 +-100.641678 17.115469 +-100.355364 17.019248 +-100.045582 16.944150 +# -b +-113.150309 18.150423 +-113.150309 18.129301 +-113.150309 18.150423 +# -b +-155.752407 20.044319 +-155.477827 19.950445 +-155.189167 19.826063 +-155.069478 19.659438 +-154.923974 19.544443 +-154.780817 19.323840 +-154.959177 19.157215 +-155.376913 19.051608 +-155.520070 18.842739 +-155.818118 18.978856 +-155.940154 19.492813 +-155.829853 19.919937 +-155.829853 19.919937 +# -b +166.489178 19.366083 +166.500912 19.323840 +166.500912 19.323840 +166.489178 19.366083 +# -b +166.888140 11.415006 +167.019562 11.447862 +166.965585 11.316439 +166.754370 11.154507 +166.721514 11.361029 +166.888140 11.415006 +166.888140 11.415006 +# -b +145.360621 20.013810 +145.292563 19.992688 +145.292563 19.992688 +# -b +145.888659 18.138689 +145.900393 18.087058 +145.855803 18.096446 +145.879272 18.129301 +145.888659 18.138689 +# -b +145.790092 15.017398 +145.768970 14.975155 +145.757236 15.050254 +145.790092 15.017398 +# -b +144.952272 13.513077 +144.907682 13.405122 +144.806768 13.254925 +144.818502 13.437978 +144.952272 13.513077 +144.952272 13.513077 +# -b +119.946743 11.891414 +120.045311 11.741216 +120.000721 11.696626 +# -b +119.967865 12.227011 +120.176733 12.163646 +120.200202 12.032224 +120.012455 12.086201 +# -b +120.376214 13.416856 +120.542840 13.480221 +120.927721 13.480221 +121.347804 13.287780 +121.514429 12.963917 +121.556672 12.574343 +121.392394 12.292722 +121.005166 12.445267 +120.796298 13.039016 +120.519371 13.395735 +120.376214 13.416856 +# -b +122.253682 18.422656 +122.263070 18.213787 +122.152768 17.622385 +122.340515 17.284441 +122.474285 16.913641 +122.230214 16.298770 +122.009612 16.073474 +121.612996 15.712061 +121.404128 15.296671 +121.591875 14.792102 +121.634118 14.416608 +121.845333 14.019993 +122.241948 13.933160 +122.286538 14.149069 +122.716009 14.332122 +123.058647 13.977750 +123.279249 13.836940 +123.413019 13.954282 +123.842490 13.794697 +123.589032 13.567054 +123.854224 13.297168 +123.908201 13.092993 +123.931669 13.039016 +124.107682 12.790251 +123.887080 12.628320 +123.964525 12.865350 +123.478730 13.017894 +123.168948 13.416856 +122.838044 13.675008 +122.507141 13.663274 +122.694887 13.200948 +122.319394 13.545932 +121.922779 13.879183 +121.490961 13.707864 +121.094346 13.707864 +120.730586 13.782963 +120.697731 14.266411 +120.918333 14.653639 +120.608551 14.491707 +120.322237 14.749859 +120.057045 15.306059 +120.057045 15.306059 +# -b +119.967865 16.211937 +120.343359 16.392643 +120.432538 17.157712 +120.432538 17.906352 +120.596817 18.464899 +121.038022 18.579894 +121.666974 18.307661 +122.042467 18.528263 +122.253682 18.422656 +122.253682 18.422656 +# -b +121.889923 14.996276 +122.009612 14.921178 +121.932166 14.663026 +121.889923 14.996276 +122.000224 15.038520 +# -b +121.866455 13.320636 +121.833599 13.503689 +122.087057 13.470834 +122.077670 13.200948 +121.866455 13.320636 +121.866455 13.320636 +# -b +121.988490 12.445267 +122.098791 12.607198 +122.021346 12.130791 +121.988490 12.445267 +# -b +122.441429 12.445267 +122.551730 12.466388 +122.662032 12.304457 +122.441429 12.445267 +122.441429 12.445267 +# -b +123.004670 13.114115 +123.103237 13.027282 +123.290983 12.855963 +123.302718 12.780864 +123.058647 12.996773 +123.004670 13.114115 +# -b +123.654743 12.628320 +123.743923 12.508631 +123.678211 12.520365 +123.654743 12.628320 +# -b +123.258128 12.562608 +123.389551 12.466388 +123.743923 12.250479 +124.030237 11.924269 +123.985647 11.783459 +123.600766 12.109669 +123.269862 11.968859 +123.258128 12.238745 +123.246394 12.508631 +123.258128 12.562608 +# -b +124.318897 12.520365 +124.372874 12.532100 +124.593477 12.508631 +125.001826 12.586077 +125.323343 12.337312 +125.487621 12.022836 +125.553333 11.415006 +125.731692 11.055940 +125.255284 11.109918 +124.947849 11.447862 +124.957236 11.729482 +124.548887 12.065079 +124.318897 12.478122 +124.318897 12.520365 +# -b +121.932166 11.870292 +122.143381 11.849171 +122.417961 11.576938 +122.826310 11.544082 +123.091503 11.511226 +122.894368 11.001963 +122.518875 10.664019 +122.009612 10.391786 +122.009612 11.067674 +122.033080 11.675505 +121.932166 11.870292 +# -b +122.650298 10.664019 +122.683153 10.490353 +122.551730 10.556064 +122.650298 10.664019 +# -b +122.960080 10.828297 +123.213538 10.924518 +123.511586 10.717996 +123.368429 10.215773 +123.368429 10.215773 +# -b +122.563465 9.964662 +122.826310 10.499740 +122.960080 10.828297 +122.960080 10.828297 +# -b +124.405730 11.654383 +124.527766 11.654383 +124.516031 11.490105 +124.405730 11.654383 +124.405730 11.654383 +# -b +124.318897 11.490105 +124.429199 11.337561 +124.748368 11.349295 +125.001826 10.957373 +125.177839 10.337809 +125.013560 10.227507 +124.769490 10.260363 +124.670923 10.924518 +124.417464 11.077062 +124.318897 11.480717 +124.318897 11.490105 +# -b +125.553333 10.161796 +125.621391 10.466885 +125.687102 10.161796 +# -b +125.654246 9.943540 +125.586188 10.042108 +125.553333 10.161796 +# -b +123.997381 11.217872 +124.030237 11.055940 +124.020849 10.391786 +123.699333 10.020986 +123.699333 10.020986 +# -b +123.368429 9.856708 +123.589032 10.337809 +123.833102 10.858806 +123.997381 11.217872 +123.997381 11.217872 +# -b +123.985647 9.955275 +124.307163 10.119553 +124.572355 10.020986 +124.572355 10.020986 +# -b +110.883266 20.034931 +110.782352 19.523321 +110.496038 18.915491 +110.141666 18.537651 +110.064221 18.455511 +# -b +119.449214 11.337561 +119.526660 11.217872 +119.514926 10.947986 +119.604106 10.544330 +119.282589 10.152409 +119.130045 10.009252 +# -b +118.510480 9.844973 +118.874240 10.260363 +119.216878 10.532596 +119.273202 10.849419 +119.360035 10.882274 +119.383503 11.142773 +119.449214 11.337561 +# -b +119.878685 11.924269 +119.890419 11.924269 +119.946743 11.891414 +# -b +120.000721 11.696626 +119.878685 11.882026 +119.878685 11.924269 +# -b +119.913888 12.292722 +119.890419 12.283335 +119.967865 12.227011 +# -b +120.012455 12.086201 +119.946743 12.250479 +119.913888 12.292722 +# -b +120.057045 15.306059 +119.857564 15.892767 +119.967865 16.211937 +119.967865 16.211937 +# -b +102.988513 11.642649 +102.690465 12.065079 +102.469862 12.151912 +102.082634 12.466388 +101.531128 12.649441 +101.000743 12.670563 +100.923298 12.748008 +100.967888 13.384001 +100.526683 13.557667 +100.008032 13.449712 +100.029154 12.769130 +100.029154 12.769130 +# -b +104.490487 10.466885 +104.237029 10.598307 +103.784090 10.556064 +103.694910 10.882274 +103.462573 11.077062 +103.131670 11.109918 +103.122282 11.337561 +102.955657 11.609793 +102.988513 11.642649 +102.988513 11.642649 +# -b +107.050884 17.030983 +107.426378 16.681304 +107.912173 16.308157 +108.123388 16.148573 +108.243077 16.073474 +108.254811 16.085208 +108.564593 15.573598 +108.872028 15.092497 +109.104365 14.407221 +109.202932 13.836940 +109.238135 13.534198 +109.247522 13.179826 +109.336702 12.834841 +109.348436 12.703419 +109.214666 12.499244 +109.127833 12.412411 +109.202932 11.914882 +109.181811 11.795193 +109.059775 11.598059 +108.827439 11.316439 +108.275932 11.001963 +107.891051 10.717996 +107.438112 10.478619 +107.050884 10.466885 +106.741102 10.281485 +106.630801 10.086697 +106.630801 10.086697 +# -b +106.609679 9.988130 +106.499378 10.009252 +# -b +104.997404 9.868442 +104.809657 10.194652 +104.490487 10.466885 +# -b +106.168474 20.053706 +105.760125 19.417714 +105.626355 18.800496 +106.091029 18.234909 +106.433667 17.634119 +106.961705 17.167099 +107.050884 17.030983 +# -b +110.064221 18.455511 +109.712195 18.192666 +109.369558 18.317048 +108.684282 18.676114 +108.651426 19.302719 +109.170077 19.741577 +109.536183 19.980954 +109.932798 19.992688 +# -b +104.004692 10.445763 +104.082138 10.107819 +103.927247 10.391786 +104.004692 10.445763 +# -b +98.571769 10.173530 +98.628093 10.783707 +98.848696 11.576938 +98.672683 11.837436 +98.717273 12.032224 +98.682070 12.694031 +98.428612 13.416856 +98.229131 13.611644 +97.942817 14.587927 +97.733949 15.754304 +97.710481 16.413765 +97.710481 16.509985 +97.182443 16.796299 +96.828071 17.242198 +96.652058 16.702426 +95.922192 16.254180 +95.358952 15.766038 +95.060904 15.925623 +94.575109 15.904502 +94.377975 16.010109 +94.267673 16.031231 +94.387362 16.606205 +94.553987 17.537899 +94.387362 18.202053 +94.145638 18.727744 +93.880446 18.906104 +93.615253 19.387205 +93.648109 19.492813 +93.472096 19.804942 +93.472096 19.804942 +# -b +98.639827 9.964662 +98.571769 10.173530 +# -b +100.029154 12.769130 +99.808551 11.914882 +99.522237 11.175629 +99.346225 10.717996 +99.191334 10.260363 +99.191334 10.009252 +# -b +98.527179 11.804581 +98.339432 11.588672 +98.595237 11.717748 +98.527179 11.804581 +# -b +98.339432 11.762338 +98.273721 11.490105 +98.339432 11.762338 +98.339432 11.762338 +# -b +98.374635 12.670563 +98.384022 12.358434 +98.374635 12.670563 +# -b +92.929977 13.524811 +92.843145 13.287780 +92.699988 12.487510 +92.667132 12.097935 +92.566218 11.708360 +92.753965 11.567550 +92.777433 12.076814 +92.897122 12.541487 +92.897122 13.027282 +93.007423 13.362879 +92.929977 13.524811 +# -b +86.572401 20.199210 +85.732234 19.762699 +84.939004 19.283944 +84.298318 18.528263 +84.021391 18.286539 +83.326728 17.727993 +82.322283 17.009861 +82.101680 16.500598 +81.428138 16.308157 +81.073766 16.010109 +80.620827 15.817669 +80.125645 15.465643 +80.125645 15.465643 +# -b +79.980141 14.888322 +80.069321 14.587927 +80.092789 14.374365 +80.069321 14.019993 +80.167888 13.621031 +80.113911 13.578788 +80.268802 13.233803 +80.224212 12.963917 +80.003610 12.271601 +80.003610 12.271601 +# -b +73.577975 15.754304 +73.411350 16.031231 +73.247071 16.362135 +73.169626 16.880785 +73.103914 17.314950 +72.916167 17.824213 +72.859843 18.033081 +72.826988 18.286539 +72.794132 18.748866 +72.859843 18.969468 +72.749542 19.105585 +72.695565 19.199458 +72.627507 19.513934 +72.585264 19.887081 +72.594651 19.950445 +# -b +73.610831 15.744917 +73.709398 15.486765 +73.899491 15.498499 +73.819699 15.317793 +73.920613 15.005664 +73.941734 14.954033 +# -b +80.125645 15.465643 +79.980141 14.888322 +79.980141 14.888322 +# -b +80.003610 12.271601 +79.750151 11.630915 +79.750151 10.957373 +79.783007 10.466885 +79.783007 10.272097 +79.529549 10.337809 +79.186911 10.096085 +79.186911 10.096085 +# -b +76.337853 9.746406 +75.819203 11.142773 +75.377998 11.882026 +75.035360 12.292722 +74.814757 13.050750 +74.594155 13.846327 +74.317228 14.470585 +73.941734 14.954033 +73.941734 14.954033 +# -b +49.905449 11.497145 +50.480424 11.931310 +50.665824 11.964165 +50.975606 11.877333 +51.053051 11.530001 +51.085907 11.018391 +51.064786 10.485659 +51.118763 10.387092 +50.832449 10.159449 +# -b +54.404332 12.569649 +54.359742 12.374862 +53.819970 12.288029 +53.479679 12.656482 +53.730790 12.569649 +54.040573 12.635360 +54.404332 12.569649 +# -b +57.689901 20.070134 +57.668780 19.736883 +57.678167 19.518628 +57.788468 19.140787 +57.448177 18.995284 +57.051562 18.901410 +56.619744 18.532957 +56.389754 17.995532 +55.882838 17.901658 +55.451020 17.744420 +55.242152 17.448719 +54.976960 17.002821 +54.646056 16.993433 +54.096897 17.002821 +53.489066 16.770484 +52.806137 16.526413 +52.308608 16.165000 +52.254631 15.770732 +52.034028 15.590026 +51.649148 15.460950 +51.020196 15.172289 +50.391244 14.958727 +50.048606 14.820264 +# -b +39.994764 15.301365 +40.379645 15.000970 +40.701162 14.766287 +41.262055 14.552725 +41.592959 14.090398 +42.067020 13.691436 +42.386189 13.325330 +42.740561 12.980345 +43.059731 12.797292 +43.334311 12.386596 +43.181766 11.898454 +42.740561 11.605100 +42.782804 11.485411 +43.224009 11.452555 +43.390635 11.356335 +43.831840 10.769626 +44.690781 10.333115 +45.462890 10.671059 +46.014396 10.779014 +46.941396 10.877581 +47.722892 11.149814 +48.208687 10.779014 +49.001917 11.248381 +49.708315 11.464290 +49.905449 11.497145 +# -b +42.684237 16.409071 +42.639647 16.622633 +42.541080 16.854970 +42.419045 17.066185 +42.275888 17.216383 +42.233645 17.385355 +42.034164 17.669322 +41.625815 17.995532 +41.428681 18.270111 +41.229200 18.659686 +41.118898 18.762947 +41.064921 18.962428 +40.919417 19.413020 +40.743405 19.612501 +40.546271 19.882387 +40.457091 19.997382 +# -b +43.468080 12.698725 +43.411756 12.905246 +43.346045 13.001467 +43.214622 13.283087 +43.214622 13.649193 +43.038609 14.036421 +42.961164 14.444770 +42.937696 14.658332 +42.827394 14.883628 +42.782804 15.097190 +42.618526 15.289631 +42.707706 15.385851 +42.639647 15.716755 +42.773417 15.888074 +42.717093 16.366828 +42.684237 16.409071 +# -b +50.048606 14.820264 +49.598014 14.754552 +49.067629 14.498747 +48.760193 14.090398 +48.220421 13.961322 +47.668915 13.832246 +47.457700 13.628072 +46.896806 13.433284 +46.422746 13.412163 +45.981541 13.391041 +45.484012 13.046056 +44.890262 12.743315 +44.183865 12.656482 +43.730926 12.710459 +43.468080 12.698725 +# -b +37.183256 20.152273 +37.227846 19.455263 +37.448448 18.784068 +37.821595 18.605709 +38.131377 18.302967 +38.307390 18.248990 +38.450547 18.091752 +38.715739 17.765542 +39.013787 16.981699 +39.234390 16.122757 +39.487848 15.536049 +39.807017 15.226266 +39.994764 15.301365 +39.994764 15.301365 +# -b +13.611644 14.411915 +13.886223 14.123254 +14.062236 13.595216 +14.592621 13.574094 +14.977502 13.520117 +15.066682 13.175132 +14.580887 12.818413 +14.580887 12.818413 +# -b +13.611644 14.411915 +13.215029 14.327428 +13.015548 14.024687 +13.236150 13.649193 +13.632765 13.207988 +13.874489 12.668216 +14.139682 12.536793 +14.449464 12.806679 +14.569152 12.806679 +# -b +-10.039761 29.387069 +-9.894257 29.638181 +-9.729978 29.849396 +# -b +-16.179081 28.553943 +-16.599165 28.368543 +-16.599165 28.009477 +-16.169694 28.417827 +-16.179081 28.553943 +-16.179081 28.553943 +# -b +-15.606454 28.145594 +-15.737876 27.852239 +-15.496152 27.725510 +-15.320140 27.892136 +-15.517274 28.124472 +-15.606454 28.145594 +# -b +-13.808778 28.690059 +-13.996525 28.572718 +-14.196006 28.241814 +-14.196006 28.115085 +-13.808778 28.436601 +-13.808778 28.690059 +# -b +-13.379307 29.185242 +-13.578788 29.086675 +-13.775922 28.863725 +-13.501342 28.962292 +-13.379307 29.185242 +# -b +-16.202550 19.934018 +-16.146226 20.236759 +-16.322238 20.588785 +-16.500598 20.579397 +-16.709466 21.004174 +-16.775178 21.116822 +-16.930069 21.198962 +-16.840889 21.827914 +-16.423152 22.372379 +-16.047659 23.045921 +-15.737876 23.677220 +-15.618188 23.979961 +-15.209838 24.435247 +-14.724044 25.068893 +-14.404874 26.106194 +-13.754801 26.601376 +-13.203294 27.380525 +-12.905246 27.821730 +-12.452307 27.969581 +-11.560510 28.232427 +-10.898702 28.758118 +-10.314340 29.135958 +-10.039761 29.387069 +-10.039761 29.387069 +# -b +-78.076858 26.819632 +-78.053390 26.779736 +-78.011147 26.650660 +-78.473473 26.631885 +-79.001511 26.699943 +-78.506329 26.800857 +-78.076858 26.819632 +-78.076858 26.819632 +# -b +-77.128737 26.345571 +-77.095881 26.404242 +-77.248425 25.916100 +-77.304749 26.195374 +-77.239038 26.561480 +-77.128737 26.345571 +-77.128737 26.345571 +# -b +-77.382195 25.038384 +-77.403316 25.108789 +-77.382195 25.038384 +-77.382195 25.038384 +# -b +-78.109714 25.078280 +-77.943088 24.857678 +-77.844521 24.505652 +-78.086245 24.362495 +-78.374906 24.594832 +-78.318582 24.967979 +-78.229402 25.197969 +-78.109714 25.078280 +# -b +-77.790544 24.313212 +-77.921967 24.151280 +-77.701364 24.282703 +-77.790544 24.313212 +# -b +-77.832787 24.010470 +-77.612185 23.869660 +-77.832787 24.010470 +-77.832787 24.010470 +# -b +-76.246327 25.197969 +-76.201737 25.127564 +-76.213471 24.806047 +-76.368362 24.906961 +-76.246327 25.197969 +-76.246327 25.197969 +# -b +-75.441362 24.343721 +-75.342795 24.172402 +-75.485952 24.313212 +-75.748797 24.686359 +-75.638496 24.665237 +-75.441362 24.343721 +-75.441362 24.343721 +# -b +-74.526096 24.163014 +-74.481506 24.010470 +-74.514362 24.163014 +# -b +-75.298205 23.595080 +-75.176170 23.289992 +-74.922711 22.994291 +-75.131580 23.116326 +-75.220760 23.463658 +-75.298205 23.595080 +# -b +-74.096626 22.658693 +-74.096626 22.729098 +-74.174071 22.729098 +-74.404061 22.790116 +-74.272638 22.832359 +-73.953469 22.689202 +-74.260904 22.229222 +-74.063770 22.576554 +-74.096626 22.658693 +# -b +-72.773011 22.341870 +-73.148504 22.372379 +-72.773011 22.341870 +-72.773011 22.341870 +# -b +-72.221504 21.971070 +-71.890601 21.910053 +-71.583165 21.724653 +-72.057226 21.931174 +-72.331806 21.888931 +-72.221504 21.971070 +# -b +-73.047590 21.396096 +-73.103914 21.086314 +-73.655421 20.961931 +-73.291661 21.198962 +-73.047590 21.396096 +# -b +-80.071668 22.933273 +-79.663318 22.637572 +-79.200992 22.402888 +-78.780908 22.341870 +-78.771521 22.360645 +-78.374906 22.186979 +-78.011147 21.879544 +-77.656774 21.827914 +-77.403316 21.755162 +-77.084147 21.539253 +-76.764977 21.332731 +-76.598352 21.271714 +-76.091435 21.126210 +-75.706554 21.055805 +-75.748797 20.764797 +-75.319327 20.755410 +-74.791289 20.567663 +-74.371205 20.349407 +-74.228048 20.152273 +-74.955567 20.006769 +-74.955567 20.006769 +# -b +-77.656774 19.840144 +-77.149858 20.494911 +-77.778810 20.703780 +-78.450005 20.961931 +-78.715197 21.569762 +-79.475572 21.612005 +-79.928511 21.694144 +# -b +-78.053390 22.290240 +-78.285726 22.391154 +-77.975944 22.043822 +-77.689630 21.919440 +-77.921967 22.217488 +-78.053390 22.290240 +# -b +-81.449260 30.107548 +-81.273247 29.579510 +-81.019789 29.077287 +-80.700620 28.563330 +-80.644296 27.969581 +-80.381450 27.439196 +-80.181969 26.850141 +-80.170235 26.195374 +-80.346247 25.587543 +-80.390837 25.418571 +-80.864898 25.179194 +-81.252126 25.308270 +-81.416404 25.808146 +-81.693331 25.927835 +-82.000766 26.462913 +-81.979645 26.690556 +-82.143923 26.958095 +-82.319936 26.927586 +-82.573394 27.244409 +-82.662574 27.734898 +-82.740019 28.018865 +-82.883176 28.096310 +-82.784609 28.748730 +-83.026333 29.213404 +-83.446417 29.579510 +-83.479272 29.722667 +-83.742118 29.964391 +# -b +-84.415660 30.079386 +-84.624528 29.955004 +-84.955432 29.809500 +-85.342659 29.743788 +-85.495204 29.964391 +# -b +-89.862664 30.001940 +-89.752363 29.992553 +# -b +-89.388603 30.020715 +-89.585737 29.790725 +-89.609206 29.464515 +-89.212591 29.222791 +-89.421459 29.049125 +-89.818074 29.387069 +-89.961231 29.483290 +# -b +-82.310548 23.177344 +-81.935055 23.177344 +-81.472728 23.128060 +-81.052645 23.076430 +-80.578584 22.994291 +-80.071668 22.933273 +-80.071668 22.933273 +# -b +-79.928511 21.694144 +-80.489404 22.053210 +-80.810921 22.074331 +-81.219270 22.208101 +-81.615885 22.186979 +-82.167392 22.320749 +-81.726187 22.515536 +-82.319936 22.668081 +-82.993477 22.607063 +-83.488660 22.229222 +-84.040166 22.053210 +-84.448515 21.818526 +-84.579938 21.806792 +-85.000022 21.867810 +-84.460249 22.013314 +-84.272503 22.607063 +-83.643551 22.881643 +-83.047455 23.015412 +-82.474827 23.198465 +-82.310548 23.177344 +# -b +-83.014599 21.900665 +-82.683695 21.539253 +-83.148369 21.581496 +-83.014599 21.900665 +-83.014599 21.900665 +# -b +-86.797697 20.609906 +-87.051155 20.328286 +-86.797697 20.609906 +# -b +-90.017555 21.302222 +-89.355748 21.417217 +-88.715062 21.560374 +-88.121312 21.684757 +-87.569806 21.600271 +-86.896264 21.396096 +-86.929120 20.858671 +-87.304614 20.516033 +-87.492360 20.018504 +-87.492360 20.018504 +# -b +-94.999886 29.241566 +-95.077332 29.037391 +-95.121921 28.920049 +-95.387114 28.736996 +-95.628838 28.579758 +-95.849440 28.492925 +-96.114633 28.424867 +-96.060655 28.492925 +-95.739139 28.629042 +-95.706283 28.687713 +-95.917499 28.629042 +-96.037187 28.579758 +-96.081777 28.736996 +-96.126367 28.697100 +-96.170957 28.638429 +-96.224934 28.697100 +-96.325848 28.610267 +-96.445536 28.687713 +-96.501860 28.542209 +-96.400947 28.424867 +-96.579306 28.375584 +-96.701341 28.260589 +-96.811643 28.152634 +-96.975921 28.122125 +-97.065101 28.025905 +-96.954800 28.035292 +-97.032245 27.819384 +-97.241114 27.800609 +-97.273969 27.760713 +-97.196524 27.554191 +-97.229379 27.288999 +-97.351415 27.251450 +-97.494572 27.279612 +-97.449982 27.190432 +-97.339681 27.063703 +-97.363149 26.915852 +-97.407739 26.756267 +-97.351415 26.500462 +-97.339681 26.439445 +-97.285703 26.282207 +-97.163668 25.974771 +-97.086222 25.913753 +-97.086222 25.883245 +-97.184790 25.664989 +-97.142546 25.585197 +-97.032245 25.735394 +-97.086222 25.474895 +-97.262235 25.324698 +-97.494572 25.373981 +-97.550896 25.174500 +-97.628341 24.944511 +-97.748030 24.763804 +-97.792620 24.601873 +-97.748030 24.289744 +-97.738643 23.944759 +-97.661197 23.773440 +-97.604873 23.245402 +-97.595486 22.776035 +-97.694053 22.285546 +-97.637729 22.081372 +-97.482838 21.813833 +-97.273969 21.597924 +-97.175402 21.339772 +-97.285703 21.154372 +-97.196524 20.947850 +-97.130812 20.832855 +-96.877354 20.438587 +-96.546450 20.138192 +-96.457271 20.002076 +# -b +-97.318559 25.275414 +-97.262235 25.183888 +-97.330293 25.033690 +-97.407739 25.143992 +-97.318559 25.275414 +-97.318559 25.275414 +# -b +-96.865620 27.936725 +-96.811643 28.014171 +-96.666139 28.131513 +-96.490126 28.239467 +-96.412681 28.180796 +-96.666139 27.955500 +-96.931331 27.683267 +-96.964187 27.760713 +-96.865620 27.899176 +-96.865620 27.936725 +# -b +-89.961231 29.483290 +-90.137244 29.290849 +-90.501003 29.232178 +-90.822519 29.194629 +-91.219135 29.272075 +-91.582894 29.570123 +-91.956041 29.818887 +-92.200112 29.675730 +-92.364390 29.598285 +-92.927631 29.703892 +-93.544848 29.809500 +-94.293489 29.675730 +-94.692451 29.520839 +-94.701838 29.551348 +-94.812139 29.809500 +-94.988152 29.598285 +-94.999886 29.396457 +-94.999886 29.396457 +# -b +-90.634773 19.891775 +-90.491616 20.652149 +-90.271013 21.210696 +-90.017555 21.302222 +# -b +-110.113504 24.238113 +-109.716889 23.944759 +-109.561998 23.693647 +-109.341395 23.367437 +-109.540876 23.010718 +-109.892902 22.848787 +-109.991469 22.970822 +# -b +-110.036059 27.054315 +-109.827190 26.875956 +-109.672299 26.678822 +-109.461084 26.638926 +-109.219360 26.439445 +-109.064469 26.261085 +-109.231094 26.063951 +-109.296806 25.744781 +-109.043347 25.545300 +-108.843866 25.625093 +-108.811011 25.514792 +-108.688975 25.303576 +-108.268892 25.143992 +-108.038902 25.054812 +-107.818299 24.773192 +-107.783097 24.522080 +-107.409950 24.228726 +-107.076700 23.965880 +-106.867831 23.834458 +-106.769264 23.742931 +-106.680084 23.510594 +-106.447748 23.346316 +-106.349181 23.144488 +-106.062867 22.898070 +-105.708495 22.571860 +-105.565338 22.367686 +-105.443302 21.947602 +-105.311880 21.701184 +-105.112399 21.360893 +-105.112399 20.966625 +-105.300145 20.760104 +-105.145254 20.595825 +-105.398712 20.429200 +-105.455037 20.253187 +-105.356469 20.044319 +# -b +-114.375357 30.027755 +-114.208732 29.710933 +-114.011597 29.663996 +-113.779261 29.443394 +-113.514068 29.192282 +-113.436623 28.997495 +-113.260610 28.873113 +-113.072863 28.793320 +-112.896851 28.424867 +-112.763081 28.384971 +-112.685636 28.220692 +-112.598803 27.859280 +-112.354732 27.594087 +-112.089539 27.141148 +-112.012094 27.082477 +-111.880671 26.944014 +-111.737514 26.608417 +-111.681190 26.568520 +-111.681190 26.777389 +-111.448853 26.629538 +-111.317431 26.371386 +-111.228251 26.113234 +-111.150805 25.735394 +-111.007648 25.545300 +-110.852757 25.315311 +-110.831636 25.153379 +-110.622767 24.822475 +-110.611033 24.451675 +-110.378697 24.158321 +-110.113504 24.238113 +-110.113504 24.238113 +# -b +-109.991469 22.970822 +-110.280130 23.519982 +-110.599299 23.742931 +-110.974793 24.066794 +-111.329165 24.249847 +-111.516912 24.461063 +-111.615479 24.491571 +-111.758636 24.672278 +-111.979238 24.702787 +-112.113008 24.693399 +-112.002707 25.064199 +-111.979238 25.404490 +-112.113008 25.883245 +-112.366466 26.162518 +-112.709104 26.340877 +-112.929706 26.608417 +-112.983684 26.826672 +-113.150309 26.768001 +-113.448357 26.737493 +-113.657225 26.904118 +-113.877828 26.993298 +-114.053840 27.141148 +-114.297911 27.190432 +-114.396478 27.446237 +-114.617081 27.535417 +-114.771972 27.673880 +-114.872886 27.770100 +-114.286177 27.779487 +-114.032719 27.819384 +-114.011597 27.976622 +-113.910683 28.143247 +-113.934152 28.307525 +-114.110164 28.600880 +-114.330767 28.833216 +-114.518514 28.997495 +-114.717995 29.180548 +-114.861152 29.375335 +-115.093488 29.480943 +-115.346947 29.626447 +-115.612139 29.797766 +-115.656729 29.971431 +# -b +-112.685636 30.152138 +-112.554213 29.788378 +-112.420443 29.645221 +-112.321876 29.335439 +-112.101274 29.142999 +-111.934648 28.861378 +-111.779757 28.619654 +-111.526299 28.406092 +-111.415998 28.366196 +-111.174274 28.063454 +-110.897347 27.917951 +-110.566443 27.859280 +-110.500732 27.683267 +-110.533588 27.516642 +-110.456142 27.328895 +-110.324719 27.190432 +-110.036059 27.054315 +-110.036059 27.054315 +# -b +-118.228860 28.959945 +-118.238247 29.006882 +-118.172536 29.093715 +-118.139680 28.901275 +-118.160802 28.823829 +-118.228860 28.959945 +-118.228860 28.959945 +# -b +-115.081754 27.976622 +-115.159200 28.014171 +-115.159200 28.131513 +-115.060633 28.307525 +-115.048899 28.103351 +-115.048899 27.995396 +-115.081754 27.976622 +# -b +-112.983684 28.969333 +-113.105719 28.997495 +-113.269997 29.201670 +-113.424889 29.412885 +-113.382646 29.452781 +-113.183165 29.220444 +-113.040008 29.037391 +-112.983684 28.969333 +-112.983684 28.969333 +# -b +-112.366466 28.978720 +-112.342998 29.142999 +-112.188106 29.065553 +-112.145863 28.861378 +-112.188106 28.736996 +-112.375853 28.774546 +-112.411056 28.901275 +-112.366466 28.978720 +# -b +-159.617644 22.090759 +-159.528465 22.081372 +-159.352452 22.100146 +-159.373574 21.802098 +-159.617644 21.802098 +-159.695090 21.978111 +-159.617644 22.090759 +# -b +-158.115670 21.379668 +-157.906802 21.421911 +-157.728442 21.206002 +-158.059346 21.236511 +-158.115670 21.379668 +-158.115670 21.379668 +# -b +-157.242647 21.081620 +-157.155814 21.051111 +-156.747465 21.060498 +-156.846032 20.914995 +-157.165202 20.936116 +-157.242647 21.081620 +-157.242647 21.081620 +# -b +-156.404827 20.790612 +-156.315647 20.823468 +-156.005865 20.626334 +-156.238202 20.417466 +-156.482273 20.687352 +-156.646551 20.823468 +-156.458804 20.823468 +-156.404827 20.790612 +# -b +-155.874442 20.044319 +-155.829853 20.053706 +-155.752407 20.044319 +# -b +-155.829853 19.919937 +-155.874442 20.044319 +-155.874442 20.044319 +# -b +-156.977455 20.750716 +-156.968068 20.781225 +-156.801442 20.677964 +-156.935212 20.647455 +-156.935212 20.647455 +-156.977455 20.750716 +# -b +-177.434817 28.162022 +-177.434817 28.162022 +# -b +153.950038 24.350761 +153.881979 24.329640 +153.872592 24.339027 +153.938303 24.390657 +153.938303 24.390657 +# -b +145.316031 20.002076 +145.360621 20.013810 +# -b +145.292563 19.992688 +145.304297 20.002076 +145.316031 20.002076 +# -b +119.913888 26.519237 +120.078166 26.857181 +120.355093 27.082477 +120.542840 27.387566 +120.662528 27.711429 +120.951189 28.035292 +121.270358 28.171409 +121.469839 28.366196 +121.535551 28.715875 +121.556672 28.997495 +121.490961 29.152386 +121.833599 29.201670 +121.854720 29.431659 +121.756153 29.549001 +121.657586 29.549001 +122.021346 29.856437 +121.666974 29.931535 +121.568407 29.980819 +# -b +121.446371 25.275414 +121.657586 25.143992 +121.854720 25.043078 +121.779622 24.742683 +121.657586 24.259235 +121.547285 23.834458 +121.458105 23.376825 +121.326682 23.071736 +121.016900 22.623491 +120.850275 22.069638 +120.674262 22.233916 +120.188467 22.806544 +120.078166 23.449577 +120.254179 24.017511 +120.685997 24.611260 +121.127202 25.104095 +121.404128 25.263680 +121.404128 25.263680 +# -b +123.732188 24.421166 +123.865958 24.310865 +123.711067 24.339027 +123.732188 24.421166 +# -b +124.107682 24.400045 +124.185128 24.470450 +124.217983 24.369536 +124.107682 24.400045 +# -b +127.794560 26.519237 +127.883740 26.706984 +128.193522 26.866569 +128.005775 26.528624 +127.862618 26.350265 +127.740583 26.141397 +127.717115 26.430057 +127.794560 26.519237 +127.794560 26.519237 +# -b +128.932775 27.791222 +128.953897 27.720817 +128.867064 27.840505 +128.899919 27.878054 +128.921041 27.800609 +128.932775 27.791222 +# -b +129.395102 28.415480 +129.618051 28.483538 +129.463160 28.279363 +129.320003 28.190184 +129.296535 28.366196 +129.395102 28.415480 +# -b +125.311609 24.822475 +125.278753 24.834209 +125.433644 24.723908 +125.311609 24.822475 +125.311609 24.822475 +# -b +109.911676 20.386957 +110.397471 20.595825 +110.284823 21.142638 +110.826942 21.400790 +111.202436 21.515784 +111.831388 21.762202 +112.075458 21.752815 +112.361772 21.813833 +112.671555 21.874850 +112.969603 21.978111 +112.957868 22.337177 +113.112760 22.520230 +113.399073 22.255038 +113.530496 22.327789 +113.509375 22.632878 +113.542230 22.818278 +113.873134 22.592982 +113.962314 22.428703 +114.204038 22.377073 +114.227506 22.470946 +114.204038 22.541351 +114.281483 22.553086 +114.525554 22.553086 +114.570144 22.623491 +114.734423 22.776035 +114.912782 22.614103 +115.321131 22.797156 +115.551121 22.705630 +115.738868 22.806544 +116.104974 22.879296 +116.313843 22.949701 +116.567301 23.083470 +116.787903 23.397946 +117.053096 23.611508 +117.306554 23.712422 +117.449711 23.703035 +117.604602 23.752318 +117.747759 23.956493 +118.069275 24.329640 +118.024685 24.491571 +118.423647 24.561976 +118.599660 24.601873 +118.709961 24.763804 +118.853118 24.932776 +119.061987 25.205009 +119.205144 25.254293 +119.350647 25.453774 +119.437480 25.594584 +119.547781 25.763556 +119.625227 25.993546 +119.615840 26.052217 +119.726141 26.310369 +119.615840 26.540358 +119.702673 26.756267 +119.878685 26.549746 +119.913888 26.519237 +# -b +110.496038 20.065440 +110.683785 20.065440 +110.883266 20.034931 +# -b +109.932798 19.992688 +110.329413 20.074828 +110.496038 20.065440 +# -b +113.950580 22.264425 +113.863747 22.233916 +113.950580 22.264425 +# -b +107.945029 21.473541 +108.254811 21.421911 +108.496535 21.710572 +109.059775 21.576802 +109.357823 21.421911 +109.733317 21.452420 +109.590160 21.029990 +109.911676 20.386957 +109.911676 20.386957 +# -b +107.945029 21.473541 +107.724426 21.433645 +107.348932 21.102741 +106.830282 20.832855 +106.553355 20.377569 +106.168474 20.053706 +# -b +92.268170 20.884486 +92.026446 21.391402 +91.871555 22.233916 +91.439737 22.776035 +90.867109 22.766648 +90.623039 22.724405 +90.545593 22.276159 +90.280401 21.917093 +90.116122 21.844341 +# -b +93.472096 19.804942 +92.786820 20.271962 +92.521628 20.471443 +92.268170 20.884486 +92.268170 20.884486 +# -b +90.613651 22.684508 +90.623039 22.327789 +90.855375 22.541351 +90.613651 22.684508 +90.613651 22.684508 +# -b +88.891074 21.628433 +88.691593 21.649554 +88.581292 21.607311 +88.262122 21.534559 +88.095497 21.680063 +88.083763 21.865463 +88.116619 22.081372 +88.116619 22.121268 +87.928872 21.917093 +87.543991 21.628433 +86.846981 21.091007 +86.771882 20.490218 +86.572401 20.199210 +# -b +90.116122 21.844341 +89.818074 21.853729 +89.585737 21.844341 +89.287689 21.783324 +89.144532 21.719959 +88.891074 21.628433 +88.891074 21.628433 +# -b +72.594651 19.950445 +72.728421 20.356448 +72.627507 20.914995 +72.585264 21.029990 +72.496084 21.154372 +72.496084 21.400790 +72.484350 21.680063 +72.463228 21.895972 +72.430373 21.987498 +72.573530 22.163511 +72.794132 22.264425 +72.507818 22.306668 +72.186302 22.337177 +72.132325 22.306668 +72.054879 21.935868 +72.031411 21.482929 +71.679385 21.072233 +71.357869 20.936116 +71.226446 20.853977 +70.686674 20.802347 +70.344036 20.823468 +70.132821 20.987747 +70.132821 20.987747 +# -b +69.825386 22.428703 +70.266591 22.879296 +70.200879 23.113979 +70.013132 22.940313 +# -b +68.025363 23.773440 +67.858738 23.803949 +67.551302 23.843845 +67.340087 24.127812 +67.140606 24.611260 +66.866026 24.773192 +66.678280 25.125217 +66.478799 25.355207 +65.993004 25.404490 +65.429763 25.373981 +65.000293 25.315311 +65.000293 25.315311 +# -b +70.132821 20.987747 +69.262145 21.813833 +68.919507 22.346564 +69.151844 22.316055 +69.503869 22.388807 +69.825386 22.428703 +# -b +70.013132 22.940313 +69.679882 22.848787 +69.128376 22.827665 +68.565135 23.123367 +68.234231 23.571612 +68.102809 23.580999 +68.025363 23.773440 +68.025363 23.773440 +# -b +61.616156 25.158073 +61.174951 25.136951 +60.501410 25.409184 +60.015615 25.338779 +# -b +65.000293 25.315311 +64.591943 25.148685 +64.117883 25.366941 +63.479543 25.237865 +62.716822 25.268374 +62.242761 25.136951 +61.825025 25.087668 +61.616156 25.158073 +61.616156 25.158073 +# -b +49.938305 26.810245 +50.006363 26.533318 +50.158907 26.176599 +50.083808 25.848042 +50.480424 25.418571 +50.743269 25.467855 +50.975606 25.995893 +51.273654 26.075685 +51.470788 25.667336 +51.527112 25.298883 +51.416811 24.726255 +51.405077 24.524427 +51.482522 24.334333 +51.703125 24.132506 +51.968317 24.031592 +52.463499 24.132506 +53.047861 24.202911 +53.467945 24.090263 +54.073428 24.212298 +54.261175 24.282703 +54.514633 24.735642 +55.209296 25.308270 +55.749068 25.737741 +56.145684 26.254045 +56.378020 26.275166 +56.300575 26.085072 +56.246598 25.737741 +56.267719 25.418571 +56.366286 24.695746 +56.819225 24.221685 +57.161863 24.040979 +57.060949 24.080875 +57.502154 23.888435 +57.889382 23.787521 +58.307119 23.656098 +58.659144 23.543450 +58.914949 23.259483 +59.144939 22.994291 +59.365541 22.677468 +59.619000 22.597675 +59.719914 22.330136 +59.487577 21.797405 +59.079228 21.313957 +58.715468 20.837549 +58.417420 20.422159 +58.187430 20.619293 +57.767347 20.152273 +57.689901 20.070134 +# -b +50.555522 26.235270 +50.424100 26.106194 +50.555522 26.235270 +50.555522 26.235270 +# -b +60.015615 25.338779 +59.210650 25.477242 +58.870359 25.507751 +57.931625 25.627440 +57.260430 25.927835 +57.028094 26.641272 +56.896671 26.908812 +56.300575 27.134108 +55.727947 26.948708 +55.307863 26.699943 +54.624934 26.493422 +53.963127 26.699943 +53.411621 26.838407 +53.334175 26.958095 +52.597269 27.331242 +52.165451 27.685614 +51.461401 27.852239 +51.261920 28.096310 +50.942750 28.884847 +50.501545 29.387069 +50.170641 29.753176 +50.048606 29.983166 +# -b +56.169152 26.927586 +55.760803 26.918199 +55.253886 26.582602 +55.760803 26.631885 +56.169152 26.927586 +# -b +40.457091 19.997382 +40.182511 20.203904 +40.083944 20.267268 +# -b +48.495001 28.300485 +48.584181 28.086923 +48.879882 27.821730 +49.234254 27.500214 +49.255376 27.342976 +49.443122 27.145842 +49.806882 26.927586 +49.938305 26.810245 +# -b +48.262664 28.807401 +48.318988 28.572718 +48.495001 28.300485 +48.495001 28.300485 +# -b +48.372966 29.955004 +48.372966 29.924495 +# -b +48.065530 30.079386 +48.208687 29.809500 +47.910639 29.551348 +47.767482 29.337786 +48.098386 29.117183 +48.220421 28.816789 +# -b +48.551325 30.098161 +48.473880 29.973778 +# -b +49.663725 30.069999 +49.532302 29.945616 +49.487712 29.992553 +# -b +32.365203 30.163872 +32.353469 29.722667 +32.529482 29.173507 +32.794674 28.631389 +33.292203 28.056414 +33.477603 27.880401 +33.522193 27.518989 +33.853097 26.997991 +34.085433 26.324450 +34.493783 25.667336 +34.812952 25.017262 +35.120388 24.484531 +35.561593 24.080875 +35.728218 23.909556 +35.662507 23.909556 +35.474760 23.726503 +35.552205 23.189078 +35.552205 23.189078 +# -b +36.831231 22.001579 +36.896942 21.518131 +37.204377 21.107435 +37.183256 20.422159 +37.183256 20.152273 +# -b +35.552205 23.189078 +35.793929 22.790116 +36.467471 22.360645 +36.831231 22.001579 +# -b +34.890398 29.492677 +34.801218 29.368295 +34.735507 29.232178 +34.592350 28.826176 +34.392869 28.309872 +34.360013 27.929685 +33.942276 27.842852 +33.477603 28.330994 +33.191289 28.875459 +32.827530 29.377682 +32.663251 29.753176 +32.574072 29.915107 +32.552950 29.992553 +# -b +37.910775 24.172402 +37.821595 24.221685 +37.657316 24.343721 +37.403858 24.353108 +37.159787 24.735642 +37.126932 25.078280 +36.906329 25.547647 +36.577772 25.887938 +36.333701 26.244657 +36.059122 26.770348 +35.695362 27.134108 +35.540471 27.371138 +35.409048 27.636330 +35.197833 27.969581 +34.899785 28.124472 +34.625205 28.145594 +34.702651 28.321606 +34.801218 28.884847 +34.911519 29.185242 +34.890398 29.492677 +# -b +40.083944 20.267268 +39.938440 20.328286 +39.684982 20.422159 +39.321223 20.703780 +39.145210 21.107435 +39.091233 21.447726 +39.058377 21.621392 +38.990319 21.849035 +38.990319 22.053210 +39.058377 22.402888 +38.924607 22.759607 +38.748595 23.097551 +38.593704 23.442536 +38.220557 23.928331 +37.910775 24.172402 +37.910775 24.172402 +# -b +0.072752 39.816405 +-0.215909 39.389281 +-0.159585 39.253164 +-0.082139 39.013787 +# -b +0.225296 38.652375 +-0.302742 38.314430 +-0.523344 37.938937 +-0.621911 37.617420 +-1.196886 37.547015 +-1.626357 37.150400 +-1.868081 36.798375 +-2.508767 36.725623 +-3.323119 36.753785 +-4.052984 36.725623 +-4.658468 36.514408 +-5.076204 36.221053 +-5.242830 36.113099 +-5.618323 36.129527 +-6.036060 36.505020 +-6.202685 36.868780 +-6.575832 37.159787 +-6.984181 37.239580 +-7.237640 37.220805 +# -b +-8.725533 40.086291 +-8.880424 39.687329 +-9.211328 39.269592 +-9.255918 38.901139 +-9.124495 38.685230 +-8.814713 38.504524 +-8.561255 38.478709 +-8.605844 38.192395 +-8.626966 37.800473 +-8.615232 37.598646 +-8.760736 37.124585 +-8.286675 37.115198 +-7.690579 37.063567 +-7.270495 37.204377 +-7.237640 37.220805 +# -b +-1.945526 35.096919 +-1.283719 35.312828 +-0.755681 35.772808 +-0.347332 35.845560 +-0.061018 35.845560 +# -b +-9.729978 29.849396 +-9.607943 30.231930 +-9.807424 30.670788 +-9.751100 31.266884 +-9.509376 31.691662 +-9.166738 32.027259 +-9.190206 32.046034 +-9.068171 32.534175 +-8.495543 33.146699 +-7.735169 33.498725 +-7.007650 33.810854 +-6.477265 34.378788 +-6.080650 35.096919 +-5.782602 35.754033 +-5.296807 35.915965 +-5.010493 35.538124 +-4.634999 35.305788 +-4.074106 35.223648 +-3.567189 35.268238 +-3.081395 35.277626 +-2.663658 35.169671 +-1.945526 35.096919 +-1.945526 35.096919 +# -b +-16.775178 32.804061 +-17.007514 32.813449 +-16.754056 32.606927 +-16.775178 32.804061 +-16.775178 32.804061 +# -b +-16.190816 33.118537 +-16.301117 32.989461 +-16.223671 33.109150 +# -b +-28.572718 38.617172 +-28.560984 38.539726 +-28.572718 38.617172 +# -b +-28.042333 38.401263 +-28.208958 38.520952 +-28.396705 38.452894 +-28.042333 38.401263 +-28.042333 38.401263 +# -b +-27.723163 38.572582 +-27.734898 38.626559 +-28.065801 38.720433 +-27.899176 38.581970 +-27.723163 38.572582 +# -b +-27.051969 38.772063 +-27.260837 38.704005 +-26.983910 38.685230 +-27.051969 38.772063 +# -b +-25.054812 37.835676 +-25.573462 37.842716 +-25.528873 37.739456 +-25.054812 37.835676 +-25.054812 37.835676 +# -b +-24.932776 36.974387 +-25.033690 36.974387 +-24.932776 36.974387 +# -b +-31.053322 39.440911 +-31.163624 39.415096 +-31.053322 39.440911 +# -b +-64.613065 32.365203 +-64.624799 32.374591 +-64.735100 32.271330 +-64.648267 32.271330 +-64.613065 32.365203 +# -b +-74.019180 40.001805 +-74.040301 39.985377 +# -b +-74.073157 40.001805 +-74.174071 39.799977 +-74.206927 39.680288 +-74.338350 39.518357 +-74.460385 39.389281 +-74.690375 39.166331 +-74.878122 39.013787 +-74.910977 39.243777 +-75.143314 39.321223 +-75.417894 39.457339 +-75.495339 39.569987 +-75.518808 39.466726 +-75.363916 39.098273 +-75.122192 38.788491 +-75.054134 38.495137 +-75.110458 38.356673 +-75.286471 38.166580 +-75.352182 38.028116 +-75.518808 37.755884 +-75.638496 37.502425 +-75.739410 37.239580 +-75.927157 37.204377 +-75.992868 37.415592 +-75.891954 37.659663 +-75.760532 37.877919 +-75.683086 37.906081 +-75.805121 38.035157 +-75.837977 38.192395 +-76.002256 38.305043 +-76.213471 38.401263 +-76.258061 38.520952 +-76.112557 38.668802 +-76.124291 38.875324 +-76.201737 38.917567 +-76.213471 39.013787 +-76.136025 39.140516 +-76.168881 39.262552 +-75.981134 39.415096 +-75.992868 39.586415 +-76.112557 39.440911 +-76.300304 39.356425 +-76.443461 39.262552 +-76.455195 39.149904 +-76.499785 38.943382 +-76.511519 38.626559 +-76.443461 38.443506 +-76.499785 38.417691 +-76.368362 38.166580 +-76.389483 38.166580 +-76.544375 38.279228 +-76.696919 38.288615 +-76.818954 38.349633 +-76.863544 38.201782 +-76.553762 38.114949 +-76.368362 37.992914 +-76.312038 37.748843 +-76.410605 37.624461 +-76.312038 37.502425 +-76.290916 37.371003 +-76.377749 37.274782 +-76.234592 37.124585 +-76.389483 37.063567 +-76.466929 36.965000 +-76.300304 36.920410 +-76.180615 36.957960 +-75.992868 36.885208 +-75.915423 36.620015 +-75.936544 36.486246 +-75.927157 36.441656 +-75.915423 36.352476 +-75.793387 36.129527 +-75.849711 36.202279 +-76.070314 36.167076 +-76.290916 36.113099 +-76.553762 36.068509 +-76.654676 36.272684 +-76.499785 35.915965 +-76.070314 35.969942 +-75.903689 35.880762 +-75.715942 35.718831 +-75.936544 35.474760 +-76.290916 35.350378 +-76.422339 35.493534 +-76.577230 35.439557 +-76.520906 35.350378 +-76.532640 35.186099 +-76.642942 35.078145 +-76.642942 34.998352 +-76.401218 34.815299 +-76.840076 34.669795 +-77.424438 34.505517 +-77.602797 34.350626 +-77.832787 34.085433 +-78.306848 33.930542 +-78.804377 33.747489 +-79.057835 33.508112 +-79.222113 33.350874 +-79.332415 33.099763 +-79.543630 32.951912 +-79.675053 32.895588 +-80.050546 32.625702 +-80.313392 32.571725 +-80.599706 32.597540 +-80.745209 32.559991 +-80.623174 32.299492 +-80.810921 32.215006 +-80.897754 32.046034 +-81.019789 32.022565 +-81.186414 31.778494 +-81.395283 31.344330 +-81.460994 31.126074 +-81.604151 30.764662 +-81.550174 30.403249 +-81.449260 30.107548 +# -b +-83.742118 29.964391 +-84.251381 30.135710 +-84.415660 30.079386 +# -b +-85.495204 29.964391 +-85.804986 30.163872 +-86.356492 30.384474 +-86.323637 30.518244 +-86.961976 30.471307 +-87.072277 30.593343 +-87.281145 30.537019 +-87.799796 30.297642 +-87.966421 30.480695 +-88.064988 30.945368 +-88.219879 30.422024 +-88.649350 30.403249 +-89.266568 30.337538 +-89.585737 30.278867 +-89.862664 30.297642 +-89.862664 30.297642 +# -b +-90.137244 30.107548 +-89.883785 30.088773 +-89.862664 30.001940 +# -b +-89.752363 29.992553 +-89.365135 30.116935 +-89.388603 30.020715 +# -b +-89.862664 30.297642 +-90.402436 30.375087 +-90.137244 30.107548 +-90.137244 30.107548 +# -b +-117.057789 32.449689 +-117.135235 32.700801 +-117.224415 33.083335 +-117.487260 33.341487 +-117.862754 33.609026 +-118.205392 33.728714 +-118.360283 33.930542 +-118.670065 34.059618 +-118.780366 34.040844 +-119.078414 34.141757 +-119.277895 34.298995 +-119.585331 34.416337 +-119.895113 34.435112 +-119.895113 34.435112 +# -b +-114.861152 31.963894 +-114.717995 31.663500 +-114.750850 31.407695 +-114.661671 30.992305 +-114.530248 30.581609 +-114.452802 30.105201 +-114.375357 30.027755 +# -b +-115.656729 29.971431 +-115.755296 30.372740 +-115.898453 30.382128 +-116.020488 30.802211 +-116.163645 30.943021 +-116.262212 31.219948 +-116.518017 31.529730 +-116.539139 31.785535 +-116.682296 31.935732 +-116.816065 32.104705 +-116.926367 32.320613 +-117.057789 32.449689 +# -b +-114.861152 31.963894 +-114.872886 31.945120 +-114.673405 31.794922 +-114.462190 31.672887 +-114.319033 31.625950 +-114.121899 31.473406 +-113.823851 31.473406 +-113.591514 31.398307 +-113.370911 31.248110 +-113.072863 31.123727 +-113.007152 30.849148 +-112.896851 30.544059 +-112.751347 30.257745 +-112.685636 30.152138 +# -b +-120.071126 33.996254 +-119.916235 33.958704 +-119.927969 33.895340 +# -b +-119.784812 34.069006 +-119.740222 34.040844 +-119.531354 34.005641 +-119.519619 33.968092 +-119.740222 33.958704 +-119.784812 34.069006 +# -b +-118.393139 33.425973 +-118.393139 33.416585 +-118.271103 33.360261 +-118.306306 33.278122 +-118.372017 33.379036 +-118.393139 33.425973 +# -b +-118.503440 33.017623 +-118.437728 32.951912 +-118.271103 32.813449 +-118.339161 32.766512 +-118.482318 32.951912 +-118.503440 33.017623 +# -b +-119.895113 34.435112 +-120.193161 34.507864 +-120.491209 34.590003 +-120.535799 34.817646 +-120.547533 34.944375 +-120.512331 35.000699 +-120.524065 35.017127 +-120.535799 35.118041 +-120.690690 35.244770 +-120.777523 35.289360 +-120.866703 35.460679 +-121.087305 35.631998 +-121.418209 36.000451 +-121.826558 36.392372 +-121.727991 36.650524 +-121.993184 36.995509 +-122.279498 37.232539 +-122.422654 37.603339 +-122.312353 37.777005 +-122.014305 37.504772 +-122.267763 37.943630 +-121.904004 38.091481 +-122.345209 38.178314 +-122.434389 37.934243 +-122.610401 37.953018 +-122.798148 38.011689 +-122.887328 38.152499 +-122.941305 38.335552 +-123.251087 38.593704 +-123.537401 38.861243 +-123.647702 39.239083 +-123.682905 39.513663 +-123.758004 39.792936 +-123.912895 39.980683 +# -b +-120.115716 33.968092 +-120.071126 33.996254 +-120.071126 33.996254 +# -b +-119.927969 33.895340 +-120.115716 33.968092 +-120.115716 33.968092 +-120.115716 33.968092 +# -b +141.960057 40.022926 +142.157191 39.469073 +142.046890 39.074805 +141.727720 38.765023 +141.629153 38.316777 +141.054179 37.934243 +141.143358 37.143360 +140.854698 36.603588 +140.744396 35.944127 +140.767865 35.603836 +140.237480 35.007740 +140.237480 35.007740 +# -b +139.984022 35.233036 +140.192890 35.622610 +140.192890 35.622610 +# -b +139.972288 39.161638 +140.148300 39.750693 +140.016877 39.844567 +# -b +140.237480 35.007740 +139.984022 35.233036 +139.984022 35.233036 +# -b +140.192890 35.622610 +139.805662 35.305788 +139.409047 35.261198 +139.209566 34.726119 +138.911518 34.871623 +138.625204 34.925600 +138.315422 34.554800 +137.731060 34.618165 +137.212409 34.554800 +137.266387 34.726119 +137.057518 34.709692 +136.836916 34.981924 +136.771204 34.536026 +136.836916 34.270833 +136.449688 34.134717 +136.229086 33.813201 +135.701048 33.498725 +135.290352 33.803813 +135.248108 34.261446 +135.522688 34.636940 +135.147195 34.608778 +134.464266 34.716732 +133.978471 34.435112 +133.835314 34.489089 +133.403496 34.371747 +133.016268 34.280221 +132.530473 34.298995 +132.244160 33.885952 +131.758365 34.005641 +131.338281 33.914114 +130.974522 34.207469 +131.460317 34.416337 +132.122124 34.827033 +132.718220 35.387927 +133.304929 35.521697 +134.077038 35.495881 +134.795169 35.631998 +135.325554 35.702403 +135.733903 35.477107 +136.031951 35.631998 +136.151640 36.176464 +136.836916 36.932144 +137.233531 37.469570 +137.212409 37.248967 +137.113842 36.915717 +137.433012 36.756132 +138.151144 37.091729 +138.836419 37.654970 +139.244769 37.969446 +139.507614 38.152499 +139.695361 38.628906 +139.972288 39.161638 +139.972288 39.161638 +# -b +140.016877 39.844567 +139.805662 39.912625 +139.906576 39.980683 +# -b +138.604083 38.272187 +138.514903 37.812208 +138.449192 38.204129 +138.604083 38.272187 +# -b +134.276519 33.268735 +133.570121 33.397811 +133.105448 32.879160 +132.751076 32.804061 +132.575063 33.167821 +132.223038 33.360261 +132.896580 33.977479 +133.436352 33.932889 +133.823580 34.226244 +134.264785 34.289608 +134.661400 33.996254 +134.771701 33.794426 +134.551098 33.618413 +134.276519 33.268735 +134.276519 33.268735 +# -b +135.060362 34.571228 +134.762314 34.207469 +135.004038 34.390522 +135.060362 34.571228 +# -b +130.864220 33.876565 +130.676474 33.848403 +130.279859 33.564436 +130.035788 33.416585 +# -b +129.916099 32.656211 +130.411281 32.759472 +130.235269 33.083335 +130.577907 32.766512 +130.631884 32.581112 +130.401894 32.095317 +130.345570 31.464019 +130.655352 31.123727 +130.688208 31.663500 +130.753919 31.445244 +130.941666 31.048629 +131.251448 31.435857 +131.549496 31.879408 +131.835810 32.552950 +132.035291 32.841611 +131.924990 33.174861 +131.746630 33.517499 +131.239714 33.573823 +130.962788 33.857790 +130.864220 33.876565 +# -b +130.146089 32.477851 +130.113233 32.142254 +130.146089 32.477851 +# -b +131.117679 30.630892 +130.962788 30.410290 +131.117679 30.630892 +# -b +130.545051 30.353966 +130.512195 30.210809 +130.545051 30.353966 +130.545051 30.353966 +# -b +130.897076 37.539975 +130.885342 37.453142 +130.897076 37.539975 +# -b +130.035788 33.416585 +129.770595 33.306284 +129.838654 33.055173 +129.958342 32.813449 +129.782329 32.766512 +129.916099 32.656211 +# -b +128.855330 32.721922 +128.867064 32.581112 +128.855330 32.721922 +# -b +129.219089 32.954259 +129.054811 32.888547 +129.219089 32.954259 +129.219089 32.954259 +# -b +129.749474 33.839016 +129.815185 33.756876 +129.749474 33.839016 +# -b +129.284800 34.289608 +129.320003 34.134717 +129.284800 34.289608 +# -b +129.406836 34.636940 +129.484281 34.425725 +129.385714 34.390522 +129.406836 34.636940 +# -b +128.435246 38.506871 +128.810740 37.995261 +129.308269 37.460182 +129.484281 36.612975 +129.618051 36.026266 +129.329390 35.352724 +128.756763 35.108654 +128.536160 35.071104 +128.479836 34.953762 +128.280355 34.918560 +127.994041 34.998352 +127.674872 34.899785 +127.606813 34.653368 +127.451922 34.726119 +127.254788 34.498476 +127.341621 34.735507 +126.989596 34.526638 +126.900416 34.453887 +126.724403 34.479702 +126.360644 34.435112 +126.316054 34.489089 +126.536656 34.590003 +126.492067 34.852848 +126.393500 35.007740 +126.524922 35.413742 +126.736137 35.702403 +126.712669 35.988717 +126.515535 36.436962 +126.426355 36.497980 +126.140041 36.596547 +126.447477 36.861739 +126.855826 36.826537 +126.834705 37.072955 +126.834705 37.267742 +126.602368 37.417939 +126.614102 37.530587 +126.503801 37.751190 +126.503801 37.767618 +# -b +126.327788 33.360261 +126.426355 33.149046 +126.900416 33.463522 +126.327788 33.360261 +# -b +128.005775 40.022926 +127.552836 39.776509 +127.564570 39.417443 +127.451922 39.264899 +127.928330 38.922261 +128.435246 38.506871 +128.435246 38.506871 +# -b +126.569512 37.723028 +126.161163 37.723028 +125.785669 37.960058 +125.654246 37.777005 +125.332730 37.662010 +125.112128 37.812208 +125.255284 37.985873 +124.870404 38.021076 +125.034682 38.445853 +125.344464 38.610132 +125.267019 38.765023 +125.511090 39.504276 +125.135596 39.579374 +124.670923 39.546519 +124.361140 39.835179 +124.393996 39.903238 +# -b +121.568407 29.980819 +121.347804 30.201421 +120.817419 30.095814 +120.211936 30.123976 +120.850275 30.335191 +121.148323 30.544059 +121.657586 30.830373 +121.800743 31.123727 +121.204647 31.597788 +120.718852 31.870021 +120.155612 31.841859 +120.641407 32.020218 +121.314948 31.813697 +121.911044 31.616563 +121.711563 31.945120 +121.392394 32.198578 +120.960576 32.656211 +120.707118 33.325059 +120.465394 33.885952 +120.078166 34.362360 +120.078166 34.362360 +# -b +119.845830 35.578021 +120.254179 35.927699 +120.420804 36.185851 +120.796298 36.293805 +120.906599 36.516755 +121.326682 36.657565 +121.845333 36.835924 +122.197358 36.950919 +122.340515 36.756132 +122.605708 37.126932 +122.584586 37.347534 +122.119913 37.460182 +121.591875 37.373349 +121.106080 37.591605 +120.772829 37.741803 +120.233057 37.434367 +120.024189 37.312332 +# -b +119.803586 39.870382 +120.012455 39.980683 +# -b +121.955634 40.046395 +121.523817 39.553559 +121.624731 39.358772 +121.624731 38.997359 +121.303214 38.696964 +121.922779 38.922261 +122.241948 39.213268 +123.046913 39.546519 +123.511586 39.666207 +124.107682 39.767121 +124.393996 39.903238 +124.393996 39.903238 +# -b +120.078166 34.362360 +119.482070 34.643980 +119.392890 35.052329 +119.726141 35.514656 +119.845830 35.578021 +# -b +120.024189 37.312332 +119.559516 37.047139 +118.918830 37.363962 +118.796794 37.767618 +118.355589 38.002301 +117.991830 38.185354 +117.726637 38.706352 +118.233554 39.110007 +118.763939 39.110007 +119.350647 39.358772 +119.681551 39.792936 +119.803586 39.870382 +# -b +49.973507 37.464876 +50.435834 37.148053 +51.372221 36.723276 +52.045763 36.678686 +52.674714 36.819496 +53.489066 36.979081 +53.334175 36.899289 +53.885681 36.908676 +53.951393 37.436714 +53.885681 37.823942 +53.876294 38.854202 +53.655692 39.241430 +53.378765 39.454992 +53.876294 39.649780 +53.390499 39.853954 +53.885681 39.863341 +53.885681 39.863341 +# -b +53.092451 40.083944 +52.961028 39.957215 +52.850727 39.957215 +# -b +48.879882 38.570235 +49.001917 37.866185 +49.520568 37.507119 +49.973507 37.464876 +# -b +49.508834 40.067516 +49.332821 39.471420 +49.112219 39.215615 +48.891616 39.225002 +48.858761 38.673496 +48.879882 38.570235 +# -b +48.372966 29.924495 +48.253277 30.001940 +48.065530 30.079386 +# -b +48.560712 30.116935 +48.551325 30.098161 +# -b +50.048606 29.983166 +49.663725 30.069999 +49.663725 30.069999 +# -b +49.487712 29.992553 +49.201398 30.175606 +49.001917 30.537019 +48.804783 30.412636 +48.626424 30.213155 +48.593568 30.079386 +# -b +29.861130 31.257497 +30.457226 31.466365 +30.468960 31.410041 +30.612117 31.353717 +30.987611 31.503915 +31.548505 31.485140 +32.100011 31.288006 +32.111745 31.288006 +# -b +31.724517 31.541464 +31.715130 31.372492 +31.682274 31.182398 +31.780841 31.032201 +32.088277 30.860882 +32.198578 30.452533 +32.198578 30.328150 +32.365203 30.163872 +# -b +35.937086 35.815051 +35.915965 36.296152 +36.246869 36.758479 +35.761074 36.777253 +35.340990 36.608281 +34.801218 36.819496 +34.756628 36.828884 +34.216856 36.500327 +33.808507 36.242175 +33.423626 36.197585 +32.904975 36.063815 +32.386325 36.305539 +32.022565 36.589506 +31.560239 36.767866 +31.173011 36.899289 +30.698950 36.892248 +30.579262 36.519101 +30.192034 36.279724 +30.192034 36.279724 +# -b +34.040844 35.472413 +34.404603 35.634345 +34.604084 35.589755 +34.216856 35.282319 +34.040844 34.949069 +33.325059 34.702651 +32.815796 34.620512 +32.353469 35.028861 +32.750084 35.164978 +33.059866 35.336297 +33.235879 35.326909 +33.688818 35.390274 +34.040844 35.472413 +# -b +35.991064 34.740200 +35.991064 35.364459 +35.883109 35.669547 +35.937086 35.815051 +# -b +35.474760 33.970438 +35.474760 33.923502 +35.385580 33.850750 +35.287013 33.639535 +35.164978 33.454135 +35.087532 33.306284 +35.000699 33.186596 +35.474760 33.970438 +35.721177 34.374094 +35.991064 34.740200 +35.991064 34.740200 +# -b +32.144601 31.278619 +32.332348 31.201173 +32.496626 31.022814 +32.937831 31.088525 +33.104456 31.013426 +33.522193 31.060363 +34.029109 31.297393 +34.162879 31.391267 +34.437459 31.625950 +34.514904 31.750332 +34.604084 32.003791 +34.679183 32.245515 +34.747241 32.470811 +34.801218 32.665598 +34.934988 32.890894 +34.956109 33.066907 +34.956109 33.066907 +# -b +32.552950 29.992553 +32.463770 30.060611 +32.341735 30.260092 +32.198578 30.633239 +32.189191 31.004039 +32.165722 31.229335 +32.165722 31.229335 +# -b +25.364594 39.922012 +25.320004 39.983030 +25.021956 39.830486 +25.188581 39.837526 +25.364594 39.922012 +25.364594 39.922012 +# -b +26.533318 39.079499 +26.455872 39.361119 +26.080379 39.351731 +25.991199 39.147557 +26.157824 39.070111 +26.465260 39.128782 +26.533318 39.079499 +# -b +25.970078 38.241678 +26.124969 38.448200 +25.880898 38.638294 +25.904366 38.319124 +25.970078 38.241678 +# -b +28.098657 36.073203 +28.274670 36.286765 +28.054067 36.368904 +27.767753 36.101365 +28.098657 36.073203 +28.098657 36.073203 +# -b +25.066546 35.373846 +24.569017 35.373846 +24.151280 35.437210 +24.008123 35.517003 +23.698341 35.500575 +23.545797 35.193140 +23.975268 35.218955 +24.470450 35.155590 +24.813088 34.892745 +25.463161 34.956109 +25.970078 35.028861 +26.289247 35.256504 +25.937222 35.148550 +25.496017 35.291707 +25.066546 35.326909 +25.066546 35.373846 +# -b +24.944511 37.657316 +24.967979 37.875572 +24.702787 37.901387 +24.890533 37.666704 +24.944511 37.657316 +# -b +25.430305 36.918063 +25.585197 37.155094 +25.385716 37.058874 +25.430305 36.918063 +# -b +22.034435 38.309737 +21.527519 38.145458 +21.130904 37.788739 +21.658941 37.305291 +21.715265 36.784294 +22.022701 37.023671 +22.332483 36.580119 +22.475640 36.500327 +22.794810 36.617669 +23.069389 36.669299 +22.926232 37.199684 +22.815931 37.507119 +23.104592 37.279476 +23.468351 37.401511 +23.214893 37.622114 +23.092858 37.953018 +22.255038 38.197089 +22.034435 38.309737 +22.034435 38.309737 +# -b +20.731942 38.068013 +20.600519 38.405957 +20.358795 38.248719 +20.633374 38.110256 +20.731942 38.068013 +# -b +24.569017 38.075053 +24.416473 38.190048 +24.205258 38.553807 +23.644364 38.750942 +23.325194 39.025521 +22.961435 38.837775 +23.268870 38.750942 +23.566918 38.466975 +23.996389 38.335552 +24.238113 38.039851 +24.536161 37.945977 +24.569017 38.075053 +24.569017 38.075053 +# -b +20.049013 39.393974 +20.060747 39.454992 +# -b +19.938711 39.386934 +20.049013 39.393974 +# -b +23.942412 40.142615 +23.963534 39.964255 +# -b +23.501207 40.100372 +23.665485 39.999458 +23.566918 39.940787 +# -b +22.607063 40.152002 +22.839399 39.659167 +23.247749 39.274286 +23.125713 39.138169 +22.916845 39.335304 +22.970822 39.018481 +22.717364 38.966850 +22.827665 38.769716 +23.289992 38.664109 +23.632630 38.387182 +24.008123 38.222904 +24.017511 37.779352 +23.599774 37.988220 +22.926232 38.023423 +22.937967 38.206476 +22.574207 38.319124 +21.945255 38.380142 +21.306916 38.422385 +21.086314 38.441159 +20.755410 38.889405 +21.053458 39.018481 +20.645109 39.102967 +20.260228 39.539478 +20.159314 39.701410 +20.159314 39.701410 +# -b +20.081868 39.684982 +20.081868 39.684982 +# -b +19.938711 32.172763 +20.379916 32.527135 +21.152025 32.815796 +21.935868 32.900282 +22.595329 32.693760 +22.926232 32.452036 +22.893377 32.320613 +23.247749 32.189191 +23.864966 32.050727 +24.559630 31.956854 +25.000835 31.663500 +25.021956 31.672887 +# -b +25.066546 31.560239 +25.782331 31.607176 +26.488728 31.513302 +27.359404 31.238722 +27.932032 31.069750 +28.727609 30.935981 +29.487983 31.032201 +29.861130 31.257497 +# -b +30.192034 36.279724 +29.553695 36.235134 +29.178201 36.589506 +29.023310 36.777253 +28.924743 36.662258 +28.626695 36.857046 +28.307525 36.749091 +28.152634 36.758479 +27.678574 36.704501 +27.779487 36.864086 +28.176103 36.953266 +28.241814 37.103463 +27.669186 37.033058 +27.490827 37.173868 +27.481439 37.385084 +27.338282 37.551709 +27.347670 37.666704 +27.127067 37.727722 +27.195125 38.049238 +26.840753 38.154846 +26.542705 38.206476 +26.345571 38.380142 +26.465260 38.621866 +26.685862 38.457587 +27.117680 38.457587 +26.929933 38.560848 +27.016766 38.889405 +26.873609 39.147557 +26.951055 39.539478 +26.620151 39.548866 +26.178946 39.548866 +26.223536 39.905585 +26.223536 39.905585 +# -b +20.060747 39.454992 +19.786167 39.778855 +19.819023 39.487848 +19.938711 39.386934 +# -b +20.081868 39.684982 +19.995035 39.762428 +19.962180 39.914972 +# -b +15.331874 40.100372 +15.418707 39.999458 +# -b +15.683899 40.025273 +15.803588 39.684982 +16.035924 39.309488 +16.179081 38.931648 +15.827056 38.682883 +15.695633 38.232291 +15.770732 37.978833 +16.035924 37.953018 +16.179081 38.145458 +16.411418 38.380142 +16.587431 38.664109 +16.643755 38.880018 +17.061491 38.992666 +17.094347 39.250818 +17.061491 39.464380 +16.718853 39.701410 +16.533453 39.914972 +16.533453 39.914972 +# -b +17.997879 40.126187 +18.328782 39.879769 +18.328782 39.914972 +# -b +15.618188 38.319124 +15.540742 38.136071 +15.165249 37.596299 +15.165249 37.305291 +15.263816 37.058874 +15.132393 36.713889 +14.646598 36.758479 +14.041115 37.112851 +13.599910 37.288863 +12.949836 37.577524 +12.541487 37.734762 +12.553221 38.110256 +12.738621 38.171273 +13.081259 38.180661 +13.412163 38.171273 +13.698477 37.997608 +14.139682 38.058625 +14.393140 38.075053 +14.822611 38.190048 +15.263816 38.267494 +15.618188 38.319124 +15.618188 38.319124 +# -b +14.372018 35.948821 +14.491707 35.939433 +14.559765 35.815051 +14.372018 35.948821 +14.372018 35.948821 +# -b +9.873135 37.331106 +10.171183 37.209071 +10.281485 36.892248 +10.546677 36.838271 +10.886968 37.068261 +11.020738 36.749091 +10.546677 36.385332 +10.645244 35.850253 +11.030125 35.634345 +11.131039 35.265891 +10.854112 34.784790 +10.490353 34.503170 +10.126594 34.329504 +10.082004 34.092474 +10.082004 34.092474 +# -b +9.929459 33.794426 +10.236895 33.648922 +10.502087 33.583211 +10.832991 33.592598 +10.964414 33.261694 +11.217872 33.214758 +11.316439 33.158434 +# -b +10.776667 33.878912 +10.821257 33.794426 +10.612388 33.702899 +10.710956 33.904727 +10.776667 33.878912 +# -b +11.316439 33.158434 +12.046305 32.900282 +12.994426 32.890894 +13.721945 32.778246 +14.569152 32.461424 +15.153514 32.245515 +15.406973 31.616563 +16.333972 31.229335 +17.293828 31.050976 +17.800744 30.823333 +18.209094 30.623852 +18.638565 30.337538 +19.222927 30.346925 +19.750964 30.670788 +19.983301 31.126074 +19.774433 31.625950 +19.795554 32.003791 +19.938711 32.172763 +# -b +0.403656 40.180164 +0.258152 39.985377 +0.072752 39.816405 +# -b +-0.082139 39.013787 +0.248765 38.865937 +0.225296 38.652375 +# -b +1.593501 39.107661 +1.680334 39.004400 +1.361164 38.926954 +1.593501 39.107661 +# -b +3.290263 39.959562 +3.248020 39.832833 +3.501478 39.663861 +3.093129 39.356425 +2.717635 39.534785 +2.684779 39.755387 +3.280876 39.985377 +3.290263 39.959562 +# -b +4.327564 40.027620 +4.348685 39.858648 +4.085840 39.910278 +# -b +9.673654 40.142615 +9.664267 39.626311 +9.598556 39.309488 +9.377953 39.189800 +9.068171 39.018481 +8.770123 38.898792 +8.626966 39.034909 +8.450953 39.309488 +8.429832 39.616924 +8.462687 39.795283 +8.495543 39.973643 +8.495543 39.973643 +# -b +-0.061018 35.845560 +0.380187 36.174117 +0.776802 36.345436 +1.328309 36.530836 +2.243574 36.620015 +2.917116 36.718582 +3.290263 36.798375 +3.489744 36.798375 +3.865237 36.885208 +4.282974 36.920410 +4.703058 36.920410 +5.001106 36.899289 +5.165384 36.777253 +5.728625 36.838271 +6.378698 37.129279 +6.852759 36.988468 +7.326819 37.112851 +7.854857 36.899289 +8.340652 36.953266 +8.716146 36.979081 +9.002460 37.155094 +9.673654 37.340494 +9.873135 37.331106 +# -b +10.082004 34.092474 +9.861401 34.071352 +9.929459 33.794426 +9.929459 33.794426 +# -b +-5.508022 50.043912 +-5.508022 49.994629 +# -b +-5.099673 50.029831 +-5.043349 49.987588 +# -b +-8.638700 41.822949 +-8.483809 41.210425 +-8.549520 40.809116 +-8.704411 40.297506 +-8.725533 40.086291 +# -b +-1.692068 43.376554 +-2.452443 43.409409 +-3.346587 43.432878 +-4.151551 43.416450 +-5.076204 43.529098 +-5.848313 43.632359 +-6.787047 43.552566 +-7.601399 43.728579 +-8.141171 43.519711 +-8.615232 43.310842 +-9.124495 42.972898 +-8.859303 42.681890 +-8.770123 42.454247 +-8.507277 42.299356 +-8.683290 41.888660 +-8.638700 41.822949 +# -b +-1.703802 43.367166 +-1.250863 43.601850 +-1.053729 44.388040 +-1.009139 44.742412 +-0.943428 45.202391 +-0.722825 45.404219 +-0.612524 45.420647 +-1.009139 45.760938 +-0.985671 46.173981 +-1.030261 46.298363 +-1.647478 46.509579 +-1.912671 46.957824 +-1.757780 47.220670 +-2.121539 47.279341 +-2.309286 47.497596 +-2.607334 47.563308 +-3.060273 47.563308 +-3.280876 47.713505 +-3.841769 47.854315 +-4.306442 47.891864 +-4.414397 48.067877 +-4.437865 48.157057 +-4.294708 48.295520 +-4.634999 48.326029 +-4.360420 48.581834 +-3.865237 48.671014 +-3.445154 48.720297 +-3.248020 48.800090 +-2.816202 48.764887 +-2.299898 48.605302 +-1.990116 48.612343 +-1.638091 48.654586 +-1.283719 48.671014 +-1.459731 49.011305 +-1.680334 49.351596 +-1.769514 49.694234 +-1.206273 49.673112 +-1.164030 49.544036 +-0.842514 49.365677 +-0.105608 49.292925 +-0.105608 49.292925 +# -b +-60.071939 45.859505 +-59.773891 45.997969 +-59.839602 46.159900 +-59.949903 46.265508 +# -b +-56.288841 47.138530 +-56.300575 46.957824 +-56.213742 46.852217 +-56.288841 47.138530 +-56.288841 47.138530 +# -b +-57.635924 50.036872 +-57.844792 49.745864 +-57.823671 49.529955 +-58.196818 49.292925 +-58.020805 49.192011 +-58.086516 49.062935 +-58.450276 48.931512 +-58.814035 48.685095 +-59.123817 48.509082 +-58.518334 48.516123 +-58.980660 48.112467 +-59.222384 47.593816 +-58.274263 47.652487 +-57.657045 47.645447 +-57.016359 47.586776 +-56.324043 47.631366 +-55.882838 47.802685 +-55.781924 47.631366 +-55.892225 47.497596 +-55.662236 47.474128 +-55.275008 47.668915 +-54.779826 47.586776 +-55.331332 47.220670 +-55.826514 47.039963 +-55.408777 46.920275 +-55.045018 47.166692 +-54.613200 47.415457 +-54.437188 47.422497 +-54.183729 47.927067 +-53.930271 47.563308 +-54.085162 46.873338 +-53.587633 47.183120 +-53.554778 46.852217 +-53.280198 46.730181 +-52.827259 47.220670 +-52.794403 47.751054 +-53.125307 47.535146 +-52.961028 48.032675 +-53.047861 48.105426 +-53.500800 47.661875 +-53.765993 47.786257 +-53.688547 48.046756 +-53.709669 48.253277 +-53.181631 48.464492 +-53.280198 48.605302 +-53.688547 48.523163 +-53.885681 48.605302 +-53.942005 48.830599 +-53.489066 49.299966 +-53.423355 49.285885 +-54.294031 49.407920 +-54.812681 49.379758 +-55.155319 49.494753 +-55.364188 49.436082 +-55.859370 49.501793 +-56.035382 49.694234 +-55.629380 49.966467 +-56.079972 49.987588 +# -b +-56.169152 50.128398 +-56.720658 49.637910 +-56.720658 49.914836 +-56.720658 49.914836 +# -b +-66.732257 50.072074 +-67.117138 49.616788 +-67.314272 49.358636 +-68.008935 49.328128 +-68.241272 49.133340 +-68.670743 48.917431 +-69.046236 48.654586 +-69.564887 48.215728 +-69.740900 48.002166 +-69.895791 47.786257 +# -b +-70.116393 47.445966 +-69.630598 47.847275 +-69.135416 48.229809 +-68.771657 48.429290 +-68.339839 48.619383 +-67.722621 48.851720 +-67.072548 49.039467 +-66.312173 49.236601 +-65.551799 49.299966 +-64.833667 49.220173 +-64.207062 48.889269 +-64.305629 48.872842 +-64.228184 48.560712 +-64.878257 48.194606 +-65.793523 48.201647 +-66.455330 48.084305 +-65.981270 47.995125 +-65.596389 47.727586 +-64.988558 47.898905 +-64.746834 47.772176 +-64.922847 47.340358 +-65.220895 47.115062 +-64.800812 47.100981 +-64.800812 46.746609 +-64.570822 46.418052 +-64.371341 46.281936 +-63.775245 46.159900 +-63.885546 45.967460 +-63.235473 45.838384 +-62.728556 45.784407 +-62.531422 45.699920 +-61.902470 45.906442 +-61.735845 45.683493 +-61.252397 45.582579 +-61.294640 45.467584 +-61.031794 45.380751 +-61.240663 45.289224 +-61.670134 45.188310 +-62.155928 45.024032 +-62.453976 44.866794 +-62.806002 44.772921 +-63.038338 44.779961 +-63.214351 44.709556 +-63.533521 44.742412 +-63.500665 44.505381 +-63.852690 44.679047 +-64.063905 44.615683 +-64.183594 44.378652 +-64.392462 44.204986 +-64.681123 43.921019 +-64.988558 43.695723 +-65.232629 43.705111 +-65.364052 43.505630 +-65.716077 43.728579 +-66.058715 44.014893 +-65.924946 44.498341 +-66.103305 44.442017 +-65.650366 44.686088 +-65.298341 44.913731 +-64.636533 45.232900 +-64.272774 45.171883 +-63.930136 45.242288 +-63.324652 45.350242 +-63.843303 45.397179 +-64.537966 45.380751 +-64.526232 45.636556 +-64.448786 45.828996 +-64.669389 45.706961 +-64.889991 45.660024 +-65.462619 45.350242 +-65.960148 45.296265 +-66.401353 45.131986 +-66.741644 45.117905 +-67.027958 45.195351 +-67.027958 45.195351 +# -b +-63.974726 49.959426 +-63.533521 49.844431 +-62.761412 49.694234 +-62.233374 49.443122 +-61.979916 49.393839 +-61.803903 49.292925 +-61.836759 49.112219 +-62.531422 49.156809 +-63.169761 49.278844 +-63.610966 49.595667 +-64.063905 49.752905 +-64.415931 49.879634 +-63.974726 49.959426 +-63.974726 49.959426 +# -b +-63.953604 46.988333 +-63.941870 47.100981 +-63.995847 46.859257 +-63.885546 46.648042 +-63.610966 46.570596 +-63.092316 46.481417 +-62.597133 46.464989 +-62.022159 46.481417 +-62.266230 46.328872 +-62.421121 46.122351 +-62.597133 46.007356 +-62.883447 46.220918 +-63.092316 46.197450 +-63.655556 46.312444 +-63.918402 46.434480 +-64.162472 46.648042 +-64.106148 46.957824 +-63.953604 46.988333 +# -b +-60.545999 46.995373 +-60.778336 46.784158 +-61.074037 46.389890 +-61.327496 46.082455 +-61.318108 45.737470 +-60.987204 45.613088 +-60.599977 45.652984 +-60.247951 45.737470 +-60.071939 45.859505 +# -b +-59.949903 46.265508 +-60.137650 46.136432 +-60.313663 46.204490 +-60.599977 46.143472 +-60.435698 46.335913 +-60.325397 46.737222 +-60.346519 46.978946 +-60.545999 46.995373 +-60.545999 46.995373 +# -b +-67.027958 45.195351 +-67.027958 45.078009 +-67.072548 44.937199 +-67.051426 44.890262 +-66.962247 44.772921 +-67.215705 44.686088 +-67.480897 44.585174 +-67.713234 44.568746 +-67.922102 44.442017 +-68.065259 44.427936 +-68.220150 44.291819 +-68.384429 44.331716 +-68.637887 44.355184 +-68.715333 44.528850 +-68.935935 44.324675 +-69.057971 44.087645 +-69.177659 44.031321 +-69.409996 43.888164 +-69.564887 43.895204 +-69.651720 43.848268 +-69.752634 43.735619 +-69.839467 43.871736 +-69.907525 43.871736 +# -b +-70.027213 41.764278 +-69.982624 41.865192 +-69.982624 41.996615 +-69.872322 41.740810 +-69.982624 41.691526 +# -b +-69.895791 47.786257 +-70.402707 47.363827 +-70.954213 46.978946 +-70.865034 46.903847 +-70.656165 47.032923 +-70.292406 47.272300 +-70.116393 47.445966 +# -b +-69.907525 43.871736 +-70.203226 43.672255 +-70.268937 43.529098 +-70.325261 43.496242 +-70.489540 43.310842 +-70.611575 43.118402 +-70.766466 42.794539 +-70.778201 42.731174 +-70.710142 42.656075 +-70.799322 42.510572 +-70.942479 42.381496 +-70.778201 42.257113 +-70.689021 42.144465 +-70.611575 42.003655 +-70.524742 41.839377 +-70.226694 41.747850 +-70.027213 41.764278 +# -b +-69.982624 41.691526 +-70.226694 41.642243 +-70.557598 41.583572 +-70.599841 41.682139 +-70.843912 41.609387 +-71.019925 41.557756 +-71.141960 41.625815 +-71.273383 41.698567 +-71.383684 41.485005 +-71.726322 41.377050 +-71.846011 41.351235 +-72.540674 41.301951 +-73.014735 41.259708 +-73.324517 41.135326 +-73.622565 41.010944 +-73.810312 40.902989 +-73.897145 40.910030 +-74.084891 40.743405 +-74.216314 40.558005 +-74.063770 40.457091 +-73.986324 40.086291 +-74.019180 40.001805 +# -b +-74.040301 39.985377 +-74.073157 40.001805 +# -b +-75.694820 44.552318 +-75.781653 44.498341 +-76.443461 44.268351 +-76.908134 44.101726 +-76.985580 44.174478 +-77.248425 44.118154 +-77.039557 43.967956 +-77.260159 43.944488 +-77.722486 43.984384 +-78.130835 43.984384 +-78.804377 43.848268 +-79.278437 43.705111 +-79.543630 43.536138 +-79.752498 43.336657 +-79.663318 43.247478 +-79.233848 43.224009 +-78.694076 43.327270 +-78.109714 43.400022 +-77.755341 43.360126 +-77.569942 43.263906 +-77.370461 43.310842 +-76.940990 43.303802 +-76.478663 43.512670 +-76.168881 43.552566 +-76.201737 43.791944 +-76.246327 43.921019 +-76.103170 43.951528 +-76.201737 44.038361 +-76.246327 44.174478 +-75.870833 44.355184 +-75.694820 44.552318 +# -b +-78.881822 42.867290 +-79.078957 42.850863 +-79.707908 42.876678 +# -b +-80.160847 42.174974 +-79.686787 42.332212 +-79.233848 42.566896 +-79.102425 42.681890 +-78.924065 42.787498 +-78.881822 42.867290 +-78.881822 42.867290 +# -b +-80.038812 44.873834 +-79.785354 44.796389 +-79.761886 44.923118 +-79.928511 44.977095 +# -b +-72.200383 41.193997 +-72.573530 40.994516 +-73.059324 40.961660 +-73.378494 40.910030 +-73.599096 40.860746 +-73.753988 40.818503 +-73.831433 40.743405 +-73.930000 40.668306 +-73.920613 40.642491 +-73.753988 40.593207 +-73.467674 40.694121 +-73.225950 40.726977 +-72.883312 40.792688 +-72.573530 40.827891 +-72.385783 40.902989 +-72.045492 41.001557 +-71.979780 41.043800 +-72.233238 41.027372 +-72.507818 40.935845 +-72.331806 41.086043 +-72.200383 41.193997 +-72.200383 41.193997 +# -b +-82.132189 45.892361 +-82.519417 45.899401 +-82.960622 45.906442 +-83.136634 45.821956 +-82.662574 45.714001 +-82.242490 45.591966 +-81.824754 45.568498 +-81.702718 45.730429 +-81.759042 45.852465 +-81.845875 45.613088 +-81.869343 45.791447 +-82.045356 45.946338 +-82.132189 45.892361 +# -b +-79.707908 42.876678 +-80.381450 42.681890 +-81.130090 42.672503 +-81.648741 42.503531 +-81.845875 42.322825 +-82.352792 42.102222 +-82.552272 41.980187 +-83.103779 42.003655 +-83.378358 41.806521 +-83.059189 41.557756 +-82.793997 41.492045 +-82.265959 41.492045 +-81.813019 41.534288 +-81.338959 41.757237 +-80.820308 41.947331 +-80.313392 42.078754 +-80.160847 42.174974 +# -b +-82.573394 42.625566 +-82.904298 42.543427 +-82.904298 42.332212 +-82.718898 42.299356 +-82.486561 42.339253 +-82.463093 42.487103 +-82.573394 42.592711 +-82.573394 42.625566 +# -b +-82.463093 43.062078 +-82.397381 43.101974 +-82.132189 43.224009 +-81.747308 43.576035 +-81.791898 44.158050 +-81.472728 44.528850 +-81.395283 44.826898 +-81.505584 45.054541 +-81.625273 45.188310 +-81.538440 45.265756 +-81.338959 45.164842 +-81.219270 44.930159 +-81.151212 44.899650 +-81.031523 44.984136 +-81.064379 44.819857 +-80.986933 44.796389 +-80.930609 44.639151 +-80.766331 44.742412 +-80.578584 44.592214 +-80.092789 44.538237 +-80.038812 44.725984 +-80.038812 44.873834 +-80.038812 44.873834 +# -b +-79.928511 44.977095 +-80.017691 45.171883 +-80.170235 45.380751 +-80.557463 45.613088 +-80.710007 45.875933 +-81.186414 45.976847 +-81.583030 45.960419 +-81.660475 46.082455 +-82.099333 46.082455 +-82.519417 46.159900 +-82.793997 46.213877 +-83.059189 46.159900 +-83.378358 46.220918 +-83.798442 46.335913 +-84.105877 46.298363 +-84.195057 46.441520 +-84.251381 46.533047 +-84.371070 46.587024 +-84.382804 46.549475 +-84.338214 46.441520 +-84.284237 46.265508 +-84.227913 46.152860 +-84.096490 46.061333 +-83.995576 45.976847 +-84.162201 45.967460 +-84.448515 45.913482 +-84.657384 45.967460 +-84.901454 45.946338 +-85.143178 46.037865 +-85.706419 45.936951 +-86.356492 45.791447 +-86.663928 45.613088 +-86.785963 45.784407 +-87.170844 45.599007 +-87.590928 45.085050 +-87.865507 44.812817 +-87.999277 44.545278 +-87.579193 44.819857 +-87.391447 45.054541 +-87.095745 45.141374 +-87.316348 44.789348 +-87.546338 44.355184 +-87.656639 43.991424 +-87.799796 43.529098 +-87.910097 42.998713 +-87.832652 42.649035 +-87.844386 42.282929 +-87.623783 41.806521 +-87.358591 41.665711 +-86.851674 41.829989 +-86.675662 42.013042 +-86.368226 42.503531 +-86.279047 42.860250 +-86.433938 43.353085 +-86.565361 43.665214 +-86.422204 44.197946 +-86.323637 44.465485 +-86.290781 44.585174 +-86.189867 44.772921 +-85.915287 45.000564 +-85.682951 45.047500 +-85.638361 44.836285 +-85.452961 45.078009 +-85.274601 45.279837 +-85.089201 45.474624 +-85.044611 45.667065 +-84.800541 45.714001 +-84.558817 45.643596 +-84.239647 45.575538 +-83.908743 45.413607 +-83.786708 45.390138 +-83.434683 45.164842 +-83.479272 45.024032 +-83.368971 44.695475 +-83.378358 44.348143 +-83.676407 44.064176 +-83.953333 43.735619 +-83.676407 43.681642 +-83.422948 43.951528 +-83.092045 44.064176 +-82.718898 43.824799 +-82.608597 43.383594 +-82.463093 43.062078 +-82.463093 43.062078 +# -b +-84.525961 46.488457 +-84.537695 46.526006 +-84.547082 46.706713 +-84.460249 46.873338 +-84.680852 47.333318 +-84.978900 47.861356 +-85.176034 47.964616 +-85.748662 47.936454 +-86.234457 48.436330 +-86.466793 48.727338 +-86.818819 48.786009 +-87.447771 48.851720 +-88.175289 48.959674 +-88.175289 48.685095 +-88.363036 48.574793 +-88.560170 48.523163 +-88.440482 48.816518 +-88.703327 48.422249 +-88.902808 48.450411 +-89.144532 48.384700 +-89.365135 48.098386 +-89.609206 48.016247 +-89.752363 47.981044 +-89.928375 47.875437 +# -b +-90.071532 46.662123 +-89.365135 46.866298 +-88.747917 47.220670 +-88.064988 47.467087 +-87.823264 47.445966 +-88.130700 47.227710 +-88.506193 46.957824 +-88.374770 46.852217 +-87.999277 46.873338 +-87.668373 46.746609 +-87.349203 46.481417 +-86.851674 46.457948 +-86.642806 46.464989 +-86.180480 46.678551 +-85.617239 46.669163 +-85.131444 46.753649 +-84.967166 46.502538 +-84.680852 46.481417 +-84.525961 46.488457 +-84.525961 46.488457 +# -b +-89.928375 47.875437 +-90.843641 47.474128 +-91.472593 47.100981 +-92.110932 46.699672 +-91.648605 46.638655 +-91.097099 46.873338 +-90.855375 46.737222 +-90.810785 46.617533 +-90.214689 46.601105 +-90.071532 46.662123 +# -b +-113.082251 41.745503 +-112.971949 41.710301 +-112.840527 41.745503 +-112.641046 41.670405 +-112.697370 41.414600 +-112.387587 41.346541 +-112.342998 41.529594 +-112.178719 41.571837 +-112.012094 41.487351 +-112.077805 41.372356 +-112.077805 41.097777 +-111.913527 40.964007 +-112.012094 40.764526 +-112.289020 40.780954 +-112.387587 40.905336 +-112.631658 41.006250 +-112.784203 41.323073 +-112.995418 41.529594 +-113.082251 41.719688 +-113.082251 41.745503 +# -b +-125.304568 50.041565 +-124.907953 49.757598 +-124.875097 49.593320 +-124.586436 49.433735 +-124.166353 49.318740 +-123.858918 49.175583 +-123.725148 49.015999 +-123.581991 48.783662 +-123.450568 48.631118 +-123.316799 48.520816 +-123.516280 48.358885 +-123.847183 48.410515 +-124.255533 48.551325 +-124.377568 48.617037 +-124.753062 48.659280 +-124.654495 48.842333 +-124.863363 48.732031 +-125.072231 48.936206 +-124.973664 49.030080 +-125.316302 49.023039 +-125.647206 49.081710 +-125.626084 49.231907 +-125.924133 49.318740 +-126.222181 49.433735 +-126.508494 49.562811 +-126.198712 49.621482 +-126.341869 49.705968 +-126.529616 49.750558 +-126.783074 49.942998 +-127.027145 49.898409 +-127.158568 49.971160 +# -b +-122.786414 49.044161 +-122.908449 49.088750 +-122.997629 49.147421 +-122.687847 49.203745 +-122.654991 49.248335 +-122.765292 49.276497 +-123.042219 49.248335 +-123.161908 49.318740 +-123.206497 49.412614 +-123.152520 49.562811 +-123.251087 49.670766 +-123.459956 49.520568 +-123.659437 49.548730 +-123.605459 49.713009 +-123.736882 49.778720 +-123.826062 49.842084 +-123.903507 49.957079 +# -b +-123.980953 50.027484 +-124.023196 49.926571 +-124.079520 49.919530 +-124.279001 49.813922 +-124.487869 49.863206 +-124.654495 49.964120 +# -b +-123.912895 39.980683 +-124.091254 40.201286 +-124.267267 40.410154 +-124.091254 40.729324 +-124.056052 40.931151 +-124.013809 41.163488 +-124.046664 41.637549 +-124.189821 42.064673 +-124.321244 42.458941 +-124.398690 42.911880 +-124.210943 43.381247 +-124.166353 43.533792 +-124.056052 43.820106 +-124.013809 44.169784 +-123.990340 44.446711 +-123.990340 44.831591 +-123.903507 45.167189 +-123.835449 45.540336 +-123.826062 45.779713 +-123.891773 45.965113 +-123.793206 46.188062 +-123.340267 46.202143 +-123.206497 46.232652 +-123.450568 46.324179 +-123.802594 46.310098 +-123.990340 46.422746 +-123.924629 46.622227 +-123.858918 46.453255 +-123.826062 46.544781 +-123.835449 46.772424 +-124.013809 46.878032 +-123.990340 47.105675 +-124.124110 47.089247 +-124.210943 47.328624 +-124.300123 47.612591 +-124.544193 47.917680 +-124.663882 48.227462 +-124.544193 48.419902 +-124.222677 48.323682 +-123.903507 48.241543 +-123.516280 48.199300 +-123.206497 48.199300 +-122.899062 48.117161 +-122.633870 48.020940 +-122.908449 47.701771 +-122.854472 47.434232 +-122.899062 47.523411 +-122.577546 47.755748 +-122.356943 47.880130 +-122.279498 47.873090 +-122.258376 48.058490 +-122.291232 48.220421 +-122.356943 48.316642 +-122.413267 48.403475 +-122.500100 48.433983 +-122.488366 48.513776 +-122.422654 48.579487 +-122.345209 48.732031 +-122.324087 48.755500 +-122.601014 48.769581 +-122.744171 48.929166 +-122.753558 49.023039 +-122.798148 49.044161 +# -b +154.832448 49.642603 +154.644701 49.391492 +154.799592 49.475978 +154.832448 49.642603 +# -b +154.224617 48.898657 +154.126050 48.746112 +154.280941 48.870495 +154.224617 48.898657 +# -b +152.293172 47.140877 +152.072570 46.878032 +151.938800 46.929662 +152.293172 47.140877 +152.293172 47.140877 +# -b +150.570595 46.171634 +150.227957 45.871239 +150.051944 45.756245 +# -b +149.843076 45.857158 +150.460294 46.232652 +150.570595 46.171634 +# -b +140.702153 50.032178 +140.589505 49.649644 +140.502672 49.253029 +140.392371 49.023039 +140.326660 48.593568 +140.016877 48.300214 +140.016877 48.300214 +# -b +144.067515 50.011057 +144.323320 49.353943 +144.764525 48.856414 +144.553310 48.964368 +143.870381 49.318740 +143.140515 49.203745 +142.875323 48.586528 +142.654720 47.880130 +142.952768 47.335665 +143.206226 46.915581 +143.516009 46.802933 +143.670900 46.415705 +143.494887 46.270201 +142.943381 46.687938 +142.434118 46.361728 +142.025768 46.049599 +142.025768 46.983639 +142.124335 47.671262 +142.258105 48.220421 +142.004647 48.950287 +142.201781 49.590973 +142.246371 49.975854 +142.267492 49.975854 +# -b +150.051944 45.756245 +149.688185 45.739817 +149.843076 45.857158 +# -b +148.958319 45.392485 +148.871486 45.345548 +148.317633 45.082703 +147.909284 44.948933 +147.566646 44.697822 +147.214621 44.446711 +147.235742 44.650885 +147.590114 45.002910 +147.953874 45.291571 +148.197945 45.230553 +148.693127 45.500439 +148.958319 45.392485 +148.958319 45.392485 +# -b +146.937694 43.843574 +146.761682 43.691030 +146.937694 43.843574 +146.937694 43.843574 +# -b +146.210175 44.446711 +146.365066 44.399774 +146.120996 44.097032 +145.614079 43.667561 +145.900393 44.113460 +146.210175 44.446711 +146.210175 44.446711 +# -b +145.083695 44.066523 +145.447454 44.209680 +145.250320 43.620625 +145.646935 43.331964 +145.492044 43.146564 +144.952272 43.017488 +144.234140 42.911880 +143.516009 42.285275 +143.051335 42.081101 +142.180659 42.440166 +141.417938 42.473022 +140.845310 42.505878 +140.502672 42.153853 +141.110503 41.900394 +140.955612 41.726729 +140.523794 41.520207 +140.082589 41.562450 +140.028612 42.120997 +140.028612 42.120997 +# -b +139.927698 42.522306 +140.514407 42.904840 +140.514407 43.282680 +141.152746 43.179420 +141.462528 43.557260 +141.727720 44.043055 +141.870877 44.721290 +141.683130 45.160148 +141.903733 45.432381 +142.136070 45.361976 +142.490442 45.042807 +142.931647 44.643845 +143.516009 44.280085 +144.144960 44.082951 +144.654224 43.906938 +145.083695 44.066523 +# -b +141.241925 45.230553 +141.340492 45.089743 +141.241925 45.230553 +# -b +141.209070 41.372356 +141.485996 41.379397 +141.495384 40.947579 +141.793432 40.325668 +141.960057 40.022926 +# -b +139.906576 39.980683 +140.061467 40.611982 +140.314926 40.787995 +140.413493 41.130632 +140.744396 40.879521 +141.075300 40.888908 +141.331105 41.245627 +140.878166 41.264402 +141.209070 41.372356 +141.209070 41.372356 +# -b +132.729954 44.838632 +132.741689 45.244634 +132.089268 45.120252 +132.300484 44.667313 +132.729954 44.838632 +132.729954 44.838632 +# -b +140.016877 48.300214 +139.620262 47.962270 +139.122733 47.441272 +138.592349 46.960171 +138.404602 46.521313 +138.261445 46.392237 +137.885951 45.979194 +137.379035 45.509827 +136.869772 45.113212 +136.538868 44.808123 +136.097663 44.413855 +135.755025 44.033668 +135.346676 43.597156 +134.628544 43.162992 +133.877557 42.782804 +133.326051 42.677197 +132.929435 42.740561 +132.410785 42.846169 +132.399051 43.137177 +132.068147 43.090240 +131.934377 43.299108 +131.781833 43.106668 +131.504906 42.822701 +131.073089 42.611485 +130.810243 42.529346 +130.622496 42.562202 +# -b +140.028612 42.120997 +139.927698 42.522306 +139.927698 42.522306 +# -b +130.699942 42.374455 +130.476993 42.268848 +129.981810 41.851111 +129.704884 41.412253 +129.749474 40.888908 +129.230823 40.579126 +128.712173 40.257610 +128.170054 40.029967 +128.005775 40.022926 +# -b +120.012455 39.980683 +120.552227 40.215367 +120.883131 40.595554 +121.347804 40.879521 +121.866455 40.987476 +122.152768 40.602595 +122.286538 40.426582 +121.955634 40.046395 +# -b +74.903937 46.833442 +75.443709 46.786505 +76.415299 46.704366 +77.255466 46.598758 +78.072164 46.589371 +78.579081 46.772424 +79.085997 46.748956 +78.701116 46.392237 +77.950129 46.347647 +77.044250 46.460295 +76.117251 46.544781 +75.399119 46.544781 +75.255962 46.507232 +74.803023 46.324179 +74.239782 46.002662 +74.052036 45.493399 +74.328962 44.815164 +73.709398 45.338508 +73.434818 45.918176 +73.899491 46.324179 +74.549565 46.734875 +74.903937 46.833442 +# -b +59.973372 43.597156 +60.489675 43.813065 +60.853435 44.195599 +61.174951 44.683741 +61.735845 45.028726 +61.461265 45.472277 +61.052916 45.833690 +61.261784 46.432133 +61.616156 46.809973 +61.064650 46.568249 +60.656301 46.727834 +60.456820 46.523660 +60.149384 46.462642 +60.468554 46.286629 +60.820579 46.195103 +60.304275 46.256120 +60.193974 46.202143 +# -b +53.885681 39.863341 +53.092451 40.083944 +53.092451 40.083944 +# -b +52.850727 39.957215 +52.761547 40.588514 +52.895317 40.940539 +52.904704 41.064921 +53.280198 40.799729 +53.808236 40.715243 +54.448922 40.741058 +54.526367 40.891255 +54.052307 41.621121 +53.721403 42.074060 +52.895317 41.902741 +52.817871 41.588265 +52.785016 41.264402 +52.463499 42.090488 +52.651246 42.808620 +51.858016 43.010447 +51.318244 43.205235 +51.053051 43.979690 +50.358388 44.376305 +50.611846 44.683741 +51.252532 44.596908 +51.351099 44.817510 +51.581089 45.270450 +51.989439 45.207085 +52.529211 45.448809 +53.390499 45.293918 +53.643957 45.371364 +54.282297 45.160148 +54.756357 45.254022 +54.681259 45.573191 +54.207198 45.965113 +53.697935 46.483763 +53.378765 46.758343 +52.993884 47.058738 +52.684102 47.201895 +52.066884 47.143224 +51.682003 47.208935 +51.217330 47.269953 +50.337267 46.870991 +50.337267 46.870991 +# -b +49.950039 40.698815 +50.280943 40.471172 +50.137786 40.471172 +# -b +59.973372 43.597156 +59.973372 43.597156 +# -b +60.193974 46.202143 +59.830215 46.385196 +59.642468 46.042558 +59.344420 45.981541 +58.837504 45.887667 +58.220286 45.035766 +58.220286 44.503035 +58.372830 43.909285 +58.638023 43.766128 +58.990048 43.749700 +59.421865 43.806025 +59.785625 43.606544 +59.973372 43.597156 +# -b +41.506126 41.646936 +41.736116 41.959065 +41.538982 42.393230 +41.318379 42.864944 +40.910030 43.116055 +40.480559 43.195847 +40.149655 43.397675 +# -b +39.994764 41.025025 +41.118898 41.423987 +41.506126 41.646936 +# -b +50.337267 46.870991 +49.034773 46.697325 +49.034773 46.432133 +48.462145 46.063680 +48.196953 45.904095 +47.866049 46.232652 +47.469434 46.378156 +47.546880 45.772672 +47.293422 45.347895 +47.051697 45.082703 +46.831095 44.801083 +46.950784 44.439670 +47.391989 43.756741 +47.657181 43.782556 +47.591470 42.961164 +48.086652 42.376802 +48.527857 41.909782 +49.100485 41.280830 +49.574545 40.689427 +49.950039 40.698815 +# -b +50.137786 40.471172 +49.541690 40.217714 +49.508834 40.067516 +# -b +40.149655 43.397675 +39.675595 43.700417 +39.276633 43.996118 +38.527992 44.369265 +37.910775 44.603948 +37.591605 44.714250 +37.126932 45.052194 +36.852352 45.307999 +37.194990 45.425341 +37.788739 45.826650 +38.229944 46.178675 +38.340246 46.272548 +37.943630 46.493151 +38.009342 46.734875 +38.560848 46.758343 +38.682883 46.939049 +39.365812 47.119756 +39.255511 47.208935 +39.189800 47.300462 +38.826040 47.291075 +38.527992 47.246485 +38.032810 47.171386 +37.424980 46.983639 +36.950919 46.894460 +36.676339 46.840482 +36.267990 46.697325 +35.991064 46.659776 +35.561593 46.469682 +35.254157 46.188062 +35.287013 46.256120 +35.287013 46.500191 +35.111000 46.317138 +34.977231 46.002662 +34.956109 45.887667 +34.845808 45.995622 +34.768362 46.178675 +34.536026 46.056639 +34.404603 46.171634 +34.261446 46.317138 +34.118289 46.188062 +33.841363 46.256120 +33.963398 46.134085 +34.139411 46.056639 +34.261446 45.958072 +34.449193 46.019090 +34.613471 45.934604 +34.714385 45.833690 +34.723773 45.702267 +35.066410 45.617781 +35.176712 45.401872 +35.528737 45.418300 +36.014532 45.486358 +36.444003 45.509827 +36.542570 45.340855 +36.521448 45.099131 +36.190545 45.089743 +35.937086 45.075662 +35.385580 45.052194 +34.845808 44.855060 +34.679183 44.761186 +34.449193 44.589867 +34.162879 44.486607 +33.766264 44.456098 +33.501071 44.596908 +33.578517 44.761186 +33.587904 45.052194 +33.247613 45.207085 +32.794674 45.394832 +32.597540 45.432381 +32.893241 45.634209 +33.325059 45.857158 +33.820241 45.972153 +33.611373 46.178675 +33.334446 46.164594 +33.158434 46.188062 +32.850998 46.127044 +32.430915 46.117657 +32.198578 46.239693 +31.879408 46.249080 +32.100011 46.422746 +31.780841 46.483763 +32.088277 46.537741 +32.165722 46.591718 +31.912264 46.734875 +31.614216 46.690285 +31.318515 46.643348 +30.898431 46.561209 +30.743540 46.432133 +30.468960 46.225612 +30.248358 46.347647 +30.391515 46.218571 +30.227236 45.873586 +30.105201 45.864199 +# -b +29.929188 41.172876 +30.579262 41.140020 +30.987611 41.090736 +31.548505 41.339501 +32.231434 41.630508 +32.860385 41.919169 +33.731061 42.041204 +34.812952 42.017736 +35.265891 42.083448 +35.662507 41.719688 +36.256256 41.604693 +36.896942 41.290217 +37.535281 41.015638 +38.131377 40.966354 +39.091233 41.100124 +39.994764 41.025025 +39.994764 41.025025 +# -b +29.640528 45.385445 +29.685118 45.106171 +29.321358 44.794042 +28.859032 44.479566 +29.046778 44.817510 +28.903621 44.995870 +28.748730 44.533543 +28.659551 44.195599 +28.659551 43.789597 +28.176103 43.364820 +27.943766 42.775764 +27.657452 42.604445 +27.678574 42.449554 +27.899176 42.132731 +28.009477 41.827643 +28.340381 41.473270 +29.079634 41.290217 +28.715875 40.989822 +28.032946 41.048493 +27.457971 40.865440 +26.664741 40.421888 +26.223536 40.109759 +26.444138 40.496987 +26.631885 40.656572 +26.101500 40.673000 +26.059257 40.731670 +# -b +26.354958 41.811215 +26.542705 41.463883 +26.247004 40.931151 +26.059257 40.731670 +# -b +24.712174 40.614329 +24.756764 40.780954 +24.526774 40.630757 +24.712174 40.614329 +# -b +26.059257 40.731670 +25.331738 40.956967 +24.857678 40.924111 +24.425860 40.956967 +23.665485 40.621369 +24.085569 40.428929 +24.306171 40.201286 +23.930678 40.370258 +23.942412 40.142615 +23.942412 40.142615 +# -b +23.963534 39.964255 +23.534063 40.269344 +23.501207 40.100372 +# -b +23.566918 39.940787 +23.092858 40.360871 +22.905111 40.621369 +22.607063 40.353830 +22.607063 40.152002 +# -b +30.105201 45.864199 +29.818887 45.765632 +29.696852 45.826650 +29.663996 45.634209 +29.640528 45.385445 +29.640528 45.385445 +# -b +26.411283 40.067516 +26.807898 40.438316 +27.138801 40.454744 +27.624596 40.370258 +27.767753 40.572086 +28.021211 40.438316 +28.605573 40.454744 +29.091368 40.565045 +29.091368 40.698815 +29.708586 40.731670 +29.741442 40.832584 +29.387069 40.823197 +29.222791 40.982782 +29.234525 41.231546 +29.455128 41.224506 +29.929188 41.172876 +# -b +26.223536 39.905585 +26.411283 40.067516 +26.411283 40.067516 +# -b +19.962180 39.914972 +19.354349 40.344443 +19.410673 40.572086 +19.443529 40.973395 +19.387205 41.372356 +19.476385 41.604693 +19.309759 41.893354 +18.946000 42.212523 +18.549385 42.465982 +18.054203 42.735868 +17.591876 42.857903 +17.138937 43.083199 +17.535552 42.954123 +17.127203 43.285027 +16.322238 43.540832 +15.958479 43.630012 +15.561864 43.909285 +15.165249 44.258964 +15.209838 44.463138 +14.890669 44.958321 +14.702922 45.169536 +14.327428 45.347895 +14.008259 44.855060 +13.665621 45.113212 +13.510730 45.502786 +13.632765 45.556764 +13.632765 45.556764 +# -b +14.503441 45.237594 +14.536297 45.176576 +14.691188 45.042807 +14.658332 45.005257 +14.416608 45.075662 +14.503441 45.237594 +14.503441 45.237594 +# -b +14.282839 45.160148 +14.315694 45.183617 +14.339163 45.099131 +14.372018 44.974748 +14.372018 44.848019 +14.437730 44.683741 +14.261717 44.887916 +14.339163 44.974748 +14.282839 45.146067 +14.282839 45.160148 +# -b +16.390297 43.414103 +16.432540 43.428184 +16.599165 43.404716 +16.808033 43.357779 +16.808033 43.317883 +16.620286 43.301455 +16.399684 43.364820 +16.390297 43.414103 +# -b +16.643755 42.977592 +16.819767 43.010447 +17.073226 42.994020 +16.984046 42.944736 +16.685998 42.937696 +16.643755 42.977592 +16.643755 42.977592 +# -b +9.861401 44.082951 +10.258016 43.766128 +10.556064 43.155951 +10.800135 42.871984 +11.131039 42.524653 +11.438474 42.458941 +11.858558 42.083448 +12.365474 41.736116 +13.048403 41.280830 +13.632765 41.290217 +14.008259 41.032065 +14.381406 40.799729 +14.559765 40.673000 +14.900056 40.588514 +14.932912 40.337402 +15.331874 40.100372 +15.331874 40.100372 +# -b +15.418707 39.999458 +15.627575 40.083944 +15.683899 40.025273 +# -b +16.533453 39.914972 +16.775178 40.353830 +17.282094 40.487600 +17.932167 40.252916 +17.997879 40.126187 +# -b +18.328782 39.914972 +18.417962 40.236488 +18.021347 40.656572 +17.481575 40.891255 +16.918334 41.165835 +16.268261 41.372356 +15.937357 41.473270 +15.991335 41.696220 +16.092248 41.926210 +15.838790 41.984880 +15.770732 41.952025 +15.209838 41.952025 +15.198104 41.844070 +14.780368 42.123344 +14.646598 42.238339 +14.327428 42.419045 +13.963669 42.808620 +13.787656 43.116055 +13.611644 43.510323 +13.346451 43.669908 +13.236150 43.749700 +12.938102 43.932754 +12.553221 44.068870 +12.288029 44.399774 +12.299763 44.770574 +12.452307 45.005257 +12.243439 45.207085 +12.342006 45.448809 +12.541487 45.495746 +13.092993 45.671758 +13.555320 45.765632 +13.665621 45.617781 +13.689089 45.725736 +# -b +5.132528 43.383594 +4.965903 43.392982 +4.625612 43.376554 +4.393275 43.465733 +4.085840 43.529098 +3.764324 43.367166 +3.269141 43.184113 +3.137719 42.820354 +3.358321 42.355680 +3.236286 42.200789 +3.158840 41.790093 +2.222453 41.292564 +1.140562 40.994516 +0.767415 40.574433 +0.403656 40.180164 +# -b +4.306442 40.027620 +4.327564 40.027620 +# -b +4.085840 39.910278 +4.196141 40.079250 +4.306442 40.027620 +# -b +-0.105608 49.292925 +0.457633 49.414960 +0.535078 49.487712 +0.380187 49.708315 +1.239129 49.942998 +1.239129 49.942998 +# -b +7.547422 43.836533 +7.293964 43.726232 +7.049893 43.580728 +6.730723 43.374207 +6.620422 43.228703 +6.256662 43.123095 +6.036060 43.106668 +5.794336 43.172379 +5.529144 43.228703 +5.320275 43.348392 +5.043349 43.421144 +5.132528 43.383594 +# -b +7.547422 43.836533 +8.066072 43.899898 +8.263206 44.115807 +8.472075 44.322328 +8.793591 44.423242 +9.309895 44.322328 +9.861401 44.082951 +# -b +9.133882 41.316032 +9.267652 41.273789 +9.431930 41.191650 +9.530497 41.074308 +9.673654 40.722283 +9.697123 40.344443 +9.673654 40.142615 +# -b +8.495543 39.973643 +8.472075 40.353830 +8.352386 40.588514 +8.209229 40.741058 +8.209229 40.966354 +8.385242 40.865440 +8.802979 41.074308 +9.089292 41.257362 +9.133882 41.316032 +# -b +9.342751 43.033916 +9.453052 42.719440 +9.553966 42.238339 +9.420196 41.827643 +9.309895 41.588265 +9.211328 41.391131 +8.903892 41.564797 +8.737267 41.787746 +8.692677 42.090488 +8.605844 42.294663 +8.615232 42.433126 +8.638700 42.475369 +8.781857 42.604445 +9.101027 42.752296 +9.321629 42.930655 +9.342751 43.033916 +# -b +-1.274331 60.003881 +-1.164030 59.982759 +-1.164030 59.982759 +# -b +-6.146361 58.445582 +-6.456143 58.377524 +-6.709602 58.227326 +-6.918470 58.203858 +-6.972447 57.980909 +-6.939591 57.835405 +-6.796435 57.769694 +-6.643890 57.877648 +-6.388085 57.941012 +-6.289518 58.058354 +-6.345842 58.128759 +-6.179217 58.180390 +-6.190951 58.255488 +-6.146361 58.412726 +-6.146361 58.445582 +# -b +-7.028771 57.612456 +-7.082748 57.647658 +-7.392531 57.624190 +-7.303351 57.539704 +-7.094483 57.516235 +-7.049893 57.581947 +-7.028771 57.612456 +# -b +-2.628455 58.945458 +-2.663658 58.997088 +-2.971093 59.001782 +-3.114250 59.154326 +-3.224551 58.990048 +-2.872526 58.961886 +-2.684779 58.929030 +-2.628455 58.945458 +# -b +-3.102516 58.830463 +-3.224551 58.921990 +-3.236286 58.814035 +-3.102516 58.830463 +# -b +-5.254564 58.215592 +-5.242830 58.105291 +-5.308541 58.004377 +-5.165384 57.922238 +-5.418842 57.858873 +-5.660566 57.781428 +-5.651179 57.617149 +-5.529144 57.535010 +-5.738012 57.511542 +-5.738012 57.457564 +-5.606589 57.356651 +-5.418842 57.333182 +-5.407108 57.286245 +-5.517409 57.171251 +-5.508022 57.093805 +-5.618323 57.028094 +-5.728625 56.896671 +-5.728625 56.769942 +-5.925759 56.725352 +-5.881169 56.654947 +-5.827192 56.617397 +-5.639445 56.476587 +-5.561999 56.460160 +-5.407108 56.521177 +-5.242830 56.610357 +-5.186506 56.605663 +-5.308541 56.392101 +-5.418842 56.239557 +-5.463432 56.079972 +-5.540878 55.906306 +-5.439964 55.833555 +-5.475166 55.671623 +-5.639445 55.415818 +-5.550265 55.303170 +-5.341397 55.608258 +-5.242830 55.781924 +-5.308541 55.955590 +-5.263951 56.030689 +-5.043349 56.183233 +-5.111407 56.035382 +-5.177118 55.838248 +-5.076204 55.882838 +-4.965903 55.932122 +-4.890804 55.901613 +-4.855602 55.913347 +-4.789890 56.023648 +-4.581022 55.936815 +-4.757035 55.819474 +-4.780503 55.664582 +-4.581022 55.458061 +-4.890804 55.087261 +-5.043349 54.960532 +-4.933047 54.662484 +-4.834480 54.777479 +-4.625612 54.784519 +-4.282974 54.732889 +-4.095227 54.796253 +-3.754936 54.822069 +-3.555455 54.873699 +-3.280876 54.941757 +-3.060273 54.892474 +-3.290263 54.815028 +-3.510865 54.540448 +-3.424032 54.322193 +-3.290263 54.188423 +-3.191696 54.155567 +-2.881914 54.129752 +-2.729369 54.136793 +-2.849058 53.890375 +-2.738757 53.733137 +-2.938238 53.477332 +-2.860792 53.371725 +-3.358321 53.287238 +-4.160939 53.087757 +-4.491842 52.789709 +-3.996660 52.822565 +-3.963805 52.555026 +-3.952070 52.386054 +-4.414397 52.109127 +-5.001106 51.900259 +-5.076204 51.750061 +-4.944782 51.618639 +-4.691323 51.625679 +-4.294708 51.750061 +-4.184407 51.564661 +-3.776058 51.639760 +-3.543721 51.468441 +-3.179962 51.379261 +-2.860792 51.564661 +-2.475911 51.721899 +-2.705901 51.433239 +-2.938238 51.212636 +-3.489744 51.184474 +-4.029516 51.116416 +-4.414397 50.790206 +-5.043349 50.353695 +-5.451698 50.135439 +-5.508022 50.043912 +# -b +-5.508022 49.994629 +-5.263951 50.065034 +-5.099673 50.029831 +-5.099673 50.029831 +# -b +-5.043349 49.987588 +-4.712445 50.205844 +-4.294708 50.346654 +-3.942683 50.318492 +-3.611779 50.241046 +-3.445154 50.346654 +-3.313731 50.628274 +-2.982827 50.677558 +-2.607334 50.677558 +-2.398466 50.522667 +-2.374997 50.529707 +-1.968995 50.571950 +-1.703802 50.684598 +-1.283719 50.762044 +-1.152296 50.823062 +-0.833126 50.783165 +-0.192440 50.797246 +-0.037549 50.801940 +# -b +0.004694 53.557124 +-0.171319 53.726097 +-0.061018 53.655692 +# -b +0.093873 53.836398 +-0.248765 54.244747 +-0.269886 54.251788 +-0.732213 54.554529 +-1.128828 54.758704 +-1.426876 55.131851 +-1.459731 55.397043 +-1.858693 55.720906 +-2.353876 55.955590 +-2.640190 56.004874 +-3.048539 55.955590 +-3.147106 56.084666 +-2.696514 56.178539 +-2.729369 56.368633 +-2.673045 56.441385 +-2.419587 56.654947 +-2.231840 56.798104 +-2.166129 56.870856 +-2.046440 57.136048 +-1.835225 57.326142 +-1.757780 57.570213 +-2.133273 57.664086 +-2.783346 57.675820 +-3.367708 57.664086 +-4.008394 57.504501 +-4.041250 57.640618 +-3.930949 57.706329 +-4.074106 57.811937 +-3.841769 57.992643 +-3.093129 58.337628 +-3.257407 58.626288 +-3.510865 58.579352 +-4.095227 58.527721 +-4.449599 58.551190 +-4.646734 58.567617 +-4.977637 58.429154 +-5.043349 58.227326 +-5.242830 58.220286 +-5.254564 58.215592 +# -b +-1.095972 50.698679 +-1.185152 50.712760 +-1.250863 50.698679 +-1.316575 50.607153 +-1.009139 50.635315 +-1.095972 50.698679 +-1.095972 50.698679 +# -b +-4.095227 53.221527 +-4.217263 53.385806 +-4.437865 53.378765 +# -b +-4.306442 54.373823 +-4.515311 54.233013 +-4.524698 54.064041 +-4.228997 54.277603 +-4.306442 54.373823 +# -b +-5.231096 55.657542 +-5.242830 55.476836 +-5.043349 55.490917 +-5.087939 55.671623 +-5.221708 55.657542 +-5.231096 55.657542 +# -b +-6.080650 55.864063 +-6.167483 55.838248 +-6.388085 55.664582 +-6.190951 55.638767 +-5.991470 55.739681 +-6.080650 55.864063 +-6.080650 55.864063 +# -b +-5.651179 56.072932 +-5.782602 56.011914 +-5.937493 55.845289 +-5.803723 55.875798 +-5.651179 56.072932 +-5.651179 56.072932 +# -b +-6.244928 56.288841 +-6.167483 56.244251 +-5.815457 56.319349 +-5.672301 56.399142 +-5.848313 56.483628 +-5.970349 56.556380 +-6.179217 56.544646 +-6.014938 56.441385 +-6.003204 56.349858 +-6.202685 56.288841 +-6.244928 56.288841 +# -b +-6.244928 57.671126 +-6.301252 57.600721 +-6.477265 57.546744 +-6.632156 57.380119 +-6.345842 57.236962 +-6.167483 57.124314 +-5.881169 57.100846 +-5.705156 57.154823 +-5.892903 57.232268 +-5.991470 57.391853 +-6.125240 57.593681 +-6.244928 57.671126 +# -b +-7.446508 54.941757 +-7.458242 55.068486 +-7.601399 55.213990 +-7.845470 55.188175 +-8.274941 55.012162 +-8.307796 54.833803 +-8.626966 54.674218 +-8.439219 54.606160 +-8.075460 54.606160 +-8.209229 54.451269 +-8.439219 54.296378 +-8.737267 54.240053 +-9.133882 54.270562 +-9.697123 54.218932 +-9.718244 53.949046 +-9.861401 53.869254 +-9.443665 53.777727 +-9.795690 53.589980 +-9.828546 53.378765 +-9.619677 53.298973 +-9.300508 53.228568 +-8.826447 53.167550 +-9.267652 52.982150 +-9.377953 52.721651 +-9.631411 52.576147 +-9.640799 52.547985 +-9.399075 52.576147 +-8.925014 52.688795 +-8.781857 52.789709 +-8.770123 52.662980 +-8.760736 52.594922 +-9.497642 52.522170 +-9.708857 52.259325 +-9.983437 52.212388 +-9.983437 52.212388 +# -b +-10.039761 52.083312 +-9.807424 52.102087 +-9.774568 52.048109 +# -b +-10.004558 51.750061 +-9.729978 51.796998 +-9.718244 51.714859 +-9.962315 51.585783 +-9.607943 51.639760 +-9.387341 51.653841 +-9.652533 51.536499 +-9.453052 51.508337 +-9.157351 51.489563 +-9.101027 51.503644 +-9.023581 51.543540 +-8.671556 51.578742 +-8.396976 51.646801 +-8.242085 51.789958 +-8.152905 51.796998 +-7.965158 51.811079 +-7.723434 51.919034 +-7.547422 51.954236 +-7.249374 52.109127 +-6.808169 52.177185 +-6.312986 52.144330 +-6.268397 52.393094 +-6.125240 52.695836 +-5.991470 52.928173 +-6.057181 53.200406 +-6.036060 53.345909 +-6.068916 53.594674 +-6.244928 53.869254 +-6.080650 53.979555 +-6.003204 54.012410 +-5.561999 54.218932 +-5.561999 54.418413 +-5.451698 54.369129 +-5.594855 54.636669 +-5.761480 54.911248 +-6.268397 55.188175 +-6.796435 55.131851 +-7.082748 55.075527 +-6.939591 55.244499 +-7.249374 55.314904 +-7.326819 55.239805 +-7.338553 55.030937 +-7.446508 54.941757 +-7.446508 54.941757 +# -b +-9.983437 52.212388 +-10.258016 52.069231 +-10.039761 52.083312 +# -b +-9.774568 52.048109 +-10.182918 51.804039 +-10.004558 51.750061 +-10.004558 51.750061 +# -b +-43.963262 59.947557 +-43.996118 59.914701 +-43.996118 59.816134 +-43.665214 59.860724 +-43.864695 59.947557 +-43.963262 59.947557 +# -b +-43.918673 60.020308 +-43.545526 59.971025 +-43.512670 59.971025 +# -b +-60.006227 55.284395 +-59.663589 55.340719 +-59.454721 55.213990 +-59.532167 54.974613 +-59.156673 55.087261 +-58.947805 55.030937 +-58.551190 54.847884 +-58.175696 54.810334 +-58.020805 54.960532 +-57.922238 54.777479 +-57.603068 54.695340 +-57.481033 54.514633 +-57.657045 54.413719 +-58.020805 54.399638 +-58.241407 54.322193 +-58.527721 54.207198 +-59.377276 54.089856 +-59.046372 54.059347 +-58.990048 54.026492 +-59.839602 53.895069 +-59.839602 53.895069 +# -b +-60.104794 53.334175 +-59.553288 53.608755 +-58.837504 53.942005 +-58.098250 54.103937 +-57.865914 54.136793 +-58.429154 54.136793 +-57.668780 54.207198 +-57.204106 54.148527 +-57.171251 53.805889 +-57.281552 53.465598 +-57.138395 53.543043 +-56.610357 53.791808 +-56.410876 53.681507 +-55.859370 53.568859 +-55.892225 53.531309 +-55.781924 53.352950 +-55.683357 53.174590 +-56.058851 53.134694 +-56.136296 53.054902 +-55.826514 52.923479 +-55.892225 52.801444 +-55.727947 52.623084 +-55.969671 52.569107 +-55.584790 52.379013 +-55.892225 52.346158 +-55.781924 52.062190 +-56.443732 51.646801 +-56.863815 51.468441 +-57.800202 51.398036 +-58.572311 51.233758 +-59.001782 50.914588 +-59.398397 50.564910 +-59.982759 50.262168 +-59.982759 50.262168 +# -b +-56.202008 51.508337 +-56.410876 51.454360 +-56.664334 51.268960 +-56.863815 51.123456 +-56.983504 50.949791 +-57.272164 50.755003 +-57.204106 50.628274 +-57.382466 50.402978 +-57.358997 50.219925 +-57.436443 50.149520 +-57.635924 50.036872 +# -b +-56.079972 49.987588 +-56.035382 50.121358 +-56.169152 50.128398 +# -b +-56.720658 49.914836 +-56.378020 50.438181 +-56.190273 50.790206 +-55.892225 50.907548 +-55.814780 51.212636 +-55.671623 51.365180 +-55.695091 51.564661 +-56.202008 51.508337 +-56.202008 51.508337 +# -b +-70.083537 59.926435 +-69.686922 59.898273 +-69.466320 59.799706 +-69.421730 59.633081 +-69.609477 59.407784 +-69.466320 59.342073 +-69.266839 59.266974 +-69.388874 59.121471 +-69.222249 59.018210 +-69.344284 58.997088 +-69.686922 58.853931 +-69.839467 59.008822 +# -b +-70.006092 58.968926 +-69.907525 58.877400 +-69.916912 58.814035 +# -b +-70.006092 58.734243 +-69.618864 58.727202 +-69.079092 58.858625 +-68.461874 58.870359 +-68.264740 58.591086 +-68.318717 58.161615 +-69.278573 57.835405 +-68.318717 58.105291 +-67.933836 58.614554 +-67.811801 58.457316 +-67.778945 58.145187 +-67.436307 58.330587 +-66.917657 58.476091 +-66.521042 58.762405 +-66.046981 58.710774 +-65.993004 58.499559 +-65.960148 58.790567 +-65.960148 58.849238 +-65.849847 58.957192 +-65.605776 59.166060 +-65.561186 59.266974 +-65.375786 59.358501 +-65.352318 59.593184 +-65.474353 59.860724 +-65.331196 59.987453 +# -b +-64.371341 60.036736 +-64.317364 59.914701 +-64.228184 59.665936 +-64.096761 59.553288 +-63.819834 59.464108 +-63.709533 59.297483 +-63.545255 59.245853 +-63.369242 59.149633 +-63.953604 59.093309 +-64.052171 59.046372 +-63.676678 59.041678 +-63.247207 59.081574 +-63.247207 58.968926 +-63.235473 58.802301 +-62.937424 58.809341 +-62.817736 58.654450 +-63.258941 58.544149 +-63.467809 58.562924 +-63.423219 58.476091 +-62.904569 58.487825 +-62.540809 58.389258 +-62.707435 58.278957 +-62.982014 58.180390 +-62.871713 58.121719 +-62.475098 58.121719 +-62.442242 58.016111 +-62.430508 57.917544 +-62.209906 57.877648 +-61.846146 57.628883 +-62.385918 57.488073 +-61.902470 57.434096 +-61.759313 57.225228 +-61.372085 57.032787 +-61.693602 56.697190 +-62.343675 56.835653 +-62.132460 56.701884 +-62.871713 56.640866 +-61.979916 56.617397 +-61.857880 56.532911 +-61.956447 56.441385 +-61.670134 56.281800 +-61.702989 56.202008 +-61.294640 56.122215 +-61.273518 55.906306 +-60.722012 55.875798 +-60.468554 55.758456 +-60.346519 55.582443 +-60.423964 55.321944 +-60.193974 55.352453 +-60.006227 55.284395 +# -b +-59.839602 53.895069 +-60.346519 53.681507 +-61.052916 53.805889 +-60.447432 53.622836 +-60.269073 53.399887 +-60.104794 53.334175 +# -b +-59.982759 50.262168 +-60.104794 50.452262 +-60.325397 50.290330 +-61.074037 50.226965 +-61.658399 50.135439 +-62.155928 50.290330 +-62.970280 50.304411 +-63.733002 50.304411 +-63.864424 50.318492 +-64.427665 50.346654 +-65.098860 50.297370 +-65.882703 50.297370 +-66.255849 50.255127 +-66.553897 50.156560 +-66.732257 50.072074 +# -b +-80.038812 51.184474 +-79.707908 51.074173 +-79.719642 51.454360 +-79.564751 51.578742 +-79.663318 51.454360 +-79.409860 51.632720 +-79.046101 51.475482 +-78.881822 51.268960 +-78.682341 51.447320 +-78.914678 51.653841 +-78.935800 51.836894 +-78.661220 51.968317 +-78.461739 52.184226 +-78.053390 52.191266 +-78.011147 52.266365 +-78.363172 52.252284 +-78.583774 52.475233 +-78.780908 52.634818 +-78.748053 52.808484 +-78.870088 53.087757 +-78.947534 53.432742 +-78.968655 53.714362 +-78.992124 53.942005 +-79.266703 54.270562 +-79.499040 54.502899 +-79.719642 54.554529 +-79.156402 54.721155 +-78.407762 55.019203 +-77.645040 55.352453 +-77.403316 55.509691 +-77.358726 55.627033 +-76.851810 56.148030 +-76.455195 56.117522 +-76.213471 56.244251 +-76.377749 56.429651 +-76.544375 56.483628 +-76.708653 56.263025 +-76.753243 56.453119 +-76.807220 56.769942 +-76.950377 57.032787 +-77.006701 57.297980 +-77.203835 57.640618 +-77.349339 57.948053 +-77.513617 58.196818 +-77.701364 58.271916 +-78.142569 58.436195 +-78.518063 58.591086 +-78.825498 58.802301 +-78.804377 58.910255 +-78.682341 59.105043 +-78.220015 59.201263 +-77.921967 59.250546 +-77.745954 59.386663 +-77.832787 59.536860 +-77.513617 59.588491 +-77.072412 59.593184 +-77.447906 59.694098 +-77.325871 59.853683 +-77.325871 59.947557 +-77.745954 59.982759 +-77.745954 59.982759 +# -b +-70.909623 60.032043 +-70.447297 59.926435 +-70.083537 59.926435 +# -b +-69.839467 59.008822 +-70.027213 58.997088 +-70.006092 58.968926 +# -b +-69.916912 58.814035 +-70.468418 58.666185 +-70.644431 58.539455 +-70.006092 58.734243 +-70.006092 58.734243 +# -b +-90.026942 56.931873 +-89.376869 56.793410 +-88.902808 56.671375 +-88.417013 56.502403 +-88.032133 56.342818 +-87.712963 56.068238 +-87.536950 55.981405 +-87.238902 55.894572 +-86.797697 55.826514 +-86.487915 55.746722 +-86.070178 55.671623 +-85.727540 55.558975 +-85.396637 55.382962 +-85.539794 55.030937 +-85.617239 54.922983 +-85.307457 55.263274 +-84.493105 55.270314 +-83.962720 55.221031 +-83.411214 55.232765 +-82.993477 55.239805 +-82.617984 55.138891 +-82.376260 55.124810 +-82.287080 54.866658 +-82.409116 54.310459 +-82.277693 53.876294 +-82.221369 53.273157 +-82.254224 52.888276 +-81.979645 52.670021 +-81.592417 52.407175 +-81.693331 52.245244 +-82.155657 52.055150 +-81.923321 52.090353 +-81.550174 52.144330 +-81.118356 52.008213 +-80.710007 51.754755 +-80.545728 51.440279 +-80.876632 51.184474 +-81.031523 51.053051 +-80.599706 51.247839 +-80.292270 51.261920 +-80.038812 51.184474 +# -b +-82.021888 53.108879 +-81.669862 53.155816 +-81.296716 53.115919 +-80.897754 52.928173 +-80.799187 52.648899 +-81.338959 52.801444 +-81.857609 52.923479 +-82.122802 52.996231 +-82.021888 53.108879 +# -b +-98.003835 54.315152 +-97.881800 54.340967 +-97.837210 54.211891 +-97.935777 53.960780 +-97.560283 53.972514 +-97.780886 53.913843 +-97.738643 53.672119 +-97.595486 53.430395 +-97.473450 53.153469 +-97.285703 52.975109 +-97.241114 52.674714 +-97.065101 52.458806 +-97.032245 52.249937 +-96.853886 52.048109 +-96.767053 51.883831 +-96.579306 51.672616 +-96.445536 51.534153 +-96.224934 51.341712 +-96.170957 51.135191 +-96.236668 50.869998 +-96.335235 50.583684 +-96.588693 50.407672 +-96.865620 50.520320 +-96.877354 50.926322 +-96.579306 51.259573 +-96.701341 51.217330 +-96.689607 51.534153 +-96.853886 51.747715 +-97.053367 51.480175 +-97.318559 51.761796 +-97.583751 52.019947 +-97.572017 52.134942 +-97.726908 51.991785 +-97.816088 51.876791 +-98.102402 52.188920 +-98.367594 52.379013 +-98.421572 52.444725 +-98.731354 52.627778 +-98.743088 52.953988 +-98.632787 53.059595 +-98.975425 53.066636 +-99.184293 53.284892 +-99.160825 53.489066 +-98.996546 53.667426 +-98.886245 53.817623 +-98.710232 53.784767 +-98.257293 53.763646 +-97.926389 53.700281 +-98.179848 53.906803 +-98.135258 54.148527 +-98.200969 54.200157 +-98.388716 54.270562 +-98.477896 54.359742 +-98.191582 54.404332 +-98.036691 54.355048 +-97.959245 54.348008 +-97.959245 54.348008 +# -b +-94.734694 60.093060 +-94.812139 59.771544 +-94.823873 59.447681 +-94.901319 59.121471 +-94.758162 58.921990 +-94.504704 58.757711 +-94.382668 58.790567 +-94.338079 58.504253 +-94.260633 58.769445 +-93.864018 58.797607 +-93.455669 58.750671 +-93.225679 58.727202 +-93.202210 58.706081 +-93.103643 58.417420 +-92.850185 58.109985 +-92.751618 57.652352 +-92.498160 57.314408 +-92.575605 57.039828 +-92.850185 56.920139 +-92.575605 56.967076 +-92.408980 56.962382 +-92.343269 56.931873 +-91.869208 57.086765 +-91.174545 57.267471 +-90.655894 57.147782 +-90.214689 56.967076 +-90.026942 56.931873 +# -b +-110.136973 59.266974 +-109.761479 59.553288 +-109.407107 59.726954 +-109.341395 59.811440 +-109.285071 59.921741 +-108.888456 59.888886 +-108.512963 59.888886 +-108.733565 59.771544 +-109.163036 59.677670 +-109.141915 59.508698 +-108.811011 59.569716 +-108.733565 59.492271 +-108.688975 59.370235 +-108.214915 59.452374 +-107.827687 59.447681 +-107.707998 59.407784 +-107.529639 59.414825 +-107.309036 59.342073 +-106.945277 59.335033 +-106.492338 59.323298 +-106.680084 59.262281 +-107.043844 59.290443 +-107.341892 59.285749 +-107.717386 59.295136 +-108.083492 59.154326 +-108.634998 59.133205 +-109.064469 59.121471 +-109.540876 59.058106 +-109.982081 58.950152 +-109.982081 58.950152 +# -b +-111.195395 58.717815 +-111.162540 58.757711 +-111.031117 58.825769 +-110.599299 59.086268 +-110.136973 59.266974 +-110.136973 59.266974 +# -b +-109.982081 58.950152 +-110.235540 58.853931 +-110.169828 58.717815 +-110.477264 58.675572 +-110.876226 58.647410 +-111.096828 58.706081 +-111.195395 58.717815 +-111.195395 58.717815 +# -b +-130.052216 53.510188 +-129.843347 53.273157 +-129.974770 53.273157 +-129.974770 53.273157 +# -b +-129.819879 53.660385 +-129.763555 53.646304 +-129.632132 53.554778 +-129.521831 53.404580 +-129.587542 53.219180 +-129.754167 53.411621 +-129.864469 53.554778 +-129.974770 53.634570 +# -b +-130.019360 53.829357 +-129.918446 53.751912 +-129.819879 53.660385 +-129.819879 53.660385 +# -b +-129.235517 52.867155 +-129.179193 52.853074 +-129.059504 52.714611 +-129.003180 52.559720 +-129.179193 52.693489 +-129.247251 52.841340 +-129.235517 52.867155 +# -b +-127.512940 50.421753 +-127.468350 50.428793 +-127.512940 50.647049 +-127.987001 50.731535 +-128.240459 50.625927 +-128.296783 50.823062 +-127.822722 50.855917 +-127.489472 50.780819 +-126.905110 50.583684 +-126.463905 50.506239 +-126.043821 50.428793 +-125.626084 50.365429 +-125.459459 50.210538 +-125.304568 50.041565 +# -b +-127.158568 49.971160 +-127.125712 50.140133 +-127.313459 50.076768 +-127.524674 50.189416 +-127.799254 50.147173 +-127.799254 50.302064 +-127.909555 50.463996 +-127.534061 50.449915 +-127.512940 50.421753 +# -b +-123.903507 49.957079 +-123.945750 50.048606 +-123.980953 50.027484 +# -b +-124.654495 49.964120 +-124.708472 50.133092 +-124.631026 50.287983 +-124.631026 50.435834 +-124.807039 50.393591 +-124.973664 50.435834 +-125.039376 50.555522 +-125.194267 50.499198 +-125.471193 50.527360 +-125.668327 50.569603 +-125.846687 50.520320 +-126.154122 50.541441 +-126.452170 50.590725 +-126.121267 50.654089 +-126.043821 50.717454 +-126.109532 50.823062 +-126.398193 50.884079 +-126.177591 50.926322 +-126.562472 51.024889 +-126.750218 50.982646 +-127.071735 51.003768 +-127.137446 50.898160 +-127.468350 51.010808 +-127.602120 51.064786 +-127.733542 51.273654 +-127.414373 51.327631 +-127.534061 51.398036 +-127.733542 51.405077 +-127.545796 51.466094 +-127.325193 51.473135 +-127.456616 51.548234 +-127.369783 51.679656 +-127.489472 51.773530 +-127.656097 51.630373 +-127.843844 51.712512 +-127.843844 51.911993 +-127.855578 52.005866 +-127.843844 52.163104 +-127.909555 52.317996 +-128.010469 52.425950 +-128.263927 52.371973 +-128.240459 52.451765 +-128.395350 52.559720 +-128.660542 52.533904 +-128.803699 52.646552 +-128.946856 52.754507 +-129.068892 52.874195 +-129.158071 53.015006 +-129.047770 53.193365 +-129.036036 53.310707 +-129.047770 53.444476 +-129.134603 53.510188 +-129.247251 53.456211 +-129.322350 53.477332 +-129.432651 53.521922 +-129.632132 53.653345 +-129.763555 53.784767 +-129.941914 53.880988 +-129.941914 53.880988 +# -b +-130.007626 54.141486 +-129.918446 54.167302 +-129.941914 54.230666 +# -b +-130.117927 55.061446 +-130.272818 55.073180 +-130.293940 55.042671 +-130.415975 54.953491 +-130.669433 54.871352 +-130.824324 54.904208 +-130.934626 54.800947 +-130.967481 55.035631 +-130.714023 55.080220 +-130.559132 55.136545 +-130.714023 55.357147 +-130.880648 55.338372 +-130.890036 55.495610 +-130.934626 55.737334 +-131.077782 55.875798 +-131.145841 56.023648 +-131.223286 56.122215 +-131.432155 55.997833 +-131.631636 55.974365 +-131.819382 55.899266 +-131.861625 55.751415 +-131.995395 55.664582 +-132.159673 55.582443 +-132.260587 55.781924 +-132.082228 55.842942 +-132.016517 55.967324 +-131.995395 56.152724 +-131.608167 56.213742 +-131.784180 56.274760 +-131.995395 56.335777 +-132.204263 56.422610 +-132.326299 56.591582 +-132.326299 56.701884 +-132.502311 56.720658 +-132.591491 56.840347 +-132.844949 56.877896 +-132.934129 56.948301 +-133.053818 57.070337 +-132.767504 56.917792 +-132.922395 57.124314 +-133.175853 57.117273 +-133.286154 57.178291 +-133.506757 57.201759 +-133.363600 57.302673 +-133.232177 57.361344 +-133.485635 57.403587 +-133.539613 57.469299 +-133.452780 57.605415 +-133.694504 57.605415 +-133.551347 57.694595 +-133.241564 57.598375 +-133.098407 57.504501 +-133.110142 57.539704 +-133.274420 57.706329 +-133.452780 57.753266 +-133.506757 57.910504 +-133.342478 57.929278 +-133.673382 57.933972 +-133.762562 57.816630 +-133.861129 57.987949 +-133.551347 58.074782 +-133.750828 58.051314 +-133.649914 58.196818 +-133.882250 58.086516 +-134.093466 58.086516 +-134.135709 58.232020 +-134.323455 58.232020 +-134.555792 58.347015 +-134.853840 58.417420 +-135.065055 58.623942 +-135.130767 58.797607 +-135.252802 58.957192 +-135.515648 59.407784 +-135.560238 59.295136 +-135.583706 59.194222 +-135.482792 58.985354 +-135.295045 58.670878 +-135.175357 58.452623 +-135.295045 58.232020 +-135.539116 58.452623 +-135.703394 58.412726 +-135.959200 58.476091 +-136.001443 58.635676 +-136.078888 58.877400 +-136.278369 58.809341 +-136.632741 58.933724 +-136.731308 58.945458 +-137.005888 59.025250 +-137.095068 58.921990 +-137.041091 58.905562 +-136.698453 58.790567 +-136.522440 58.706081 +-136.421526 58.654450 +-136.200924 58.520681 +-136.334693 58.347015 +-136.564683 58.393952 +-136.653863 58.271916 +-136.951911 58.365790 +-137.339139 58.457316 +-137.702898 58.595779 +-137.714632 58.717815 +-137.890645 58.734243 +-138.200427 58.957192 +-138.266138 59.173101 +-138.144103 59.386663 +-137.857789 59.548595 +-138.155837 59.642468 +-138.000946 59.492271 +-138.275526 59.447681 +-138.442151 59.407784 +-138.421030 59.210650 +-138.728465 59.182488 +-138.895090 59.234119 +-139.315174 59.346767 +-139.458331 59.386663 +-139.634343 59.447681 +-139.899536 59.525126 +-139.690667 59.604919 +-139.613222 59.738688 +-139.667199 59.893579 +-139.502921 59.971025 +-139.458331 59.792665 +-139.348029 59.569716 +-139.348029 59.731648 +-139.204873 59.860724 +-139.324561 59.905313 +-139.434862 59.954597 +# -b +-139.711789 60.057858 +-139.955860 59.872458 +-139.955860 59.872458 +# -b +-134.943020 57.283899 +-134.886696 57.248696 +-134.910164 56.997585 +-134.776395 56.997585 +-134.809250 56.877896 +-134.755273 56.755861 +-134.710683 56.500056 +-134.722417 56.427304 +-134.722417 56.281800 +-134.877309 56.300575 +-134.996997 56.464853 +-134.975876 56.713618 +-134.954754 56.805144 +-135.107298 56.720658 +-135.306779 56.847387 +-135.295045 56.955342 +-135.273924 57.093805 +-135.449936 57.255737 +-135.661151 57.356651 +-135.583706 57.511542 +-135.428815 57.473992 +-135.142501 57.391853 +-134.987610 57.302673 +-134.943020 57.283899 +# -b +-134.633238 57.617149 +-134.731805 57.746225 +-134.820984 57.898769 +-134.832719 58.063048 +-134.644972 58.180390 +-134.368045 58.173349 +-134.147443 58.023152 +-133.959696 57.804896 +-133.861129 57.621843 +-133.915106 57.652352 +-134.048876 57.811937 +-134.192033 57.980909 +-134.302334 58.070088 +-134.358658 57.945706 +-134.180298 57.753266 +-134.037142 57.628883 +-134.025407 57.539704 +-134.037142 57.462258 +-134.060610 57.361344 +-134.192033 57.333182 +-134.302334 57.283899 +-134.433757 57.124314 +-134.621503 57.093805 +-134.644972 57.236962 +-134.621503 57.321448 +-134.457225 57.380119 +-134.534671 57.457564 +-134.445491 57.546744 +-134.567526 57.551438 +-134.633238 57.617149 +# -b +-134.203767 56.647906 +-134.358658 56.732392 +-134.433757 56.877896 +-134.246010 56.924833 +-133.992552 56.791063 +-133.882250 56.647906 +-133.959696 56.464853 +-133.959696 56.293534 +-134.060610 56.267719 +-134.246010 56.293534 +-134.168564 56.446079 +-134.135709 56.537605 +-134.281212 56.617397 +-134.203767 56.647906 +# -b +-133.795418 56.924833 +-133.893985 56.990544 +-134.016020 57.098499 +-133.607671 57.063296 +-133.319010 57.032787 +-133.077286 56.948301 +-133.053818 56.840347 +-133.053818 56.671375 +-133.199321 56.755861 +-133.384721 56.852081 +-133.265033 56.676068 +-133.187587 56.561073 +-133.375334 56.514137 +-133.649914 56.579848 +-133.717972 56.852081 +-133.727359 56.894324 +-133.882250 56.906058 +-133.795418 56.924833 +-133.795418 56.924833 +# -b +-132.856683 56.805144 +-132.823828 56.779329 +-132.645468 56.610357 +-132.755770 56.591582 +-132.910661 56.603316 +-132.943516 56.791063 +-132.856683 56.805144 +-132.856683 56.805144 +# -b +-132.767504 56.434344 +-132.722914 56.317003 +-132.856683 56.317003 +-133.086673 56.396795 +-132.856683 56.469547 +-132.767504 56.434344 +-132.767504 56.434344 +# -b +-132.105696 56.335777 +-131.995395 56.255985 +-132.082228 56.213742 +-132.227732 56.267719 +-132.338033 56.385061 +-132.314565 56.422610 +-132.150286 56.366286 +-132.105696 56.335777 +# -b +-135.130767 58.081823 +-135.041587 58.051314 +-135.130767 57.952747 +-135.119033 57.894076 +-135.363103 57.840099 +-135.682273 57.910504 +-135.649417 57.851833 +-135.363103 57.781428 +-135.217600 57.776734 +-135.020465 57.633577 +-135.020465 57.481033 +-135.395959 57.593681 +-135.694007 57.776734 +-135.825430 57.682861 +-135.694007 57.546744 +-135.825430 57.415321 +-136.036645 57.516235 +-136.123478 57.633577 +-136.266635 57.769694 +-136.388670 57.976215 +-136.322959 58.039580 +-136.400405 58.215592 +-136.233779 58.149881 +-136.057767 58.248448 +-135.738597 58.239061 +-135.506260 58.121719 +-135.252802 58.133453 +-135.130767 58.081823 +-135.130767 58.081823 +# -b +-132.812094 56.035382 +-132.645468 55.899266 +-132.502311 55.725600 +-132.502311 55.683357 +-132.269975 55.540200 +-132.380276 55.540200 +-132.558635 55.533160 +-132.448334 55.413471 +-132.183142 55.352453 +-132.192529 55.225724 +-132.039985 55.136545 +-132.171408 54.986347 +-132.028251 54.927676 +-132.049372 54.744623 +-132.192529 54.763398 +-132.338033 54.904208 +-132.424866 54.991041 +-132.568023 55.073180 +-132.678324 55.213990 +-132.966985 55.275008 +-133.241564 55.368881 +-133.044430 55.469795 +-132.976372 55.589484 +-133.164119 55.627033 +-133.363600 55.763149 +-133.286154 56.028342 +-133.309623 56.171499 +-133.408190 56.047117 +-133.661648 55.955590 +-133.649914 56.115175 +-133.661648 56.281800 +-133.584202 56.366286 +-133.363600 56.331084 +-133.110142 56.274760 +-133.131263 56.084666 +-132.901273 56.065891 +-132.812094 56.035382 +# -b +-131.420420 55.312557 +-131.321853 55.345413 +-131.244408 55.263274 +-131.101251 55.155319 +-130.958094 55.237458 +-131.044927 55.446327 +-131.044927 55.725600 +-131.145841 55.892225 +-131.354709 55.948549 +-131.542456 55.868757 +-131.596433 55.788965 +-131.652757 55.688051 +-131.706734 55.533160 +-131.608167 55.345413 +-131.554190 55.521425 +-131.399299 55.465101 +-131.375831 55.619993 +-131.333587 55.401737 +-131.420420 55.312557 +-131.420420 55.312557 +# -b +-133.053818 55.035631 +-132.955251 54.960532 +-132.800359 54.770438 +-133.044430 54.890127 +-133.253299 55.087261 +-133.253299 55.256233 +-133.065552 55.124810 +-133.053818 55.035631 +# -b +-131.631636 55.312557 +-131.497866 55.225724 +-131.399299 55.073180 +-131.542456 55.113076 +-131.587046 55.237458 +-131.631636 55.312557 +# -b +-132.061106 54.049960 +-131.819382 54.153221 +-131.807648 53.822317 +-131.950805 53.477332 +-132.072841 53.233261 +-132.171408 53.284892 +-132.314565 53.284892 +-132.525780 53.273157 +-132.535167 53.364684 +-132.568023 53.514881 +-132.866071 53.627530 +-133.032696 53.939659 +-133.121876 54.141486 +-132.833215 54.174342 +-132.678324 54.042919 +-132.502311 54.108631 +-132.281709 54.012410 +-132.359154 53.822317 +-132.657202 53.693241 +-132.481190 53.653345 +-132.314565 53.667426 +-132.138552 53.869254 +-132.093962 53.979555 +-132.093962 54.042919 +-132.061106 54.049960 +# -b +-132.150286 52.740426 +-132.192529 52.813178 +-132.260587 52.895317 +-132.227732 53.054902 +-132.359154 53.113573 +-132.105696 53.186325 +-131.894481 53.291932 +-131.706734 53.113573 +-131.939071 53.073676 +-131.673879 52.961028 +-131.917949 52.900011 +-131.939071 52.707570 +-131.828770 52.592575 +-131.575311 52.512783 +-131.432155 52.386054 +-131.265529 52.163104 +-131.542456 52.303915 +-131.774792 52.444725 +-131.751324 52.505742 +-132.039985 52.667674 +-132.150286 52.740426 +# -b +-130.660046 53.979555 +-130.603722 54.042919 +-130.460565 54.101590 +-130.293940 53.946699 +-130.472299 53.902109 +-130.624843 53.965474 +-130.660046 53.979555 +# -b +-130.538010 53.660385 +-130.493421 53.646304 +-130.162517 53.554778 +-130.052216 53.510188 +# -b +-129.974770 53.273157 +-130.305674 53.482026 +-130.526276 53.646304 +-130.538010 53.660385 +# -b +-129.974770 53.634570 +-130.052216 53.737831 +-130.150783 53.784767 +-130.251696 53.880988 +-130.150783 53.902109 +-130.019360 53.829357 +-130.019360 53.829357 +# -b +-129.941914 53.880988 +-130.117927 54.005370 +-130.007626 54.141486 +# -b +-129.941914 54.230666 +-130.183638 54.218932 +-130.371385 54.348008 +-130.472299 54.451269 +-130.404241 54.610853 +-130.239962 54.725848 +-130.162517 54.756357 +-130.106193 54.915942 +-130.040481 55.012162 +-130.117927 55.061446 +-130.117927 55.061446 +# -b +-139.955860 59.872458 +-140.385331 59.731648 +-140.915715 59.776238 +-141.455487 59.881845 +-141.389776 59.966331 +-141.401510 59.992146 +# -b +-141.643234 60.008574 +-142.084439 59.987453 +-142.084439 59.987453 +# -b +-147.484507 60.003881 +-147.606542 59.881845 +-147.913978 59.792665 +-147.925712 59.947557 +-147.836532 59.975719 +# -b +-148.742410 60.015615 +-149.195350 59.975719 +-149.195350 59.975719 +# -b +-149.394831 60.008574 +-149.472276 59.987453 +# -b +-149.547375 60.015615 +-149.702266 59.715220 +-149.880626 59.898273 +-149.934603 59.698792 +-149.934603 59.698792 +# -b +-158.568609 56.366286 +-158.568609 56.342818 +-158.390250 56.305268 +-158.446574 56.176192 +-158.556875 56.084666 +-158.556875 56.281800 +-158.568609 56.366286 +# -b +-154.771430 56.556380 +-154.693984 56.579848 +-154.604805 56.579848 +-154.726840 56.415570 +-154.771430 56.556380 +-154.771430 56.556380 +# -b +-154.241045 56.544646 +-154.372468 56.556380 +-154.241045 56.629132 +-154.184721 56.568114 +-154.241045 56.544646 +# -b +-153.192010 57.129008 +-153.245987 57.086765 +-153.433734 57.117273 +-153.203744 57.206453 +-152.947939 57.190025 +-153.192010 57.129008 +-153.192010 57.129008 +# -b +-154.837141 57.373078 +-154.848875 57.403587 +-154.661129 57.551438 +-154.372468 57.659392 +-154.130744 57.621843 +-154.053298 57.523276 +-153.865552 57.427056 +-153.809228 57.570213 +-153.865552 57.722757 +-153.931263 57.898769 +-153.666071 57.711023 +-153.433734 57.835405 +-153.192010 57.858873 +-153.159154 57.933972 +-152.980795 57.804896 +-152.760192 57.905810 +-152.595914 57.753266 +-152.584180 57.671126 +-152.384699 57.617149 +-152.330721 57.516235 +-152.640504 57.511542 +-152.992529 57.558478 +-152.861106 57.462258 +-152.682747 57.349610 +-152.849372 57.333182 +-153.015997 57.349610 +-153.081709 57.279205 +-153.457202 57.194719 +-153.710660 57.063296 +-153.766984 56.877896 +-154.119010 56.791063 +-153.942997 57.009319 +-154.107276 57.093805 +-154.339612 57.194719 +-154.241045 57.136048 +-154.351346 56.906058 +-154.593070 57.182985 +-154.837141 57.373078 +-154.837141 57.373078 +# -b +-153.478324 58.109985 +-153.445468 58.145187 +-153.203744 58.126412 +-153.236600 58.074782 +-153.457202 58.086516 +-153.478324 58.109985 +# -b +-152.793048 58.290691 +-152.893962 58.318853 +-152.882228 58.405686 +-152.694481 58.476091 +-152.384699 58.469050 +-152.462144 58.354055 +-152.232154 58.337628 +-152.142975 58.227326 +-152.551324 58.145187 +-152.849372 58.098250 +-152.971407 58.070088 +-153.081709 58.173349 +-153.147420 58.208552 +-152.980795 58.290691 +-152.793048 58.290691 +-152.793048 58.290691 +# -b +-152.682747 58.647410 +-152.628769 58.602820 +-152.495000 58.635676 +-152.495000 58.532415 +-152.682747 58.607514 +-152.682747 58.647410 +# -b +-160.002525 56.537605 +-159.814779 56.586889 +-159.429898 56.706577 +-159.054404 56.870856 +-158.789212 56.847387 +-158.613199 57.129008 +-158.413718 57.236962 +-158.193116 57.384813 +-157.850478 57.605415 +-157.728442 57.875301 +-157.641609 58.173349 +-157.463250 58.330587 +-157.540695 58.480785 +-157.132346 58.774139 +-157.087756 58.858625 +-156.813176 59.098002 +-157.078369 59.069840 +-157.376417 58.905562 +-157.683852 58.774139 +-158.017103 58.694347 +-158.324538 58.682612 +-158.613199 58.837504 +-158.535753 58.968926 +-158.667176 58.968926 +-158.899513 58.802301 +-158.854923 58.670878 +-158.998080 58.433848 +-159.176439 58.469050 +-159.439285 58.745977 +-159.650500 58.917296 +-159.826513 58.905562 +-159.925080 58.870359 +# -b +-149.934603 59.698792 +-150.256119 59.665936 +-150.486109 59.374929 +-150.563555 59.543901 +-150.840481 59.442987 +-151.138529 59.323298 +-151.302808 59.238812 +-151.800337 59.189529 +-152.020939 59.342073 +-151.866048 59.480536 +-151.690035 59.499311 +-151.424843 59.464108 +-151.370866 59.543901 +-151.072818 59.783278 +-151.546878 59.661243 +-151.866048 59.705833 +-151.800337 59.947557 +-151.800337 59.947557 +# -b +-152.771926 60.020308 +-153.081709 59.905313 +-153.159154 59.837255 +-153.457202 59.698792 +-153.633215 59.687058 +-153.710660 59.569716 +-153.942997 59.419519 +-154.250433 59.217691 +-154.250433 59.041678 +-153.788106 59.006476 +-153.522914 58.945458 +-153.490058 58.767098 +-153.687192 58.670878 +-154.020443 58.579352 +-154.184721 58.476091 +-154.327878 58.347015 +-154.217577 58.239061 +-154.527359 58.173349 +-154.780817 58.074782 +-155.111721 58.016111 +-155.233756 57.905810 +-155.444972 57.828364 +-155.564660 57.753266 +-155.785263 57.788468 +-155.886177 57.605415 +-156.193612 57.485726 +-156.503394 57.415321 +-156.592574 57.314408 +-156.491660 57.190025 +-156.735731 57.028094 +-156.900009 56.985851 +-157.111225 56.906058 +-157.352949 56.840347 +-157.618141 56.786370 +-157.751911 56.659641 +-158.071080 56.636172 +-157.927923 56.591582 +-158.237705 56.514137 +-158.622586 56.410876 +-159.030936 56.410876 +-159.152971 56.427304 +-158.744622 56.251291 +-158.789212 56.035382 +-158.899513 56.035382 +-159.197561 55.936815 +-159.429898 55.911000 +-159.561320 55.925081 +-159.650500 55.725600 +-159.781923 55.612952 +-159.749067 55.807739 +-159.993138 55.824167 +-159.993138 55.824167 +# -b +-169.331195 52.801444 +-169.277218 52.907051 +-169.000291 53.179284 +-168.735099 53.324788 +-168.547352 53.482026 +-168.106147 53.536003 +-168.261038 53.343562 +-168.615410 53.172244 +-168.868869 53.007965 +-169.298339 52.787363 +-169.331195 52.801444 +# -b +-167.840955 53.317747 +-167.840955 53.404580 +-167.587497 53.430395 +-167.310570 53.627530 +-167.089968 53.679160 +-167.179147 53.784767 +-167.125170 53.991289 +-166.791919 53.888028 +-166.550195 54.017104 +-166.538461 53.880988 +-166.615907 53.770686 +-166.791919 53.601714 +-167.134557 53.477332 +-167.533519 53.338869 +-167.840955 53.317747 +-167.840955 53.317747 +# -b +-166.130112 54.277603 +-165.975221 54.230666 +-166.019811 54.064041 +-166.240413 54.153221 +-166.130112 54.277603 +# -b +-165.048221 54.648403 +-164.827618 54.756357 +-164.595282 54.986347 +-164.132955 54.998081 +-163.811439 55.113076 +-163.647160 55.042671 +-163.569715 54.878393 +-163.468801 54.833803 +-163.304522 54.782172 +-163.459414 54.751664 +-164.055510 54.662484 +-164.705583 54.392598 +-164.982510 54.547489 +-165.048221 54.648403 +# -b +-162.896173 54.500552 +-162.795259 54.521674 +-162.708426 54.437188 +-162.896173 54.500552 +-162.896173 54.500552 +# -b +-160.732391 55.368881 +-160.798103 55.375922 +-160.720657 55.413471 +-160.643211 55.357147 +-160.610356 55.270314 +-160.744125 55.237458 +-160.887282 55.289089 +-160.842692 55.368881 +-160.732391 55.368881 +# -b +-160.854427 58.846891 +-160.896670 58.710774 +-161.161862 58.612207 +-161.051561 58.757711 +-160.854427 58.846891 +-160.854427 58.846891 +# -b +-165.688907 60.003881 +-165.954099 59.942863 +-166.186436 59.872458 +-166.615907 59.872458 +-166.991400 59.982759 +-167.212003 59.999187 +# -b +-163.435945 55.188175 +-163.205955 55.244499 +-163.006474 55.251539 +-162.830462 55.375922 +-162.675571 55.502651 +-162.497211 55.650501 +-162.199163 55.807739 +-161.769692 55.960284 +-161.471644 56.016608 +-161.295632 56.072932 +-161.030439 56.054157 +-161.030439 55.960284 +-160.776981 55.887532 +-160.631477 55.911000 +-160.345163 55.849982 +-160.401487 55.906306 +-160.622090 55.974365 +-160.544644 56.171499 +-160.213741 56.422610 +-160.002525 56.537605 +# -b +-159.925080 58.870359 +-160.190272 58.905562 +-160.368632 58.957192 +-160.324042 59.121471 +-160.434343 59.229425 +-160.744125 58.990048 +-161.051561 58.938417 +-161.459910 58.797607 +-161.614801 58.687306 +-162.034885 58.635676 +-161.912849 58.722509 +-161.725102 58.877400 +-161.736837 59.086268 +-161.891728 59.149633 +-162.056006 59.318605 +-161.826016 59.464108 +-161.879994 59.633081 +-162.056006 59.898273 +-162.189776 59.982759 +# -b +-162.574657 60.081326 +-162.839849 59.853683 +-163.105041 59.670630 +-163.492269 59.698792 +-163.790317 59.738688 +-164.121221 59.837255 +-163.856029 59.954597 +-164.067244 59.975719 +-164.067244 59.975719 +# -b +-159.993138 55.824167 +-160.246596 55.737334 +-160.500054 55.688051 +-160.666680 55.594177 +-160.819224 55.577750 +-160.964728 55.526119 +-161.316753 55.446327 +-161.626535 55.465101 +-161.647657 55.664582 +-161.868259 55.469795 +-162.034885 55.263274 +-162.222631 55.176441 +-162.443234 55.124810 +-162.541801 55.150626 +-162.619247 55.270314 +-162.684958 55.213990 +-162.762404 55.049712 +-163.060452 55.054405 +-163.205955 55.087261 +-163.337378 54.908902 +-163.391355 55.030937 +-163.536859 55.131851 +-163.435945 55.188175 +# -b +-169.873314 56.647906 +-169.894435 56.617397 +-169.751279 56.603316 +-169.774747 56.549339 +-169.774747 56.549339 +-169.873314 56.647906 +# -b +-178.429875 51.916687 +-178.406406 51.951889 +-178.141214 51.923727 +-177.843166 51.855669 +-177.976936 51.686697 +-178.242128 51.679656 +-178.296105 51.843935 +-178.429875 51.916687 +# -b +-177.822045 51.686697 +-177.610829 51.754755 +-177.390227 51.855669 +-177.237683 51.904953 +-177.357371 51.733634 +-177.732865 51.686697 +-177.822045 51.686697 +# -b +-177.038202 51.808732 +-176.927900 51.829854 +-176.895045 51.973011 +-176.751888 51.904953 +-176.585262 51.848629 +-176.531285 51.768836 +-176.805865 51.691391 +-176.972490 51.698431 +-177.038202 51.808732 +-177.038202 51.808732 +# -b +-174.454336 52.386054 +-174.367503 52.425950 +-174.189144 52.271059 +-174.355769 52.141983 +-174.576372 52.066884 +-174.818096 52.113821 +-174.597493 52.217082 +-174.454336 52.343811 +-174.454336 52.386054 +# -b +-174.156288 52.156064 +-174.123432 52.156064 +-173.881708 52.149023 +-173.548458 52.113821 +-173.241022 52.113821 +-173.515602 52.052803 +-173.902830 52.066884 +-174.156288 52.156064 +-174.156288 52.156064 +# -b +-172.698903 52.418909 +-172.588602 52.386054 +-172.621458 52.282793 +-172.698903 52.418909 +-172.698903 52.418909 +# -b +-170.546856 57.201759 +-170.448289 57.225228 +-170.535121 57.178291 +-170.546856 57.201759 +# -b +172.297595 52.928173 +172.285860 52.939907 +172.473607 53.015006 +172.750534 52.993884 +172.950015 52.928173 +173.135415 52.860114 +172.860835 52.787363 +172.640233 52.820218 +172.506463 52.874195 +172.297595 52.928173 +172.297595 52.928173 +# -b +177.441857 52.141983 +177.498181 52.181879 +177.498181 52.034028 +177.397267 51.944849 +177.110954 51.911993 +177.441857 52.141983 +177.441857 52.141983 +# -b +178.512014 51.665575 +178.622315 51.686697 +179.000000 51.499861 +179.000000 51.499861 +# -b +179.000000 51.414012 +178.612928 51.597517 +178.512014 51.665575 +# -b +170.375537 60.048470 +170.222992 59.942863 +170.089223 59.971025 +# -b +164.998937 59.804400 +164.736092 59.942863 +164.736092 59.942863 +# -b +164.557732 60.036736 +164.104793 59.935822 +163.532165 59.860724 +163.266973 59.581450 +163.245852 59.274015 +163.133203 59.086268 +162.903214 58.973620 +162.283649 58.515987 +161.985601 58.086516 +162.173348 57.746225 +162.426806 57.898769 +163.022902 57.804896 +163.144938 57.574906 +162.724854 57.272164 +162.748323 56.936567 +162.802300 56.683109 +163.189528 56.615051 +163.266973 56.255985 +163.046371 55.986099 +162.825768 56.028342 +162.649755 56.237210 +162.968925 56.476587 +162.703733 56.446079 +162.239059 56.305268 +162.339973 56.232517 +162.051312 56.065891 +161.720409 55.669276 +161.675819 55.237458 +162.018457 54.890127 +161.931624 54.603813 +161.344915 54.488818 +160.605662 54.430147 +160.098746 54.146180 +# -b +159.997832 53.153469 +160.009566 53.146428 +# -b +159.997832 59.194222 +160.340470 59.358501 +160.927178 59.654202 +161.368383 59.954597 +# -b +164.369986 59.170754 +164.017960 59.058106 +163.785624 58.933724 +163.475841 58.567617 +163.764502 58.640369 +164.614056 58.950152 +164.369986 59.170754 +164.369986 59.170754 +# -b +166.479790 60.008574 +166.235720 59.853683 +166.080828 59.853683 +166.158274 59.954597 +# -b +165.088117 60.069592 +165.043527 59.877151 +165.010672 59.860724 +# -b +165.982261 55.319598 +166.202864 55.282048 +166.181742 55.195215 +166.280309 55.035631 +166.557236 54.807988 +166.611213 54.700033 +166.479790 54.700033 +166.116031 54.948798 +165.860226 55.244499 +165.871960 55.307863 +165.982261 55.312557 +165.982261 55.319598 +# -b +167.308223 54.871352 +167.427912 54.789213 +167.648514 54.685952 +167.880851 54.533408 +167.671983 54.636669 +167.350466 54.819722 +167.308223 54.871352 +# -b +160.098746 54.146180 +159.878143 53.672119 +159.910999 53.390499 +159.997832 53.153469 +159.997832 53.153469 +# -b +160.009566 53.146428 +159.490915 53.172244 +158.805639 52.881236 +158.519326 52.846033 +158.552181 52.639512 +158.486470 52.451765 +158.409024 52.099740 +157.857518 51.581089 +157.315399 51.182127 +156.829604 50.898160 +156.719303 51.168046 +156.599614 51.815773 +156.322688 52.545639 +156.146675 53.350603 +155.926073 53.958433 +155.804037 54.256481 +155.682002 54.953491 +155.604556 55.643461 +155.858015 56.446079 +156.289832 56.882590 +156.808483 57.091458 +156.984495 57.680514 +157.449169 57.765000 +158.078121 57.969175 +158.939409 58.386911 +159.624685 58.802301 +159.943855 59.149633 +159.997832 59.194222 +# -b +154.665822 60.086020 +154.379508 59.816134 +154.280941 59.710526 +154.224617 59.468802 +154.776124 59.459415 +155.163351 59.234119 +154.886425 59.109736 +154.501544 59.159020 +154.060339 59.053412 +153.419653 59.130858 +153.032425 58.950152 +152.534896 59.013516 +151.995124 58.830463 +151.354438 58.905562 +151.375559 59.126164 +152.072570 59.137898 +152.093691 59.262281 +151.607896 59.480536 +151.023534 59.548595 +150.746608 59.496964 +150.317137 59.581450 +150.173980 59.621346 +# -b +156.543290 50.827755 +156.367278 50.771431 +156.421255 50.654089 +156.543290 50.827755 +# -b +156.090351 50.717454 +155.869749 50.527360 +155.550579 50.337267 +155.294774 50.217578 +155.372220 50.018097 +155.881483 50.210538 +156.200653 50.513279 +156.090351 50.710413 +156.090351 50.710413 +# -b +150.173980 59.621346 +149.476970 59.719914 +149.035765 59.581450 +148.913729 59.452374 +148.913729 59.330339 +148.660271 59.210650 +148.373957 59.367888 +147.843573 59.250546 +147.390633 59.262281 +146.695970 59.407784 +146.374454 59.222384 +146.001307 59.159020 +145.879272 59.367888 +145.348887 59.386663 +144.454743 59.367888 +143.426829 59.330339 +142.865935 59.250546 +141.992913 58.914949 +141.220804 58.429154 +140.547262 57.941012 +140.181156 57.711023 +# -b +139.861986 54.146180 +140.314926 53.946699 +140.568384 53.653345 +141.274781 53.317747 +141.417938 53.179284 +141.197336 53.019699 +140.854698 53.146428 +140.303191 53.252036 +140.049733 53.259076 +# -b +139.939432 53.186325 +140.580118 53.059595 +141.152746 52.885930 +141.230191 52.519823 +141.408551 52.235856 +141.396817 52.031682 +141.185601 51.705472 +140.821842 51.430892 +140.767865 51.252532 +140.666951 51.001421 +140.502672 50.625927 +140.612974 50.161254 +140.702153 50.032178 +# -b +142.645333 54.340967 +142.952768 54.134446 +143.086538 53.521922 +143.384586 52.813178 +143.196839 52.275752 +143.316528 51.698431 +143.494887 51.369874 +143.682634 50.834796 +144.067515 50.011057 +144.067515 50.011057 +# -b +142.267492 49.975854 +142.213515 50.358388 +142.201781 50.919282 +142.157191 51.369874 +141.772310 51.691391 +141.706599 52.120861 +141.870877 52.639512 +141.903733 53.198059 +142.136070 53.521922 +142.577275 53.442130 +142.621864 53.658038 +142.678188 53.822317 +142.589009 54.010064 +142.389528 54.275256 +142.645333 54.340967 +142.645333 54.340967 +# -b +140.181156 57.711023 +139.894842 57.617149 +139.575672 57.368385 +139.078143 57.147782 +138.681528 56.917792 +138.460926 56.798104 +138.151144 56.556380 +137.897685 56.317003 +137.731060 56.138643 +137.289855 55.911000 +136.848650 55.669276 +136.440301 55.514385 +135.954506 55.192869 +135.522688 55.016856 +135.236374 54.723502 +135.755025 54.540448 +136.494278 54.596772 +136.782939 54.596772 +136.804060 54.359742 +136.804060 54.218932 +136.747736 53.972514 +136.893240 53.829357 +137.266387 54.010064 +137.388422 54.270562 +137.498723 54.113324 +137.665349 53.932618 +137.454133 53.658038 +137.576169 53.547737 +138.383480 53.815276 +138.437457 53.653345 +138.714384 53.789461 +138.758974 54.061694 +138.934986 54.230666 +139.519348 54.230666 +139.772807 54.171995 +139.861986 54.146180 +139.861986 54.146180 +# -b +140.049733 53.259076 +139.939432 53.186325 +# -b +137.355566 54.833803 +137.301589 54.718808 +137.632493 54.648403 +138.007987 54.793907 +137.984518 55.124810 +137.587903 55.091955 +137.355566 54.833803 +# -b +109.590160 55.688051 +109.688727 55.676317 +109.810763 55.368881 +109.655871 54.775132 +109.468125 54.134446 +109.038654 53.547737 +108.585715 53.449170 +108.872028 53.296626 +108.243077 52.860114 +107.459234 52.613697 +106.741102 52.289834 +106.046439 51.766489 +104.699356 51.381608 +103.826333 51.562315 +104.511609 51.752408 +105.208619 51.827507 +105.882161 52.350851 +106.698859 52.780322 +107.360667 53.052555 +107.581269 53.205099 +107.095474 53.205099 +107.858196 53.697935 +108.463679 54.249441 +108.916618 54.864312 +109.226401 55.338372 +109.503327 55.681010 +109.590160 55.688051 +# -b +29.938576 59.924088 +30.093467 59.924088 +30.215502 59.963984 +# -b +31.449938 60.083673 +31.130768 59.912354 +30.987611 59.940516 +# -b +23.578653 60.006227 +23.444883 59.963984 +23.346316 59.980412 +# -b +23.313460 60.090713 +22.926232 59.858377 +23.069389 59.989800 +23.069389 59.989800 +# -b +19.917590 54.934717 +20.281349 54.998081 +20.666230 55.136545 +20.952544 55.387656 +21.053458 55.669276 +21.041724 55.568362 +20.842243 55.249193 +20.656843 54.976960 +21.140291 54.946451 +21.241205 55.256233 +21.173147 55.380615 +21.130904 55.669276 +21.029990 55.953243 +21.029990 55.922734 +20.919688 56.255985 +20.964278 56.523524 +21.074579 56.856775 +21.360893 57.168904 +21.691797 57.586640 +22.287893 57.727450 +22.630531 57.626537 +23.027146 57.312061 +23.113979 57.354304 +23.313460 57.110233 +23.710075 57.018706 +24.008123 57.030440 +24.228726 57.187678 +24.306171 57.560825 +24.306171 57.879995 +24.416473 58.241407 +24.339027 58.415073 +24.008123 58.293038 +23.656098 58.391605 +23.444883 58.680266 +23.710075 58.788220 +23.423761 58.839850 +23.489473 58.994741 +23.400293 59.114430 +23.522328 59.276362 +23.742931 59.304524 +24.029245 59.389010 +24.249847 59.445334 +24.536161 59.501658 +24.780232 59.586144 +25.120523 59.541554 +25.442040 59.586144 +25.594584 59.630734 +25.770597 59.619000 +25.925488 59.647162 +26.509850 59.574410 +26.951055 59.461762 +27.744285 59.457068 +27.976622 59.663589 +28.143247 59.757463 +28.438948 59.825521 +28.781586 59.825521 +29.002189 59.947557 +# -b +29.255647 60.006227 +29.774297 59.940516 +29.938576 59.924088 +# -b +22.937967 58.640369 +22.299627 58.633329 +21.989845 58.508947 +21.834954 58.398645 +21.945255 58.241407 +21.956989 58.056007 +22.222182 58.213245 +22.386460 58.311812 +22.672774 58.300078 +22.937967 58.415073 +23.158569 58.525374 +22.937967 58.623942 +22.937967 58.640369 +# -b +22.299627 58.978314 +22.651653 59.062800 +22.409929 59.046372 +22.198713 58.978314 +22.055557 58.907909 +22.365339 58.743630 +22.740832 58.875053 +22.806544 59.034638 +22.496762 59.114430 +22.332483 58.987701 +22.299627 58.978314 +# -b +27.457971 59.022903 +27.094212 58.994741 +27.061356 58.715468 +27.326548 58.304772 +27.558885 58.241407 +27.767753 58.640369 +27.612862 59.006476 +27.457971 59.022903 +# -b +11.107571 59.123817 +10.964414 59.163714 +10.656978 59.227078 +10.588920 59.428906 +10.523209 59.764503 +10.556064 59.891232 +10.403520 59.863070 +10.391786 59.691752 +10.335462 59.534514 +10.182918 59.712873 +10.204039 59.557982 +10.347196 59.396050 +10.215773 59.231772 +10.138328 59.051066 +10.004558 59.015863 +# -b +18.626830 60.055511 +18.692542 59.841949 +18.471939 59.630734 +17.922780 59.428906 +17.580142 59.518086 +17.326684 59.518086 +17.073226 59.501658 +16.653142 59.595531 +16.312851 59.529820 +16.566309 59.496964 +17.117815 59.344420 +17.469841 59.292790 +18.328782 59.384316 +18.340517 59.311564 +18.131648 59.299830 +17.922780 59.067493 +17.568408 58.936071 +17.425251 58.959539 +17.117815 58.783526 +16.840889 58.692000 +16.068780 58.675572 +16.125104 58.640369 +16.542841 58.605167 +16.676610 58.478438 +16.289383 58.485478 +16.632021 58.328240 +16.599165 58.119372 +16.587431 57.955094 +16.366828 57.938666 +16.509985 57.732144 +16.488864 57.462258 +16.333972 57.103192 +16.068780 56.596276 +15.606454 56.169152 +15.022092 56.211395 +14.491707 56.047117 +14.118560 55.817127 +14.008259 55.413471 +13.179826 55.387656 +12.762089 55.469795 +12.839535 55.598871 +12.684644 55.873451 +12.398330 56.225476 +12.672910 56.248944 +12.541487 56.413223 +12.816067 56.474241 +12.475776 56.737086 +12.067426 57.133701 +11.858558 57.396547 +11.769378 57.567866 +11.825702 57.851833 +11.682545 57.985602 +11.339907 58.138147 +11.515920 58.293038 +11.494798 58.379871 +11.328173 58.316506 +11.283583 58.391605 +11.131039 58.497212 +11.074715 58.727202 +11.030125 58.983007 +11.107571 59.107390 +# -b +13.808778 58.851585 +13.963669 59.095655 +13.897958 59.339726 +13.567054 59.412478 +13.215029 59.384316 +12.982692 59.266974 +13.081259 58.987701 +12.783211 59.107390 +12.553221 58.943111 +12.508631 58.675572 +12.243439 58.410380 +12.553221 58.462010 +12.982692 58.537109 +13.477874 58.696693 +13.743067 58.816382 +13.787656 58.839850 +# -b +16.244793 56.279453 +16.465395 56.493015 +16.730588 56.983504 +16.918334 57.335529 +16.775178 57.258083 +16.500598 56.852081 +16.268261 56.427304 +16.244793 56.279453 +# -b +18.021347 56.964729 +18.295927 57.164210 +18.572853 57.347263 +18.727744 57.520929 +18.793456 57.767347 +18.880289 57.922238 +18.528263 57.922238 +18.065937 57.579600 +17.997879 57.300327 +18.042468 57.110233 +18.119914 57.056256 +18.021347 56.964729 +# -b +14.977502 55.021550 +14.768633 55.256233 +14.580887 55.110729 +14.911790 55.028590 +14.977502 55.021550 +# -b +9.861401 57.560825 +10.380052 57.720410 +10.326075 57.537357 +10.424642 57.258083 +10.204039 57.002278 +10.182918 56.814532 +10.150062 56.718311 +10.171183 56.669028 +10.072616 56.511790 +10.314340 56.530565 +10.699221 56.511790 +10.809523 56.305268 +10.523209 56.206701 +10.347196 56.241904 +10.215773 55.972018 +10.126594 55.903960 +# -b +9.995171 54.385557 +10.391786 54.397291 +10.776667 54.359742 +10.964414 54.256481 +10.666366 54.028838 +10.832991 53.958433 +11.217872 53.972514 +11.372763 54.042919 +11.802234 54.197810 +12.034571 54.179036 +12.365474 54.455962 +12.464041 54.397291 +12.442920 54.333927 +12.872391 54.397291 +13.158705 54.197810 +13.456753 54.139140 +13.653887 53.998329 +13.832246 53.822317 +14.196006 53.770686 +14.458851 53.756605 +14.217127 53.888028 +14.217127 53.888028 +# -b +13.510730 54.467697 +13.578788 54.345661 +13.367573 54.319846 +13.048403 54.364436 +13.060137 54.545142 +13.367573 54.493512 +13.158705 54.641362 +13.325330 54.615547 +13.534198 54.519327 +13.501342 54.474737 +# -b +14.217127 53.888028 +14.569152 53.951393 +15.022092 54.160261 +15.737876 54.268216 +16.345707 54.507593 +17.007514 54.723502 +17.744420 54.845537 +18.450818 54.838496 +18.716010 54.641362 +18.385106 54.761051 +18.582241 54.437188 +18.781722 54.352702 +19.377818 54.430147 +19.685253 54.563917 +19.840144 54.697686 +19.917590 54.934717 +19.917590 54.934717 +# -b +-0.037549 50.801940 +0.699357 50.858264 +1.074850 50.970912 +1.516055 51.276001 +1.020873 51.315897 +0.699357 51.503644 +0.919959 51.604558 +0.865982 51.728940 +1.185152 51.768836 +1.340043 51.904953 +1.548911 52.001173 +1.814104 52.515130 +1.417488 52.909398 +0.800271 52.916438 +0.445899 52.749813 +0.138463 52.822565 +0.183053 52.928173 +0.403656 53.087757 +0.380187 53.327135 +0.105608 53.524269 +0.004694 53.557124 +# -b +-0.061018 53.655692 +0.061018 53.615795 +0.269886 53.601714 +0.093873 53.836398 +# -b +5.010493 53.214487 +4.989371 53.141735 +4.923660 52.996231 +5.010493 53.214487 +# -b +3.534334 51.351099 +3.841769 51.315897 +4.261853 51.372221 +4.151551 51.412117 +3.942683 51.508337 +4.503577 51.625679 +4.855602 51.754755 +4.470721 51.707818 +4.217263 51.904953 +4.250118 51.968317 +4.348685 52.041069 +4.634999 52.259325 +4.879070 52.862461 +5.001106 52.946947 +5.001106 52.946947 +# -b +4.062372 51.761796 +4.151551 51.796998 +4.339298 51.667922 +4.062372 51.761796 +4.062372 51.761796 +# -b +3.832382 51.693737 +4.008394 51.700778 +4.041250 51.646801 +3.832382 51.693737 +# -b +3.665756 51.536499 +3.698612 51.433239 +3.665756 51.536499 +3.665756 51.536499 +# -b +2.806815 51.095294 +3.224551 51.287735 +3.534334 51.351099 +3.534334 51.351099 +# -b +1.239129 49.942998 +1.736658 50.283289 +1.724924 50.684598 +2.321020 51.010808 +2.717635 51.060092 +2.806815 51.095294 +# -b +10.004558 59.015863 +9.563353 59.006476 +9.223062 58.783526 +8.826447 58.569964 +8.098928 58.182737 +7.657723 58.060701 +7.270495 58.154574 +6.754192 58.131106 +6.686133 58.375177 +6.080650 58.358749 +5.540878 58.875053 +5.728625 58.931377 +5.914025 58.943111 +5.904637 59.051066 +6.167483 59.255240 +6.057181 59.344420 +6.235541 59.541554 +5.738012 59.445334 +5.594855 59.332686 +5.320275 59.316258 +5.231096 59.461762 +5.585468 59.630734 +5.871781 59.691752 +6.334108 59.825521 +6.125240 59.818481 +5.782602 59.902967 +5.949227 59.989800 +# -b +5.794336 60.083673 +5.407108 59.956944 +5.407108 59.956944 +# -b +5.439964 59.741035 +5.451698 59.891232 +5.296807 59.947557 +5.287420 59.797359 +5.397721 59.752769 +# -b +5.263951 59.159020 +5.254564 59.327992 +5.177118 59.266974 +5.177118 59.159020 +5.198240 59.163714 +# -b +8.659822 54.908902 +8.626966 55.230418 +8.418098 55.526119 +8.087194 55.563669 +8.131784 55.880491 +8.021482 56.267719 +8.152905 56.664334 +8.549520 57.114927 +9.321629 57.199413 +9.718244 57.478686 +9.861401 57.560825 +# -b +10.126594 55.903960 +9.905991 55.798352 +9.542232 55.725600 +9.575087 55.563669 +9.530497 55.443980 +9.563353 55.275008 +9.387341 55.167053 +9.521110 55.028590 +9.640799 54.901861 +9.476520 54.927676 +9.464786 54.894820 +# -b +8.659822 54.908902 +8.650434 54.800947 +8.913280 54.577998 +8.716146 54.423107 +8.749001 54.326886 +8.847568 54.164955 +8.835834 54.068735 +9.068171 53.888028 +8.737267 53.848132 +8.528399 53.730790 +8.582376 53.409274 +8.429832 53.533656 +8.152905 53.442130 +7.735169 53.709669 +7.183662 53.566512 +7.061627 53.416314 +7.347941 53.343562 +7.446508 53.198059 +7.082748 53.256730 +# -b +9.464786 54.894820 +9.377953 54.845537 +9.795690 54.793907 +9.884870 54.582691 +9.983437 54.460656 +9.995171 54.385557 +# -b +5.001106 52.946947 +5.221708 52.752160 +5.022227 52.592575 +5.099673 52.343811 +5.561999 52.336770 +5.848313 52.585535 +5.892903 52.733385 +5.573733 52.878889 +5.397721 53.045514 +5.684035 53.329481 +6.235541 53.362337 +6.608688 53.449170 +6.995916 53.324788 +7.082748 53.256730 +7.082748 53.256730 +# -b +-7.082748 62.064402 +-7.293964 62.099604 +-7.406612 62.059708 +-7.082748 62.064402 +-7.082748 62.064402 +# -b +-6.775313 61.961141 +-6.761232 62.033893 +-6.995916 62.219293 +-7.225905 62.223987 +-7.160194 62.125420 +-6.897348 62.038587 +-6.873880 61.949407 +-6.775313 61.961141 +# -b +-6.665012 62.055014 +-6.599300 62.099604 +-6.754192 62.219293 +-6.941938 62.301432 +-6.866840 62.172356 +-6.721336 62.059708 +-6.665012 62.055014 +# -b +-6.456143 62.266230 +-6.564098 62.289698 +-6.629809 62.202865 +-6.474918 62.202865 +-6.456143 62.266230 +# -b +-6.608688 61.756966 +-6.754192 61.883696 +-6.763579 61.810944 +-6.688480 61.752273 +-6.608688 61.756966 +# -b +-6.897348 61.616156 +-6.939591 61.595035 +-6.850412 61.407288 +-6.742457 61.470653 +-6.897348 61.616156 +-6.897348 61.616156 +# -b +-1.239129 60.637526 +-1.283719 60.625792 +-1.471466 60.513144 +-1.349430 60.344172 +-1.504321 60.196321 +-1.239129 60.179893 +-1.274331 60.003881 +# -b +-1.164030 59.982759 +-1.074850 60.147038 +-1.074850 60.273767 +-1.053729 60.377027 +-1.164030 60.452126 +-1.239129 60.592936 +-1.239129 60.637526 +# -b +-19.985648 63.545255 +-19.985648 63.545255 +# -b +-20.072481 66.058715 +-19.696987 65.833419 +-19.420061 65.770054 +-19.434142 66.049328 +-19.110278 66.058715 +-18.739479 66.199525 +-18.650299 66.084530 +-18.331129 65.910865 +-18.119914 65.662100 +-18.110527 65.936680 +-18.274805 66.169016 +-17.800744 66.103305 +-17.392395 66.058715 +-17.059145 66.192485 +-16.650795 66.154935 +-16.453661 66.248809 +-16.566309 66.483492 +-16.233059 66.539816 +-15.782466 66.394313 +-15.660431 66.234728 +-15.364730 66.213606 +-15.054947 66.319214 +-14.646598 66.399006 +-14.965768 66.222994 +-15.097190 66.039941 +-14.702922 66.021166 +-14.768633 65.725465 +-14.327428 65.734852 +-14.041115 65.579961 +-13.839287 65.551799 +-13.862755 65.300687 +-13.552973 65.242017 +-13.764188 64.995599 +-13.886223 64.847748 +-14.336816 64.767956 +-14.458851 64.678776 +-14.228861 64.678776 +-14.834345 64.357260 +-15.130046 64.322057 +-15.364730 64.437052 +-15.735530 64.183594 +-16.575697 63.894933 +-17.007514 63.876159 +-17.237504 63.845650 +-17.720952 63.641475 +-18.495408 63.430260 +-19.035180 63.388017 +-19.640663 63.514746 +-19.983301 63.545255 +-19.983301 63.545255 +# -b +-22.189326 70.050682 +-22.531964 69.975583 +-22.874602 69.952115 +-23.146835 69.874669 +-23.095205 69.815998 +-23.325194 69.844160 +-23.620896 69.759674 +-23.808642 69.672841 +-23.724156 69.593049 +-24.052713 69.607130 +-24.395351 69.553153 +-24.231073 69.475707 +-24.174749 69.407649 +-24.395351 69.402955 +-24.648809 69.372446 +-24.892880 69.252758 +-24.991447 69.259798 +-25.287149 69.205821 +-25.099402 69.154191 +-25.254293 69.114295 +-25.399797 69.043889 +-25.672029 69.027462 +-25.672029 68.961750 +-25.841002 68.865530 +-25.972424 68.795125 +-26.357305 68.743495 +-26.469953 68.694211 +-26.723412 68.698905 +-27.009725 68.651968 +-27.296039 68.595644 +-27.436849 68.511158 +-27.760713 68.527586 +-27.901523 68.522892 +-28.079882 68.478302 +-28.366196 68.490036 +-28.605573 68.421978 +-29.046778 68.377388 +-29.323705 68.316371 +-29.487983 68.248312 +-29.764910 68.321064 +-29.929188 68.400857 +-29.929188 68.400857 +# -b +-19.985648 63.545255 +-20.337673 63.603926 +-20.868058 63.808100 +-21.661288 63.857384 +-22.079025 63.836262 +-22.689202 63.817488 +-22.740832 64.068599 +-22.079025 64.108495 +-21.816179 64.345526 +-21.947602 64.432358 +-21.994539 64.568475 +-22.247997 64.577862 +-22.370032 64.683470 +-22.576554 64.833667 +-22.909805 64.824280 +-23.482432 64.814893 +-23.956493 64.786731 +-23.679566 64.894685 +-22.994291 64.981518 +-22.520230 65.066004 +-21.872503 65.075391 +-21.994539 65.108247 +-22.534311 65.162224 +-22.402888 65.291300 +-22.027395 65.396908 +-22.046169 65.521290 +-22.290240 65.516596 +-22.445131 65.594042 +-22.754913 65.612817 +-23.238361 65.502515 +-23.524675 65.472006 +-23.923637 65.474353 +-24.275663 65.502515 +-24.397698 65.629244 +-23.768746 65.575267 +-23.890782 65.676181 +-24.177095 65.824032 +-23.580999 65.643325 +-23.304073 65.739546 +-23.801602 65.861581 +-23.735890 65.964842 +-23.857926 66.039941 +-23.688954 66.107999 +-23.491820 66.187791 +-23.083470 65.981270 +-22.698589 65.950761 +-22.477987 65.847500 +-22.477987 66.098611 +-22.942660 66.213606 +-22.567167 66.239422 +-22.665734 66.323908 +-23.008372 66.314520 +-23.097551 66.403700 +-22.952048 66.455330 +-22.675121 66.443596 +-22.290240 66.293399 +-21.806792 66.133814 +-21.529865 66.070449 +-21.487622 65.936680 +-21.431298 65.770054 +-21.759855 65.753627 +-21.473541 65.544758 +-21.417217 65.457925 +-21.234164 65.232629 +-20.868058 65.415682 +-20.638068 65.666794 +-20.384610 65.589348 +-20.328286 65.910865 +-20.281349 66.124427 +-20.074828 66.058715 +# -b +-29.931535 68.400857 +-30.034796 68.227191 +-30.133363 68.161479 +-30.429064 68.231885 +-30.781090 68.182601 +-30.715378 68.067606 +-31.067403 68.182601 +-31.180052 68.121583 +-31.170664 68.072300 +-31.508608 68.091074 +-31.677581 68.088728 +-31.907570 68.210763 +-31.696355 68.248312 +-32.085930 68.332798 +-32.184497 68.400857 +-32.372244 68.400857 +-32.414487 68.558095 +-32.545910 68.546360 +-32.780593 68.527586 +-32.503667 68.360960 +-32.480198 68.201376 +-32.038993 68.062912 +-32.226740 67.931490 +-32.437955 67.861085 +-32.644477 67.818842 +-33.076294 67.678031 +-33.231185 67.560690 +-33.461175 67.426920 +-33.540968 67.333047 +-33.583211 67.135913 +-33.836669 67.009183 +-34.033803 66.901229 +-34.080740 66.849599 +-34.137064 66.767459 +-34.287261 66.713482 +-34.521945 66.650118 +-34.653368 66.469411 +-34.864583 66.359110 +-35.103960 66.443596 +-35.249464 66.262890 +-35.845560 66.424821 +-35.765767 66.272277 +-35.756380 66.138508 +-35.976983 66.054022 +-36.174117 65.964842 +-36.408800 65.936680 +-36.563691 65.976576 +-36.671646 65.828725 +-37.056527 66.025860 +-37.244273 65.995351 +-37.244273 65.878009 +-37.478957 65.887396 +-37.765271 65.936680 +-37.685478 66.058715 +-37.478957 66.204219 +-37.408552 66.307480 +-37.741803 66.363804 +-38.084440 66.363804 +-37.929549 66.239422 +-38.051585 66.124427 +-38.060972 65.946067 +-38.258106 65.910865 +-38.492790 65.882703 +-38.192395 65.798217 +-38.281575 65.701996 +-38.459934 65.652713 +-38.699311 65.671487 +-38.811959 65.589348 +-39.154597 65.624551 +-39.384587 65.612817 +-39.614577 65.638632 +-39.882116 65.521290 +-39.882116 65.521290 +# -b +-40.088638 65.457925 +-39.947828 65.333543 +-39.900891 65.237323 +# -b +-39.879769 65.521290 +-40.222407 65.502515 +-40.086291 65.457925 +# -b +-39.900891 65.237323 +-40.088638 65.084779 +-40.421888 65.042536 +-40.684734 65.028455 +-41.125939 65.103553 +-41.107164 64.939275 +-40.853706 64.706938 +-40.496987 64.418277 +-40.511068 64.385422 +-41.107164 64.361953 +-41.445108 64.197675 +-40.741058 64.164819 +-40.773914 64.016969 +-40.562698 63.758817 +-41.402865 63.812794 +-40.806769 63.695452 +-40.853706 63.549948 +-40.952273 63.425566 +-41.172876 63.406792 +-41.247974 63.317612 +-41.590612 63.326999 +-41.548369 63.214351 +-41.379397 63.120478 +-41.745503 63.075888 +-42.106916 63.153333 +-41.665711 63.000789 +-41.482658 62.974974 +-41.637549 62.913956 +-41.801827 62.834164 +-41.956718 62.820083 +-42.210177 62.813042 +-42.463635 62.798961 +-42.618526 62.693354 +-42.632607 62.641723 +-42.379149 62.489179 +-42.266501 62.310820 +-42.125691 62.012771 +-42.102222 61.803903 +-42.355680 61.606769 +-42.379149 61.480040 +-42.672503 61.285253 +-42.639647 61.189032 +-42.695971 61.045875 +-42.761683 60.954349 +-42.827394 60.832313 +-42.860250 60.703237 +-42.928308 60.550693 +-43.148911 60.517837 +-43.644093 60.550693 +-43.301455 60.435698 +-43.104321 60.273767 +-43.071465 60.163465 +-43.181766 60.147038 +-43.599503 60.142344 +-44.052442 60.250298 +-44.228455 60.163465 +-44.801083 60.125916 +-45.009951 60.114182 +-45.131986 60.191627 +-45.033419 60.332437 +-44.911384 60.452126 +-44.890262 60.567121 +-45.275143 60.480288 +-45.188310 60.670382 +-45.441769 60.534265 +-45.617781 60.583549 +-45.695227 60.679769 +-45.716348 60.717318 +-45.340855 60.937921 +-45.716348 60.794764 +-46.091842 60.740787 +-45.958072 60.832313 +-45.662371 60.949655 +-45.993275 60.966083 +-45.981541 61.062303 +-46.256120 61.055263 +-46.619880 60.944961 +-47.126796 60.954349 +-47.380254 60.975470 +-47.448313 60.944961 +-47.535146 60.841701 +-47.812072 60.841701 +-47.976351 60.853435 +-47.877783 60.928534 +-47.591470 61.029448 +-47.701771 61.071691 +-48.020940 61.130361 +-48.119507 61.214848 +-48.396434 61.210154 +-48.572447 61.343923 +-48.694482 61.400247 +-48.901004 61.374432 +-48.295520 61.505855 +-48.483267 61.580954 +-49.023039 61.480040 +-48.980796 61.616156 +-49.013652 61.742885 +-49.332821 61.918898 +-48.933859 62.111339 +-49.342209 62.022159 +-49.576892 62.003384 +-49.506487 62.116032 +-49.619135 62.202865 +-49.609748 62.249802 +-49.750558 62.428161 +-49.896062 62.475098 +# -b +-43.148911 60.064898 +-43.202888 60.048470 +-43.566647 60.097754 +-43.951528 60.081326 +-43.918673 60.020308 +# -b +-43.512670 59.971025 +-43.378901 60.048470 +-43.148911 60.064898 +# -b +-50.686945 63.000789 +-50.808981 63.080581 +-51.118763 63.446688 +-51.452013 63.627394 +-51.414464 63.923095 +-51.470788 64.164819 +-50.921629 64.357260 +-50.180029 64.469908 +-50.743269 64.617758 +-50.025138 64.636533 +-50.686945 64.814893 +-51.217330 64.678776 +-51.935461 64.275121 +-52.109127 64.422971 +-52.090353 64.650614 +-51.935461 64.843055 +-52.109127 64.906419 +-52.278099 65.089472 +-52.221775 65.300687 +-52.376666 65.333543 +-52.400135 65.497822 +-52.686449 65.622204 +-53.113573 65.657406 +-52.925826 65.866275 +-53.137041 65.896784 +-53.226221 66.061062 +-52.916438 66.178404 +-53.489066 66.178404 +-53.554778 66.342682 +-53.137041 66.504614 +-53.179284 66.713482 +-53.015006 66.896535 +-53.554778 66.978675 +-53.873947 67.187543 +-53.676813 67.354168 +-53.456211 67.509059 +-53.503147 67.673338 +-53.390499 67.910368 +-53.193365 68.025363 +-53.071330 68.112196 +-53.249689 68.154439 +-52.606656 68.173214 +-52.179532 68.091074 +-51.559968 68.051178 +-50.940403 68.095768 +-51.076520 68.194335 +-51.231411 68.337492 +-51.193862 68.433712 +-51.372221 68.325758 +-52.353198 68.215457 +-52.808484 68.227191 +-52.892970 68.382082 +-52.123208 68.586257 +-51.161006 68.579216 +-51.193862 68.743495 +-51.175087 68.917160 +-51.175087 69.013381 +-50.766738 69.135416 +-50.569603 69.130722 +-50.710413 69.217555 +-50.963872 69.449892 +-50.832449 69.618864 +-50.334920 69.808958 +-50.433487 69.907525 +# -b +-50.388897 70.006092 +-50.961525 69.989664 +# -b +-53.191018 70.177411 +-52.153717 69.794877 +-51.909646 69.607130 +-52.562066 69.384181 +-53.608755 69.283267 +-54.148527 69.384181 +-53.674466 69.431117 +-53.618142 69.463973 +-53.871600 69.595396 +-54.833803 69.595396 +-54.359742 69.668148 +-54.800947 69.884056 +-54.524021 69.970889 +-54.524021 69.970889 +# -b +-49.928917 62.475098 +-50.168295 62.653457 +-50.116664 62.789574 +-50.257474 62.723862 +-50.379510 62.864673 +-50.581338 62.996095 +-50.684598 63.000789 +# -b +-68.806859 70.031907 +-68.708292 69.930993 +-68.708292 69.930993 +# -b +-67.450388 70.031907 +-67.239173 69.710391 +-68.032404 69.672841 +-68.651968 69.637639 +-68.464221 69.522644 +-68.102809 69.492135 +-67.042039 69.421730 +-66.488186 69.201127 +-67.149994 69.137763 +-68.046485 69.271532 +-68.267087 69.196434 +-68.520545 69.114295 +-67.746090 68.980525 +-68.154439 68.877264 +-67.858738 68.722373 +-68.023016 68.607378 +-67.999548 68.506464 +-67.164075 68.438406 +-66.755725 68.292902 +-66.535123 68.173214 +-66.225341 68.055872 +-65.948414 67.882206 +-64.967437 68.030057 +-65.112941 67.818842 +-64.624799 67.807107 +-64.216450 67.645176 +-63.920748 67.328353 +-64.028703 67.250907 +-63.592191 67.208664 +-63.028951 67.264988 +-63.249554 66.964594 +-62.892835 66.962247 +-62.179397 66.964594 +-61.705336 66.809702 +-61.484734 66.518695 +-61.780435 66.382578 +-61.935326 66.234728 +-62.301432 66.262890 +-62.606521 66.070449 +-62.254495 65.971882 +-62.399999 65.774748 +-62.719169 65.570574 +-63.423219 65.744239 +-63.282409 65.429763 +-63.446688 65.171612 +-63.578110 64.899379 +-63.887893 65.122328 +-64.418277 65.185693 +-64.606024 65.406295 +-65.066004 65.507209 +-65.342930 65.685568 +-65.572920 65.941373 +-66.169016 66.138508 +-66.976328 66.319214 +-67.117138 66.525735 +-67.196930 66.434209 +-67.337740 66.298092 +-67.915062 66.452984 +-68.154439 66.382578 +-67.548956 66.173710 +-67.361209 65.936680 +-67.769558 65.896784 +-67.933836 65.612817 +-67.272029 65.608123 +-67.164075 65.396908 +-67.239173 65.260791 +-66.943472 65.103553 +-66.699401 64.800812 +-66.488186 64.953356 +-66.337989 64.805505 +-65.995351 64.833667 +-65.643325 64.767956 +-65.352318 64.711632 +-65.244363 64.554394 +-65.033148 64.326751 +-65.112941 64.096761 +-64.591943 63.927789 +-64.437052 63.704840 +-64.573169 63.437300 +-64.746834 63.392711 +-65.000293 63.263635 +-64.793771 63.014870 +-64.606024 63.024257 +# -b +-67.661604 63.010176 +-67.933836 63.193230 +-68.135664 63.228432 +-68.520545 63.474850 +-68.661355 63.763510 +-68.243619 63.592191 +-67.811801 63.549948 +-67.239173 63.282409 +-66.722870 63.040685 +-66.722870 63.040685 +# -b +-70.125780 60.874556 +-69.752634 60.959042 +-69.541419 60.970777 +-69.454586 60.808845 +-69.696310 60.616405 +-69.708044 60.398149 +-69.586008 60.250298 +-69.532031 60.076632 +-69.762021 60.003881 +-69.982624 60.003881 +# -b +-65.331196 59.987453 +-64.955703 60.175200 +-64.911113 60.229177 +-64.690510 60.316010 +-64.547353 60.196321 +-64.371341 60.036736 +-64.371341 60.036736 +# -b +-68.220150 60.484982 +-68.274128 60.283154 +-67.832923 60.468554 +-68.163826 60.555387 +-68.220150 60.484982 +# -b +-65.077738 61.705336 +-64.955703 61.684215 +-64.735100 61.590341 +-64.904072 61.353311 +-65.232629 61.470653 +-65.509556 61.641971 +-65.077738 61.705336 +-65.077738 61.705336 +# -b +-64.606024 63.024257 +-64.446439 62.960893 +-64.657655 62.859979 +-65.009680 62.890488 +-64.845401 62.688660 +-64.756222 62.566625 +-65.089472 62.658151 +-65.108247 62.798961 +-65.305381 62.843551 +-65.460272 62.979668 +-65.727811 62.935078 +-65.915558 62.899875 +-66.722870 63.040685 +-66.722870 63.040685 +# -b +-67.534875 63.000789 +-67.337740 62.843551 +-66.873067 62.693354 +-66.455330 62.505607 +-66.079837 62.249802 +-66.178404 62.038587 +-66.366151 61.876655 +-66.840211 62.120726 +-67.412839 62.059708 +-67.830576 62.207559 +-68.360960 62.249802 +-68.759922 62.378878 +-69.046236 62.414080 +-69.309082 62.646417 +-69.463973 62.768452 +-69.726819 62.808349 +-69.914565 62.890488 +-69.947421 62.930384 +# -b +-76.384790 68.292902 +-76.164187 68.243619 +-75.680739 68.206069 +-75.173823 68.095768 +-75.108111 67.652216 +-75.732370 67.274376 +-76.638248 67.206318 +-77.234344 67.417533 +-77.309443 67.835269 +-76.948030 68.133317 +-76.384790 68.292902 +-76.384790 68.292902 +# -b +-74.807717 67.992507 +-74.366512 68.145052 +-73.925307 67.985467 +-73.761028 67.727315 +-74.765474 67.872819 +-74.807717 67.992507 +# -b +-78.579081 69.208168 +-78.687035 69.107254 +-79.039060 68.905426 +-79.447410 68.954710 +-79.039060 69.114295 +-78.654179 69.231636 +-78.358478 69.241024 +-78.442964 69.360712 +-78.710503 69.325510 +-78.579081 69.208168 +-78.579081 69.208168 +# -b +-80.066974 69.722125 +-79.724336 69.783143 +-79.480265 69.637639 +-79.888615 69.576621 +# -b +-78.501635 63.397404 +-78.435924 63.446688 +-77.919620 63.420873 +-77.567595 63.214351 +-78.116754 63.200270 +-78.501635 63.397404 +# -b +-77.454947 63.695452 +-76.816607 63.568723 +-76.703959 63.406792 +-77.342299 63.554642 +-77.454947 63.695452 +# -b +-71.278077 63.000789 +-71.498679 63.125171 +-71.874173 63.331693 +-71.874173 63.437300 +-71.555003 63.613313 +-71.939884 63.845650 +-72.207423 63.700146 +-72.395170 63.857384 +-72.700259 63.894933 +-72.977185 63.958298 +-73.033509 64.127270 +-73.286967 64.326751 +-73.484102 64.488683 +-73.662461 64.627146 +-73.972243 64.683470 +-74.310188 64.631839 +-74.634051 64.697551 +-74.765474 64.819586 +-74.718537 64.645920 +-74.718537 64.493376 +-74.962608 64.441746 +-75.380344 64.526232 +-75.732370 64.596637 +-75.901342 64.394809 +-76.295610 64.289202 +-76.760283 64.207062 +-77.379848 64.279814 +-77.994719 64.488683 +-78.149610 64.904072 +-77.431478 65.166918 +-77.431478 65.434457 +-76.868238 65.366399 +-76.009296 65.319462 +-75.394425 65.246710 +-75.061175 65.382827 +-74.455691 65.453232 +-73.991018 65.474353 +-73.638993 65.629244 +-74.202233 65.910865 +-74.333656 66.222994 +-73.648380 66.509308 +-73.240031 66.678280 +-73.019428 66.753378 +-72.855150 67.042039 +-72.371702 67.264988 +-72.578223 67.539568 +-72.888005 67.856391 +-73.197788 68.222497 +-73.704704 68.276474 +-73.948775 68.551054 +-74.300800 68.642581 +-74.530790 68.614419 +-74.831185 68.903079 +-74.343043 68.996953 +-75.380344 68.893692 +-76.309691 68.694211 +-76.736815 69.032155 +-75.732370 69.114295 +-76.506825 69.475707 +-77.159245 69.625905 +-76.990273 69.808958 +-77.464334 69.785489 +-77.708405 69.942727 +-77.708405 69.942727 +# -b +-78.886516 70.111699 +-79.327721 69.869975 +-79.923817 69.900484 +-79.923817 69.900484 +# -b +-77.745954 59.982759 +-77.534739 60.076632 +-77.645040 60.245605 +-77.811666 60.409883 +-77.832787 60.604670 +-77.501883 60.717318 +-77.790544 60.771296 +-78.196546 60.825273 +-77.921967 61.231275 +-77.795238 61.407288 +-77.724833 61.559832 +-77.640347 61.738192 +-77.818706 61.695949 +-77.987678 61.897777 +-78.039309 62.214599 +-77.929007 62.310820 +-77.823400 62.479792 +-77.680243 62.519688 +-77.436172 62.526728 +-77.217916 62.489179 +-77.034863 62.423468 +-76.851810 62.348369 +-76.748549 62.240414 +-76.560802 62.289698 +-76.471623 62.172356 +-76.295610 62.177050 +-76.159494 62.310820 +-75.887261 62.423468 +-76.049192 62.348369 +-75.772266 62.449283 +-75.464830 62.219293 +-75.244228 62.158275 +-75.237187 61.986956 +-75.286471 61.841452 +-75.192598 61.949407 +-75.056481 61.857880 +-74.967301 61.663093 +-74.939139 61.573913 +-74.763127 61.641971 +-74.795982 61.505855 +-74.852306 61.369739 +-74.551912 61.243010 +-74.432223 61.172604 +-74.012139 61.071691 +-73.803271 61.062303 +-73.516957 61.020060 +-73.195441 61.013020 +-73.085140 60.874556 +-73.085140 60.874556 +# -b +-69.982624 60.003881 +-70.304140 60.025002 +-70.975335 60.097754 +-71.163082 60.048470 +-70.909623 60.032043 +# -b +-80.083402 61.670134 +-79.764232 61.649012 +-79.585873 61.914204 +-79.388739 62.280311 +-79.862799 62.362450 +# -b +-69.949768 62.930384 +-70.226694 62.789574 +-70.405054 62.813042 +-70.658512 62.899875 +-71.278077 63.000789 +-71.278077 63.000789 +# -b +-71.031659 62.784880 +-70.674940 62.742637 +-70.402707 62.646417 +-70.829831 62.611214 +-71.031659 62.784880 +-71.031659 62.784880 +# -b +-74.052036 62.693354 +-74.009793 62.676926 +-74.418142 62.637030 +-74.671600 62.728556 +-74.150603 62.733250 +-74.052036 62.693354 +# -b +-90.015208 68.635540 +-89.850930 68.694211 +-89.860317 69.036849 +-89.287689 69.283267 +-88.959132 69.149497 +-88.231614 68.870224 +-88.029786 68.541667 +-88.043867 68.248312 +-88.264469 68.410244 +-88.386505 68.133317 +-88.250388 67.811801 +-87.888976 67.539568 +-87.480626 67.295497 +-87.147376 67.323659 +-86.851674 67.408145 +-86.631072 67.405799 +-86.541892 67.741396 +-86.157011 67.971386 +-85.945796 68.194335 +-85.936409 68.292902 +-85.772130 68.602684 +-85.471735 68.708292 +-85.265214 68.759922 +-84.734829 68.762269 +-85.063386 68.811553 +-85.119710 68.928895 +-84.889720 68.996953 +-84.856865 69.043889 +-85.241746 69.126029 +-85.452961 69.348978 +-85.485816 69.485094 +-85.485816 69.668148 +-85.349700 69.801917 +-84.777072 69.827732 +-84.091796 69.754981 +-83.584880 69.654067 +-83.012252 69.644679 +-82.585128 69.642332 +-82.552272 69.480401 +-82.383300 69.353672 +-82.275346 69.208168 +-81.580683 69.177659 +-81.449260 69.050930 +-81.843528 68.926548 +-81.566602 68.830327 +-81.294369 68.630847 +-81.735574 68.515852 +-81.899852 68.389122 +-82.209635 68.511158 +-82.561660 68.473609 +-82.317589 68.316371 +-82.284733 68.260047 +-82.120455 68.189642 +-82.120455 67.987814 +-81.637007 67.635788 +-81.294369 67.429267 +-81.392936 67.286110 +-81.425792 67.103057 +-81.801285 67.016224 +-82.111067 66.819090 +-82.463093 66.671239 +-82.970009 66.556244 +-83.232855 66.387272 +-83.500394 66.478799 +-83.885275 66.619609 +-84.115265 66.666546 +-84.129346 66.579713 +-83.753852 66.222994 +-83.993229 66.232381 +-84.392191 66.368497 +-84.514227 66.253503 +-84.800541 66.262890 +-85.161953 66.272277 +-85.349700 66.579713 +-85.790905 66.499920 +-85.992733 66.504614 +-86.499649 66.575019 +-86.687396 66.504614 +-86.687396 66.373191 +-86.100687 66.279318 +-86.044363 66.075143 +-86.100687 66.009432 +-86.368226 65.856887 +-86.673315 65.666794 +-86.926773 65.570574 +-87.128601 65.392214 +-87.757553 65.371093 +-88.151821 65.483741 +-88.705674 65.685568 +-88.968520 65.753627 +-89.334626 65.847500 +-89.785218 65.873315 +-89.785218 65.873315 +# -b +-90.179487 65.819338 +-89.353401 65.472006 +-88.846484 65.342930 +-88.095497 65.251404 +-87.480626 65.272525 +-87.006566 65.209161 +-87.048809 65.051923 +-87.316348 64.744488 +-87.579193 64.563781 +-87.823264 64.516845 +-87.907750 64.345526 +-88.151821 64.188288 +-88.494459 64.049824 +-89.043618 64.049824 +-89.433193 64.082680 +-89.498904 64.035743 +-89.686651 64.108495 +-89.850930 64.101455 +-89.860317 64.031050 +-89.818074 63.944217 +-89.907254 63.944217 +# -b +-90.069185 63.890240 +-89.970618 63.831569 +# -b +-86.652193 68.260047 +-86.548933 68.107502 +-86.595869 67.760171 +-86.980750 67.964345 +-86.957282 68.227191 +-86.661581 68.260047 +-86.652193 68.260047 +# -b +-85.814373 65.788829 +-85.668870 65.882703 +-85.307457 65.819338 +-85.152566 65.535371 +-84.889720 65.260791 +-84.514227 65.453232 +-84.148120 65.305381 +-83.805482 65.148143 +-83.453457 65.136409 +-83.190612 64.925194 +-82.571047 64.749181 +-82.021888 64.664695 +-81.834141 64.498070 +-81.744961 64.251652 +-81.599457 64.045131 +-81.228657 64.035743 +-80.829696 64.108495 +-80.609093 63.948910 +-80.566850 63.871465 +-80.210131 63.777591 +-80.674804 63.627394 +-80.984587 63.500665 +-81.402323 63.528827 +-81.524359 63.603926 +-81.890465 63.681371 +-82.219022 63.686065 +-82.397381 63.845650 +-82.636759 63.972379 +-82.955928 64.000541 +-83.134288 64.000541 +-82.970009 64.178900 +-83.542637 64.101455 +-83.650591 63.939523 +-83.650591 63.768204 +-83.852419 63.709533 +-84.026085 63.636781 +-84.415660 63.505359 +-84.547082 63.420873 +-84.941351 63.233126 +-85.330925 63.183842 +-85.659482 63.474850 +-85.706419 63.812794 +-85.814373 63.758817 +-86.091300 63.667290 +-86.377614 63.671984 +-86.565361 63.681371 +-86.926773 63.573417 +-87.227168 63.690759 +-87.015953 63.904321 +-86.476181 64.077986 +-86.368226 64.312670 +-86.419857 64.563781 +-86.279047 64.819586 +-86.189867 65.051923 +-86.166399 65.448538 +-85.912940 65.744239 +-85.814373 65.788829 +# -b +-83.894662 65.964842 +-83.739771 65.922599 +-83.552024 65.711384 +-83.552024 65.624551 +-84.091796 65.798217 +-84.467290 66.070449 +-84.148120 66.079837 +-83.894662 65.964842 +# -b +-80.254721 69.785489 +-80.066974 69.722125 +-80.066974 69.722125 +# -b +-79.890961 69.576621 +-80.069321 69.463973 +-80.477670 69.703350 +-80.257068 69.785489 +-80.257068 69.785489 +# -b +-79.923817 69.900484 +-80.036465 69.970889 +-80.167888 69.968543 +# -b +-80.275842 70.001398 +-80.519913 69.968543 +# -b +-81.777817 70.027213 +-80.961118 69.740900 +-81.646394 69.938034 +-82.153311 69.839467 +-82.219022 69.806611 +-82.857361 69.919259 +-83.598961 69.921606 +-83.918131 69.930993 +-84.856865 69.980277 +# -b +-85.626627 70.027213 +-85.363781 69.970889 +-85.584383 69.970889 +# -b +-82.540538 62.930384 +-83.103779 62.813042 +-83.563758 62.475098 +-83.850072 62.116032 +-83.446417 62.184090 +-82.948888 62.296738 +-82.737672 62.505607 +-82.287080 62.637030 +-82.043009 62.843551 +-82.343404 62.960893 +-82.540538 62.930384 +# -b +-80.050546 62.357756 +-80.139726 62.331941 +-80.294617 62.177050 +-80.360328 61.785128 +-80.083402 61.670134 +# -b +-79.862799 62.362450 +-80.050546 62.357756 +# -b +-96.936025 69.534378 +-97.100303 69.644679 +-97.306825 69.729165 +-97.607220 69.851201 +-97.959245 69.813651 +-98.311270 69.600089 +-98.301883 69.557846 +-98.531873 69.487441 +-98.456774 69.302041 +-98.766556 69.184700 +-99.174906 69.130722 +-99.512850 69.003993 +-99.339184 68.835021 +-99.052870 68.898386 +-98.700845 68.806859 +-98.409837 68.778697 +-98.203316 68.715333 +-97.818435 68.675436 +-97.330293 68.555748 +-97.067448 68.574522 +-96.734197 68.499424 +-96.292992 68.482996 +-95.973823 68.626153 +-95.565473 68.731760 +-95.255691 68.762269 +-95.499762 68.795125 +-95.818931 68.973484 +-96.030147 69.182353 +-96.339929 69.309082 +-96.748278 69.461626 +-96.936025 69.534378 +# -b +-100.026807 67.861085 +-99.355612 67.785986 +-99.078685 67.785986 +-98.684417 67.785986 +-98.576463 67.870472 +-98.768903 68.039444 +-98.520139 68.069953 +-98.323005 67.870472 +-97.933430 67.701500 +-97.346721 67.638135 +-97.205911 67.954958 +-97.454676 67.903328 +-97.933430 67.985467 +-97.961592 67.839963 +-98.210356 67.997201 +-98.323005 68.112196 +-98.520139 68.267087 +-98.712579 68.412591 +-98.379329 68.382082 +-98.182194 68.412591 +-97.736296 68.391469 +-98.041384 68.546360 +-97.651810 68.494730 +-97.539162 68.515852 +-97.036939 68.382082 +-97.008777 68.309330 +-96.562878 68.330452 +-96.675526 68.133317 +-96.562878 68.081687 +-96.060655 68.267087 +-96.032493 68.112196 +-96.201466 67.776599 +-96.422068 67.584158 +-96.060655 67.358862 +-95.779035 67.412839 +-95.530271 67.358862 +-95.361299 67.241520 +-95.361299 67.478550 +-95.666387 67.743743 +-95.530271 67.997201 +-95.530271 68.100462 +-95.333137 68.069953 +-94.943562 68.100462 +-94.826220 68.051178 +-94.539906 68.194335 +-94.295835 68.248312 +-93.953198 68.482996 +-93.774838 68.630847 +-93.765451 68.865530 +-94.051765 69.013381 +-94.131557 68.846755 +-93.995441 68.863183 +-94.507051 68.715333 +-94.680716 68.799819 +-94.657248 68.940629 +-94.370934 69.013381 +-94.403790 69.126029 +-94.230124 69.341938 +-93.821775 69.414689 +-93.896874 69.172965 +-93.676271 69.426424 +-94.051765 69.463973 +-94.507051 69.492135 +-94.769896 69.588355 +-95.018661 69.630598 +-95.206408 69.672841 +-95.337830 69.759674 +-95.821278 69.745593 +-96.074737 69.895791 +-96.393906 69.952115 +# -b +-92.155522 70.050682 +-92.089810 69.912218 +-92.385512 69.834773 +-92.596727 69.778449 +-92.728150 69.668148 +-92.277557 69.625905 +-91.845740 69.510910 +-91.517183 69.611824 +-91.460859 69.522644 +-91.230869 69.473360 +-90.986798 69.452239 +-90.874150 69.440505 +-90.996185 69.297348 +-91.418616 69.348978 +-90.808438 69.107254 +-90.634773 68.914814 +-90.545593 68.583910 +-90.414170 68.365654 +-90.217036 68.349226 +-90.015208 68.572176 +-90.015208 68.635540 +# -b +-89.782872 65.873315 +-90.078573 65.910865 +-90.177140 65.819338 +# -b +-89.904907 63.944217 +-90.069185 63.890240 +-90.069185 63.890240 +# -b +-89.970618 63.831569 +-90.191221 63.618007 +-90.454066 63.549948 +-90.740380 63.559336 +-91.040775 63.641475 +-91.402188 63.754123 +-91.669727 63.768204 +-91.932573 63.798713 +-92.120319 63.763510 +-92.570912 63.840956 +-92.969874 63.948910 +-93.519033 64.026356 +-93.575357 63.885546 +-93.312512 63.904321 +-92.857226 63.852690 +-92.584993 63.716574 +-92.120319 63.730655 +-92.232967 63.641475 +-92.120319 63.641475 +-91.622790 63.681371 +-91.359945 63.533521 +-90.909352 63.486584 +-90.829560 63.366895 +-90.674669 63.219045 +-90.618345 63.089969 +-90.632426 63.019564 +-90.763849 62.895181 +-91.186279 62.890488 +-91.636871 62.794268 +-92.232967 62.789574 +-92.340922 62.632336 +-91.998284 62.587746 +-92.608461 62.571318 +-92.683560 62.310820 +-92.707028 62.132460 +-93.002729 62.137154 +-93.223332 61.956447 +-93.378223 61.918898 +-93.378223 61.789822 +-93.706780 61.569220 +-94.260633 61.416675 +-94.401443 61.301680 +-94.248899 61.066997 +-94.523478 60.853435 +-94.511744 60.625792 +-94.755815 60.480288 +-94.722959 60.240911 +-94.732347 60.093060 +# -b +-100.862280 70.013132 +-100.904523 69.776102 +-101.270629 69.691616 +-101.434908 69.858241 +-101.556943 69.808958 +-101.646123 69.661107 +-101.866726 69.703350 +-102.040391 69.930993 +-102.218751 69.895791 +-102.406498 69.806611 +-102.627100 69.715084 +-102.528533 69.557846 +-102.772604 69.576621 +-103.091774 69.583662 +-103.058918 69.463973 +-103.058918 69.353672 +-102.969738 69.344284 +-102.561389 69.510910 +-102.143652 69.515603 +-101.932437 69.461626 +-102.129571 69.332550 +-102.242219 69.271532 +-102.021617 69.273879 +-101.589799 69.219902 +-101.688366 69.090826 +-101.866726 69.013381 +-102.162427 68.961750 +-102.650569 68.877264 +-102.889946 68.823287 +-103.256052 68.802165 +-103.673789 68.813900 +-104.058670 68.905426 +-104.490487 68.950016 +-105.030259 68.921854 +-105.110052 69.050930 +-105.142907 69.126029 +-105.537176 69.130722 +-105.823490 69.201127 +-106.198983 69.201127 +-106.321019 69.320816 +-106.640188 69.517950 +-107.048538 69.377140 +-106.959358 69.212862 +-107.414644 69.003993 +-107.907479 68.966444 +-108.583368 68.966444 +-108.738259 68.818593 +-109.564345 68.647274 +-109.916370 68.626153 +# -b +-110.029018 67.997201 +-109.977388 67.976080 +# -b +-110.029018 67.924449 +-109.808416 67.870472 +-109.808416 67.785986 +-109.498633 67.785986 +-108.996411 67.785986 +-108.996411 67.680378 +-108.996411 67.499672 +-108.855601 67.455082 +-108.663160 67.659257 +-108.634998 67.520793 +-108.409702 67.478550 +-108.020127 67.295497 +-108.048289 67.100710 +-108.437864 67.100710 +-107.991965 66.814396 +-107.738507 66.936432 +-107.264446 66.957553 +-107.292608 67.142953 +-107.574229 67.250907 +-107.710345 67.466816 +-107.794831 67.668644 +-107.991965 67.903328 +-107.710345 67.964345 +-107.738507 68.091074 +-107.236284 68.173214 +-106.846710 68.236578 +-106.508765 68.360960 +-106.260001 68.412591 +-105.950219 68.555748 +-105.922057 68.687171 +-106.372649 68.656662 +-106.677738 68.525239 +-106.677738 68.464221 +-106.734062 68.309330 +-106.846710 68.370348 +-107.067312 68.412591 +-107.264446 68.318717 +-107.574229 68.370348 +-107.879317 68.370348 +-107.794831 68.267087 +-107.907479 68.206069 +-108.020127 68.206069 +-108.353378 68.227191 +-108.634998 68.257700 +-108.883763 68.309330 +-108.663160 68.525239 +-108.104613 68.668396 +-107.597697 68.720026 +-106.982826 68.860836 +-106.424279 68.931241 +-106.034705 68.921854 +-105.645130 68.769310 +-105.701454 68.720026 +-105.391672 68.565135 +-105.673292 68.504117 +-105.391672 68.412591 +-105.086583 68.288209 +-104.748639 68.257700 +-104.748639 68.121583 +-104.190092 68.039444 +-103.856842 68.048831 +-103.687870 68.091074 +-103.326457 68.154439 +-102.904027 67.903328 +-102.345480 67.701500 +-102.068553 67.764864 +-101.871419 67.743743 +-101.369197 67.755477 +-100.838812 67.743743 +-100.195779 67.870472 +-100.026807 67.861085 +# -b +-110.024325 62.890488 +-109.550264 62.838857 +-109.221707 62.789574 +-109.141915 62.658151 +-109.451697 62.545503 +-109.606588 62.658151 +-109.916370 62.728556 +# -b +-110.146360 62.552544 +-109.883514 62.461017 +-109.883514 62.461017 +# -b +-120.017148 69.356019 +-119.599412 69.306735 +-119.026784 69.252758 +-118.618435 69.165925 +-118.120906 69.067358 +-117.660926 68.957057 +-117.182172 68.921854 +-117.017893 68.931241 +-117.017893 68.931241 +# -b +-119.963171 66.990409 +-119.963171 66.990409 +# -b +-120.061738 65.117634 +-119.859911 65.281913 +-119.456255 65.295994 +-119.873992 65.434457 +-119.827055 65.570574 +-119.695632 65.690262 +-119.212184 65.730158 +-118.803835 65.666794 +-118.583232 65.570574 +-118.315693 65.589348 +-117.987136 65.643325 +-117.977749 65.701996 +-118.217126 65.671487 +-118.437728 65.697303 +-118.062235 65.847500 +-117.996523 65.931986 +-117.879182 65.990657 +-117.799389 66.079837 +-117.611642 66.199525 +-117.775921 66.244115 +-117.635111 66.314520 +-117.456751 66.452984 +-117.536544 66.424821 +-117.733678 66.452984 +-117.578787 66.556244 +-117.578787 66.619609 +-117.912037 66.591447 +-118.249982 66.424821 +-118.461197 66.312173 +-118.794447 66.288705 +-119.268508 66.298092 +-119.676857 66.272277 +-119.742569 66.319214 +-119.996027 66.354416 +# -b +-120.073473 66.596140 +-119.688592 66.652464 +-119.303711 66.767459 +-119.158207 66.809702 +-119.181675 66.866026 +-119.378809 66.891842 +-119.599412 66.948166 +-119.712060 66.905923 +-119.951437 66.957553 +-119.965518 66.990409 +# -b +-114.889314 69.285614 +-115.030124 69.248064 +-115.241339 69.255105 +-115.724787 69.285614 +-116.212929 69.365406 +-116.574341 69.529684 +-116.916979 69.644679 +-117.236149 69.825386 +-117.367572 69.952115 +# -b +-109.916370 68.626153 +-110.291864 68.612072 +-110.700213 68.602684 +-111.052238 68.602684 +-111.371408 68.572176 +-111.493443 68.539320 +-112.023828 68.522892 +-112.784203 68.515852 +-113.225408 68.515852 +-113.370911 68.642581 +-113.676000 68.893692 +-113.610289 69.088479 +-113.854359 69.189393 +-114.182916 69.283267 +-114.769625 69.290307 +-114.891661 69.285614 +# -b +-117.015546 68.931241 +-116.231703 68.900733 +-116.147217 68.931241 +-116.062731 69.001646 +-115.757643 69.001646 +-115.255420 68.961750 +-115.058286 68.820940 +-114.804828 68.769310 +-114.471577 68.668396 +-114.218119 68.412591 +-114.138326 68.339839 +-114.274443 68.257700 +-114.471577 68.309330 +-114.832990 68.257700 +-115.339906 68.206069 +-115.339906 68.100462 +-115.504185 67.933836 +-115.391536 67.903328 +-114.668711 67.839963 +-114.302605 67.776599 +-113.631410 67.764864 +-113.072863 67.743743 +-112.350038 67.785986 +-112.068418 67.734355 +-111.843122 67.818842 +-111.566195 67.785986 +-111.148459 67.912715 +-110.979486 67.785986 +-110.420940 67.997201 +-110.026671 67.997201 +-110.026671 67.997201 +# -b +-109.975041 67.976080 +-110.026671 67.924449 +# -b +-115.788152 62.996095 +-115.745909 62.974974 +-115.755296 62.838857 +-115.501838 62.688660 +-115.116957 62.566625 +-114.783706 62.414080 +-114.422294 62.496219 +-114.342501 62.693354 +-114.441068 62.820083 +-114.211078 62.667538 +-114.178223 62.545503 +-114.164142 62.418774 +-113.910683 62.214599 +-113.624370 62.167663 +-113.502334 62.357756 +-113.427235 62.209906 +-113.305200 62.050321 +-112.831139 62.076136 +-112.277286 62.202865 +-111.883018 62.439895 +-111.704658 62.658151 +-111.263453 62.789574 +-110.831636 62.864673 +-110.399818 62.916303 +-110.024325 62.890488 +-110.024325 62.890488 +# -b +-109.914023 62.728556 +-110.397471 62.740290 +-110.467876 62.714475 +-110.078302 62.672232 +-110.388084 62.637030 +-110.144013 62.552544 +-110.144013 62.552544 +# -b +-109.881168 62.461017 +-110.420940 62.430508 +-110.843370 62.444589 +-111.031117 62.439895 +-110.974793 62.310820 +-111.439466 62.188784 +-111.744555 62.106645 +-111.777410 61.956447 +-112.002707 61.778088 +-112.307795 61.632584 +-112.838180 61.501161 +-113.260610 61.480040 +-113.556311 61.318108 +-113.765180 61.163217 +-114.030372 60.975470 +-114.516167 61.029448 +-115.058286 60.900372 +-115.487757 60.832313 +-115.919574 60.841701 +-116.337311 60.841701 +-116.614238 61.008326 +-116.924020 61.078731 +-117.222068 61.151483 +-117.463792 61.200766 +-117.684394 61.280559 +-117.937853 61.400247 +-118.102131 61.395554 +-118.111518 61.285253 +-118.289878 61.280559 +-118.609047 61.289946 +-118.627822 61.395554 +-118.397832 61.555139 +-118.022339 61.555139 +-117.590521 61.433103 +-117.304207 61.332189 +-116.905245 61.280559 +-116.630665 61.416675 +-116.264559 61.289946 +-115.821007 61.205460 +-115.710706 61.365045 +-115.644995 61.437797 +-115.292969 61.480040 +-115.316438 61.590341 +-115.194402 61.752273 +-115.161547 61.853187 +-114.861152 61.815637 +-114.598306 61.857880 +-114.795440 61.925939 +-114.598306 61.970528 +-114.556063 62.064402 +-115.081754 62.101951 +-114.917476 62.228680 +-115.128691 62.228680 +-115.358681 62.444589 +-115.757643 62.514994 +-115.954777 62.698047 +-116.119055 62.881100 +-116.428838 62.991402 +-116.053344 62.956199 +-115.799886 62.996095 +-115.799886 62.996095 +# -b +-113.061129 61.841452 +-112.929706 61.879002 +-112.497889 61.918898 +-112.169332 61.991650 +-112.277286 61.862574 +-112.389934 61.773394 +-112.610537 61.747579 +-112.831139 61.794516 +-113.061129 61.841452 +-113.061129 61.841452 +# -b +-116.440572 61.221888 +-116.363126 61.163217 +-116.163645 61.034141 +-116.351392 61.045875 +-116.616584 61.142096 +-116.449959 61.221888 +-116.440572 61.221888 +# -b +-111.261107 62.662845 +-111.106216 62.658151 +-110.805821 62.693354 +-110.665011 62.613561 +-111.031117 62.561931 +-111.303350 62.571318 +-111.556808 62.475098 +-111.580276 62.566625 +-111.261107 62.662845 +-111.261107 62.662845 +# -b +-129.613357 70.020173 +-129.998238 69.895791 +-129.998238 69.895791 +# -b +-130.164864 69.703350 +-129.592236 69.827732 +-129.085319 69.914565 +-128.986752 69.846507 +-129.207355 69.703350 +-128.766150 69.797224 +-128.423512 69.949768 +# -b +-127.163261 70.036601 +-126.876948 69.783143 +-126.501454 69.583662 +-126.388806 69.487441 +-126.060249 69.391221 +-125.473540 69.360712 +-125.234163 69.402955 +-125.553333 69.445198 +-125.497009 69.499176 +-125.299874 69.534378 +-125.389054 69.668148 +-125.285793 69.764368 +-125.079272 69.862935 +-124.858669 69.989664 +# -b +-124.914993 70.001398 +-125.187226 69.942727 +-125.187226 69.942727 +# -b +-124.760102 70.027213 +-124.703778 69.961502 +# -b +-124.429199 70.001398 +-124.462054 69.869975 +-124.494910 69.717431 +-124.166353 69.722125 +-124.142885 69.644679 +-124.443280 69.445198 +-124.560621 69.402955 +-124.307163 69.344284 +-124.110029 69.348978 +-123.734535 69.377140 +-123.438834 69.461626 +-123.237006 69.588355 +-123.119665 69.801917 +-122.697234 69.839467 +-122.213786 69.806611 +-122.026039 69.806611 +-121.650546 69.778449 +-121.242196 69.710391 +-120.833847 69.607130 +-120.481822 69.433464 +-120.153265 69.367753 +-120.017148 69.356019 +# -b +-119.963171 66.990409 +-120.183774 66.943472 +-120.371521 66.835518 +-120.624979 66.809702 +-120.920680 66.762766 +-121.131895 66.697054 +-121.305561 66.605528 +-121.605956 66.584406 +-121.812477 66.535123 +-122.080017 66.490533 +-122.408573 66.499920 +-122.676113 66.478799 +-122.882634 66.460024 +-123.093849 66.429515 +-123.192416 66.483492 +-123.558523 66.382578 +-123.985647 66.253503 +-124.253186 66.323908 +-124.417464 66.284011 +-124.623986 66.248809 +-124.900912 66.244115 +-125.121515 66.187791 +-125.121515 66.025860 +-124.947849 65.901477 +-124.844588 65.976576 +-124.638067 65.990657 +-124.459707 66.124427 +-124.220330 66.124427 +-124.009115 66.054022 +-123.675864 66.079837 +-123.290983 66.115039 +-123.183029 66.014125 +-123.051606 66.115039 +-122.971814 66.183097 +-122.586933 66.164323 +-122.202052 66.178404 +-121.845333 66.143201 +-121.671667 66.044634 +-121.418209 66.016472 +-121.338417 65.892090 +-121.760847 65.861581 +-122.220827 65.927292 +-122.464898 65.950761 +-122.563465 65.878009 +-122.333475 65.819338 +-122.211439 65.697303 +-122.422654 65.530677 +-122.774680 65.483741 +-122.793454 65.371093 +-122.849778 65.227936 +-123.117318 65.157531 +-123.436487 65.143450 +-123.389551 65.089472 +-123.150173 65.000293 +-122.774680 64.929888 +-122.319394 64.939275 +-121.892270 64.948662 +-121.615343 65.162224 +-121.460452 65.319462 +-120.953536 65.502515 +-120.521718 65.535371 +-120.423151 65.347624 +-120.676609 65.141103 +-120.977004 65.042536 +-121.253931 64.906419 +-121.493308 64.810199 +-121.174138 64.758569 +-120.812726 64.880604 +-120.258873 65.080085 +-120.061738 65.117634 +# -b +-119.996027 66.354416 +-120.357440 66.359110 +-120.249485 66.424821 +-120.216629 66.530429 +-120.071126 66.596140 +# -b +-140.033305 69.656413 +-139.690667 69.595396 +-139.225994 69.534378 +-138.751933 69.306735 +-138.432764 69.219902 +-138.122982 69.130722 +-137.639533 68.992259 +-137.278121 68.945322 +-136.888546 68.886652 +-136.724268 68.886652 +-136.536521 68.905426 +-136.207964 68.893692 +-135.785534 68.802165 +-135.292698 68.668396 +-135.226987 68.710639 +-135.442896 68.830327 +-135.433508 68.914814 +-134.992303 68.886652 +-134.663747 68.748188 +-134.288253 68.600338 +-134.189686 68.722373 +-134.410288 68.846755 +-134.649666 69.027462 +-134.461919 69.114295 +-134.020714 69.264492 +-133.734400 69.365406 +-133.175853 69.419383 +-133.006881 69.611824 +-132.744035 69.632945 +-132.476496 69.733859 +-132.204263 69.703350 +-132.035291 69.776102 +-131.748977 69.834773 +-131.486132 69.949768 +-131.021458 69.970889 +-131.021458 69.970889 +# -b +-129.998238 69.895791 +-130.406588 69.806611 +-130.913504 69.618864 +-131.307772 69.600089 +-131.927337 69.522644 +-132.058760 69.409996 +-132.401397 69.271532 +-132.645468 69.161231 +-132.974025 69.111948 +-132.678324 69.118988 +-132.312218 69.170619 +-131.838157 69.330203 +-131.828770 69.402955 +-131.608167 69.332550 +-131.443889 69.344284 +-131.288998 69.456932 +-131.021458 69.438158 +-131.087170 69.201127 +-130.749226 69.440505 +-130.406588 69.686922 +-130.162517 69.703350 +# -b +-135.060362 69.384181 +-134.952407 69.365406 +-135.027506 69.461626 +-134.731805 69.452239 +-134.497121 69.515603 +-134.576914 69.546112 +-134.553445 69.679882 +-134.487734 69.733859 +-134.314068 69.644679 +-134.159177 69.529684 +-133.882250 69.560193 +-134.079385 69.379487 +-134.454878 69.154191 +-134.830372 69.050930 +-134.952407 69.025115 +-134.872615 69.090826 +-134.750579 69.182353 +-135.126073 69.201127 +-135.327901 69.391221 +-135.248108 69.461626 +-135.074443 69.384181 +-135.060362 69.384181 +# -b +-135.954506 69.266839 +-135.996749 69.231636 +-135.987362 69.147150 +-135.785534 69.060317 +-135.579012 69.036849 +-135.325554 68.966444 +-135.123726 68.914814 +-135.058015 68.985219 +-135.245762 69.043889 +-135.400653 69.090826 +-135.400653 69.147150 +-135.597787 69.172965 +-135.733903 69.266839 +-135.884101 69.285614 +-135.954506 69.266839 +# -b +-139.434862 59.954597 +-139.711789 60.057858 +-139.711789 60.057858 +# -b +-145.327765 70.008439 +-144.952272 69.982624 +-144.952272 69.982624 +# -b +-144.919416 70.024867 +-144.797381 69.982624 +-144.609634 69.982624 +# -b +-142.560847 70.006092 +-142.307389 69.914565 +-141.974138 69.820692 +-141.579870 69.766715 +-141.392123 69.656413 +-141.227844 69.698656 +-141.162133 69.745593 +-141.007242 69.722125 +-141.007242 69.722125 +# -b +-141.004895 69.722125 +-140.826536 69.672841 +-140.197584 69.649373 +-140.033305 69.656413 +# -b +-141.401510 59.992146 +-141.511811 60.032043 +-141.643234 60.008574 +# -b +-142.084439 59.987453 +-142.492789 60.036736 +-142.835426 60.109488 +-143.088885 60.114182 +-143.466725 60.041430 +-143.872728 60.025002 +-144.137920 60.015615 +-144.194244 60.097754 +-144.492292 60.196321 +-144.658917 60.196321 +-144.912376 60.299582 +-145.022677 60.459167 +-145.100122 60.492022 +# -b +-147.815411 60.015615 +-147.681641 60.086020 +-147.395327 60.233870 +-147.263904 60.393455 +-147.207580 60.311316 +-147.219314 60.208055 +-147.484507 60.003881 +-147.484507 60.003881 +# -b +-147.836532 59.975719 +-147.827145 60.003881 +-147.815411 60.015615 +# -b +-146.810965 60.386415 +-146.822699 60.447432 +-146.611484 60.484982 +-146.379147 60.442739 +-146.280580 60.386415 +-146.667808 60.306622 +-146.778109 60.360600 +-146.810965 60.386415 +# -b +-145.154100 60.492022 +-145.255013 60.414577 +-145.431026 60.339478 +-145.729074 60.475594 +-145.916821 60.534265 +-145.860497 60.604670 +-145.926208 60.670382 +-146.113955 60.703237 +-146.346292 60.707931 +-146.423737 60.783030 +-146.832087 60.729053 +-146.501183 60.808845 +-146.480061 60.890984 +-146.787497 60.933227 +-146.733520 61.078731 +-146.656074 61.142096 +-147.162990 60.982511 +-147.461038 60.982511 +-147.716844 61.050569 +-147.827145 60.937921 +-148.146314 60.937921 +-147.913978 61.268825 +-148.268350 61.062303 +-148.322327 61.130361 +-148.432628 61.003632 +-148.697821 60.862822 +-148.697821 60.729053 +-148.399773 60.740787 +-148.554664 60.588243 +-148.510074 60.517837 +-148.146314 60.538959 +-148.277737 60.442739 +-148.510074 60.266726 +-148.355183 60.250298 +-148.488952 60.142344 +-148.643843 60.020308 +-148.742410 60.015615 +# -b +-149.195350 59.975719 +-149.293917 60.008574 +-149.394831 60.008574 +# -b +-149.472276 59.987453 +-149.537988 60.102448 +-149.547375 60.015615 +# -b +-150.044904 60.937921 +-149.481664 60.916799 +-149.195350 60.923840 +-149.714000 61.024754 +-149.979193 61.045875 +# -b +-150.033170 61.226582 +-149.702266 61.407288 +-149.641248 61.517589 +-149.779712 61.449531 +# -b +-160.072930 66.455330 +-159.523771 66.509308 +-159.875796 66.556244 +-159.875796 66.556244 +# -b +-160.105786 66.575019 +-159.678662 66.640730 +-159.875796 66.692361 +-159.875796 66.692361 +# -b +-151.800337 59.947557 +-151.535144 60.201015 +-151.424843 60.571815 +-151.359132 60.766602 +-150.885071 60.886291 +-150.476722 61.020060 +-150.044904 60.937921 +-150.044904 60.937921 +# -b +-149.979193 61.045875 +-150.033170 61.226582 +-150.033170 61.226582 +# -b +-149.857157 61.449531 +-150.373461 61.247703 +-150.659775 61.400247 +-150.382848 61.717070 +-150.218570 62.094911 +-150.307749 62.285004 +-150.382848 62.033893 +-150.626919 61.712377 +-150.838134 61.437797 +-150.988332 61.200766 +-151.464739 61.029448 +-151.894210 60.799458 +-152.203992 60.609364 +-152.445716 60.360600 +-152.776620 60.245605 +-153.163848 60.299582 +-152.788354 60.142344 +-152.755499 60.020308 +# -b +-164.550692 63.050073 +-164.663340 63.028951 +-164.386413 63.028951 +-164.330089 63.005483 +# -b +-163.757462 63.000789 +-163.569715 63.059460 +-163.184834 63.035992 +-162.776485 63.188536 +-162.358748 63.460769 +-162.081821 63.474850 +-162.203857 63.388017 +-161.696940 63.420873 +-161.222880 63.479543 +-160.847386 63.700146 +-160.767594 63.866771 +-160.945953 64.026356 +-160.955340 64.174207 +-161.340221 64.418277 +-161.476338 64.516845 +-161.067989 64.502764 +-160.748819 64.664695 +-160.955340 64.861829 +-161.265123 64.838361 +-161.598373 64.796118 +-161.894075 64.735100 +-162.443234 64.526232 +-162.776485 64.284508 +-163.020555 64.559088 +-163.391355 64.622452 +-163.053411 64.512151 +-163.184834 64.441746 +-163.635426 64.573169 +-163.870110 64.554394 +-164.306621 64.563781 +-164.869861 64.441746 +-165.414327 64.507457 +-166.038585 64.563781 +-166.240413 64.608371 +-166.512646 64.730407 +-166.681618 65.004986 +-166.855284 65.265485 +-166.648763 65.141103 +-166.193476 65.295994 +-166.869365 65.382827 +-167.122823 65.371093 +-167.826874 65.535371 +-168.136656 65.692609 +-167.958297 65.701996 +-167.826874 65.685568 +-167.549947 65.765361 +-167.310570 65.906171 +-166.935076 65.960148 +-166.733249 66.054022 +-166.141846 66.187791 +-165.832064 66.124427 +-165.677173 66.218300 +-165.498813 66.394313 +-165.226580 66.438902 +-164.827618 66.535123 +-164.409882 66.591447 +-163.799705 66.626649 +-163.945208 66.600834 +-163.780930 66.474105 +-163.888884 66.267584 +-163.888884 66.204219 +-163.658895 66.070449 +-163.020555 66.070449 +-162.720160 66.103305 +-162.621593 66.054022 +-162.293037 66.039941 +-161.992642 66.030553 +-161.762652 66.000044 +-161.584292 66.208913 +-161.330834 66.248809 +-161.100844 66.173710 +-160.945953 66.274624 +-161.551437 66.399006 +-161.818976 66.293399 +-161.870606 66.474105 +-162.016110 66.636037 +-161.560824 66.464718 +-161.199411 66.530429 +-160.988196 66.448290 +-160.659639 66.363804 +-160.218434 66.424821 +-160.072930 66.455330 +# -b +-159.873449 66.556244 +-160.192619 66.514001 +-160.103439 66.575019 +# -b +-159.873449 66.692361 +-160.225475 66.645424 +-160.469546 66.589100 +-160.854427 66.652464 +-161.197064 66.605528 +-161.305019 66.661852 +-161.516234 66.579713 +-161.882340 66.762766 +-161.596026 66.922351 +-161.802548 67.034999 +-162.121718 67.030305 +-162.577004 66.990409 +-162.356401 67.161728 +-162.530067 67.135913 +-162.642715 67.088976 +-162.882092 67.004490 +-163.257586 67.037345 +-163.755115 67.218052 +-163.820826 67.354168 +-164.107140 67.560690 +-164.205707 67.631095 +-164.815884 67.811801 +-165.365044 68.006588 +-165.984608 68.121583 +-166.458669 68.304636 +-166.885793 68.365654 +-166.580704 68.473609 +-166.698046 68.393816 +-166.524380 68.426672 +-166.172355 68.511158 +-166.313165 68.558095 +-166.280309 68.811553 +-166.270922 68.891345 +-165.871960 68.903079 +-165.815636 68.846755 +-165.088117 68.914814 +-164.482634 68.954710 +-163.952249 69.015727 +-163.468801 69.229289 +-163.224730 69.463973 +-163.069839 69.499176 +-162.882092 69.595396 +-162.830462 69.618864 +-162.896173 69.747940 +-162.332933 69.764368 +-162.750669 69.776102 +-162.694345 69.912218 +-162.530067 69.970889 +# -b +-162.290690 70.017826 +-161.868259 69.921606 +-161.901115 69.956808 +-161.901115 69.956808 +# -b +-162.466702 66.931738 +-162.325892 66.957553 +-162.147533 66.840211 +-162.048966 66.722870 +-162.424459 66.769806 +-162.523026 66.896535 +-162.466702 66.931738 +# -b +-169.833418 63.035992 +-169.885048 63.115784 +-169.885048 63.115784 +# -b +-170.075142 63.491278 +-169.737198 63.420873 +-169.568225 63.343427 +-169.295993 63.303531 +-169.019066 63.343427 +-168.774995 63.268328 +-168.840707 63.179149 +-169.249056 63.188536 +-169.493127 63.108743 +-169.713729 63.045379 +-169.713729 63.045379 +# -b +-167.566375 60.262032 +-167.256593 60.250298 +-166.737942 60.327744 +-166.395304 60.402843 +-165.986955 60.339478 +-165.721763 60.306622 +-165.667785 60.097754 +-165.688907 60.003881 +# -b +-167.212003 59.999187 +-167.477195 60.118875 +-167.566375 60.262032 +-167.566375 60.262032 +# -b +-165.379125 60.670382 +-165.191378 60.757215 +-164.860474 60.837007 +-164.320702 60.679769 +-164.628137 60.435698 +-164.937920 60.595283 +-165.292292 60.653954 +-165.379125 60.670382 +# -b +-164.330089 63.005483 +-164.320702 62.829470 +-164.597629 62.798961 +-164.907411 62.702741 +-164.973122 62.829470 +-164.550692 63.050073 +# -b +-162.189776 59.982759 +-162.344667 60.240911 +-162.443234 60.365293 +-161.978561 60.653954 +-161.560824 60.846394 +-161.638269 60.846394 +-162.046619 60.712625 +-162.431500 60.529572 +-162.586391 60.257339 +-162.541801 60.142344 +-162.574657 60.081326 +# -b +-164.067244 59.975719 +-164.055510 60.076632 +-164.419269 60.025002 +-164.585894 60.273767 +-164.341824 60.484982 +-164.121221 60.653954 +-163.724606 60.771296 +-164.055510 60.825273 +-164.407535 60.841701 +-164.773641 60.900372 +-164.738439 61.020060 +-164.961388 61.113934 +-165.203112 60.975470 +-165.390859 61.125668 +-165.501160 61.268825 +-165.440142 61.407288 +-165.726456 61.348617 +-165.803902 61.517589 +-165.531669 61.576260 +-165.526975 61.665440 +-165.747578 61.590341 +-165.951752 61.548098 +-166.024504 61.576260 +-165.902469 61.658399 +-165.951752 61.742885 +-165.947059 61.836759 +-165.803902 61.846146 +-165.792168 61.977569 +-165.764006 62.127766 +-165.698294 62.270923 +-165.625542 62.374184 +-165.548097 62.470404 +-165.404940 62.566625 +-165.322801 62.618255 +-165.151482 62.754371 +-165.052915 62.740290 +-164.919145 62.763759 +-164.952001 62.899875 +-164.759560 63.000789 +# -b +-170.098610 66.159629 +-169.690261 66.115039 +-169.957800 66.049328 +# -b +-169.887395 63.115784 +-170.342681 63.193230 +-170.685319 63.326999 +-171.126524 63.383323 +-171.511405 63.308224 +-171.854043 63.430260 +-171.905673 63.554642 +-171.830574 63.784632 +-171.431612 63.681371 +-171.013876 63.592191 +-170.694706 63.650862 +-170.441248 63.690759 +-170.140853 63.622700 +-170.075142 63.491278 +-170.075142 63.491278 +# -b +-172.931240 60.545999 +-172.919506 60.501410 +-172.698903 60.409883 +-172.555747 60.372334 +-172.865529 60.435698 +-172.996952 60.522531 +-172.931240 60.545999 +# -b +-179.000000 68.743495 +-178.779738 68.579216 +-178.601379 68.466568 +-178.282209 68.421978 +-178.404245 68.511158 +-178.085075 68.337492 +-177.948959 68.271781 +-177.545303 68.243619 +-177.301232 68.184948 +-177.277764 68.107502 +-176.935126 68.041791 +-177.071242 67.943224 +-176.540858 67.882206 +-176.155977 67.849350 +-176.385967 67.722621 +-176.296787 67.640482 +-175.714772 67.509059 +-175.456620 67.502019 +-175.733546 67.602933 +-175.935374 67.722621 +-175.766402 67.753130 +-175.404989 67.685072 +-175.160919 67.480897 +-174.808893 67.340087 +-174.996640 67.438654 +-174.916848 67.243867 +-174.696245 66.943472 +-174.644615 66.722870 +-174.433400 66.619609 +-174.222185 66.560938 +-173.982807 66.495227 +-174.034438 66.328601 +-173.795061 66.460024 +-173.968726 66.645424 +-174.147086 66.692361 +-174.067293 66.978675 +-174.334833 67.020918 +-174.442787 67.051426 +-174.377076 67.088976 +-173.935871 67.067854 +-173.780980 67.051426 +-173.626088 67.124178 +-173.396099 67.063161 +-173.485278 66.948166 +-173.241207 66.823783 +-173.241207 66.988062 +-172.898570 66.905923 +-172.424509 66.948166 +-172.659192 67.011530 +-172.049015 66.978675 +-171.729846 66.870720 +-171.457613 66.711135 +-170.946003 66.452984 +-170.528266 66.284011 +-170.518879 66.232381 +-170.232565 66.173710 +-170.101142 66.159629 +# -b +-169.955453 66.049328 +-170.415433 65.936680 +-170.593792 65.755973 +-170.847251 65.624551 +-171.354167 65.842806 +-171.100709 65.594042 +-171.330699 65.483741 +-171.992506 65.479047 +-172.180253 65.251404 +-172.457179 65.204467 +-172.058217 65.056617 +-172.644926 64.958050 +-172.710638 64.852442 +-172.842060 64.824280 +-172.973483 64.721019 +-172.842060 64.631839 +-172.513503 64.601331 +-172.344531 64.432358 +-172.898384 64.512151 +-172.874916 64.446439 +-173.109600 64.242265 +-173.259797 64.469908 +-173.339589 64.474601 +-173.771407 64.376034 +-174.034253 64.413584 +-174.189144 64.622452 +-174.663204 64.702245 +-174.606880 64.953356 +-174.705447 64.934581 +# -b +-174.674939 64.967437 +-174.773506 64.824280 +-175.050432 64.786731 +-175.008189 64.730407 +-175.402458 64.828974 +-175.909374 65.042536 +-175.956311 65.319462 +-176.120589 65.488434 +-176.519551 65.598736 +-176.848108 65.603429 +-177.364412 65.535371 +-177.876022 65.507209 +-178.490893 65.565880 +-178.580072 65.802910 +-178.889855 65.964842 +-178.842918 66.039941 +-178.580072 66.192485 +-178.655171 66.347376 +-178.941485 66.159629 +-179.000000 66.189567 +# -b +169.885048 68.755229 +170.448289 68.846755 +170.866025 69.039196 +170.898881 69.231636 +170.720521 69.407649 +170.335640 69.593049 +170.335640 69.717431 +170.481144 69.869975 +170.415433 69.930993 +# -b +171.330699 70.017826 +172.067605 69.956808 +172.687169 69.919259 +173.447544 69.884056 +174.118739 69.888750 +174.738303 69.832426 +174.860339 69.858241 +175.221751 69.869975 +175.860090 69.869975 +176.437412 69.733859 +177.099219 69.625905 +177.362065 69.614170 +178.066115 69.449892 +178.385285 69.419383 +178.718536 69.325510 +179.000000 69.263358 +# -b +179.000000 64.747939 +178.575564 64.577862 +178.476997 64.664695 +178.223538 64.744488 +177.937225 64.697551 +177.383371 64.843055 +177.139301 65.014374 +176.580754 65.066004 +176.346070 65.166918 +176.435250 64.976824 +176.965635 64.943969 +177.162769 64.772650 +176.444637 64.847748 +175.961189 64.981518 +176.191179 64.824280 +176.158324 64.636533 +176.139549 64.350219 +175.731200 64.150738 +175.665488 64.059212 +176.289746 64.270427 +176.205260 64.559088 +176.590141 64.601331 +177.139301 64.725713 +177.373984 64.636533 +177.561731 64.371341 +178.087422 64.228184 +178.387817 64.261039 +178.519240 64.063905 +178.298637 64.016969 +178.650662 63.967685 +178.772698 63.592191 +179.000000 63.289088 +179.000000 63.289088 +# -b +179.000000 63.030208 +178.993300 63.028951 +# -b +178.995462 63.028951 +178.962606 62.974974 +179.000000 62.950668 +# -b +179.000000 62.338348 +178.798328 62.336635 +178.380591 62.444589 +177.784495 62.557237 +177.498181 62.679273 +177.474713 62.566625 +177.329209 62.644070 +177.155543 62.723862 +176.934941 62.838857 +177.099219 62.627642 +177.155543 62.540809 +176.658014 62.465711 +176.216809 62.310820 +175.784992 62.188784 +175.662956 62.177050 +175.231139 62.076136 +175.221751 62.167663 +175.076247 62.085523 +174.836870 61.935326 +174.428521 61.815637 +174.085883 61.773394 +173.841812 61.658399 +173.578967 61.726458 +173.391220 61.569220 +173.287959 61.517589 +173.025114 61.374432 +172.762268 61.390860 +172.813898 61.259437 +172.569828 61.189032 +172.405549 61.142096 +172.283514 60.998939 +172.030055 61.083425 +172.107501 60.949655 +171.908020 60.862822 +171.699152 60.825273 +171.499671 60.733746 +171.257947 60.571815 +171.004488 60.545999 +170.671238 60.459167 +170.560937 60.409883 +170.474104 60.250298 +170.373190 60.048470 +170.373190 60.048470 +# -b +170.089223 59.971025 +170.068101 60.020308 +# -b +159.988444 69.778449 +160.476586 69.722125 +160.992890 69.553153 +161.302672 69.492135 +161.612454 69.435811 +162.077128 69.621211 +162.382216 69.693963 +162.781178 69.656413 +163.311563 69.722125 +163.827867 69.736206 +164.193973 69.679882 +164.569467 69.555500 +165.020059 69.560193 +165.020059 69.560193 +# -b +164.998937 69.569581 +165.219540 69.593049 +165.604421 69.571927 +165.970527 69.550806 +166.430507 69.492135 +166.820081 69.475707 +167.172107 69.576621 +167.500664 69.717431 +167.890238 69.747940 +167.876157 69.668148 +168.176552 69.571927 +168.218795 69.377140 +168.251651 69.208168 +168.669388 69.170619 +169.002638 69.083786 +169.387519 68.940629 +169.664446 68.766963 +169.885048 68.755229 +# -b +168.099107 69.994358 +168.099107 69.994358 +# -b +168.474600 70.020173 +169.127020 69.884056 +169.366398 69.729165 +169.258443 69.611824 +168.807851 69.564887 +168.230529 69.710391 +167.836261 69.888750 +168.099107 69.994358 +# -b +164.736092 59.942863 +164.557732 60.036736 +# -b +161.368383 59.954597 +161.908156 60.299582 +162.173348 60.496716 +162.781178 60.642220 +163.332684 60.745480 +163.708178 60.937921 +163.609611 61.151483 +163.874803 61.374432 +163.858376 61.585647 +163.956943 61.810944 +163.996839 62.090217 +164.107140 62.310820 +164.381720 62.414080 +164.381720 62.414080 +# -b +164.888636 62.407040 +164.438044 62.681619 +163.621345 62.545503 +163.302176 62.275617 +163.081573 61.923592 +163.269320 61.688908 +162.968925 61.526977 +162.828115 61.717070 +162.396297 61.599728 +161.809588 61.306374 +161.412973 61.118627 +160.859120 60.792417 +160.340470 60.604670 +160.241903 60.799458 +160.220781 60.991898 +160.220781 60.991898 +# -b +159.988444 61.066997 +160.021300 61.135055 +# -b +159.910999 61.315761 +160.131601 61.552792 +160.209047 61.956447 +160.028341 61.794516 +# -b +170.068101 60.020308 +169.812296 60.212749 +169.472005 60.447432 +169.162223 60.545999 +168.807851 60.571815 +168.467560 60.588243 +168.134309 60.621098 +167.782284 60.538959 +167.472502 60.426311 +167.273021 60.409883 +167.120476 60.339478 +166.932730 60.372334 +166.831816 60.184587 +166.557236 60.057858 +166.479790 60.008574 +# -b +166.158274 59.954597 +166.247454 60.175200 +166.226332 60.381721 +166.181742 60.496716 +166.026851 60.452126 +165.707682 60.273767 +165.374431 60.217443 +165.088117 60.069592 +165.088117 60.069592 +# -b +159.922733 70.095272 +159.683356 69.851201 +159.988444 69.778449 +159.988444 69.778449 +# -b +160.220781 60.991898 +159.899265 61.024754 +159.988444 61.066997 +# -b +160.021300 61.135055 +159.910999 61.205460 +159.910999 61.315761 +# -b +160.033034 61.794516 +159.577748 61.679521 +159.145931 61.918898 +158.850229 61.836759 +158.319845 61.794516 +157.611100 61.782782 +157.038473 61.573913 +156.672366 61.315761 +156.242896 61.034141 +155.956582 60.754868 +155.480174 60.534265 +154.919281 60.316010 +154.663475 60.086020 +154.663475 60.086020 +# -b +70.320568 66.640730 +70.865034 66.741644 +71.437661 66.851945 +71.592552 66.657158 +70.982375 66.544510 +70.466072 66.556244 +70.320568 66.640730 +# -b +72.526593 70.006092 +72.592304 69.914565 +72.672097 69.715084 +72.606385 69.541419 +72.517205 69.386527 +72.460881 69.118988 +72.728421 68.863183 +73.244724 68.654315 +73.432471 68.410244 +73.080446 68.138011 +73.122689 67.823535 +72.949023 67.626401 +72.582917 67.502019 +72.338846 67.281416 +72.151099 67.159381 +71.723975 67.103057 +71.357869 67.093669 +71.766218 67.086629 +71.930497 66.964594 +71.493985 66.948166 +71.095023 66.835518 +70.775854 66.767459 +70.254856 66.692361 +70.189145 66.753378 +# -b +69.780796 66.697054 +70.081191 66.499920 +70.099965 66.363804 +70.541170 66.333295 +71.348482 66.354416 +72.043145 66.222994 +72.273135 66.525735 +72.869231 66.657158 +73.498183 66.870720 +73.850208 67.192237 +74.052036 67.405799 +74.436917 67.588852 +74.732618 67.795373 +74.746699 67.985467 +74.601195 68.184948 +74.314881 68.321064 +74.357124 68.454834 +74.389980 68.682477 +75.108111 68.818593 +75.629109 68.877264 +76.103170 68.933588 +76.642942 68.903079 +76.750896 68.698905 +77.173326 68.572176 +77.290668 68.417285 +77.239038 68.299943 +77.346992 68.210763 +77.281281 68.067606 +77.239038 67.823535 +77.379848 67.678031 +77.689630 67.527834 +78.295114 67.513753 +78.628364 67.534875 +78.759787 67.602933 +78.187159 67.647523 +77.835134 67.715581 +77.656774 67.703847 +77.511271 67.889247 +77.600450 68.138011 +78.163691 68.260047 +77.985331 68.414938 +77.755341 68.682477 +77.576982 68.870224 +76.840076 69.020421 +76.220511 69.177659 +75.629109 69.208168 +75.140967 69.055624 +74.413448 69.107254 +73.751641 69.194087 +73.930000 69.456932 +73.596750 69.862935 +73.643686 69.942727 +# -b +60.020308 70.050682 +60.517837 69.815998 +60.414577 69.663454 +60.062551 69.675188 +60.062551 69.675188 +# -b +59.888886 68.691864 +60.592936 68.778697 +60.846394 68.893692 +60.959042 69.118988 +60.757215 69.212862 +60.461513 69.438158 +60.428658 69.630598 +60.790070 69.740900 +61.146789 69.825386 +61.541058 69.745593 +62.104298 69.733859 +62.766106 69.724472 +63.273022 69.642332 +63.958298 69.529684 +64.563781 69.377140 +65.225589 69.219902 +65.690262 69.154191 +65.610470 69.072052 +65.929639 69.032155 +66.549204 68.877264 +67.276723 68.710639 +67.858738 68.482996 +68.182601 68.260047 +68.576869 68.360960 +68.910120 68.734107 +69.008687 68.926548 +68.356267 69.111948 +68.069953 69.360712 +67.896287 69.480401 +67.243867 69.654067 +66.990409 69.522644 +66.858986 69.888750 +66.858986 69.888750 +# -b +66.912963 70.036601 +67.025611 69.975583 +67.213358 69.975583 +# -b +70.189145 66.753378 +69.780796 66.697054 +69.780796 66.697054 +# -b +49.842084 68.008935 +50.330226 68.138011 +50.823062 68.309330 +51.001421 68.311677 +51.686697 68.426672 +52.137289 68.506464 +52.456459 68.349226 +52.634818 68.522892 +52.620737 68.663702 +52.855421 68.680130 +53.296626 68.626153 +53.273157 68.795125 +53.568859 68.893692 +54.066388 68.945322 +54.385557 68.961750 +54.516980 68.973484 +# -b +49.896062 69.259798 +50.093196 69.278573 +50.280943 68.996953 +50.158907 69.090826 +# -b +58.806995 69.963849 +58.764752 69.968543 +# -b +60.064898 69.675188 +59.689405 69.790183 +59.163714 69.877016 +59.248200 69.771408 +58.886787 69.938034 +58.806995 69.963849 +# -b +54.516980 68.973484 +54.498205 68.950016 +54.057000 68.921854 +53.770686 68.813900 +53.934965 68.853796 +54.024145 68.680130 +53.902109 68.527586 +54.000676 68.311677 +54.418413 68.267087 +54.883086 68.145052 +54.948798 68.344533 +55.314904 68.494730 +55.873451 68.595644 +56.403835 68.572176 +57.023400 68.579216 +57.497461 68.595644 +57.994990 68.774003 +58.445582 68.926548 +59.083921 68.985219 +59.370235 68.750535 +59.196569 68.626153 +59.313911 68.365654 +59.989800 68.466568 +59.891232 68.691864 +59.891232 68.691864 +# -b +39.914972 68.079340 +40.205979 67.938530 +40.393726 67.795373 +40.853706 67.720274 +41.064921 67.471510 +41.163488 67.208664 +41.327767 66.978675 +40.778607 66.553897 +40.271691 66.354416 +40.093331 66.274624 +# -b +39.950174 64.608371 +40.475865 64.526232 +40.809116 64.474601 +40.752792 64.601331 +40.466478 64.915806 +40.034660 65.213855 +40.034660 65.213855 +# -b +39.860995 65.617510 +40.508721 65.802910 +41.015638 65.976576 +41.644589 66.138508 +42.109263 66.368497 +42.404964 66.490533 +42.705359 66.382578 +43.287374 66.354416 +43.578382 66.164323 +43.676949 66.133814 +44.005506 65.985963 +44.202640 65.960148 +44.183865 66.234728 +44.169784 66.337989 +44.446711 66.565632 +44.535890 66.870720 +44.380999 67.093669 +43.897551 67.180502 +43.949181 67.487938 +44.118154 67.844657 +44.151009 67.903328 +44.169784 68.215457 +43.784903 68.445447 +43.277987 68.663702 +43.841227 68.567482 +44.404467 68.527586 +45.052194 68.515852 +45.746857 68.461874 +46.080108 68.264740 +46.488457 68.051178 +46.530700 67.807107 +45.671758 67.732009 +45.197698 67.534875 +45.099131 67.316619 +45.681146 67.077242 +45.967460 66.844905 +46.530700 66.856639 +46.741915 66.797968 +47.314543 66.849599 +47.746361 66.999796 +47.779216 67.264988 +48.032675 67.577118 +48.563059 67.619361 +48.802437 67.703847 +49.168543 67.856391 +49.839738 68.008935 +49.839738 68.008935 +# -b +48.661626 69.445198 +48.793049 69.475707 +48.990183 69.480401 +49.323434 69.452239 +49.896062 69.259798 +49.896062 69.259798 +# -b +50.161254 69.090826 +49.588626 68.818593 +49.015999 68.694211 +48.682748 68.680130 +48.297867 68.823287 +48.222768 68.755229 +48.232156 69.032155 +48.419902 69.313776 +48.663973 69.445198 +# -b +29.978472 69.703350 +30.100507 69.656413 +30.246011 69.684575 +30.433758 69.654067 +30.588649 69.783143 +30.893738 69.754981 +31.104953 69.729165 +31.480446 69.630598 +31.701049 69.745593 +31.963894 69.771408 +31.977975 69.900484 +32.470811 69.794877 +32.860385 69.747940 +33.080988 69.722125 +32.893241 69.557846 +32.428568 69.618864 +32.142254 69.722125 +32.175110 69.541419 +32.395712 69.461626 +32.494279 69.440505 +32.813449 69.445198 +32.968340 69.421730 +33.066907 69.341938 +33.268735 69.332550 +33.320365 69.271532 +33.386077 69.208168 +33.827282 69.259798 +34.381135 69.243370 +34.963150 69.182353 +35.287013 69.182353 +35.681281 69.172965 +36.080243 69.107254 +36.727970 68.938282 +37.192643 68.823287 +37.633848 68.675436 +38.098521 68.499424 +38.361367 68.349226 +38.680537 68.248312 +38.835428 68.304636 +39.112354 68.128624 +39.440911 68.074647 +39.863341 68.025363 +39.914972 68.079340 +# -b +40.093331 66.274624 +39.290714 66.129120 +38.713392 66.075143 +37.967099 66.093918 +37.788739 66.107999 +37.446101 66.194832 +36.709195 66.288705 +35.901884 66.373191 +35.230689 66.474105 +34.789484 66.584406 +34.390522 66.722870 +34.104208 66.711135 +33.686471 66.819090 +33.423626 66.774500 +32.860385 66.973981 +32.484892 67.140606 +32.109398 67.114791 +32.405099 66.936432 +32.649170 66.675933 +33.066907 66.518695 +33.606679 66.403700 +33.874218 66.239422 +34.268487 66.133814 +34.658061 65.927292 +34.780097 65.594042 +34.456233 65.392214 +34.709692 65.051923 +34.888051 64.871217 +34.723773 64.507457 +35.033555 64.399503 +35.540471 64.298589 +35.958208 64.218796 +36.286765 64.016969 +37.169175 63.845650 +37.600992 63.798713 +37.934243 63.939523 +38.164233 63.944217 +38.018729 64.317364 +37.577524 64.385422 +37.061220 64.474601 +36.709195 64.692857 +36.610628 64.889991 +36.939185 65.162224 +37.779352 64.990905 +38.375448 64.819586 +38.131377 64.655308 +38.474015 64.749181 +39.013787 64.730407 +39.699063 64.554394 +39.952521 64.608371 +39.952521 64.608371 +# -b +40.037007 65.213855 +39.863341 65.521290 +39.863341 65.617510 +# -b +30.215502 59.963984 +30.182647 60.001534 +30.048877 60.013268 +# -b +30.931287 61.681868 +31.142502 61.672480 +31.471059 61.531670 +31.813697 61.329842 +32.341735 61.207807 +32.552950 60.973123 +32.740697 60.768949 +32.630396 60.531918 +32.376937 60.189281 +31.980322 60.243258 +31.449938 60.083673 +31.449938 60.083673 +# -b +30.987611 59.940516 +30.910165 60.304275 +30.633239 60.646913 +30.436105 60.768949 +30.358659 60.959042 +30.292948 61.043529 +30.060611 61.059956 +30.114588 61.426063 +30.241317 61.541058 +30.375087 61.672480 +30.501816 61.688908 +30.511204 61.735845 +# -b +19.987995 69.806611 +20.293083 69.914565 +20.293083 69.522644 +20.072481 69.318469 +20.462055 69.553153 +20.560623 69.733859 +20.856324 69.888750 +20.936116 69.806611 +21.166106 69.825386 +21.320997 69.888750 +# -b +21.255286 70.013132 +21.705878 69.839467 +22.006273 69.790183 +21.973417 69.989664 +21.973417 69.989664 +# -b +22.987250 70.048335 +23.226627 69.956808 +23.226627 69.956808 +# -b +29.173507 70.001398 +29.450434 69.884056 +29.943269 69.815998 +29.624100 69.729165 +29.891639 69.693963 +29.976125 69.703350 +# -b +19.865959 63.650862 +20.217985 63.721267 +20.480830 63.812794 +20.715514 63.923095 +20.936116 64.131964 +21.156719 64.289202 +21.363240 64.427665 +21.433645 64.350219 +21.466501 64.488683 +21.255286 64.617758 +21.198962 64.716326 +21.100395 64.843055 +21.311610 64.948662 +21.433645 65.042536 +21.565068 65.195080 +21.377321 65.333543 +21.597924 65.406295 +21.752815 65.453232 +21.917093 65.502515 +22.039129 65.549452 +21.860769 65.706690 +22.071984 65.671487 +22.236263 65.652713 +22.292587 65.734852 +22.391154 65.901477 +22.466253 65.861581 +22.653999 65.868622 +22.832359 65.838113 +23.076430 65.760667 +23.503554 65.856887 +23.911903 65.765361 +24.024551 65.936680 +24.132506 65.892090 +24.310865 65.814644 +24.573711 65.784135 +24.939817 65.622204 +25.258986 65.443844 +25.324698 65.272525 +25.301230 65.112941 +25.348166 64.972131 +25.146338 64.885298 +24.639422 64.814893 +24.231073 64.437052 +23.616202 64.092067 +23.128060 63.817488 +22.719711 63.500665 +22.334830 63.322305 +21.851382 63.223738 +21.574455 63.134559 +21.649554 63.040685 +# -b +27.624596 60.585896 +27.457971 60.522531 +26.974523 60.592936 +26.399548 60.494369 +26.026402 60.433351 +25.880898 60.400496 +25.540607 60.337131 +25.320004 60.297235 +24.867065 60.198668 +24.458716 60.161119 +24.228726 60.067245 +23.874354 60.078979 +23.578653 60.006227 +# -b +23.346316 59.980412 +23.358050 60.067245 +23.313460 60.090713 +# -b +23.069389 59.989800 +22.949701 60.083673 +22.783075 60.215096 +22.496762 60.292541 +22.398194 60.407536 +21.834954 60.536612 +21.536906 60.663341 +21.360893 60.738440 +21.250592 60.808845 +21.241205 60.952002 +21.283448 61.090465 +21.384362 61.292293 +21.363240 61.472999 +21.433645 61.566873 +21.424258 61.595035 +21.351506 61.796863 +21.236511 62.057361 +21.236511 62.381225 +21.163759 62.573665 +21.203655 62.822430 +21.323344 62.906916 +21.346812 63.021911 +21.501703 63.040685 +# -b +19.983301 60.025002 +20.049013 60.090713 +# -b +19.983301 60.222136 +20.016157 60.346519 +20.016157 60.346519 +# -b +21.769243 60.210402 +21.614352 60.243258 +21.757508 60.139997 +21.802098 60.156425 +# -b +22.553086 60.050817 +22.696243 60.264379 +22.541351 60.254992 +22.299627 60.116529 +22.419316 60.083673 +22.553086 60.050817 +# -b +29.002189 59.947557 +29.100756 60.001534 +29.255647 60.006227 +# -b +30.048877 60.013268 +29.950310 60.132957 +29.422272 60.215096 +28.870766 60.254992 +28.516394 60.358253 +28.507006 60.553040 +28.584452 60.564774 +28.605573 60.754868 +28.262935 60.663341 +27.866320 60.560081 +27.624596 60.585896 +# -b +9.941194 63.411485 +10.138328 63.465462 +10.579533 63.519440 +10.668712 63.603926 +10.969107 63.763510 +11.344601 63.831569 +11.231953 63.845650 +10.649938 63.704840 +10.161796 63.554642 +10.039761 63.578110 +# -b +9.962315 63.754123 +10.004558 63.798713 +# -b +9.929459 63.923095 +10.051495 64.087374 +10.248629 64.237571 +10.534943 64.385422 +10.746158 64.488683 +10.966761 64.608371 +11.407966 64.540313 +11.440821 64.763262 +11.670811 64.847748 +11.361029 64.843055 +11.694279 65.004986 +11.900801 65.148143 +12.168340 65.171612 +12.356087 65.251404 +12.342006 65.371093 +12.069773 65.305381 +12.309150 65.443844 +12.309150 65.549452 +12.665869 65.392214 +12.576689 65.549452 +12.464041 65.652713 +12.708112 65.690262 +12.816067 65.842806 +12.961570 65.910865 +13.017894 66.054022 +12.520365 65.946067 +12.928715 66.119733 +13.027282 66.258196 +13.445018 66.347376 +13.172786 66.389619 +13.271353 66.478799 +13.247884 66.575019 +13.313596 66.706442 +13.721945 66.800315 +13.721945 66.938778 +13.951935 66.990409 +14.228861 67.063161 +14.449464 67.196930 +14.360284 67.318966 +14.834345 67.560690 +15.078416 67.487938 +15.529008 67.487938 +15.585332 67.560690 +15.223919 67.598239 +15.388198 67.614667 +15.486765 67.753130 +15.444522 67.893940 +15.773079 68.001895 +15.820016 68.072300 +16.050005 68.105155 +16.256527 67.926796 +16.392643 68.055872 +16.402031 68.201376 +16.303464 68.365654 +16.768137 68.400857 +17.138937 68.337492 +17.406476 68.445447 +17.472188 68.522892 +16.974658 68.534626 +16.514679 68.518198 +16.735281 68.630847 +17.209342 68.703598 +17.373620 68.762269 +17.683403 68.795125 +17.725646 68.910120 +17.547286 69.008687 +17.847681 69.126029 +18.044815 69.224596 +18.101139 69.384181 +18.298273 69.433464 +18.396841 69.348978 +18.664380 69.259798 +18.697235 69.365406 +18.476633 69.510910 +18.838046 69.468667 +19.260476 69.271532 +19.490466 69.273879 +19.025792 69.473360 +19.007018 69.632945 +19.335575 69.754981 +19.631276 69.771408 +19.654744 69.529684 +19.809635 69.715084 +19.987995 69.806611 +# -b +18.234909 63.000789 +18.380413 63.085275 +18.643258 63.219045 +18.962428 63.312918 +19.239354 63.474850 +19.624235 63.514746 +19.868306 63.650862 +19.868306 63.650862 +# -b +15.632269 68.926548 +15.773079 68.945322 +15.805935 68.778697 +15.852871 68.659009 +15.927970 68.640234 +16.139185 68.799819 +16.524066 68.771657 +16.402031 68.572176 +15.993681 68.426672 +15.773079 68.443100 +15.599413 68.309330 +15.519621 68.466568 +14.979849 68.243619 +14.848426 68.276474 +14.604355 68.217804 +14.261717 68.206069 +14.374365 68.316371 +14.717003 68.400857 +14.989236 68.445447 +15.209838 68.534626 +15.444522 68.626153 +15.519621 68.774003 +15.599413 68.910120 +15.632269 68.926548 +# -b +14.451811 68.680130 +14.484666 68.727067 +14.616089 68.778697 +14.827304 68.877264 +15.071375 68.881958 +15.169942 68.893692 +15.277897 68.755229 +15.169942 68.630847 +14.860160 68.630847 +14.925871 68.670743 +14.639558 68.630847 +14.428342 68.663702 +14.451811 68.680130 +# -b +15.775426 69.194087 +15.888074 69.252758 +16.108676 69.285614 +16.094595 69.147150 +15.906849 69.025115 +15.564211 68.985219 +15.676859 69.130722 +15.775426 69.194087 +# -b +14.925871 67.795373 +14.827304 67.868125 +15.202798 67.877512 +15.291978 67.807107 +14.907097 67.682725 +14.770980 67.732009 +14.925871 67.795373 +14.925871 67.795373 +# -b +16.944150 69.194087 +16.944150 69.219902 +16.887826 69.302041 +16.977005 69.367753 +17.319643 69.414689 +17.319643 69.480401 +17.451066 69.569581 +17.596570 69.560193 +17.803091 69.503869 +17.925127 69.426424 +17.859415 69.236330 +17.563714 69.147150 +17.310256 69.083786 +16.869051 69.036849 +16.887826 69.111948 +16.991086 69.172965 +16.944150 69.194087 +# -b +18.244296 69.693963 +18.464899 69.691616 +18.633871 69.729165 +18.741825 69.855894 +18.920185 69.722125 +18.699582 69.576621 +18.244296 69.550806 +18.225522 69.595396 +18.244296 69.693963 +18.244296 69.693963 +# -b +18.863861 70.020173 +18.788762 69.989664 +# -b +19.150175 70.031907 +19.197111 69.952115 +19.215886 69.987317 +# -b +19.347309 70.006092 +19.525668 69.938034 +19.215886 69.797224 +18.840392 69.900484 +18.887329 69.975583 +18.887329 69.975583 +# -b +18.087058 63.012523 +18.227868 62.989055 +18.218481 62.918650 +17.974410 62.801308 +17.744420 62.852938 +17.688096 62.862326 +17.720952 62.634683 +17.622385 62.507954 +17.359539 62.512647 +17.279747 62.346022 +17.312603 62.113685 +17.270360 61.829718 +17.204648 61.698296 +16.993433 61.625544 +17.007514 61.435450 +17.014555 61.207807 +17.136590 60.883944 +17.214036 60.705584 +16.993433 60.433351 +16.507638 60.243258 +16.265914 60.144691 +16.772831 60.222136 +17.246891 60.449779 +17.368927 60.656301 +17.554327 60.553040 +17.941555 60.489675 +18.359291 60.308969 +18.293580 60.231524 +18.624484 60.055511 +# -b +19.962180 60.391108 +19.664132 60.391108 +19.607808 60.304275 +19.718109 60.128263 +19.983301 60.025002 +# -b +20.049013 60.090713 +19.983301 60.222136 +19.983301 60.222136 +# -b +20.016157 60.346519 +19.983301 60.369987 +19.962180 60.391108 +# -b +7.547422 63.010176 +7.594358 63.125171 +7.791493 63.165067 +7.969852 63.174455 +8.035563 63.237819 +8.190455 63.244860 +8.340652 63.219045 +8.387589 63.308224 +8.542480 63.392711 +8.805325 63.470156 +9.105720 63.524133 +9.213675 63.352814 +9.293467 63.486584 +9.359178 63.564029 +9.612637 63.646169 +9.866095 63.549948 +9.941194 63.411485 +9.941194 63.411485 +# -b +10.039761 63.578110 +9.917725 63.676678 +9.964662 63.754123 +# -b +10.006905 63.798713 +9.711204 63.880852 +9.931806 63.923095 +# -b +8.450953 63.568723 +8.648087 63.592191 +8.849915 63.681371 +9.089292 63.667290 +9.023581 63.559336 +8.493196 63.524133 +8.450953 63.568723 +# -b +4.933047 61.130361 +4.846215 61.099853 +4.780503 61.041182 +4.768769 60.987204 +4.890804 61.008326 +4.933047 61.130361 +4.933047 61.130361 +# -b +5.001106 60.670382 +4.989371 60.778336 +4.989371 60.675075 +5.001106 60.670382 +# -b +5.949227 59.989800 +6.268397 60.165812 +6.498386 60.440392 +6.665012 60.386415 +6.819903 60.564774 +6.498386 60.614058 +5.958614 60.247951 +5.794336 60.083673 +# -b +5.407108 59.956944 +5.705156 60.074286 +5.550265 60.193974 +5.320275 60.165812 +5.153650 60.346519 +5.439964 60.456820 +5.695769 60.677422 +5.177118 60.592936 +5.001106 60.785377 +5.165384 60.759561 +5.308541 60.855782 +5.087939 60.942615 +5.364865 61.022407 +5.860047 61.069344 +6.477265 61.097506 +6.897348 60.968430 +7.150807 60.947308 +7.380796 61.144442 +7.425386 61.235969 +7.380796 61.367392 +7.331513 61.477693 +7.080402 61.170258 +6.859799 61.177298 +6.606341 61.320455 +6.352883 61.165564 +5.867088 61.186685 +5.294460 61.106893 +5.106713 61.224235 +5.118447 61.383820 +5.224055 61.524630 +5.174771 61.625544 +5.130182 61.735845 +5.306194 61.855533 +5.489247 61.817984 +5.784949 61.886042 +5.576080 61.876655 +5.693422 61.975222 +5.522103 61.932979 +5.350784 61.923592 +5.191199 61.942366 +5.167731 62.118379 +5.350784 62.040933 +5.416495 62.134807 +5.571387 62.092564 +5.641792 62.097258 +5.625364 62.226333 +5.803723 62.294392 +5.857700 62.252149 +5.862394 62.416427 +5.845966 62.442242 +5.829538 62.493873 +5.763827 62.543156 +5.923412 62.608868 +6.122893 62.604174 +6.348189 62.554890 +6.381045 62.676926 +6.294212 62.756718 +6.155749 62.796614 +6.082997 62.906916 +6.327068 62.918650 +6.364617 63.010176 +# -b +5.892903 62.238068 +6.014938 62.350716 +5.813111 62.364797 +5.827192 62.238068 +5.892903 62.238068 +# -b +5.001106 61.761660 +5.141916 61.850840 +5.001106 61.881349 +5.001106 61.796863 +# -b +-8.382895 71.076249 +-8.955523 70.916664 +-8.936748 70.848606 +-8.185761 70.984722 +-7.965158 71.160735 +-8.382895 71.076249 +-8.382895 71.076249 +# -b +-17.746767 79.200992 +-17.521471 79.135281 +-17.605957 79.055488 +-17.878190 78.999164 +-17.981451 79.114159 +-17.746767 79.200992 +# -b +-17.735033 77.900845 +-17.537899 77.844521 +-17.772582 77.663815 +-18.091752 77.727179 +-17.735033 77.900845 +-17.735033 77.900845 +# -b +-20.072481 79.771273 +-19.912896 79.794741 +# -b +-20.006769 79.923817 +-19.781473 79.980141 +# -b +-17.514431 80.012997 +-17.833600 79.874534 +-18.115220 79.750151 +-19.082116 79.764232 +-19.373124 79.738417 +-19.654744 79.524855 +-19.626582 79.409860 +-19.861266 79.222113 +-19.598420 79.308946 +-19.213539 79.212726 +-19.466997 79.238541 +-19.664132 79.100078 +-19.945752 79.109465 +-19.880040 78.888863 +-19.880040 78.888863 +# -b +-20.095949 77.814012 +-19.053954 77.682590 +-19.542096 77.612185 +-19.851878 77.689630 +# -b +-20.006769 77.365767 +-19.377818 77.234344 +-19.049261 77.314136 +-18.467246 77.293015 +-18.279499 77.271893 +-18.195013 77.044250 +-18.204400 76.985580 +-18.204400 76.985580 +# -b +-18.197360 76.985580 +-18.206747 76.938643 +-18.385106 76.811914 +-18.892023 76.814261 +-19.746271 76.901094 +-19.746271 76.901094 +# -b +-20.215638 76.215818 +-19.802595 76.084395 +-19.811982 76.035111 +# -b +-20.084215 75.887261 +-19.577299 75.706554 +-19.483425 75.274737 +-19.769739 75.112805 +-19.769739 75.112805 +# -b +-20.206250 74.631704 +-19.520975 74.643438 +-19.136094 74.406408 +-19.619542 74.216314 +# -b +-18.748866 76.502132 +-18.739479 76.267448 +-18.664380 75.929504 +-18.786415 76.131332 +-19.030486 76.396524 +-19.143134 76.539681 +-19.002324 76.586618 +-18.852127 76.647635 +-18.748866 76.502132 +# -b +-17.976757 75.300552 +-18.187972 75.194944 +-17.957982 75.072909 +-17.493309 75.133927 +-17.648200 74.925058 +-18.220828 74.976689 +-18.671420 74.983729 +-18.924878 75.122192 +-18.948347 75.281777 +-18.586934 75.342795 +-18.187972 75.380344 +-17.976757 75.300552 +-17.976757 75.300552 +# -b +-20.525420 80.012997 +-20.609906 79.848718 +-20.253187 79.750151 +-20.065440 79.771273 +# -b +-19.908202 79.794741 +-20.002076 79.923817 +-20.002076 79.923817 +# -b +-19.884734 78.888863 +-20.729595 78.820805 +-21.133250 78.771521 +-21.095701 78.642445 +-20.954891 78.609589 +-21.292835 78.388987 +-21.649554 78.114407 +-21.612005 77.992372 +-21.705878 77.835134 +-21.489969 77.663815 +-21.001828 77.931354 +-20.598172 77.886764 +-20.100643 77.814012 +# -b +-19.851878 77.689630 +-20.659190 77.689630 +-20.415119 77.574635 +-20.527767 77.520658 +-20.274309 77.443212 +-20.283696 77.370461 +-20.002076 77.365767 +# -b +-19.753311 76.901094 +-20.907954 76.945683 +-21.715265 76.950377 +-20.757757 76.896400 +-21.198962 76.865891 +-21.292835 76.814261 +-21.123863 76.769671 +-21.649554 76.647635 +-22.137696 76.790792 +-22.719711 76.682838 +-22.531964 76.516213 +-22.147083 76.513866 +-21.827914 76.419992 +-22.616450 76.422339 +-21.705878 76.396524 +-21.687103 76.328466 +-21.583843 76.218164 +-21.142638 76.154800 +-20.870405 76.143066 +-21.058152 76.279182 +-20.222678 76.215818 +-20.222678 76.215818 +# -b +-19.819023 76.035111 +-20.438587 75.988175 +-21.076926 75.943585 +-20.325939 75.875527 +-20.091256 75.887261 +# -b +-19.774433 75.112805 +-20.215638 75.314633 +-21.914746 75.546970 +-21.881891 75.460137 +-21.520478 75.403813 +-20.703780 75.190251 +-21.374974 75.070562 +-21.121516 75.049441 +-20.778878 74.932099 +-20.858671 74.683334 +-21.055805 74.641091 +-20.525420 74.645785 +-20.206250 74.631704 +# -b +-19.619542 74.216314 +-20.384610 74.418142 +-21.267020 74.465079 +-22.116574 74.526096 +-22.201060 74.307841 +-22.168205 74.202233 +-22.332483 74.077851 +-22.135349 73.995712 +-21.318650 73.946428 +-20.933769 73.904185 +-20.417466 73.789190 +-20.591131 73.549813 +-21.121516 73.444205 +-21.806792 73.371453 +-22.468600 73.244724 +-23.416721 73.409003 +-24.097303 73.756334 +-24.439941 73.739907 +-24.693399 73.561547 +-24.960938 73.526345 +-25.411531 73.397269 +-25.918447 73.225950 +-26.744533 73.303395 +-26.692903 73.176666 +-26.603723 73.146157 +-25.655602 73.066365 +-25.181541 72.953717 +-25.876204 72.812907 +-26.758614 72.798826 +-26.866569 72.681484 +-26.425364 72.606385 +-25.524179 72.791785 +-24.829516 72.559449 +-25.599278 72.418638 +-25.477242 72.252013 +-25.411531 72.169874 +-24.904614 72.418638 +-24.308518 72.303643 +-23.979961 72.214464 +-23.571612 72.097122 +-23.083470 71.968046 +-22.773688 71.829583 +-23.205506 71.571431 +-23.083470 71.590206 +-22.534311 71.766218 +-22.576554 71.592552 +-22.102493 71.709894 +-22.600022 71.442355 +-22.332483 71.432968 +-21.806792 71.477558 +-21.914746 71.271036 +-21.895972 71.097370 +-21.816179 70.994109 +-21.905359 70.806363 +-21.783324 70.656165 +-21.661288 70.459031 +-22.355951 70.482499 +-22.600022 70.808710 +-22.665734 70.440256 +-23.867313 70.581067 +-24.275663 71.062168 +-24.782579 71.322666 +-25.796412 71.536228 +-26.636579 71.557350 +-27.683267 71.806114 +-27.838158 71.616021 +-27.354710 71.463477 +-26.369040 71.477558 +-25.608665 71.210018 +-26.031095 71.076249 +-27.087171 70.940132 +-27.763060 70.921358 +-28.335687 70.893196 +-28.410786 70.548211 +-28.687713 70.451991 +-27.462665 70.398013 +-26.570867 70.334649 +-27.406341 70.207920 +-28.312219 70.137515 +-28.002437 70.006092 +-27.199819 70.163330 +-26.162518 70.247816 +-25.369288 70.285365 +-25.003181 70.271284 +-24.097303 70.163330 +-23.163263 70.069456 +-22.313708 70.114046 +-22.149430 70.139861 +# -b +-22.147083 70.139861 +-22.189326 70.050682 +-22.189326 70.050682 +# -b +-21.759855 74.361818 +-21.849035 74.155296 +-20.924382 74.103666 +-20.206250 74.197539 +-20.581744 74.394674 +-21.562721 74.408755 +-21.759855 74.361818 +# -b +-25.641521 73.207175 +-24.937470 73.071059 +-24.097303 73.014735 +-23.271217 73.071059 +-23.247749 73.169626 +-24.299131 73.223603 +-24.740336 73.282274 +-23.900169 73.218909 +-23.383865 73.244724 +-23.965880 73.343291 +-24.928083 73.399615 +-25.420918 73.289314 +-25.641521 73.207175 +# -b +-22.036782 72.871578 +-22.149430 72.747195 +-22.266772 72.690871 +-22.698589 72.714340 +-22.942660 72.824641 +-23.435496 72.864537 +-24.153627 72.897393 +-24.641769 72.960757 +-23.810989 73.005347 +-23.116326 73.005347 +-22.501455 72.977185 +-22.046169 72.899740 +-22.036782 72.871578 +# -b +-23.062349 72.721380 +-22.231569 72.493737 +-22.198713 72.395170 +-22.794810 72.367008 +-22.222182 72.247319 +-22.353605 72.099469 +-22.794810 72.167527 +-23.569265 72.397517 +-24.132506 72.533633 +-24.404739 72.655669 +-24.536161 72.808213 +-24.306171 72.866884 +-23.667832 72.824641 +-23.203159 72.791785 +-23.062349 72.721380 +# -b +-25.453774 70.862687 +-25.388062 70.635044 +-25.819880 70.574026 +-26.139050 70.541170 +-26.946361 70.510661 +-27.650411 70.456684 +-28.058761 70.496580 +-27.626943 70.705449 +-26.890037 70.874421 +-25.909060 71.043393 +-25.524179 70.916664 +-25.453774 70.862687 +# -b +-50.433487 69.907525 +-50.391244 70.006092 +# -b +-50.963872 69.989664 +-51.494256 70.001398 +-52.817871 70.245469 +-54.183729 70.524742 +-53.963127 70.799322 +-52.817871 70.745345 +-51.672616 70.433216 +-50.611846 70.405054 +-51.207943 70.491887 +-51.029583 70.606882 +-51.095294 70.728917 +-51.053051 70.869727 +-51.902606 71.050434 +-51.470788 71.069208 +-52.188920 71.113798 +-52.001173 71.263996 +-52.264018 71.364909 +-52.996231 71.400112 +-51.869750 71.665304 +-52.761547 71.648876 +-53.104185 71.773259 +-53.423355 71.899988 +-53.873947 71.754484 +-54.094550 71.688773 +-54.010064 71.449395 +-55.178788 71.484598 +-55.751415 71.674692 +-55.047365 71.895294 +-55.540200 72.024370 +-54.934717 72.221504 +-54.826762 72.442107 +-54.714114 72.646281 +-54.559223 72.850456 +-55.319598 73.019428 +-55.385309 73.155545 +-55.352453 73.305742 +-55.451020 73.343291 +-55.497957 73.446552 +-55.662236 73.542772 +-56.004874 73.664808 +-55.817127 73.732866 +-56.112828 73.941734 +-56.300575 74.030914 +-56.183233 74.249170 +-56.643213 74.331309 +-56.488322 74.397020 +-56.248944 74.481506 +-56.765248 74.669253 +-57.042175 74.784248 +-57.150129 74.892203 +-57.910504 75.042400 +-58.318853 75.293511 +-58.530068 75.331061 +-58.267223 75.528195 +-58.398645 75.622068 +-58.708428 75.697167 +-58.891481 75.847365 +-59.112083 75.877873 +-59.224731 75.913076 +# -b +-54.348008 70.327608 +-53.643957 70.247816 +-53.193365 70.177411 +# -b +-54.526367 69.970889 +-54.516980 70.290059 +-54.348008 70.327608 +# -b +-70.097618 70.806363 +-69.942727 70.822791 +# -b +-70.142208 70.590454 +-69.546112 70.738304 +-69.086133 70.653818 +-68.490036 70.566985 +-68.565135 70.367505 +-68.851449 70.301793 +-69.668148 70.151596 +-69.203474 70.156289 +-68.696558 70.095272 +-68.809206 70.031907 +# -b +-68.708292 69.930993 +-68.309330 70.184451 +-67.450388 70.031907 +-67.450388 70.031907 +# -b +-68.950016 77.264853 +-68.856143 77.300055 +-68.396163 77.384542 +-67.682725 77.396276 +-67.034999 77.396276 +-66.462371 77.302402 +-65.908518 77.224957 +-66.687667 77.159245 +-67.748436 77.231997 +-68.649621 77.241385 +-68.950016 77.264853 +# -b +-70.264244 77.227304 +-69.231636 77.217916 +-68.555748 77.185061 +-68.227191 77.163939 +-67.663950 77.199142 +-66.593794 77.138124 +-66.115039 77.156899 +-65.655060 77.248425 +-66.274624 77.335258 +-66.274624 77.466681 +-65.758320 77.567595 +-66.011779 77.661468 +-66.490533 77.635653 +-66.462371 77.687283 +-66.922351 77.663815 +-67.663950 77.544126 +-68.311677 77.607491 +-68.602684 77.579329 +-69.334897 77.485455 +-69.644679 77.520658 +# -b +-70.118740 77.612185 +-69.630598 77.727179 +-69.996705 77.682590 +# -b +-70.109353 78.802030 +-69.480401 78.827845 +-69.086133 78.856007 +-69.236330 78.914678 +-69.020421 79.015592 +-68.128624 79.081303 +-67.678031 79.109465 +-67.246214 79.147015 +-66.964594 79.088344 +-66.560938 79.097731 +-66.204219 79.062529 +-65.931986 79.161096 +-65.509556 79.306600 +-65.171612 79.407513 +-64.843055 79.522508 +-65.068351 79.675053 +-65.124675 79.801782 +-64.401850 79.841678 +-64.833667 79.909736 +-64.880604 79.982488 +# -b +-65.497822 80.022384 +-66.164323 79.989529 +-66.164323 79.989529 +# -b +-59.886539 75.913076 +-60.665688 76.049192 +-60.684463 75.992868 +-60.909759 76.103170 +-61.435450 76.133678 +-62.101951 76.192349 +-62.646417 76.201737 +-63.406792 76.187656 +-63.951257 76.192349 +-64.430012 76.182962 +-64.889991 76.103170 +-65.584655 76.046846 +-65.706690 76.241633 +-66.204219 76.089089 +-66.711135 76.215818 +-66.908270 76.075008 +-66.786234 75.903689 +-67.584158 75.978787 +-68.813900 76.152453 +-69.527338 76.382443 +-68.485343 76.551415 +-68.560441 76.647635 +-69.208168 76.668757 +-69.884056 76.734468 +# -b +-70.008439 76.833035 +-69.764368 77.006701 +-69.923953 76.929256 +# -b +-79.384045 76.969152 +-79.083650 77.053638 +-79.524855 77.163939 +-79.844025 77.161592 +# -b +-80.254721 77.224957 +-79.353536 77.229650 +-78.865395 77.276587 +-78.611936 77.278934 +-78.095633 77.424438 +-77.776463 77.541779 +-78.114407 77.647387 +-78.198893 77.783504 +-78.292767 77.853909 +-78.114407 77.896152 +-77.447906 77.886764 +-76.950377 77.863296 +-76.556109 77.950129 +-76.077354 77.912579 +-75.805121 78.006453 +-75.683086 78.076858 +-76.208777 78.102673 +-76.649982 78.114407 +-77.034863 78.166038 +-76.537334 78.196546 +-75.955319 78.166038 +-75.645537 78.182465 +-75.373304 78.262258 +-75.307592 78.370212 +-75.983481 78.424190 +-76.302651 78.489901 +-75.542276 78.485207 +-75.007198 78.539184 +-74.857000 78.604896 +-74.800676 78.672954 +-74.800676 78.722238 +-74.857000 78.811417 +-75.570438 78.881822 +-76.312038 78.863048 +-75.880220 78.935800 +-76.011643 78.989777 +-76.537334 78.985083 +-77.316483 78.973349 +-77.860949 78.898250 +-77.879724 79.001511 +-77.476068 79.010898 +-76.678144 79.055488 +-76.190002 79.076610 +-76.903440 79.118853 +-77.776463 79.118853 +-77.382195 79.161096 +-76.640595 79.186911 +-75.917770 79.130587 +-75.842671 79.041407 +-75.232494 79.008551 +-74.594155 79.008551 +-74.688028 79.111812 +-74.622317 79.210379 +-75.429628 79.226807 +-75.964706 79.222113 +-76.537334 79.238541 +-77.372807 79.212726 +-77.457293 79.222113 +-77.832787 79.269050 +-77.823400 79.313640 +-77.222610 79.306600 +-77.419744 79.409860 +-77.119349 79.353536 +-76.462235 79.325374 +-76.002256 79.344149 +-76.452848 79.416901 +-77.147511 79.445063 +-77.091187 79.487306 +-76.725081 79.470878 +-76.096129 79.412207 +-75.485952 79.372311 +-75.129233 79.447410 +-74.922711 79.423941 +-74.237436 79.461491 +-74.087238 79.522508 +-73.617871 79.545977 +-73.786843 79.705561 +-74.857000 79.743111 +-74.256210 79.787701 +-73.542772 79.745458 +-73.383188 79.644544 +-73.017081 79.644544 +-72.594651 79.649237 +-72.162833 79.646891 +# -b +-72.160487 79.646891 +-71.625408 79.719642 +-71.531535 79.822903 +-71.606633 79.905042 +-71.165428 79.959020 +# -b +-72.247319 80.005956 +-72.707299 79.998916 +# -b +-80.189010 75.173823 +-79.747805 75.319327 +-79.790048 75.464830 +-79.987182 75.504727 +-79.944939 75.535235 +# -b +-79.229154 76.046846 +-79.294865 75.962359 +-79.078957 75.814509 +-79.491999 75.809815 +-79.689134 75.767572 +-79.848718 75.837977 +-79.689134 75.950625 +-79.529549 76.060927 +-79.304253 76.075008 +-79.229154 76.046846 +# -b +-79.703215 74.847613 +-79.604648 74.943833 +-79.792394 75.028319 +-79.792394 75.028319 +# -b +-80.045853 74.817104 +-79.792394 74.845266 +-79.703215 74.847613 +# -b +-77.708405 69.942727 +-77.952476 70.184451 +-78.492248 70.247816 +-79.285478 70.433216 +-79.430982 70.318221 +-78.886516 70.111699 +# -b +-80.144420 72.357621 +-79.881574 72.315378 +-79.463837 72.364661 +-78.933453 72.303643 +-78.689382 72.413945 +-78.238790 72.658016 +-77.201488 72.721380 +-76.131332 72.559449 +-75.436668 72.446800 +-75.028319 72.193342 +-74.751393 72.066613 +-74.432223 71.827236 +-75.070562 71.655917 +-74.652825 71.627755 +-73.582669 71.782646 +-73.859595 71.606633 +-73.836127 71.557350 +-73.549813 71.357869 +-73.286967 71.292158 +-73.132076 71.547963 +-72.658016 71.592552 +-72.428026 71.648876 +-71.442355 71.475211 +-71.188897 71.134920 +-72.127631 71.031659 +-71.432968 70.928398 +-70.649125 71.022272 +-70.883808 70.689021 +-70.306487 70.745345 +-70.099965 70.806363 +# -b +-69.942727 70.822791 +-70.440256 70.524742 +-70.139861 70.590454 +-70.139861 70.590454 +# -b +-80.320432 76.220511 +-79.278437 76.434073 +-78.583774 76.464582 +-78.095633 76.631207 +-78.283379 76.943337 +-78.987430 76.793139 +-79.325374 76.889359 +-79.391086 76.969152 +-79.391086 76.969152 +# -b +-78.963962 73.603790 +-78.245830 73.615524 +-77.330564 73.465327 +-77.011395 73.279927 +-76.537334 73.085140 +-76.316732 72.925555 +-76.635901 72.789438 +-77.936048 72.866884 +-78.996817 72.737808 +-79.790048 72.754236 +# -b +-80.090442 73.664808 +-78.963962 73.603790 +-78.963962 73.603790 +# -b +-71.299198 76.999661 +-71.158388 77.046597 +-70.754732 77.131083 +-70.266591 77.227304 +-70.266591 77.227304 +# -b +-69.644679 77.520658 +-70.029560 77.548820 +-70.123434 77.612185 +# -b +-69.999051 77.682590 +-70.468418 77.750648 +-70.496580 77.830440 +-71.322666 77.830440 +-71.735709 77.919620 +-72.205076 77.943088 +-72.242626 78.013493 +-72.702605 78.114407 +-72.740155 78.191853 +-72.486697 78.276339 +-72.824641 78.344397 +-72.646281 78.438271 +-72.073654 78.546225 +-71.529188 78.633058 +-71.210018 78.635405 +-70.928398 78.675301 +-70.365158 78.757440 +-70.111699 78.802030 +# -b +-69.888750 76.734468 +-70.010786 76.833035 +# -b +-69.921606 76.929256 +-70.850953 76.823648 +-71.095023 76.933949 +-71.432968 76.959764 +-71.292158 77.004354 +# -b +-87.245943 80.050546 +-87.114520 79.947285 +-87.302267 79.893308 +-87.030034 79.898002 +-87.274105 79.740764 +-87.621436 79.628116 +-87.433690 79.623422 +-87.161457 79.653931 +-86.832900 79.698521 +-86.485568 79.623422 +-86.260272 79.541283 +-86.335371 79.452103 +-86.138237 79.461491 +-86.081913 79.529549 +-85.959877 79.599954 +-85.781518 79.574139 +-85.349700 79.447410 +-85.190115 79.374658 +-85.096242 79.276091 +-85.330925 79.193951 +-85.509285 79.158749 +-86.372920 79.064875 +-86.767188 78.978043 +-86.983097 78.902944 +-87.030034 79.001511 +-87.208393 79.034367 +-87.180231 78.900597 +-87.536950 78.701116 +-87.931219 78.661220 +-88.137740 78.848967 +-88.222226 78.931106 +-88.184677 79.006205 +-88.194064 79.055488 +-88.391198 78.900597 +-88.419360 78.736319 +-88.287938 78.621324 +-88.118965 78.478167 +-88.250388 78.428883 +-88.635269 78.527450 +-88.823016 78.593162 +-88.869953 78.461739 +-88.560170 78.351438 +-88.691593 78.158997 +-89.076474 78.166038 +-89.358094 78.297460 +-89.489517 78.346744 +-89.771137 78.400721 +-89.968271 78.499288 +# -b +-90.080920 78.426536 +-89.705426 78.281033 +-89.433193 78.093286 +-89.902560 78.227055 +-89.902560 78.227055 +# -b +-88.637616 76.999661 +-88.487419 77.013742 +-88.431094 77.067719 +-88.187024 77.058331 +-88.008664 77.041904 +-87.830305 77.077106 +-87.680107 77.055985 +-87.614396 77.088840 +-87.473586 77.124043 +-87.229515 77.140471 +-87.004219 77.088840 +-86.900958 77.138124 +-87.229515 77.161592 +-87.342163 77.194448 +-87.135641 77.231997 +-87.370325 77.253119 +-87.041768 77.309443 +-87.295226 77.330564 +-87.680107 77.297709 +-87.886629 77.384542 +-87.867854 77.469028 +-88.064988 77.525352 +-88.355996 77.586369 +-88.374770 77.670855 +-88.393545 77.727179 +-88.309059 77.769423 +-87.924178 77.816359 +-87.623783 77.860949 +-87.295226 77.867990 +-86.778923 77.835134 +-86.365880 77.767076 +-86.243844 77.694324 +-85.924675 77.562901 +-85.858963 77.478415 +-85.746315 77.429131 +-85.267561 77.382195 +-84.901454 77.356380 +-84.638609 77.290668 +-84.497799 77.342299 +-84.422700 77.386888 +-83.972108 77.379848 +-83.568452 77.365767 +-83.746812 77.403316 +-83.784361 77.450253 +-83.465191 77.513617 +-83.258670 77.586369 +-83.023986 77.687283 +-82.817465 77.792891 +-82.686042 77.900845 +-82.610943 77.978291 +-82.507683 78.022881 +-82.873789 77.954822 +-82.995824 77.804625 +-83.380705 77.623919 +-83.784361 77.504230 +-84.188017 77.499536 +-84.544736 77.513617 +-84.732482 77.506577 +-84.939004 77.574635 +-84.779419 77.645040 +-84.770032 77.734220 +-84.901454 77.635653 +-85.126751 77.612185 +-85.342659 77.638000 +-85.408371 77.713098 +-85.211237 77.790544 +-85.352047 77.790544 +-85.539794 77.785850 +-85.492857 77.839828 +-85.107976 77.844521 +-84.957778 77.870336 +-84.948391 77.903192 +-85.333272 77.867990 +-85.699378 77.842174 +-85.887125 77.900845 +-85.549181 77.985331 +-85.173687 77.978291 +-85.089201 78.015840 +-85.201849 78.058083 +-85.089201 78.109714 +-84.760644 78.121448 +-84.450862 78.114407 +-84.141080 78.144916 +-84.319439 78.151957 +-84.779419 78.168384 +-84.957778 78.201240 +-84.779419 78.283379 +-84.666771 78.335010 +-84.892067 78.346744 +-84.854518 78.454698 +-84.713708 78.555612 +-84.835743 78.501635 +-84.976553 78.388987 +-85.126751 78.248177 +-85.427146 78.095633 +-85.652442 78.088592 +-85.896513 78.069817 +-86.243844 78.058083 +-86.300168 78.130835 +-86.037323 78.229402 +-85.934062 78.337357 +-86.112421 78.295114 +-86.243844 78.198893 +-86.469140 78.187159 +-86.656887 78.105020 +-86.919733 78.088592 +-87.295226 78.079205 +-87.539297 78.093286 +-87.370325 78.156650 +-87.210740 78.170731 +-87.501748 78.180119 +-87.558072 78.227055 +-87.595621 78.309195 +-87.698882 78.379600 +-87.539297 78.459392 +-87.060543 78.522757 +-87.191966 78.555612 +-87.060543 78.677648 +-86.816472 78.769174 +-86.328330 78.778562 +-85.586730 78.811417 +-85.417758 78.886516 +-85.136138 78.881822 +-84.760644 78.846620 +-84.141080 78.820805 +-83.596614 78.750400 +-83.192958 78.654179 +-82.798690 78.588468 +-82.404422 78.515716 +-82.610943 78.647139 +-82.301161 78.670607 +-82.686042 78.682341 +-82.939500 78.701116 +-83.268057 78.738665 +-83.202346 78.799683 +-82.629718 78.780908 +-82.244837 78.799683 +-82.000766 78.764481 +-81.888118 78.785602 +-81.813019 78.832539 +-81.766083 78.891210 +-81.615885 78.959268 +-81.981992 78.900597 +-82.188513 78.853660 +-82.479521 78.839579 +-82.648493 78.841926 +-83.108472 78.879476 +-83.437029 78.888863 +-83.953333 78.900597 +-84.291277 78.909984 +-84.629222 78.975696 +-84.835743 78.994470 +-84.835743 79.071916 +-84.535348 79.076610 +-84.075368 78.999164 +-83.530903 78.978043 +-83.512128 79.003858 +-83.774974 79.060182 +-84.037819 79.111812 +-84.037819 79.198645 +-84.291277 79.161096 +-84.460249 79.217420 +-84.507186 79.294865 +-84.591672 79.407513 +-85.023490 79.508427 +-85.145525 79.576486 +-85.239399 79.644544 +-85.614892 79.703215 +-85.952837 79.724336 +-86.591176 79.818210 +-86.609950 79.926164 +-86.328330 79.970754 +-85.680604 79.905042 +-85.474082 79.923817 +-86.046710 79.980141 +-86.356492 79.998916 +# -b +-83.209386 80.005956 +-82.683695 79.874534 +-82.298814 79.783007 +-82.167392 79.672706 +-81.979645 79.616382 +-81.970257 79.550670 +-81.557214 79.578832 +-81.050298 79.508427 +-80.947037 79.515468 +-80.806227 79.569445 +-80.458896 79.592913 +-80.064627 79.635156 +-80.289923 79.653931 +-80.618480 79.616382 +-81.059685 79.616382 +-81.378855 79.653931 +-81.707412 79.700868 +-81.810673 79.743111 +-81.848222 79.848718 +-81.782511 79.881574 +-81.698025 79.919123 +-81.923321 79.926164 +-82.139230 79.954326 +-82.495948 79.996569 +# -b +-79.846372 77.161592 +-80.437774 77.039557 +-80.409612 77.163939 +-81.047951 77.199142 +-81.911587 77.044250 +-82.127495 77.217916 +-81.310797 77.255466 +-81.695678 77.393929 +-81.160599 77.304749 +-80.250027 77.224957 +-80.250027 77.224957 +# -b +-90.125509 74.502628 +-89.416765 74.615276 +-89.627980 74.690375 +-89.496558 74.758433 +-89.243099 74.695068 +-88.956786 74.742005 +-88.778426 74.767820 +-88.745570 74.594155 +-88.754958 74.479160 +-88.346608 74.479160 +-87.952340 74.436917 +-87.576847 74.528443 +-87.281145 74.446304 +-86.783616 74.467425 +-86.849328 74.509669 +-86.384654 74.570686 +-86.121809 74.450998 +-85.689991 74.652825 +-85.337966 74.479160 +-85.159606 74.636398 +-85.126751 74.617623 +-84.577591 74.504975 +-83.695181 74.556605 +-83.573146 74.788942 +-83.892315 74.892203 +-83.408867 74.800676 +-83.188265 74.603542 +-82.648493 74.504975 +-82.404422 74.488547 +-81.752002 74.509669 +-81.193455 74.558952 +-80.817961 74.558952 +-80.531647 74.584767 +-80.287577 74.725577 +-80.320432 74.788942 +-80.663070 74.983729 +-80.287577 75.108111 +-80.189010 75.173823 +# -b +-79.944939 75.535235 +-80.564503 75.530542 +-80.418999 75.624415 +-80.728782 75.678392 +-81.240392 75.687780 +-81.306103 75.791040 +-81.568949 75.833284 +-81.813019 75.854405 +-82.118108 75.781653 +-82.334017 75.762878 +-82.441971 75.786347 +-82.596862 75.814509 +-82.840933 75.713595 +-83.014599 75.640843 +-83.324381 75.652577 +-83.652938 75.596253 +-83.634163 75.504727 +-83.873541 75.551663 +-84.305358 75.537582 +-84.591672 75.497686 +-84.042513 75.399119 +-84.385151 75.380344 +-84.901454 75.345142 +-85.131444 75.319327 +-84.910842 75.387385 +-85.441227 75.462484 +-85.751009 75.563397 +-86.037323 75.462484 +-86.178133 75.523501 +-86.501996 75.462484 +-86.764842 75.431975 +-86.877490 75.554010 +-87.008912 75.596253 +-87.295226 75.596253 +-87.248290 75.431975 +-87.548684 75.516461 +-87.891322 75.525848 +-88.046214 75.511767 +-88.163555 75.535235 +-87.778674 75.589213 +-87.694188 75.744104 +-87.858467 75.767572 +-87.910097 75.765225 +# -b +-90.059798 75.784000 +-89.956537 75.849711 +-89.956537 75.849711 +# -b +-90.268666 76.107863 +-89.517679 76.121944 +-89.386256 76.283876 +-89.714813 76.272142 +-89.958884 76.283876 +# -b +-79.792394 75.028319 +-80.224212 74.962608 +-80.496445 74.932099 +-80.191356 74.807717 +-80.045853 74.817104 +# -b +-80.165541 69.968543 +-80.273496 70.001398 +# -b +-80.519913 69.968543 +-81.435179 70.088231 +-81.777817 70.027213 +# -b +-84.854518 69.980277 +-85.624280 70.027213 +-85.624280 70.027213 +# -b +-85.582037 69.970889 +-86.595869 70.257203 +-87.135641 70.273631 +-87.919484 70.266591 +-88.346608 70.405054 +-89.308811 70.787588 +-89.529413 71.050434 +-88.581292 70.954213 +-87.454811 70.956560 +-87.886629 71.132573 +-89.041272 71.242874 +-89.956537 71.308585 +# -b +-90.125509 71.651223 +-89.947150 71.761525 +# -b +-90.069185 72.054879 +-89.970618 72.169874 +-89.970618 72.169874 +# -b +-90.048064 72.367008 +-89.738282 72.606385 +-89.320545 72.747195 +-89.254834 72.967798 +-89.179735 73.181360 +-88.837097 73.298702 +-88.109578 73.603790 +-87.170844 73.761028 +-86.166399 73.810312 +-85.504591 73.791537 +-85.110323 73.735213 +# -b +-85.107976 73.735213 +-85.173687 73.624912 +-85.887125 73.371453 +-86.408123 73.012388 +-86.802391 72.613426 +-86.581788 72.190995 +-86.178133 71.752137 +-85.525713 71.468170 +-85.061039 71.313279 +-85.502244 71.252261 +-86.042016 71.186550 +-86.717905 71.001150 +-86.042016 71.085636 +-85.295723 71.141960 +-85.061039 71.127879 +-85.061039 70.926051 +-84.873292 71.245221 +-84.821662 71.418887 +-85.075120 71.627755 +-85.713459 71.862438 +-85.877738 72.017330 +-85.549181 72.228545 +-85.028184 72.268441 +-85.107976 72.367008 +-85.746315 72.517205 +-85.835495 72.876271 +-85.084508 72.899740 +-84.356989 72.737808 +-84.831049 72.892699 +-85.614892 73.049937 +-85.337966 73.101567 +-84.277196 73.003000 +-84.521267 73.082793 +-85.117363 73.317476 +-84.464943 73.207175 +-84.258422 73.446552 +-83.784361 73.286967 +-83.648244 73.566241 +-82.869095 73.695317 +-81.906893 73.704704 +-81.367121 73.577975 +-81.268554 73.312783 +-81.137131 73.188400 +-80.728782 72.988919 +-80.728782 72.796479 +-80.564503 72.606385 +-80.850817 72.284869 +-80.860204 72.155793 +-81.005708 72.085388 +-81.005708 71.902335 +-80.395531 72.200383 +-80.142073 72.357621 +-80.142073 72.357621 +# -b +-88.553130 76.999661 +-88.862912 76.938643 +-89.501251 76.828342 +-89.585737 76.628861 +-89.623287 76.509172 +-89.210244 76.384790 +-88.881687 76.450501 +-88.787813 76.628861 +-88.665778 76.692225 +-88.628229 76.441114 +-88.252735 76.370709 +-87.867854 76.347240 +-87.755206 76.483357 +-87.323388 76.344894 +-86.797697 76.459888 +-86.675662 76.448154 +-86.459753 76.321425 +-86.788310 76.567843 +-86.769535 76.363668 +-86.215682 76.302651 +-85.586730 76.255714 +-84.920229 76.239286 +-85.201849 76.415299 +-85.023490 76.396524 +-84.460249 76.603045 +-83.652938 76.382443 +-83.596614 76.675797 +-83.343156 76.560802 +-82.892564 76.342547 +-82.272999 76.481010 +-82.498295 76.614780 +-82.141576 76.499785 +-81.531399 76.450501 +-81.033870 76.394177 +-81.231004 76.180615 +-80.320432 76.220511 +-80.320432 76.220511 +# -b +-79.792394 72.754236 +-80.242987 73.071059 +-80.773371 73.223603 +-80.871939 73.470021 +-80.477670 73.702357 +-80.092789 73.664808 +# -b +-99.944668 71.871826 +-99.986911 71.881213 +# -b +-100.000992 73.120342 +-99.935280 73.106261 +-99.888344 73.129729 +# -b +-100.090171 73.885410 +-99.813245 73.782150 +-99.437751 73.723479 +-99.020015 73.711745 +-98.489630 73.732866 +-98.104749 73.815005 +-97.804354 73.852555 +-97.442941 73.880717 +-97.175402 73.753988 +-97.100303 73.624912 +-97.320906 73.547466 +-97.518040 73.495836 +-97.630688 73.462980 +-97.306825 73.446552 +-97.288050 73.312783 +-97.715174 73.270540 +-97.968632 73.164932 +-98.278415 73.031162 +-98.433306 72.925555 +-98.259640 72.918514 +-97.597833 72.986573 +-97.344374 72.899740 +-97.353762 72.834028 +-97.255195 72.763623 +-97.076835 72.683831 +-97.123772 72.585264 +-96.701341 72.695565 +-96.569919 72.669750 +-96.471352 72.533633 +-96.438496 72.357621 +-96.701341 72.291909 +-96.546450 72.174568 +-96.677873 72.007942 +-96.504207 71.961006 +-96.569919 71.796727 +-96.912557 71.672345 +-97.574364 71.601940 +-98.090668 71.601940 +-97.917002 71.475211 +-98.222091 71.343788 +-98.531873 71.259302 +-98.700845 71.362563 +-99.038789 71.308585 +-99.184293 71.508066 +-99.395508 71.693466 +-99.813245 71.820195 +-99.944668 71.871826 +# -b +-96.680220 72.974838 +-96.670833 72.986573 +-96.717769 73.117995 +-97.069795 73.120342 +-97.144893 72.970145 +-96.825724 72.897393 +-96.680220 72.974838 +-96.680220 72.974838 +# -b +-98.665642 73.800924 +-98.501364 73.824393 +-98.083627 73.913572 +-97.872412 74.073157 +-98.459121 74.028567 +-99.031749 73.941734 +-99.440098 73.850208 +-99.285207 73.824393 +-98.989506 73.831433 +-98.811146 73.812658 +-98.665642 73.800924 +# -b +-96.393906 69.952115 +-96.628590 70.156289 +-96.614509 70.386279 +-96.375131 70.477806 +-96.196772 70.569332 +-96.065349 70.656165 +-96.318807 70.766466 +-96.440843 70.968294 +-96.375131 71.052780 +-96.342276 71.210018 +-96.173304 71.273383 +-95.999638 71.378990 +-95.657000 71.235834 +-95.525577 71.341441 +-95.788423 71.503373 +-95.666387 71.658264 +-95.337830 71.806114 +-95.117228 71.949271 +-95.037435 71.953965 +# -b +-96.410334 75.633803 +-96.565225 75.584519 +-96.630936 75.497686 +-96.696648 75.450749 +-96.950106 75.413200 +-97.104997 75.500033 +-96.950106 75.589213 +-96.640324 75.638496 +-96.452577 75.720635 +-96.278911 75.657271 +-96.124020 75.579825 +-96.354010 75.539929 +-96.508901 75.633803 +-96.508901 75.633803 +# -b +-97.689359 76.002256 +-97.689359 75.955319 +-97.773845 75.861446 +-97.877106 75.800428 +-97.623648 75.767572 +-97.520387 75.654924 +-97.534468 75.490646 +-97.543855 75.471871 +-97.731602 75.626762 +-98.017916 75.633803 +-97.928736 75.579825 +-97.985060 75.556357 +-98.116483 75.523501 +-98.017916 75.469524 +-98.083627 75.408506 +-98.261987 75.408506 +-98.182194 75.342795 +-98.008529 75.253615 +-97.905268 75.143314 +-98.196275 75.227800 +-98.261987 75.157395 +-98.158726 75.049441 +-98.632787 75.030666 +-98.844002 75.023625 +-99.008280 75.089337 +-99.252351 75.033013 +-99.397855 75.051787 +-99.552746 75.122192 +-99.773349 74.997810 +-99.773349 74.997810 +# -b +-100.062009 75.518808 +-99.860182 75.518808 +-99.850794 75.549316 +# -b +-100.050275 75.593906 +-99.754574 75.657271 +-99.731106 75.725329 +-99.477647 75.741757 +-99.482341 75.765225 +-99.745187 75.751144 +-99.843754 75.734716 +-99.843754 75.734716 +# -b +-100.083131 75.978787 +-99.735799 76.004602 +-99.970483 76.042152 +-99.970483 76.042152 +# -b +-100.094865 76.204083 +-99.935280 76.204083 +# -b +-100.029154 76.645288 +-99.766308 76.661716 +-99.559787 76.600699 +-99.400202 76.563149 +-99.146744 76.542028 +-99.118582 76.471623 +-98.883898 76.481010 +-98.958997 76.600699 +-98.611665 76.614780 +-98.724313 76.675797 +-98.508405 76.687532 +-98.170460 76.593658 +-98.339432 76.579577 +-97.982713 76.551415 +-97.766805 76.431726 +-97.823129 76.307344 +-97.644769 76.166534 +-97.719868 76.053886 +-97.691706 76.002256 +# -b +-95.065597 77.933701 +-95.290894 77.943088 +-95.750873 77.893805 +-96.295339 77.877377 +-96.595734 77.875030 +-96.614509 77.842174 +-96.736544 77.792891 +-97.177749 77.792891 +-97.065101 77.898498 +-97.403045 77.987678 +-97.750377 78.062777 +-97.468757 78.116754 +-96.755319 78.140222 +-97.027552 78.198893 +-97.543855 78.234096 +-97.909962 78.278686 +-97.872412 78.283379 +-97.985060 78.342050 +-98.013222 78.471126 +-98.360554 78.572040 +-98.125870 78.602549 +-98.219744 78.691729 +-98.294843 78.827845 +-98.154032 78.893557 +-97.609567 78.905291 +-97.027552 78.839579 +-96.642671 78.764481 +-96.173304 78.698769 +-96.041881 78.616630 +-95.966782 78.539184 +-95.525577 78.557959 +-95.084372 78.494595 +-94.952949 78.438271 +-94.783977 78.360825 +-94.990499 78.306848 +-94.999886 78.128488 +-94.859076 78.097979 +-94.802752 78.013493 +-94.943562 77.926660 +-95.065597 77.933701 +# -b +-100.029154 78.724584 +-99.841407 78.698769 +-99.681822 78.637751 +-99.869569 78.532144 +-99.907118 78.433577 +-99.803858 78.365519 +-99.494075 78.252871 +-99.118582 78.112060 +-99.203068 77.980638 +-99.372040 77.867990 +-99.935280 77.835134 +-99.935280 77.835134 +# -b +-98.341779 80.027078 +-98.238518 79.919123 +-98.238518 79.787701 +-98.360554 79.653931 +-98.632787 79.668012 +-98.886245 79.768926 +-99.167865 79.834637 +-99.533971 79.862799 +-99.533971 79.959020 +-99.533971 79.959020 +# -b +-89.970618 78.499288 +-90.195915 78.553265 +-90.083266 78.426536 +# -b +-89.904907 78.227055 +-90.411823 78.231749 +-90.618345 78.241136 +-90.317950 78.184812 +-90.177140 78.072164 +-90.806092 78.069817 +-91.266071 78.102673 +-91.660340 78.147263 +-92.092157 78.201240 +-92.214193 78.248177 +-92.204805 78.295114 +-92.355003 78.255217 +-92.523975 78.295114 +-92.833757 78.386640 +-92.768046 78.438271 +-92.401940 78.457045 +-91.923185 78.468779 +-91.650952 78.496941 +-91.960735 78.506329 +-92.345615 78.553265 +-92.664785 78.569693 +-92.899469 78.553265 +-93.105990 78.614283 +-93.293737 78.679995 +-93.105990 78.722238 +-92.739884 78.752746 +-93.115377 78.804377 +-93.519033 78.825498 +-93.772491 78.959268 +-93.274962 79.027326 +-92.918243 79.125893 +-92.458264 79.132934 +-91.848086 79.142321 +-91.068937 79.184564 +-90.383661 79.200992 +-90.186527 79.271397 +-90.665282 79.238541 +-91.359945 79.198645 +-91.791762 79.198645 +-92.054608 79.205686 +-92.270517 79.264356 +-91.895023 79.276091 +-91.106487 79.308946 +-91.284846 79.332415 +-91.895023 79.315987 +-92.110932 79.377005 +-92.420714 79.388739 +-92.589686 79.330068 +-92.908856 79.308946 +-92.852532 79.412207 +-93.021504 79.358230 +-93.228025 79.292518 +-93.556582 79.226807 +-93.734942 79.283131 +-93.528420 79.353536 +-93.594132 79.369964 +-93.781879 79.393432 +-94.101048 79.369964 +-94.110436 79.318334 +-94.467154 79.266703 +-94.683063 79.287825 +-94.767549 79.346496 +-94.842648 79.384045 +-95.002233 79.365270 +-95.114881 79.381698 +-95.377726 79.416901 +-95.368339 79.503734 +-95.002233 79.501387 +-94.814486 79.510774 +-94.373281 79.538936 +-93.903914 79.583526 +-93.819428 79.649237 +-94.044724 79.616382 +-94.326344 79.597607 +-94.748775 79.618729 +-95.077332 79.621075 +-95.302628 79.642197 +-95.649959 79.733724 +-95.922192 79.818210 +-96.072390 79.867493 +-95.621797 79.898002 +-96.016066 79.933204 +-96.081777 79.973101 +# -b +-94.823873 80.003610 +-94.730000 79.989529 +# -b +-94.349813 80.003610 +-94.049418 79.949632 +-94.068192 79.970754 +# -b +-95.065597 77.738914 +-94.924787 77.720139 +-94.652554 77.755341 +-94.483582 77.734220 +-94.164413 77.717792 +-93.929729 77.694324 +-93.666884 77.720139 +-93.516686 77.696671 +-93.272615 77.656774 +-93.347714 77.593410 +-93.441587 77.551167 +-93.469750 77.461987 +-93.526074 77.396276 +-93.741982 77.398623 +-93.967279 77.400969 +-94.305223 77.419744 +-94.596230 77.429131 +-94.802752 77.443212 +-94.999886 77.412704 +-95.056210 77.433825 +-95.572514 77.452600 +-96.060655 77.548820 +-96.192078 77.633306 +-95.797810 77.731873 +-95.553739 77.792891 +-95.290894 77.745954 +-95.065597 77.738914 +# -b +-94.999886 76.211124 +-94.859076 76.243980 +-94.286448 76.211124 +-93.817081 76.215818 +-93.873405 76.279182 +-93.648109 76.288570 +-93.422813 76.356628 +-93.075481 76.180615 +-92.840798 75.950625 +-92.531015 75.863792 +-92.286945 75.605641 +-92.653051 75.373304 +-92.638970 75.237187 +-92.286945 75.131580 +-92.014712 75.098724 +-92.352656 74.974342 +-92.268170 74.784248 +-91.892676 74.718537 +-91.859821 74.643438 +-91.418616 74.631704 +-91.141689 74.795982 +-91.198013 74.709149 +-90.953942 74.617623 +-90.723952 74.608236 +-90.400089 74.544871 +-90.127856 74.502628 +-90.127856 74.502628 +# -b +-89.937763 75.765225 +-90.059798 75.784000 +# -b +-89.958884 75.849711 +-90.193568 75.929504 +-90.475188 75.903689 +-90.681709 75.917770 +-90.953942 75.915423 +-91.413922 75.755838 +-91.198013 75.894301 +-90.878844 75.960013 +-90.728646 76.009296 +-91.019654 76.035111 +-91.160464 76.084395 +-91.714317 76.124291 +-91.629831 76.201737 +-91.066590 76.126638 +-90.512737 76.072661 +-90.268666 76.107863 +-90.268666 76.107863 +# -b +-89.958884 76.283876 +-90.324990 76.335506 +-90.681709 76.342547 +-91.000879 76.403564 +-91.263724 76.429380 +-91.629831 76.462235 +-91.310661 76.466929 +-91.019654 76.462235 +-90.559674 76.441114 +-90.709871 76.551415 +-91.188626 76.631207 +-91.498408 76.671104 +-91.714317 76.682838 +-92.089810 76.649982 +-92.606114 76.614780 +-93.056707 76.596005 +-93.347714 76.518559 +-93.591785 76.427033 +-93.704433 76.450501 +-93.582398 76.539681 +-93.469750 76.671104 +-93.497912 76.802526 +-93.807694 76.945683 +-94.155025 76.931602 +-94.399096 76.908134 +-94.746428 76.994967 +-94.999886 76.211124 +-95.253344 76.354281 +-95.600676 76.391830 +-96.107592 76.586618 +-96.323501 76.654676 +-96.567572 76.678144 +-96.896129 76.722734 +-96.961840 76.816607 +-96.623896 76.781405 +-96.361050 76.793139 +-96.454924 76.818954 +-96.867967 76.896400 +-96.896129 76.992620 +-96.520635 77.009048 +-96.088818 77.086493 +-95.572514 77.081800 +-95.168858 77.025476 +-94.999886 77.030169 +# -b +-94.999886 75.657271 +-94.873157 75.619722 +-94.281754 75.511767 +-94.079927 75.420241 +-93.826468 75.340448 +-93.587091 75.234841 +-93.596479 75.126886 +-93.652803 75.023625 +-93.563623 74.763127 +-93.793613 74.636398 +-94.488276 74.636398 +-94.952949 74.704456 +-95.051516 74.711496 +-95.150083 74.772514 +-95.328443 74.819451 +-95.427010 74.781901 +-95.581901 74.812410 +-95.666387 74.873428 +-95.901071 74.861694 +-96.055962 74.990770 +-96.088818 75.056481 +-96.276564 74.957914 +-96.506554 75.126886 +-96.407987 75.216066 +-96.295339 75.279430 +-95.957395 75.305246 +-95.901071 75.349835 +-95.957395 75.429628 +-95.802504 75.457790 +-96.121673 75.457790 +-95.722711 75.469524 +-95.722711 75.582172 +-95.337830 75.666658 +-95.084372 75.690127 +# -b +-95.070291 74.073157 +-94.835608 74.110707 +-94.338079 74.091932 +-93.488524 74.171724 +-92.897122 74.110707 +-92.742231 74.094279 +-92.310413 73.955815 +-92.047567 74.019180 +-91.723704 74.019180 +-91.216788 73.993365 +-90.569061 73.915919 +-90.348459 73.871329 +-90.536206 73.692970 +-90.874150 73.568588 +-91.141689 73.540426 +-91.094752 73.416043 +-91.230869 73.272886 +-91.428003 73.197788 +-91.723704 72.951370 +-91.902064 72.857497 +-92.366737 72.704952 +-92.840798 72.723727 +-93.291390 72.796479 +-93.929729 72.749542 +-94.248899 72.714340 +-93.896874 72.672097 +-93.521380 72.460881 +-93.699739 72.357621 +-93.962585 72.256707 +-94.150332 72.146406 +-94.173800 72.078347 +-94.427258 72.007942 +-94.727653 72.005595 +-94.990499 71.986821 +-95.004580 72.014983 +-95.225182 72.029064 +-94.952949 72.144059 +-95.215795 72.183955 +-95.225182 72.406904 +-94.938868 72.559449 +-95.281506 72.557102 +-95.525577 72.653322 +-95.591288 72.754236 +-95.689856 72.911474 +-95.680468 73.047590 +-95.600676 73.134423 +-95.624144 73.235337 +-95.657000 73.406656 +-95.666387 73.589709 +-95.713324 73.700010 +-95.511496 73.793884 +-95.290894 73.742253 +-95.150083 73.707051 +-94.859076 73.624912 +-94.713572 73.667155 +-94.990499 73.730519 +-95.037435 73.840820 +-95.272119 73.866636 +-95.403542 73.955815 +-95.281506 74.044995 +-95.070291 74.073157 +# -b +-94.999886 71.937537 +-94.877851 71.939884 +-94.507051 71.895294 +-94.624392 71.775606 +-94.450727 71.714588 +-94.216043 71.773259 +-93.732595 71.747444 +-93.709127 71.529188 +-93.159967 71.336747 +-92.939365 71.104411 +-92.948752 70.848606 +-92.793861 70.785241 +-92.474691 70.667899 +-92.333881 70.588107 +-92.146134 70.400360 +-92.066342 70.273631 +-91.911451 70.341689 +-91.747173 70.193839 +-91.573507 70.121087 +-91.892676 70.102312 +-92.333881 70.175064 +-92.441836 70.107006 +-92.155522 70.050682 +-92.155522 70.050682 +# -b +-89.958884 71.308585 +-90.113775 71.529188 +-90.127856 71.651223 +# -b +-89.949497 71.761525 +-90.071532 72.054879 +-90.071532 72.054879 +# -b +-89.970618 72.169874 +-90.045717 72.367008 +# -b +-110.068914 72.540674 +-109.979735 72.564142 +# -b +-110.003203 72.653322 +-109.914023 72.695565 +# -b +-110.068914 72.974838 +-109.824844 72.890352 +-109.627709 72.859843 +-109.341395 72.747195 +-109.120793 72.707299 +-109.041001 72.625160 +-108.712444 72.524246 +-108.712444 72.294256 +-108.566940 72.106509 +-108.383887 71.984474 +-108.402661 71.796727 +-108.304094 71.728669 +-108.027168 71.655917 +-107.886358 71.721628 +-107.576575 71.855398 +-107.534332 71.961006 +-107.684530 72.132325 +-107.853502 72.327112 +-107.830034 72.397517 +-107.905132 72.564142 +-107.961456 72.711993 +-108.125735 72.911474 +-108.149203 73.024122 +-108.271239 73.150851 +-107.975537 73.209522 +-108.083492 73.308089 +-107.830034 73.322170 +-107.553107 73.270540 +-107.003948 73.160238 +-106.891300 73.190747 +-107.022722 73.270540 +-106.736408 73.254112 +-106.548662 73.200135 +-106.384383 73.075752 +-105.943178 72.995960 +-105.703801 72.918514 +-105.525442 72.841069 +-105.445649 72.737808 +-105.337695 72.655669 +-105.304839 72.510165 +-105.215659 72.411598 +-105.159335 72.327112 +-105.093624 72.151099 +-105.018525 71.993861 +-104.929345 71.862438 +-104.511609 71.674692 +-104.445897 71.540922 +-104.380186 71.400112 +-104.544464 71.308585 +-104.600789 71.153694 +-104.267538 71.015231 +-103.981224 70.839218 +-103.638586 70.768813 +-103.394515 70.632697 +-103.089427 70.583413 +-102.943923 70.679634 +-102.681077 70.566985 +-102.183548 70.405054 +-101.587452 70.308834 +-101.512353 70.158636 +-101.179103 70.151596 +-100.902176 70.092925 +-100.859933 70.013132 +# -b +-104.973935 73.080446 +-104.734558 73.261152 +-104.589054 73.519304 +-104.753333 73.608484 +-105.250862 73.742253 +-105.804715 73.725826 +-106.433667 73.723479 +-106.818548 73.589709 +-106.982826 73.441859 +-106.583864 73.387881 +-106.245920 73.279927 +-105.959606 73.160238 +-105.739004 73.014735 +-105.363510 72.883312 +-105.218006 72.927902 +-104.988016 73.047590 +-104.973935 73.080446 +# -b +-99.989258 71.881213 +-100.191085 72.007942 +-100.444544 72.106509 +-100.716776 72.137018 +-101.017171 72.153446 +-101.500619 72.228545 +-101.711834 72.345887 +-102.120184 72.477309 +-102.429966 72.641588 +-102.340786 72.899740 +-101.941824 72.953717 +-101.655510 72.876271 +-101.580412 72.796479 +-101.280017 72.747195 +-101.139207 72.604038 +-100.641678 72.648628 +-100.388219 72.653322 +-100.275571 72.773011 +-100.111293 72.805866 +-100.101906 72.934942 +-100.313121 72.998307 +-100.430463 73.146157 +-100.101906 73.146157 +-100.003339 73.120342 +# -b +-99.890690 73.129729 +-100.289652 73.303395 +-100.552498 73.207175 +-101.040640 73.251765 +-101.369197 73.427778 +-100.984316 73.484102 +-100.632290 73.380841 +-100.651065 73.526345 +-100.993703 73.585015 +-101.228386 73.653074 +-100.885749 73.761028 +-100.486787 73.735213 +-100.191085 73.690623 +-100.299040 73.772762 +-100.275571 73.864289 +-100.092518 73.885410 +# -b +-99.775696 74.997810 +-100.446890 75.025972 +-100.587700 75.112805 +-100.667493 75.225453 +-100.390566 75.241881 +-100.291999 75.279430 +-100.348323 75.349835 +-100.723817 75.373304 +-100.554845 75.422587 +-100.620556 75.467177 +-100.179351 75.495339 +-100.062009 75.518808 +# -b +-99.850794 75.549316 +-100.202819 75.549316 +-100.047928 75.593906 +# -b +-99.841407 75.734716 +-100.310774 75.706554 +-100.611169 75.694820 +-101.010131 75.650230 +-101.502966 75.647884 +-101.789280 75.626762 +-102.211710 75.577478 +-102.507412 75.537582 +-102.826581 75.636149 +-102.699852 75.683086 +-102.390070 75.722982 +-102.174161 75.739410 +-102.343133 75.795734 +-101.948865 75.898995 +-101.610921 75.828590 +-101.179103 75.795734 +-101.319913 75.802775 +-101.507660 75.896648 +-101.432561 76.016337 +-101.873766 75.997562 +-102.023964 76.168881 +-102.221098 76.222858 +-102.136612 76.375402 +-101.995802 76.455195 +-101.639083 76.462235 +-101.423174 76.450501 +-101.376237 76.405911 +-101.197878 76.363668 +-101.207265 76.288570 +-100.812997 76.164187 +-100.625250 76.138372 +-100.625250 76.091435 +-100.137108 75.990521 +-100.099559 75.978787 +# -b +-99.972830 76.042152 +-100.235675 76.192349 +-100.094865 76.204083 +# -b +-99.939974 76.204083 +-100.446890 76.227552 +-100.334242 76.288570 +-100.259144 76.342547 +-100.719123 76.384790 +-101.075842 76.499785 +-100.794222 76.600699 +-100.296693 76.657023 +-100.033847 76.645288 +# -b +-100.050275 78.736319 +-100.069050 78.731625 +-100.031501 78.724584 +# -b +-99.939974 77.835134 +-100.259144 77.849215 +-100.681574 77.914926 +-100.869321 78.039309 +-100.869321 78.126141 +-101.075842 78.222362 +-101.376237 78.203587 +-101.554597 78.271645 +-102.042738 78.297460 +-102.643528 78.271645 +-102.859437 78.384293 +-103.432065 78.325622 +-103.816946 78.278686 +-104.070404 78.245830 +-104.605482 78.306848 +-104.830778 78.363172 +-104.980976 78.461739 +-104.896490 78.550919 +-104.445897 78.553265 +-103.901432 78.518063 +-103.535325 78.548572 +-103.816946 78.604896 +-103.807558 78.656526 +-103.507163 78.764481 +-103.741847 78.757440 +-103.901432 78.783255 +-104.229989 78.757440 +-104.192439 78.832539 +-104.061016 78.870088 +-104.154890 78.971002 +-104.530383 78.935800 +-104.736905 78.816111 +-105.056075 78.806724 +-104.943426 78.874782 +-104.802616 78.956921 +-105.027913 79.022632 +-105.638090 78.989777 +-105.703801 79.076610 +-105.713188 79.186911 +-105.544216 79.294865 +-104.802616 79.297212 +-104.220601 79.348843 +-103.779396 79.294865 +-103.629199 79.278437 +-103.328804 79.189258 +-103.385128 79.020286 +-103.141057 78.954574 +-103.065958 79.088344 +-102.718627 79.198645 +-102.239872 79.165789 +-101.883153 79.060182 +-101.695407 79.095384 +-101.601533 78.938146 +-101.451336 78.870088 +-101.141554 78.914678 +-100.784835 78.926412 +-100.493827 78.893557 +-100.249756 78.830192 +-100.287306 78.738665 +-100.071397 78.745706 +-100.052622 78.736319 +# -b +-101.991108 77.947782 +-101.765812 77.966557 +-101.089923 77.790544 +-101.718875 77.760035 +-102.319665 77.795238 +-102.610672 77.912579 +-102.113143 77.950129 +-101.991108 77.947782 +# -b +-105.023219 77.572288 +-104.966895 77.461987 +-104.769761 77.426785 +-104.572627 77.365767 +-104.356718 77.323524 +-104.450591 77.271893 +-104.272232 77.199142 +-104.582014 77.109962 +-105.135867 77.170980 +-105.351776 77.300055 +-105.605234 77.443212 +-105.699107 77.544126 +-105.839917 77.668509 +-105.971340 77.764729 +-105.577072 77.738914 +-105.173416 77.633306 +-105.023219 77.572288 +-105.023219 77.572288 +# -b +-104.009386 76.603045 +-103.896738 76.628861 +-103.586956 76.523253 +-103.173913 76.450501 +-103.202075 76.356628 +-103.662054 76.316732 +-104.131422 76.319078 +-104.103259 76.351934 +-104.375492 76.394177 +-104.413042 76.499785 +-104.572627 76.504478 +-104.694662 76.556109 +-104.544464 76.628861 +-103.999999 76.673450 +-103.999999 76.614780 +-104.009386 76.603045 +# -b +-101.021865 76.739162 +-100.749632 76.764977 +-100.674533 76.687532 +-101.322260 76.563149 +-101.688366 76.581924 +-101.294098 76.680491 +-101.021865 76.739162 +-101.021865 76.739162 +# -b +-103.028409 76.323772 +-102.925148 76.323772 +-102.577817 76.248673 +-102.859437 76.114904 +-103.516551 76.060927 +-103.995305 76.058580 +-104.145503 76.058580 +-104.464672 76.140719 +-104.417735 76.239286 +-103.723072 76.272142 +-103.225543 76.321425 +-103.028409 76.323772 +# -b +-103.049531 76.070314 +-102.777298 76.100823 +-102.392417 76.079701 +-102.730361 75.983481 +-103.500123 75.922463 +-103.931941 75.906035 +-103.753581 75.976440 +-103.199728 76.051539 +-103.049531 76.070314 +# -b +-103.061265 75.917770 +-102.864131 75.955319 +-102.422926 75.995215 +-102.122531 75.950625 +-102.526186 75.842671 +-102.742095 75.784000 +-103.136363 75.748797 +-103.399209 75.805121 +-103.145751 75.908382 +-103.061265 75.917770 +# -b +-104.086832 75.446056 +-103.955409 75.420241 +-103.777049 75.284124 +-103.791130 75.103418 +-104.471713 75.075256 +-104.903530 75.180863 +-104.640685 75.373304 +-104.232335 75.453096 +-104.086832 75.446056 +# -b +-110.043099 76.506825 +-109.705155 76.556109 +-109.564345 76.682838 +-109.357823 76.816607 +-108.794583 76.854157 +-108.531737 76.743856 +-108.728872 76.649982 +-108.597449 76.532640 +-108.512963 76.431726 +-108.128082 76.347240 +-108.137469 76.262754 +-108.325216 76.164187 +-108.578674 76.098476 +-108.362765 76.072661 +-108.043596 76.082048 +-107.696264 76.032765 +-107.696264 75.936544 +-108.024821 75.847365 +-107.799525 75.896648 +-107.330158 75.920116 +-107.086087 75.861446 +-106.870178 75.704208 +-106.682431 75.814509 +-106.851403 75.969400 +-106.475910 76.053886 +-106.091029 76.032765 +-105.565338 75.849711 +-105.443302 75.706554 +-105.673292 75.530542 +-105.781247 75.331061 +-105.978381 75.155048 +-106.288163 75.072909 +-106.565090 75.037706 +-107.217510 74.943833 +-107.644634 75.009544 +-107.776056 75.098724 +-108.118694 74.971995 +-108.681935 74.979036 +-108.583368 75.035360 +-108.780502 75.122192 +-109.090284 75.009544 +-109.508021 74.925058 +-109.949226 74.887509 +# -b +-110.064221 75.577478 +-109.148955 75.535235 +-108.914271 75.622068 +-108.975289 75.767572 +-109.092631 75.849711 +-109.294459 75.906035 +-109.341395 75.936544 +-109.102018 76.039805 +-109.205279 76.206430 +-109.407107 76.253367 +-109.449350 76.262754 +# -b +-110.075955 78.093286 +-109.869433 77.964210 +-109.963307 77.929007 +# -b +-110.019631 78.604896 +-109.738011 78.574387 +-109.550264 78.478167 +-109.503327 78.377253 +-109.935145 78.290420 +-109.935145 78.290420 +# -b +-120.017148 72.230892 +-119.665123 72.294256 +-119.355341 72.406904 +-119.237999 72.564142 +-118.848425 72.740155 +-118.397832 72.838722 +-117.726637 72.986573 +-117.337063 73.054631 +-116.942794 73.162585 +-116.356086 73.279927 +-115.849169 73.355026 +-115.652035 73.401962 +-115.389190 73.521651 +-115.661422 73.655421 +-116.060384 73.770415 +-116.656481 73.955815 +-116.952182 74.073157 +-117.416855 74.218661 +-117.989483 74.284372 +-118.562111 74.277332 +-119.026784 74.171724 +-119.026784 74.030914 +-119.158207 74.098972 +-119.191063 74.216314 +-119.557169 74.195193 +-119.754303 74.080198 +-119.852870 74.152950 +-119.777771 74.242129 +-119.909194 74.265598 +# -b +-117.369918 69.952115 +-117.041362 70.092925 +-115.994673 70.226694 +-115.253073 70.285365 +-114.624121 70.327608 +-113.976395 70.311180 +-113.014192 70.271284 +-112.554213 70.252510 +-112.418096 70.367505 +-112.098927 70.374545 +-112.366466 70.491887 +-112.807671 70.557598 +-113.291119 70.599841 +-113.666613 70.656165 +-113.943539 70.686674 +-114.436375 70.653818 +-114.858805 70.609229 +-115.389190 70.555251 +-115.652035 70.569332 +-116.126096 70.599841 +-116.609544 70.609229 +-117.238496 70.660859 +-117.590521 70.674940 +-117.834592 70.733611 +-118.111518 70.869727 +-118.144374 71.078596 +-117.557665 71.202978 +-116.928713 71.259302 +-116.290374 71.357869 +-116.069772 71.341441 +-115.774071 71.400112 +-116.027529 71.435314 +-115.675504 71.482251 +-115.717747 71.536228 +-116.323230 71.486945 +-116.844227 71.447049 +-117.318288 71.414193 +-117.571746 71.463477 +-117.571746 71.397765 +-117.834592 71.397765 +-118.252328 71.390725 +-118.111518 71.519801 +-117.834592 71.569084 +-117.956627 71.651223 +-118.454156 71.599593 +-118.717002 71.655917 +-118.970460 71.686426 +-118.970460 71.961006 +-118.618435 72.113550 +-118.120906 72.223851 +-118.200698 72.334152 +-118.496399 72.371702 +-118.233554 72.625160 +-117.515422 72.857497 +-116.844227 72.993613 +-116.388941 73.115648 +-115.792845 73.190747 +-114.891661 73.326864 +-114.483311 73.336251 +-114.295564 73.242378 +-114.107818 73.066365 +-114.117205 72.850456 +-114.426987 72.765970 +-114.483311 72.674443 +-114.746157 72.615773 +-114.417600 72.620466 +-114.065575 72.681484 +-113.844972 72.648628 +-113.708856 72.770664 +-113.455397 72.951370 +-113.347443 73.012388 +-112.906238 72.988919 +-112.455646 72.918514 +-111.859550 72.812907 +-111.502831 72.747195 +-111.305696 72.580570 +-111.638947 72.430373 +-111.990972 72.315378 +-111.723433 72.334152 +-111.493443 72.423332 +-111.315084 72.420985 +-111.418345 72.345887 +-111.197742 72.322418 +-111.061626 72.451494 +-110.808167 72.564142 +-110.620421 72.559449 +-110.413899 72.554755 +-110.291864 72.503124 +-110.226152 72.559449 +-110.160441 72.559449 +-110.071261 72.540674 +# -b +-109.982081 72.564142 +-110.235540 72.665056 +-110.113504 72.681484 +-110.005550 72.653322 +# -b +-109.916370 72.695565 +-110.146360 72.775357 +-110.446755 72.876271 +-110.390431 72.995960 +-110.071261 72.974838 +# -b +-110.052487 76.502132 +-110.043099 76.518559 +-110.043099 76.506825 +# -b +-109.953919 74.887509 +-110.427980 74.840572 +-110.648583 74.772514 +-110.836329 74.704456 +-110.991221 74.666906 +-111.376102 74.598848 +-112.061377 74.500281 +-112.657474 74.446304 +-113.507028 74.462732 +-114.023332 74.547218 +-114.398825 74.650479 +-114.398825 74.774861 +-113.849666 74.871081 +-113.427235 74.864041 +-113.089291 75.018932 +-112.183413 75.049441 +-111.742208 74.993117 +-111.432426 75.103418 +-111.014689 75.263003 +-111.455894 75.201985 +-112.028522 75.183210 +-112.380547 75.270043 +-112.657474 75.279430 +-112.920319 75.133927 +-113.361524 75.115152 +-114.046800 75.103418 +-113.783954 75.211372 +-113.868440 75.366263 +-113.563352 75.457790 +-114.070268 75.439015 +-114.309645 75.241881 +-114.610040 75.255962 +-114.586572 75.101071 +-114.872886 75.009544 +-115.206136 75.185557 +-115.633260 75.145661 +-115.853863 75.004851 +-116.163645 75.140967 +-116.539139 75.206679 +-117.003812 75.171476 +-117.707863 75.277084 +-117.496648 75.434322 +-116.792597 75.518808 +-116.121402 75.504727 +-115.459595 75.633803 +-115.206136 75.734716 +-116.173033 75.600947 +-117.013200 75.572785 +-117.238496 75.795734 +-116.844227 75.814509 +-116.464040 75.866139 +-116.238744 75.880220 +-116.215276 75.922463 +-116.539139 75.896648 +-116.947488 75.870833 +-117.111767 75.950625 +-117.017893 76.049192 +-116.844227 76.213471 +-116.520364 76.208777 +-116.257519 76.187656 +-116.163645 76.199390 +-116.506283 76.258061 +-116.684643 76.344894 +-116.384248 76.481010 +-116.135483 76.513866 +-115.806926 76.445807 +-115.844476 76.330813 +-115.684891 76.218164 +-115.417352 76.279182 +-115.187362 76.225205 +-114.962066 76.147759 +-114.793093 75.999909 +-114.685139 75.924810 +-114.713301 75.833284 +-114.488005 75.856752 +-114.488005 75.741757 +-114.422294 75.629109 +-114.150061 75.554010 +-113.929458 75.586866 +-113.497641 75.598600 +-113.047048 75.577478 +# -b +-109.986775 76.262754 +-110.399818 76.389483 +-110.381043 76.459888 +-110.052487 76.502132 +-110.052487 76.502132 +# -b +-118.059888 76.049192 +-118.041113 76.049192 +-117.581134 76.112557 +-117.843979 75.870833 +-118.031726 75.720635 +-118.477625 75.523501 +-119.083108 75.584519 +-119.406971 75.732370 +-118.834344 75.896648 +-118.289878 76.032765 +-118.139680 76.049192 +# -b +-120.045311 77.041904 +-119.688592 77.145164 +-119.406971 77.229650 +-119.209837 77.314136 +-118.853118 77.358726 +-118.515174 77.344645 +-118.027032 77.372807 +-117.914384 77.262506 +-117.726637 77.316483 +-117.388693 77.321177 +-116.900551 77.356380 +-117.210334 77.400969 +-117.135235 77.469028 +-116.675255 77.548820 +-116.337311 77.487802 +-116.027529 77.419744 +-115.642648 77.323524 +-115.755296 77.255466 +-116.168339 77.196795 +-116.496896 77.175673 +-116.571995 77.119349 +-116.252825 76.997314 +-116.055691 76.901094 +-116.496896 76.905787 +-116.243438 76.795486 +-116.243438 76.647635 +-116.816065 76.572537 +-117.182172 76.490397 +-117.210334 76.300304 +-117.679701 76.281529 +-118.083356 76.445807 +-118.036420 76.654676 +-118.008258 76.811914 +-118.468237 76.736815 +-118.477625 76.654676 +-118.646597 76.504478 +-118.975154 76.539681 +-118.853118 76.462235 +-118.665371 76.349587 +-119.012703 76.173575 +-119.237999 76.121944 +-119.547781 76.368362 +-119.782465 76.304997 +-119.688592 76.187656 +-119.791852 76.138372 +-119.641655 76.011643 +-119.810627 75.903689 +-119.970212 75.880220 +# -b +-114.154754 76.891706 +-113.863747 76.865891 +-113.647838 76.807220 +-113.844972 76.729775 +-114.276790 76.729775 +-114.755544 76.748549 +-114.520861 76.870585 +-114.154754 76.891706 +# -b +-112.094233 78.034615 +-111.972198 78.032268 +-111.502831 78.074511 +-111.155499 78.053390 +-110.836329 78.090939 +-110.244927 78.095633 +-110.075955 78.093286 +# -b +-109.965654 77.929007 +-110.341147 77.903192 +-110.782352 77.877377 +-111.148459 77.851562 +-111.063972 77.816359 +-111.477015 77.802278 +-111.542727 77.750648 +-111.383142 77.743607 +-111.261107 77.757688 +-111.063972 77.724833 +-110.876226 77.767076 +-110.341147 77.774116 +-110.266049 77.663815 +-110.331760 77.525352 +-110.726028 77.459640 +-111.204783 77.424438 +-111.674150 77.393929 +-112.331263 77.346992 +-112.687982 77.452600 +-113.241835 77.494843 +-113.335709 77.612185 +-113.438970 77.741260 +-113.429582 77.872683 +-113.063476 77.917273 +-112.669208 77.978291 +-112.359425 78.018187 +-112.143517 78.025228 +-112.096580 78.034615 +# -b +-115.070020 77.940741 +-114.957372 77.954822 +-114.816562 78.006453 +-114.488005 78.020534 +-114.450456 77.957169 +-114.103124 77.884417 +-113.802729 77.814012 +-114.046800 77.717792 +-114.478618 77.722486 +-114.863499 77.846868 +-115.060633 77.905539 +-115.126344 77.943088 +-115.070020 77.940741 +# -b +-110.129932 78.630711 +-110.017284 78.604896 +-110.017284 78.604896 +# -b +-109.932798 78.290420 +-110.411552 78.285726 +-111.012342 78.325622 +-111.397223 78.405415 +-111.538033 78.365519 +-111.538033 78.271645 +-111.913527 78.259911 +-112.232696 78.346744 +-112.598803 78.381946 +-112.645739 78.353784 +-112.927360 78.330316 +-112.974296 78.288073 +-113.349790 78.271645 +-113.434276 78.351438 +-113.077557 78.461739 +-112.842874 78.471126 +-112.533091 78.522757 +-112.101274 78.541531 +-111.594357 78.583774 +-111.369061 78.679995 +-111.059279 78.698769 +-110.702560 78.731625 +-110.505426 78.703463 +-110.251968 78.672954 +-110.129932 78.630711 +-110.129932 78.630711 +# -b +-130.141395 70.074150 +-129.855081 70.207920 +-129.559380 70.146902 +-129.615704 70.020173 +-129.615704 70.020173 +# -b +-128.421165 69.949768 +-128.299130 70.118740 +-127.815682 70.184451 +-127.979960 70.257203 +-128.055059 70.381586 +-128.266274 70.447297 +-127.881393 70.503621 +-127.341621 70.292406 +-127.163261 70.036601 +-127.163261 70.036601 +# -b +-124.858669 69.989664 +-124.914993 70.001398 +# -b +-125.189573 69.942727 +-125.091006 70.048335 +-124.762449 70.027213 +-124.762449 70.027213 +# -b +-124.703778 69.961502 +-124.506644 70.064763 +-124.736634 70.114046 +-124.459707 70.095272 +-124.426852 70.001398 +# -b +-124.286042 74.016833 +-124.009115 73.915919 +-124.074826 73.793884 +-124.286042 73.603790 +-124.506644 73.465327 +-124.661535 73.326864 +-124.769490 73.218909 +-124.990092 73.134423 +-124.778877 73.045243 +-124.670923 72.960757 +-125.055804 72.909127 +-125.187226 72.848109 +-125.112128 72.756583 +-125.088659 72.655669 +-125.299874 72.535980 +-125.389054 72.500778 +-125.506396 72.402211 +-125.586188 72.303643 +-125.576801 72.261400 +-125.764548 72.230892 +-125.741079 72.181608 +-125.708224 72.078347 +-125.985150 71.975087 +-125.595576 71.963352 +-125.102740 71.956312 +-125.220082 71.916416 +-124.792958 71.810808 +-124.623986 71.862438 +-124.516031 71.792033 +-124.041971 71.695813 +-123.732188 71.486945 +-123.469343 71.214712 +-123.014057 71.111451 +-122.497753 71.256955 +-122.065936 71.386031 +-121.803090 71.519801 +-121.648199 71.407152 +-121.272705 71.407152 +-121.084958 71.461130 +-120.690690 71.543269 +-120.502943 71.738056 +-120.535799 71.916416 +-120.371521 72.085388 +-120.258873 72.263747 +-120.014802 72.230892 +-120.014802 72.230892 +# -b +-119.906847 74.265598 +-120.423151 74.343043 +-120.812726 74.462732 +-121.075571 74.551912 +-121.526163 74.591808 +-121.835946 74.547218 +-122.098791 74.549565 +-122.497753 74.521403 +-122.882634 74.509669 +-123.136092 74.481506 +-123.093849 74.373552 +-123.234659 74.441610 +-123.413019 74.453344 +-123.666477 74.490894 +-123.919935 74.469772 +-124.187475 74.441610 +-124.703778 74.401714 +-124.525419 74.289066 +-124.450320 74.211620 +-124.351753 74.056729 +-124.286042 74.016833 +# -b +-120.132143 77.011395 +-120.047657 77.041904 +-120.047657 77.041904 +# -b +-119.967865 75.880220 +-120.277647 75.941238 +-120.521718 75.903689 +-120.681303 76.018683 +-120.793951 76.190002 +-121.094346 76.100823 +-121.263318 75.950625 +-121.789009 76.032765 +-121.864108 76.107863 +-121.995531 76.063273 +-122.389799 75.950625 +-122.699581 75.992868 +-122.483672 76.168881 +-122.934265 76.194696 +-122.662032 76.279182 +-122.380411 76.427033 +-121.845333 76.424686 +-121.601262 76.459888 +-121.291480 76.603045 +-121.225769 76.671104 +-120.915986 76.711000 +-120.606204 76.776711 +-120.409070 76.858850 +-120.211936 76.987926 +-120.127450 77.011395 +# -b +-131.023805 69.970889 +-130.751572 70.118740 +-130.451177 70.139861 +-130.141395 70.074150 +-130.141395 70.074150 +# -b +-150.157552 70.423829 +-149.570843 70.496580 +-148.923117 70.426175 +-148.557010 70.346383 +-148.106418 70.315874 +-147.796636 70.252510 +-147.355431 70.203226 +-146.839127 70.158636 +-146.196094 70.177411 +-145.670403 70.062416 +-145.294910 70.048335 +-145.327765 70.008439 +# -b +-144.952272 69.982624 +-144.919416 70.024867 +# -b +-144.611981 69.982624 +-144.381991 70.050682 +-144.250568 70.055375 +-143.785895 70.102312 +-143.485500 70.050682 +-143.311834 70.102312 +-142.870629 70.064763 +-142.560847 70.006092 +# -b +-160.061196 70.290059 +-159.873449 70.367505 +-159.727946 70.473112 +-159.662234 70.496580 +-159.896918 70.602188 +# -b +-160.105786 70.649125 +-159.885184 70.745345 +-159.181133 70.893196 +-159.336024 70.841565 +-159.443979 70.759426 +-159.223376 70.667899 +-159.101341 70.773507 +-158.815027 70.773507 +-158.373822 70.832178 +-157.834050 70.869727 +-157.482024 70.982375 +-157.294278 71.085636 +-157.162855 71.141960 +-157.031432 71.207671 +-156.951640 71.238180 +-156.810830 71.315626 +-156.646551 71.315626 +-156.280445 71.273383 +-156.083311 71.163082 +-155.651493 71.172469 +-155.576394 71.052780 +-155.881483 70.961254 +-156.214734 70.949520 +-156.303913 70.855646 +-155.947194 70.799322 +-155.684349 70.775854 +-155.454359 70.728917 +-155.299468 70.841565 +-155.308855 71.038699 +-155.069478 71.057474 +-154.759696 71.071555 +-154.647048 70.879115 +-154.219924 70.806363 +-153.820962 70.900236 +-153.600359 70.879115 +-153.234253 70.935439 +-152.915083 70.808710 +-152.717949 70.775854 +-152.473878 70.867380 +-152.145321 70.752385 +-152.056142 70.620963 +-152.356537 70.574026 +-151.779215 70.555251 +-151.736972 70.456684 +-151.065777 70.447297 +-150.511924 70.503621 +-150.183367 70.440256 +-150.159899 70.423829 +-150.159899 70.423829 +# -b +-162.532414 69.970889 +-162.457315 70.031907 +-162.293037 70.017826 +# -b +-161.903462 69.956808 +-162.203857 70.137515 +-161.894075 70.285365 +-161.903462 70.245469 +-161.983254 70.132821 +-161.617148 70.219654 +-161.067989 70.315874 +-160.579847 70.440256 +-160.734738 70.456684 +-160.237209 70.583413 +-160.030687 70.508315 +-160.227822 70.329955 +-160.063543 70.290059 +# -b +-159.896918 70.602188 +-160.028341 70.616269 +-160.103439 70.649125 +# -b +-179.000000 71.549461 +-178.711495 71.498679 +-178.195191 71.447049 +-178.162336 71.376644 +-177.829085 71.285117 +-177.664807 71.111451 +-178.228047 71.001150 +-178.603541 70.970641 +-179.000000 70.924468 +-179.000000 70.924468 +# -b +170.415433 69.930993 +170.833170 70.055375 +171.330699 70.017826 +# -b +179.000000 70.853299 +178.751576 70.874421 +178.554442 70.970641 +178.718721 71.141960 +179.000000 71.268997 +179.000000 71.268997 +# -b +159.922733 70.451991 +160.044768 70.299446 +160.044768 70.226694 +# -b +168.099107 69.994358 +168.474600 70.020173 +168.474600 70.020173 +# -b +149.965112 72.017330 +150.040210 71.843664 +150.040210 71.843664 +# -b +149.920522 71.653570 +150.328871 71.545616 +150.662122 71.437661 +151.211281 71.421233 +151.652486 71.393071 +152.004511 71.254608 +152.337762 71.078596 +151.783909 70.970641 +152.304906 70.888502 +152.732030 70.834525 +153.187316 70.881461 +153.384450 70.907277 +153.858511 70.916664 +154.341959 70.897889 +154.618886 70.963601 +155.224369 70.935439 +155.764141 70.977682 +156.285139 71.005844 +156.946946 71.012884 +157.650997 71.012884 +158.359741 70.968294 +158.998080 70.874421 +159.350105 70.740651 +159.725599 70.602188 +159.922733 70.451991 +159.922733 70.451991 +# -b +160.044768 70.226694 +159.979057 70.165677 +159.922733 70.095272 +# -b +149.887666 75.201985 +150.352339 75.138620 +151.089246 75.096377 +150.924967 74.927405 +150.155205 74.753739 +150.033170 74.732618 +# -b +139.984022 71.442355 +140.040346 71.493985 +140.030958 71.564390 +# -b +139.906576 72.094775 +140.366556 72.183955 +140.690419 72.397517 +141.009589 72.557102 +141.009589 72.641588 +140.831229 72.780051 +141.281822 72.819947 +141.549361 72.749542 +141.976485 72.709646 +142.197087 72.700259 +142.896444 72.693218 +143.534783 72.690871 +144.248221 72.660362 +144.825543 72.589957 +145.520206 72.552408 +145.905087 72.519552 +146.346292 72.430373 +146.745254 72.374049 +146.135077 72.371702 +145.693872 72.420985 +144.825543 72.467922 +144.417193 72.486697 +144.459436 72.327112 +144.248221 72.169874 +144.623715 72.125284 +145.421639 72.172221 +146.003654 72.270788 +146.566894 72.317724 +146.623218 72.207423 +146.069365 71.921109 +145.895699 72.045492 +145.905087 72.207423 +146.158545 72.162833 +145.848763 72.214464 +145.693872 72.003249 +145.440413 71.918763 +144.999208 71.939884 +145.266748 71.874173 +145.233892 71.820195 +144.877173 71.749790 +144.999208 71.623061 +145.252667 71.585512 +145.585917 71.686426 +146.003654 71.834276 +146.510570 71.972740 +146.745254 72.193342 +147.040955 72.301297 +147.538484 72.367008 +148.031319 72.359968 +148.134580 72.343540 +148.486605 72.364661 +148.960666 72.277828 +149.444114 72.223851 +149.852463 72.085388 +149.965112 72.017330 +# -b +150.042557 71.843664 +149.690532 71.846011 +149.347894 71.874173 +149.005256 71.709894 +149.235246 71.674692 +149.667064 71.646530 +149.920522 71.653570 +# -b +139.960553 75.793387 +140.336047 75.802775 +140.270336 75.720635 +140.232786 75.650230 +140.509713 75.598600 +140.786639 75.607987 +140.828882 75.732370 +140.781946 75.812162 +140.772558 76.009296 +141.082341 76.079701 +141.542320 76.006949 +141.908427 75.873180 +142.096173 75.734716 +142.410649 75.647884 +142.222902 75.492992 +142.072705 75.361570 +142.302695 75.159742 +142.753287 75.056481 +143.260204 74.981382 +143.095925 74.913324 +142.457586 74.955567 +142.213515 74.845266 +141.805166 74.976689 +141.762923 75.072909 +141.209070 74.962608 +140.514407 74.847613 +139.998103 74.795982 +# -b +141.328758 76.143066 +141.619766 76.105516 +142.107908 75.974094 +142.502176 75.852058 +143.121740 75.845018 +143.638044 75.873180 +144.088636 75.744104 +144.520454 75.678392 +144.985127 75.607987 +145.379396 75.530542 +145.205730 75.500033 +144.849011 75.453096 +144.661264 75.385038 +144.675345 75.239534 +144.299852 75.089337 +143.670900 75.054134 +142.732166 75.138620 +142.323816 75.403813 +142.502176 75.598600 +142.694616 75.769919 +142.356672 75.842671 +142.018728 75.955319 +141.671396 76.058580 +141.399163 76.138372 +141.371001 76.143066 +# -b +146.292315 75.558704 +146.569241 75.514114 +146.888411 75.422587 +147.573687 75.415547 +148.221413 75.375651 +148.596907 75.331061 +148.221413 75.251268 +148.916076 75.255962 +149.380750 75.274737 +149.887666 75.201985 +149.887666 75.201985 +# -b +150.030823 74.732618 +149.622474 74.732618 +149.345547 74.737312 +148.660271 74.831185 +147.956221 74.908630 +147.439917 74.997810 +147.064423 75.117499 +146.721785 75.342795 +146.257112 75.523501 +146.289968 75.558704 +146.289968 75.558704 +# -b +140.953265 74.138869 +140.521447 74.307841 +140.080242 74.159990 +140.145953 74.002752 +140.479204 73.892451 +140.390024 73.946428 +140.699806 73.988671 +140.896941 74.033261 +140.915715 74.098972 +140.953265 74.138869 +# -b +141.328758 73.892451 +141.516505 73.899491 +141.943629 73.922960 +142.497482 73.838474 +143.060723 73.667155 +143.422135 73.453593 +143.511315 73.225950 +142.938687 73.232990 +142.398915 73.279927 +141.746495 73.352679 +140.887553 73.418390 +140.028612 73.362066 +140.028612 73.362066 +# -b +139.784541 73.472367 +140.399412 73.521651 +140.742050 73.768069 +140.953265 73.887757 +141.328758 73.892451 +141.328758 73.892451 +# -b +139.972288 72.472616 +140.178809 72.460881 +140.676338 72.489043 +140.587158 72.359968 +140.446348 72.294256 +140.347781 72.270788 +140.136566 72.237932 +# -b +129.946608 71.038699 +130.232922 71.012884 +130.462912 70.895542 +130.838405 70.862687 +130.993296 70.848606 +131.213899 70.707796 +131.580005 70.855646 +131.899175 71.139613 +132.007129 71.367256 +132.218344 71.625408 +132.514046 71.874173 +132.758116 71.949271 +132.903620 71.747444 +133.157078 71.646530 +133.419924 71.522147 +133.837661 71.400112 +134.358658 71.409499 +134.720071 71.378990 +134.776395 71.451742 +135.020465 71.618368 +135.583706 71.639489 +136.057767 71.543269 +136.508359 71.522147 +136.728961 71.486945 +137.245265 71.395418 +137.634840 71.282770 +137.855442 71.184203 +138.273179 71.177163 +138.582961 71.332054 +138.756627 71.381337 +138.977229 71.400112 +139.333948 71.402459 +139.451290 71.512760 +139.981675 71.442355 +139.981675 71.442355 +# -b +140.028612 71.564390 +139.728217 71.738056 +139.883108 71.853051 +139.751685 71.984474 +139.906576 72.094775 +# -b +136.013177 74.054382 +136.182149 73.998058 +136.215005 73.876023 +135.750331 74.028567 +135.417081 74.169377 +135.684620 74.148256 +136.013177 74.054382 +136.013177 74.054382 +# -b +135.848898 75.549316 +135.726863 75.467177 +135.717476 75.345142 +135.417081 75.427281 +135.464017 75.544623 +135.478098 75.744104 +135.487486 75.821549 +135.623602 75.673699 +135.853592 75.598600 +135.755025 75.549316 +# -b +139.918310 75.837977 +139.955860 75.823896 +139.965247 75.793387 +# -b +140.005143 74.795982 +139.817396 74.833532 +139.639037 74.960261 +139.563938 75.049441 +139.366804 74.955567 +139.409047 74.859347 +139.042941 74.688028 +138.568880 74.742005 +137.939928 74.817104 +137.719326 74.976689 +137.282815 75.054134 +136.949564 75.126886 +136.705493 75.321673 +137.038744 75.338101 +136.991807 75.406160 +137.146698 75.446056 +136.818141 75.577478 +136.916708 75.575132 +137.062212 75.600947 +136.982420 75.746451 +137.221797 75.793387 +137.132617 75.826243 +137.080987 75.945932 +137.278121 75.990521 +137.479949 76.077354 +137.601984 76.136025 +137.822587 76.204083 +137.897685 76.159494 +138.066657 76.030418 +138.287260 75.978787 +138.320116 75.873180 +138.446845 75.837977 +138.446845 75.837977 +# -b +140.028612 73.362066 +139.653118 73.437165 +139.784541 73.472367 +# -b +137.038744 71.613674 +137.193635 71.566737 +137.512804 71.585512 +137.977478 71.533882 +137.620759 71.456436 +137.203022 71.472864 +136.738349 71.559697 +136.949564 71.599593 +137.038744 71.613674 +# -b +138.043189 71.526841 +138.249711 71.578471 +138.517250 71.578471 +138.803564 71.618368 +138.958455 71.493985 +138.822338 71.414193 +138.437457 71.350828 +138.108900 71.325013 +137.864830 71.400112 +138.029108 71.508066 +138.043189 71.526841 +138.043189 71.526841 +# -b +139.972288 72.472616 +139.972288 72.472616 +# -b +140.138913 72.237932 +139.599141 72.233238 +139.387926 72.176914 +139.233035 72.294256 +139.378538 72.388130 +139.467718 72.486697 +139.894842 72.503124 +139.974634 72.472616 +# -b +119.977252 73.021775 +120.460700 72.995960 +121.047409 72.920861 +121.244543 72.946676 +121.718604 72.970145 +122.094098 72.953717 +122.347556 72.972491 +122.732437 73.012388 +123.239353 73.033509 +123.352001 73.200135 +123.173642 73.399615 +123.154867 73.472367 +123.319146 73.751641 +123.525667 73.702357 +123.858918 73.709398 +123.858918 73.836127 +124.187475 73.784496 +124.642761 73.744600 +124.938462 73.709398 +125.173145 73.688276 +125.281100 73.582669 +125.558026 73.577975 +125.788016 73.549813 +126.088411 73.533385 +126.407581 73.486448 +126.614102 73.401962 +126.801849 73.465327 +127.045920 73.533385 +127.275910 73.505223 +127.454269 73.493489 +127.764051 73.493489 +128.139545 73.458286 +128.191175 73.397269 +128.491570 73.366760 +128.646461 73.256459 +128.932775 73.183707 +129.341124 73.047590 +129.514790 72.972491 +129.430304 72.883312 +129.317656 72.791785 +129.359899 72.730767 +129.251945 72.634547 +129.397448 72.540674 +129.228476 72.463228 +129.627438 72.376395 +129.463160 72.219157 +129.416223 72.153446 +129.219089 72.092428 +129.176846 72.026717 +128.965631 72.003249 +128.712173 71.888254 +128.843595 71.738056 +128.942162 71.594899 +129.139297 71.653570 +129.195621 71.585512 +129.317656 71.458783 +129.505403 71.247568 +129.749474 71.160735 +129.946608 71.038699 +129.946608 71.038699 +# -b +109.942185 76.661716 +110.251968 76.718040 +110.627461 76.699266 +111.078053 76.713347 +111.134378 76.638248 +111.472322 76.619473 +111.500484 76.574883 +111.857203 76.509172 +112.073112 76.422339 +112.354732 76.375402 +112.673901 76.295610 +112.551866 76.211124 +112.664514 76.152453 +112.795937 76.065620 +113.077557 76.138372 +113.058782 76.211124 +113.340403 76.138372 +113.424889 75.992868 +113.631410 75.898995 +113.809770 75.793387 +113.603248 75.622068 +113.424889 75.589213 +112.993071 75.690127 +112.617577 75.769919 +112.242084 75.802775 +112.608190 75.708901 +112.631658 75.605641 +112.828792 75.626762 +113.040008 75.568091 +113.424889 75.507073 +113.556311 75.422587 +113.457744 75.375651 +113.499987 75.284124 +113.227754 75.178517 +113.072863 75.082296 +112.763081 75.028319 +112.706757 74.964955 +112.345344 74.873428 +112.124742 74.896896 +112.054337 74.835879 +111.890058 74.798329 +111.636600 74.756086 +111.613132 74.638744 +111.293962 74.692722 +110.918469 74.622317 +110.665011 74.537831 +110.547669 74.540177 +110.223805 74.483853 +110.073608 74.399367 +109.853006 74.333656 +# -b +109.986775 73.491142 +110.230846 73.549813 +110.625114 73.624912 +110.714294 73.744600 +110.287170 73.702357 +110.151054 73.653074 +# -b +109.787294 73.974590 +110.491345 73.965203 +110.866838 73.913572 +111.265800 74.028567 +111.308043 73.934694 +111.200089 73.857248 +111.641294 73.707051 +112.115355 73.678889 +112.828792 73.775109 +112.777162 74.002752 +113.138575 73.805618 +113.359177 73.620218 +113.185511 73.420737 +113.326322 73.310436 +113.185511 73.263499 +113.734671 73.263499 +114.250975 73.200135 +114.626468 73.148504 +114.044453 73.364413 +113.546924 73.495836 +114.185263 73.568588 +114.673405 73.554507 +115.034818 73.582669 +115.321131 73.660114 +115.818660 73.685929 +116.358433 73.627258 +117.020240 73.599096 +117.705516 73.538079 +118.235901 73.531038 +118.728736 73.533385 +118.916483 73.465327 +# -b +113.018886 74.512015 +113.305200 74.462732 +113.328668 74.312534 +113.051742 74.181112 +112.577681 74.117747 +111.981585 74.211620 +111.474669 74.307841 +111.685884 74.340696 +112.005053 74.411101 +112.005053 74.547218 +112.446258 74.504975 +112.812365 74.493241 +113.018886 74.512015 +# -b +118.942298 73.467674 +118.810875 73.465327 +118.580885 73.434818 +118.458850 73.338598 +118.435382 73.275233 +118.444769 73.209522 +118.867199 73.110955 +119.392890 73.059324 +119.758997 72.981879 +119.979599 73.021775 +119.979599 73.021775 +# -b +99.864875 79.665665 +100.230982 79.653931 +100.230982 79.653931 +# -b +99.975176 78.431230 +100.087825 78.487554 +100.228635 78.635405 +100.604128 78.773868 +101.064108 78.729278 +100.791875 78.860701 +100.895136 78.996817 +101.148594 79.024979 +101.148594 79.107119 +101.233080 79.177524 +101.617961 79.278437 +101.815095 79.294865 +102.153039 79.215073 +102.153039 79.372311 +102.444047 79.416901 +102.866477 79.384045 +102.904027 79.327721 +103.119936 79.283131 +102.922801 79.104772 +103.054224 79.055488 +103.307682 79.203339 +103.598690 79.158749 +103.795824 79.125893 +104.039895 79.163443 +104.114994 79.100078 +104.199480 78.978043 +104.330902 79.034367 +104.499875 78.956921 +104.865981 78.841926 +105.269637 78.790296 +105.457383 78.675301 +105.457383 78.525103 +105.128826 78.330316 +104.650072 78.297460 +103.992958 78.238790 +103.260746 78.201240 +102.950963 78.170731 +102.537920 78.215321 +102.040391 78.180119 +101.467764 78.182465 +100.998397 78.116754 +100.529030 78.041655 +100.069050 77.968903 +# -b +99.986911 78.339703 +100.033847 78.365519 +# -b +107.022722 78.175425 +107.219857 78.135529 +107.604737 78.173078 +107.801872 78.119101 +107.473315 78.051043 +106.910074 78.088592 +106.600292 78.130835 +106.966398 78.168384 +107.022722 78.175425 +# -b +99.951708 76.450501 +100.439850 76.450501 +100.862280 76.499785 +101.134513 76.537334 +101.068802 76.631207 +101.228386 76.621820 +101.228386 76.652329 +101.059414 76.722734 +100.852893 76.802526 +100.984316 76.889359 +101.172062 76.957418 +101.294098 77.070066 +101.510007 77.149858 +101.707141 77.222610 +101.988761 77.274240 +102.110796 77.302402 +102.289156 77.382195 +102.542614 77.471374 +102.777298 77.534739 +102.993206 77.609838 +103.425024 77.595757 +103.640933 77.642693 +103.903778 77.689630 +104.157237 77.691977 +104.279272 77.638000 +104.523343 77.670855 +104.823738 77.565248 +105.293105 77.508924 +105.593500 77.530045 +105.800021 77.424438 +106.044092 77.321177 +105.612274 77.339952 +105.452690 77.239038 +104.945773 77.152205 +104.607829 77.034863 +104.260497 76.938643 +104.720477 77.002007 +105.152295 77.046597 +105.518401 77.060678 +105.734310 77.128737 +105.668599 77.004354 +105.968993 77.044250 +106.175515 77.011395 +106.466522 77.023129 +106.663657 76.985580 +106.804467 76.990273 +107.133024 76.971499 +107.217510 76.917521 +107.179960 76.879972 +107.057925 76.804873 +107.086087 76.783752 +107.179960 76.788445 +106.842016 76.718040 +106.560396 76.570190 +106.306938 76.506825 +106.119191 76.471623 +106.306938 76.448154 +106.748143 76.424686 +107.189348 76.443461 +107.414644 76.492744 +107.733813 76.544375 +107.865236 76.591311 +107.799525 76.628861 +107.940335 76.711000 +108.128082 76.741509 +108.193793 76.696919 +108.343991 76.701613 +108.606836 76.678144 +108.991717 76.696919 +109.310887 76.734468 +109.592507 76.687532 +109.808416 76.673450 +109.939838 76.661716 +# -b +110.031365 74.333656 +109.984428 74.319575 +109.730970 74.157643 +108.937740 73.991018 +108.505922 73.791537 +108.144510 73.587362 +107.604737 73.606137 +107.107208 73.573281 +107.064965 73.514610 +106.806814 73.397269 +106.332753 73.275233 +105.980728 73.157891 +105.792981 73.040550 +105.595847 72.909127 +105.196885 72.784745 +104.779148 72.756583 +104.427123 72.658016 +104.164277 72.550061 +104.558545 72.594651 +104.657113 72.585264 +105.131173 72.726074 +105.652171 72.798826 +106.013583 72.941983 +106.609679 72.857497 +106.886606 72.866884 +106.290510 72.951370 +106.248267 73.129729 +106.853750 73.125036 +107.515558 73.148504 +107.956763 73.232990 +108.243077 73.251765 +108.660813 73.317476 +109.191198 73.385534 +109.336702 73.406656 +109.116099 73.526345 +109.435269 73.416043 +109.984428 73.491142 +109.984428 73.491142 +# -b +110.151054 73.653074 +109.691074 73.678889 +109.667606 73.601443 +109.447003 73.791537 +109.789641 73.974590 +109.789641 73.974590 +# -b +92.366737 80.010650 +92.948752 79.987182 +93.465056 79.926164 +93.540155 79.829944 +93.258534 79.778313 +92.761005 79.703215 +92.301026 79.689134 +91.775335 79.642197 +91.324742 79.714949 +91.615750 79.726683 +91.925532 79.707908 +92.216540 79.712602 +91.963081 79.783007 +91.456165 79.815863 +91.446778 79.848718 +91.296580 79.921470 +91.193319 79.970754 +91.268418 79.998916 +# -b +94.030643 80.003610 +93.833509 79.996569 +# -b +98.057812 80.020037 +98.114136 79.895655 +97.672931 79.829944 +97.372536 79.768926 +96.893782 79.703215 +97.325600 79.724336 +97.729255 79.757192 +97.992101 79.836984 +98.405144 79.898002 +98.452080 79.989529 +98.452080 79.989529 +# -b +98.862777 80.001263 +98.937875 79.989529 +99.097460 79.991875 +# -b +99.280513 80.010650 +99.656007 79.902696 +99.843754 79.790048 +99.853141 79.710255 +99.862528 79.665665 +# -b +100.228635 79.653931 +99.815592 79.548324 +99.665394 79.470878 +99.674782 79.332415 +99.421323 79.250275 +98.970731 79.306600 +99.327450 79.144668 +99.590296 79.064875 +99.665394 78.928759 +99.233577 78.823151 +98.782984 78.748053 +98.069546 78.771521 +97.581405 78.813764 +97.083876 78.867741 +96.426762 78.949881 +96.041881 79.001511 +95.760261 79.055488 +95.591288 79.123546 +95.028048 78.994470 +94.708878 79.085997 +94.230124 79.226807 +94.220737 79.372311 +94.136251 79.477918 +93.779532 79.454450 +93.516686 79.482612 +93.216291 79.524855 +93.141193 79.449756 +92.822023 79.553017 +93.272615 79.578832 +93.695046 79.658625 +93.882792 79.752498 +94.474195 79.797088 +94.239511 79.898002 +94.492970 79.970754 +94.577456 79.984835 +# -b +99.942321 78.424190 +99.970483 78.431230 +# -b +100.064356 77.968903 +99.632539 77.924314 +99.557440 78.008800 +99.379080 78.076858 +99.594989 78.203587 +99.942321 78.323276 +99.979870 78.339703 +# -b +100.031501 78.365519 +99.947014 78.424190 +99.947014 78.424190 +# -b +89.914294 75.462484 +90.078573 75.481258 +90.003474 75.488299 +# -b +89.980006 75.551663 +90.463454 75.582172 +90.904659 75.622068 +91.303621 75.650230 +91.524223 75.626762 +91.580547 75.706554 +91.744826 75.727676 +91.956041 75.753491 +92.162562 75.798081 +92.444183 75.840324 +92.481732 75.915423 +92.416021 75.929504 +92.373778 75.913076 +92.181337 75.920116 +92.148481 76.018683 +92.223580 75.985828 +92.406633 76.051539 +92.523975 76.025724 +92.566218 76.065620 +92.744577 76.086742 +92.908856 76.044499 +93.007423 76.100823 +93.171701 76.086742 +93.321899 76.075008 +93.420466 76.114904 +93.631681 76.126638 +93.763104 76.032765 +93.575357 75.906035 +93.669230 75.873180 +93.903914 75.960013 +94.054111 75.957666 +93.960238 75.863792 +94.147985 75.894301 +94.265327 75.971747 +94.331038 75.948278 +94.438992 75.952972 +94.593884 75.955319 +94.607965 76.023377 +94.617352 76.075008 +94.762856 76.058580 +94.725306 76.133678 +94.903666 76.190002 +95.119575 76.246327 +95.274466 76.208777 +95.260385 76.143066 +95.448132 76.112557 +95.532618 76.013990 +95.626491 76.096129 +95.635878 76.159494 +95.654653 76.236939 +95.424663 76.255714 +95.293240 76.326119 +95.189980 76.410605 +95.161818 76.464582 +95.161818 76.464582 +# -b +98.804106 76.464582 +99.001240 76.459888 +99.376734 76.431726 +99.817939 76.438767 +99.958749 76.450501 +99.958749 76.450501 +# -b +96.321154 76.274489 +96.283605 76.215818 +96.321154 76.128985 +95.926886 76.138372 +95.504456 76.175921 +95.288547 76.239286 +95.373033 76.248673 +95.513843 76.248673 +95.776688 76.274489 +96.030147 76.236939 +96.424415 76.276835 +96.574612 76.185309 +96.490126 76.236939 +96.321154 76.274489 +# -b +96.300033 77.004354 +96.084124 76.931602 +95.736792 76.861197 +95.755567 76.896400 +95.736792 76.926909 +95.239263 76.896400 +95.483334 76.997314 +96.027800 77.067719 +96.337582 77.117002 +96.365744 77.009048 +96.300033 77.004354 +96.300033 77.004354 +# -b +80.341554 73.164932 +80.585625 73.261152 +80.341554 73.315129 +80.552769 73.329210 +80.782759 73.418390 +80.707660 73.437165 +80.552769 73.526345 +80.839083 73.547466 +81.148865 73.568588 +81.303756 73.596750 +81.599457 73.620218 +81.965564 73.657767 +82.294121 73.641340 +82.716551 73.648380 +83.176531 73.646033 +83.918131 73.676542 +84.368723 73.714091 +84.819315 73.751641 +85.194809 73.695317 +85.626627 73.812658 +85.969264 73.838474 +86.264966 73.852555 +86.673315 73.918266 +86.631072 73.974590 +86.696783 74.021527 +86.893917 74.037955 +86.682702 74.148256 +86.354145 74.253863 +85.969264 74.284372 +85.889472 74.380593 +86.067832 74.399367 +86.241497 74.439263 +86.377614 74.467425 +86.584135 74.469772 +86.509037 74.523750 +86.462100 74.561299 +86.020895 74.608236 +85.668870 74.650479 +85.814373 74.723231 +85.912940 74.786595 +85.955183 74.817104 +86.189867 74.781901 +86.476181 74.697415 +86.649847 74.619970 +86.715558 74.737312 +86.917386 74.786595 +87.091052 74.880468 +87.170844 74.967301 +87.400834 74.934446 +87.522869 75.011891 +87.114520 75.042400 +86.917386 75.101071 +87.490014 75.115152 +87.734084 75.068215 +87.987543 75.096377 +88.039173 75.166782 +88.395892 75.267696 +88.616494 75.307592 +88.968520 75.368610 +88.846484 75.415547 +89.189122 75.469524 +89.475436 75.403813 +89.916641 75.462484 +89.916641 75.462484 +# -b +90.003474 75.488299 +89.980006 75.551663 +89.980006 75.551663 +# -b +89.496558 77.304749 +89.440234 77.260159 +89.590431 77.199142 +89.336973 77.152205 +89.139839 77.208529 +89.365135 77.293015 +89.496558 77.304749 +# -b +82.188513 75.413200 +82.230756 75.340448 +82.052397 75.232494 +81.920974 75.352182 +81.611192 75.382691 +81.690984 75.201985 +81.493850 75.370957 +81.681597 75.424934 +81.888118 75.460137 +81.855262 75.509420 +82.155657 75.457790 +82.188513 75.413200 +# -b +82.319936 70.398013 +82.441971 70.515355 +82.714204 70.379239 +82.747060 70.214960 +82.427890 70.231388 +82.319936 70.360464 +82.319936 70.398013 +# -b +79.961367 72.198036 +80.590318 72.068960 +80.918875 71.937537 +81.327225 71.780299 +81.669862 71.702854 +82.167392 71.681732 +82.716551 71.723975 +83.106126 71.695813 +83.270404 71.557350 +83.059189 71.407152 +82.430237 71.249915 +82.355138 71.015231 +82.322283 70.759426 +82.242490 70.543517 +82.242490 70.329955 +82.387994 70.137515 +82.796343 70.102312 +83.246936 70.048335 +83.148369 70.226694 +83.523862 70.273631 +83.800789 70.444950 +83.678753 70.738304 +83.448764 70.994109 +83.270404 71.228793 +83.613042 71.468170 +83.655285 71.674692 +83.425295 71.789687 +82.894910 71.864785 +82.477174 72.029064 +82.430237 72.139365 +82.054743 72.254360 +81.482116 72.308337 +80.975199 72.423332 +80.900101 72.580570 +80.834389 72.763623 +80.951731 72.864537 +80.867245 72.979532 +80.754597 73.038203 +80.580931 73.110955 +80.444815 73.136770 +80.341554 73.164932 +# -b +70.243122 73.014735 +70.275978 73.134423 +70.341689 73.343291 +71.092677 73.432471 +71.083289 73.249418 +71.524494 73.235337 +71.181856 73.085140 +70.520049 73.040550 +70.341689 73.040550 +70.243122 73.014735 +# -b +74.202233 73.019428 +74.634051 73.064018 +74.732618 73.005347 +74.469772 72.902086 +74.202233 73.019428 +# -b +79.276091 73.012388 +79.496693 72.892699 +79.445063 72.672097 +78.834886 72.756583 +78.971002 72.944329 +79.243235 73.040550 +79.276091 73.012388 +# -b +77.368114 72.500778 +77.588716 72.575876 +78.184812 72.526593 +78.086245 72.364661 +77.321177 72.254360 +76.969152 72.291909 +77.368114 72.500778 +77.368114 72.500778 +# -b +69.947421 72.871578 +70.473112 72.876271 +71.289811 72.883312 +71.829583 72.824641 +72.505471 72.740155 +72.589957 72.723727 +# -b +72.592304 72.723727 +72.550061 72.683831 +72.592304 72.566489 +72.681484 72.345887 +72.526593 72.120590 +72.254360 71.862438 +72.118244 71.709894 +71.799074 71.592552 +71.756831 71.498679 +72.188649 71.280423 +72.540674 71.127879 +72.770664 70.853299 +72.695565 70.536477 +72.573530 70.360464 +72.442107 70.177411 +72.526593 70.006092 +72.526593 70.006092 +# -b +73.641340 69.942727 +73.796231 70.196186 +74.237436 70.482499 +74.134175 70.787588 +73.796231 71.113798 +73.387881 71.357869 +72.998307 71.540922 +73.355026 71.702854 +73.528691 71.878866 +74.101319 71.993861 +74.279679 72.029064 +74.983729 72.268441 +74.899243 72.632200 +75.016585 72.845762 +75.392079 72.700259 +75.570438 72.540674 +75.481258 72.397517 +75.561051 72.200383 +75.204332 71.991514 +75.251268 71.789687 +75.471871 71.601940 +75.218413 71.440008 +75.359223 71.334401 +75.978787 71.235834 +76.485704 71.202978 +77.170980 71.160735 +77.574635 71.141960 +77.950129 70.982375 +78.414802 70.996456 +78.151957 71.263996 +77.907886 71.369603 +77.555861 71.280423 +77.288321 71.322666 +76.617126 71.486945 +76.297957 71.627755 +76.002256 71.871826 +76.551415 71.862438 +77.203835 71.716935 +78.029921 71.895294 +77.654428 72.052532 +77.598104 72.176914 +78.095633 72.324765 +79.010898 72.334152 +79.813516 72.256707 +79.959020 72.198036 +# -b +59.933476 75.999909 +60.215096 76.072661 +60.599977 76.100823 +60.440392 75.964706 +60.881597 76.032765 +60.984858 76.114904 +60.919146 76.225205 +61.022407 76.281529 +61.623197 76.262754 +62.242761 76.246327 +62.590093 76.190002 +63.050073 76.201737 +63.500665 76.281529 +63.876159 76.267448 +64.185941 76.293263 +64.542660 76.328466 +65.058963 76.415299 +65.406295 76.518559 +65.838113 76.539681 +65.847500 76.708653 +66.241768 76.781405 +66.391966 76.781405 +66.664199 76.882319 +67.171115 76.903440 +67.771905 76.945683 +68.269434 76.910481 +68.710639 76.823648 +68.879611 76.718040 +69.029808 76.579577 +68.898386 76.478663 +68.795125 76.410605 +68.551054 76.328466 +68.344533 76.234592 +68.372695 76.145413 +67.912715 76.180615 +67.387024 76.082048 +66.880108 75.999909 +66.269930 75.945932 +65.659753 75.908382 +65.321809 75.821549 +64.871217 75.758185 +63.857384 75.600947 +63.528827 75.694820 +63.392711 75.610334 +62.810695 75.424934 +62.313166 75.359223 +62.036240 75.307592 +61.651359 75.155048 +61.135055 75.030666 +60.726706 74.990770 +60.407536 75.051787 +60.571815 74.934446 +60.262032 74.795982 +60.130610 74.664560 +59.999187 74.659866 +# -b +59.766850 70.146902 +60.020308 70.050682 +# -b +66.858986 69.888750 +66.910616 70.036601 +# -b +67.211011 69.975583 +67.178156 70.285365 +67.318966 70.616269 +67.032652 70.801669 +66.638383 70.721877 +66.802662 70.935439 +67.032652 71.076249 +66.858986 71.071555 +66.690014 71.076249 +66.934085 71.294504 +68.013629 71.583165 +68.445447 71.888254 +68.666049 72.247319 +68.886652 72.589957 +69.262145 72.838722 +69.360712 72.927902 +69.858241 72.944329 +69.947421 72.871578 +# -b +58.797607 80.001263 +58.581698 79.973101 +58.562924 79.942592 +58.750671 79.921470 +58.806995 79.879227 +58.957192 79.900349 +59.051066 79.862799 +59.276362 79.853412 +59.473496 79.867493 +59.473496 79.900349 +59.698792 79.898002 +59.689405 79.956673 +59.651855 79.996569 +# -b +53.744871 73.261152 +54.054654 73.251765 +54.636669 73.333904 +55.298476 73.315129 +55.918041 73.251765 +56.500056 73.127383 +56.260679 73.047590 +56.091706 73.019428 +56.345165 72.970145 +55.716213 72.911474 +56.302922 72.934942 +56.091706 72.780051 +55.575403 72.775357 +55.819474 72.733114 +55.753762 72.604038 +55.519079 72.507818 +55.453367 72.418638 +55.462755 72.209770 +55.420512 71.977433 +55.551934 71.747444 +55.716213 71.491639 +56.082319 71.252261 +56.523524 70.994109 +57.039828 70.841565 +57.438790 70.773507 +57.518582 70.639737 +57.175944 70.623310 +56.974116 70.588107 +57.143089 70.550558 +56.955342 70.534130 +56.598623 70.656165 +56.302922 70.696061 +56.359246 70.606882 +56.326390 70.566985 +55.936815 70.602188 +55.786618 70.660859 +55.476836 70.689021 +55.298476 70.616269 +54.979307 70.606882 +54.937064 70.719530 +54.528714 70.740651 +54.218932 70.712489 +53.923231 70.754732 +53.744871 70.855646 +53.679160 71.003497 +53.998329 71.010537 +54.308112 71.050434 +54.195464 71.120839 +53.843438 71.149001 +53.566512 71.263996 +53.754259 71.343788 +53.744871 71.397765 +53.458557 71.350828 +53.458557 71.519801 +53.237955 71.447049 +52.918785 71.449395 +52.796750 71.578471 +52.496355 71.529188 +52.388401 71.547963 +52.055150 71.456436 +51.759449 71.498679 +51.529459 71.674692 +51.515378 71.904682 +51.768836 72.083041 +52.078618 72.092428 +52.332077 72.014983 +52.510436 72.132325 +52.641859 72.256707 +52.651246 72.355274 +52.820218 72.446800 +53.040821 72.566489 +52.820218 72.589957 +52.562066 72.641588 +52.477580 72.780051 +53.003271 72.885659 +53.191018 72.909127 +53.294279 72.984226 +53.125307 73.092180 +53.669773 73.235337 +53.744871 73.261152 +# -b +53.669773 73.763375 +53.974861 73.782150 +54.481778 73.915919 +54.768091 74.047342 +55.279701 74.087238 +56.105787 74.002752 +55.378269 74.171724 +55.551934 74.209274 +55.190522 74.331309 +55.852329 74.378246 +55.664582 74.455691 +55.453367 74.605889 +55.772537 74.622317 +56.415570 74.624663 +56.312309 74.671600 +55.852329 74.730271 +55.598871 74.772514 +55.903960 74.925058 +55.716213 74.986076 +55.429899 75.016585 +55.598871 75.145661 +55.927428 75.065868 +56.467200 75.098724 +56.866162 75.263003 +57.260430 75.284124 +57.626537 75.305246 +57.790815 75.467177 +57.978562 75.500033 +58.288344 75.607987 +58.565271 75.629109 +58.574658 75.751144 +58.804648 75.835630 +59.053412 75.887261 +59.236465 75.999909 +59.236465 75.999909 +# -b +60.076632 74.659866 +59.447681 74.720884 +59.823174 74.549565 +59.677670 74.544871 +59.039331 74.617623 +59.128511 74.502628 +58.983007 74.486200 +59.058106 74.399367 +58.973620 74.373552 +58.565271 74.469772 +58.466704 74.420489 +58.738936 74.260904 +58.616901 74.176418 +58.443235 74.164684 +58.419767 74.059076 +58.246101 74.014486 +58.124066 73.962856 +57.837752 74.080198 +57.504501 74.164684 +57.504501 74.059076 +57.363691 74.019180 +57.701635 73.913572 +57.823671 73.833780 +57.790815 73.723479 +57.405934 73.810312 +56.776982 73.819699 +57.373078 73.707051 +57.462258 73.568588 +57.129008 73.566241 +56.931873 73.559200 +57.152476 73.458286 +57.039828 73.371453 +56.842694 73.298702 +56.711271 73.225950 +56.359246 73.258805 +55.918041 73.303395 +55.443980 73.331557 +54.922983 73.401962 +54.481778 73.343291 +54.106284 73.331557 +54.397291 73.425431 +54.373823 73.528691 +54.838496 73.599096 +55.077874 73.671848 +54.636669 73.655421 +54.242400 73.589709 +53.866907 73.676542 +53.679160 73.753988 +53.669773 73.763375 +# -b +52.310955 71.287464 +52.578494 71.355522 +52.963375 71.299198 +53.193365 71.120839 +53.151122 70.956560 +53.005618 71.008190 +52.620737 71.207671 +52.310955 71.287464 +# -b +58.764752 69.968543 +58.666185 70.125780 +58.699040 70.182105 +58.633329 70.273631 +58.863319 70.412094 +59.360848 70.290059 +59.769197 70.146902 +59.769197 70.146902 +# -b +47.624325 80.005956 +47.727586 79.961367 +47.915333 79.989529 +47.915333 79.989529 +# -b +29.957350 70.705449 +30.332844 70.590454 +30.605077 70.524742 +30.971183 70.405054 +30.661401 70.247816 +30.196728 70.130474 +29.999593 70.069456 +# -b +19.987995 78.968655 +20.354101 78.909984 +20.861017 78.874782 +21.358547 78.858354 +21.424258 78.785602 +21.377321 78.701116 +21.161412 78.658873 +20.738982 78.679995 +20.457362 78.635405 +20.119418 78.614283 +20.025544 78.588468 +# -b +21.389055 78.604896 +21.398443 78.581427 +21.614352 78.574387 +22.121268 78.588468 +22.337177 78.503982 +22.215141 78.431230 +22.121268 78.316235 +21.933521 78.252871 +21.548640 78.229402 +21.144985 78.182465 +20.788266 78.224709 +20.647455 78.306848 +20.638068 78.417149 +20.178088 78.471126 +20.675617 78.508676 +21.013562 78.541531 +21.276407 78.614283 +21.389055 78.604896 +# -b +22.888683 78.281033 +22.926232 78.248177 +22.982556 78.220015 +23.076430 78.203587 +23.170303 78.208281 +23.254789 78.170731 +23.358050 78.137876 +23.292339 78.119101 +23.311113 78.083898 +23.104592 78.067471 +23.048268 78.015840 +23.113979 77.957169 +23.273564 77.924314 +23.498860 77.875030 +23.714769 77.835134 +24.033939 77.844521 +24.202911 77.886764 +24.428207 77.842174 +24.522080 77.802278 +24.615954 77.781157 +24.691052 77.745954 +24.888187 77.734220 +24.831862 77.701364 +24.691052 77.703711 +24.493918 77.691977 +24.202911 77.663815 +24.127812 77.621572 +24.005777 77.595757 +23.864966 77.544126 +23.818030 77.497190 +23.714769 77.459640 +23.611508 77.422091 +23.461311 77.405663 +23.367437 77.377501 +23.273564 77.361073 +23.160916 77.393929 +23.057655 77.361073 +22.879296 77.325871 +22.869908 77.288321 +22.757260 77.260159 +22.663387 77.278934 +22.550739 77.257812 +22.438091 77.290668 +22.503802 77.344645 +22.578901 77.408010 +22.672774 77.464334 +22.804197 77.497190 +22.832359 77.539433 +22.663387 77.490149 +22.578901 77.518311 +22.616450 77.553514 +22.381767 77.548820 +22.259731 77.487802 +22.071984 77.480762 +21.884238 77.469028 +21.658941 77.461987 +21.424258 77.457293 +21.245898 77.433825 +21.114476 77.443212 +20.926729 77.447906 +20.870405 77.497190 +20.907954 77.534739 +20.954891 77.569942 +21.217736 77.612185 +21.236511 77.659121 +21.255286 77.727179 +21.367934 77.788197 +21.499357 77.872683 +21.555681 77.914926 +21.302222 77.947782 +21.152025 77.990025 +20.992440 78.018187 +20.842243 78.051043 +20.898567 78.095633 +21.161412 78.128488 +21.499357 78.170731 +21.780977 78.194200 +22.062597 78.173078 +22.306668 78.184812 +22.541351 78.205934 +22.578901 78.220015 +22.719711 78.227055 +22.813584 78.238790 +22.888683 78.281033 +22.888683 78.281033 +# -b +26.427710 78.703463 +26.465260 78.694076 +26.540358 78.654179 +26.737493 78.626017 +26.897077 78.665914 +26.887690 78.687035 +26.671781 78.736319 +26.615457 78.773868 +26.446485 78.806724 +26.399548 78.776215 +26.380774 78.748053 +26.408936 78.722238 +26.427710 78.703463 +# -b +28.976373 78.839579 +29.023310 78.839579 +29.201670 78.823151 +29.304930 78.851313 +29.502064 78.865395 +29.549001 78.893557 +29.483290 78.893557 +29.304930 78.874782 +29.098409 78.893557 +28.966986 78.902944 +28.976373 78.921719 +28.685366 78.935800 +28.600880 78.954574 +28.441295 78.942840 +28.460070 78.919372 +28.394358 78.912331 +28.291097 78.893557 +28.150287 78.895903 +28.000090 78.874782 +27.981315 78.837232 +27.793568 78.858354 +27.802956 78.825498 +27.849892 78.806724 +28.037639 78.806724 +28.150287 78.841926 +28.338034 78.863048 +28.347422 78.863048 +28.478844 78.856007 +28.535168 78.884169 +28.713528 78.884169 +28.901275 78.858354 +28.976373 78.839579 +# -b +27.112986 80.005956 +27.037888 79.935551 +27.075437 79.907389 +27.169310 79.860453 +27.037888 79.818210 +26.775042 79.808822 +26.587295 79.750151 +26.587295 79.724336 +26.446485 79.682093 +26.324450 79.684440 +26.221189 79.642197 +26.052217 79.651584 +25.958343 79.630463 +25.826921 79.567098 +25.948956 79.517815 +25.902019 79.487306 +25.817533 79.470878 +25.761209 79.447410 +25.695498 79.409860 +25.657948 79.377005 +25.442040 79.351189 +25.338779 79.332415 +25.207356 79.332415 +25.122870 79.313640 +25.019609 79.332415 +24.869412 79.351189 +24.784926 79.341802 +24.531468 79.301906 +24.296784 79.290172 +24.240460 79.252622 +24.155974 79.210379 +24.052713 79.172830 +23.949452 79.175177 +23.827417 79.154055 +23.686607 79.147015 +23.592734 79.147015 +23.386212 79.147015 +23.367437 79.154055 +23.236015 79.154055 +23.170303 79.170483 +22.935620 79.177524 +22.954394 79.198645 +22.804197 79.226807 +22.813584 79.238541 +22.672774 79.254969 +22.607063 79.323027 +22.700936 79.365270 +22.644612 79.372311 +22.494415 79.367617 +22.231569 79.384045 +22.090759 79.386392 +21.921787 79.358230 +21.734040 79.369964 +21.565068 79.377005 +21.555681 79.395779 +21.461807 79.386392 +21.377321 79.374658 +21.255286 79.372311 +21.095701 79.369964 +21.029990 79.351189 +20.879792 79.339455 +20.729595 79.369964 +20.720207 79.416901 +20.598172 79.433329 +20.344714 79.430982 +20.166354 79.454450 +20.091256 79.484959 +# -b +19.931671 79.614035 +20.185129 79.597607 +20.325939 79.553017 +20.682658 79.553017 +20.898567 79.553017 +21.095701 79.548324 +21.039377 79.578832 +20.814081 79.588220 +20.682658 79.602301 +20.607559 79.628116 +20.579397 79.658625 +20.767144 79.679746 +20.936116 79.658625 +21.114476 79.679746 +21.311610 79.693827 +21.508744 79.679746 +21.809139 79.682093 +21.818526 79.707908 +21.940562 79.710255 +21.996886 79.752498 +21.799752 79.759539 +21.931174 79.794741 +21.846688 79.787701 +21.649554 79.799435 +21.443033 79.775967 +21.217736 79.773620 +20.870405 79.775967 +20.785919 79.780660 +20.466749 79.764232 +20.354101 79.750151 +20.138192 79.750151 +20.025544 79.721989 +# -b +22.128308 80.010650 +22.325443 79.982488 +22.438091 79.991875 +# -b +21.320997 69.888750 +21.255286 70.013132 +# -b +21.973417 69.989664 +21.696491 70.088231 +21.541600 70.283018 +21.795058 70.137515 +21.940562 70.245469 +22.161164 70.231388 +22.358298 70.107006 +22.564820 70.193839 +22.940313 70.170370 +22.841746 70.095272 +22.987250 70.048335 +# -b +23.228974 69.956808 +23.252442 70.168024 +23.505901 70.297099 +24.111384 70.447297 +24.346068 70.602188 +24.421166 70.721877 +24.566670 70.773507 +24.730949 70.921358 +24.984407 70.916664 +25.195622 70.775854 +25.622746 70.860340 +25.669683 70.733611 +25.270721 70.555251 +25.172154 70.405054 +25.129911 70.252510 +24.909308 70.111699 +25.214397 70.125780 +25.327045 70.226694 +25.711926 70.496580 +26.012321 70.653818 +26.439445 70.893196 +26.674128 70.834525 +26.495769 70.653818 +26.584948 70.459031 +26.824326 70.451991 +27.091865 70.602188 +27.246756 70.726570 +27.500214 70.926051 +27.673880 71.043393 +28.129166 71.057474 +28.448335 70.963601 +27.974275 70.799322 +27.753672 70.609229 +28.284057 70.616269 +27.974275 70.444950 +28.284057 70.426175 +28.523434 70.543517 +28.734649 70.834525 +29.166467 70.846259 +29.297890 70.726570 +29.316664 70.656165 +29.715626 70.672593 +29.959697 70.705449 +29.959697 70.705449 +# -b +30.001940 70.069456 +29.372988 70.102312 +28.922396 70.151596 +28.645470 70.125780 +29.063206 70.043641 +29.175854 70.001398 +# -b +19.999729 70.095272 +20.065440 70.074150 +# -b +20.682658 70.214960 +20.790612 70.175064 +20.701433 70.027213 +20.560623 70.062416 +20.527767 70.196186 +20.682658 70.214960 +# -b +22.733792 70.226694 +22.466253 70.285365 +22.602369 70.353423 +22.822972 70.327608 +22.888683 70.231388 +22.733792 70.226694 +# -b +22.358298 70.646778 +22.433397 70.674940 +22.555432 70.689021 +22.564820 70.623310 +22.776035 70.681980 +22.921539 70.672593 +23.085817 70.583413 +22.888683 70.508315 +22.564820 70.484846 +22.301974 70.522396 +22.179939 70.574026 +22.170551 70.632697 +22.358298 70.646778 +# -b +23.383865 70.327608 +23.243055 70.283018 +22.989597 70.334649 +22.966129 70.433216 +23.111632 70.466072 +23.332235 70.510661 +23.562225 70.496580 +23.383865 70.327608 +23.383865 70.327608 +# -b +23.935371 70.517702 +23.747625 70.602188 +23.789868 70.681980 +24.033939 70.590454 +24.043326 70.524742 +23.935371 70.517702 +# -b +25.831614 71.062168 +25.977118 70.989416 +25.920794 70.954213 +25.723660 70.916664 +25.503057 70.933092 +25.423265 70.928398 +25.568769 71.017578 +25.301230 71.043393 +25.653255 71.078596 +25.831614 71.062168 +25.831614 71.062168 +# -b +14.749859 79.740764 +15.031479 79.719642 +15.115965 79.682093 +15.228613 79.616382 +15.284937 79.534243 +15.341261 79.445063 +15.369423 79.416901 +15.388198 79.358230 +15.491459 79.247929 +15.435135 79.175177 +15.472684 79.137627 +15.632269 79.165789 +15.885727 79.057835 +16.082861 78.961615 +16.458355 78.900597 +16.289383 79.008551 +16.064086 79.114159 +15.979600 79.233848 +15.876340 79.360577 +15.829403 79.459144 +15.791854 79.574139 +15.754304 79.691480 +15.669818 79.724336 +15.735530 79.820556 +16.035924 79.867493 +15.970213 79.928511 +15.998375 79.998916 +# -b +16.556922 80.010650 +16.575697 79.937898 +16.575697 79.867493 +16.857317 79.848718 +16.951190 79.919123 +17.251585 79.895655 +17.683403 79.808822 +17.871150 79.705561 +17.749114 79.630463 +17.570755 79.536589 +17.645853 79.499040 +17.702177 79.421594 +17.570755 79.332415 +17.758501 79.386392 +18.049509 79.459144 +17.983798 79.527202 +18.115220 79.590567 +18.453165 79.571792 +18.650299 79.475572 +18.781722 79.393432 +18.781722 79.313640 +18.725397 79.208032 +19.044567 79.165789 +19.504547 79.128240 +19.673519 79.093038 +19.842491 78.992124 +19.983301 78.968655 +# -b +20.020850 78.588468 +19.758005 78.579081 +19.589033 78.534491 +19.354349 78.461739 +19.016405 78.414802 +19.035180 78.276339 +19.016405 78.227055 +18.969468 78.140222 +18.969468 78.008800 +18.687848 78.025228 +18.425003 77.975944 +18.434390 77.882071 +18.462552 77.776463 +18.387453 77.670855 +18.387453 77.598104 +18.331129 77.555861 +18.274805 77.469028 +17.946248 77.469028 +17.608304 77.400969 +17.814825 77.363420 +17.467494 77.311790 +17.383008 77.215569 +17.392395 77.138124 +17.354846 77.063025 +17.383008 76.994967 +17.354846 76.933949 +17.082613 76.851810 +17.063838 76.788445 +17.120162 76.675797 +17.045064 76.603045 +16.678957 76.553762 +16.538147 76.610086 +16.331626 76.556109 +16.331626 76.657023 +15.965519 76.755590 +15.599413 76.882319 +15.918583 76.922215 +16.218978 76.891706 +16.256527 76.976192 +15.909195 77.006701 +15.608800 76.983233 +15.195757 77.002007 +14.970461 77.091187 +14.416608 77.152205 +14.228861 77.239038 +14.088051 77.330564 +14.097439 77.433825 +14.275798 77.560554 +14.548031 77.513617 +14.773327 77.492496 +15.026785 77.506577 +15.374117 77.515964 +15.571251 77.494843 +15.993681 77.499536 +15.571251 77.569942 +15.045560 77.586369 +14.895363 77.656774 +15.242694 77.677896 +15.599413 77.715445 +15.890421 77.710752 +16.078167 77.752995 +16.303464 77.781157 +16.509985 77.771769 +16.829155 77.767076 +16.791605 77.865643 +16.810380 77.903192 +16.538147 77.842174 +16.068780 77.821053 +15.796547 77.799931 +15.543089 77.825747 +15.242694 77.778810 +15.092497 77.762382 +14.895363 77.769423 +14.688841 77.767076 +14.519869 77.741260 +14.238249 77.757688 +13.890917 77.710752 +13.797044 77.776463 +13.703170 77.860949 +13.646846 77.947782 +13.721945 78.029921 +14.022340 78.013493 +14.275798 77.980638 +14.369671 78.065124 +14.867201 78.067471 +15.111271 78.144916 +15.355342 78.227055 +15.683899 78.229402 +15.730836 78.313888 +16.059393 78.342050 +16.284689 78.339703 +16.613246 78.318582 +16.885479 78.344397 +17.110775 78.377253 +17.307909 78.433577 +16.894866 78.386640 +16.660183 78.433577 +16.425499 78.431230 +16.472436 78.518063 +16.697732 78.616630 +16.669570 78.710503 +16.378562 78.665914 +16.265914 78.525103 +15.881033 78.459392 +15.496152 78.464086 +15.289631 78.574387 +15.543089 78.715197 +15.252082 78.762134 +15.111271 78.626017 +14.857813 78.633058 +14.754552 78.722238 +14.529256 78.597855 +14.416608 78.445311 +14.688841 78.367865 +14.369671 78.363172 +14.181925 78.283379 +13.994178 78.224709 +13.703170 78.189506 +13.515424 78.187159 +13.355839 78.191853 +13.074219 78.220015 +13.036669 78.281033 +12.877084 78.337357 +12.623626 78.374906 +12.473429 78.473473 +12.970958 78.478167 +12.989732 78.525103 +12.567302 78.539184 +12.032224 78.597855 +11.910188 78.679995 +11.675505 78.738665 +11.910188 78.802030 +11.788153 78.839579 +11.346948 78.949881 +11.938350 78.909984 +12.417105 78.917025 +12.126097 78.942840 +11.844477 79.006205 +11.853864 79.095384 +12.004062 79.193951 +12.022836 79.269050 +11.769378 79.215073 +11.365723 79.264356 +11.450209 79.109465 +11.159201 79.161096 +10.999616 79.278437 +10.933905 79.323027 +10.830644 79.294865 +10.811869 79.428635 +10.671059 79.517815 +11.009004 79.543630 +10.774320 79.656278 +10.990229 79.646891 +11.309398 79.628116 +11.140426 79.743111 +11.403272 79.724336 +11.459596 79.787701 +11.637955 79.815863 +11.844477 79.724336 +12.079160 79.686787 +12.201196 79.705561 +12.135484 79.820556 +12.323231 79.764232 +12.623626 79.738417 +12.970958 79.775967 +13.477874 79.822903 +13.797044 79.787701 +13.768882 79.693827 +13.337064 79.693827 +12.961570 79.642197 +12.435879 79.564751 +12.595464 79.517815 +13.102381 79.562405 +13.393388 79.534243 +13.271353 79.447410 +13.421550 79.416901 +13.740720 79.327721 +14.228861 79.200992 +14.012953 79.323027 +13.872142 79.487306 +14.088051 79.611688 +14.303960 79.721989 +14.519869 79.773620 +14.745165 79.740764 +# -b +10.513821 78.874782 +10.757892 78.851313 +10.992576 78.762134 +11.161548 78.665914 +11.283583 78.572040 +11.368069 78.525103 +11.630915 78.454698 +11.874986 78.398374 +11.940697 78.311541 +12.072120 78.250524 +12.025183 78.201240 +11.818662 78.257564 +11.649690 78.337357 +11.443168 78.398374 +11.264809 78.431230 +11.020738 78.464086 +10.832991 78.616630 +10.570145 78.731625 +10.513821 78.846620 +10.513821 78.874782 +# -b +18.884982 74.453344 +18.894370 74.436917 +19.025792 74.394674 +19.016405 74.345390 +19.204152 74.373552 +19.237008 74.429876 +19.227620 74.476813 +19.049261 74.519056 +18.960081 74.486200 +18.870901 74.469772 +18.884982 74.453344 +# -b +20.086562 79.484959 +19.889428 79.515468 +19.729843 79.553017 +19.701681 79.588220 +19.917590 79.606994 +19.926977 79.614035 +# -b +20.020850 79.721989 +19.739230 79.726683 +19.664132 79.707908 +19.438835 79.689134 +19.298025 79.710255 +19.129053 79.710255 +18.941306 79.717296 +18.809884 79.710255 +18.678461 79.729030 +18.678461 79.757192 +18.622137 79.780660 +18.490714 79.768926 +18.425003 79.804129 +18.312355 79.832291 +18.274805 79.867493 +18.190319 79.893308 +18.453165 79.928511 +18.500101 79.949632 +18.565813 79.961367 +18.706623 79.980141 +18.725397 79.989529 +# -b +18.863861 70.020173 +18.863861 70.020173 +# -b +18.786415 69.989664 +18.739479 70.081191 +19.114972 70.055375 +19.147828 70.031907 +# -b +19.215886 69.987317 +19.347309 70.006092 +# -b +18.884982 69.975583 +18.917838 70.017826 +18.861514 70.020173 +# -b +19.821369 70.158636 +19.943405 70.137515 +19.999729 70.095272 +# -b +20.065440 70.074150 +19.722802 70.062416 +19.549137 70.231388 +19.713415 70.193839 +19.821369 70.158636 +# -b +-14.205393 -7.918222 +-14.228861 -7.962812 +-14.205393 -7.918222 +# -b +-36.157689 -10.150062 +-35.892496 -9.856708 +-35.385580 -9.298161 +-35.010086 -8.465034 +-34.834074 -7.819655 +-34.878664 -6.817556 +-35.188446 -5.585468 +-35.904231 -5.120794 +-36.643484 -5.177118 +-37.270089 -4.768769 +-38.152499 -4.125736 +-38.539726 -3.761977 +-39.386934 -3.163534 +-39.983030 -2.886607 +# -b +-50.048606 0.037549 +-49.917183 -0.018775 +# -b +-39.983030 -2.886607 +-40.832584 -2.910076 +-42.001308 -2.820896 +-42.904840 -2.588559 +-43.313189 -2.489992 +-43.545526 -2.400812 +-43.864695 -2.600293 +-44.249576 -2.755184 +-44.371612 -2.788040 +-44.493647 -2.600293 +-44.327022 -2.257655 +-44.603948 -2.201331 +-44.493647 -1.990116 +-44.747105 -1.513709 +-45.033419 -1.546564 +-45.340855 -1.492587 +-45.782060 -1.203926 +-45.993275 -1.126481 +-46.631614 -0.938734 +-47.138530 -0.694663 +-47.403723 -0.661808 +-47.943495 -0.694663 +-47.999819 -0.793230 +-48.142976 -1.081891 +-48.340110 -1.260250 +-48.527857 -1.546564 +-48.980796 -1.736658 +-49.156809 -2.177863 +-49.278844 -2.511114 +-49.365677 -2.245921 +-49.222520 -1.846959 +-49.332821 -1.724924 +-48.804783 -1.424529 +-48.462145 -0.837820 +-48.372966 -0.295701 +-49.091097 -0.218256 +-49.222520 -0.307435 +-49.938305 -0.206521 +-50.015750 -0.239377 +-50.280943 -0.373147 +-50.337267 -0.938734 +-50.665824 -0.983324 +-51.196208 -1.192192 +-51.261920 -0.894144 +-51.362834 -0.438858 +-50.931016 -0.007041 +-50.931016 -0.007041 +# -b +-80.017691 -2.290511 +-79.907389 -2.257655 +-79.862799 -2.555703 +-79.752498 -2.555703 +-79.862799 -2.966400 +-79.982488 -3.240979 +-79.982488 -3.240979 +# -b +-80.038812 -6.808169 +-79.618729 -7.369062 +-79.323027 -7.939343 +-78.914678 -8.324224 +-78.748053 -8.730227 +-78.539184 -9.155004 +-78.374906 -9.582128 +-78.229402 -9.985783 +-78.229402 -9.985783 +# -b +-89.355748 -0.748640 +-89.355748 -0.870676 +-89.609206 -0.959856 +-89.466049 -0.783843 +-89.355748 -0.748640 +# -b +-80.059934 0.171319 +-80.402572 -0.361413 +-80.468283 -0.715785 +-80.864898 -1.081891 +-80.864898 -1.692068 +-80.832042 -2.189597 +-80.843777 -2.335101 +-80.512873 -2.543969 +-80.313392 -2.677739 +-80.160847 -2.511114 +-80.017691 -2.290511 +-80.017691 -2.290511 +# -b +-79.982488 -3.240979 +-80.259415 -3.395870 +-80.346247 -3.508519 +-80.799187 -3.851156 +-81.174680 -4.203182 +-81.284982 -4.691323 +-81.130090 -5.087939 +-80.986933 -5.451698 +-81.040911 -5.848313 +-80.888366 -6.212073 +-80.226559 -6.632156 +-80.038812 -6.808169 +# -b +-91.460859 -0.328557 +-91.428003 -0.528038 +-91.648605 -0.429471 +-91.472593 -0.340291 +-91.460859 -0.328557 +# -b +-91.371679 0.103261 +-91.097099 -0.417737 +-90.942208 -0.682929 +-91.040775 -1.016180 +-91.428003 -1.081891 +-91.371679 -0.772109 +-91.219135 -0.506916 +-91.395147 -0.185400 +-91.526570 -0.051630 +-91.526570 -0.051630 +# -b +-90.712218 -0.206521 +-90.876497 -0.373147 +-90.667628 -0.417737 +-90.712218 -0.206521 +-90.712218 -0.206521 +# -b +-90.346112 -0.528038 +-90.524471 -0.572628 +-90.524471 -0.572628 +-90.346112 -0.528038 +# -b +-140.030958 -8.727880 +-139.965247 -8.903892 +-139.965247 -8.903892 +# -b +-138.960802 -9.713551 +-138.871622 -9.692429 +-138.751933 -9.746406 +-138.949067 -9.767528 +-138.960802 -9.713551 +# -b +-140.087283 -8.727880 +-140.054427 -8.718493 +-140.030958 -8.727880 +# -b +-139.965247 -8.903892 +-140.120138 -8.892158 +-140.087283 -8.727880 +-140.087283 -8.727880 +# -b +-157.906802 -9.002460 +-157.784766 -9.014194 +-157.805888 -9.089292 +-157.906802 -9.002460 +# -b +-173.062663 -2.776306 +-173.062663 -2.776306 +-173.062663 -2.776306 +# -b +-170.668891 -3.705653 +-170.657157 -3.693918 +-170.668891 -3.705653 +# -b +-171.804759 -9.145616 +-171.750782 -9.232449 +-171.804759 -9.145616 +# -b +174.318220 -0.635992 +174.383931 -0.814352 +174.318220 -0.635992 +174.318220 -0.635992 +# -b +160.816877 -8.389936 +160.969421 -8.422791 +161.091457 -8.772470 +161.389505 -9.155004 +161.478685 -9.319282 +161.675819 -9.570394 +161.445829 -9.483561 +161.014011 -8.957870 +160.837999 -8.422791 +160.816877 -8.389936 +# -b +160.263024 -8.990725 +160.441384 -8.969604 +160.417915 -9.133882 +160.263024 -8.990725 +# -b +159.932120 -9.331016 +160.209047 -9.363872 +160.352204 -9.375606 +160.671373 -9.537538 +160.969421 -9.701816 +160.694842 -9.887216 +160.220781 -9.833239 +160.075277 -9.833239 +# -b +169.537717 -0.835473 +169.558838 -0.802618 +169.549451 -0.924653 +169.537717 -0.835473 +169.537717 -0.835473 +# -b +150.129390 -2.475911 +150.371114 -2.410200 +150.549474 -2.642536 +150.206836 -2.576825 +150.129390 -2.475911 +# -b +150.957823 -2.642536 +151.145570 -2.698860 +151.563306 -2.964053 +152.126547 -3.240979 +152.558364 -3.583617 +152.889268 -3.905134 +153.220172 -4.191448 +153.220172 -4.545820 +152.910390 -4.578675 +152.713256 -3.905134 +152.403473 -3.485050 +151.938800 -3.318425 +151.521063 -3.029764 +151.100980 -2.764572 +150.957823 -2.642536 +150.957823 -2.642536 +# -b +149.908788 -5.517409 +150.084800 -5.240483 +150.293668 -5.085592 +150.293668 -5.496288 +150.746608 -5.517409 +151.187813 -5.273339 +151.640752 -4.954169 +151.786256 -4.512964 +151.873089 -4.224303 +152.150015 -4.236037 +152.403473 -4.257159 +152.480919 -4.843868 +152.203992 -5.130182 +152.006858 -5.583121 +151.697076 -5.770868 +151.035268 -6.190951 +150.472028 -6.277784 +150.105922 -6.322374 +# -b +154.677557 -4.954169 +154.743268 -5.076204 +154.743268 -5.296807 +154.677557 -4.954169 +154.677557 -4.954169 +# -b +154.832448 -5.418842 +155.097640 -5.484554 +155.494255 -5.970349 +156.012906 -6.432675 +156.024640 -6.740110 +155.592822 -6.796435 +155.318242 -6.244928 +154.865303 -5.770868 +154.832448 -5.418842 +154.832448 -5.418842 +# -b +156.587880 -6.596954 +156.874194 -6.751845 +157.195711 -6.972447 +157.568857 -7.157847 +157.249688 -7.202437 +156.674713 -6.718989 +156.587880 -6.596954 +# -b +156.653592 -7.500485 +156.862460 -7.709353 +156.752159 -7.775065 +156.653592 -7.500485 +156.653592 -7.500485 +# -b +157.205098 -7.850164 +157.172242 -8.082500 +157.151121 -7.796186 +157.205098 -7.850164 +# -b +157.371723 -8.181067 +157.493759 -7.960465 +157.702627 -8.148212 +157.834050 -8.488503 +157.449169 -8.246779 +157.371723 -8.181067 +# -b +157.383457 -8.554214 +157.449169 -8.422791 +157.458556 -8.608191 +157.383457 -8.554214 +# -b +158.045265 -8.608191 +158.089855 -8.509624 +158.176688 -8.641047 +158.045265 -8.608191 +# -b +158.629627 -7.509872 +158.915941 -7.653029 +159.326637 -7.906488 +159.699784 -8.103622 +159.932120 -8.324224 +159.821819 -8.399323 +159.368880 -8.103622 +158.915941 -7.873632 +158.629627 -7.509872 +158.629627 -7.509872 +# -b +159.678662 -9.277039 +159.932120 -9.331016 +159.932120 -9.331016 +# -b +160.075277 -9.833239 +159.666928 -9.504682 +159.678662 -9.277039 +# -b +152.722643 -8.948482 +153.065281 -9.166738 +152.811823 -9.145616 +152.722643 -8.948482 +# -b +150.648041 -9.342751 +150.889765 -9.396728 +151.077511 -9.701816 +150.659775 -9.528151 +150.648041 -9.342751 +# -b +150.967210 -9.800383 +151.187813 -9.952928 +151.375559 -9.964662 +# -b +151.122101 -10.018639 +150.967210 -9.800383 +150.967210 -9.800383 +# -b +149.953377 -9.593862 +150.150512 -9.692429 +150.019089 -9.767528 +# -b +146.695970 -1.999504 +146.850861 -2.032359 +147.116054 -2.210719 +146.895451 -2.198985 +146.728826 -2.067562 +146.695970 -1.999504 +# -b +149.664717 -1.335349 +149.852463 -1.511362 +149.643595 -1.379939 +149.664717 -1.335349 +# -b +147.181765 -5.252217 +147.357778 -5.395374 +147.170031 -5.341397 +147.181765 -5.252217 +# -b +147.921018 -5.538531 +148.031319 -5.529144 +148.207332 -5.738012 +148.019585 -5.726278 +147.921018 -5.538531 +147.921018 -5.538531 +# -b +148.451403 -5.517409 +148.650884 -5.496288 +149.235246 -5.538531 +149.599005 -5.538531 +149.908788 -5.517409 +# -b +150.105922 -6.322374 +149.509826 -6.134627 +148.925464 -5.937493 +148.451403 -5.529144 +148.451403 -5.517409 +# -b +141.119890 -2.576825 +141.495384 -2.731716 +142.025768 -2.919463 +142.577275 -3.172921 +143.128781 -3.318425 +143.703755 -3.506172 +144.323320 -3.759630 +144.764525 -4.081146 +145.438067 -4.468374 +145.956717 -5.076204 +146.022429 -5.505675 +146.663115 -5.726278 +147.214621 -5.946880 +147.777861 -6.090037 +147.998464 -6.718989 +147.500935 -6.805822 +147.268598 -7.049893 +147.590114 -7.542728 +148.075909 -7.972199 +148.141621 -8.049644 +# -b +148.129886 -8.049644 +148.308246 -8.115356 +148.451403 -8.608191 +148.871486 -9.079905 +149.312691 -9.023581 +149.357281 -9.441318 +149.953377 -9.593862 +149.953377 -9.593862 +# -b +150.019089 -9.767528 +149.953377 -9.898951 +# -b +147.899897 -10.051495 +147.479813 -9.570394 +147.202887 -9.396728 +147.083198 -9.220715 +146.773416 -9.035315 +146.409656 -8.476768 +145.966105 -8.049644 +145.438067 -7.861898 +145.259707 -7.817308 +144.940538 -7.664764 +144.687079 -7.620174 +144.377297 -7.643642 +143.903236 -7.554462 +143.870381 -8.026176 +143.605188 -8.190455 +143.128781 -8.366467 +143.426829 -8.793591 +143.262550 -9.035315 +142.908178 -9.253571 +142.544419 -9.211328 +142.290961 -9.178472 +141.805166 -9.220715 +141.518852 -9.133882 +141.119890 -9.056437 +140.502672 -8.488503 +140.115445 -8.136477 +140.028612 -8.059032 +# -b +139.927698 -2.344488 +140.336047 -2.353876 +140.612974 -2.398466 +140.833576 -2.499379 +140.964999 -2.586212 +141.119890 -2.576825 +141.119890 -2.576825 +# -b +140.028612 -8.059032 +139.420781 -8.148212 +139.024166 -8.169333 +138.956108 -8.357080 +138.538371 -8.357080 +138.007987 -8.432179 +137.975131 -8.059032 +138.383480 -7.455895 +138.934986 -7.509872 +138.878662 -7.258761 +138.836419 -7.103870 +138.768361 -6.730723 +138.503169 -6.256662 +138.449192 -5.803723 +138.183999 -5.451698 +137.864830 -5.296807 +137.752182 -5.174771 +137.400156 -5.043349 +136.893240 -4.897845 +136.252554 -4.688977 +135.701048 -4.534085 +135.257496 -4.468374 +135.060362 -4.379194 +134.750579 -4.003701 +134.396207 -4.102268 +134.065304 -3.837075 +133.811845 -3.527293 +133.877557 -2.975787 +133.746134 -3.428726 +133.570121 -3.837075 +133.194628 -4.114002 +132.896580 -4.024822 +132.851990 -3.562496 +132.575063 -3.118944 +131.990701 -2.952319 +132.443640 -2.698860 +133.060858 -2.553357 +133.645220 -2.565091 +133.889291 -2.187250 +133.382375 -2.243574 +132.521086 -2.276430 +132.044679 -2.067562 +131.802955 -1.600542 +131.317160 -1.457385 +130.986256 -1.457385 +131.007377 -1.314228 +131.251448 -0.868329 +131.648063 -0.781496 +132.166714 -0.427124 +132.905967 -0.415390 +133.415230 -0.790883 +134.023061 -0.790883 +134.231929 -1.555952 +134.187339 -2.243574 +134.473653 -2.797427 +134.705990 -2.609681 +134.938326 -3.184655 +135.379531 -3.384136 +135.853592 -3.086088 +136.097663 -2.776306 +136.473156 -2.264696 +136.881506 -2.198985 +137.245265 -1.889202 +137.555047 -1.612276 +138.017374 -1.469119 +138.437457 -1.689721 +138.845807 -1.889202 +139.409047 -2.121539 +139.817396 -2.321020 +139.927698 -2.344488 +# -b +135.489832 -0.748640 +135.665845 -0.704051 +136.020217 -0.826086 +136.329999 -1.147602 +135.942772 -1.135868 +135.588400 -0.826086 +135.489832 -0.748640 +# -b +135.611868 -1.633397 +135.755025 -1.600542 +136.207964 -1.689721 +136.747736 -1.722577 +136.660903 -1.910324 +136.074194 -1.811757 +135.632989 -1.677987 +135.611868 -1.633397 +# -b +130.423015 -0.114995 +130.500461 -0.070405 +131.260836 -0.337944 +130.852486 -0.436511 +130.455871 -0.281620 +130.423015 -0.114995 +130.423015 -0.114995 +# -b +130.699942 -0.990364 +130.908810 -0.912919 +131.007377 -1.269638 +130.732798 -1.091278 +130.699942 -0.990364 +# -b +129.958342 -1.800023 +130.300980 -1.710843 +130.390160 -1.999504 +130.047522 -2.088683 +# -b +129.892631 -3.018030 +130.345570 -3.008643 +130.631884 -3.363015 +130.864220 -3.726774 +130.512195 -3.738508 +130.035788 -3.473316 +130.035788 -3.473316 +# -b +133.072592 -5.395374 +133.194628 -5.362518 +133.028002 -5.681688 +133.072592 -5.395374 +# -b +134.297640 -5.803723 +134.506509 -5.451698 +134.762314 -5.726278 +134.738845 -6.003204 +134.705990 -6.376351 +134.407941 -6.212073 +134.431410 -5.836579 +134.297640 -5.803723 +# -b +134.231929 -6.212073 +134.199073 -6.101771 +134.309374 -6.179217 +134.518243 -6.310640 +134.595688 -6.498386 +134.452531 -6.432675 +134.253050 -6.244928 +134.231929 -6.212073 +# -b +134.175605 -6.233194 +134.375086 -6.432675 +134.485387 -6.674399 +134.264785 -6.939591 +134.098159 -6.653278 +134.243663 -6.695521 +134.175605 -6.355230 +134.175605 -6.233194 +# -b +131.183390 -7.784452 +131.239714 -7.653029 +131.460317 -7.345594 +131.713775 -7.202437 +131.594086 -7.763331 +131.317160 -7.972199 +131.183390 -7.784452 +# -b +129.782329 -1.856347 +129.880897 -1.856347 +129.958342 -1.800023 +# -b +130.047522 -2.088683 +129.782329 -1.856347 +129.782329 -1.856347 +# -b +127.982307 -3.527293 +127.961185 -3.130678 +128.238112 -2.863139 +128.700438 -2.907729 +129.197968 -2.907729 +129.728352 -2.898341 +129.892631 -3.018030 +# -b +130.035788 -3.473316 +129.540605 -3.363015 +129.242557 -3.449848 +128.899919 -3.285569 +128.536160 -3.485050 +128.160666 -3.196389 +128.026897 -3.461582 +127.982307 -3.527293 +# -b +129.650907 -7.906488 +129.838654 -7.850164 +129.716618 -8.026176 +129.650907 -7.906488 +# -b +128.590137 -7.181315 +128.688704 -7.148460 +128.590137 -7.181315 +128.590137 -7.181315 +# -b +125.907705 -8.026176 +125.961682 -7.697619 +126.393500 -7.664764 +126.679813 -7.608439 +126.658692 -7.850164 +126.161163 -7.983933 +125.907705 -8.026176 +# -b +124.781224 -9.068171 +124.990092 -8.903892 +125.278753 -8.652781 +125.797403 -8.563601 +126.217487 -8.521358 +126.780727 -8.432179 +127.198464 -8.411057 +126.834705 -8.793591 +126.128307 -9.089292 +125.511090 -9.286427 +125.112128 -9.417849 +125.067538 -9.603249 +124.825814 -9.887216 +124.825814 -9.887216 +# -b +123.722801 -10.009252 +123.711067 -9.626718 +124.053705 -9.352138 +124.307163 -9.232449 +124.616945 -9.133882 +124.781224 -9.068171 +# -b +124.494910 -8.190455 +124.670923 -8.190455 +125.112128 -8.267900 +124.748368 -8.455647 +124.527766 -8.300756 +124.494910 -8.190455 +# -b +124.020849 -8.465034 +124.164006 -8.267900 +124.173394 -8.554214 +124.020849 -8.465034 +# -b +123.356695 -8.521358 +123.466996 -8.223310 +123.666477 -8.202189 +123.722801 -8.432179 +123.413019 -8.575336 +123.356695 -8.521358 +# -b +120.000721 -8.443913 +120.254179 -8.324224 +120.662528 -8.213923 +121.138936 -8.345346 +121.490961 -8.575336 +121.955634 -8.443913 +122.230214 -8.563601 +122.638563 -8.411057 +122.915490 -8.256166 +122.870900 -8.037910 +122.960080 -8.399323 +122.596320 -8.706758 +121.976756 -8.849915 +121.336070 -8.903892 +120.772829 -8.838181 +120.188467 -8.805325 +120.033576 -8.817060 +# -b +119.878685 -8.488503 +120.000721 -8.443913 +# -b +120.000721 -9.277039 +120.244791 -9.462439 +120.608551 -9.713551 +120.796298 -9.931806 +# -b +119.902154 -9.352138 +120.000721 -9.277039 +# -b +120.188467 0.028162 +120.155612 -0.758028 +120.629672 -1.201580 +121.138936 -1.379939 +121.469839 -0.957509 +121.899310 -0.924653 +122.286538 -0.802618 +122.838044 -0.790883 +123.037525 -0.582015 +123.478730 -0.692316 +123.114971 -0.903532 +122.518875 -1.412795 +121.943900 -1.734311 +121.413515 -1.800023 +121.899310 -2.421934 +122.298272 -2.898341 +122.417961 -3.327812 +122.286538 -3.637594 +122.605708 -4.081146 +122.894368 -4.280627 +122.495406 -4.435518 +121.932166 -4.864989 +121.547285 -4.379194 +121.314948 -3.860544 +121.127202 -3.118944 +121.049756 -2.642536 +120.387948 -2.919463 +120.441926 -3.649329 +120.420804 -4.578675 +120.387948 -5.285073 +120.155612 -5.615976 +120.155612 -5.615976 +# -b +121.866455 -5.198240 +122.033080 -5.130182 +122.009612 -5.439964 +121.866455 -5.198240 +121.866455 -5.198240 +# -b +122.375718 -4.721832 +122.450817 -4.733566 +122.694887 -4.667855 +122.727743 -5.052736 +122.596320 -5.317928 +122.331128 -5.120794 +122.375718 -4.721832 +122.375718 -4.721832 +# -b +122.805189 -4.998759 +122.861513 -4.677242 +122.981201 -4.358073 +123.201804 -4.754688 +123.014057 -4.965903 +123.168948 -5.240483 +122.948346 -5.538531 +122.673766 -5.439964 +122.805189 -4.998759 +122.805189 -4.998759 +# -b +123.037525 -4.015435 +123.114971 -3.991967 +123.213538 -4.224303 +123.025791 -4.036556 +123.037525 -4.015435 +# -b +123.070381 -1.156990 +123.201804 -1.213314 +123.014057 -1.555952 +122.861513 -1.290759 +123.070381 -1.156990 +123.070381 -1.156990 +# -b +123.225272 -1.379939 +123.511586 -1.269638 +123.457609 -1.555952 +123.213538 -1.511362 +123.225272 -1.379939 +# -b +124.417464 -1.668600 +124.616945 -1.668600 +124.957236 -1.746045 +125.213041 -1.734311 +125.213041 -1.823491 +124.769490 -1.910324 +124.450320 -1.910324 +124.417464 -1.668600 +124.417464 -1.668600 +# -b +125.421910 -1.823491 +125.630778 -1.856347 +125.996884 -1.800023 +126.304320 -1.788288 +125.907705 -1.910324 +125.466500 -1.877468 +125.421910 -1.823491 +# -b +125.907705 -2.011238 +125.973416 -2.177863 +125.996884 -2.377344 +125.907705 -2.011238 +125.907705 -2.011238 +# -b +126.062596 -3.086088 +126.238608 -3.140065 +126.736137 -3.018030 +127.088163 -3.327812 +127.165608 -3.693918 +126.548391 -3.804220 +126.095451 -3.372402 +126.062596 -3.086088 +126.062596 -3.086088 +# -b +127.928330 0.061018 +128.170054 -0.647726 +128.280355 -0.891797 +127.749970 -0.269886 +127.749970 -0.269886 +# -b +127.353355 -0.359066 +127.597426 -0.459980 +127.839150 -0.781496 +127.519980 -0.802618 +127.365089 -0.427124 +127.353355 -0.359066 +# -b +127.409679 -1.445650 +127.794560 -1.391673 +128.160666 -1.600542 +127.707727 -1.701455 +127.397945 -1.591154 +127.409679 -1.445650 +# -b +128.059752 -3.815954 +128.005775 -3.705653 +128.238112 -3.517906 +128.247499 -3.750243 +128.005775 -3.783098 +128.005775 -3.783098 +# -b +112.150557 -8.256166 +111.843122 -8.324224 +111.554461 -8.291369 +111.268147 -8.157599 +110.859798 -8.181067 +110.418593 -8.005055 +110.010244 -7.763331 +110.010244 -7.763331 +# -b +109.944532 -6.838678 +110.418593 -6.939591 +110.704907 -6.608688 +111.002955 -6.388085 +111.411304 -6.662665 +111.753942 -6.662665 +112.051990 -6.796435 +112.117701 -6.838678 +112.427484 -6.829290 +112.713798 -7.169581 +112.892157 -7.566196 +113.455397 -7.697619 +114.084349 -7.631908 +114.448109 -8.016789 +114.436375 -8.509624 +114.469230 -8.751348 +113.753446 -8.476768 +112.978990 -8.357080 +112.284327 -8.291369 +112.150557 -8.256166 +112.150557 -8.256166 +# -b +117.583480 0.007041 +117.517769 -0.481101 +117.142275 -1.180458 +116.787903 -1.401061 +116.325577 -1.767167 +116.489855 -2.022972 +116.689336 -2.255309 +116.489855 -2.532235 +116.346698 -2.964053 +116.248131 -3.151800 +116.104974 -3.318425 +115.982939 -3.571883 +115.771724 -3.705653 +115.574590 -3.815954 +115.100529 -4.036556 +114.725035 -4.092880 +114.656977 -3.715040 +114.469230 -3.485050 +114.194651 -3.363015 +113.762833 -3.440460 +113.521109 -3.208124 +113.166737 -3.062620 +113.044701 -3.184655 +112.516663 -3.395870 +112.218615 -3.395870 +112.040256 -3.440460 +111.962810 -3.485050 +111.908833 -3.372402 +111.831388 -2.996908 +111.688231 -2.863139 +111.545074 -2.931197 +111.235291 -2.996908 +110.892654 -3.008643 +110.639195 -2.964053 +110.329413 -2.952319 +110.275436 -2.520501 +110.132279 -2.145007 +110.010244 -1.767167 +110.043099 -1.347083 +110.043099 -1.347083 +# -b +116.269253 -3.285569 +116.334964 -3.440460 +116.358433 -3.750243 +116.367820 -3.914521 +116.158952 -3.914521 +116.126096 -3.527293 +116.215276 -3.294957 +116.269253 -3.285569 +# -b +120.033576 -8.817060 +119.857564 -8.596457 +119.878685 -8.488503 +# -b +120.134490 -10.063229 +119.460949 -9.790996 +119.094842 -9.450705 +119.547781 -9.352138 +119.902154 -9.352138 +119.902154 -9.352138 +# -b +117.109420 -8.411057 +117.473179 -8.389936 +117.848673 -8.641047 +118.102131 -8.641047 +118.036420 -8.432179 +117.980096 -8.070766 +118.411913 -8.312490 +118.721695 -8.497890 +119.029131 -8.411057 +119.205144 -8.685637 +118.918830 -8.718493 +118.510480 -8.772470 +117.958974 -8.903892 +117.285432 -9.079905 +116.853615 -8.892158 +116.963916 -8.530746 +117.109420 -8.411057 +# -b +116.104974 -8.455647 +116.367820 -8.223310 +116.743313 -8.521358 +116.534445 -8.936748 +115.959471 -8.871037 +116.104974 -8.575336 +116.104974 -8.455647 +# -b +115.044205 -8.091888 +115.398577 -8.082500 +115.684891 -8.443913 +115.264807 -8.817060 +114.955025 -8.411057 +114.579531 -8.300756 +114.779012 -8.070766 +115.023083 -8.091888 +115.044205 -8.091888 +# -b +112.802977 -6.927857 +113.145615 -6.850412 +113.807423 -6.873880 +113.974048 -7.092136 +113.300506 -7.193050 +112.835833 -7.103870 +112.802977 -6.927857 +# -b +115.297663 -6.784700 +115.607445 -6.817556 +115.398577 -7.005303 +115.297663 -6.784700 +# -b +120.155612 -5.615976 +119.526660 -5.571387 +119.470336 -5.120794 +119.625227 -4.358073 +119.580637 -3.661063 +119.106576 -3.506172 +118.918830 -2.842017 +119.249733 -2.109805 +119.371769 -1.302493 +119.714407 -0.769762 +119.890419 -0.570281 +119.791852 -0.049284 +119.791852 -0.049284 +# -b +103.838067 0.072752 +103.650320 -0.227643 +103.596343 -0.492835 +103.805211 -0.936387 +104.269885 -1.046688 +104.600789 -1.424529 +104.621910 -1.877468 +105.009138 -2.076949 +105.041994 -2.309286 +105.539523 -2.365610 +105.891548 -2.698860 +106.145006 -3.140065 +105.968993 -3.726774 +105.992462 -4.092880 +105.968993 -4.566941 +105.968993 -5.097326 +105.924404 -5.606589 +105.694414 -5.726278 +105.372897 -5.561999 +105.030259 -5.615976 +104.800270 -5.660566 +104.577320 -5.693422 +104.147849 -5.285073 +103.718379 -4.864989 +103.265439 -4.522351 +102.789032 -4.191448 +102.404151 -3.705653 +101.918356 -3.250367 +101.498272 -2.741103 +101.089923 -2.321020 +100.979622 -1.877468 +100.571273 -1.091278 +100.261490 -0.537425 +100.029154 -0.305089 +# -b +104.445897 -0.481101 +104.556199 -0.349678 +104.654766 -0.591402 +104.645378 -0.359066 +104.445897 -0.481101 +104.445897 -0.481101 +# -b +105.262596 -1.889202 +105.429221 -1.722577 +105.516054 -1.567686 +105.748391 -1.668600 +105.870426 -1.689721 +106.025317 -1.490240 +106.245920 -2.088683 +106.511112 -2.454790 +106.809160 -2.508767 +106.741102 -2.919463 +106.687125 -3.062620 +106.222452 -2.809162 +106.058173 -2.443055 +105.760125 -2.088683 +105.396366 -1.978382 +105.262596 -1.889202 +105.262596 -1.889202 +# -b +107.790137 -2.541622 +108.034208 -2.532235 +108.341644 -2.752838 +108.231342 -3.151800 +107.956763 -3.130678 +107.691570 -2.952319 +107.736160 -2.630802 +107.790137 -2.541622 +# -b +110.010244 -7.763331 +109.634750 -7.697619 +109.280378 -7.653029 +109.038654 -7.709353 +108.707750 -7.742209 +108.442558 -7.763331 +107.912173 -7.643642 +107.217510 -7.488751 +106.764571 -7.357328 +106.478257 -7.223559 +106.621414 -6.981835 +106.102763 -6.829290 +105.649824 -6.772966 +105.384631 -6.674399 +105.340042 -6.620422 +105.417487 -6.608688 +105.703801 -6.596954 +105.947872 -6.322374 +106.168474 -5.946880 +106.731715 -5.979736 +107.184654 -5.902290 +107.560148 -6.167483 +108.144510 -6.244928 +108.564593 -6.498386 +108.904884 -6.796435 +109.202932 -6.796435 +109.590160 -6.784700 +109.944532 -6.838678 +# -b +110.043099 -1.347083 +109.810763 -0.891797 +109.623016 -0.659461 +109.315580 -0.525691 +109.202932 -0.082139 +109.202932 -0.082139 +# -b +100.029154 -0.305089 +99.963442 -0.147851 +# -b +98.836961 -0.936387 +99.069298 -0.948121 +99.334490 -1.523096 +99.245311 -1.755433 +98.902673 -1.469119 +98.771250 -1.079544 +98.836961 -0.936387 +# -b +55.275008 -4.569288 +55.275008 -4.569288 +55.275008 -4.569288 +# -b +43.137177 0.192440 +42.529346 -0.272233 +42.639647 -0.361413 +42.308744 -0.748640 +41.869886 -1.304840 +41.506126 -1.846959 +41.074308 -1.957260 +40.877174 -2.377344 +40.292812 -2.853752 +40.093331 -3.508519 +# -b +46.443867 -9.417849 +46.300710 -9.483561 +46.443867 -9.417849 +46.443867 -9.417849 +# -b +34.151145 -0.938734 +34.007988 -1.147602 +33.942276 -1.304840 +33.808507 -1.492587 +33.698206 -1.703802 +33.501071 -1.835225 +33.379036 -2.013585 +33.501071 -2.145007 +33.766264 -2.123886 +33.599639 -2.400812 +33.071601 -2.489992 +32.904975 -2.898341 +32.782940 -2.522848 +32.386325 -2.311633 +32.231434 -2.532235 +32.055421 -2.677739 +31.825431 -2.588559 +31.769107 -2.201331 +31.769107 -1.659212 +31.870021 -1.049035 +31.780841 -0.894144 +# -b +29.861130 -6.388085 +30.445492 -6.796435 +30.600383 -7.369062 +30.877310 -8.005055 +31.163624 -8.554214 +31.163624 -8.554214 +# -b +34.040844 -9.692429 +34.404603 -9.746406 +34.559494 -9.997518 +# -b +34.040844 -9.692429 +34.073699 -9.887216 +# -b +29.994900 -7.237640 +30.480695 -7.873632 +30.579262 -8.148212 +# -b +30.633239 -8.235044 +30.612117 -8.554214 +31.008733 -8.772470 +31.163624 -8.554214 +# -b +34.019722 0.114995 +34.139411 -0.194787 +34.437459 -0.272233 +34.812952 -0.340291 +34.249712 -0.539772 +34.151145 -0.938734 +# -b +32.419180 0.103261 +31.956854 -0.140810 +31.902877 -0.506916 +31.759720 -0.849554 +31.780841 -0.894144 +# -b +40.093331 -3.508519 +39.586415 -4.524698 +39.332957 -4.646734 +# -b +39.929053 -5.087939 +39.929053 -5.055083 +39.774162 -5.341397 +39.839873 -4.921313 +39.929053 -5.087939 +39.929053 -5.087939 +# -b +39.386934 -5.761480 +39.431524 -5.916371 +39.574681 -6.212073 +39.553559 -6.388085 +39.344691 -6.026673 +39.386934 -5.761480 +# -b +39.332957 -4.646734 +39.267245 -4.998759 +39.067764 -5.639445 +38.912873 -6.280131 +39.234390 -6.587566 +39.619271 -7.094483 +39.476114 -7.336207 +39.476114 -7.786799 +39.476114 -8.159946 +39.377547 -8.476768 +39.565293 -8.828794 +39.598149 -9.035315 +39.753040 -9.342751 +39.872729 -9.668961 +39.929053 -9.997518 +39.929053 -9.997518 +# -b +29.696852 -4.381541 +29.708586 -5.010493 +29.840009 -5.439964 +29.905720 -6.036060 +29.861130 -6.388085 +# -b +29.333092 -3.386483 +29.464515 -3.729121 +29.586550 -4.271240 +29.696852 -4.381541 +# -b +29.333092 -3.386483 +29.178201 -3.928602 +29.243913 -4.193794 +29.157080 -5.087939 +29.377682 -5.881169 +29.497371 -6.542976 +29.994900 -7.237640 +29.994900 -7.237640 +# -b +13.290127 -10.018639 +13.060137 -9.187860 +13.280740 -8.817060 +13.215029 -8.258513 +13.015548 -7.861898 +12.839535 -7.193050 +12.541487 -6.730723 +12.288029 -6.301252 +12.309150 -6.059528 +12.133138 -5.728625 +12.067426 -5.165384 +11.846824 -4.801625 +11.537041 -4.369807 +11.074715 -3.970845 +10.767280 -3.541374 +10.072616 -2.886607 +9.563353 -2.278777 +9.166738 -1.746045 +8.903892 -1.070157 +8.826447 -0.748640 +9.199594 -0.429471 +9.232449 -0.194787 +# -b +-40.062822 -19.779126 +-39.743653 -19.361390 +-39.731919 -18.762947 +-39.623964 -18.122261 +-39.260205 -17.702177 +-39.269592 -17.237504 +-39.225002 -16.854970 +-39.126435 -16.291729 +-39.016134 -15.897461 +-39.114701 -15.536049 +-39.114701 -15.118312 +-39.138169 -14.883628 +-39.126435 -14.336816 +-39.072458 -13.724292 +-39.016134 -13.369920 +-38.685230 -12.926368 +-38.455240 -12.980345 +-38.046891 -12.527406 +-37.760577 -12.039264 +-37.572830 -11.670811 +-37.295904 -11.215525 +-37.028365 -10.999616 +-36.643484 -10.661672 +-36.157689 -10.150062 +-36.157689 -10.150062 +# -b +-40.250569 -20.185129 +-40.062822 -19.779126 +-40.062822 -19.779126 +# -b +-70.097618 -15.406973 +-69.820692 -15.205145 +-69.456932 -15.514927 +-69.170619 -15.791854 +-68.752882 -15.876340 +-68.795125 -16.111023 +-68.785738 -16.333972 +-69.137763 -16.345707 +-69.480401 -16.111023 +-69.766715 -15.812975 +-69.886403 -15.812975 +# -b +-77.769423 -11.126345 +-77.715445 -11.323479 +-77.638000 -11.508879 +-77.262506 -11.985287 +-76.943337 -12.503938 +-76.645288 -12.959224 +-76.347240 -13.454406 +-76.481010 -13.982444 +-76.150106 -14.465892 +-75.786347 -14.829651 +-75.312286 -15.301365 +-74.772514 -15.641656 +-74.164684 -15.972560 +-73.988671 -16.143879 +-73.514610 -16.345707 +-72.841069 -16.632021 +-72.181608 -17.002821 +-71.573778 -17.427598 +-71.144307 -17.859415 +-70.581067 -18.248990 +-70.527089 -18.354598 +-70.405054 -18.974162 +-70.339342 -19.579645 +-70.261897 -19.830757 +# -b +-70.041294 -15.599413 +-70.097618 -15.451562 +-70.097618 -15.406973 +# -b +-69.886403 -15.812975 +-70.041294 -15.599413 +-70.041294 -15.599413 +# -b +-78.229402 -9.985783 +-78.065124 -10.380052 +-77.832787 -10.901049 +-77.769423 -11.126345 +-77.769423 -11.126345 +# -b +-149.453502 -17.568408 +-149.444114 -17.697484 +-149.354934 -17.918086 +-149.674104 -17.643506 +-149.453502 -17.568408 +-149.453502 -17.568408 +# -b +-145.639894 -17.326684 +-145.541327 -17.495656 +-145.693872 -17.293828 +-145.693872 -17.293828 +-145.639894 -17.326684 +# -b +-145.121244 -16.073474 +-145.121244 -16.042965 +# -b +-146.433125 -14.428342 +-146.522304 -14.503441 +-146.367413 -14.440077 +-146.433125 -14.428342 +# -b +-146.113955 -14.374365 +-146.191401 -14.503441 +-146.036510 -14.353244 +-146.113955 -14.374365 +# -b +-140.336047 -15.988988 +-140.347781 -16.000722 +-140.249214 -15.935011 +-140.336047 -15.988988 +# -b +-140.589505 -19.678213 +-140.535528 -19.596073 +-140.577771 -19.617195 +# -b +-145.067267 -19.814329 +-145.165834 -19.877694 +-145.067267 -19.814329 +-145.067267 -19.814329 +# -b +-150.005008 -17.568408 +-149.918175 -17.495656 +-149.960418 -17.483922 +# -b +-151.626671 -16.744669 +-151.516370 -16.754056 +-151.582081 -16.838542 +-151.626671 -16.744669 +# -b +-150.005008 -17.505043 +-150.005008 -17.568408 +# -b +-149.960418 -17.483922 +-150.005008 -17.505043 +# -b +-160.908404 -10.368318 +-160.809837 -10.389439 +-160.908404 -10.401173 +-160.908404 -10.368318 +# -b +-172.827979 -13.470834 +-172.452486 -13.599910 +-172.452486 -13.836940 +-172.762268 -13.815818 +-173.036848 -13.557667 +-173.048582 -13.491955 +-172.827979 -13.470834 +# -b +-171.945569 -13.848674 +-171.757823 -13.881530 +-171.605278 -14.031727 +-171.978425 -14.041115 +-172.231883 -13.977750 +-172.112195 -13.836940 +-171.945569 -13.848674 +# -b +-170.016471 -18.969468 +-170.004737 -19.084463 +-170.115038 -18.957734 +-170.016471 -18.969468 +-170.016471 -18.969468 +# -b +177.789189 -17.420557 +177.965201 -17.378314 +178.108358 -17.453413 +178.352429 -17.612998 +178.418141 -17.864109 +178.319574 -18.117567 +177.965201 -18.244296 +177.678888 -18.223175 +177.437164 -18.129301 +177.160237 -18.033081 +177.204827 -17.655241 +177.514609 -17.441679 +177.789189 -17.420557 +177.789189 -17.420557 +# -b +178.749044 -16.467742 +178.847611 -16.467742 +179.000000 -16.402818 +# -b +179.000000 -16.728223 +178.814756 -16.923028 +178.504974 -16.880785 +178.352429 -16.660183 +178.749044 -16.467742 +178.749044 -16.467742 +# -b +159.967323 -11.731829 +160.307614 -11.839783 +160.089358 -11.839783 +160.089358 -11.839783 +# -b +166.444588 -14.728737 +166.531421 -14.815570 +166.599479 -15.029132 +166.698046 -15.209838 +166.852937 -15.008011 +166.951504 -15.083109 +167.007828 -15.179330 +167.050071 -15.381157 +166.930383 -15.531355 +166.665190 -15.606454 +166.510299 -15.083109 +166.444588 -14.728737 +166.444588 -14.728737 +# -b +167.061805 -15.871646 +167.204962 -15.913889 +167.315264 -16.042965 +167.437299 -16.211937 +167.589843 -16.341013 +167.601578 -16.488864 +167.294142 -16.500598 +167.226084 -16.073474 +167.061805 -15.925623 +167.061805 -15.871646 +# -b +168.031048 -15.477378 +168.063904 -15.594719 +168.131962 -15.808281 +168.054517 -15.820016 +168.031048 -15.477378 +168.031048 -15.477378 +# -b +168.021661 -16.085208 +168.054517 -16.139185 +168.141350 -16.329279 +167.878504 -16.308157 +167.911360 -16.169694 +168.021661 -16.085208 +# -b +168.307975 -17.547286 +168.394808 -17.676362 +168.251651 -17.800744 +168.099107 -17.664628 +168.307975 -17.547286 +168.307975 -17.547286 +# -b +168.836013 -18.643258 +168.946314 -18.654992 +168.990904 -18.842739 +168.868869 -18.842739 +168.868869 -18.842739 +168.836013 -18.643258 +# -b +169.101205 -19.366083 +169.223241 -19.438835 +169.211506 -19.605461 +169.080084 -19.408327 +169.101205 -19.366083 +# -b +161.488072 -10.182918 +161.675819 -10.258016 +162.173348 -10.445763 +162.384563 -10.727383 +162.128758 -10.781361 +161.642963 -10.445763 +161.488072 -10.182918 +161.488072 -10.182918 +# -b +165.728803 -10.804829 +165.794515 -10.717996 +166.071441 -10.706262 +165.937671 -10.814216 +165.782780 -10.825950 +165.728803 -10.804829 +# -b +159.979057 -11.839783 +159.967323 -11.731829 +159.967323 -11.731829 +# -b +160.089358 -11.839783 +159.979057 -11.839783 +# -b +151.375559 -9.964662 +151.122101 -10.018639 +151.122101 -10.018639 +# -b +149.953377 -9.898951 +150.516618 -10.161796 +150.978944 -10.227507 +150.615185 -10.347196 +150.770076 -10.499740 +150.173980 -10.607695 +150.105922 -10.422295 +# -b +139.866680 -17.718605 +140.474510 -17.645853 +140.915715 -17.169446 +141.169174 -16.639061 +141.356920 -15.841137 +141.586910 -15.115965 +141.488343 -14.235902 +141.544667 -13.461446 +141.586910 -13.008507 +141.577523 -12.621279 +141.654968 -12.090895 +141.999953 -11.525307 +142.225249 -10.999616 +142.225249 -10.999616 +# -b +142.722778 -11.025431 +142.767368 -11.264809 +142.833080 -11.926616 +143.065416 -12.165993 +143.229695 -12.576689 +143.330609 -12.891165 +143.539477 -13.419203 +143.593454 -13.935507 +143.837525 -14.430689 +144.234140 -14.313347 +144.619021 -14.409568 +144.994515 -14.806183 +145.259707 -15.212185 +145.280829 -15.651043 +145.435720 -16.129798 +145.501431 -16.617940 +145.876925 -16.925375 +146.052937 -17.498003 +146.106915 -17.983798 +146.106915 -18.467246 +146.294661 -18.676114 +146.318130 -18.730091 +146.404963 -19.053954 +146.902492 -19.305066 +147.331963 -19.377818 +147.564299 -19.743924 +147.838879 -19.765045 +148.148661 -19.889428 +# -b +142.225249 -10.999616 +142.302695 -10.912783 +142.621864 -10.706262 +142.727472 -10.858806 +142.727472 -10.999616 +142.727472 -11.025431 +# -b +150.105922 -10.422295 +149.378403 -10.302606 +148.848018 -10.204039 +148.174476 -10.150062 +147.899897 -10.051495 +# -b +129.923140 -13.581135 +130.209453 -13.245537 +130.110886 -12.977998 +130.507502 -12.684644 +130.805550 -12.651788 +130.793815 -12.480469 +131.068395 -12.327925 +131.279610 -12.285682 +131.840504 -12.349046 +132.237119 -12.273948 +132.502311 -11.938350 +132.204263 -11.569897 +131.840504 -11.396231 +131.741937 -11.297664 +131.908562 -11.199097 +132.007129 -11.525307 +132.138552 -11.231953 +132.314565 -11.297664 +132.546901 -11.569897 +132.734648 -11.450209 +133.009228 -11.764685 +133.340132 -11.818662 +133.605324 -11.806928 +133.671035 -11.905495 +134.013673 -12.025183 +134.422023 -12.121403 +134.729458 -12.165993 +135.104952 -12.327925 +135.313820 -12.133138 +135.501567 -12.079160 +135.776146 -12.025183 +135.722169 -12.187115 +135.898182 -12.177727 +135.898182 -12.403024 +135.975627 -12.567302 +136.163374 -12.295069 +136.416832 -12.025183 +136.625701 -12.285682 +136.780592 -12.435879 +136.538868 -12.846575 +136.470810 -12.945143 +136.470810 -13.170439 +136.285410 -13.278393 +136.074194 -13.269006 +136.064807 -13.440325 +135.865326 -13.515424 +135.886448 -13.752454 +135.886448 -14.064583 +135.710435 -14.472932 +135.534422 -15.029132 +135.853592 -15.191064 +136.008483 -15.329527 +136.327653 -15.618188 +136.571723 -15.895114 +137.210063 -15.979600 +137.674736 -16.310504 +138.104207 -16.671917 +138.676835 -16.831502 +139.129774 -17.202301 +139.514655 -17.519124 +139.866680 -17.718605 +139.866680 -17.718605 +# -b +130.054562 -11.839783 +130.000585 -11.851517 +# -b +129.967729 -11.698973 +130.110886 -11.417353 +130.286899 -11.677852 +130.408934 -11.839783 +130.054562 -11.839783 +# -b +130.254043 -11.255421 +130.462912 -11.417353 +130.749226 -11.438474 +131.080129 -11.342254 +131.357056 -11.396231 +131.312466 -11.656730 +130.969828 -11.905495 +130.552091 -11.710707 +130.308021 -11.384497 +130.254043 -11.255421 +# -b +136.428567 -11.525307 +136.416832 -11.297664 +136.592845 -11.243687 +136.428567 -11.525307 +# -b +136.405098 -13.818165 +136.571723 -13.743067 +136.780592 -14.085704 +136.703146 -14.322735 +136.405098 -13.818165 +136.405098 -13.818165 +# -b +139.580366 -16.437233 +139.779847 -16.566309 +139.535776 -16.671917 +139.207219 -16.650795 +139.481799 -16.416112 +139.580366 -16.437233 +# -b +119.878685 -19.941058 +120.474781 -19.765045 +121.014553 -19.535056 +121.321989 -19.262823 +121.509736 -18.887329 +121.688095 -18.612749 +121.974409 -18.352251 +122.195011 -18.002572 +122.061242 -17.476881 +122.305313 -16.988739 +122.624482 -16.744669 +122.678460 -16.650795 +122.845085 -16.608552 +123.032832 -16.988739 +123.340267 -17.486269 +123.506892 -17.117815 +123.650049 -16.883132 +123.462302 -16.521719 +123.528014 -16.160307 +123.957485 -16.343360 +124.386955 -16.542841 +124.300123 -16.129798 +124.541847 -15.841137 +124.541847 -15.437481 +124.929074 -15.458603 +124.839895 -15.137087 +125.236510 -15.158208 +125.116821 -14.677107 +125.480581 -14.559765 +125.665981 -14.698228 +125.987497 -14.334469 +125.942907 -14.001218 +126.175244 -14.184272 +126.306667 -14.184272 +126.625836 -14.055196 +126.801849 -13.839287 +127.013064 -13.947241 +127.508246 -14.172537 +127.961185 -14.677107 +127.994041 -15.052601 +127.904861 -15.554823 +127.970573 -15.437481 +128.080874 -15.254428 +128.104342 -15.073722 +128.247499 -14.998623 +128.378922 -14.881282 +128.852983 -14.890669 +129.261332 -15.019745 +129.592236 -15.233307 +129.681416 -14.857813 +129.282454 -14.386099 +129.514790 -14.097439 +129.714271 -13.797044 +129.923140 -13.581135 +129.923140 -13.581135 +# -b +130.000585 -11.851517 +129.967729 -11.743563 +129.967729 -11.698973 +# -b +124.825814 -9.887216 +124.471442 -10.171183 +123.964525 -10.347196 +123.567910 -10.258016 +123.722801 -10.009252 +# -b +122.903756 -10.901049 +123.082115 -10.760239 +123.380163 -10.509128 +123.424753 -10.619429 +123.103237 -10.924518 +122.903756 -10.901049 +# -b +120.796298 -9.931806 +120.552227 -10.290872 +120.134490 -10.063229 +# -b +118.864852 -20.077175 +119.008009 -19.952792 +119.249733 -19.941058 +# -b +119.425746 -20.034931 +119.646349 -19.941058 +119.878685 -19.941058 +# -b +49.950039 -14.052849 +50.104930 -14.878935 +50.226965 -15.690940 +50.137786 -15.904502 +# -b +57.492767 -20.011463 +57.558478 -19.980954 +# -b +40.677693 -10.999616 +40.532190 -11.262462 +40.337402 -11.774072 +40.412501 -12.543834 +40.346790 -13.071872 +40.379645 -13.675008 +40.435969 -14.041115 +40.468825 -14.245289 +40.501681 -14.449464 +40.665959 -14.674760 +40.346790 -15.209838 +40.445357 -15.531355 +40.281078 -15.615841 +40.116800 -15.796547 +# -b +43.113708 -11.393885 +43.202888 -11.361029 +43.324923 -11.762338 +43.324923 -11.926616 +43.137177 -11.480717 +43.113708 -11.393885 +# -b +44.305900 -16.265914 +44.437323 -16.169694 +44.878528 -16.106329 +45.120252 -16.085208 +45.397179 -16.042965 +45.695227 -15.766038 +46.026131 -15.754304 +46.378156 -16.096942 +46.267855 -15.754304 +46.697325 -15.252082 +46.852217 -15.540742 +47.051697 -15.369423 +47.204242 -14.857813 +47.347399 -14.815570 +47.591470 -14.674760 +47.800338 -14.590274 +47.591470 -14.299266 +47.856662 -13.977750 +47.800338 -13.557667 +48.164097 -13.665621 +48.330723 -13.287780 +48.715604 -13.017894 +48.626424 -12.445267 +49.023039 -12.175381 +49.586279 -12.780864 +49.785760 -13.254925 +49.950039 -14.052849 +49.950039 -14.052849 +# -b +50.137786 -15.904502 +49.806882 -15.435135 +49.574545 -16.127451 +49.619135 -16.817421 +49.321087 -17.495656 +49.210786 -18.371025 +48.947940 -19.166602 +48.825905 -19.511587 +48.682748 -19.959833 +# -b +44.315288 -20.023197 +44.437323 -19.565564 +44.129888 -18.812230 +43.996118 -18.054203 +43.808371 -17.526165 +44.216721 -16.786912 +44.305900 -16.265914 +44.305900 -16.265914 +# -b +39.929053 -9.997518 +40.227101 -10.281485 +40.489946 -10.389439 +40.677693 -10.652285 +40.656572 -10.945639 +40.677693 -10.999616 +# -b +40.116800 -15.796547 +39.607536 -16.277648 +39.631005 -16.509985 +39.058377 -16.838542 +38.560848 -17.145977 +37.889653 -17.357193 +37.051833 -17.821866 +36.720929 -18.211441 +36.488593 -18.265418 +36.509714 -18.476633 +36.178810 -18.894370 +35.958208 -18.812230 +35.662507 -19.126706 +35.221302 -19.574952 +34.646327 -19.938711 +34.646327 -19.938711 +# -b +34.944375 -11.600406 +34.679183 -11.307052 +34.568881 -11.055940 +# -b +34.327157 -10.999616 +34.172266 -11.142773 +34.139411 -11.339907 +34.216856 -11.752950 +34.029109 -12.130791 +34.061965 -12.597811 +34.172266 -13.146970 +34.371747 -13.590522 +34.482049 -14.085704 +34.714385 -14.257023 +35.066410 -14.364978 +35.164978 -14.386099 +35.000699 -13.858061 +34.824686 -13.665621 +34.789484 -13.644499 +# -b +34.944375 -11.600406 +34.866930 -11.774072 +34.789484 -12.088548 +34.636940 -12.543834 +34.658061 -13.050750 +34.735507 -13.545932 +34.845808 -13.644499 +# -b +34.559494 -9.997518 +34.643980 -10.750852 +34.568881 -10.999616 +# -b +34.073699 -9.887216 +34.261446 -10.380052 +34.327157 -10.793095 +34.327157 -10.999616 +# -b +11.626221 -17.314950 +11.572244 -16.838542 +11.682545 -16.796299 +11.659077 -16.319891 +11.825702 -15.775426 +12.022836 -15.167595 +12.133138 -14.545684 +12.288029 -14.062236 +12.419452 -13.686742 +12.541487 -13.308902 +12.827801 -12.942796 +13.215029 -12.661176 +13.543586 -12.241092 +13.665621 -11.795193 +13.677355 -11.666117 +13.698477 -11.393885 +13.710211 -11.100530 +13.698477 -11.034819 +# -b +12.893512 -20.053706 +12.696378 -19.678213 +12.529753 -19.387205 +12.374862 -19.126706 +12.121403 -18.748866 +11.957125 -18.612749 +11.757644 -18.317048 +11.647343 -17.927474 +11.614487 -17.580142 +11.626221 -17.314950 +11.626221 -17.314950 +# -b +13.698477 -11.034819 +13.710211 -10.553718 +13.290127 -10.018639 +13.290127 -10.018639 +# -b +-50.097889 -29.858783 +-49.776373 -29.377682 +-49.490059 -29.086675 +-49.203745 -28.776892 +-48.839986 -28.652510 +-48.663973 -28.349768 +-48.607649 -27.636330 +-48.574793 -27.223287 +-48.565406 -27.075437 +-48.663973 -26.730452 +-48.675707 -26.512196 +-48.675707 -26.146090 +-48.598262 -25.796412 +-48.255624 -25.437346 +-47.880130 -25.108789 +-47.572695 -24.747376 +-47.164346 -24.505652 +-46.734875 -24.141893 +-46.281936 -23.989349 +-45.831343 -23.757012 +-45.357283 -23.585693 +-45.157802 -23.463658 +-44.904343 -23.311113 +-44.627417 -23.198465 +-44.672007 -23.067042 +-44.373959 -22.933273 +-44.153356 -22.984903 +-43.822452 -22.933273 +-43.416450 -22.963782 +-43.073812 -22.945007 +-42.632607 -22.945007 +-42.203136 -22.881643 +-42.027123 -22.719711 +-41.970799 -22.473293 +-41.365316 -22.156470 +-41.111858 -21.849035 +-41.079002 -21.332731 +-40.736364 -20.868058 +-40.384339 -20.443281 +-40.250569 -20.185129 +# -b +-50.184722 -30.116935 +-50.140133 -29.964391 +-50.097889 -29.858783 +# -b +-70.261897 -19.830757 +-70.252510 -20.370529 +-70.217307 -21.116822 +-70.217307 -21.745774 +-70.318221 -22.372379 +-70.395667 -23.006025 +-70.625656 -23.329888 +-70.515355 -23.564572 +-70.571679 -24.151280 +-70.571679 -24.775538 +-70.538823 -25.097055 +-70.670246 -25.498364 +-70.792282 -25.887938 +-70.726570 -26.244657 +-70.768813 -26.699943 +-70.944826 -27.124720 +-71.012884 -27.401647 +-71.055127 -27.617556 +-71.221752 -28.213652 +-71.353175 -28.708834 +-71.597246 -29.049125 +-71.564390 -29.272075 +-71.442355 -29.591244 +-71.397765 -29.889292 +-71.397765 -29.889292 +# -b +-109.498633 -27.169310 +-109.409454 -27.080131 +-109.531489 -27.129414 +-109.543223 -27.169310 +# -b +-124.945502 -24.641769 +-124.912647 -24.651156 +-124.945502 -24.641769 +# -b +-135.684620 -21.461807 +-135.750331 -21.586190 +-135.684620 -21.461807 +-135.684620 -21.461807 +# -b +-130.270471 -25.043078 +-130.237615 -25.043078 +-130.270471 -25.043078 +# -b +-137.249959 -23.111632 +-137.292202 -23.184384 +-137.249959 -23.111632 +-137.249959 -23.111632 +# -b +-140.798374 -21.750468 +-140.810108 -21.771589 +-140.744396 -21.668329 +-140.798374 -21.750468 +# -b +-175.219404 -21.133250 +-175.219404 -21.297529 +-175.496331 -21.194268 +-175.353174 -21.133250 +-175.219404 -21.133250 +# -b +165.010672 -21.431298 +164.508449 -21.081620 +164.212748 -20.659190 +163.924087 -20.253187 +164.278459 -20.283696 +164.651606 -20.492564 +164.851087 -20.668577 +164.998937 -20.717861 +165.066996 -20.821121 +165.186684 -20.966625 +165.275864 -21.112129 +165.419021 -21.297529 +165.651358 -21.482929 +165.925937 -21.616698 +166.289697 -21.811486 +166.543155 -22.079025 +166.841203 -22.316055 +166.709780 -22.398194 +166.620600 -22.377073 +166.289697 -22.255038 +166.003383 -22.121268 +165.827370 -21.956989 +165.627889 -21.884238 +165.341575 -21.698838 +165.109239 -21.525172 +165.010672 -21.431298 +# -b +166.996094 -20.802347 +167.172107 -20.821121 +167.303530 -21.018255 +167.226084 -21.194268 +166.984360 -20.978359 +166.996094 -20.802347 +166.996094 -20.802347 +# -b +167.711879 -21.452420 +167.768203 -21.410177 +167.944215 -21.443033 +167.944215 -21.647207 +167.711879 -21.452420 +167.711879 -21.452420 +# -b +149.922869 -22.203407 +150.197448 -22.367686 +150.561208 -22.459212 +150.671509 -22.492068 +150.781810 -23.062349 +151.014147 -23.651404 +151.389640 -23.996389 +151.875435 -24.228726 +152.171137 -24.641769 +152.448063 -24.892880 +152.767233 -25.244905 +152.856412 -25.683764 +153.077015 -25.824574 +153.077015 -26.420670 +153.142726 -26.944014 +153.098136 -27.171657 +153.208438 -27.406341 +153.384450 -27.868667 +153.506486 -28.211305 +153.560463 -28.560984 +153.518220 -29.006882 +153.330473 -29.720320 +153.330473 -29.720320 +# -b +153.098136 -24.794313 +153.220172 -24.883493 +153.175582 -25.413878 +153.008957 -25.674376 +152.976101 -25.214397 +153.098136 -24.794313 +153.098136 -24.794313 +# -b +153.450162 -27.347670 +153.518220 -27.526029 +153.417306 -27.446237 +153.450162 -27.347670 +153.450162 -27.347670 +# -b +148.148661 -19.889428 +148.467831 -20.065440 +148.775266 -20.264921 +148.876180 -20.523073 +148.852712 -20.814081 +149.207084 -21.081620 +149.326772 -21.454767 +149.481664 -21.865463 +149.547375 -22.142389 +149.648289 -22.348911 +149.812567 -22.459212 +149.922869 -22.203407 +# -b +113.913030 -21.865463 +114.023332 -21.856076 +114.002210 -22.090759 +114.002210 -22.276159 +114.046800 -22.522577 +114.365969 -22.050863 +114.729729 -21.762202 +115.126344 -21.588536 +115.555815 -21.288141 +115.919574 -20.978359 +116.306802 -20.783572 +116.691683 -20.553582 +117.034321 -20.616947 +117.529503 -20.659190 +118.059888 -20.368182 +118.611394 -20.283696 +118.864852 -20.077175 +# -b +119.249733 -19.941058 +119.425746 -20.034931 +# -b +114.962066 -30.105201 +114.929210 -29.614712 +114.807175 -29.142999 +114.520861 -28.570371 +114.100777 -27.622249 +113.659572 -26.934627 +113.328668 -26.469953 +113.143268 -26.232923 +113.286425 -26.232923 +113.429582 -26.540358 +113.683040 -26.617804 +113.593861 -26.232923 +113.373258 -25.585197 +113.593861 -26.024055 +113.826197 -26.193027 +114.079656 -26.282207 +113.957620 -25.655602 +113.826197 -25.385716 +113.528149 -24.852984 +113.307547 -24.198217 +113.528149 -23.651404 +113.650185 -23.245402 +113.617329 -22.818278 +113.626716 -22.316055 +113.837932 -21.917093 +113.913030 -21.865463 +# -b +55.122464 -20.987747 +55.275008 -20.914995 +55.704479 -21.142638 +55.507344 -21.410177 +55.122464 -20.987747 +55.122464 -20.987747 +# -b +57.391853 -20.074828 +57.415321 -20.044319 +57.492767 -20.011463 +# -b +57.558478 -19.980954 +57.635924 -20.283696 +57.293286 -20.501952 +57.391853 -20.074828 +57.391853 -20.074828 +# -b +48.682748 -19.959833 +48.384700 -20.738982 +48.098386 -21.792711 +47.767482 -22.754913 +47.568001 -23.519982 +47.293422 -24.339027 +46.974252 -24.932776 +46.476723 -25.132257 +45.594313 -25.423265 +44.857407 -25.463161 +44.204986 -25.092361 +43.730926 -24.571364 +43.566647 -23.731197 +43.456346 -23.060002 +43.170032 -22.416969 +43.191154 -21.802098 +43.402369 -21.421911 +43.721538 -21.048764 +44.151009 -20.210944 +44.315288 -20.023197 +# -b +32.815796 -26.735146 +32.639783 -27.326548 +32.487239 -27.964887 +32.222046 -28.666591 +31.691662 -28.976373 +31.262191 -29.401150 +31.107300 -29.689811 +30.954755 -29.929188 +# -b +34.646327 -19.938711 +34.592350 -20.450321 +34.866930 -20.790612 +34.988965 -21.069886 +35.155590 -21.607311 +35.287013 -22.222182 +35.463026 -22.386460 +35.418436 -22.980210 +35.254157 -23.712422 +35.265891 -24.024551 +35.340990 -24.155974 +34.977231 -24.651156 +34.162879 -24.972673 +33.346180 -25.294189 +32.860385 -25.524179 +32.475505 -26.012321 +32.705494 -26.289247 +32.850998 -26.279860 +32.827530 -26.735146 +32.815796 -26.735146 +# -b +16.432540 -28.666591 +16.179081 -28.530475 +15.881033 -28.286404 +15.585332 -27.946113 +15.374117 -27.631637 +15.144127 -27.258490 +15.022092 -26.706984 +14.900056 -26.329143 +14.867201 -26.031095 +14.747512 -25.564075 +14.768633 -25.132257 +14.580887 -24.712174 +14.404874 -24.317906 +14.381406 -23.834458 +14.372018 -23.367437 +14.393140 -22.907458 +14.294573 -22.438091 +13.951935 -21.956989 +13.754801 -21.576802 +13.433284 -21.112129 +13.236150 -20.750716 +13.092993 -20.356448 +12.893512 -20.053706 +# -b +17.094347 -30.102854 +16.840889 -29.441047 +16.521719 -28.917702 +16.432540 -28.666591 +16.432540 -28.666591 +# -b +-53.240302 -33.611373 +-52.820218 -33.287509 +-52.533904 -32.881507 +-52.444725 -32.639783 +-52.203001 -32.217353 +-51.585783 -31.844206 +-51.198555 -31.588401 +-50.858264 -31.182398 +-50.503892 -30.698950 +-50.283289 -30.375087 +-50.184722 -30.116935 +# -b +-60.020308 -38.828387 +-59.435946 -38.776757 +-58.795260 -38.603091 +-58.541802 -38.560848 +-57.826018 -38.335552 +-57.516235 -37.838023 +-57.021053 -37.295904 +-56.711271 -36.704501 +-56.922486 -36.347782 +-57.441137 -35.857294 +-57.241656 -35.444251 +-57.539704 -35.092226 +-58.201511 -34.702651 +-58.553536 -34.310730 +-58.476091 -34.007988 +-58.344668 -34.017375 +-58.023152 -34.320117 +-57.682861 -34.465621 +-57.098499 -34.564188 +-56.392101 -34.791831 +-55.974365 -34.857542 +-55.345413 -34.857542 +-54.606160 -34.857542 +-54.010064 -34.484395 +-53.735484 -34.191041 +-53.536003 -33.824935 +-53.359990 -33.705246 +-53.327135 -33.613720 +# -b +-51.266613 -30.004287 +-51.243145 -30.194381 +-51.123456 -30.377434 +-50.956831 -30.386821 +-50.614193 -30.281214 +-50.593072 -30.520591 +-50.682251 -30.461920 +-50.736229 -30.652014 +-50.923975 -30.957102 +-51.078867 -31.090872 +-51.231411 -31.372492 +-51.365180 -31.571973 +-51.707818 -31.797269 +-52.026988 -31.872368 +-52.092699 -32.050727 +-52.224122 -31.919305 +-52.268712 -31.759720 +-52.125555 -31.628297 +-52.048109 -31.363105 +-51.728940 -31.269231 +-51.562315 -31.050976 +-51.442626 -30.729459 +-51.365180 -30.614464 +-51.299469 -30.386821 +-51.266613 -30.004287 +-51.266613 -30.004287 +# -b +-62.369490 -40.039354 +-62.148888 -39.734266 +-62.313166 -39.248471 +-62.313166 -38.757982 +-61.806250 -38.957463 +-61.055263 -38.990319 +-60.428658 -38.922261 +-60.020308 -38.828387 +# -b +-71.397765 -29.889292 +-71.585512 -30.234277 +-71.749790 -30.701297 +-71.716935 -31.203520 +-71.630102 -31.750332 +-71.585512 -32.294798 +-71.529188 -32.872120 +-71.728669 -33.390770 +-71.850704 -33.888299 +-72.005595 -34.345932 +-72.071307 -34.646327 +-72.235585 -35.118041 +-72.533633 -35.542818 +-72.676790 -35.946474 +-72.852803 -36.385332 +-73.040550 -36.695114 +-73.216562 -36.800722 +-73.195441 -37.180909 +-73.636646 -37.314679 +-73.657767 -37.734762 +-73.559200 -38.030463 +-73.580322 -38.560848 +-73.502876 -38.750942 +-73.371453 -39.102967 +-73.338598 -39.523050 +-73.526345 -39.844567 +-73.702357 -39.912625 +# -b +172.816245 -34.467968 +172.849101 -34.458580 +172.917159 -34.622859 +173.015726 -34.850502 +173.203473 -34.951416 +173.302040 -34.977231 +173.611822 -35.040595 +173.952113 -35.132122 +173.874668 -35.230689 +174.118739 -35.284666 +174.261896 -35.509962 +174.449642 -35.690669 +174.449642 -35.852600 +174.229040 -35.897190 +174.372197 -35.951167 +174.658511 -36.333701 +174.679632 -36.547263 +174.724222 -36.706848 +174.592799 -36.875820 +174.757078 -36.946225 +174.900235 -36.972041 +175.153693 -36.965000 +175.329706 -37.237233 +175.397764 -36.777253 +175.275728 -36.566038 +175.540921 -36.681033 +175.660609 -36.850005 +175.749789 -37.079995 +175.749789 -37.256008 +175.871825 -37.457835 +176.036103 -37.694866 +176.632199 -37.877919 +177.139116 -38.016382 +177.380840 -37.929549 +177.601442 -37.737109 +177.833779 -37.605686 +178.141214 -37.563443 +178.385285 -37.755884 +178.296105 -38.035157 +178.274984 -38.312083 +178.218660 -38.581970 +177.887756 -38.795532 +177.854900 -39.079499 +177.810310 -39.260205 +177.678888 -39.063071 +177.282272 -39.088886 +176.951369 -39.328263 +176.787090 -39.558253 +176.972490 -39.713144 +176.862189 -39.992417 +# -b +175.001149 -40.034660 +174.426174 -39.804671 +173.898136 -39.551212 +173.919258 -39.079499 +174.491886 -38.814306 +174.592799 -38.295656 +174.801668 -38.103215 +174.768812 -37.842716 +174.757078 -37.528241 +174.559944 -37.256008 +174.691366 -37.096423 +174.613921 -36.972041 +174.229040 -36.697461 +174.160982 -36.547263 +174.315873 -36.610628 +174.196184 -36.397066 +174.238427 -36.190545 +173.996703 -36.190545 +174.008437 -36.387679 +173.445197 -35.735259 +173.412341 -35.455985 +173.391220 -35.383233 +173.060316 -35.202527 +173.069703 -35.068757 +172.872569 -34.758975 +172.651967 -34.496130 +172.816245 -34.467968 +# -b +153.330473 -29.720320 +153.196704 -30.257745 +153.032425 -30.762315 +153.053547 -30.999345 +152.999569 -31.339636 +152.734377 -31.942773 +152.457450 -32.261943 +152.415207 -32.550603 +152.105425 -32.719575 +151.974002 -32.858039 +151.687689 -33.174861 +151.323929 -33.580864 +151.366172 -33.709940 +151.213628 -34.085433 +150.969557 -34.578269 +150.793544 -35.078145 +150.638653 -35.141509 +150.408663 -35.528737 +150.242038 -35.808010 +150.155205 -36.282071 +150.143471 -36.638790 +150.021436 -36.850005 +# -b +149.988580 -37.079995 +150.054291 -37.380390 +150.021436 -37.502425 +# -b +150.021436 -36.850005 +149.979193 -36.990815 +149.988580 -37.079995 +# -b +150.021436 -37.502425 +149.767977 -37.547015 +149.371362 -37.816901 +148.566398 -37.826289 +147.949180 -37.974139 +147.453998 -38.253413 +147.200540 -38.427078 +146.836780 -38.704005 +146.515264 -38.704005 +146.294661 -38.840121 +146.538732 -38.755635 +146.526998 -39.056030 +146.196094 -38.875324 +145.876925 -38.685230 +145.546021 -38.572582 +145.456841 -38.234638 +145.060226 -38.427078 +145.027370 -38.288615 +144.884214 -37.870878 +144.410153 -38.060972 +144.675345 -38.227597 +144.123839 -38.443506 +143.682634 -38.755635 +143.307140 -38.746248 +142.448199 -38.391876 +141.807513 -38.262800 +141.500077 -38.375448 +141.026017 -38.053932 +140.253908 -37.748843 +140.143607 -37.554056 +# -b +147.904590 -39.797630 +148.136927 -39.865688 +148.280084 -39.959562 +# -b +148.104071 -40.121493 +147.860000 -39.865688 +147.904590 -39.797630 +# -b +140.143607 -37.554056 +139.723523 -37.009590 +139.812703 -36.584813 +139.636690 -36.167076 +139.392619 -35.906577 +139.261197 -35.610876 +139.183751 -35.430170 +138.885703 -35.512309 +138.479700 -35.655466 +138.158184 -35.629651 +138.500822 -35.005393 +138.223895 -34.315423 +137.871870 -34.568881 +137.761569 -35.122735 +137.376688 -35.214261 +136.858037 -35.214261 +137.198328 -34.951416 +137.475255 -34.470314 +137.454133 -34.296649 +137.564435 -33.975132 +137.883604 -33.524540 +137.895339 -33.146699 +137.928194 -32.951912 +137.839014 -32.757125 +137.707592 -32.644477 +137.618412 -32.970687 +137.275774 -33.498725 +136.968339 -33.719327 +136.616313 -33.930542 +136.285410 -34.296649 +135.921650 -34.597043 +135.954506 -34.770709 +135.722169 -34.988965 +135.269230 -34.615818 +135.182397 -34.496130 +135.424121 -34.496130 +135.226987 -33.965745 +134.851493 -33.414239 +134.598035 -33.228839 +134.091119 -32.923750 +134.222542 -32.559991 +133.441045 -32.139907 +133.372987 -32.224393 +132.624347 -31.942773 +132.359154 -32.046034 +132.194876 -31.989710 +131.476744 -31.557892 +130.892382 -31.520343 +130.286899 -31.586054 +# -b +136.548255 -35.817398 +136.980073 -35.664853 +137.442399 -35.629651 +137.684123 -35.772808 +138.104207 -35.915965 +137.618412 -35.995757 +137.078640 -36.040347 +136.538868 -35.880762 +136.548255 -35.817398 +# -b +130.286899 -31.586054 +129.183887 -31.576667 +128.092608 -32.083583 +127.332234 -32.224393 +126.592981 -32.271330 +125.820872 -32.271330 +125.149677 -32.644477 +124.541847 -32.876813 +124.002075 -33.193636 +123.727495 -33.653616 +123.307411 -33.864831 +122.744171 -33.829628 +122.183277 -33.930542 +121.885229 -33.820241 +121.068531 -33.792079 +120.209589 -33.892993 +119.988986 -33.883606 +119.526660 -34.195735 +119.404625 -34.388175 +118.799141 -34.514904 +118.367323 -34.862236 +117.904997 -34.925600 +117.597561 -35.087532 +117.132888 -34.996005 +116.539139 -34.916213 +116.306802 -34.805912 +115.943043 -34.660408 +115.501838 -34.296649 +115.081754 -34.050231 +115.072367 -33.571477 +115.105223 -33.562089 +115.612139 -33.332099 +115.644995 -32.775899 +115.734174 -32.477851 +115.743562 -31.877062 +115.501838 -31.302087 +115.248380 -30.790477 +114.962066 -30.105201 +114.962066 -30.105201 +# -b +30.954755 -29.929188 +30.555793 -30.569874 +30.060611 -31.196479 +29.455128 -31.649419 +29.002189 -32.177456 +28.274670 -32.773553 +27.800609 -33.181902 +27.281958 -33.486990 +26.721065 -33.745142 +26.136703 -33.754530 +25.660295 -33.836669 +25.683764 -34.111249 +24.944511 -34.038497 +24.327293 -34.167573 +23.620896 -34.029109 +23.081123 -34.167573 +22.496762 -34.047884 +22.100146 -34.167573 +21.792711 -34.404603 +21.295182 -34.404603 +20.898567 -34.413990 +20.567663 -34.496130 +20.269615 -34.587656 +19.861266 -34.742547 +19.619542 -34.695611 +19.288638 -34.632246 +19.190071 -34.423378 +18.760600 -34.404603 +18.605709 -34.111249 +18.429696 -34.294302 +18.319395 -34.275527 +18.361638 -33.918808 +18.241949 -33.606679 +17.943901 -33.219451 +17.845334 -33.024664 +17.866456 -32.745391 +18.251337 -32.569378 +18.098793 -31.745639 +17.702177 -31.226988 +17.380661 -30.675482 +17.094347 -30.102854 +17.094347 -30.102854 +# -b +-68.642581 -50.018097 +-68.630847 -49.870246 +-68.630847 -49.870246 +# -b +-67.990161 -50.067381 +-67.682725 -49.598014 +-67.748436 -49.419654 +-67.307231 -48.898657 +-67.009183 -48.687442 +-66.525735 -48.448064 +-66.072796 -48.175832 +-65.763014 -48.004513 +-65.798217 -47.701771 +-65.709037 -47.215976 +-66.293399 -47.140877 +-66.943472 -46.870991 +-67.441001 -46.476723 +-67.572424 -46.141125 +-67.318966 -45.763285 +-67.086629 -45.486358 +-66.668892 -45.237594 +-66.171363 -45.049847 +-65.655060 -45.082703 +-65.521290 -44.941893 +-65.366399 -44.587521 +-65.202120 -44.169784 +-65.202120 -43.627665 +-64.904072 -43.282680 +-64.528579 -43.139523 +-64.286855 -43.040956 +-64.519191 -42.944736 +-65.026108 -42.815660 +-64.838361 -42.660769 +-64.364300 -42.571589 +-64.110842 -42.864944 +-63.613313 -42.742908 +-63.636781 -42.245379 +-64.298589 -42.212523 +-64.275121 -42.426085 +-64.519191 -42.294663 +-65.035495 -41.876926 +-65.157531 -41.172876 +-64.859482 -40.780954 +-64.352566 -40.964007 +-63.801060 -41.163488 +-63.106397 -41.182263 +-62.500913 -40.973395 +-62.313166 -40.654225 +-62.369490 -40.039354 +-62.369490 -40.039354 +# -b +-73.702357 -39.912625 +-73.702357 -40.184858 +-73.812658 -40.738711 +-73.878370 -41.271443 +-73.714091 -41.555410 +-73.559200 -41.768972 +-73.195441 -41.752544 +-72.974838 -41.546022 +-72.578223 -41.703260 +-72.313031 -41.653977 +-72.533633 -41.778359 +-72.611079 -42.048245 +-72.423332 -42.334559 +-72.655669 -42.278235 +-72.533633 -42.611485 +-72.775357 -42.879025 +-72.852803 -43.259212 +-73.019428 -43.477468 +-72.897393 -43.627665 +-72.885659 -43.787250 +-73.085140 -44.059483 +-73.228297 -44.169784 +-73.195441 -44.249576 +-72.852803 -44.430283 +-72.688524 -44.650885 +-72.831681 -44.932505 +-73.249418 -45.026379 +-73.371453 -45.268103 +-72.951370 -45.408913 +-72.930248 -45.516867 +-73.261152 -45.361976 +-73.502876 -45.509827 +-73.448899 -45.610741 +-73.171972 -45.610741 +-73.392575 -45.772672 +-73.272886 -45.810222 +-73.502876 -45.847771 +-73.570934 -46.117657 +-73.514610 -46.131738 +-73.359719 -45.911136 +-73.371453 -46.110617 +-73.526345 -46.300710 +-73.746947 -46.528353 +-73.800924 -46.338260 +-74.000405 -46.460295 +-74.164684 -46.277242 +-74.155296 -46.155206 +-74.197539 -45.965113 +-74.474466 -45.955725 +-74.849960 -45.894708 +-74.969648 -46.094189 +-74.749046 -46.124698 +-75.058828 -46.293670 +-75.488299 -46.582330 +-75.532889 -46.953130 +-75.345142 -46.765384 +-75.157395 -46.605799 +-74.793636 -46.793546 +-74.483853 -46.741915 +-74.087238 -46.885072 +-74.155296 -47.119756 +-74.176418 -47.239444 +-74.408755 -47.471781 +-74.021527 -47.589123 +-74.131828 -47.753401 +-73.845514 -47.797991 +-73.690623 -47.952882 +-73.338598 -48.218075 +-73.746947 -48.079611 +-74.197539 -48.065530 +-74.242129 -48.124201 +-74.495587 -48.117161 +-74.364165 -48.438677 +-74.033261 -48.431637 +-73.812658 -48.513776 +-74.122441 -48.504388 +-74.155296 -48.746112 +-74.307841 -48.919778 +-74.286719 -49.253029 +-74.143562 -49.468938 +-73.857248 -49.152115 +-73.890104 -49.382105 +-73.779803 -49.576892 +-73.967550 -49.583933 +-74.242129 -49.769333 +-74.298453 -49.926571 +-74.298453 -49.926571 +# -b +-73.878370 -41.752544 +-73.824393 -41.834683 +-73.681236 -41.867539 +-73.526345 -42.024777 +-73.404309 -42.327518 +-73.636646 -42.571589 +-73.756334 -42.660769 +-73.538079 -42.864944 +-73.592056 -43.090240 +-73.702357 -43.364820 +-74.286719 -43.364820 +-74.242129 -42.904840 +-74.188152 -42.426085 +-74.098972 -41.966106 +-73.911226 -41.768972 +-73.878370 -41.752544 +# -b +-73.007694 -44.406814 +-72.909127 -44.477219 +-72.765970 -44.610989 +-72.808213 -44.707209 +-73.129729 -44.955974 +-73.416043 -44.730678 +-73.150851 -44.463138 +-73.007694 -44.406814 +# -b +-74.298453 -44.650885 +-74.209274 -44.643845 +-73.967550 -44.681394 +-74.197539 -44.784655 +-74.298453 -44.650885 +-74.298453 -44.650885 +# -b +-74.232742 -45.049847 +-74.274985 -44.965361 +-73.967550 -44.972402 +-74.232742 -45.049847 +-74.232742 -45.049847 +# -b +-74.164684 -45.129640 +-74.110707 -45.106171 +-73.746947 -45.190657 +-74.000405 -45.160148 +-74.164684 -45.129640 +# -b +-74.143562 -45.237594 +-74.087238 -45.244634 +-73.857248 -45.392485 +-74.054382 -45.322080 +-74.143562 -45.237594 +# -b +-73.866636 -45.796141 +-73.746947 -45.932257 +-73.878370 -45.847771 +-73.866636 -45.796141 +-73.866636 -45.796141 +# -b +-74.298453 -47.776870 +-74.617623 -47.643100 +-74.397020 -47.605551 +-74.298453 -47.776870 +-74.298453 -47.776870 +# -b +-74.981382 -47.701771 +-75.213719 -47.849621 +-75.255962 -47.753401 +-74.981382 -47.701771 +-74.981382 -47.701771 +# -b +-75.136273 -48.093692 +-75.002504 -48.124201 +-74.781901 -48.203994 +-74.936792 -48.344804 +-75.136273 -48.093692 +-75.136273 -48.093692 +# -b +-75.443709 -48.168791 +-75.399119 -48.065530 +-75.267696 -48.159404 +-75.157395 -48.396434 +-75.070562 -48.570100 +-75.213719 -48.417556 +-75.443709 -48.168791 +-75.443709 -48.168791 +# -b +-74.915671 -48.410515 +-74.772514 -48.438677 +-74.528443 -48.593568 +-74.739658 -48.586528 +-74.948527 -48.417556 +-74.915671 -48.410515 +# -b +-75.467177 -48.607649 +-75.488299 -48.497348 +-75.324020 -48.504388 +-75.356876 -48.694482 +-75.467177 -48.607649 +-75.467177 -48.607649 +# -b +-75.014238 -48.985490 +-75.014238 -48.870495 +-74.793636 -48.680401 +-74.507322 -48.936206 +-74.441610 -49.382105 +-74.441610 -49.919530 +-74.441610 -49.919530 +# -b +-74.727924 -50.046259 +-74.849960 -49.720049 +-74.814757 -49.518221 +-75.190251 -49.339862 +-75.112805 -49.274150 +-75.070562 -49.187317 +-75.014238 -48.985490 +-75.014238 -48.985490 +# -b +-75.521154 -49.705968 +-75.544623 -49.647297 +-75.389732 -49.640257 +-75.267696 -49.863206 +-75.521154 -49.705968 +-75.521154 -49.705968 +# -b +-176.322417 -43.791944 +-176.345885 -43.871736 +-176.399862 -44.045402 +-176.686176 -44.068870 +-176.742500 -43.878776 +-176.676789 -43.775516 +-176.322417 -43.791944 +-176.322417 -43.791944 +# -b +172.067605 -41.050840 +172.112195 -40.985129 +172.264739 -40.792688 +172.485341 -40.649531 +172.628498 -40.623716 +172.696557 -40.858400 +172.982871 -40.959314 +173.036848 -41.292564 +173.334896 -41.233893 +173.501521 -41.142367 +173.644678 -41.034412 +173.841812 -40.966354 +173.776101 -41.060227 +173.787835 -41.266749 +173.942726 -41.233893 +173.919258 -41.151754 +174.017825 -41.034412 +174.139860 -41.109511 +174.062415 -41.243281 +174.128126 -41.374703 +174.095270 -41.597653 +174.139860 -41.862845 +173.942726 -42.142118 +173.698655 -42.336906 +173.424076 -42.646688 +173.236329 -42.890759 +173.102559 -42.972898 +172.950015 -43.076159 +172.872569 -43.116055 +172.827979 -43.141870 +172.795124 -43.165339 +172.771655 -43.205235 +172.729412 -43.446959 +172.684822 -43.662868 +172.992258 -43.759088 +172.926546 -43.831840 +172.518197 -43.815412 +172.342185 -43.878776 +172.145050 -43.871736 +171.835268 -44.038361 +171.581810 -44.118154 +171.459775 -44.038361 +171.405797 -44.315288 +171.229785 -44.779961 +171.119483 -44.974748 +170.964592 -45.225860 +170.920002 -45.505133 +170.699400 -45.711655 +170.678278 -45.828996 +170.621954 -45.920523 +170.511653 -46.012050 +170.171362 -46.258467 +170.028205 -46.310098 +# -b +169.995349 -43.350739 +170.225339 -43.132483 +170.546856 -42.996366 +170.931737 -42.752296 +171.140605 -42.468328 +171.229785 -42.240685 +171.372942 -41.853458 +171.703845 -41.682139 +171.990159 -41.400519 +172.067605 -41.050840 +172.067605 -41.050840 +# -b +176.862189 -39.992417 +176.620465 -40.330362 +176.367007 -40.649531 +175.982126 -41.151754 +175.451741 -41.531941 +175.087982 -41.391131 +174.646777 -41.151754 +174.801668 -41.083696 +175.099716 -40.682387 +175.186549 -40.245876 +175.001149 -40.034660 +# -b +167.878504 -46.744262 +167.920747 -46.758343 +168.063904 -46.910887 +167.944215 -46.948437 +168.099107 -47.016495 +167.932481 -47.166692 +167.690757 -47.166692 +167.503010 -47.279341 +167.524132 -47.091594 +167.657902 -46.941396 +167.711879 -46.720794 +167.878504 -46.744262 +167.878504 -46.744262 +# -b +170.028205 -46.310098 +169.807603 -46.418052 +169.673833 -46.523660 +169.497820 -46.591718 +169.157529 -46.645695 +168.847747 -46.652736 +168.638879 -46.584677 +168.451132 -46.563556 +168.307975 -46.448561 +168.120228 -46.418052 +167.768203 -46.401624 +167.446686 -46.173981 +167.150985 -46.279589 +166.665190 -46.181022 +166.874059 -45.927563 +166.620600 -46.082455 +166.686312 -45.920523 +166.456322 -45.906442 +166.742636 -45.798488 +166.796613 -45.674105 +166.841203 -45.559110 +166.841203 -45.458196 +166.841203 -45.310346 +167.028950 -45.333814 +167.172107 -45.310346 +167.007828 -45.216472 +167.050071 -45.068622 +167.204962 -44.904343 +167.336385 -45.014645 +167.458421 -44.991176 +167.503010 -44.796389 +167.822180 -44.559359 +168.063904 -44.284779 +168.307975 -44.028974 +168.704590 -43.982037 +169.145795 -43.791944 +169.530676 -43.599503 +169.995349 -43.350739 +169.995349 -43.350739 +# -b +148.280084 -39.959562 +148.136927 -40.290465 +148.104071 -40.121493 +# -b +148.136927 -40.424235 +148.280084 -40.339749 +148.500686 -40.450050 +148.136927 -40.424235 +148.136927 -40.424235 +# -b +144.795034 -40.675346 +144.982781 -40.759833 +145.304297 -40.776260 +145.787745 -40.985129 +146.404963 -41.151754 +146.759335 -41.118898 +147.254517 -41.010944 +147.761433 -40.867787 +148.125193 -40.818503 +148.345795 -41.276136 +148.336408 -41.714994 +148.369264 -42.085794 +148.378651 -42.200789 +148.268350 -42.052939 +148.092337 -42.503531 +147.982036 -42.771070 +147.606542 -42.778111 +147.496241 -43.062078 +147.242783 -43.174726 +147.033914 -43.360126 +146.792190 -43.608890 +146.473021 -43.552566 +146.031816 -43.416450 +146.052937 -43.296761 +145.656322 -42.923615 +145.435720 -42.731174 +145.280829 -42.322825 +145.325419 -42.289969 +145.435720 -42.217217 +145.104816 -41.764278 +144.851358 -41.360622 +144.785646 -40.844319 +144.795034 -40.675346 +# -b +70.027213 -49.163849 +69.999051 -49.182624 +69.999051 -49.255376 +# -b +68.966444 -49.109872 +69.999051 -49.145074 +# -b +69.970889 -49.656684 +70.252510 -49.602707 +70.196186 -49.529955 +69.999051 -49.365677 +70.503621 -49.346902 +70.559945 -49.034773 +70.252510 -49.109872 +70.055375 -49.145074 +# -b +69.999051 -49.255376 +69.832426 -49.311700 +69.637639 -49.220173 +69.691616 -49.128647 +69.747940 -49.018345 +69.581315 -48.999571 +69.104907 -49.034773 +69.273879 -48.851720 +69.161231 -48.666320 +68.966444 -48.685095 +68.910120 -48.889269 +68.966444 -49.109872 +68.966444 -49.109872 +# -b +69.999051 -49.145074 +69.245717 -49.201398 +69.076745 -49.438429 +69.104907 -49.637910 +69.412343 -49.511181 +69.776102 -49.656684 +69.916912 -49.565158 +69.970889 -49.656684 +# -b +37.612727 -46.880379 +37.711294 -46.873338 +37.800473 -47.016495 +37.612727 -46.880379 +37.612727 -46.880379 +# -b +-26.359652 -58.408033 +-26.261085 -58.443235 +-26.458219 -58.459663 +-26.437098 -58.403339 +-26.359652 -58.408033 +# -b +-38.124337 -54.028838 +-38.056278 -54.003023 +-37.781699 -53.977208 +-37.450795 -53.977208 +-37.241927 -54.047613 +-37.065914 -54.068735 +-36.845312 -54.125059 +-36.711542 -54.157914 +-36.702155 -54.254135 +-36.535529 -54.326886 +-36.282071 -54.326886 +-36.094324 -54.505246 +-35.930046 -54.575651 +-35.885456 -54.709421 +-35.951167 -54.768091 +-35.951167 -54.869005 +-36.138914 -54.869005 +-36.326661 -54.671871 +-36.523795 -54.531061 +-36.756132 -54.448922 +-37.042446 -54.326886 +-37.406205 -54.268216 +-37.385084 -54.176689 +-37.650276 -54.171995 +-37.737109 -54.113324 +-37.802820 -54.061694 +-38.056278 -54.054654 +-38.124337 -54.028838 +# -b +-59.313911 -51.423851 +-59.182488 -51.437932 +-59.248200 -51.616292 +-59.555635 -51.841588 +-59.755116 -51.991785 +-59.975719 -51.996479 +-59.975719 -51.996479 +# -b +-60.020308 -51.731287 +-59.963984 -51.724246 +# -b +-60.041430 -51.505991 +-59.710526 -51.463748 +-59.313911 -51.484869 +-59.313911 -51.423851 +# -b +-58.464357 -51.327631 +-58.276610 -51.409770 +-58.079476 -51.423851 +-57.793162 -51.477829 +-57.903463 -51.595170 +-57.715716 -51.656188 +-57.924585 -51.780570 +-58.332934 -51.928421 +-58.851585 -51.881484 +-58.607514 -52.010560 +-58.598126 -52.139636 +-58.851585 -52.120861 +-59.015863 -52.132596 +-58.806995 -52.221775 +-59.093309 -52.235856 +-59.292790 -52.207694 +-59.259934 -52.343811 +-59.391357 -52.308608 +-59.579103 -52.106780 +-59.457068 -51.949542 +-59.358501 -51.848629 +-59.105043 -51.724246 +-59.015863 -51.559968 +-58.917296 -51.463748 +-58.785873 -51.353446 +-58.586392 -51.346406 +-58.464357 -51.327631 +# -b +-70.064763 -52.578494 +-69.600089 -52.484621 +-69.358365 -52.275752 +-69.006340 -52.289834 +-68.431366 -52.376666 +-68.365654 -52.308608 +-68.508811 -52.214735 +-68.806859 -51.949542 +-69.126029 -51.677310 +-69.280920 -51.581089 +-69.060317 -51.334672 +-69.292654 -51.083560 +-69.149497 -50.708067 +-68.663702 -50.280943 +-68.454834 -50.130745 +-68.642581 -50.018097 +# -b +-68.630847 -49.870246 +-68.243619 -50.123705 +-67.990161 -50.067381 +# -b +-68.651968 -52.658287 +-68.454834 -52.806137 +-68.222497 -53.045514 +-68.222497 -53.111226 +-68.487690 -53.191018 +-68.189642 -53.376418 +-67.990161 -53.669773 +-67.584158 -53.859866 +-67.318966 -54.061694 +-66.966940 -54.150874 +-66.690014 -54.261175 +-66.359110 -54.460656 +-65.917905 -54.639015 +-65.357012 -54.697686 +-65.178652 -54.861965 +-65.476700 -54.976960 +-65.840460 -54.925329 +-66.305133 -55.021550 +-66.690014 -54.958185 +-67.110097 -54.894820 +-67.638135 -54.876046 +-67.936183 -54.824415 +-68.377388 -54.843190 +-68.586257 -54.894820 +# -b +-69.158884 -54.995734 +-69.370100 -55.033284 +-69.733859 -55.077874 +-69.844160 -55.014509 +-69.799570 -54.920636 +-69.644679 -54.913595 +-69.280920 -54.939410 +-69.158884 -54.995734 +# -b +-69.942727 -55.174094 +-69.632945 -55.129504 +-69.215208 -55.052058 +-68.950016 -55.028590 +-68.532279 -54.969919 +-68.288209 -55.059099 +-68.464221 -55.152972 +-68.851449 -55.091955 +-68.696558 -55.185828 +-68.267087 -55.211643 +-68.145052 -55.312557 +-68.508811 -55.331332 +-68.201376 -55.392350 +-67.990161 -55.523772 +-67.915062 -55.711519 +-68.133317 -55.610605 +-68.365654 -55.462755 +-68.651968 -55.512038 +-68.774003 -55.418165 +-68.905426 -55.312557 +-69.215208 -55.267967 +-69.072052 -55.486223 +-69.280920 -55.549588 +-69.402955 -55.443980 +-69.600089 -55.336026 +-69.337244 -55.230418 +-69.590702 -55.272661 +-69.942727 -55.272661 +-69.942727 -55.174094 +-69.942727 -55.174094 +# -b +-68.091074 -55.014509 +-68.255353 -55.007469 +-68.067606 -54.951145 +-67.638135 -54.939410 +-67.175809 -54.976960 +-67.042039 -55.178788 +-67.131219 -55.305517 +-67.363556 -55.317251 +-67.494978 -55.223377 +-67.682725 -55.272661 +-67.781292 -55.230418 +-68.046485 -55.152972 +-68.091074 -55.014509 +-66.481146 -55.211643 +-66.514001 -55.305517 +-66.612568 -55.216337 +-66.612568 -55.216337 +# -b +-64.408890 -54.798600 +-64.230531 -54.772785 +-64.045131 -54.772785 +-63.714227 -54.735236 +-63.690759 -54.819722 +-63.944217 -54.812681 +-64.155432 -54.869005 +-64.408890 -54.920636 +-64.606024 -54.894820 +-64.507457 -54.772785 +-64.408890 -54.798600 +# -b +-60.890984 -51.820466 +-60.801805 -51.827507 +-60.869863 -51.991785 +-61.156177 -51.874444 +-61.210154 -51.717206 +-61.177298 -51.780570 +-61.088118 -51.834547 +-60.890984 -51.820466 +-60.890984 -51.820466 +# -b +-59.975719 -51.996479 +-60.175200 -52.017601 +-60.273767 -52.174839 +-60.527225 -52.247590 +-60.691503 -52.132596 +-60.703237 -52.179532 +-60.858129 -52.045763 +-60.691503 -51.977704 +-60.339478 -51.956583 +-60.351212 -51.841588 +-60.163465 -51.745368 +-60.020308 -51.731287 +# -b +-59.963984 -51.724246 +-60.184587 -51.581089 +-60.405189 -51.534153 +-60.372334 -51.463748 +-60.428658 -51.416811 +-60.041430 -51.505991 +-60.041430 -51.505991 +# -b +-68.741148 -52.658287 +-68.910120 -52.618390 +-69.358365 -52.533904 +-69.691616 -52.637165 +-69.945074 -52.770935 +# -b +-69.999051 -53.395193 +-69.412343 -53.343562 +-69.637639 -53.611102 +-69.916912 -53.693241 +# -b +-69.999051 -54.155567 +-69.412343 -54.286990 +-69.553153 -54.418413 +-69.888750 -54.401985 +-69.888750 -54.401985 +# -b +-69.999051 -54.887780 +-69.553153 -54.854924 +-68.910120 -54.951145 +-68.602684 -54.887780 +-68.586257 -54.894820 +# -b +-74.298453 -49.926571 +-74.462732 -50.130745 +-74.340696 -50.379510 +-73.988671 -50.449915 +-74.066117 -50.527360 +-73.934694 -50.778472 +-73.714091 -50.729188 +-74.087238 -50.902854 +-73.944081 -51.214983 +-73.570934 -51.534153 +-73.538079 -51.916687 +-73.282274 -52.085659 +-73.392575 -51.623332 +-73.249418 -51.881484 +-73.040550 -51.977704 +-73.085140 -51.710165 +-72.754236 -51.827507 +-72.831681 -51.635067 +-73.117995 -51.470788 +-72.578223 -51.738327 +-72.489043 -51.970664 +-72.622813 -52.017601 +-72.435066 -52.282793 +-72.709646 -52.463499 +-72.632200 -52.564413 +-72.456188 -52.679408 +-71.904682 -52.557373 +-71.409499 -52.719304 +-71.123185 -52.965722 +-71.552656 -53.242649 +-71.961006 -53.402233 +-72.137018 -53.303666 +-72.214464 -53.566512 +-71.651223 -53.782421 +-71.233487 -53.845785 +-71.022272 -53.735484 +-70.956560 -53.282545 +-70.836872 -53.012659 +-70.836872 -52.766241 +-70.548211 -52.691142 +-70.196186 -52.625431 +-70.064763 -52.578494 +# -b +-74.441610 -49.919530 +-74.551912 -50.032178 +-74.727924 -50.046259 +# -b +-75.377998 -50.302064 +-75.356876 -50.189416 +-75.047094 -50.182376 +-74.903937 -50.287983 +-75.136273 -50.428793 +-75.377998 -50.302064 +-75.377998 -50.302064 +# -b +-74.441610 -50.686945 +-74.573033 -50.597765 +-74.695068 -50.393591 +-74.364165 -50.555522 +-74.155296 -50.827755 +-74.373552 -50.722148 +-74.441610 -50.686945 +# -b +-74.441610 -51.001421 +-74.629357 -51.153965 +-74.838225 -50.722148 +-74.814757 -50.679905 +-74.483853 -50.771431 +-74.408755 -50.966218 +# -b +-74.882815 -51.430892 +-74.826491 -51.306510 +-74.629357 -51.182127 +-74.629357 -51.416811 +-74.859347 -51.416811 +-74.882815 -51.430892 +# -b +-74.871081 -52.139636 +-74.969648 -51.970664 +-74.882815 -51.792304 +-74.781901 -51.888525 +-74.871081 -52.139636 +-74.871081 -52.139636 +# -b +-74.054382 -51.677310 +-73.866636 -51.881484 +-74.164684 -51.710165 +-74.164684 -51.602211 +-74.054382 -51.677310 +# -b +-73.714091 -51.534153 +-73.669502 -51.602211 +-73.723479 -51.670269 +-73.890104 -51.423851 +-73.714091 -51.534153 +-73.714091 -51.534153 +# -b +-73.538079 -52.221775 +-73.502876 -52.179532 +-73.272886 -52.221775 +-73.007694 -52.179532 +-72.852803 -52.289834 +-72.841069 -52.106780 +-72.676790 -52.092699 +-72.688524 -52.390747 +-72.841069 -52.665327 +-72.622813 -52.824912 +-72.369355 -52.857768 +-72.005595 -52.705223 +-71.552656 -52.726345 +-71.630102 -52.965722 +-72.038451 -53.151122 +-72.247319 -53.209793 +-72.489043 -53.249689 +-72.521899 -53.442130 +-72.754236 -53.402233 +-73.117995 -53.191018 +-72.697912 -53.191018 +-72.876271 -52.958682 +-73.085140 -53.057249 +-73.240031 -52.932866 +-73.448899 -52.759201 +-73.570934 -52.691142 +-73.559200 -52.369626 +-73.538079 -52.221775 +# -b +-73.723479 -52.449418 +-73.681236 -52.592575 +-73.812658 -52.712264 +-73.878370 -52.672368 +-73.812658 -52.597269 +-73.901838 -52.611350 +-73.866636 -52.470540 +-73.723479 -52.449418 +# -b +-74.671600 -52.759201 +-74.605889 -52.777975 +-74.418142 -52.911745 +-74.131828 -52.998578 +-73.833780 -53.071330 +-73.538079 -53.165203 +-73.416043 -53.209793 +-73.216562 -53.303666 +-73.207175 -53.381112 +-73.502876 -53.336522 +-73.812658 -53.118266 +-73.866636 -53.216833 +-74.087238 -53.158163 +-74.474466 -53.019699 +-74.650479 -52.799097 +-74.671600 -52.759201 +# -b +-74.629357 -51.731287 +-74.594155 -51.773530 +-74.573033 -51.902606 +-74.629357 -52.092699 +-74.749046 -52.031682 +-74.695068 -51.888525 +-74.683334 -51.745368 +-74.629357 -51.731287 +# -b +-73.613177 -53.395193 +-73.437165 -53.402233 +-73.240031 -53.474985 +-73.085140 -53.449170 +-72.930248 -53.474985 +-72.775357 -53.519575 +-72.599345 -53.592327 +-72.435066 -53.683854 +-72.202730 -53.794155 +-72.345887 -53.859866 +-72.423332 -54.080469 +-72.622813 -54.054654 +-72.808213 -54.120365 +-72.897393 -54.073428 +-73.028816 -54.021798 +-73.294008 -53.970167 +-73.272886 -53.819970 +-73.448899 -53.761299 +-73.514610 -53.625183 +-73.681236 -53.453864 +-73.613177 -53.395193 +# -b +-71.883560 -53.859866 +-71.794380 -53.925578 +-71.707547 -54.010064 +-71.618368 -54.028838 +-71.386031 -54.042919 +-71.266342 -54.132099 +-71.090330 -54.164955 +-71.099717 -54.357395 +-71.275730 -54.305765 +-71.662957 -54.228319 +-71.707547 -54.312805 +-71.993861 -54.190770 +-72.104162 -54.106284 +-72.181608 -53.951393 +-71.928150 -53.866907 +-71.883560 -53.859866 +# -b +-70.548211 -53.592327 +-70.482499 -53.611102 +-70.449644 -53.866907 +-70.372198 -54.054654 +-70.494234 -54.054654 +-70.625656 -54.087509 +-70.383932 -54.223626 +-70.461378 -54.275256 +-70.747692 -54.132099 +-70.836872 -53.904456 +-70.649125 -53.873947 +-70.670246 -53.730790 +-70.548211 -53.592327 +-70.548211 -53.592327 +# -b +-71.001150 -55.110729 +-70.989416 -55.033284 +-70.801669 -54.984000 +-70.747692 -55.129504 +-70.890849 -55.148279 +-71.001150 -55.110729 +# -b +-70.362811 -55.272661 +-70.449644 -55.267967 +-70.616269 -55.129504 +-70.437910 -55.148279 +-70.339342 -55.235112 +-70.362811 -55.272661 +# -b +-69.945074 -52.770935 +-70.419135 -52.754507 +-70.111699 -52.942254 +-70.362811 -52.991537 +-70.475459 -53.261423 +-70.168024 -53.444476 +-69.999051 -53.395193 +# -b +-69.916912 -53.693241 +-70.111699 -53.909150 +-69.999051 -54.155567 +# -b +-69.888750 -54.401985 +-70.224348 -54.319846 +-70.139861 -54.418413 +-70.503621 -54.303418 +-70.949520 -54.204851 +-70.754732 -54.385557 +-70.921358 -54.418413 +-71.313279 -54.498205 +-71.285117 -54.646056 +-71.090330 -54.646056 +-70.921358 -54.725848 +-70.811056 -54.791560 +-70.613922 -54.805641 +-69.999051 -54.887780 +-69.999051 -54.887780 +# -b +166.167661 -50.600112 +166.179395 -50.738575 +166.223985 -50.872345 +166.092563 -50.865305 +166.101950 -50.954484 +165.925937 -50.900507 +165.947059 -50.752656 +166.113684 -50.571950 +166.167661 -50.600112 +# -b +-1.509015 -70.053029 +-1.462078 -69.877016 +-0.880063 -69.656413 +-0.959856 -69.370100 +-1.020873 -69.111948 +-0.326210 -69.067358 +-0.147851 -69.130722 +-0.147851 -69.130722 +# -b +0.021122 -69.095520 +-0.058671 -69.201127 +# -b +-45.697574 -60.548346 +-45.399526 -60.553040 +-45.169536 -60.665688 +-45.059234 -60.764255 +-45.333814 -60.698544 +-45.664718 -60.644567 +-45.885320 -60.651607 +-45.941644 -60.585896 +-45.697574 -60.548346 +# -b +-54.646056 -61.144442 +-54.876046 -61.203113 +-55.472142 -61.294640 +-55.124810 -61.102199 +-54.646056 -61.144442 +-54.646056 -61.144442 +# -b +-58.943111 -62.273270 +-58.830463 -62.184090 +-58.544149 -62.090217 +-58.112331 -62.010425 +-57.638271 -62.076136 +-58.102944 -62.151235 +-58.422114 -62.247455 +-58.802301 -62.273270 +-58.943111 -62.273270 +# -b +-60.027349 -62.641723 +-59.919395 -62.719169 +# -b +-58.316506 -64.448786 +-58.171002 -64.364300 +-58.466704 -64.235224 +-58.335281 -64.110842 +-57.879995 -63.913708 +-57.527970 -64.045131 +-57.241656 -64.291548 +-57.847139 -64.476948 +-58.316506 -64.448786 +-58.316506 -64.448786 +# -b +-57.490420 -64.601331 +-57.110233 -64.481642 +-57.199413 -64.596637 +-57.199413 -64.596637 +# -b +-60.062551 -63.953604 +-59.583797 -63.920748 +-59.227078 -63.742389 +-58.405686 -63.517093 +-57.668780 -63.399751 +-57.011666 -63.383323 +-57.194719 -63.681371 +-57.466952 -63.552295 +-57.748572 -63.704840 +-58.382218 -63.864424 +-58.804648 -64.246958 +-58.907909 -64.751528 +-59.255240 -65.319462 +-59.565022 -65.678528 +-59.823174 -65.950761 +# -b +-57.283899 -64.636533 +-57.434096 -64.638880 +-57.490420 -64.601331 +# -b +-57.739185 -63.937176 +-57.222881 -63.906667 +-57.485726 -64.009928 +-57.739185 -63.937176 +# -b +-60.717318 -67.042039 +-60.834660 -67.647523 +-60.787724 -68.515852 +-60.379374 -69.172965 +-60.604670 -69.830079 +-60.604670 -69.830079 +# -b +-61.120974 -62.763759 +-61.106893 -62.747331 +-60.858129 -62.669885 +-60.496716 -62.608868 +-60.074286 -62.594787 +-60.027349 -62.641723 +# -b +-59.917048 -62.719169 +-60.362946 -62.791921 +-60.719665 -62.728556 +-61.118627 -62.780187 +-61.118627 -62.763759 +# -b +-62.691007 -64.566128 +-62.658151 -64.425318 +-62.545503 -64.183594 +-62.094911 -64.192981 +-62.226333 -64.378381 +-62.489179 -64.512151 +-62.691007 -64.566128 +# -b +-64.296242 -64.756222 +-63.986460 -64.591943 +-63.559336 -64.368994 +-63.249554 -64.392462 +-63.165067 -64.465214 +-63.216698 -64.638880 +-62.855285 -64.613065 +-63.484237 -64.763262 +-64.033396 -64.847748 +-64.296242 -64.756222 +-64.296242 -64.756222 +# -b +-66.248809 -65.941373 +-66.187791 -65.856887 +-65.995351 -65.676181 +-65.638632 -65.631591 +-65.868622 -65.814644 +-66.225341 -65.948414 +-66.248809 -65.941373 +# -b +-69.076745 -67.825882 +-69.137763 -67.757824 +-69.287960 -67.539568 +-68.870224 -67.262642 +-68.504117 -66.950513 +-67.950264 -66.823783 +-68.001895 -67.023264 +-67.950264 -67.304885 +-68.199029 -67.494978 +-68.231885 -67.685072 +-68.630847 -67.764864 +-69.076745 -67.825882 +-69.076745 -67.825882 +# -b +-70.064763 -69.295001 +-69.557846 -69.395915 +-69.374793 -69.632945 +-69.351325 -69.834773 +# -b +-68.837368 -70.001398 +-68.659009 -69.625905 +-68.274128 -69.337244 +-67.659257 -69.208168 +-67.321313 -68.924201 +-67.063161 -68.567482 +-66.969287 -68.332798 +-67.124178 -68.149745 +-66.682973 -67.875166 +-66.837864 -67.800067 +-66.593794 -67.699153 +-66.964594 -67.659257 +-67.532528 -67.631095 +-67.678031 -67.448042 +-67.541915 -67.274376 +-67.110097 -67.060814 +-66.837864 -67.152340 +-66.687667 -67.358862 +-66.321561 -67.333047 +-66.330948 -66.877761 +-65.401601 -66.631343 +-65.725465 -66.335642 +-65.425070 -66.215953 +-65.087125 -66.105652 +-65.091819 -66.014125 +-64.622452 -66.072796 +-64.594290 -65.915558 +-64.303283 -65.828725 +-64.275121 -65.720771 +-64.040437 -65.640979 +-63.730655 -65.577614 +-64.120229 -65.312422 +-63.298837 -65.136409 +-63.148640 -65.084779 +-62.402346 -64.904072 +-62.355409 -64.645920 +-62.069095 -64.718672 +-61.505855 -64.566128 +-61.102199 -64.399503 +-60.440392 -64.014622 +-60.064898 -63.953604 +# -b +-59.825521 -65.950761 +-60.632832 -66.596140 +-60.717318 -67.042039 +-60.717318 -67.042039 +# -b +-75.910729 -70.010786 +-76.042152 -69.818345 +-75.389732 -69.724472 +-74.817104 -69.628251 +-74.399367 -69.799570 +-74.643438 -69.989664 +-74.643438 -69.989664 +# -b +-74.573033 -70.001398 +-74.174071 -69.851201 +-73.301048 -69.794877 +-72.639241 -69.701003 +-72.798826 -69.578968 +-72.470269 -69.438158 +-71.784993 -69.569581 +-71.902335 -69.264492 +-71.573778 -69.072052 +-70.611575 -68.921854 +-70.146902 -69.057971 +-70.090578 -69.168272 +-70.067110 -69.295001 +# -b +-90.484575 -68.804512 +-90.404783 -69.027462 +-90.841294 -69.032155 +-90.742727 -68.809206 +-90.484575 -68.804512 +# -b +159.753761 -69.675188 +160.063543 -69.855894 +160.265371 -69.977930 +# -b +164.132955 -67.548956 +164.419269 -67.466816 +164.334783 -67.663950 +164.189279 -67.523140 +164.189279 -67.523140 +# -b +149.864198 -68.501771 +150.995372 -68.414938 +152.943245 -68.482996 +154.492157 -68.656662 +154.398283 -68.910120 +155.398035 -69.025115 +156.829604 -69.074398 +157.289584 -69.219902 +158.303417 -69.323163 +159.753761 -69.675188 +159.753761 -69.675188 +# -b +139.923004 -66.690014 +141.640887 -66.793275 +142.373100 -67.023264 +143.527743 -67.042039 +144.452396 -67.145300 +145.827641 -67.234480 +145.273788 -67.673338 +146.301702 -67.818842 +147.024527 -68.020669 +148.155702 -68.267087 +147.841226 -68.450140 +148.864446 -68.377388 +149.310345 -68.506464 +149.662370 -68.525239 +149.864198 -68.501771 +149.864198 -68.501771 +# -b +129.894978 -66.007085 +130.932279 -66.197178 +132.133858 -66.192485 +133.532572 -66.131467 +134.518243 -65.863928 +134.907817 -65.312422 +135.588400 -65.249057 +135.208212 -65.990657 +135.226987 -66.077490 +136.029605 -66.302786 +137.616065 -66.476452 +139.409047 -66.668892 +139.920657 -66.690014 +# -b +119.604106 -66.969287 +120.932414 -66.805009 +121.035675 -66.370844 +121.181179 -65.720771 +121.824212 -66.258196 +122.523568 -66.600834 +123.302718 -66.790928 +123.875345 -66.598487 +123.363735 -66.551551 +123.828409 -66.239422 +125.386707 -66.298092 +126.461558 -66.445943 +127.099897 -66.556244 +127.813335 -67.023264 +129.122869 -67.037345 +129.535912 -66.619609 +129.817532 -66.215953 +129.897324 -66.007085 +# -b +109.958613 -66.652464 +110.474917 -66.530429 +110.521854 -66.291052 +111.897099 -65.936680 +112.868689 -65.784135 +113.877828 -66.049328 +114.488005 -66.441249 +115.032471 -66.492880 +115.910187 -66.387272 +116.698724 -66.701748 +117.717250 -66.973981 +118.510480 -66.922351 +119.604106 -66.969287 +# -b +99.822632 -65.821685 +100.775447 -65.469660 +101.573371 -65.650366 +102.582510 -65.716077 +102.873518 -65.199774 +103.624505 -65.406295 +104.802616 -65.633938 +104.999751 -66.054022 +104.131422 -65.917905 +104.844859 -66.136161 +106.525193 -66.450637 +107.876970 -66.614915 +108.454292 -66.851945 +109.050388 -66.936432 +109.646484 -66.645424 +109.956266 -66.652464 +# -b +89.545841 -66.920004 +91.850433 -66.624302 +93.047319 -66.678280 +94.309916 -66.626649 +94.309916 -66.626649 +# -b +94.300529 -66.636037 +94.835608 -66.417781 +95.173552 -66.481146 +95.520883 -66.265237 +95.497415 -65.619857 +96.093511 -65.152837 +97.318559 -65.450885 +98.440346 -65.816991 +99.524584 -65.946067 +99.824979 -65.821685 +# -b +79.768926 -68.034750 +81.294369 -67.896287 +81.791898 -67.396411 +82.369219 -66.959900 +81.336612 -66.049328 +82.181473 -66.025860 +83.265710 -66.504614 +84.387498 -66.481146 +85.283989 -66.551551 +86.264966 -66.314520 +88.273857 -66.192485 +89.545841 -66.920004 +89.545841 -66.920004 +# -b +69.682229 -68.053525 +70.475459 -68.544014 +71.357869 -68.734107 +72.141712 -68.410244 +73.493489 -68.609725 +73.455940 -68.924201 +74.347737 -69.046236 +74.225701 -69.590702 +74.192846 -69.818345 +75.370957 -69.311429 +75.535235 -69.578968 +76.544375 -69.499176 +77.929007 -69.048583 +78.243483 -68.497077 +79.768926 -68.034750 +79.768926 -68.034750 +# -b +59.680017 -67.541915 +61.158523 -67.581811 +61.322802 -67.689766 +61.923592 -67.668644 +62.913956 -67.746090 +64.228184 -67.701500 +65.603429 -67.861085 +67.908021 -67.961998 +69.625905 -67.884553 +69.682229 -68.053525 +# -b +49.992282 -67.349475 +50.250434 -67.196930 +50.386550 -66.936432 +50.039219 -66.887148 +# -b +49.903102 -66.671239 +50.799593 -66.368497 +52.179532 -66.077490 +53.385806 -66.016472 +54.653096 -66.075143 +55.615299 -66.258196 +56.103441 -66.457677 +56.802797 -66.638383 +57.070337 -66.887148 +56.450772 -66.999796 +56.812185 -67.182849 +57.412975 -67.157034 +58.018458 -67.206318 +58.562924 -67.330700 +58.445582 -67.412839 +59.182488 -67.506712 +59.445334 -67.473857 +59.680017 -67.541915 +# -b +39.940787 -68.966444 +41.029719 -68.684824 +42.184361 -68.447793 +42.803926 -68.095768 +44.268351 -67.757824 +45.127293 -67.746090 +46.249080 -67.344781 +47.187814 -67.567730 +47.070472 -67.713234 +47.469434 -67.844657 +48.380006 -67.640482 +49.041814 -67.511406 +48.614690 -67.459776 +48.253277 -67.124178 +48.971409 -67.074895 +49.759945 -67.318966 +49.989935 -67.349475 +# -b +50.036872 -66.887148 +49.900755 -66.671239 +# -b +29.858783 -69.353672 +30.661401 -69.133069 +31.590748 -69.205821 +32.365203 -69.550806 +33.012930 -69.334897 +32.801715 -69.043889 +33.961051 -68.774003 +35.096919 -69.226943 +35.810357 -69.590702 +36.612975 -69.757327 +37.575177 -69.811305 +37.575177 -69.811305 +# -b +38.150152 -70.132821 +38.863590 -69.752634 +39.225002 -69.553153 +39.314182 -69.327857 +39.511316 -69.001646 +39.943134 -68.966444 +39.943134 -68.966444 +# -b +19.525668 -69.994358 +20.041972 -69.987317 +# -b +27.507255 -70.053029 +28.582105 -69.844160 +29.079634 -69.625905 +29.858783 -69.353672 +# -b +9.868442 -69.975583 +10.051495 -69.963849 +# -b +12.600158 -70.104659 +12.886472 -69.841813 +13.477874 -69.548459 +14.571499 -69.381834 +14.839039 -69.370100 +15.303712 -69.712738 +16.345707 -69.792530 +17.819519 -69.855894 +18.373372 -69.989664 +# -b +19.147828 -70.043641 +19.523321 -69.994358 +# -b +-0.150197 -69.130722 +0.023468 -69.095520 +# -b +-0.053977 -69.201127 +0.359066 -69.651720 +1.016180 -69.980277 +# -b +1.342390 -70.062416 +1.783595 -69.933340 +# -b +6.824597 -70.010786 +7.171928 -69.992011 +# -b +7.545075 -70.003745 +7.906488 -69.994358 +8.239738 -69.989664 +# -b +9.239490 -70.043641 +9.868442 -69.975583 +9.868442 -69.975583 +# -b +-10.150062 -70.914317 +-9.539885 -70.635044 +-8.704411 -70.571679 +-7.840776 -70.717183 +-7.014690 -70.501274 +-6.263703 -70.520049 +-5.188852 -70.459031 +-4.311136 -70.407401 +-3.372402 -70.360464 +-2.597946 -70.266591 +-1.509015 -70.053029 +-1.509015 -70.053029 +# -b +-20.105337 -73.479408 +-19.452916 -73.066365 +-18.955387 -72.869231 +-18.495408 -72.629854 +-17.101388 -72.613426 +-16.420805 -72.486697 +-15.529008 -72.209770 +-14.139682 -72.019676 +-13.318289 -72.104162 +-13.046056 -71.989168 +-12.501591 -71.770912 +-12.140178 -71.407152 +-11.370416 -71.141960 +-10.375358 -70.994109 +-10.150062 -70.914317 +# -b +-30.236624 -76.718040 +-28.790973 -76.375402 +-27.457971 -76.187656 +-26.650660 -75.915423 +-26.683515 -75.565744 +-25.031343 -75.293511 +-24.425860 -75.086990 +-23.642017 -74.535484 +-22.440438 -74.213967 +-21.558027 -74.216314 +-20.727248 -73.908879 +-20.107683 -73.479408 +-20.107683 -73.479408 +# -b +-31.975629 -77.117002 +-31.008733 -76.910481 +-30.238971 -76.718040 +# -b +-40.799729 -77.825747 +-37.514160 -77.985331 +-35.430170 -77.870336 +-32.848651 -77.196795 +-31.975629 -77.117002 +# -b +-50.323186 -77.659121 +-47.966963 -77.722486 +-45.920523 -78.058083 +-44.427936 -78.250524 +-42.428432 -77.818706 +-40.795035 -77.825747 +# -b +-45.997969 -77.680243 +-47.471781 -77.713098 +-47.621978 -77.471374 +-45.885320 -77.699017 +-46.091842 -77.724833 +# -b +-60.238564 -72.160487 +-59.961638 -72.303643 +# -b +-60.210402 -72.890352 +-59.656549 -73.380841 +-59.656549 -73.380841 +# -b +-60.590589 -75.281777 +-58.093557 -75.748797 +-56.765248 -76.422339 +-55.826514 -76.788445 +-54.709421 -77.046597 +-54.085162 -77.241385 +-54.446575 -77.457293 +-54.207198 -77.659121 +# -b +-60.602324 -69.830079 +-60.691503 -70.557598 +-60.419270 -71.064515 +-60.555387 -71.806114 +-60.175200 -71.961006 +-60.236217 -72.160487 +# -b +-59.961638 -72.303643 +-60.210402 -72.890352 +-60.210402 -72.890352 +# -b +-59.654202 -73.380841 +-60.719665 -73.620218 +-60.578855 -74.143562 +-60.677422 -74.284372 +-61.498815 -74.723231 +-60.588243 -75.281777 +-60.588243 -75.281777 +# -b +-69.353672 -69.834773 +-68.837368 -70.001398 +-68.837368 -70.001398 +# -b +-74.936792 -70.043641 +-75.448403 -70.027213 +-75.908382 -70.010786 +# -b +-74.643438 -69.989664 +-74.939139 -70.043641 +-74.939139 -70.043641 +# -b +-80.036465 -73.085140 +-78.675301 -73.251765 +-77.990025 -73.343291 +-78.708157 -72.885659 +-77.544126 -72.756583 +-77.675549 -72.559449 +-76.802526 -72.573530 +-76.473970 -72.702605 +-76.145413 -72.829335 +-75.798081 -72.939636 +-74.629357 -72.923208 +-73.704704 -73.068712 +-73.465327 -73.263499 +-72.658016 -73.484102 +-71.930497 -73.350332 +-72.643935 -73.017081 +-72.132325 -72.693218 +-72.545368 -72.484350 +-72.719033 -72.174568 +-73.615524 -72.202730 +-74.925058 -71.982127 +-75.511767 -71.493985 +-74.868734 -71.371950 +-73.662461 -71.259302 +-73.685929 -70.970641 +-74.770167 -70.907277 +-75.155048 -70.787588 +-74.568339 -70.731264 +-74.221008 -70.569332 +-74.610582 -70.092925 +-74.573033 -70.001398 +# -b +-90.301522 -72.496084 +-88.818322 -72.517205 +-87.311654 -72.540674 +-85.800292 -72.880965 +-83.880581 -72.885659 +-81.721493 -73.033509 +-80.036465 -73.085140 +-80.036465 -73.085140 +# -b +-100.054969 -72.014983 +-99.867222 -72.031411 +# -b +-100.045582 -72.087735 +-99.463566 -72.181608 +-98.956650 -72.221504 +-98.280762 -72.317724 +-98.468508 -72.155793 +-97.961592 -72.092428 +-97.562630 -72.282522 +-97.327946 -72.176914 +-96.797562 -72.047838 +-96.581653 -72.252013 +-95.891683 -72.291909 +-95.760261 -72.411598 +-95.919845 -72.634547 +-95.197020 -72.714340 +-94.906013 -72.733114 +-93.676271 -72.704952 +-92.408980 -72.737808 +-90.860069 -72.543021 +-90.301522 -72.496084 +# -b +-104.903530 -73.308089 +-104.457632 -73.279927 +-104.194786 -73.486448 +-104.795576 -73.418390 +-104.903530 -73.308089 +# -b +-110.029018 -74.350084 +-109.193545 -74.718537 +-107.010988 -75.070562 +-107.597697 -74.392327 +-105.607581 -74.274985 +-105.250862 -74.657519 +-104.931692 -74.810063 +-102.843009 -75.016585 +-101.181450 -75.009544 +-101.890194 -74.652825 +-101.988761 -74.218661 +-102.134265 -73.838474 +-101.556943 -73.753988 +-100.974928 -73.589709 +-102.016923 -73.498183 +-103.011981 -73.430124 +-103.415637 -73.218909 +-103.227890 -73.017081 +-102.800766 -72.890352 +-102.997900 -72.669750 +-103.584609 -72.423332 +-102.279769 -72.324765 +-101.214305 -72.050185 +-100.054969 -72.014983 +# -b +-99.864875 -72.031411 +-100.043235 -72.087735 +# -b +-120.141531 -73.915919 +-118.954032 -74.037955 +-117.179825 -74.155296 +-115.424392 -74.181112 +-113.978742 -74.061423 +-113.448357 -74.190499 +-112.026175 -74.371205 +-111.031117 -74.267944 +-110.026671 -74.350084 +# -b +-130.223534 -74.192846 +-128.411778 -74.096626 +-128.411778 -74.096626 +# -b +-127.503553 -73.988671 +-125.954641 -73.718785 +-125.513436 -73.369107 +-124.030237 -73.470021 +-123.030485 -73.700010 +-121.214034 -73.807965 +-120.247138 -73.904185 +-120.143878 -73.915919 +# -b +-140.474510 -75.126886 +-135.931037 -74.673947 +-135.316167 -74.737312 +# -b +-135.318514 -74.737312 +-134.201420 -74.765474 +-133.046777 -74.634051 +-131.948458 -74.418142 +-130.629537 -74.199886 +-130.225881 -74.192846 +# -b +-150.134084 -76.614780 +-148.143968 -76.260408 +-148.143968 -76.260408 +# -b +-145.801826 -75.335754 +-146.623218 -75.666658 +-146.979937 -75.554010 +-145.923861 -75.349835 +-145.801826 -75.335754 +# -b +-147.461038 -76.347240 +-145.827641 -76.546721 +-146.588016 -76.089089 +-145.043798 -75.626762 +-142.279227 -75.237187 +-140.472163 -75.126886 +-140.472163 -75.126886 +# -b +-160.464852 -77.975944 +-158.568609 -77.652081 +-158.465348 -77.203835 +-154.935708 -77.117002 +-153.283536 -77.276587 +-151.415456 -77.107615 +-150.157552 -76.718040 +-150.129390 -76.614780 +# -b +-170.490532 -78.565000 +-166.989054 -78.546225 +-164.454472 -78.407762 +-162.408031 -78.173078 +-160.464852 -77.975944 +# -b +-179.000000 -78.427199 +-176.287399 -78.506329 +-173.865466 -78.520410 +-170.486023 -78.565000 +-170.486023 -78.565000 +# -b +169.988309 -71.411846 +170.485838 -71.914069 +170.274623 -72.031411 +# -b +169.910863 -77.530045 +172.257698 -77.675549 +175.299197 -77.851562 +178.500280 -78.189506 +179.000000 -78.238497 +# -b +160.263024 -69.977930 +160.671373 -70.322915 +161.459910 -70.416788 +162.271915 -70.719530 +162.975966 -70.731264 +164.247950 -70.752385 +165.862573 -70.628003 +166.299084 -70.759426 +166.989054 -71.019925 +168.124922 -71.170122 +169.293646 -71.639489 +169.880354 -71.571431 +169.988309 -71.411846 +# -b +170.274623 -72.031411 +169.903823 -72.298950 +169.565879 -72.866884 +168.796117 -73.244724 +167.613312 -73.491142 +166.618254 -74.103666 +164.952001 -74.265598 +165.332188 -74.561299 +164.144689 -74.753739 +163.501657 -75.263003 +164.229175 -75.631456 +162.708426 -75.593906 +162.501905 -75.962359 +162.802300 -76.295610 +162.553535 -76.577230 +162.445581 -76.936296 +162.774138 -77.117002 +162.957191 -77.461987 +163.421864 -77.811666 +163.830214 -77.882071 +164.276112 -77.736567 +164.313662 -77.332911 +164.538958 -77.142818 +164.825272 -77.288321 +165.557484 -77.440866 +166.177049 -77.530045 +166.177049 -77.530045 +# -b +169.603428 -73.338598 +169.603428 -73.338598 +169.495474 -73.308089 +169.603428 -73.338598 +# -b +37.577524 -69.811305 +37.962405 -70.020173 +38.150152 -70.132821 +# -b +20.041972 -69.987317 +21.426605 -70.158636 +21.022949 -70.236082 +23.008372 -70.233735 +24.378923 -70.339342 +24.791966 -70.217307 +25.284802 -70.203226 +26.092113 -70.132821 +26.617804 -70.022520 +27.509601 -70.053029 +# -b +10.051495 -69.963849 +10.764933 -70.020173 +11.928963 -70.043641 +12.600158 -70.104659 +# -b +18.373372 -69.989664 +18.758253 -70.017826 +19.147828 -70.043641 +# -b +1.013833 -69.980277 +1.342390 -70.062416 +# -b +1.781248 -69.933340 +2.813855 -70.111699 +4.062372 -70.069456 +5.118447 -70.128127 +5.564346 -70.290059 +5.972695 -70.158636 +6.399819 -70.203226 +6.822250 -70.010786 +6.822250 -70.010786 +# -b +7.171928 -69.992011 +7.547422 -70.003745 +# -b +8.242085 -69.989664 +9.194900 -70.107006 +9.241837 -70.043641 +# -b +-19.443529 81.768430 +-18.908451 81.744961 +-18.561119 81.665169 +-18.974162 81.686290 +-19.443529 81.768430 +# -b +-19.598420 80.231253 +-19.063342 80.153807 +-19.729843 80.052893 +-19.898815 80.177275 +-19.598420 80.231253 +# -b +-20.018504 81.463341 +-19.596073 81.522012 +-18.948347 81.458647 +-18.413268 81.449260 +-18.300620 81.543133 +-18.047162 81.573642 +-18.065937 81.629966 +-18.103486 81.709759 +-17.568408 81.676903 +-17.605957 81.824754 +-17.221076 81.834141 +-16.742322 81.869343 +-15.878686 81.885771 +-15.202798 81.904546 +-14.376712 81.831794 +-13.691436 81.810673 +-12.959224 81.740268 +-12.349046 81.615885 +-12.837188 81.442219 +-13.372267 81.296716 +-13.851021 81.191108 +-14.151416 81.108969 +-14.695882 81.111316 +-15.118312 81.047951 +-14.742818 80.907141 +-15.690940 80.832042 +-16.010109 80.766331 +-16.714160 80.705313 +-17.718605 80.742863 +-18.150423 80.702966 +-18.591628 80.623174 +-19.464651 80.646642 +-19.736883 80.665417 +# -b +-20.018504 80.627868 +-19.267516 80.559809 +-18.206747 80.543382 +-17.249238 80.595012 +-16.263567 80.536341 +-16.573350 80.386144 +-16.704772 80.329820 +-17.455760 80.217172 +-18.366332 80.212478 +-19.333228 80.250027 +-19.896468 80.271149 +# -b +-19.774433 79.980141 +-19.107932 80.062280 +-18.469592 80.102177 +-17.709218 80.113911 +-17.512084 80.012997 +# -b +-21.121516 82.153311 +-20.849283 82.080559 +-20.314205 81.977298 +-20.041972 81.834141 +-20.792959 81.920974 +-21.374974 82.071171 +-21.121516 82.153311 +# -b +-22.851134 82.033622 +-22.560126 81.911587 +-22.513189 81.761389 +-22.550739 81.550174 +-22.785422 81.390589 +-23.414374 81.277941 +-23.461311 81.242738 +-23.461311 81.123050 +-24.043326 80.923569 +-24.597179 80.665417 +-24.906961 80.482364 +-24.709827 80.482364 +-24.268622 80.590318 +-23.921290 80.726435 +-23.827417 80.829696 +-23.442536 80.911835 +-22.879296 81.047951 +-22.071984 81.245085 +-21.715265 81.402323 +-20.954891 81.573642 +-20.325939 81.648741 +-20.466749 81.507931 +-20.156967 81.453954 +-20.025544 81.463341 +# -b +-19.741577 80.665417 +-20.717861 80.576237 +-20.990093 80.533994 +-20.426853 80.555116 +-20.023197 80.627868 +# -b +-19.896468 80.271149 +-20.553582 80.088096 +-20.525420 80.012997 +# -b +-30.175606 83.500394 +-29.987859 83.502741 +-29.893986 83.483966 +# -b +-30.053571 83.406520 +-29.302583 83.420601 +-29.584204 83.451110 +-28.420173 83.451110 +-26.936974 83.343156 +-27.181044 83.195305 +-28.345075 83.129594 +-29.678077 83.146022 +-29.678077 83.146022 +# -b +-30.318763 83.089698 +-29.586550 83.028680 +-29.267381 83.052148 +-27.971928 83.035721 +-26.995644 83.108472 +-25.925488 83.103779 +-25.887938 83.014599 +-25.756516 82.937153 +-26.188333 82.864402 +-26.310369 82.808078 +-27.220941 82.732979 +-26.282207 82.758794 +-25.005528 82.862055 +-24.423513 82.847974 +-24.385964 82.768181 +-23.907209 82.810424 +-23.419068 82.768181 +-22.930926 82.772875 +-22.508496 82.737672 +-21.719959 82.636759 +-21.644860 82.535845 +-22.039129 82.484214 +-22.536658 82.380954 +-23.353356 82.270652 +-24.282703 82.256571 +-25.521832 82.136883 +-25.925488 82.125148 +-26.685862 82.122802 +-27.624596 82.155657 +-28.788627 82.162698 +-29.248606 82.150964 +# -b +-30.163872 81.946789 +-29.178201 81.979645 +-27.629290 81.979645 +-26.596683 81.949136 +-26.343224 81.716799 +-27.685614 81.554868 +-28.145594 81.430485 +-27.169310 81.491503 +-25.723660 81.665169 +-24.615954 81.733227 +-24.803700 81.850569 +-24.550242 81.986685 +-23.395599 82.035969 +-22.851134 82.033622 +# -b +-40.055782 83.155409 +-39.886810 83.108472 +# -b +-40.079250 82.836240 +-39.647433 82.808078 +-39.975990 82.850321 +# -b +-40.067516 82.991131 +-38.959810 83.009905 +-38.828387 83.019293 +-39.842220 83.021640 +-39.185106 83.096738 +-38.302696 83.134288 +-38.903486 83.153062 +-39.335304 83.190612 +-39.954868 83.216427 +-39.954868 83.216427 +# -b +-40.022926 83.251629 +-39.947828 83.277445 +-39.947828 83.298566 +# -b +-40.067516 83.359584 +-39.879769 83.378358 +# -b +-40.001805 83.404174 +-39.494888 83.406520 +-39.006747 83.373665 +-39.138169 83.479272 +-38.687577 83.469885 +-38.086787 83.411214 +-37.561096 83.354890 +-37.842716 83.422948 +-38.049238 83.486313 +-37.542322 83.554371 +-36.866433 83.552024 +-36.321967 83.563758 +-35.758727 83.542637 +-35.420783 83.507434 +-35.270585 83.530903 +-34.838767 83.603655 +-34.050231 83.608348 +-33.618413 83.568452 +-32.923750 83.570799 +-32.266636 83.570799 +-31.158930 83.549677 +-30.633239 83.481619 +-30.163872 83.500394 +-30.163872 83.500394 +# -b +-29.886945 83.483966 +-30.187340 83.444070 +-30.055917 83.406520 +# -b +-29.678077 83.146022 +-31.198826 83.162450 +-32.250208 83.117860 +-33.264041 83.042761 +-34.071352 83.099085 +-34.709692 83.148369 +-34.221550 83.087351 +-34.184000 82.993477 +-35.066410 82.960622 +-36.211666 82.913685 +-36.493286 82.880829 +-36.436962 82.803384 +-35.742299 82.894910 +-35.197833 82.880829 +-34.981924 82.803384 +-34.906826 82.911338 +-34.061965 82.930113 +-33.160780 82.953581 +-32.860385 82.948888 +-32.128173 83.049802 +-31.114340 83.103779 +-30.250705 83.089698 +# -b +-29.666343 82.150964 +-31.177705 82.104027 +-31.769107 82.155657 +-32.904975 82.158004 +-31.853593 82.136883 +-31.384226 82.045356 +-32.557644 81.958523 +-33.374342 81.899852 +-34.134717 81.756695 +-33.731061 81.655781 +-32.736003 81.801285 +-31.449938 81.876384 +-30.961796 81.848222 +-30.163872 81.946789 +-30.163872 81.946789 +# -b +-48.415209 82.622678 +-47.851968 82.650840 +-47.560961 82.648493 +-47.147918 82.669614 +-46.575290 82.599209 +-46.012050 82.535845 +-45.655331 82.430237 +-45.298612 82.324629 +-45.786753 82.254224 +-45.871239 82.160351 +-45.664718 82.047703 +-46.096536 82.122802 +-46.669163 82.226062 +-47.307503 82.317589 +-47.814419 82.413809 +-48.218075 82.578088 +-48.415209 82.622678 +# -b +-47.699424 82.944194 +-47.305156 82.941847 +-47.136184 82.965315 +-47.530452 82.995824 +-47.004761 83.073270 +-46.629267 83.012252 +-46.047252 82.937153 +-46.103576 82.843280 +-46.704366 82.840933 +-47.436578 82.897257 +-47.699424 82.944194 +# -b +-42.538734 83.164796 +-42.013042 83.155409 +-41.487351 83.047455 +-40.942886 82.960622 +-41.731422 83.009905 +-42.388536 83.124900 +-42.538734 83.164796 +# -b +-41.632855 83.134288 +-41.201038 83.148369 +-40.581473 83.082657 +-40.525149 82.986437 +-41.144713 83.054495 +-41.632855 83.134288 +# -b +-41.611734 83.361931 +-41.104817 83.293872 +-40.485253 83.185918 +-40.072210 83.155409 +# -b +-39.900891 83.108472 +-40.651878 83.143675 +-41.233893 83.244589 +-41.740810 83.314994 +-41.609387 83.361931 +# -b +-50.135439 82.491255 +-49.609748 82.364526 +-48.483267 82.223716 +-47.722892 82.118108 +-46.802933 81.986685 +-46.342953 81.866997 +-45.441769 81.744961 +-45.075662 81.796592 +-45.329121 81.874037 +-45.676452 81.960870 +-45.516867 82.040662 +-44.794042 82.057090 +-44.925465 82.082905 +-45.451156 82.104027 +-45.601353 82.197900 +-45.197698 82.301161 +-43.902245 82.230756 +-43.395328 82.207288 +-43.911632 82.265959 +-44.737718 82.329323 +-44.784655 82.404422 +-45.413607 82.507683 +-45.826650 82.594516 +-46.427439 82.714204 +-46.202143 82.770528 +-45.225860 82.758794 +-43.883470 82.770528 +-42.935349 82.669614 +-42.841475 82.458399 +-42.700665 82.545232 +-42.775764 82.683695 +-42.447207 82.718898 +-41.799480 82.594516 +-41.161141 82.484214 +-40.917070 82.432584 +-41.057881 82.547579 +-40.964007 82.648493 +-41.245627 82.683695 +-41.893354 82.732979 +-42.315784 82.775222 +-43.019835 82.826852 +-43.761435 82.843280 +-44.559359 82.831546 +-45.244634 82.901951 +-44.831591 82.897257 +-44.540584 82.918379 +-44.869141 82.911338 +-45.197698 82.981743 +-45.376057 83.038067 +-45.563804 83.094391 +-45.376057 83.120207 +-45.216472 83.094391 +-45.188310 83.131941 +-44.718943 83.108472 +-44.615683 83.117860 +-44.371612 83.110819 +-44.794042 83.185918 +-44.371612 83.211733 +-44.409161 83.270404 +-43.986731 83.228161 +-43.752047 83.155409 +-43.742660 83.087351 +-43.339004 83.028680 +-42.963511 82.937153 +-42.559855 82.927766 +-42.259460 82.836240 +# -b +-39.978336 82.850321 +-40.203633 82.970009 +-40.072210 82.991131 +# -b +-39.957215 83.216427 +-40.032314 83.228161 +-40.032314 83.251629 +# -b +-39.957215 83.298566 +-40.032314 83.329075 +-40.069863 83.359584 +# -b +-39.879769 83.378358 +-40.011192 83.404174 +# -b +-53.721403 82.317589 +-53.355297 82.280040 +-53.120613 82.179126 +-52.397788 82.080559 +-51.815773 81.972604 +-52.238203 81.949136 +-52.829606 81.981992 +-53.392846 82.054743 +-53.815276 82.165045 +-53.899762 82.268305 +-53.721403 82.317589 +# -b +-60.193974 81.869343 +-59.414825 81.789551 +-59.311564 81.667516 +-58.701387 81.571295 +-58.053661 81.496197 +-57.790815 81.416404 +-57.659392 81.470381 +-58.203858 81.601804 +-58.485478 81.660475 +-58.907909 81.768430 +-59.414825 81.911587 +-59.799706 81.939749 +# -b +-60.029696 81.967911 +-59.428906 82.059437 +-58.649757 82.113414 +-57.748572 82.150964 +-57.025747 82.197900 +-56.819225 82.233103 +-56.171499 82.226062 +-56.180886 82.244837 +-55.739681 82.317589 +-54.988694 82.329323 +-54.594426 82.204941 +-54.256481 82.045356 +-54.040573 81.878731 +-54.200157 81.705065 +-54.200157 81.533746 +-53.909150 81.627619 +-53.496107 81.822407 +-53.524269 82.000766 +-52.792056 81.932708 +-52.444725 81.906893 +-51.571702 81.805979 +-50.886426 81.702718 +-50.933363 81.770776 +-51.487216 81.883424 +-50.877039 81.892812 +-50.210538 81.895159 +-50.886426 82.035969 +-51.355793 82.167392 +-51.524765 82.294121 +-51.646801 82.397381 +-51.834547 82.498295 +-51.787611 82.507683 +# -b +-51.789958 82.507683 +-51.104682 82.514723 +-50.287983 82.491255 +-50.137786 82.491255 +# -b +-70.196186 80.280536 +-69.510910 80.451855 +-69.201127 80.576237 +-68.684824 80.700620 +-68.121583 80.773371 +-67.736702 80.850817 +-67.558343 80.893060 +-66.920004 80.996321 +-66.525735 81.094888 +-66.009432 81.202842 +-65.108247 81.320184 +-64.620105 81.418751 +-64.591943 81.531399 +-65.023761 81.524359 +-66.018819 81.458647 +-66.863680 81.355387 +-67.689766 81.320184 +-68.553401 81.231004 +-69.276226 81.162946 +-69.989664 81.090194 +-69.989664 81.090194 +# -b +-70.031907 81.172333 +-69.900484 81.242738 +-69.337244 81.221617 +-68.605031 81.310797 +-67.919755 81.404670 +-67.121832 81.482116 +-67.168768 81.519665 +-67.891593 81.510278 +-68.558095 81.500890 +-69.149497 81.477422 +-69.046236 81.533746 +-68.914814 81.583030 +-69.365406 81.676903 +-69.046236 81.641700 +-68.539320 81.561908 +-68.304636 81.615885 +-67.947917 81.594764 +-67.168768 81.594764 +-66.492880 81.604151 +-65.910865 81.615885 +-65.497822 81.665169 +-65.863928 81.688637 +-65.300687 81.721493 +-64.850095 81.698025 +-64.352566 81.719146 +-64.324404 81.761389 +-63.939523 81.770776 +-63.629741 81.838835 +-62.766106 81.916280 +-62.146541 82.017194 +-61.742885 82.122802 +-61.282906 82.204941 +-61.160870 82.291774 +-61.395554 82.427890 +-62.249802 82.470133 +-62.371837 82.500642 +# -b +-62.367144 82.500642 +-62.817736 82.465440 +-63.390364 82.416156 +-63.174455 82.526457 +-63.521786 82.603903 +-63.822181 82.709510 +-63.700146 82.801037 +-64.019315 82.852667 +-64.404196 82.782262 +-64.732753 82.847974 +-64.770303 82.894910 +-64.976824 82.885523 +-65.239670 82.808078 +-65.117634 82.732979 +-65.399255 82.847974 +-66.450637 82.754100 +-66.882454 82.711857 +-67.135913 82.695429 +-67.858738 82.646146 +-68.337492 82.669614 +-67.051426 82.789303 +-66.366151 82.918379 +-66.572672 82.958275 +-66.854292 82.953581 +-67.032652 82.991131 +-67.295497 82.995824 +-67.670991 82.993477 +-67.811801 83.019293 +-67.811801 83.019293 +# -b +-64.880604 79.982488 +-64.307976 80.081055 +-63.744736 80.120951 +-64.185941 80.226559 +-64.279814 80.219518 +-64.617758 80.071668 +-65.284260 80.055240 +-65.490781 80.022384 +# -b +-66.159629 79.989529 +-66.600834 80.055240 +-67.192237 80.050546 +-67.351821 80.106870 +-67.661604 80.205437 +-67.699153 80.308698 +-67.304885 80.376756 +-66.957553 80.414306 +-66.732257 80.503485 +-66.516348 80.562156 +-66.037594 80.637255 +-65.493128 80.592665 +-65.727811 80.679498 +-65.342930 80.768678 +-64.986212 80.871939 +-64.779690 80.991627 +-64.338485 81.066726 +-64.160126 81.134784 +-63.822181 81.158252 +-63.155680 81.188761 +-62.498566 81.116009 +-61.944713 81.097235 +-61.559832 81.195802 +-61.728804 81.306103 +-61.390860 81.456300 +-61.625544 81.554868 +-61.756966 81.629966 +-61.879002 81.646394 +-61.869615 81.768430 +-61.240663 81.876384 +-60.771296 81.916280 +-60.771296 81.916280 +# -b +-60.768949 81.916280 +-60.440392 81.885771 +-60.186934 81.869343 +# -b +-59.797359 81.939749 +-60.032043 81.967911 +# -b +-80.177275 80.498792 +-79.548324 80.536341 +-78.834886 80.559809 +-78.403068 80.576237 +-78.863048 80.595012 +-79.548324 80.597359 +-79.895655 80.583278 +# -b +-80.210131 80.623174 +-79.637503 80.688885 +-79.158749 80.738169 +-78.820805 80.759290 +-78.013493 80.810921 +-77.760035 80.782759 +-77.656774 80.827349 +-77.159245 80.815614 +-76.821301 80.803880 +-76.558456 80.817961 +-76.624167 80.867245 +-76.229899 80.860204 +-76.164187 80.897754 +-75.704208 80.918875 +-75.497686 80.951731 +-75.873180 80.932956 +-76.483357 80.904794 +-76.896400 80.886020 +-77.224957 80.883673 +-77.572288 80.900101 +-77.835134 80.897754 +-78.088592 80.897754 +-78.454698 80.890713 +-78.783255 80.874285 +-79.093038 80.860204 +-79.421594 80.848470 +-79.515468 80.911835 +-79.233848 81.026830 +-79.130587 81.127744 +-78.811417 81.221617 +-78.755093 81.254473 +-78.464086 81.299063 +-78.135529 81.350693 +-77.929007 81.383549 +-77.694324 81.444566 +-77.844521 81.449260 +-78.285726 81.376508 +-78.764481 81.317837 +-79.177524 81.216923 +-79.412207 81.116009 +-79.393432 81.092541 +-79.599954 81.083154 +-79.731377 81.104275 +-79.890961 81.130090 +# -b +-80.066974 81.125397 +-79.766579 81.052645 +-79.869840 80.921222 +-79.738417 80.911835 +-79.935551 80.817961 +-79.935551 80.817961 +# -b +-71.167775 79.959020 +-71.252261 80.062280 +-72.247319 80.005956 +# -b +-72.700259 79.998916 +-72.240279 80.059934 +-71.095023 80.149113 +-70.334649 80.174929 +-70.869727 80.313392 +-70.681980 80.374409 +-70.193839 80.280536 +-70.193839 80.280536 +# -b +-69.987317 81.090194 +-70.325261 81.066726 +-70.456684 81.097235 +-71.057474 81.141825 +-70.513008 81.132437 +-70.024867 81.172333 +# -b +-69.766715 83.019293 +-70.517702 83.052148 +-70.930745 83.106126 +-72.132325 83.031027 +-72.489043 83.019293 +-72.920861 83.106126 +-73.728172 83.087351 +-73.972243 83.031027 +-74.272638 82.892564 +-73.803271 82.744713 +-74.742005 82.864402 +-75.136273 82.965315 +-76.206430 83.038067 +-77.032516 83.047455 +-77.276587 83.040414 +-77.971250 83.007559 +-78.459392 82.958275 +-77.821053 82.857361 +-77.163939 82.770528 +-76.760283 82.636759 +-76.384790 82.507683 +-77.004354 82.470133 +-77.248425 82.639105 +-77.980638 82.805731 +-79.107119 82.932460 +-79.445063 82.864402 +-79.764232 82.876136 +-80.214825 82.883176 +-80.308698 82.876136 +# -b +-90.036330 80.526954 +-89.670223 80.517566 +-89.304117 80.519913 +-89.060046 80.482364 +-88.938011 80.402572 +-89.088208 80.369716 +-88.947398 80.308698 +-88.994335 80.193703 +-88.891074 80.160847 +-88.571905 80.071668 +-88.252735 80.088096 +-88.130700 80.120951 +-88.290284 80.181969 +-88.571905 80.268802 +-88.421707 80.402572 +-87.858467 80.390837 +-87.605009 80.294617 +-87.529910 80.167888 +-87.811530 80.120951 +-87.989889 80.076361 +-87.614396 80.081055 +-87.248290 80.050546 +-87.248290 80.050546 +# -b +-86.354145 79.998916 +-86.739026 80.071668 +-86.729639 80.186663 +-86.616991 80.266455 +-86.185173 80.313392 +-85.528059 80.280536 +-85.068080 80.247680 +-84.204444 80.235946 +-83.631817 80.106870 +-83.209386 80.005956 +# -b +-82.493602 79.996569 +-82.700123 80.104523 +-83.131941 80.210131 +-83.432336 80.280536 +-83.056842 80.327473 +-82.625024 80.350941 +-82.061784 80.362675 +-81.798938 80.365022 +-81.169987 80.414306 +-80.738169 80.430734 +-80.437774 80.426040 +-80.747556 80.465936 +-80.503485 80.508179 +-80.174929 80.498792 +# -b +-79.890961 80.583278 +-80.285230 80.569197 +-80.332166 80.606746 +-80.210131 80.623174 +# -b +-79.890961 81.130090 +-80.163194 81.167640 +-80.059934 81.125397 +# -b +-79.935551 80.817961 +-80.311045 80.759290 +-80.555116 80.724088 +-81.043258 80.646642 +-81.662822 80.590318 +-82.019541 80.541035 +-82.329323 80.517566 +-82.751753 80.491751 +-83.136634 80.465936 +-83.587227 80.508179 +-83.493353 80.569197 +-83.117860 80.625521 +-82.676655 80.641949 +-82.507683 80.710007 +-82.085252 80.766331 +-82.132189 80.775718 +-82.310548 80.787452 +-82.254224 80.822655 +-82.235450 80.886020 +-82.517070 80.843777 +-82.479521 80.810921 +-82.667267 80.726435 +-83.061536 80.665417 +-83.474579 80.618480 +-83.615389 80.597359 +-83.821910 80.587971 +-83.943946 80.630215 +-83.765586 80.693579 +-83.662326 80.752250 +-83.897009 80.686539 +-84.216179 80.618480 +-84.122305 80.552769 +-84.253728 80.489404 +-84.479024 80.456549 +-84.920229 80.454202 +-85.258173 80.480017 +-85.380209 80.515220 +-85.201849 80.576237 +-85.492857 80.522260 +-85.633667 80.489404 +-85.952837 80.501139 +-86.394042 80.543382 +-86.365880 80.597359 +-86.272006 80.665417 +-86.187520 80.726435 +-86.046710 80.773371 +-85.821414 80.825002 +-85.708766 80.871939 +-85.530406 80.911835 +-85.286335 80.937650 +-84.920229 80.970506 +-84.572898 80.982240 +-84.028432 80.998668 +-83.709262 81.015095 +-83.408867 81.029176 +-82.864402 81.054992 +-82.244837 81.087847 +-82.301161 81.097235 +-82.808078 81.080807 +-83.277445 81.073766 +-83.765586 81.054992 +-84.056594 81.054992 +-84.450862 81.038564 +-84.826356 81.022136 +-85.230011 81.015095 +-85.586730 80.991627 +-85.896513 80.923569 +-86.469140 80.789799 +-86.741373 80.677151 +-86.844634 80.583278 +-87.135641 80.559809 +-87.417262 80.569197 +-87.661333 80.623174 +-88.074376 80.651336 +-88.280897 80.695926 +-88.759651 80.785106 +-89.116370 80.829696 +-89.341667 80.864898 +-89.341667 80.864898 +# -b +-79.968407 82.876136 +-80.531647 82.953581 +-81.226311 82.876136 +-80.794493 82.826852 +-80.409612 82.709510 +-80.860204 82.700123 +-81.057339 82.695429 +-82.005460 82.793997 +-82.118108 82.723591 +-81.676903 82.599209 +-81.395283 82.524110 +-81.789551 82.498295 +-82.681348 82.617984 +-83.338462 82.571047 +-82.625024 82.491255 +-82.962969 82.477174 +-83.432336 82.444318 +-83.404174 82.296467 +-82.502989 82.188513 +-81.705065 82.108721 +-81.601804 82.045356 +-81.714452 82.003113 +-82.653186 82.118108 +-83.413561 82.254224 +-83.854766 82.216675 +-83.563758 82.092293 +-83.469885 82.075865 +-83.845379 82.141576 +-84.211485 82.291774 +-84.408619 82.322283 +-85.037571 82.315242 +-85.422452 82.402075 +-85.713459 82.437278 +-86.417510 82.423197 +-86.304862 82.348098 +-86.210988 82.272999 +-86.783616 82.216675 +-87.365631 82.195554 +-86.755454 82.113414 +-85.863657 82.031275 +-85.450614 81.996073 +-86.042016 81.998419 +-86.126502 81.932708 +-87.065236 82.045356 +-87.431343 81.977298 +-87.543991 81.979645 +-87.666026 82.050050 +-88.013358 82.080559 +-88.614148 82.094640 +-89.243099 82.003113 +-89.383910 81.899852 +-89.674917 81.913933 +-89.806340 81.827100 +-89.956537 81.852916 +# -b +-90.036330 81.629966 +-89.482477 81.601804 +-89.970618 81.529052 +-89.970618 81.529052 +# -b +-90.059798 81.357733 +-89.383910 81.428138 +-88.632922 81.514971 +-88.003970 81.538440 +-87.337469 81.503237 +-86.483221 81.505584 +-86.980750 81.470381 +-87.938259 81.505584 +-88.632922 81.446913 +-89.750016 81.310797 +-89.261874 81.242738 +-88.999029 81.200495 +-89.890826 81.181721 +-89.928375 81.057339 +-89.205550 80.982240 +-88.501500 81.017442 +-87.750512 81.029176 +-87.112173 81.033870 +-86.426897 81.080807 +-85.891819 81.186414 +-85.000022 81.242738 +-84.558817 81.235698 +-85.506938 81.116009 +-86.182826 81.012749 +-87.121560 80.944690 +-87.844386 80.963465 +-88.576598 80.932956 +-89.205550 80.881326 +-89.336973 80.864898 +# -b +-99.123275 80.076361 +-99.010627 80.055240 +-98.832268 80.045853 +-98.475549 80.057587 +-98.344126 80.027078 +# -b +-99.531625 79.959020 +-99.343878 80.052893 +-99.118582 80.076361 +# -b +-95.187633 80.578584 +-94.924787 80.559809 +-94.511744 80.543382 +-93.986053 80.543382 +-93.601172 80.515220 +-93.807694 80.576237 +-94.136251 80.585625 +-94.220737 80.616134 +-93.976666 80.651336 +-93.497912 80.674804 +-93.817081 80.688885 +-94.061152 80.712354 +-94.474195 80.717047 +-94.652554 80.742863 +-94.446033 80.787452 +-94.915400 80.766331 +-94.887238 80.822655 +-94.906013 80.853164 +-94.943562 80.909488 +-94.840301 80.977546 +-94.596230 81.012749 +-94.173800 80.984587 +-94.155025 80.937650 +-93.995441 80.958771 +-93.807694 80.970506 +-93.601172 80.982240 +-93.788919 81.010402 +-93.995441 81.064379 +-93.591785 81.050298 +-93.338327 81.045604 +-93.028545 81.043258 +-92.803248 81.069073 +-92.699988 81.106622 +-92.643664 81.155906 +-92.850185 81.146518 +-92.962833 81.181721 +-93.300777 81.167640 +-93.713820 81.144171 +-93.939117 81.146518 +-94.342772 81.174680 +-94.436646 81.235698 +-94.408484 81.270901 +-94.605618 81.277941 +-94.370934 81.327225 +-93.939117 81.301409 +-93.488524 81.322531 +-93.235066 81.345999 +-92.897122 81.313144 +-92.427755 81.270901 +-92.014712 81.195802 +-91.545345 81.104275 +-91.601669 81.029176 +-91.404535 80.965812 +-91.244950 80.867245 +-91.066590 80.810921 +-90.963330 80.761637 +-90.935168 80.693579 +-90.634773 80.616134 +-90.691097 80.529301 +-90.691097 80.496445 +-90.512737 80.555116 +-90.240504 80.526954 +-90.033983 80.526954 +# -b +-96.079430 79.973101 +-95.703937 80.038812 +-96.192078 80.078708 +-96.201466 80.142073 +-95.797810 80.132685 +-95.450478 80.090442 +-95.112534 80.027078 +-94.924787 80.005956 +-94.821527 80.003610 +# -b +-94.725306 79.989529 +-94.349813 80.003610 +-94.349813 80.003610 +# -b +-94.072886 79.970754 +-94.298182 80.066974 +-93.885139 80.118604 +-93.594132 80.130339 +-93.969625 80.139726 +-94.176147 80.189010 +-94.551641 80.111564 +-94.955296 80.090442 +-95.067944 80.106870 +-95.246304 80.132685 +-95.199367 80.179622 +-95.199367 80.179622 +-95.002233 80.167888 +-94.748775 80.167888 +-94.720613 80.217172 +-94.974071 80.200744 +-95.002233 80.207784 +-95.236916 80.235946 +-95.603023 80.179622 +-95.875256 80.240640 +-96.063002 80.296964 +-96.297686 80.339207 +-95.940967 80.348594 +-95.443438 80.367369 +-94.927134 80.336860 +-94.927134 80.365022 +-94.992846 80.365022 +-95.077332 80.383797 +-95.424663 80.411959 +-95.800157 80.451855 +-95.687509 80.501139 +-95.743833 80.569197 +-95.434051 80.573890 +-95.293240 80.576237 +-95.189980 80.578584 +# -b +-89.949497 81.852916 +-90.428251 81.897505 +-91.104140 81.838835 +-91.451471 81.782511 +-91.826965 81.686290 +-92.024099 81.615885 +-91.507795 81.585376 +-91.338823 81.517318 +-90.878844 81.540787 +-90.615998 81.629966 +-90.156018 81.655781 +-90.033983 81.629966 +# -b +-89.970618 81.529052 +-90.449373 81.383549 +-90.064492 81.357733 +-90.064492 81.357733 +# -b +91.296580 80.001263 +91.090059 80.045853 +91.230869 80.045853 +91.456165 80.052893 +91.765947 80.071668 +92.141441 80.017691 +92.366737 80.010650 +# -b +91.275459 79.998916 +91.303621 80.001263 +# -b +90.911699 81.223964 +91.202707 81.207536 +91.653299 81.158252 +91.334130 81.071420 +90.770889 81.047951 +90.207649 81.073766 +90.048064 81.097235 +# -b +89.972965 81.167640 +90.545593 81.198149 +90.911699 81.223964 +90.911699 81.223964 +# -b +94.870810 81.101928 +95.105494 81.153559 +95.227529 81.223964 +95.668734 81.223964 +96.044228 81.134784 +96.307073 81.047951 +96.504207 80.935303 +96.860926 80.855511 +97.189483 80.801533 +97.461716 80.735822 +97.593139 80.688885 +97.649463 80.658377 +97.123772 80.611440 +97.039286 80.491751 +97.048673 80.397878 +97.217645 80.346247 +97.330293 80.304004 +96.926638 80.250027 +96.297686 80.245334 +95.574861 80.205437 +94.880197 80.120951 +94.241858 80.043506 +94.035337 80.003610 +# -b +93.833509 79.996569 +93.354755 80.045853 +92.969874 80.130339 +92.284598 80.160847 +92.275210 80.259415 +91.646259 80.299311 +91.383413 80.294617 +91.702583 80.357982 +91.824618 80.393184 +92.125013 80.444815 +92.641317 80.503485 +92.810289 80.602053 +92.519281 80.637255 +92.566218 80.759290 +93.016810 80.836736 +93.223332 80.909488 +93.720861 80.937650 +94.209003 80.991627 +94.706532 80.984587 +94.828567 81.069073 +94.866116 81.101928 +# -b +94.880197 80.015344 +94.927134 80.062280 +95.246304 80.029425 +95.499762 80.085749 +95.940967 80.118604 +96.438496 80.130339 +97.170709 80.139726 +97.471103 80.139726 +97.658850 80.092789 +98.062506 80.020037 +98.062506 80.020037 +# -b +98.454427 79.989529 +98.379329 80.041159 +98.651561 80.031772 +98.867470 80.001263 +98.867470 80.001263 +# -b +99.104501 79.991875 +99.282860 80.010650 +# -b +94.572762 79.984835 +94.854382 80.015344 +94.873157 80.015344 +# -b +79.982488 80.862551 +80.292270 80.881326 +80.705313 80.829696 +80.921222 80.810921 +80.968159 80.808574 +80.846123 80.752250 +80.273496 80.724088 +80.076361 80.719394 +# -b +90.050411 81.097235 +89.947150 81.127744 +89.975312 81.167640 +# -b +79.926164 80.848470 +79.944939 80.850817 +79.982488 80.862551 +# -b +80.069321 80.719394 +79.628116 80.771025 +79.834637 80.843777 +79.919123 80.848470 +# -b +60.506103 80.789799 +60.355906 80.789799 +60.158772 80.810921 +60.093060 80.806227 +# -b +59.933476 80.376756 +60.149384 80.365022 +60.262032 80.379103 +60.487329 80.374409 +60.590589 80.369716 +60.815886 80.350941 +61.069344 80.339207 +61.285253 80.367369 +61.538711 80.376756 +61.482387 80.461242 +61.472999 80.512873 +61.360351 80.562156 +61.163217 80.599706 +61.210154 80.641949 +61.407288 80.670111 +61.810944 80.674804 +62.214599 80.679498 +62.280311 80.717047 +62.205212 80.756944 +62.167663 80.794493 +62.148888 80.810921 +62.083176 80.841430 +61.932979 80.878979 +61.698296 80.853164 +61.472999 80.808574 +61.257091 80.796840 +61.022407 80.803880 +60.844048 80.801533 +60.637526 80.778065 +60.506103 80.789799 +60.506103 80.789799 +# -b +60.980164 81.071420 +60.961389 81.054992 +60.783030 81.033870 +60.492022 81.026830 +60.219789 80.991627 +60.191627 80.928263 +60.398149 80.895407 +60.792417 80.876632 +61.120974 80.869592 +61.487080 80.925916 +61.468306 80.972852 +61.299334 81.003361 +61.440144 81.012749 +61.149136 81.043258 +60.980164 81.071420 +60.980164 81.071420 +# -b +63.528827 81.287328 +63.434954 81.275594 +63.115784 81.223964 +62.843551 81.153559 +62.646417 81.106622 +62.721516 81.101928 +62.749678 81.069073 +62.796614 81.024483 +62.561931 80.958771 +62.496219 80.904794 +62.843551 80.853164 +63.068847 80.799187 +63.341080 80.752250 +63.556989 80.775718 +63.707186 80.822655 +63.866771 80.871939 +64.016969 80.911835 +64.204715 80.954078 +64.552047 80.961118 +64.852442 80.975199 +65.030801 80.961118 +65.199774 80.963465 +65.378133 80.958771 +65.509556 80.965812 +65.312422 81.015095 +65.143450 81.062032 +65.049576 81.099582 +64.871217 81.130090 +64.814893 81.158252 +64.814893 81.209883 +64.918153 81.256820 +64.899379 81.303756 +64.918153 81.348346 +64.702245 81.362427 +64.505110 81.385895 +64.232877 81.385895 +63.913708 81.334265 +63.622700 81.289675 +63.528827 81.287328 +# -b +63.538214 81.693331 +63.669637 81.665169 +63.556989 81.615885 +63.162721 81.615885 +62.852938 81.658128 +62.599480 81.665169 +62.411733 81.672209 +62.392959 81.700371 +62.468057 81.721493 +62.627642 81.700371 +62.777840 81.726187 +62.937424 81.730880 +63.162721 81.749655 +63.359855 81.744961 +63.500665 81.709759 +63.538214 81.693331 +# -b +50.844183 80.871939 +50.693986 80.839083 +50.299717 80.843777 +50.374816 80.890713 +50.243393 80.860204 +50.065034 80.853164 +50.065034 80.853164 +# -b +49.996976 80.853164 +50.006363 80.864898 +# -b +49.928917 80.806227 +50.097889 80.759290 +50.032178 80.731128 +# -b +49.964120 80.318085 +50.057993 80.339207 +50.217578 80.346247 +50.255127 80.379103 +50.283289 80.426040 +50.076768 80.437774 +# -b +49.964120 80.484711 +50.142479 80.508179 +50.292677 80.529301 +50.583684 80.512873 +50.818368 80.512873 +51.043664 80.496445 +51.231411 80.545728 +51.372221 80.548075 +51.513031 80.599706 +51.578742 80.648989 +51.531806 80.691232 +51.390996 80.714701 +51.231411 80.733475 +50.959178 80.726435 +50.790206 80.698273 +50.452262 80.674804 +50.283289 80.702966 +50.349001 80.759290 +50.640008 80.787452 +50.893467 80.803880 +50.931016 80.853164 +50.959178 80.883673 +50.865305 80.876632 +50.837143 80.871939 +# -b +53.029087 80.353288 +53.104185 80.348594 +53.357643 80.332166 +53.573552 80.264108 +53.714362 80.224212 +53.611102 80.165541 +53.385806 80.160847 +53.413968 80.116258 +53.169897 80.113911 +53.038474 80.132685 +52.953988 80.104523 +52.775628 80.120951 +52.672368 80.146766 +52.503396 80.163194 +52.371973 80.198397 +52.465846 80.207784 +52.794403 80.245334 +52.850727 80.296964 +52.831952 80.318085 +52.878889 80.341554 +52.982150 80.350941 +53.029087 80.353288 +# -b +56.767595 80.327473 +56.579848 80.329820 +56.626785 80.289923 +56.410876 80.294617 +56.157418 80.289923 +55.922734 80.282883 +55.913347 80.235946 +55.922734 80.181969 +55.866410 80.123298 +55.781924 80.074015 +55.941509 80.066974 +56.138643 80.052893 +56.298228 80.064627 +56.495362 80.038812 +56.598623 80.055240 +56.786370 80.041159 +56.955342 80.055240 +56.861468 80.116258 +56.917792 80.146766 +57.002278 80.205437 +57.067990 80.219518 +57.105539 80.278189 +56.936567 80.311045 +56.805144 80.332166 +56.767595 80.327473 +# -b +58.102944 80.456549 +57.962134 80.437774 +57.811937 80.433080 +57.558478 80.430734 +57.351957 80.433080 +57.220534 80.449508 +57.098499 80.435427 +57.201759 80.390837 +57.201759 80.357982 +57.314408 80.325126 +57.258083 80.261761 +57.220534 80.221865 +57.220534 80.170235 +57.107886 80.137379 +57.267471 80.102177 +57.408281 80.057587 +57.671126 80.050546 +57.765000 80.074015 +57.671126 80.135032 +57.689901 80.186663 +58.027845 80.224212 +58.271916 80.273496 +58.553536 80.287577 +58.778833 80.285230 +58.947805 80.266455 +59.116777 80.296964 +58.975967 80.334513 +58.675572 80.353288 +58.337628 80.395531 +58.149881 80.447161 +58.102944 80.456549 +# -b +59.227078 80.045853 +59.142592 80.024731 +58.804648 80.001263 +58.804648 80.001263 +# -b +59.656549 79.996569 +59.412478 80.031772 +59.224731 80.045853 +59.224731 80.045853 +# -b +60.097754 80.806227 +59.816134 80.803880 +59.684711 80.761637 +59.590838 80.728782 +59.543901 80.660723 +59.356154 80.599706 +59.252893 80.522260 +59.346767 80.458896 +59.496964 80.414306 +59.534514 80.381450 +59.759810 80.362675 +59.938169 80.376756 +59.938169 80.376756 +# -b +58.422114 81.787204 +58.365790 81.782511 +58.168656 81.803632 +57.924585 81.770776 +57.887035 81.723840 +57.877648 81.681597 +58.149881 81.632313 +58.469050 81.651088 +58.656797 81.655781 +58.891481 81.683943 +58.966579 81.735574 +58.872706 81.798938 +58.628635 81.782511 +58.422114 81.787204 +# -b +57.671126 81.531399 +57.455218 81.536093 +57.239309 81.524359 +56.985851 81.498544 +56.798104 81.463341 +56.704230 81.425792 +56.910752 81.416404 +57.117273 81.385895 +57.248696 81.395283 +57.473992 81.376508 +57.539704 81.360080 +57.755613 81.348346 +57.980909 81.360080 +58.187430 81.385895 +58.318853 81.397630 +58.337628 81.437526 +58.112331 81.463341 +57.877648 81.514971 +57.671126 81.531399 +57.671126 81.531399 +# -b +56.535258 81.369468 +56.366286 81.367121 +56.356899 81.331918 +56.413223 81.303756 +56.507096 81.273247 +56.403835 81.247432 +56.356899 81.216923 +56.225476 81.242738 +56.065891 81.235698 +55.896919 81.231004 +55.849982 81.249779 +55.671623 81.270901 +55.427552 81.259166 +55.436939 81.207536 +55.681010 81.179374 +55.925081 81.160599 +56.169152 81.177027 +56.234863 81.148865 +56.535258 81.160599 +56.525871 81.191108 +56.873203 81.209883 +57.060949 81.209883 +57.380119 81.233351 +57.567866 81.259166 +57.680514 81.259166 +57.793162 81.275594 +57.624190 81.310797 +57.502154 81.294369 +57.229921 81.310797 +56.948301 81.336612 +56.685456 81.374161 +56.535258 81.369468 +# -b +58.708428 80.853164 +58.745977 80.841430 +58.774139 80.782759 +58.558230 80.728782 +58.342321 80.726435 +58.117025 80.726435 +57.863567 80.754597 +57.854180 80.782759 +58.088863 80.822655 +58.285997 80.841430 +58.492519 80.853164 +58.680266 80.855511 +58.708428 80.853164 +# -b +56.105787 80.719394 +55.983752 80.702966 +55.730294 80.705313 +55.476836 80.677151 +55.533160 80.663070 +55.495610 80.637255 +55.551934 80.599706 +55.796005 80.592665 +56.162111 80.609093 +56.312309 80.592665 +56.603316 80.595012 +56.706577 80.602053 +56.922486 80.634908 +56.847387 80.679498 +56.762901 80.698273 +56.537605 80.719394 +56.302922 80.719394 +56.105787 80.719394 +# -b +54.606160 80.860204 +54.512286 80.853164 +54.108631 80.843777 +54.071081 80.815614 +54.052307 80.766331 +54.324540 80.766331 +54.559223 80.754597 +54.577998 80.707660 +54.784519 80.700620 +55.037977 80.717047 +55.282048 80.695926 +55.554281 80.731128 +55.798352 80.747556 +55.648155 80.787452 +55.432246 80.766331 +55.282048 80.792146 +55.300823 80.827349 +54.981653 80.806227 +55.000428 80.839083 +54.859618 80.848470 +54.606160 80.860204 +54.606160 80.860204 +# -b +55.864063 80.970506 +55.751415 80.986933 +55.469795 81.010402 +55.216337 81.024483 +54.934717 81.045604 +54.653096 81.043258 +54.531061 81.010402 +54.371476 80.968159 +54.531061 80.949384 +54.793907 80.932956 +55.000428 80.918875 +55.319598 80.918875 +55.394696 80.878979 +55.657542 80.881326 +55.788965 80.822655 +56.070585 80.787452 +56.417916 80.775718 +56.661987 80.768678 +56.708924 80.719394 +56.877896 80.719394 +56.887284 80.688885 +56.999932 80.660723 +57.131354 80.660723 +57.525623 80.691232 +57.619496 80.735822 +57.459911 80.775718 +57.178291 80.829696 +56.915446 80.871939 +56.690149 80.907141 +56.549339 80.909488 +56.286494 80.932956 +56.248944 80.979893 +55.929775 80.965812 +55.864063 80.970506 +# -b +56.821572 81.043258 +56.558727 81.045604 +56.370980 81.054992 +56.183233 81.076113 +56.202008 81.026830 +56.549339 80.972852 +56.821572 80.932956 +56.971770 80.911835 +57.337876 80.817961 +57.553785 80.810921 +57.769694 80.789799 +57.872954 80.825002 +57.966828 80.839083 +58.023152 80.871939 +57.816630 80.883673 +57.572559 80.937650 +57.253390 80.991627 +56.990544 81.024483 +56.821572 81.043258 +# -b +46.511925 80.860204 +46.098882 80.832042 +45.826650 80.801533 +45.667065 80.773371 +45.413607 80.747556 +45.272796 80.745209 +45.085050 80.724088 +44.859753 80.705313 +44.690781 80.710007 +44.465485 80.688885 +44.324675 80.656030 +44.334062 80.625521 +44.249576 80.609093 +44.212027 80.576237 +44.230802 80.552769 +44.268351 80.531647 +44.296513 80.503485 +44.521809 80.519913 +44.887916 80.515220 +45.122599 80.489404 +45.141374 80.447161 +45.300958 80.472977 +45.413607 80.487058 +45.554417 80.498792 +45.779713 80.491751 +45.948685 80.461242 +46.080108 80.409612 +46.145819 80.449508 +46.192756 80.465936 +46.089495 80.517566 +46.098882 80.552769 +45.911136 80.595012 +45.967460 80.660723 +46.155206 80.679498 +46.286629 80.691232 +46.333566 80.717047 +46.474376 80.752250 +46.690285 80.747556 +47.103328 80.754597 +47.591470 80.747556 +47.779216 80.691232 +47.948189 80.660723 +48.145323 80.646642 +48.370619 80.660723 +48.586528 80.651336 +48.896310 80.681845 +48.708563 80.717047 +48.464492 80.738169 +48.107773 80.778065 +47.835540 80.815614 +47.619632 80.825002 +47.384948 80.846123 +47.169039 80.839083 +46.990680 80.855511 +46.896806 80.834389 +46.577637 80.853164 +46.511925 80.860204 +# -b +50.062687 80.853164 +49.996976 80.853164 +# -b +50.006363 80.864898 +49.884327 80.867245 +49.630869 80.848470 +49.677806 80.834389 +49.687193 80.810921 +49.931264 80.806227 +49.931264 80.806227 +# -b +50.029831 80.731128 +49.795148 80.733475 +49.569852 80.731128 +49.466591 80.707660 +49.466591 80.681845 +49.335168 80.681845 +49.297619 80.651336 +49.231907 80.651336 +49.166196 80.639602 +49.278844 80.644296 +49.147421 80.641949 +48.912738 80.623174 +48.781315 80.606746 +48.593568 80.611440 +48.311948 80.585625 +48.152363 80.604399 +47.945842 80.625521 +47.851968 80.599706 +47.701771 80.609093 +47.382601 80.606746 +47.176080 80.637255 +46.950784 80.625521 +46.781811 80.611440 +46.669163 80.583278 +46.537741 80.531647 +46.622227 80.505832 +46.903847 80.519913 +46.978946 80.508179 +47.363827 80.477670 +47.316890 80.442468 +47.448313 80.421346 +47.579735 80.418999 +47.654834 80.369716 +47.457700 80.383797 +47.269953 80.379103 +47.063432 80.372063 +46.988333 80.339207 +46.875685 80.306351 +46.734875 80.301658 +46.697325 80.233599 +46.650389 80.207784 +46.809973 80.170235 +46.969558 80.163194 +46.960171 80.137379 +47.044657 80.120951 +47.288728 80.123298 +47.420151 80.144420 +47.682996 80.177275 +47.711158 80.132685 +47.805032 80.139726 +47.889518 80.088096 +47.701771 80.064627 +47.617285 80.005956 +47.617285 80.005956 +# -b +47.910639 79.989529 +47.995125 80.038812 +48.145323 80.043506 +48.304907 80.020037 +48.351844 80.057587 +48.304907 80.123298 +48.436330 80.104523 +48.652239 80.085749 +48.661626 80.132685 +48.821211 80.120951 +48.962021 80.160847 +48.896310 80.181969 +48.915085 80.221865 +48.924472 80.247680 +48.821211 80.292270 +48.624077 80.304004 +48.680401 80.341554 +48.943247 80.336860 +49.159155 80.322779 +49.346902 80.329820 +49.468938 80.329820 +49.562811 80.318085 +49.731783 80.332166 +49.910143 80.313392 +49.966467 80.318085 +# -b +50.083808 80.437774 +49.886674 80.458896 +49.971160 80.484711 +49.971160 80.484711 +# -b +33.463522 80.207784 +33.491684 80.196050 +33.416585 80.177275 +33.200677 80.167888 +32.947218 80.132685 +32.703148 80.120951 +32.430915 80.092789 +32.280717 80.076361 +32.092970 80.078708 +32.064808 80.074015 +32.008484 80.050546 +31.952160 80.038812 +31.698702 80.029425 +31.557892 80.036465 +31.435857 80.045853 +31.370145 80.064627 +31.445244 80.083402 +31.661153 80.095136 +31.933386 80.109217 +32.177456 80.127992 +32.374591 80.156154 +32.534175 80.167888 +32.759472 80.170235 +32.881507 80.191356 +32.975380 80.224212 +33.172515 80.224212 +33.416585 80.217172 +33.463522 80.207784 +# -b +22.778382 80.512873 +22.806544 80.498792 +23.031840 80.472977 +23.219587 80.454202 +23.200812 80.407265 +23.069389 80.381450 +23.163263 80.343901 +23.200812 80.306351 +23.163263 80.254721 +23.031840 80.217172 +22.966129 80.174929 +22.919192 80.139726 +23.013065 80.102177 +23.069389 80.102177 +23.153875 80.132685 +23.238361 80.142073 +23.285298 80.163194 +23.313460 80.132685 +23.379172 80.177275 +23.473045 80.142073 +23.473045 80.113911 +23.604468 80.116258 +23.642017 80.132685 +23.707728 80.153807 +23.698341 80.172582 +23.810989 80.191356 +23.726503 80.233599 +23.857926 80.233599 +23.735890 80.257068 +23.820377 80.254721 +24.017511 80.245334 +23.989349 80.273496 +24.064447 80.261761 +24.205258 80.242987 +24.120771 80.280536 +24.214645 80.271149 +24.421166 80.240640 +24.571364 80.245334 +24.693399 80.259415 +24.806047 80.315739 +24.834209 80.334513 +24.890533 80.301658 +24.862371 80.257068 +24.777885 80.217172 +24.618301 80.191356 +24.590138 80.151460 +24.486878 80.113911 +24.608913 80.137379 +24.759111 80.186663 +24.899921 80.207784 +25.012569 80.193703 +25.115830 80.228906 +25.350513 80.242987 +25.303576 80.233599 +25.256640 80.200744 +25.350513 80.170235 +25.444386 80.198397 +25.528873 80.186663 +25.613359 80.165541 +25.726007 80.191356 +25.791718 80.179622 +25.810493 80.170235 +25.782331 80.139726 +25.932528 80.146766 +26.026402 80.151460 +26.354958 80.151460 +26.599029 80.139726 +26.730452 80.139726 +26.824326 80.102177 +26.908812 80.074015 +26.955748 80.055240 +27.105946 80.062280 +27.134108 80.038812 +27.105946 80.005956 +# -b +19.955139 80.402572 +20.217985 80.418999 +20.321245 80.374409 +20.452668 80.329820 +20.462055 80.280536 +20.734288 80.289923 +20.734288 80.245334 +20.781225 80.210131 +20.846936 80.198397 +21.109782 80.196050 +21.288141 80.231253 +21.457114 80.228906 +21.644860 80.207784 +21.757508 80.252374 +21.907706 80.250027 +21.917093 80.196050 +21.710572 80.130339 +21.682410 80.116258 +21.907706 80.109217 +22.123615 80.010650 +22.123615 80.010650 +# -b +22.435744 79.991875 +22.323096 80.034118 +22.379420 80.074015 +22.360645 80.149113 +22.426356 80.247680 +22.445131 80.292270 +22.323096 80.318085 +22.379420 80.381450 +22.435744 80.400225 +22.548392 80.367369 +22.717364 80.329820 +22.801850 80.357982 +22.820625 80.421346 +22.792463 80.475323 +22.754913 80.505832 +22.783075 80.512873 +# -b +15.996028 79.998916 +16.305810 80.062280 +16.559269 80.017691 +16.559269 80.010650 +# -b +18.730091 79.989529 +18.880289 80.029425 +18.645605 80.012997 +18.495408 80.024731 +18.392147 80.034118 +18.317048 80.015344 +18.157463 80.045853 +18.082365 80.074015 +18.063590 80.102177 +17.950942 80.142073 +17.810132 80.139726 +17.650547 80.132685 +17.622385 80.160847 +17.913393 80.179622 +18.101139 80.174929 +18.317048 80.167888 +18.561119 80.144420 +18.720704 80.186663 +18.908451 80.163194 +18.983549 80.118604 +19.161909 80.066974 +19.359043 80.001263 +19.405980 80.052893 +19.387205 80.081055 +19.462304 80.095136 +19.387205 80.132685 +19.565564 80.116258 +19.565564 80.146766 +19.330881 80.163194 +19.133747 80.198397 +19.039873 80.228906 +19.096197 80.271149 +19.086810 80.313392 +19.124359 80.332166 +19.340268 80.275842 +19.481078 80.210131 +19.659438 80.207784 +19.828410 80.177275 +19.856572 80.200744 +19.828410 80.221865 +19.734537 80.252374 +19.828410 80.301658 +19.828410 80.325126 +19.790861 80.327473 +19.762699 80.348594 +19.865959 80.383797 +19.715762 80.393184 +19.640663 80.383797 +19.574952 80.383797 +19.490466 80.393184 +19.490466 80.454202 +19.603114 80.451855 +19.668825 80.487058 +19.743924 80.515220 +19.959833 80.465936 +19.959833 80.402572 +19.959833 80.402572 diff --git a/demo/demo.py b/demo/demo.py new file mode 100755 index 00000000..99f75a1a --- /dev/null +++ b/demo/demo.py @@ -0,0 +1,4 @@ +#!/usr/bin/env python + +import Main +Main.main() diff --git a/demo/dllwidget/Makefile b/demo/dllwidget/Makefile new file mode 100644 index 00000000..bcf3a564 --- /dev/null +++ b/demo/dllwidget/Makefile @@ -0,0 +1,16 @@ + +CXX = c++ +CXXFLAGS = `wx-config --cxxflags` -fPIC -I. +LDFLAGS = `wx-config --libs` + + +all: test_dll.so + +test_dll.so: test_dll.o + $(CXX) $(LDFLAGS) -shared -o $@ $< + +%.o : %.cpp + $(CXX) -c $(CXXFLAGS) -o $@ $< + +clean: + rm -f *.o *.so diff --git a/demo/dllwidget/makefile.vc b/demo/dllwidget/makefile.vc new file mode 100644 index 00000000..e12c0d34 --- /dev/null +++ b/demo/dllwidget/makefile.vc @@ -0,0 +1,32 @@ + +WXDIR = $(WXWIN) +WXUSINGDLL = 1 + +PROGRAM = test_dll +OBJECTS = test_dll.obj + +!include $(WXDIR)\src\makevc.env + + +$(PROGRAM).dll : $(OBJECTS) + $(link) @<< +-out:$(PROGRAM).dll +-dll $(LINK_DEBUG_FLAGS) $(WINLINKFLAGS) +$(OBJECTS) +$(WXLIB) +<< + + +clean: + del $(OBJECTS) + del $(PROGRAM).dll + del $(PROGRAM).exp + del $(PROGRAM).lib + del $(PROGRAM).pdb + +test: + @echo -out:$(PROGRAM).dll + @echo -dll $(LINK_DEBUG_FLAGS) $(WINLINKFLAGS) + @echo $(OBJECTS) + @echo $(WXLIB) + diff --git a/demo/dllwidget/test_dll.cpp b/demo/dllwidget/test_dll.cpp new file mode 100644 index 00000000..4790351d --- /dev/null +++ b/demo/dllwidget/test_dll.cpp @@ -0,0 +1,54 @@ + +#include +#include +#include + +#include "../../contrib/dllwidget/dllwidget.h" + +class TestWindow : public wxWindow +{ +public: + TestWindow(wxWindow *parent, long style) + : wxWindow(parent, wxID_ANY) + { + SetBackgroundColour(wxColour("white")); + } + + int HandleCommand(int cmd, const wxString& param) + { + if (cmd == 1) + { + SetBackgroundColour(wxColour("red")); + Refresh(); + } + + if (cmd == 2) + { + SetBackgroundColour(wxColour(param)); + Refresh(); + } + + else if (cmd == 3) + { + wxMessageBox("Message from embedded widget:\n\n" + param); + } + + return 0; + } +private: + DECLARE_ABSTRACT_CLASS(TestWindow) +}; + +IMPLEMENT_ABSTRACT_CLASS(TestWindow, wxWindow) + + +//DECLARE_DLL_WIDGET(TestWindow) +static int SendCommandToTestWindow(wxWindow *wnd, int cmd, const wxString& param) +{ + return wxStaticCast(wnd, TestWindow)->HandleCommand(cmd, param); +} + + +BEGIN_WIDGET_LIBRARY() + REGISTER_WIDGET(TestWindow) +END_WIDGET_LIBRARY() diff --git a/demo/dllwidget/test_prog.py b/demo/dllwidget/test_prog.py new file mode 100644 index 00000000..bd54f16c --- /dev/null +++ b/demo/dllwidget/test_prog.py @@ -0,0 +1,84 @@ +#!/usr/bin/env python + +from wxPython.wx import * +from wxPython.dllwidget import wxDllWidget, wxDllWidget_GetDllExt + +#---------------------------------------------------------------------- + +class TestFrame(wxFrame): + def __init__(self): + wxFrame.__init__(self, None, -1, "Test wxDllWidget") + + menu = wxMenu() + menu.Append(101, "Send command &1") + menu.Append(102, "Send command &2") + menu.Append(103, "Send command &3") + menu.AppendSeparator() + menu.Append(110, "E&xit") + + mb = wxMenuBar() + mb.Append(menu, "&Test") + self.SetMenuBar(mb) + + EVT_MENU_RANGE(self, 101, 109, self.OnSendCommand) + EVT_MENU(self, 110, self.OnExit) + + panel = wxPanel(self, -1) + panel.SetFont(wxFont(12, wxSWISS, wxNORMAL, wxBOLD)) + + st = wxStaticText(panel, -1, + "The widget below was dynamically imported from\n" + "test_dll.dll or test_dll.so with no prior knowledge\n" + "of it's contents or structure by wxPython.") + + self.dw = dw = wxDllWidget(panel, -1, + "test_dll" + wxDllWidget_GetDllExt(), + "TestWindow", + size=(250, 150)) + + if dw.Ok(): + # The embedded window is the one exported from the DLL + print dw.GetWidgetWindow().GetClassName() + + # This shows that we can give it a child from this side of things. + # You can also call any wxWindow methods on it too. + wxStaticText(dw.GetWidgetWindow(), -1, + "Loaded from test_dll...", pos=(10,10)) + else: + wxStaticText(dw, -1, "ERROR!!!!", pos=(20,20)) + + sizer = wxBoxSizer(wxVERTICAL) + sizer.Add(wxStaticLine(panel, -1), 0, wxGROW) + sizer.Add(st, 0, wxGROW|wxALL, 5) + sizer.Add(dw, 1, wxGROW|wxALL, 5) + + panel.SetSizer(sizer) + panel.SetAutoLayout(true) + sizer.Fit(self) + sizer.SetSizeHints(self) + + + def OnExit(self, evt): + self.Close() + + + def OnSendCommand(self, evt): + ID = evt.GetId() - 100 # use the menu ID as the command + param = "" + if ID == 2: + dlg = wxTextEntryDialog(self, "Enter a colour name to pass to the embedded widget:") + if dlg.ShowModal() == wxID_OK: + param = dlg.GetValue() + dlg.Destroy() + self.dw.SendCommand(ID, param) + + + +#---------------------------------------------------------------------- + + +if __name__ == "__main__": + app = wxPySimpleApp() + frame = TestFrame() + frame.Show(true) + app.MainLoop() diff --git a/demo/encode_bitmaps.py b/demo/encode_bitmaps.py new file mode 100644 index 00000000..5be7ffbb --- /dev/null +++ b/demo/encode_bitmaps.py @@ -0,0 +1,180 @@ + +""" +This is a way to save the startup time when running img2py on lots of +files... +""" + +import sys +from wx.tools import img2py + + +command_lines = [ + " -F -i -n Mondrian bmp_source/mondrian.ico images.py", + "-a -F -n Background bmp_source/backgrnd.png images.py", + "-a -F -n TestStar -m #FFFFFF bmp_source/teststar.png images.py", + "-a -F -n TestStar2 bmp_source/teststar.png images.py", + "-a -F -n TestMask bmp_source/testmask.bmp images.py", + + "-a -F -n Test2 bmp_source/test2.bmp images.py", + "-a -F -n Test2m -m #0000FF bmp_source/test2.bmp images.py", + "-a -F -n Robin bmp_source/robin.jpg images.py", + + "-a -F -n Bulb1 bmp_source/bulb1.bmp images.py", + "-a -F -n Bulb2 bmp_source/bulb2.bmp images.py", + + "-a -F -n DbDec bmp_source/DbDec.bmp images.py", + "-a -F -n Dec bmp_source/Dec.bmp images.py", + "-a -F -n Pt bmp_source/Pt.bmp images.py", + "-a -F -n DbInc bmp_source/DbInc.bmp images.py", + "-a -F -n Inc bmp_source/Inc.bmp images.py", + + "-a -F -n Tog1 -m #C0C0C0 bmp_source/tog1.bmp images.py", + "-a -F -n Tog2 -m #C0C0C0 bmp_source/tog2.bmp images.py", + + "-a -F -n Smiles -m #FFFFFF bmp_source/smiles2.bmp images.py", + + "-a -F -n GridBG bmp_source/GridBG.gif images.py", + + "-a -F -n SmallUpArrow -m #0000FF bmp_source/sm_up.bmp images.py", + "-a -F -n SmallDnArrow -m #0000FF bmp_source/sm_down.bmp images.py", + + "-a -F -n NoIcon bmp_source/noicon.png images.py", + + "-a -F -n WizTest1 bmp_source/wiztest1.bmp images.py", + "-a -F -n WizTest2 bmp_source/wiztest2.bmp images.py", + + "-a -F -n Vippi bmp_source/Vippi.png images.py", + + "-a -F -n LB01 bmp_source/LB01.png images.py", + "-a -F -n LB02 bmp_source/LB02.png images.py", + "-a -F -n LB03 bmp_source/LB03.png images.py", + "-a -F -n LB04 bmp_source/LB04.png images.py", + "-a -F -n LB05 bmp_source/LB05.png images.py", + "-a -F -n LB06 bmp_source/LB06.png images.py", + "-a -F -n LB07 bmp_source/LB07.png images.py", + "-a -F -n LB08 bmp_source/LB08.png images.py", + "-a -F -n LB09 bmp_source/LB09.png images.py", + "-a -F -n LB10 bmp_source/LB10.png images.py", + "-a -F -n LB11 bmp_source/LB11.png images.py", + "-a -F -n LB12 bmp_source/LB12.png images.py", + + "-a -F -n FloatCanvas bmp_source/floatcanvas.png images.py", + "-a -F -n TheKid bmp_source/thekid.png images.py", + + "-a -F -n Carrot bmp_source/carrot.png images.py", + "-a -F -n Pointy bmp_source/pointy.png images.py", + "-a -F -n Pencil bmp_source/pencil.png images.py", + + "-a -F -i -n WXPdemo bmp_source/wxpdemo.ico images.py", + + "-a -F -n _rt_alignleft bmp_source/rt_alignleft.xpm images.py", + "-a -F -n _rt_alignright bmp_source/rt_alignright.xpm images.py", + "-a -F -n _rt_bold bmp_source/rt_bold.xpm images.py", + "-a -F -n _rt_centre bmp_source/rt_centre.xpm images.py", + "-a -F -n _rt_colour bmp_source/rt_colour.xpm images.py", + "-a -F -n _rt_copy bmp_source/rt_copy.xpm images.py", + "-a -F -n _rt_cut bmp_source/rt_cut.xpm images.py", + "-a -F -n _rt_font bmp_source/rt_font.xpm images.py", + "-a -F -n _rt_idea bmp_source/rt_idea.xpm images.py", + "-a -F -n _rt_indentless bmp_source/rt_indentless.xpm images.py", + "-a -F -n _rt_indentmore bmp_source/rt_indentmore.xpm images.py", + "-a -F -n _rt_italic bmp_source/rt_italic.xpm images.py", + "-a -F -n _rt_open bmp_source/rt_open.xpm images.py", + "-a -F -n _rt_paste bmp_source/rt_paste.xpm images.py", + "-a -F -n _rt_redo bmp_source/rt_redo.xpm images.py", + "-a -F -n _rt_sample bmp_source/rt_sample.xpm images.py", + "-a -F -n _rt_save bmp_source/rt_save.xpm images.py", + "-a -F -n _rt_smiley bmp_source/rt_smiley.xpm images.py", + "-a -F -n _rt_underline bmp_source/rt_underline.xpm images.py", + "-a -F -n _rt_undo bmp_source/rt_undo.xpm images.py", + "-a -F -n _rt_zebra bmp_source/rt_zebra.xpm images.py", + + "-a -F -n _bp_btn1 bmp_source/bp_btn1.png images.py", + "-a -F -n _bp_btn2 bmp_source/bp_btn2.png images.py", + "-a -F -n _bp_btn3 bmp_source/bp_btn3.png images.py", + "-a -F -n _bp_btn4 bmp_source/bp_btn4.png images.py", + + "-a -F -n _book_red bmp_source/book_red.png images.py", + "-a -F -n _book_green bmp_source/book_green.png images.py", + "-a -F -n _book_blue bmp_source/book_blue.png images.py", + + "-a -F -c bmp_source/book.png images.py", + "-a -F -c bmp_source/clipboard.png images.py", + "-a -F -c bmp_source/code.png images.py", + "-a -F -c bmp_source/core.png images.py", + "-a -F -c bmp_source/custom.png images.py", + "-a -F -c bmp_source/deleteperspective.png images.py", + "-a -F -c bmp_source/demo.png images.py", + "-a -F -c bmp_source/dialog.png images.py", + "-a -F -c bmp_source/exit.png images.py", + "-a -F -c bmp_source/expansion.png images.py", + "-a -F -c bmp_source/find.png images.py", + "-a -F -c bmp_source/findnext.png images.py", + "-a -F -c bmp_source/frame.png images.py", + "-a -F -c bmp_source/images.png images.py", + "-a -F -c bmp_source/inspect.png images.py", + "-a -F -c bmp_source/layout.png images.py", + "-a -F -c bmp_source/miscellaneous.png images.py", + "-a -F -c bmp_source/modifiedexists.png images.py", + "-a -F -c bmp_source/morecontrols.png images.py", + "-a -F -c bmp_source/moredialog.png images.py", + "-a -F -c bmp_source/overview.png images.py", + "-a -F -c bmp_source/process.png images.py", + "-a -F -c bmp_source/pyshell.png images.py", + "-a -F -c bmp_source/recent.png images.py", + "-a -F -c bmp_source/saveperspective.png images.py", + "-a -F -c bmp_source/customcontrol.png images.py", + + "-a -F -c bmp_source/deletedocs.png images.py", + + "-a -F -c -n spinning_nb0 bmp_source/FRM_0.png images.py", + "-a -F -c -n spinning_nb1 bmp_source/FRM_1.png images.py", + "-a -F -c -n spinning_nb2 bmp_source/FRM_2.png images.py", + "-a -F -c -n spinning_nb3 bmp_source/FRM_3.png images.py", + "-a -F -c -n spinning_nb4 bmp_source/FRM_4.png images.py", + "-a -F -c -n spinning_nb5 bmp_source/FRM_5.png images.py", + "-a -F -c -n spinning_nb6 bmp_source/FRM_6.png images.py", + "-a -F -c -n spinning_nb7 bmp_source/FRM_7.png images.py", + "-a -F -c -n spinning_nb8 bmp_source/FRM_8.png images.py", + + " -F -c bmp_source/001.png throbImages.py", + "-a -F -c bmp_source/002.png throbImages.py", + "-a -F -c bmp_source/003.png throbImages.py", + "-a -F -c bmp_source/004.png throbImages.py", + "-a -F -c bmp_source/005.png throbImages.py", + "-a -F -c bmp_source/006.png throbImages.py", + "-a -F -c bmp_source/007.png throbImages.py", + "-a -F -c bmp_source/008.png throbImages.py", + "-a -F -c bmp_source/009.png throbImages.py", + "-a -F -c bmp_source/010.png throbImages.py", + "-a -F -c bmp_source/011.png throbImages.py", + "-a -F -c bmp_source/012.png throbImages.py", + "-a -F -c bmp_source/013.png throbImages.py", + "-a -F -c bmp_source/014.png throbImages.py", + "-a -F -c bmp_source/015.png throbImages.py", + "-a -F -c bmp_source/016.png throbImages.py", + "-a -F -c bmp_source/017.png throbImages.py", + "-a -F -c bmp_source/018.png throbImages.py", + "-a -F -c bmp_source/019.png throbImages.py", + "-a -F -c bmp_source/020.png throbImages.py", + "-a -F -c bmp_source/021.png throbImages.py", + "-a -F -c bmp_source/022.png throbImages.py", + "-a -F -c bmp_source/023.png throbImages.py", + "-a -F -c bmp_source/024.png throbImages.py", + "-a -F -c bmp_source/025.png throbImages.py", + "-a -F -c bmp_source/026.png throbImages.py", + "-a -F -c bmp_source/027.png throbImages.py", + "-a -F -c bmp_source/028.png throbImages.py", + "-a -F -c bmp_source/029.png throbImages.py", + "-a -F -c bmp_source/030.png throbImages.py", + + "-a -F -c bmp_source/logo.png throbImages.py", + "-a -F -c bmp_source/rest.png throbImages.py", + ] + + +if __name__ == "__main__": + for line in command_lines: + args = line.split() + img2py.main(args) + diff --git a/demo/images.py b/demo/images.py new file mode 100644 index 00000000..9f93f5b8 --- /dev/null +++ b/demo/images.py @@ -0,0 +1,6812 @@ +#---------------------------------------------------------------------- +# This file was generated by encode_bitmaps.py +# +from wx.lib.embeddedimage import PyEmbeddedImage + +Mondrian = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAHFJ" + "REFUWIXt1jsKgDAQRdF7xY25cpcWC60kioI6Fm/ahHBCMh+BRmGMnAgEWnvPpzK8dvrFCCCA" + "coD8og4c5Lr6WB3Q3l1TBwLYPuF3YS1gn1HphgEEEABcKERrGy0E3B0HFJg7C1N/f/kTBBBA" + "+Vi+AMkgFEvBPD17AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Background = PyEmbeddedImage( + "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" + "ndTk/wDWjbRY8zgTJQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +TestStar = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAYAAACOEfKtAAAABHNCSVQICAgIfAhkiAAAChNJ" + "REFUeJztm22sHFUZx//PmdndCx80SsG0tJWAEhuaQiktLZTypiGKsVQsUAqU9t5bevsKDWl8" + "SZT4CkGqtL1aQpSIiYlG4xc1avBLY2kgogE1FhVQAbFVEaPs7syc53n8cM7Mzu7dIu3uzh3I" + "PsnJOTM7yZ397f95Oc/MJTIBhnbiZqb7Bt7oNgTYow0B9mhDgD3aEGCPNgTYow0B9mhDgD3a" + "EGCPNgTYow0B9mhDgD1aON038Fp29PEdigBACJx27v003ffTzUqrwKOHtitIMePwbnf82x06" + "zbfU1UoLkEgx48kvAQLM+P3u6b6dY1ppAQIA9JgHpbHSAqQOYERDgK/b/nFoi8IokE8bBPz9" + "6W2lo1hKgETA2x/f03bulGe+DJRQhaUECMoNg5YSS1jIlA7gPw9tVgTq7iyFl4N49NmtpZJh" + "6QASAW87uHcqPAOc8vz9pcvFpQOIAC1oKcAcxLJl49IBpBSa38JlAD1YLdkdl+p2XvnFhFIK" + "LlVifvh3AP72/JbSyLBUAImAtzy614FKQabDAz315T2lioPlAphXXzry6svHx5JYqQC2qa7S" + "cZyHS8CLL5ajnCkNwP/8ekLJoB1eBVMVGQLviPZASqLCvjRUm49s0kwO/idRaq0ztwty5/3Q" + "gLLPTn5sH1DDVAV2ggxdvHzuha1qhZAAsAIkYsB+tkqw4kaiAItBokDCBBYDMjUkYiBCsGrA" + "EkDEQDTEtuU7X/fP0xeAFADV703mTqBVw3Wop81FQwBVv67m1pWOa7q49anYgwYIDSU0rBsx" + "G0R+XWeTnW+wQZ3T6wxe9XOdgQYbNG0Ia0eQ2BGsmrfxuL57fwBWAIx0nOyo36ZA7Aaw0mWE" + "ubV3aw2AxBKsAJYJiRCsGKc49UPQWrcdA5wOIbAQVAOoGnx43hjkOCNrX2IgBQBfu8VBHAFw" + "ElrrKpxb1vxxuq7m5mPBy4PLQU/EQYuFkGjLTZ0bw51TAouDZAVgJb8mt1aA4WYRg2vecxsU" + "ih2X3HFc0bUvACvL9hNCgFduaYeUQkvPVTs+ywPsBjLsWIcAEyFmcqAESBgtiB6QZQ8zU58f" + "CqdAr0YWgkiAlWdPQBXYvvzO405NfcvClcX7CRWAr84psRvMTvXlIb4W0Kpz3Vi8ApVyc6q8" + "HLg0gYiDloj7jDM3d+c/9O5tUBhsvXjXCeV16vc70slTmxQEBAcm2zsqQcfoliDyIw/QryMh" + "NJkQsUsMDSZEDDSsQZMNGtma0GCXKNzskwUb1C3QtAaXnbkdzC77Tiz72AkXRX0HCADJ7zYp" + "AASHJrMSZUoi6ZZQ8vDyMGtArA5ckwlNa9AUoMkGTetnn1EbTA6mz8AtmK2MvHTORhg6CeNL" + "PtlzNTmQQroyz8fEFV1i4rESyrHiYNW5ZCwOYMxArM6NYwZiMYjFzQm7Oi9mFxtt6tZpplaD" + "i+aOQ5X6Ag8YkAJTS57z7vzk5FQVdtaF3ZRYARIAkRhETIgsIRKnqKZfNy2h6V07VaRz1/S6" + "lmsvnr0RVggbL/xC3/YxAwUIAMmfN6kSED492T0Wdtu6eXixurgXW0IkJot/EbegRSlAm0L0" + "LswtuA1rcP6sMVg1GF9yd183gQMHCADRC06Jlecmp8bBLrFQQ5c1I2sQaQrNuWnE8CBbQPPg" + "omx3gSweLjx9HCyEDYvv6fsOuhCAANB8ySWW6kuTXRsE7XUeEPtCOY19kbj6L1VfqsS8AiNx" + "iSK95pyZ47BswEK4dQDwgAIBAkDjyCZVIoz8a98UgGpyOwwllwwEbeA616nyYiY0GG2qPGfm" + "OBIh3HT+vQPt2xQKEAD+e3RCAeDkyEFUg2yvGue2aOlxxF6JTIgkl1D8cWy96wqyEmf+LAfv" + "xoWDhQdMA0AA+PfRCVUljMg+137yAFMFJpn7AnEOYCxOZVHnzK0Ce/7MMVgh3LDwi4V0DKel" + "ofrW075KVtEqbn2Bm+0c2hJDe5JoMnLubHxt6Mb8WWNgLQ4eME1vqB7562ZNfHmSbzcl0u7K" + "eSUmXnGpGpucSzAMRAKIEK4/rzh4wDQBZCHE8VfAWQ8v3fBT1llO8jHR7yTyACPxI+faKsV/" + "l2lx4YQJdesypxvpcb4BkCuOxV3X5PaCObJeff4aJoOHn9hV6MOmwgE+86etauFb6kmAujUe" + "lkEzMVkR3LabsGn8a4+JLhYaX0ATfvzHr0O02KdNhbuwFcLLr+4Hw7mraNpNTrvFvjHQkZWT" + "NCuLqxGjnCvHjGyWgh/XFQ6QGaizb6mnbXdNuyUpSLQapuwAJwLEbLKGagowSyp+loJfninc" + "hTvLl7ofTZuLf76f1+qo+HOSNgpaxXTenRMOoDB44NCnCouDhQL81eHtaoV83AscOB/r6m2N" + "T0xpiDZtewJp2PZ6MeEKLNfw7d98B6rFbQ4KdeFECE+/8iBYCaIAq2k94FHkHgD5ZxhKWDZ7" + "FALgp88+1HoSl7quj43MFVipQKQC5mqhiaRQBTK3XLZujZu9u6bZ2KnPuenSWaP+OS7hsjPG" + "2ksbBmIOkNgqLFchtga2NTBXoRpi74G7C3HjwgD+/Knb1QIelMmA1W0r5tX9+ToTlp++AYkS" + "Vi7YTdcsuI9YgPefNdrmsglXwVyD5RosO5DWVvHwEz8qzI0LA2gVOHjka/61i/bXL+oWLQUy" + "4ZLZG2DVYNV592W+eN3Ce4mVsOrsUViuIeERr7ga2FYziCwOpBaUjQsDmDDwqjWos0E98e7r" + "C+d6+tyCCVfM2QAWg1VdGgJrF91DqiGun3cr2NY8yBqsONdlrsFaB/HNp0Dxakso67jU0y2c" + "JVwxZxRXzhmFZYOPLDp2H++WxZ8lkQBr56/J1Mc+DnKHAu97ZN/A42AhAH/w2E61giy+ub2v" + "8bUf4aq5o2AmrL7gXlq9+P83QTcsvYtEQ9xy7rVZDHQKrIC5AuEQDzx6EFKACgsBmCjw/b98" + "IwOYZWImfGDOBlgBrltyfN3j8Ys+TioB1i/6YJvy3LoClkoh/xlWCEAr6ft58PHPHa+c65LF" + "DReeWOv9tkt2kWqIsQuuwtgF74X4WjAdigD3/OTBgWIsBCALZeAa1qBhQ6x+5xhYQqxd1tvT" + "ss0r7qCtl99OqgFuW3oZWEKvwBB7D/wSOuCvOHCA3zrwURUJkHANiR2BtSNYc8Z6CBNuuvjz" + "fdsy7LhyKwkIExddDOEQIiFEK1AZbBwcOEBhg4f+8F0kSQ1rzliHG8+8BSIhbl7RP3ip7bxy" + "ghQGm5cvAUsI4QA64G3dwAFaDZDYEdx01lqIBlh36Wdo3aWfHti3uvN94wQE2LZiEUQrGPRX" + "HDhAlRDr3rUaKgbrL7+rkF3+rqvWkyph24oF2P2zwwP9W9PyXLhI+9wPv6mfuPrmgf1wb3qA" + "g7bS/KfSG9WGAHu0IcAebQiwRxsC7NGGAHu0IcAebQiwRxsC7NH+B9lU5vQMoztoAAAAAElF" + "TkSuQmCC") + +#---------------------------------------------------------------------- +TestStar2 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAIAAAABc2X6AAAAA3NCSVQICAjb4U/gAAAJSElE" + "QVR4nO2ba4xdVRXH/2ufc+4dSDRRSgyFIgFtJC0F2lJLqU2DJMQXFQpoedOZ4TlTakE+GKJG" + "RcQHaDtjMESJxhg1Gr+hMRoSkmJsRCURw0sJYKxgAaPpee318MM+5947U5AyPfcUh1k5udl3" + "7vTc9Zv/Wmuvte8tmRneTOYOtwNt2wLwfLcF4PluC8Dz3RaA57stAM93e9MBx4flXfc9fDMi" + "IMai5V9r+a0Pg8L79uwA2aLH7gKw77GbW373wwBMZIseuRuKRU/c1f67H6YctldYtWOHQ+EB" + "SKL5DvzSnpvgDFQ/J7z41CfadKBtYCK8fc/O3tOj/vJ1tCty6yFN9eVQ6Uyv8S+atVaBX96z" + "DZHB1bQ1875ntrfmQ6vARHjb7l0zaB2Oeu4bbcZ0uyEd1ZwBuGZus1a3rTAcQlNZAUeAg7Xo" + "RXtv9e8/TFJAjWraHjPwwt9vaseN9oCJ8NaHdiGqFY778Ee/tLO1mG4RuCdvNCByNJDYrViL" + "2dMTNhlY9/4KhL3/aGNzagl4/58nyQ3QJjPVjvGOYqe2IvJcDgDKByaqlHMAYFT/3UJkRvVP" + "HOBgEYFAMY787RS6MxUexI5BhGf2bmclD7DCqxOFV8dGrMRK3iDqvMELiTpyXa9OldicaKTq" + "1OIbz9zWPDBF6Px0un5Sb6oDcvVDNwY6QAJ06kUy8NLMCD8aOzNQZpQxZUyluIIpY0rFhZ9k" + "4lIJr7r9TBm7VJCJyzlmHvE8cv7J17ym83MCToCRgecDO+oM5lnAycwrrhcRkMAieCZWsJBX" + "YnWsxEZsxIpq0V9DwqUkSmaRmbvg5DE9iFo/lxymCLL5RowAI8ARqBYdoAt0gZF60akfD6RN" + "Zge2V/JKpZK3KnpZ4RXeiI1EIUqsECNRYiUxEoOAxKDqPvqeaw02uW5yKMDRminEkE039tm6" + "NXZ3gLw7ADwLOx5YxBCiUsgHQkHFrMRKLOAaO2QyG9ggCjYSJdVo09LrzTBx5kEV+TlW6Wjl" + "FBLIh2qdZ5EPyttjfkX4DixCqfBK3qh+DNrWqKFiKdjgFRzUtor8vHdPGtwNa3ccpOd0KN/x" + "kEcnQIgenO4PQNHANasyJX3IwUpWKOVChVAmLhMqBBm7XFxWLSgTythlQhkjE5eLSxk5u40n" + "bhNxotG1az558D4fEjAAeWICQPSb6bAhzahbs6pXckD16qI0KoRyoZxdrsjF5YxcXC4I/Hld" + "omvyqlyvXXKNoyNGV33q9Tp8qI1HtHQKMWTDzHw+sHodmMYdeKNSqRAqBaXBK5WCUl2pKNV5" + "gRcqBb5K47qAm1t3/LgZzYEWh65wMHl2AoTokekZIg/uybN0TuCBQl0hVDAVSplQzlQo5Uy5" + "Ui4U1M6kiuqcqyA/47hrWGls9efn5mozwADkbxNGiB+fnp3Js9rJBEhQGgqlkqlQFxK4kIqz" + "CMAcmCkPgc2UK2XsVi4eY3Ojq74wZz8bAwbg906AkDw9PSONZ2ayxfCKgl1hgROlukKQCxVS" + "wfdQi6qRQkjm048dF6WrVt5+KE42CQygfGECQGfv9KzZYGC/RakUrkKoUCpreYPOPYULpYyr" + "l5YdM87iROmKQ6NF48AAin0TRjTy8tQgsLm6lzLyQqWihzq4CNqWQpmgJ/iyY8a90iWn3tGI" + "e80DA0hfnARwZDGFCOYQeuCybh7DuhAqA6rW1UuoUJRMubhCEfaq5YvHvdLHVzRDiyEBA/jP" + "i5NmNKJTUnVLlcK+imeUNXCpKMQVg49StSLLjxljpYtXfKlBx4Z1APCWo3axoeoTmDJxVbfU" + "r0n94pQL6th2hVApVAotXzwm1jAthvcNgH8+v01BJffHOq/9wO7p7MUViiB1LnUlExQKVbro" + "lIZpMTxgUSrLb0o11oa+P2A738tnIa/UAy6Uiiq3UYgzHYpjwwppL5QyZYJMkFXr3gxQ9xWK" + "TEJxqsK7YCoEhVCuEHLf/+Ncmsf/bUMBfvq57QzK2KU+StllTDm73Lusng2q5olDAvfzuZDQ" + "e7lC6BdPfUet+XO9oYQ0K720/x4BsUItHF+EYwqU6vxAxfahYiv53oasVErYpaFDOMgcCrAI" + "UiGxcCIDsTDlBGxUg76QN3hFKS4cABTVLkWlUK5UCukQPnQaSkgPbkgpU8qUc53A4nrDbR62" + "Kw0TQtV79GLbS2Rw9+6Z41T0atY88CNP7mCllF3GUcrVuJP2x3cMDvQ59ytWxv1d2kvC0v3R" + "n35sFjXrXvMh7ZUe/9e9YqQGMVedthnqUzh4BRudedyoAr/8633VYaVUE4VXEklYE9VEpNN4" + "3WpeYZEqjFN2aX2MHmp1xsjYZeLWLh5lgxhtPGGsv0sJSok8d1g6yl3hrkjHLJ7e/dUG3WsY" + "+KFHb2EgZZexC5Bp1VcGfpcKrT92qzf6yLIvn7fsTlF84KTRXhh76Yh0WbosHZYOc+d7D9/f" + "bFQ3DMyG3c9/O2MKn4nU8qJSWOh9x21lc5tOuTP8/oUr7hCj85eOsnS9jAh3RbrCncAs2mHp" + "WKO1umFgL9jPLhWXepcypd5l4tJwHCV09pKtom7TzHlgy2m3m8UfO/kq4S5L10uXtStBau6I" + "dt7YCqvLmFJPYTBKQ1PJdPaS0fcvGWVxF5z2CpPtZSs/qxpdunxLkFe4w9KRAYXvfuCepjxs" + "Evj+393KipComVDKLmfKmM49flSENp9+x+aVrzrHX3XGbWrxFaduDjks0hFJRBKV+FsP7dbm" + "RG4S2Bt+9ux3A3BVqIU+uGQrKy5c9dpHFqPvvdU0unrVh3vainREE9Gkwa81NQnMGj6/Reqr" + "grzp+K1s7uLVB3tAM75uh1k8tvrcsdXnqCa9yxB95Vf3NeJkk8CiFFAzdhnHF71zTDTesub1" + "nTNed9bkDRsmzKJr124UjUUT0XjXg7+3hlxtDPiHu29Tjbx0PY8wj2w54WoVumTt5+Z2t8mN" + "1yno+nVnqcSqsVpi2kwaNwas4u578ifed7eccOUlJ16hGl961hxpg23fOG5wN6xfIxqrRNZQ" + "j9kYMFvkeeSyky5Viy5f/5nL13/60O+54+yrgWhywyq1pClXGwM2ja9810Wm7soNtzV1TwC3" + "nHO5GU1uWHHXrx9r5o72f2Jf/PkPGrnPsA7i37D2pvuveAvA890WgOe7LQDPd1sAnu/2XyhV" + "zwAumKtrAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +TestMask = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAFAAAABQCAIAAAABc2X6AAAAA3NCSVQICAjb4U/gAAADgElE" + "QVR4nNVcyXYEIQhs8+b/f9kcJjGODchSYKeOPYriwlKYtN779YvW2qXA3OUOiJA8vI6Mel1X" + "aw2r87LQnPAG32G9HKW0LYTh7sK/goNF0HtP1Zb89ZjCj7jDvfftacybqPISCl24NrMoj9Fy" + "zGzB0oWc9/sjfH3XI+0wSK21+aPJYm3bW6VtQdxhUmf9QvRPxKeIhXSkIdN9C+E2ynEJg9De" + "4eDMNObQAY0tWNqwbin1NGYof+kcO6Fw3mwyxMoDPSjSSlrWAW63T4aWeXmV0EWrsGbUgkMb" + "PxeswtlHTomxiEt44wbrlu7bJbsWbM4Y7CWAVXiOnMZHOYqQMe+Vo7sV8ygfOb+SACA3MCm/" + "uXYr6ztN714vudH8a2VgfJ8MhCrovcM4rbzlsEqWd+5L00jfBg6TtltL3lo7xlqiYN0Gf6RV" + "sOEZ0U51aHmcEnAqTBI93E8Lzur8GpNQTlRopj/kkQAmAqRbmoVaW1ZqTkRaJG8ikynzAfGd" + "2GBQpVm7n2MFuVFc4OqTMAMijY2l3XAofO+C1ZmD7Q7Haw6CWM1V0oiSu4SMFjdRazbjo/59" + "AAQeQRtb7JYxbmlx4/Imo5wQ6Sn2h2u0doyxxbYygDXpGoHOHSbvrRBvAhEkKjz5MMnvXQz3" + "fTxbWGDwn77oQl7Kmqs0489KFxemTQBWmz/cEkmRoBhwEvXrSBith9QckpDOeCRVJNwI1RBs" + "I4GYkKCcOk5LmEfl8xfzDkdmpnmDQbbUvOUQpH305bo5wkBNDrR15nplfLkqoZVj/VCztN5P" + "OWcmx3qZhiQjVXdwG7y3Vv70/fFBr2lR9S1VMc0t7lQVzk2SlhbTglTuIsTx63X22VIcjoWr" + "22HI9g6QzK7qzYXyjQcnF8vg6d2Se1znnwBgiTjso4ZNXyvPlpTcKItD8dGlQKKAah3QF+uC" + "8NeW4Ic/sr56s5JopU8xJ9ztAJRLsSo5MhNN9wWJO1xj7axIibQ4Rv4JNH3dGw8hZatUuyiW" + "fg7LvyrcfrHtqSeogtDI1I9rzocdOJUzk3D+zUOxyZU30HSspAfiwluTerjzwQV7K12p4TaM" + "j9sIsJUGpo1DFHbFK9yS0szWVGr/AaeFdXV/CgOpJv338et5twSHEEuX2kVrYS5SuVvHhuZ9" + "SqxuaevuOLWf9jyJA+2Ht7P/L+rdcfh/8UDamPANIgqdxHdWF6wAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +Test2 = PyEmbeddedImage( + "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") + +#---------------------------------------------------------------------- +Test2m = PyEmbeddedImage( + "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" + "Mpi6AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Robin = PyEmbeddedImage( + "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" + "L2b2/wO95SbBGokj2QAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +Bulb1 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAA3NCSVQICAjb4U/gAAAAuklE" + "QVRYhe3XSw6AIAwE0I7x/lfGhbLwR2catSbQHYnwaAkfYVYsI6YUdcBdwHO0I/ZNeWsEYJhZ" + "KTsJgMpDnCwO5IlnR5PWuKXaVgY0PojBjqraJEypks3Agsrb/R0gLizXeQ232v/NeMCfwaVe" + "AFq45/Z/M86E5Woz9yOZsWCTtzJfasrm3wLSGjv2ey+Qli2pAfjaVtUY/EykwXKJaq9zaOME" + "/yRuHvRCjIzpXheT+QB+IPrbx2nwAhZDRFVKSaXBAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Bulb2 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAIAAAADnC86AAAAA3NCSVQICAjb4U/gAAABZ0lE" + "QVRYhd2XTRKDIAyFQ6euPZk9rJ7MtQu6oLYRXn6gLXb6xo0I+UggAQNRpDN0OYX6dfC63ZSv" + "8fms28RflfasBXaQrO2PxfCQzHnYYGmYz5bdk30VPpuBguvlpsaArLy2xjjMRXMgonWbeNM4" + "LDte22XcmgZG7JAhCzywBh0wwFlnhSqxhbCxPF63m5p2NpUeSxBMKpUeczYb46KygQtRVKgA" + "nE1iHOZaKmcrHbSSqcz3fXU6JMoNJIb6nTgnPVeaUPCuEAm7tuKxnQP4s0hdB3AfZFKPzQXr" + "kgmO+wFQJ57H4zCX7E7pVC7i7132WMpXR9uslyQVEFTfvZXEQ6XS4+QoyiuX3xlVOWcP4ITM" + "qGywwS59hfs5qfbqQ1LMlQjDEDbsauC3vq7J78x1DaxfIaqUVpCzu+Zx5kbDDwGU6z/DdaGX" + "FWI8jAqh2k4jGDXW2QE3EI+Qx3U6zeM28Af0e8fi34LvHAyFYho2A4MAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +DbDec = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAAcUlE" + "QVRIie3UQQ6AIAwEwG3Dv+Tp9WV68EAoGhuknrY3COwAAcTMkFnq2rVurz3zwPL0DshIb0BS" + "OoASSR8HmO1BQIBjYl1xQMeh8cmRKleiOwTX84XUp4hV+2jXNMnoHlqGIX//RQQIECBAgACB" + "2zoBmUYswftQP5gAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +Dec = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAAaklE" + "QVRIie2UUQ7AIAxC607Wo3O0/S2xwW6L+Ae/Gl4RdQCIk7qatUQeBEjclwCVOwcI3SNilJJf" + "3ZHoNxRNCbSzE8Df6b6oHlHMOfaRpGRtDn5NhYzlQ1MxSAdadX+RAQYYYIABBhjw6AbsOBx9" + "les1zAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +Pt = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAAQElE" + "QVRIiWM8cOAAAy0BE01NHxYWsECoAwcciNTg4HCAJAuGfhCNWjDwFjCOFhWjFoxaMGrBqAWj" + "FoxaMDIsAABPtQfBbeinLQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +DbInc = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAAcUlE" + "QVRIie3USw6AIAwE0MF4Lzn6cDLduaBSPta4me74zQslIZHEl7XZqZwPZxgAxBrPQKDRBLrk" + "YCXgdJbJUuWSJRJoqeObOy2yWbM32O2Buyfv0zH1yAvpHlDFraU3gah0AOmHv0iAAAECBAgQ" + "YOsCx7AqwchhZKwAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +Inc = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAAZElE" + "QVRIie3TsRHAIAwDQDuTeXSNliINBWAuEp1cUujRYRJA3Jxnelqou4DQWAIqYwdIjATQpqDw" + "G2gafMP0OAKYBjn9B+OVmfRoG5DpDcCn7wBJeqzeQDhHW2TAgAEDBgwYeAGQuBx9fpoCrwAA" + "AABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +Tog1 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAFdJ" + "REFUKJFjZGRiZqAEMFGkm4GBgQXG+P/v739SNDIyMTNS5IL6utr/KC6AmYgMYK5qaGjAaRAL" + "Thk00NjUjGEBAwMVAnHUgMFgAN50gJS4cCZzRkpzIwAQgA63kzHTVAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +Tog2 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAD5J" + "REFUKJFjZGRiZqAEMFGkmxoGsCBz/v/7858UzYxMLIwUu4CRUCDCXMXIxMKITX7gA3HUgMFg" + "AMGERAgAAPsqCDCpcwplAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Smiles = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAolJ" + "REFUOI1tk91Lk2EYxn/vx7OmwyBhVsytmY1cCBFBQWSRlYVGJ51EjajptliH4X/QQeJ5J+ZJ" + "f0AnIVSWJ0EQQfQhzNG3JkRQILrl3tft6sDNRvnAdfI8z8V939d13Vi2w79IpS4pHt8p17Vk" + "jK1EIqpcLqPN/to0nWwmrc5IUL29n3jw4Ajl8mVKpYvcv7+frq5HdEZqymauqZljWbYDwOlT" + "xxSL/eTOnfMY4wElYAWoAhXgI75fIJ/3mJ8/wvST5xaw3kE2k1YsBhMTtzEmCYTqxEaxVaCM" + "MRYTE1uIxZ6RzVxdf7Rsh2i0XZ5XkPRF0mONjo4KkJSSlBKgcDgsqVVSizwPRTuRZTu42Uxa" + "XV1rGNMCOECN8fHxpimX6OnpYW5uDmgF1TAEuXG9yuf5lOyZmYcMDUWAReAj8LqJXAEWWVhY" + "aLqrQaWVoZNtzMxMYRljq1S6iTFtwCrDw9+ZnPQ2hIOFuqB1crUKSx34qw6hXfMNG7264stM" + "TvrAEvAOKDaRBVpjd2cQ/BbwgwDY8XiEYvEb8AMokky+BF7UK+svGR+qNp+/L0O5jeKcRXxX" + "GLe//wxTU/fo7Q0AolCAUEiUGoWpAWtQtTi4rw19iUB5K1OPf9F//GTDRkue11K3ad0qBYMK" + "BAJyXUehoKv93e3S4l6p0Cfv1QlFdwS0EeXBwTT5/Op6mw389qn4Pr5jcTjZweunUVgOw1qA" + "/K0ig2fOsREky3YYGOjTyAjyPCTVUbWllW3St6T04ZC8N0c1cmGHBo4f0H/LNP3kueU4w3R3" + "w9gYzM6CX3HwKzaz71cYu/uV7rMvcLb2Mf3srbURi81WNJdLK5HYLuMi46LEng7lMlc2Xec/" + "xiMt8QU2mDwAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +GridBG = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAFQAAABUCAYAAAAcaxDBAAAABHNCSVQICAgIfAhkiAAAAX9J" + "REFUeJzt3FtqgjEUAOGjBi+tgpt3C751b4XaakXRDYRfiJOQwHyPDVgZCByStLPD8esRwqSI" + "iP1um138/jnF52adXfs9XybX1qtldu3yfy3+zBHW5tmfqphBYQaFGRRmUNjMsYmVIiLSYpFd" + "vN3vXY1Gpd9zao0eGd3yMIPCDAozKMygMMcmWIqIKiNOjROs0rXtxya7dvo745/plocZFGZQ" + "mEFhBoU5NsGqjU2jrNEnWG55mEFhBoUZFGZQmGMTrNrYVONCbYT3Um55mEFhBoUZFGZQmGMT" + "LEVElUusUS7+fNvUOYPCDAozKMygMMcmWHeXdCOcKE19T7c8zKAwg8IMCjMozLEJ9nJs6ulp" + "d08Xhp42NWJQmEFhBoUZFObYBBvqbVPrv6QrGRnd8jCDwgwKMyjMoDDHJthQ/7dphDHNLQ8z" + "KMygMIPCDApzbIK9ddrU8hSnt4s/x6ZGDAozKMygMIPCHJtg3b1tan2CRf8+tzzMoDCDwgwK" + "MyjsCUFtsOQdiq21AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +SmallUpArrow = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADxJ" + "REFUOI1jZGRiZqAEMFGke2gY8P/f3/9kGwDTjM8QnAaga8JlCG3CAJdt2MQxDCAUaOjyjKMp" + "cRAYAABS2CPsss3BWQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +SmallDnArrow = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEhJ" + "REFUOI1jZGRiZqAEMFGke9QABgYGBgYWdIH///7+J6SJkYmZEacLkCUJacZqAD5DsInTLhDR" + "bcPlKrwugGnCFy6Mo3mBAQChDgRlP4RC7wAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +NoIcon = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAIxJ" + "REFUWIXtlUsKwCAMRJPY+9+4tSshldRqP4zQyUYyanxgPqqWBGkGfZ0ABBCRZeRw3tbsfbWk" + "0Z7XXwWIHlVLWtZa74kH/wICDOdAZCUPvN99l7OAAFMD1K33C4NXQbMP+J4e1fmV5vVbABHI" + "meb9kcE0dxL+AqArB6Jh82QAHWKjyxD+BQQgABxgB0zmRH3prALAAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +WizTest1 = PyEmbeddedImage( + "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") + +#---------------------------------------------------------------------- +WizTest2 = PyEmbeddedImage( + "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" + "YII=") + +#---------------------------------------------------------------------- +Vippi = PyEmbeddedImage( + "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") + +#---------------------------------------------------------------------- +LB01 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAACu0lE" + "QVRIibVWO3LbMBB9dty4hEuUuMKqcpHKOoK6FK7AI8iVJqNKrlK4Io9gHsFXIK6AVl1QZUau" + "lGJJcLmA4kwyfoVmBCzf2z8JfDKuAAznoWu6+/uv+/0OQIyR74wxAJxz2TpfyUN1lVJig91u" + "//j47Voa7XZ79bBzDkQgqvPyFZG8YreMMe/vvwBcT5b08vJD+sJ2ABDCyKWQT0KQEUxnoes6" + "ADejsScPnzVk4M65UUNhycuZmd2aTsYa8NHqaiUZpLVzTnKVROVTFYHQhaZp2MhtNuxmjFF6" + "l+ky0VinKSyZq5TSosicNQAjOwAi51ymls7mbgGNtc72UBjOw3AeiCg7JTNA3ssrCSLiW2ls" + "BBYCJUU76OarCBA556QlG2efxhQ1qzH1kih0/nUby9RLmxjj6zaGzkt2FuPfscjru7Xybk5x" + "MdvSALXij2UPIYRwo3hzpNw8siXk5lCtot0XVdECAFicG1/1eJbPt3pfFf06t+nMNY1oxTVA" + "LR+2mQMKASHEvs8nOgI1+pXgAAIFAkIwxvBwGGPULsq4rp4qLMYCxdYrZlC6OArIeP8ZaQk+" + "nHfR+m59SWCxdiZwTjg/f/BsrkG1bRRUomXvX3pwsU2bVVPVyNO7NQbI7wZ6TinLXBJYFLkd" + "Wt6dsqpyeT2nhLHI9JySXmqFW1qANd5+vuUVnU1jjETePDywBrMT+RhjVSAf1tuUZeQeds71" + "/ROBjDFPTErU90+bzQFTqdWirrzRSnBrzWMMAAghSG35LeO9J08Qb9/aLhI4HA78ElX9o/5K" + "agYRcb98MMnkqW3bPIYcNRHJaSrZJb4A8N999Y5hyVrYvu+NMdZaay0Aa+3t7a0x5nQ6bbfb" + "kt3CxhiPx+MHKZrjQMu5Khd41XfyhA74y2WHKVdq2zjn2qG9/Azhwy76H+SvrM/Fb1QY3j5A" + "lgwhAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +LB02 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAECUlE" + "QVRIibVWK5DjRhB9Vo4ETqCqlkzIXd0FtfkSHQy0wJELGiGDrQUSDbNRwCENO5AFEliyzCIG" + "y9QoVXdsqFmGmm1Aj0Yfu5Yk6dK65PHM6+7X/XoW+J9tBUBrnWVZWZYA8jwHYAg07CBDizNs" + "ebEuKwxUrRPApmm01qvVKgGgsqzruq7r8jw3NKKToUv0qy7jym6jtdZEpLV2zgFIABAzAGut" + "QMfTIS7L64LXBU8X47v8xJbJkBw0BAa+fv1TyEhkq1LKez/jQZ4BzjkX3+NLwZP9E8e+6758" + "+WO7vQPwJuQIUKbG2C9eBK62zEOKbFlI0FovNpeZAvDh81v8Fh3Mq8qWjSGQESQb+ZmniIET" + "Cn/gImylupZfVwBqQyGJWL0Bmi0zYBnOud1GzzhktM5tJHyi2oynrGUCUNfr1To4mKKz5QJk" + "wNJzSqn4OW0fZjBgKLSmcEVEBqFlCVhbThaxx1pZhvd+t9sJ0YsWiFa1znuvlJKdbdtakAXF" + "SJIZJ5FWsOxh5r6G9957H8QxFFnKJuhN6Zg5JAEmjEpMcCEc+WrARGStXRdj+GMjSLpgSW5d" + "wFqrtY5KIkOgGqFN5+FLC7FlQ7AIeVxSRAPv0/LMOgU8OADNOxBRmQZgy0wUZbSollIKRAYc" + "oReTKhlRJ3lMNRxnAIOnZFJsbuZ4RNp6am8mGQfPcTTCXtHXnCVicNQoD0BkyKlSww8ZcLFI" + "Ygg5POLR0KwXACwWaFIDrb3AJJjPqWnuYiLj6coU0TnFAPM44QE4VcbtSWCCC7CNSUQfgq61" + "l/ADy5ZjTN575xwDrcoGt3Ucf4hFniVBNYBWZUVAH4dlfOIRQyQ+AKiykbPBuADwAwDza/rE" + "SE+nND0hJefO7fPZOff8/Oy9T9MUSPkE+8RPfPrmf3x25333jZGe32fvlXvi0/l8Pp/Pm81G" + "NAEuOE1PKdnfbewiWIaxDBSqbKy1mMwfIhJVM493QNM0ALpOA6FH9vt9LfN00vHDsKPggwG/" + "z4nIOSfhZFn26dMnZu77nogAlGV5OBy01vv9flZzqdN8LiSxH0YN1bUB73Y7DFP65uamruuq" + "qpqmISJjjNa6qqqyLHkiLDK0QMdUyWSIaLiJ6jqKVoiqqmq323VdF/cbY6y18bao+xrXbLgy" + "DYGMMTNFHP4+fPzpY9u28jXWIM/z7fbu+/e/AHRdp5Tq+97j+oWxAvDSG3EiQ26xI/85V0pJ" + "bTG54kEEZgBN03h9HX29Wg9dRAYX9Ql5HA55nj8+Pt7e3k7Xj8fjPfMr6GJJRA9KvjCv/XZ7" + "9/DwcDweZ+j391mWvY6OQNFLDxC4uJqBWFu1mChDKfXu3S8fPr99HT38V/Hy0l9l/9/berX+" + "zzGX9g/BE1Gzc614hwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +LB03 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAD30lE" + "QVRIibVWrXIbSRD+pPILjB5hjAIO9ZJTVWQyC/wAK5AKMOpFRgfWj6AFRkFqJpAA7wMYeIni" + "qoRoWECIpwIO36ADQT7Q2tFo7bq4kkqD1e78fN399Z+A3ywTALvH3W9CLybFFMDydFnOynJW" + "ftl8/XXQL5uviqafUwDGGGNMjPHi4m0xKbz4n4P24otJcXHxNsaYFqcAQNQ0jTFGl+q6Tvpf" + "LuWsrOta3xPUoABgZvWDmAHEGMtZWdfyEui6lnJWqtXWWsVJuyf6s91unXPeeyYS5tj3IYTQ" + "dWXXWWuZGYBzLl3r+x6AiIQQ1CCFZmYRIaKu644UfPv293y+0BMQEYCA2PcxxhCCiNzc3Fh7" + "YNY5t1wuFT0ZzszMHEJ49eqPpGAKAN5///6v2rXZvFd71S69zMw5OgBrIzNbaw+kEzHzZvO+" + "7/t3nz6mkxPdtlXFRMy83W7/+vABQOg6XXTOKXoIJlegKyLSx6iHAVy/eXN2dnZ6emqMWe/W" + "xaSYAFiv11dXV7aqQtclo5g5QSuW8p4oyrcSXdbaEIIxpmkaYiomxQkAYjKtAbBarZxzImKt" + "ZaaB4T26+KP6SDqsjbvduijqEAKIVsxt2xLTgaLd486LVyeYaJQwKsu21WgBABGAm6YZnRER" + "ETHGGOfWawaw90CdWGHVti2IEnriRLyH9yEEa22MMXadtXbZtmpNMkizQ0SaYR0pTfcbTaNH" + "EyEEEJGiA4gxpjbgjBGRZIGmQ55aYwXMrLwruhZBNEZxjTFJh74ndI2S7EEIx7JvFXUtue2h" + "69TSGGMqmSS5HwcVXSfeh2BGOqYAUpfWTFd0a22s7tTfBJf6jD7zM3oxT+UjD1TyclVCvPf2" + "7h+lBYBzLjWyWN1574kpbxj6kifhkYIRD6YrjTGhnBljvPd5j8x3MQQmORozQ0/wnOjpp0SP" + "LBidt1XFTCEY2NHAAS7ni7ZtQzCJhNze9PmU4rRrrWWiEEw8botTAK9f/wnAD/fz6aaSyFWr" + "n9WtVTZCR6JIdWib1XaUELXXO2MAELMX6WIkIu990t00DQB6UgQYBflyvhDv+77XCZrPP+1z" + "XqQLQUGJSHebpjkqumOZAHh83GkF3N9/Vj+0yehEtNYqlq7wMLT90J2Un2fN3/8vwnEFqB+j" + "5owhQinOmv76fBZd5QRACEYVaCTu7z9fzhfvPn0EkQVCCBpb59z19fXt7W3ePEat7akcYpCc" + "UDWX8wUAEO2DPKTv+fl5VVUvRIfG4OHhIVeQxwNDamnH1oI6lNUQqvVu/Sz6fianICOb5vqZ" + "wj66mY+a5XL5Pwp+6OKvyn+2lmdb7GZzQAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +LB04 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAACUUlE" + "QVRIidWWPXLbMBCFP2Sc3hzXSkEegenDQi50gOQAKZAjSEewj0AWKV3kAiqiggcQ3acAirDO" + "SL0KpAAI8A+0VXgywWg0hLB4b/e9JSD434eILZgjAA2A+BaJKQHIAcTHK5kdgUeZjZEh2Mdf" + "gW6kNFL2gQbEchgTyePd/M9NNNnp0vLvEQIwJaKqHHTuhLZpeuntg6gqIxHVPE7cZJ+yRe/v" + "z3v55pAvOXwTWxAVpnSJW7jskAJqrQfTXEexXz+MJE1TY4wxJk3T0XR5b9QDB10GrYQY6Omn" + "yw0aN/kYOi87pFprIMsytdZON89RLb0rMx703+FY86kfOvuSAmqraaKvOstdJKquR5uew136" + "3n+L7iIZnxw3Hs6t2aCqh54DKDRwr9dogJ+fD/e7tdtbHvyRZeS4mkEFnsaFVpgjNPD1DIj3" + "t0mSAPYbOJ1Odqp+PfP9liaktSCaY3JHTYlSylzO9mNXk2644MvZXM5KKZ+iKUNrjU02EqQT" + "19Zb1y2QfrizWLYUD20f9O8/Yxm67ph4YNe8kwC0bdufKqWyLFNK9XFDjISpyW404cyyUhqJ" + "KAqgrutRrX3Woih89aNzaaZNg0q2GtshkcPSjrquPz0VoQmbkOucB3nAdXsa6rperVYxgrZt" + "Q+nlQIm5NmUolHR8u2S72WzoBKHTbb/fP5wep+LMEMyQDaveJdtp5MPp0d8QUyXnCQZNRffc" + "xO/LuEnRCgZMnmM0XuH/CwQzfHmoZhnajhcunH8z+nfRG6CX1/2Ju8KD/vUAV9jwtuMvbsIk" + "t9g4CtEAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +LB05 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAClElE" + "QVRIie1WO47bQAx9CpI+OsA29hHoA7jYbotUyhFGR1gX6eMrcNJsEaRwrrCFXKQbArmAK/cO" + "tl+AKTgzlqWRrRRJFcIYCBTNx9+jBvgv/1DYzTYNTKrzzRGCC0xzrZUZQGCE4MYw4zADU2AA" + "UDcvJg2cTQNTCPnZfmQPPYDoXfvaJG8LCAI4UjgAVetDiOUSAURABAGIVGHK1cqrc5ioUAGg" + "alsNDAIkIXoBBCAQEUFAEBGx1xQPA56VAaJrIbH6rFr7qwQ2R5I0CCyxvSJV68veisLu3GSn" + "nE9zd6EJ7sqAvpl60XpAYkReJJ+WXV9DV+dzEsAk+lz584mhRnyp9kmqqReByWIjyi7GjlLb" + "vQCyaucBsAMRQM5yFy/1/Q5A20YH2+Z58/0eADP/ev4IgBxZECJyrdPszgRWdZliT09fVRVA" + "XdeLJHVdq+rhcMgZ28K4vZHOjE0bpuu6pmlUVVXrJKraNE3XdUi7KwfUlwIPRJDnThLfHh4+" + "4PVl8+nz6XSqqkpVN5vN7tuX/Y+fAEAkPlPvQoY9MM/knHHVHoxWXdfd3d0BWC6XVpnj8bhe" + "rwMTOQJgGIMeFJocGHk8kFfQmc8D4zhsFtC4w+US5fmx9M27quL1ZViBd+9VbYSEiMajPARg" + "h9YDkMCSw7dc9vu9lSjL8XiMATmqKgEk/b0XwTiDnHtO2fZ8kUfpQ1Zm2TWAQSyxMUAeFaO5" + "NWYc+G2AcrD9xdZb2lfkDwAuMMRP1WQgN7bpQOS8n+feISYBIpcfLzTk4gYE0cU95REASt/8" + "CYDARPkOsgO2RSsBgC2wSwpyY4ypDGT8ncrELq2cZEDDG1iByewAutyLC2CLVQt23ugqgtYD" + "W2AxCm0K/y/Jb6NFiKLVxRI/AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +LB06 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAD1klE" + "QVRIibVWLY/kRhB9Mxnt4h5FAQN7FCkr3UmRyjjI+xOMl5V/QgaddEEbsDpwqIsdPdNjY7Tg" + "kIsFBDU1u6Z7aAPK7rE9s6uQK1madne5Pt6r6hrgB8sKQPfcSS0h8OHQ3Ny8vfv+qKqiAMAE" + "CgEiAFS1EO2YClEmYgIR1aKiwysAUYhq99yZ9WJVrAGgrpumidEx88evjwCICECbkiggAuYc" + "kTk+FyKyrxayzt/s93vvE1Q/Xf9h1mOMr6ev+oK3hQMT51yMrizLu++P+7/bV6wzkYymmYbX" + "l5xtADQxeu+nFm2dkTUOFiKKwASAoQAVoh2fa2Ez/BIhRgA3N2/3f71jIosuS6Z93D+dEVH2" + "wWc0rAB4751zZVmmlKCaTU9JsxI65QSIwgrpQgRdsMVQRSmlh4eH1LY6YLosCR28nqwTERNE" + "TzzT5HQqPwF4enq6urrSvg+73lRV9f2X/ov2O/R93w8mdiCi3W7X9/3OBD2AfhQi2qHXHtfX" + "v/7y+88A5L2sDaK2bWkMZNZlo0yDslNTs8c2a1HL4+vHD1l5A+Bz6RaIA0OFALAuk6JmulD4" + "gckUgkgtWosGJob+8+nfN3e/wUh+DjzFetGrCqSUSudCF7SuRdGm9Ll0oghd2G5vnXMppcr7" + "IR4aYEAIxarYnJuWkdImRgDHb75Yxca5MCqUzomiidFqJaV0/OZvtzGlZDAzVBScITI0m5g1" + "4JxrUzpWXqBSKzNE0oV2E6mqBEBqBZylIqrTLllNgwVgmeY0awXGxs6ng3HVKXNhvFwtUCbi" + "bgJRSsk5V3mfqVVVIuoIqirwAJoYT/gCAIkqYdZuTAC8qDYxcs7AMMnWz1sMwG0TK+9zzUDE" + "gF00l7m/bYy84zgP5hpgNiuZeftgJswWh9FORBQChWDrKZLrDO4QyzxAI7/y/qQgktnOU0xV" + "h01mzG/JWQYDOKP1qW/ru+2hWdVSiK5WxfbQAAhdWPqYyxyicTRa4Lm0DDcKgSfQMbNhYmov" + "jdIlBxjaQi32wBSYahmiu7+vrO2fA9/fV5Zu5b3pXxxqm+WGiOhQVKd7BrI9NF5ROpdaBbCq" + "5c/oANirc66JkenEbeZ5A4CXl6U65wbrIjpm0zSNGCXMUE1tOzUn8/Azz+ZgiWDl/dS6nR4r" + "D8BwB1AX9TkgJxnVlhzoZGSOCQ0LK/ZxV0wnazrnLjraLDK6KNYKtSjrMmqb+KKza2oqa1Ma" + "whSxVlgMn/GORB5h9pxfLZcdZMnDPb+aY++9917G8m3HW/2CGG0ZyezgdYgAlM4xkbmJMeaE" + "/s+/xx8r/wFXh3rTELfZNgAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +LB07 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAADyElE" + "QVRIibVWK5YbSRCMmecLtPACv7pCNDJYNHOE3iNkoQHzTPoIYgsWdaJFS/oIEjExUhxh6wgq" + "Yu4FWd1qaTUeEyeY109TFZEZ+SvgF9sDgNP301v/9j5PEwFAkuQizWi8PZYdksiXT79//etP" + "kDYZgP6h//C+DxJIkAQMcnc5AMylbE/VWv9+ef348bevcWWxnyBYLmQHwBvoISUARj3PXTsL" + "EPDsEcQ7En378u2fz58vRMvHViOjSD5kkTQzSS0C0t0ff+S3K9CNMipcIzBRxsblixpG1lol" + "XX6U8AOJvM8CJopk7wyvw1mAko611loBuGiQERCPx+PT01PXdSvOfYILulmftYXejZGA7jCU" + "P44JwFyKC13X1aqu6yQF8ZsEN+gRBGiQsrczh6GS/JeQiqtlZC6l1lpKiQiIexK9gc5AFzkA" + "kwFAhHI+2LS0yJCSS7XWrUSPN+jG5k/OmqjwTu4PWSIneKBLigKNLiEZaTey67ogGEt3S3Ab" + "jeiSpN4BgBJJLf4add6n3Vh2z/OWY0ipbBrlfxKJm78C0NDNJjbou97sxgJ0Q0LEYZQRvd9E" + "QG671MjlNCllx4q+dtxhqE2odkUA5lKySPJWIpusKbtYSulY66eX17kUM82liARQSsmiJJLn" + "fQqm82FYL5ZSIvQrArkATNbq5FjrMAwAXl9fDvtW2ifDZE3oLEbh7sYSsyi8HlI6DPVkdwh8" + "MoAXlff7Iarieez6jNVHo9Zkrs0RTKvIUcePG/TLjN0ayVJKSun7yW7kPgw1wj0MNYQK2yZy" + "S3DlfqRrHOdpMjMjIPdA18IRguzGksW4uKWJ/DcC38a5jIRSyvF4HMd5MhjlYvaLIM9z1y/f" + "pZQ+tynd6mqh/7CCLmpehIq2AjDiaW82BRzV1sFcSingcN43uSXRDNKQkqshNQKXpmmSNM8z" + "lj01Ub2aIKoLcdsljDaOUXE+UL7RYJOGRmBmOeeu64aUjKLFagGvZ28bfECfdbKN4pKLUdw3" + "1nJgk0U5GpVF0Ma5iyCeui5mKs1irMq9lNIWwzJojYrvANynehUBgPM+ZQfJk7Hv8+k0QX4Z" + "TYLxIsKQ0lzKFj3U3w6rw1B7v1763mfEuCcB5NwGS0qp1vq0TPnNQo5h1dAjz/FjbJusawLK" + "A3RNZ601Fkigr9DknZm6df8+wRpHe82hPeie5+5mCK62Uq4BrUYo695OttMEORg14QQOkHjn" + "xSiXX1cnoci0lqfTmw8vxgNRctyB3nKsHRDoaw4EuvTOy+5nLDgCHRuhQqJfbv8BP7qkTc4J" + "UvYAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +LB08 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAADYUlE" + "QVRIie1WO5LkKBB9dHREG2P1FcoeDx0BjqBxxmgvZa9VOkKttTZYsxFrtY4gjgDe2LpCHyHX" + "eIiiVLW95jiToVCg5OXLHyCA3/KrxWTBvLmU0uc45xyAyykBmDcH4HMT4k8fCVmgGpxzVN3j" + "skADstzoqdGA3opjt4tqyILnWBAg64ppmIhIKTnn1jGVAiABMFMlBVAKrEUpGCKVycOtYyJm" + "T/TDigUQCwwAsQhZgTgN0/ZaEUAhRYvd2uqJzpqPLNcBLFAQCwlRJtM7AKKhfSkWgLWlxd7T" + "WXutVUsIACwG4lUBTIMRiycmMg0GcaCBmQAUjrMgS2VvqZgJZkIpVU/2IQI73hhTJkNlzUC6" + "oDjBxPlm9emSteo/m+++pPPmTh+p9sA5dzmlQ8XvhYCGIW+rT+8mCyzgN5dSMuz7ekrlNvwm" + "h3j/V99IVGAinsnex5gFf36My7L0Bi3xdUyA+GW7ILWcmrAYxNPvE4ACmJ2aRT+/Ltx9moW7" + "ZoiwljtZ/LK1ku57ynJnXW5jBf6jBzwM1nX89i0555ZlaZatPmYCj5lxHFNK7+/O+wq7rg7V" + "50MdWNnVJgBlSu/vAUBfLQK4gufNXU7JyijivF/2zV95VGCMMfyeN7deTgD8vHEAACUC8Itr" + "4VsrYP8j3cS9K4AVlAgrZDBD1CwlxidaUsWBnzc/b6T2S7W3IgBgAQQggKcC8Yvzi/Pz1tgB" + "aBa0jZYFVsTPW0pJH26EUsxUNIu5XTfU7CaFPqlpyJoBQ3bOccIM8cq1r/Oe/Xw+HzSAZUk1" + "i583rsCb9lLqssvCaQ5UVbMQcz6fyQ5Ag9VgOdvwvTm4TA9Z959miKpqjFFVxMFM112rwUIy" + "AM4aY3rbY4l6YbmI4MHLN6xtFKpK9gOmVfie9ig15c64umkA1fvZPoksqP+Dh2KGyFP63rIC" + "jEGZruxlOgA+S6P9ylvr2lQIIYTQ+vzQd8sA9z2op/fYTp6i2fLNmry8fHl5+XK5XPhZZ8MN" + "iQaIvc3gGnKobz4ANNudXVRFb0R2H4/l+qNsdM453nY4aD6cc+SqzrJt7D9+/HMIv0WJdlyz" + "Jv39B4Bfrje4xvL29h1l+PvnH29f/wLg59f+ildJp9qDWGAeXujupbH0l7NeL4/qtL26fwHi" + "Q5sXlpUuEwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +LB09 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAADoklE" + "QVRIibVWMY4jNxAsLe4DrSfQiQ1c1owcXDTzBG5yB6wj8guKLnA0XyAjL+DIfIL0BHZkA+tk" + "+QTxCXLQM9RIe6vdg+2GMOBQZFd3VTc5wP9sGwDF4/5gAAxEAA6ttdaIqLW2d23MdJzMvJx5" + "O2Yd7l1Lwp4Fsbzm3W7sHYAkPBC11mKJ0WMgUu8AxkwAREREAECfwHEyYybPkoQR7I0M7gDk" + "WgEQkbUBPsbIfwzVGaOTOhgzbXdVRI6T2bu23VUA7H2u9TbGZu1FkY57B0BSSsI644zJtV7R" + "JUs2YyZnjC/xVYrUuyLtXdvYZIOs1+VanTGdru2uagZJOAnvXQOQbHiVIgCeBcBAdH8wxSOy" + "9PAVWONQXwA0G8+iFM2Db2HMVaSWhAEcWhuIPAszdzbGTOp07xozhzSH9XLNuqjsxm56gGqd" + "rnVmakqRaqAUEdE5FGaVbS2G3dgP/eU4me2uehZ1pEia00LLGcwZc2it1pqAQzODIPoL2S6M" + "FjsVT0SeuXgUDyLS59WgeHjm+TWCiJ6fn3XXvPdU9Icu8nEyvf5yrWMmJVezUW17TppWJ3M/" + "NWut/vWy9WaRk3D0AJ8JUeG6et1j7wxVyCYAMMa01vpkV2LuA90fEkIQACHIdszbMYP5XBsr" + "9jtMEj5F1iLslcKXUW4AeOa+R6Xuz5CuQ+471/pjKW4AMbIeXohlzkC9a5h6AGx31RmjY2dM" + "p7sLcAWG5SQGAPbr+XOZKlFYJAXmZnbG9Epf1s4xKsY6lRmVuZ+7Hzqz6isJ+gnhDPausWdw" + "hCR1OmYyxoA5QnpLX5gksAfSGWCmYglQwTQc9h7skYK6JjK+VYhAJAPwEv23MK4oUt378bsC" + "E7CHJBG5PxgiuFrdqSyBSg4h8bXyUaSHPwNED5wvq+vywEwLAZj47Iw9A7GGAAYz24QSOYqE" + "BEC61ndYbkRmRiyIxZdIw9AJFRGt8YLrTmTPP/32u45Libs8X+lJJF2IHIuCnimaHOC045Mw" + "MDfa48+fPr5gOcBHSSxpcggBdbmAVwA3bCUMmD8+/Lj+86/Hvx8ePj88fH58/IT0BUCuRETG" + "mN7PGwDl9Op3B4Jl73+4PwD4+vXXp6c/3eTeiGllF/fBDRuIcq1Pv3yZTicAgteP/hd29/YS" + "9gCI6MBsQ9jtdu/3/j4AIJY4EDHAIt9FEd7WAECwrPe4JLk8yN6092kQSwiJiFal8R32jgz+" + "hdnNrc/W/8b+AWuuNm4mLOApAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +LB10 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAACG0lE" + "QVRIibWWW5HrMAyG/+6USSAoEA4WiUIhLAWbwlJYCBGEYOk+yHZs+dL24Wg605nY+T9dLDk3" + "4if+p90BqMbpuor9BwKAsk+12kNh9jYR31d0FdMtxkgYqp6ryoLxNdQtjg+NMym7icX+FqBi" + "Xts7zv0FZsGoACqBsBY1E4XkGhTMjDFK0SsjAtHFwJKRAcuERHg5xruMQQSiYFy5ioAq/rWM" + "ofHooQdIq2XqgfCbV2s5F8TQGoAoiPALBIJoVmeAEPLvJcNlqWm0QKh7Oqmn94CRswzElkFt" + "LRtArEVrdSBqWgo5Ue5QlM0SQXS1d04RheKFxOaFon6ep0SAkvrL7Jv5Ip/n6Z4U9ZkEV2mR" + "mCIrlagAFFSx/Wz4hsT0gw3Ob2w/W9kYRufR9pt6vd5N00cjIRGBIQ8A2B7brOYMgFI/ltpY" + "WINx3Ts4dNnKMOt/zpeHr0Gj9UYZXVv0vHaafqiON45T28mltuofDiw7O2OYt76TG57isKsw" + "Yo/jSli1F/W4xrVbuNQBMA4axJGQyzuqiaCO9HDXOOMAdkHgdHY9bBLE3dwngmonmm2XC2mj" + "ph8nvcU+gn3ybXCEayl9IFGCBU4nYlaDG/GT9WZz9OBVQndpJMxBrSrsGBEAPd+99GfB1b73" + "eAxHxVC6D78Mg36pBEeUAXYx7dHX2aWlZ7iU9h15RZAYbSre+Q4bqquCcagV+QONz+0Phw4J" + "ZHiPPT8AAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +LB11 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAADPUlE" + "QVRIib1VvZnrNhCc07sGeCFCtDAqQRcqlEsAS3gvvdAlcEvwpZedStCUYKXIHkuwgwVAkJRC" + "GwE/EMTu7Mz+EPiP1wuA2z+39k6ZTPI9AKDtVZ++JCRCdeM3JaTb1LwdX46vG9dWjd2AXJBY" + "XbTlr4IEVhO5H0wFpgKMo3b2JKSC4ccmERQEgKBTJegwZW9SjakAUNZ7J0GAiWbyfYvUY6zh" + "V4/1hKCLtstB4sZ7u8Q9MAlAkoBE+qZdcHmnia7S8eX4AwAZmjIhIAMmIYcQEICvjfeUQIac" + "eQ44p5AzckbAVxZyyBmJyMqeA/uwQ5fSAlKUrVRY5SzefXUbkqxa0esKwDj690Mv6H7p8TEA" + "yOq3lJo+Ne1gomP8AICQ/WZGRg5nBuRwDjCVQgJchhxyboX18fF1RvZ9yFk5K2eCLmxWBmDK" + "rzWZdB6CIDrTRFjHwIRSI+Po9Xo0W1q0JwekRDPBqyixeHcYVx8P2krzHE/DsGQFJYJWP83W" + "zUfTYQPemkDrw0Tc78M8z9d5lkDPbvLCl0m/Pu/Nr0pqiJZkEiwlXhJIrBYTvy/xEuM8z+0I" + "TExM5P0+LDexOFkAmhSs7vrwAZiVqrnEuCUN/P6+/P6+oNZPH9wiUT9zNvbsI+giRJmNANPK" + "JLG5OmDdBG1OqLvNVNSr/dymTxmZNo49trriWxho6ZuV/n6b3Z2utNRszcRO2ybUViL3KFOD" + "MVWM0qsg8ed1fnv/fHt7f3v/HB91eyNxQO2yXh8PpBGxGrjXa0r8+69TjBFAjHEi1px3OWg0" + "+1D6qBuGG5sIptvEGOPtNi0BuV9bMdo12joKx7jW2pdgYhkDTIkwE6dp1zaLqy2AU2tReCZO" + "w3Cd5wIjgyxRGsdyQcZWrx17X694vnoSUMG4XiEt6jmM1lZbgDbm8KTR2uHP01Bq0TtLZh1X" + "mVpMeijRanbaFmue55X3yvGhVQvrqUQCYPI29h/VJcb3z/s3wGTNnQn96NnoUwC6GV549L/i" + "YlleownXP64ATsPQzjcTVN342s4it9lPlR7uNAy999SNh70SBxSEZar0PHruXNNa/TzS0xp5" + "mgM+iObBpxa+w2ymy/+x/gWtyv3j8QyAFwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +LB12 = PyEmbeddedImage( + "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" + "0EwqYgAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +FloatCanvas = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAfAAAAFACAIAAADMBLnEAAAAA3NCSVQICAjb4U/gAAAgAElE" + "QVR4nOydd3wc1bXHz53ZvtqqVe/NlqvcZBtXbEzHENMxkBAggQfkYXAg4SUhpEIgtMQOgVBD" + "DRCqDRiMjcHGRa5yt3pfraSVtteZ+/6Y1ezsbFeXPN+PPvrMzM7cuTs785tzzz33XHR3yVMg" + "ICAgIDD+IUa7AgICAgICQ4Mg6AICAgITBEHQBQQEBCYIotGugIBAomysu3+0qzCUCN1XAkOO" + "YKELjA8mmJoLCAwHgoUuMJ7Ytm3baFdhCFi5cuVoV0FgYiJY6AICAgITBEHQBQQEBCYIgqAL" + "CAgITBAEQRcQEBCYIAiCLiAgIDBBEARdQEBAYIIgCLqAgIDABEEQdAEBAYEJgiDoAgICAhME" + "QdAFBAQEJgiCoAsICEwQHl7fPdpVGGWEXC4CAgLjjBjC/fD67t8/aRjJyowpBEE/q7njgmfi" + "7vP8l+tGoCYCAgkimOExEAT9bCQRHQ/fWVB2gVFHUPPYCIJ+dsGT8tkvtMU95NBPc7jHCrIu" + "MIr8/kmDoOkxEAT9LIJV80R0nIXdmVH2Oy54RtB0gVGEcZELsh4RQdDPCriGeVJqzmX2C22s" + "poNgqguMHoKaR0MIW5z4cA3zAat5eAlJOeIFBIaK2Gp+Noe4gCDoE56BuVliI2i6wKjw8Pru" + "cDU/yxWchyDoE5nhUHNegYKmC4wMEQ1zQc15CD70ic+QqzlbLBsAIyAwrMQwzAV/OhfBQp+w" + "MLbzMKk5A1O4YKQLDB9x3SzRls9OBAt9YjLCIivEMgoMBwm6WQQdZxEEfSIzrOY5ewrB8SIw" + "HAj9nwNAcLlMQEbA2cJFcLwIDC1CNMuAEQR9HODHXh/tGe1aCCTNL986MNpVGH8I0SyDQXC5" + "jAM+aNvQ5Wm9u+SpoSqQpmmMMbtKkuRQlSzAwEo5s/DY2rmjWp0kWFV1C7OwtfLVkT+7YJgP" + "EkHQRxkM9HHL7hO2vWavEQNWiXQZ0vwlhh/IyZSBFZiIv4UgAi0znrIPGMaTzu0afbf1yXm6" + "C4qVM3Z0vS8jUxboL4pbSLe3/bjl+zZXrdXfAwCpkuy5ulXFyhkRd16yJPCc79wpRK0NGaya" + "M8sjqekjaZgfeaaFu1qxLm84zjIqCII+uuCtnW+fsR9YoL/osqzbRUjS6qr53PjKXN15XEG/" + "Nvf+UaziAHD4Lb1eU558MgBucB6/OPPHiRx1yrqv1VWz1LAmS1bkoKzfdv33c+Mrl2ffmSef" + "xNuTVXNmeaxperin5ZdvHRhHRvrIM6xqzpPviY0g6KNJvePYGfuB2doV83QXMFuKldPFhGR0" + "azV4Gp0ncuVlYkLS5WmlMZUuTdQCKlBOzVeUA4CWSFuRft2/m/5wyrovXNAFJhJD7mY5qxSc" + "hyDoo8lJ2z4ANEu7nLMNXZ1zn1qsB4BXm37n8FvYD7g+dCdle6Xxt8zyNPU509TnbO/6T7en" + "Qy/JWGWGEr2Y+YjrUUH9JFg37rEEQSRyoJfCz9f/wo99zOrGukDD4h9162drVyxKXR378Fx5" + "mYjzMpMRSgDw4QnSGzwujPStla+OpA99SAzzgcl3xbq8Can7gqCPJiZ3s0asV5Bq7ka9JINZ" + "uDn/V8zCt93/PWHdy91HjKTLDFcCwLfdH1h9PZ8bXylNmVWsnLG/d2urTccIOqPIXm81c4hE" + "MjNxNacoCiHEdJa+39XFbLw6LS32UWIS/aToUQD8atPvVmf9NFWS/Znx5ULl1KmqhYmculA5" + "jbva6DwOAFmy4vA9d+7sHo8+9PGi6cNRbPh7YmBqPmD5HsBR4xFB0EcTF2XXiouifUqiwK+D" + "wqJLxYRkhmYJAHz751+1AFz7+zfTpLkAUO84CuAFAIwxV80BwOutlslmJVIrmqahv+OUVXNm" + "ObamIwACEX2+Lgr7DdJsANTpblyUuppASUfHOvyWnd0fGyTZMzSLI+4wjnRcILyvNUE3iyDf" + "ySII+miCEIKEreYYMGoOAKvS187KfBsAIsauxDaTWe1eo9cnbsuH0+Guz5IVISDM3k4A0EnS" + "ky3B6uv5tOMFtVh/SeatIjTuexS4DLmRPrpRhgNg0Tt/XbSev5FRc0G+B48g6KOJglRzveQD" + "4adzp6nPgbRrmDW9JEsjHchgMa4l/qHZvEavpygqfLcrrrji448/jlbIk9/3vdbvN+c60Ekk" + "+knRn9kGR2xMnpZNHf8qUEw5N+2aBA85axnFKMOBseidv4ZvvCrPBQlL+cDke+MvlgPA3X/Z" + "MYBjxxfCAzOaZMmKauyH7P6+FJF2OMqXy2e7XIfY5cQPRAgxLper09IS96H/70KN3Pbrt1oe" + "W5F2XZas6GvTW6mSHKbLN0FpbnXVfGZ8abZ2ZaXufIAhaLuMQc7C4aNMX2u4ml+V52IW0l9p" + "Mv24IPxAwfpOFkHQR5Op6oU19kP7zFtWpl/H2YxpTBNoUKM3EUIYY5qmk9LxYA0wxhgzjpe4" + "Os4iJpCHdtn9lkxZIYlERnfTDM3SxK1ss7fzM+PLU1ULK/uDOAXGKYzzZNuFgfEHvS++A9HV" + "HAAYNR8++Q63zVn3zgR7ZwiCPprkystmapZWW77DQE/XLJYS8h5vR7Xlu+WGK/WSLBrTzG4Y" + "MACwqwQiADDd7yXHgJmPEAp2nzIRioymcx3i0Zzj4ZY4TdPsgFIAwBhzV6NhdDcaJDkiJLb7" + "+xyUNfEIdADY0fWej/bISdVRy052Y4pIV8SJfrHMCvTrag4fTrzkscb825/Y9+IDgy9nhKMM" + "oxHR9x2i5mFcleeaYEo6RhAEfZRZaviBQZpz1LLzw7a/A0CqJGeKqlIjTgeAfzf/gethf67+" + "5wCgEul+WPAbJ2Vn49BPWPecsO4BgKnqBSvSgpY+QRBM5CLTQcoNQueN+Gfc5Wv0ejapC0mS" + "NE0z4S68Y2NjdDdmygoAoMPdmCbJScoJ7qAs8MKBPQDw02C3Yb6inBX0D81mdrtl1qxxqum5" + "5t2t+nPm3/4EbI+8w9MnVzEL903ZGre0kdfxpLouw9Wc6f+sGMoaCQRBQ5jySWCMMMLpcwGA" + "SYk+yDkuVlXdsub9BghrIHO7/riMWUFP0EteuZ3vVeuo2PnOO49wtySi6cyBWUeWJFa75Igh" + "36wNvnLLK7yPKtblPX1yVTQ1H0XYe+nJXX9gFiZYQ0Gw0AUiEzugZchhnrQPry4CALi6iDU8" + "o6n5+OKxtXPDVb5qBcXT9AGL8lCpeUT5Tn+liXnNcIWbVXNmmffieXh991hWcwBYv/g3rKZP" + "JARBF4jMSKr5ABiz5nlsHnr8Nmbh0QdfGt2asMR2oWy78MdwYXB55ZZXAibtyaiHCAnNRxFh" + "gosJCOP6GPzMcC7XIeYv9m5D4m/h8fTJVawrmYvm8GHmbwjPNTI8tnYuq+bQr+xVKwLB/nhB" + "IJ8P19RN0N8yMDb+YjkTnZ0UcR0UEYeAxlDzVVW3MH/J1kQgIoKgT2QGo+lcHY+h6UM1oSi3" + "c+/SlFZm4emTq7jb1+j1Q3KusQlesJyR9fumbGX+RqUaFevydnbctLPjpop1eTHkO/zFM4B5" + "43gDowZU3yTg3ksT0t8CgstlovL8l+tGcpLPITHPmect3DBntrNDT8cUGzZsuOeeewZTAuNJ" + "R3t34AXLmf8AgPYO+5jG8NDsiPJ935St0aJuuKvjxc0S1PQJOgOuIOgTFkbTD/00J9lwl7g+" + "FpbhcLaML5JSc83hw2wcfTQfOiPlA5D1IQxI52l93LaCMG/c2EFwuUxw6v50+P2uLm6qlthE" + "VPOIw02HytnCY8ScyKOC5vDhRx98iafmrCedBe3dwVrriTDCvguWAbhZuHDfPWM/Ec24QLDQ" + "JzJ1fwp2HsZNfhuRaJkDWDUfsHkew4WycUIlWOQTLYRxnpO/50h6YAbAkLhZBB0fWgRBF0ia" + "waj5IF3hK1eu3LZt22BKSJD9+/fPmzdvBE7EwrrReRthQB6Y4UZws4xNBEE/i2CEOLZLPXaC" + "Rq6bJVk1H6pezZUrVwLAsMr6/v37YTg1fd+LD8y//QnexohGOgMr69E0fSSTugx3/2dSmQ8E" + "eAiCPpHhPeclFwAAxO0mHXI3y3AEqAyrrM+bN4/R9LEAO6w/tgdmZHwXI6bmzLKg6ckiCPoE" + "h/ucP//lOmYsSfVP1zBbEgmA4XV+DqGaP3rQm2AhD82J7FYfbg/MiBnp7JijrZV8seYO6x9W" + "D8yRZ1p2dtwE0SeCGLybJdpEE8OUiyZasRM1dy4Ign6Wk1SkylBJeeI6Hn5IuLIP3lSPnZJ3" + "BJzp3BGkiUw8NLSyXrEuL24CxeE2zIcps9gwFTuWEQR9gpCg55Exjp6HgDQnMvgocR3nGkQR" + "1XwAUh6xhIiyPjBNZ9UcRjwlb+V2MjxgMXHiOtYHQETbfAjVPO4kcDHGMQkkgiDoE4EBex6H" + "dkxQDDUfvJSHl8aT9eFzvwyfkT5ITYfhD20c+WgWQccHgzCwSGCIGbCaH7zsWeYvwROFF8u4" + "X4aEkYxZ5I4z+uqehmQlnh2FlPhApEQY5KAhgVFBEHSBoWS4bfO4hSer6VwfS0R/y90PrIP+" + "QMbhgEmJzgwfffTBl/Yrts1zroyo6UwGyqdPrtr4bgR31tDK+njJzSLAQxD0icAYGS7PU/NH" + "D3oHpuaJG+kRzzIATU8kJe/oBjJyvWreGdURNR2SzxkQkWRT4AqMHQRBnyCMbs5ViKTmyZYw" + "Z9O97HJSmh5+uiH0vUC/kT58hM9FB5ESvCTOgE11wc0y3hEEXWAMwdX0McjYGW0UlwF4YP7b" + "Ig/fOLpqznqZRrEO4wtB0AWGgMGb5+GctUY640aHUCNdcnRmxOXYJC7r4Wo+6m4WXuzWKNZk" + "HCEIugCfZCcnG7yaP7T/6EP7jzLLjJH+3iMr33tk5ehqOhPosvGJQKh+7N7RDRs2DOZcsWE8" + "5pKjM5m/ZA+P7Vh/eH13RDWPXaZgO49NBEEXGEqGxDYfjONlWINqGBhNX1mrWVmrYTcOct4i" + "iO5Jj9b/mSwRTfWBRbMItvOYRRhYJMAn7nA+LkOSeOvReTN4W655JDBE6OBlzw5G34d2tNHd" + "D6xjDfaBwQxM/dBsjjg/6uDHGcWGlzNgjPd/CqNGB4BgoQsMGUNoHY9ZI511vGwrtWwrtSR1" + "LDfNwIdmc4w9WTf6vv95YEDVjAXjgQlX86vyXEN+rkEy6rFb4w7BQp+YjEx27GGduHnOpnsZ" + "HzrPSP/8tRfdDkfsY+ff/sS+FwNSOBhP+uOPPx7to/379z/44IPRzs7bwtSBK+Kv/O1j43Aa" + "47EZpJrHtp0Fs3oUESz0CciozDA5rHZxsr2jw8pwR7ywDId5zsB1rfxu51W/23lV4seuqrpl" + "VdUtm+25EW3nse9en8C5c0Gw0FnOzKQtqTjap0WnCEMHSmR/VR8qPyS8JocG1kjnkpaT63W5" + "w3d2uxyW7ghdfABwd8lTA6tA0/NQcId/4xPPRBTxxx9/vOn5CE9QFfBNb6YC3PlG6L09Gnnw" + "jvJKwaWMevsNB6ymI9hx5JmWmW/fBAAAcbpPeLaCMCPoWEMQdIEBMqz+lnBYx8u8VRdF3KG9" + "rnbvls0RP9pYd/+ANT0iA+4dZRWwILRx3J2FG8pDBP0f6+cOtHYDofqGNwBgJtwUI2vjIFt7" + "gitmBBBsyQCqPqQzIZ0pxAxX2IDZKA1zMLL7i/s9Dcyqqm9EqhsTrt00eBuqo2Jn3H2GaiTR" + "wcuerfrj9VyrfMD5AIY7fpGx2Qvu8A9H4eEhjObczuE4EY/Bp/eKllZo7LtiJgaChR4gqxkB" + "IACoSg+2lzPa+J6W8P1Z30vp8TH0dhzCtnCy075U/fH6yl+/M+DTkXvOgTHmNI9NwR3+iI6X" + "wTBUsecJwk5adOSZlop1iU6HFO0eEwzwUUQQdIEhZjBqHhdG6MdIypfBh6UnCM88986oBgA4" + "OVjpjBgK1ZuOa6fSANsAAFbAPOdKVtZ5c44P5tRjk/7vHqDymwhDvcY4gqALjBUS964wn1IL" + "dzPm/Kjr+3AY6dEIqDkAJDk7FQ9e9+aRXX8IrGCm5RmAccJwNX1gpxsfo4RCv/t4RBB0gdGB" + "Sd7CHSNaXmhnFk41pvA0mlHwNxsvZFZvLNwC/c4Z9lNnJsCcoa9n0/OiGIEuI2CkM+a5vjVj" + "SEpjVXWzPdFDhmqWu7Gr4xOIMeT2FTibKS+0v3777ewy79M5m+5l1Rw4yh6Dg5c9e032E9dk" + "88f4DDkxekdzzbuH++xJMeDeyGGa5S4cgiS4f+E7JJg5jlPIODe5k0Sw0AVGh/D8LTe/+GJS" + "JbBWfGz/DKPpJlegrztdPlyO0XDHS6v+nEGWGR7cIjk6k/W6DMbmvTSldbM9l1neWvkqJNDM" + "4KWCGfCpY7Du5YuKZ6ezq/fMfDXxY7kunb8d+iGzvPvDmjd/u2voKjjWEQR9GIk4+Ig7Rskv" + "AVMO3ZuK3QrABIh8oLSi9Hak6UnCrKBI6DNgqx67UrBXivwijBEgDKQfRD4kdYHCgVIsoOpD" + "ZJIhdhiBVY8tenCosUeGKRHQBCAaRD6QelBR1tV2U5Ol9bTXaU2wQI/T2d3eZu7qtJnNTqvF" + "43L6vV6apgmS/Eoh0Rk0ecWZFfMmaVNV3KPihs0wyt5eV9sVJQ6dC6vsDNH03ScBczpt04JL" + "CYdqEYVh093/MGiVpflpC2cULZ9XKpOIxb5TzM6JOF5oAiypuC8VO9TgkWGaBIIG0gdSD5K6" + "gCKTGFUkOTpz/nNPRMzOyMKYsdHyrJGUjqCVP5CC30utm/c6AGw79yExIfLR/tseexOAjngU" + "AyvrSWk693r6ZJgigKCQxAMKB2i6kb4LCAoBwFM/+ozZ//rfnLPkmsnMcs0Mus8QuD7z920D" + "gKoV/V+Ehjk7SAgLi1x508sONd777G1dWZib72xaVSyfREaOWlksPVI/9BGiaflqtUFed3DY" + "Y08FQR81ejJx4ySa5jyVPgn0GXCfARs6UeFJAsV9xhF05NPtBZhTSOAYjMAvBr8YuxXAvFQQ" + "BnUvyq9BMmcCbwsEpmzcXkD7pPxPMAE+KfikOE29IK18AQA07vogdmEuu7215lRbXW2vKfIN" + "TVOU3eay21wtDcY931RXLF1ROHU6+ymj5k8eK18/PSCgjA89diLGOZvufWiOJK7LJVzffRJo" + "LaZ7MjFmrxMNAOD2+lpNfa2mvm/21/zz/Z33X1e2ck4m87nYd4rR9Gi9oz0ZuKWEfzFpAmgp" + "+KTYro5ctyGPPWd7Jimyd+9/289ZU3b9mtdaVmAAWHLfa3ufvW3Jfa/BlJBDomd/3Fa4eIrB" + "nxVX1iNcTwAAoEnsVoBbAeY03FICBTWE3sS/M5me25pbX078OyaOMY9uKQ15xn557bQ1i8sX" + "3PsSsxoj82X40PHYnPejaUuumZxUg2NgCII+OrQX4raiqHZQdwYWeei8uljWBEbQMJXuSQ/e" + "kaSIVPhEEg8gGmMC+cTglYc8Re4s8PUSyh4ENKZcvmgl+yVQO422aUPudbEXmDeBR469ocJE" + "SmQx6gkAOz5812Wz8TbKU1JkCiVCyOWwu+xBpzlN0Yd3fK0xGHTpAbkk+t9STx8LmGxi5XZm" + "4eh1z1W8eyeNoz5a77UH0qEwI0V58h1OUwrVPQtocXCLyAsaNSYJkKn1LZ29GAMA9NmcD794" + "pHm185aLi3klFNzhrzrDr0/91Fg2b0TiqnnVCiqGkR7NNme9NDf+bnGyVeKB6k+jjjOxPTCW" + "VFw3haZCr6fMCQQGnwRcysBGvwTqptFuBZHdGLh0uVdOZg+Zcs3MYx9VA4BdHXI/K21IFOUu" + "VtiB4Owq9oDMjQCASPp3GGcIgj6MZLQiXRcCgMbykPuoKzug5giDrgulWBAA9KXSVk6K7M48" + "nN6Gpe6oUtWdiblqntGCFiysKLx6diIVs9d1H12/KeJHfhE+NYtmnzQA0JhRbj1S2II18cig" + "Nx03F/kQkZw/OlUjXVaRvnBa2nfeSrE0+BpwWq3H9+xqrT3DrGIMddWHmSH+BOAcMT+3Ys4H" + "NwcrDK4OnyLBCvAcLDx9d2ZC92xgdUDWA9rTIO0DAFS5DgOYn1z/k5c/3v35zuPMDi9+WlOS" + "nbK0IuDzTcTxIvKBtptIsYDYhxDGPhH4ZNgjh+apnfLe9NjHDg8ImHcUgQEAEAaMfnXD0ssX" + "TgKAZT9/9X+vWHBxZSmB0Mffn3r2o300xgCAEFy1ZOp168qzc9SkiLD2uJvar/3sj1tbTwfS" + "ScpVkkvurJh5YaEuTeHxUg2dfU+8t6v1SHduPalyEMvXTpm+NDdnsk6plfl81IG6jt+98W2v" + "3dVWRMvthK6bf8+fe/E8/8PHAMCUg52Vsjsvm7t4ap5GKevosG3/59E9R2qgv/GBsIigND6H" + "+JN3ftxrCtw2Ij+aeghJXOGPUv93B/jvw9fkGgINpb3P3sYs/OOT/a9tPcIsp2kVd146d/G0" + "PI1S1tpl++z16mOv1QLA6p/NvvAnFcw+6xe+4XH6Jy/M+tkLFwLA4a+aXly//ZHNVxryAiVv" + "qL6FWfjk2QNfvnR0gL9YTARBH0Y05sA91Fge3OhQ4a5sDABKKyo+Qcj6kwpktJJtRbi9MCD9" + "GIE5HbKaoxbemRdU85wGIrsRkfOGoEO/firmqnlWE8qt5zcUpG7IbEY1qT0ybXIa9MitM2eX" + "6QFgz7EQo16hVs87/yK309nd3sps6enoSLBMd2svZCQq6Dy4+u5KgeZZFKvmqibQnQCe18ug" + "VT74o1Upcsl7Xx1itjz1n5MLphmQfCp3t6sn4ffDjHQASDWiglqCDBqViP2/98btxduuYz9I" + "0NkS20hPhMwWlNlCQn8OQsnlHfl/yn1r+9E0jeKcKbl//NEKSb339Qe+XXhF6fWrpls/NlVv" + "bwaAmSvzf3rNOf99omrPRzWUn84q0dz6xLl5qxe1aG1o7w6xjFz38kW6nJTfvrWjqrY916D+" + "xz2XXLms+IJfzFk/9WupSnTVA5X/+dOeN36702X1zr246IaHF125pPylLw4BQPMkrDGjaHZ0" + "qUdx/72XtVnsdz67ucvqvHrJ1Lt+v9hp8TC1+sN5e3757upeo/OL5/dY+ly2Stlv71wJGIqP" + "B9WcTbXI/e4A8M+TX5Ai4sIH5ixaWfyD373LbCzb4q+0kwCgNsgffHt1T5ttw41fWEzOZdeX" + "37l+yQvN3urtzZ89d+TItpb7Xr24Zr/R66YAoO6gqelo93fvna7aXA8Az9z6BSkiVv9szrxL" + "in978ftMyU7LcOWlmGiCLlJJdfPzNdMy5AVaqUEpSpEikqB9FOXwebvtzjars67bcqzT0WgG" + "ekST27GYcjAAqPpQ2RGCDL1xsxtRdxawDg2rHmc1R9ZoigxJzpfeOjR16zMAtxdX1xVBzVnc" + "1uQEHSGYnBfFWwyAEMotm8QKutsZJ+P5kNMwmcL93zXFisobCBOO7J+59QfnbNl9ymp3AUBX" + "n/vranLVgsBHMYx0bTcqOhW5X2Tju/cbTs8bWLUHr+nhNBj7uixOAOgw27/7TRUAtJzombWq" + "oHRORvW2ZgDIn5oKAFWb6lw2LwA0Hes5/l2b56gR7W3EC5YvWK7Kmax/8tWd3x5vBoCaNrOp" + "z37RghxATgDwe6mPnt6/891TjHH8/Qc1Nzy8KF0VMCK8UtybjlONqPWD04X9naLsaKaL76hI" + "1Snu+vOnTX4HAPz76yM/WDR5yQ/LGUG/8CczZUrJc3d93Gdy1k+he07i3wIobUG7igsvd25f" + "pxMAXE4fAHSYA+7BXDvJnleTJv/rTZuY3b56+ejiqyctX1tevb2Z8tPNx7v/88c9N/1h8QW3" + "ztjyYvUV985pOdmz56Mabsluhw8AetoSDv4fKBNH0EUqad4Ns9JXTSIk/PubEJOElhRrZcpS" + "AywvBgBfn7tnd6Pp61pHbeSEq8OKxA2lx/hqDgAIg7abMOUEPvDwZ+4N4heHrDLuwtZ3Dre+" + "czji/i2l+Nq//jhuxTryghKGMOTVxjL53daol443aCi3dLLX7VqS51TIRADw5LHyiEdJOE4Y" + "mgrUhAbU4kvh7ZknDnkwBjlNHQBYddjBedfk1iHAPP9MMEJIJhEvnV28+buA42V71elVC4IO" + "X0bTeUY6QUN+DYrfyz3G2PBpFeNNsHY7AUAiD8jFmX3Gi35a8fM3Ltn53pkz+4ytp83v/nkP" + "8xHau2PyNecCGLbWNrHlOOguIALX1+ehtr5yLEUry5msV6VKRWIRAHCT35nT6FRj4MrzBqbO" + "XJnfXtOr/95rnEf6RRgA2npsk6ek+iUg8sLUxTltZ8x9JmdnLu7JDFxrhWMImq3Mea3dbjY0" + "vrvVlleeyu6w5+OawpmGy342J0UnLZ6V8fSPPx/8SQfGBBF0eZ52ym/PlxqU8XcFAACxVpZ5" + "cbk0LeXUH0dh9FrJCTJaZ46cY5h6JVEFgPcy6Myls5pi9aBqeuLXyisFuza4qu1GMTz4AOCx" + "Bgt9aI4kRnbD6ecsBgAnwJPHYlUAoYE/ewcvezbz2Uu5Wx6aI0n88K6s4KWWuEHVF6cmZfnp" + "AAFBr65pxxjC666RgsUTWFabgxezo2InN9/Z4PNwJWWks+GMNB3whgdc6JEuvtdHbfzFSgjr" + "Yj2zr+Nvt21Z+aNpl941+wf3ky679/BXzZs2HLR0OQFArpIAgMURuB8y9PIphSmAaKY/VqoQ" + "3fT7JbNWFbSc7DE1WT0uPwBwHwfuTcir+d/TFJo0xT93/5C7naZx7TR68mFCm67oqOuzaXFL" + "KQ0AcicAwImZWRt/sTypaXLDURsUmjQFG9seOC8V8nh+9NT++ZeVrrh52lM//MzvHbW5qCaC" + "oIu1sqm/u0CiDzpSXa0W45bT9hMmb68TU1islSmL9Nq5ufoF+eH2+wiT3oZSok9FyXGwAo4u" + "0SIvyFzg7jfhW4uxT0JnNSKxL7ISqXvjayUvrEUbLxb+UtFVXxz4DM5qNzIAACAASURBVABs" + "xgbeR+GDhkaX2MnQmXB7djXatVq37iLwnQIAn7hcpw6aDnanx2xxqFTB2++n99/77OPPsmoO" + "AGQHZjtgyT3nQP8PN8JZFbm4rF4AkKVIGLeJkpS6qaiBTyzM20gkIesOm85UdYgkZNHMtBkr" + "8s9dW55brvvLdZ8CgNXs8tCQn6U3mu0AQFjS7p8aNJsuuG3G7AsKX1i3jfHeAMDiqyZxneZ+" + "EfiivIvNHsrVaHnsmk8AwJiPW0r6D9NCSynt99IiGVk3jcYISAomHR/gk46CfaUBnFZPr9HB" + "nDcaP7hvXs3+juJZ6Vc+MP/pWz6nfBE0PbzkIWciCHrBj+Zx1dy0tab+n3uwP3hBfRaXs6m3" + "65s6kUqaddmUnGsqEDFqA4KVtlinJhL+vTObCG7wTGcu7srBmh6k6UGqPkgo2DwUZ0rIuZX8" + "OEM+cge01w2wfYMx9jidbqfT7/VQfh9NY8BgNhkHVhpD/aObB5bLxSfDXBeWPJL3ft264Kwa" + "Yt8pERkSuWnqtX3bGrx6WjnRGzqlkijUdxo3ejJZEjfSWVu19XQPABRVpJ3Y2QYAk1VZDY6u" + "GPszMG2LS++a5fNQnz132O+lavYba/YbjUvzr54cCNKq3ttaM6Vk9dVXMKt9Ld0nbKXQH9qo" + "m0MDwMldbcyn2nQFAL/z2SOL8Bjc/ZcdNSmLF1xellueuv7D2RjDwy8d2X4wcM905uKmxt6s" + "KTqkJMFHFR8nrrxlNgBMre64+y+JjhTFNAYAuUTs9IS8245+08yct/VU5KbugtWlZZWZT9yw" + "qbQy886/n3flz+e99+je8JKlcrHbGf+tORjGvaBL9HLD8hJ21VHfU/+P3ZiO3E3ut3la3j5s" + "WFosy47aOzdeSOtAbiUycmJdaAS9BtxrwAAg9oKqF6n7khB3nlkkielvCSe21wUAKIoyNTUZ" + "mxvMnUZHXy9FDY2oyXJ1gyzBE/rFW0pxSym/bkvu2hKjBKeL/8UrFi/7/r3v2FWxM8JR7306" + "XFOGJsLRb1osXa4r1s0zNVr9PuqG4sUftx1I/PBZqwo66voajpicVm9WiWZpuuzT1oAjfNat" + "qac5z59ILZ66urvNbPtaQQFAhQnmAyz865xtRxqLM7U/Or8CAMgCWUG6pslkIQkCAJCUZEwu" + "1meNaRpj+PRvhybPz/7le5dStBUj38M3z5uS204AueGTKgB4++DJ35Qv/fMtKw9tbVp0YY7f" + "RwGAIU9VMMPQdDShrjJThw0Abl41c9/ptil5hqx0/O1/TgEEzvuzf12w5V/Vzce7CYLInqzT" + "pik+eno/QaLsUt2VD1Y+e+sXbqfv2I6Wr14+ev6tMxqOdB3c0sC6ZbpbbQCw6tbpp3a3508z" + "+D0UU/KQM+4FXTsnh2tud3xyIpqas3i67RNA0AEgr5ZIseKWEtoTNrLHJwFzBjZnYACQuUAX" + "NgYvHDrUwiMT0Nu7S55KZCI6jHH90SOnD1R5XJGEbdBEnHqUJe7kc/SgHwKv389Lc9djDfmm" + "GWJGqQIMuYUOYUY6z1Mfjsfp/8ddX133fwt/88kap9XzTs+ezzoCMddsHPp3T95y/5zXAeCR" + "zVcCwJJrJpMi4s3f7jr8dZM2Q3HFurn6LCUA6jXaD793+vvnAqGcTo8POC2e3DR1nrZg46dV" + "zOrrXx/J0CkvWzDpysXlh+s7/++VbU/cfv7ymQUIwQMvbn3uZ5dUFAfzSrJu6/+d/W9M0ZYu" + "5+M3bPrTt5cSlAoBKSLwdcvVf3490B+7ed+ZTF3K9cumVv406/v/1nz89P6FV5SVzctccvXk" + "BAV9++YzJcuzf3jezLXnTq9uNO36OHBBmPNedMfMFTdO1WYqfW6q9VTPN2+fBIBL75rFxKEv" + "WlP2/uP7AGD5DVMA4JbHls06r+DF9YERcN9/UFO+KOf8W2esvHl6wxHTZ89HDl4YPONe0JXF" + "qdxV64n4Abze7liyQmCg+9UvEf8HHtXYBZ0JabtISyqYM2iLHvsj/Z5uOXQUxK8kT/Lp5FNx" + "RjTSacq/9/PNxuZG7sYUrTY1K0el1cmUKRKphCRFiCS62lpP7tuT5DmHABQ60FTuQBJPhN3K" + "lwRcCjTiR91oVQpjqKPGG9pm5wVWp8vJgPf8wAEAgLlJTx9auZ2MMTAdEptnqu20mc2dAgD4" + "GQwAjT/u+dPb3/3p7UDzohJIAHjk0pDsDk1Hu1976DuIgig0S2Jtc8+zz20CAE3gFqM3vHF8" + "wxvHwdLL7HDD3W8zCxpAD/x2MwDkNCClNbIJYjO7KLIPyMBMjx19zq0H6oEEAMAYXvzi4Ptv" + "HCo9FggPTXaovdPh/d/nvmBXKw8EX5A2s+u9R/fyHCkA8OnfD33690PcLfcveCO8ZJfNu/GO" + "L5OqzMAY94Iu0YYMKvH1hs3+GYa3J1aMM+kDur8NTiVweZh90OgNKUYYtN2g7SYAgSMFW3XY" + "pgObBtNJ9gmRoc49SgJEJF3jEddIP7rrO66aG7JzZixepk2LEMDuccb/7aIxZ9O9O2+PYKQn" + "Mje0yBvytjMYUWak8P+8hd3Qnyw3nFPHYoUYM+nSYrBB9+xT8H3cqrKYXFTBZwAATZcENw5H" + "TPoAePGHB897o4JdFflg0hGebWABALxgBUTKGdBRsVNpjfU2YjPSuDzUj3++kwoNbesz4I4C" + "zKYQONsY94KOxKH3SgK/o6cnloUu9iJff7ygTxp/ChOfGAHgaOElIwoGpQ0pbSirGTAChwpb" + "9GDOoN2JjaPkTYTtUmCxJ+kvxTPSnXZbw/HgEGdDbt7iy35AEMOShb/4oUsTybYYjsyFEA6O" + "+HcqY/3o0Wa64KGQh/SaZt3qN74YfNYY8/zDIjMUAQCs4UcJJUHBZyGrVZeMvqbLQgfZ01F+" + "7WjJeBNpWzARkPXTaFc6BgCNGdFEMEyrrYhWWomI44kmPONe0ClXSE5YWY7G2WCOfUjvvpZT" + "vS4A8PdFMAllTnD2N6nDpVCSptRX5qnKMxQFWkmqgpSLFxIERfk9Tg+92uFs6bOf6bJWd7hN" + "SQwJIySkqiwtpTxNUaAX5amWpyukMilJkACY/onfa3Y6m3rN+1rM3zfS/bFQNAKPAgBA7IWI" + "Ie0IQ4oVpVghu4nszsKNk+K3IFKsiOtksuhx7GBHQkrq5uSqZ2b9s+QMnQaKFDVBki67rbtu" + "t2HSHBctcmGys6kRcwK1ps5fmIiaq9WqsklFBpFbjCgykHEDURhoIPwY+WKEc4aSiHkOAAQF" + "Cgc4+n90qx5HNKiZqYsAoNMWJ87YS2FDZmZ5eSm7RZyKy38H3dvImx6fBgCPKS/Y6spmP/2w" + "yNzTdCRaaRSGLi9xC/nXIjQrjchXgJoAkvqv39lp7zvTY9zX3Lm3BVOB37fgMzBBsHLpcrLg" + "x5XZV0yLUdvD93zoao0QSHv9DVekpxsg0oCtfde/QbkDz51ubi6ZEpaTk4NIJTWcWxLdfdna" + "d7DVl2QyXgDozA3kMpK4ofg4wgQ6Po9i81nWT6WnHSAi5W9JgrjtqjHIuBd0V3vIvZh92ZTa" + "v8eJUvKand69UZOkKK1g7vcH2DTBZ1tZnJq3drZ2bm74CAyRSCRSi0CtVE1Jz7hgEgA4G8xH" + "f7GZjvncE1IydWFB6uJCTUUOIY1oVSFSIZYrNPJcTeriQvcNFWce2+5o7AUAnwyOzacAILsJ" + "5UQfnQ8ACENaO3KmxL+zlRZEUkD1V6QnA+c2RHYlkQpx9g+mZ15SLgp7kpVqrVKtBfApCZ8f" + "o+7QEa0RPS0hO2jUi5ZUlpYWAgB3cCYCLEIAQEmif483H7y+9Lxg0q6k5irSmQhHSuCr+iRg" + "08Z6mZ0weftcsV6QTi8GdfoFF/K/rK4C9nYAAKwqMHG3W/rsb22vhjD8GOodRJOb9NGwiryV" + "+xGRQmpSpJqS1IKLJ7m6HMde2Nv+bQQ73+Si0vzDq0m5a2ellBhi7KBWq9TrlsbYofrnm/xR" + "ZrmLNie1TYubS2kAIGgoO0aK/AAAZceIk3MCmTf9YqiZhqccQsQgup8xAWjURggNkHE/BV3f" + "wZA8JmnnleXdMAsGEWau7g1eE0oEVj1GBJH/w7kznlytmxdBzSOiKNLHDnWX56jnvXJ96X3L" + "dPPzo6g5H1mmuvzh80WKkCC7GOkBuDAJHWNDYEg1Br+7Twod+RFkSzMja9aGNbnXVoSrOQ8R" + "wrOnFS1btiB40WIOq1BJ8Nqbr+xX8xHF0BGSEKq1lKZHqr3u9fr/+9rX9rDAxx4fsaNHXOsk" + "ffEaV/I0ZeWvVhY8tmAQI205JD4UYkgJn+WON401u+yTQu00mvGK5Z8hFP0DJpRWVHAmeAM7" + "VTjjF5lPnUhi1j2ePR4xxGCMMw6rHIqjpttytEMzI4vdknvdLNX0zIbndkdsSMZFYQe5A7Gp" + "r4zFaP6qc/UL8rn7OJv7TFtr+k53Hi6yYglhUGlmkzmGhYWJR0MScgmp4JivNLaeMlkOtxu7" + "uk/prX6/XyqVpKUZFhaUqyalsXtJ9IqMiya3fRD0SrvkCT1+vNwv0chqRt1ZQadnWyFW2EHL" + "ifgyLCsqXbcUcdwmliMd3d/V2Wt6fBbXay1/yCwomXPuxedd92M2Mcus2dPdHu++vYcAoNfU" + "acjODT8vxuAxNkwtzuJtpzHyAUFjhBAQgAmgRVHawA/NkeiLZvI2mlxUghPOib2Q2YzaCwOF" + "O1KgcSpdeIIYPnFjZoDzuL3vv7q1s61bIiK9nKFw7R7iiJXkvv6O4R27qffr8SErdBFYdOfv" + "n9TNz8+8aDI78nnW7OnuRwLXGQAqt5NMcOSZNw/Vf3AMADRlqQseXsW1dao37jZ+3+TudWGK" + "Zi8U6k8r8cnHWwiCvGhaZfbCEgBwt1tP/n4r7fMDADVsQ9vR3h0YxZoOiUZQM53ySwAA0jpQ" + "WugsE2ntyK4murMCX+Gz3W3Ti7RPn1yV4Fx9vCm9XClYknw30ugy7gUdY6j/+67pf71MrA4G" + "Y2umZVb87YrOLWda3z2SSNwLj6xmVD8l8DDNvXyhfkaImje/cbD9g2OYphum0lYPBg+ojzpb" + "GjpbXz9Y/vAF2tnZkYqMhfGzk63/qfZZXADQm4Z7p9MAYAPo7jKnPFdfcs+i9JVl7M66eblc" + "QXcrwCMDqTu81CA0CUzC3rhI3JDTQARHVCOonU5lN6HMZkRQSFORVbpuGdvyoJy+M89+W9vU" + "7FLivCYCANaqHthYdf/Jqp1fv/vyL1/4wJAdSGi3YMHs+rqm7m7z8d27llx+JSkOeb247Hbj" + "6eqlC0LkuLmpTZZT6sF8OUYIizDO5AzU6Wo889Dq+dG+UeKantVEWFJphypwoXrSsUdGF5xG" + "Cjv/kV5RogAAiqaPnmn7YvdJmsb/d9uFH3KiXLRyYkWJorqm7d7H32c3pmqV3573597zAp2Y" + "kuoKTWvZit33t/fYNArpmiXTXv3yIPNRfl42V81FCGZpqJtMa7h1sB4zWo8ZO784NfWRC6Tp" + "Afc/e52Z1cAXpylwUABg3N184pX9U2+rZAuZesu8rgNtjP/d5KKy7sgGAEoGrSsBAJxOd1lZ" + "EaPmtMd/+rFtbmNgrkG/GMxZtF+MshtRxMT653x0C7tsMnW/8/bHAJBiRRGvJwNGYNfg7iwM" + "CIr6PTDhtJTRTBo1hQ0Ye5wXcV94BjlTwNk/ieHT754szQ2ssLlzeakWWXjduaZsWtPDv3n8" + "YjCnB757xEJGl3Ev6ADgNtlP/PqL8odDknMhgsi8uDz9vDLj5pPtHx7zWWNqXij6TtSVhWxa" + "XFCYO2NGSGrAhuf3GD8/5ZVCSxltTsMAIHMGotwwBndrHyQv6J1f1TBqHgEaN72yP+3cEtYo" + "luVqQj4nofocSmEDbTeh7gOFFYXk7UJg0+CWEszNtRubjBbkTEE9GcGp7NoKcWcOTnfI59y/" + "nFVzmqa3vLWlTtaJp4C6N3g4E8VobKr72/pbfv/214FaILRg4ezNm742dxq3vvNGwdRpGr2B" + "EJFuu93U2tzd0nTD2jVcd8HePYf27Tu4aPUa5ti0nODjhzHyJRLJlDwEDWXVxOlZFJsO3q7G" + "xytxihWpzSB3ItIHnU7kpfBbn1Wdbuo8dLrN5nADwLI5pRELnFmWs3xu6Y4DtcxqT59j2n/v" + "nbXreZfORPhFM00PyiyGdrCJSeLXa8/t6A04DqRS6QUXrWDVHCGo1Pp14sg/n7vdeuaJ7TOe" + "WN2/c+A6Q6QQxnQ5ad10vHd6hq6/uSlSiuc/fN6Oez9hezgBgHSDyAl+Beh1mlXnL2M2Hn59" + "p8neS6eDSwE2LW3TAkaQaoSEosr6Cb+eAECJwSMFhxrbtIEEDMwgOLR3x9bKHTwfencWZrJP" + "i3xQdpxgOnh4UTGIhrJjZOP5pMXuBQCfn/7VC4dzxAnFoYk9IHUF3Zh9BqiZQem7CJEXaNGg" + "vvuIMREEHQCczX1H7/+0+M5z9IsKuNsJCZm9ZnrmJeUdn55o//i435ZAZDUAwlBynDg9h1qy" + "JMT0az7TvKPjuK8SXP0REWIvlB1FzPy2AOAyhiRAMebRTv4YFDBl01YtSsukGYuU9lGu5j4A" + "6MnAFj3mZbGon0IDuCabrOrMQA46cSTPtVMFThXdDgAAEg+IvQjRmCKRRx4nGp19YC5NaWWa" + "pQhD8UlC5KW5E2j4xVB82QypKtgGOrC/utbRGbELhtH0+mOHqnd+PXPJeczG4uICuVzucrmc" + "NuvJvbu5+8+dN1OlCr6Ja2sa9+07iDHs+uRDACBJ8vI77uHuv3/rF3kXB59hiVIz+aLbAUCs" + "CJla2tRviZqAkpDBZ6/wFBFx3BAAiL1QfoisnxIytbddzcz5iQHgTCsAoL0fJhowvv7m8+pb" + "u1s6+9gtKcbCFGNh8Iwk8au1584oymAFvbKyQqEIXucSORVNzdm8iX0H27RzcpiN7HWOeAjG" + "UPvszhlPXibLCvgGVYW6heuX1j79bacz6EVRN4BtluiSS1eJxSIAOHTw+E5HHVRELDI+PD8G" + "93rGhdHxtiX5jmUasPRa+wMTCQoaJ2FVL85q5t+CHfm0TQeuLprNgNbV57bNQVI39u/WkzMt" + "SBnLX5TZQjRxQsL6DNBnGE/T1o37TlEWn9V9+vHtp//0tbudPwk9IRXlXD1zzgtX515bQcoS" + "eoeJvbDAnZOaGpIn5Jvde626oJqr+tDUgwQ3U4q7I+TUVh30ZAZTMzM41NCTiY2krfHlqsaX" + "q+qf2820eZ0q3JOJeblDmcO9mPNMEAgAJG4oOUbouoLvEhavFBwqbNeAKyWo5hE9z9yOps32" + "3OC86Rjya4nJh4PdTWKJeMbM4OTBfoo6dCiQCZf0g8bMv4uYeMFD3waHxiGECosieM8RQrNn" + "B+eDxhjv2rUvdka6rraQbnBCJNHkTtbkTlboQ9pGrrTgn0WP2b/Yg8VEPphUTRQfJ+QJJCmQ" + "iEUXnDPllssXRttBpZQ9/cDVM0ojN9oydSlP/OSiheXBy8K7zjRNFyXQtOrdH7wg3OsccSip" + "3+k9/dh22hP8yLCsOOOSKelysuP5duavpJu88Jyl+lQtALS3G3ft2scrBGFINaLYGZtZpC5I" + "8HoiGlKNKCfMleG0NFpIs0WP2YBVrwws+pCptVhcSrDosTe0b8mtwBY9pk0y8Mepc1o7ij37" + "c1LffeSZIBY6i7mqpfdgW9rKkpxrKmTpIeYxKRfnrZ2decmU5jcOmLbVxp2xKH1+IXe1vc3Y" + "12dFNEjdKMUCqZ0E19XA4DbGS1HYj9Ph7th6PMGdw0EY9F1I34UwAbYFM+2kxdXX4JaDV4Jp" + "MdAIAAPpB4kHKRyg6kPaLoD4o2FCUPeiaftJhxr3GnD6kgLGWGNorW8TGT0ZdqTuRereKJFh" + "Lxxo04SE4KgIl7W9RqHPFstTAECmVMos8tLsEoUiuFt7W6fFEnINsR+3/DXQZ5D38xkPzZHM" + "uuHXyX2T5Ek1oVQTaVfjvjTsUIFbgX1iwAQQCCQklBRkleWlVUzOXTC9QC6Lk3U9VaN85sGr" + "C99bYDg9T9mZJ/LKKYnbkdr+f/PWXji3VCwKvHJlSisAFBflc6+zpbtbnBk19RibB9HV0sfd" + "npWZfvJEYLqciGNHnU299f/YVXrfMnZL4W2VjvoegICLOfOiKUWziwHAbXNt/XAb+GgggaCA" + "dIHYCulWQtcddXbmyBchyvVEGEQ+kLqRwgaqXqQ1DyrKcEhAGIpOEfou3JWFHSrsFwNNAkmD" + "xAVyO1L3omS/+wgz0QQdADBFm76q6dpen7aiOPeamdL0kJa4WCsruWdx+qqy2r/tDLfluain" + "Z3JXfVtb447B85gc7R8f768GnlSdxGs8r5bIq438keyyqEchGtS7q9XsQOpdEWIDmLb5svAP" + "AF6//fabX3wxRq2UVqS0otJLQ2xM9J1xyqH4PY220JTQWq3q1GcvcLc8etCrIb0AwYi9lOz8" + "NXdFGMrCzFZxFxy4ay0/I6AMK+Y5V0asANq7g5sGK8He0WBlrCglNKMIM7Do7geuTaocAqGe" + "0sM9pcF8TOFThl6yMOeShTlVRl0DJzJrcUkqQPz2Pq9/SKePMkMEh64d9VN+s8zX34+LCGLS" + "AysOOE65KEeGNKfwtkoAwDRd++g3ZSe8q6oCkya/Nf0lAEiTD9B3HH49E6TsaPA5ihEAw1B8" + "kig+Gfkj7oSisWHSUCdcwTHEBBR0BuynTF/VdG2rS1tRnHNNhSwjRNZV5ekzn7q89qlvzfsi" + "jzBCIlIR2v1or4mfsA37qaZXqgZTbQZCTBIyERIRgSSiovhKFG0gdQy2Vr56c1VAzVkfekR4" + "GdCcCcSD3v2XHfJcDWwIxmbo0vlRiQ/NkTz04ofTOPEM/7pnzeHvvopW5j/eCiSxWvQQZzCw" + "yxXt++IFy9MAur7Zxq7GrnOygxUTRHkw0bmTet0heyrJQCNS35rB3X7XkwcAglVlh4kGjkoJ" + "Gd8cLcGLRA2UF+j+l6lEL79AedVXpg8uSL8akQQANL6y33aik+uXW3vsNkbTY7Oq6hZHW9y9" + "BggTqz5Mv9QEYMIKOgOmaNPW2q7t9ennlebdNIcb2kjKRJN+ueL0n7/muiBZpHo5b3SSJ2F3" + "SrKQSom2IktVni7P18myVBKdYsDTKrGyzr3jA23zj4rC92cH4MUO05WGOq+mPHz+AOqmVGnC" + "N+YUhwQRGZvrB1ByNHiPfdc322Ib6XEVH+BrdknsC+Sz9okjT5EajXDzHADsvRkpuk6nP6R6" + "VX2Bx/MNSWg2i4cAIMKvySCTJPb+QCDVg7sL2Kmws6QF1+bcKSPkANCzs6Fz04mEyhlxBE2P" + "wQQXdAZM0Z1fnunZ3VT6s8W6+cGgckSgkv9dcvjOD/xO/ji9kFE/AADgtycUIZMUiiJ97tUz" + "9QvzETmUfSxo3w73Aj0AoPrT7MaWw8HYDHeX3ZMWMj2NtCsNokPIExuYFBO5TM1LzUiSIo0h" + "ZHy83RLWLxFGxAwtPo2VjhK8ogGw+WgAoK1Kk0MeQ9PjakTTXlHBHf6NTzzDm8AohqYnbp7b" + "ezN80RJZJQMp4j/UEY30rZWvrqq6RaoDN6flyai5s7mvbsOu4Z4sbTAImh6Ns0LQGfw2z+nH" + "tpfcvSjtvOA4HbFaZlhebPw8bPaQsBxSsROzJAtCkHPdrLxrKyJmKfDbPT6Lh3J7sR8DjZXF" + "ekKaxC+FMXbiLQAhZlz1Z40hO4VaeLEFHSB+1sm4MJHmrBxvrLtfqlDyJob2uKJmNo6dacuT" + "ZvLqo74MAr9lXS7tSCxVwrAR0TwfLZj2Wdn9yw3LQu6G5tf2s5HpjO4zy4n4W5hDuAOLhglB" + "0yNyFgk6AGAa1z23R1FiUBYGgwfU0zLCBZ32+nlbCKmIcg1Z93bezXNzrgyZSdnb5TBtr+07" + "3O5sNFOhEw/OePKy2PmPhhvK6eNmbjnxyJeJ9CjE5u6Sp8Ra/kxLP81/LG700SBJfOzo4Enc" + "PGcQIfBxvv18rV8jwgBQ1D6Ju9ttG76JeDg60J+WLmzkbDRPumZaZuqSQt7G/B/Nsxwz0p6g" + "pnM/jX0BGfUfPh86FxQlpdfZzPgVdOxXuHwaC5XioORuWuTFJA0II0yAnyB9EsIjEznlpD1F" + "ZFMizuga7Kfa3q+e9POgt1SSGiGc1RuWMECSqhhYcphwUspSeWre8cnx5tcP0pFmCh8LeLsc" + "XEGXaOWUI9b0oTFgo93vm7IVU3ztJkTE0LaEIjJ4TfeJy1kfOgT86fwo+3A1j2ueywns42QF" + "89BITGAAcELIjUd/uz2iccr2AcyLFPSNF/C3SGuqyh44NzyLnCJfW3LXObXPfJes14Xbgzoy" + "ROw0OpsZj4KOvbpeV04HpYhw22JEg5j2i/2gcHp1AAAIEyKLStKrl5h1iCIBwFrdwT0kov+a" + "dnp9Vje3E1VRqB8qQc+8LCQ/dc/3jU2vVA2hyxIB0u+r5G3ktoLrvt56au+HiRfoaOpVFOnZ" + "VWWxvuubugFULDh2CeDpk6vun7YNY+A6XUQpUq95IPOOptRGGH9vnh8ScZQiJmKFqY4BVCJs" + "9Qcvh9UHOWGzxcaAK2oRRxVxjXREEpOevZZpJHntVO3mrvKrMghR4OyG5SVWt9Z4MPSC9ccL" + "jTUE9wvLOBN0TFCOkgavLn7XWfAQRPu0Fp/W4tdYlLUlAOC3h1iXER0pGIO9pls3N2h26WZn" + "9+wcxNQyHLSzQgL4Oj4+PrQdUNGySAeRJqMTANbjxrRzS9hVzawcgCGIzsQ07et1SvTBMDtp" + "RkpcQRdrhsAPPqyOF4wHYp4DgF6C2zgx5V1eYkqUOPS4EhZx0lGu46XgR3NVuTIAwDR95o9b" + "bKdMDV1lJfcsZncuWqVzfL3bfiaCby2BcCBOVYdngir+WQRNB4DxJegY0bbJNX5VSPggQYgM" + "xeVyUWr3lkbAQIl9lMLpV9mwKGrLXawLkTN3Z+R4xL4DbVxBPL3ZxQAAIABJREFU1y8qFL1U" + "FR4PkyykTMSTJEdjnCmWkoKXRTqypnuSSFUGAL17W/D/0OyTqcjXKksNjtqQRz3uNPMRcTb1" + "cQU9pcRgO2ni7cN9PyEEJfcsSvYsLOlykh1qNEhN53pdfOJygGC2xfBegAT7QjMk+BgKJo23" + "U6jPh7RRcrkMhtTFhVmXB5qJja/st50yAYBpa43vFmV5yixmOyKJyQ+sqF7/aXhiu2i6yU2n" + "xUKoVAm+AAYpx4Kmw/gSdFdOO0/NpV1pM6+9Mf2cMo/JZvv3f9ntGGGfts+T2elTRRBr9bSQ" + "IaDM3RxOz67GwtsqWYcMKRdnXzW9+fWDg/wWhCTsmsceDEggMt748iGE1Ttq4W5WoH1Wd8/O" + "Jm4sRP5Nc0797ktuwyLBqSC5PnQAsJ3s5CYc1s7L7QgNf+a9n04+fkhXGTn3KQDwpqu+Yf4N" + "3NWd3R+drjsNnMmM2MpIJPxc6tF4HB5nl7nRiogjxG2e5EJZvtwaHAZgchOyohmqtMA1OeMg" + "52v5/fMJEs1IX1ajL/lZ4Mfq+b6RG2++s+dzgyTTIAk8IJI0Zel9y0794SuccE81Y0As/OBH" + "rGteJPYnKLKJG/5u2AcAqCUwakHcpyWdcuBoOpu5jD0kbu7cicG4EXRa7PNkhTwnMmOGojlf" + "LJYDgFin4D5RCCNJr07Sq3NldbjyQsYNIQSZlwXzH2E/1VsVeUCwz+IyfV3LTCnHkL1mhuWo" + "0XK4fTBfhOfwAQBppoqXjiNYWwIV37VYnpPovBmD583GC5mFGwvBBEEbtvXdw4blRWyOPO2s" + "7JxrKlrfjToTZjR441F79zXnrZ3NrmoqshUFOmdTZJeazwn5N86O+BGEqXlcmG+62Z4LAB+a" + "zWv0+nhHxEJEIF9/H68a0pSgdUDgN41rnn+8KSSl+KzVGlbQu72o1jmUriGxWDT5lyuZFHWu" + "Nmvd30Pizf3Y/6Xp/atzfiJBgT5w7ezsnGsrWt85zCsndoOMdvlIZcAKEWvkohRpIsM4Ejeu" + "XUzvSH/7WZk3g4Bgv1RSHqEJxhjNGRaON9WMORNcIp9I3hr0hxBiMqUsQiS1yMGPYMm6Yhp3" + "DqDOr2pi5NRtfecQ90ZEBCp/6Dxeht6IyDLV0WYvwjTNyyGTcX5ZxD1FKdLJD61MXxU53XY0" + "uD6WqD708FotWI4XLOd2WjJ6xxrsrlaLOCR7AuStnV14ayVKIC2BWC3LuXKGsiiCYjoae7le" + "WoSg9N4l4aO6AIPPCt5eAICI/bFJqfl77Q8wC4yaM3xoHpTjSy4OiRWpIKLOfOaiUF/M3Nzp" + "khBz+IyduFH0RxHwW2kobBaI8OvMC1VECM5btVSeqwEA2kOd+cu28A4kq793W9dH3C25181i" + "0/OyxG6QeXpCOkLCD2eRpadwn8eBgepPMzPYsX93/2UH1zw/exg3FrpPExJhIjHrUeiwuumP" + "X9p7oNW46YTlSAfbQiR9nMcAodzrZ+VdPytYZq+r5a1DMU7qNbvqNnw/+Zcr2C2ElJz84Apz" + "VYvxkxPW40ZeU1RqUGrn5KQuKdTMzK55cke05F/mqhbuROyZq6d5e5wdm0/h/knICCmZtrwk" + "74bZYt1AOgAT13GWfuMoggwxmp4uJyUpQHuB4jhUsy6fppuX1/7RsZ7dTeHvRUmqQlORrV+Y" + "r5ubi0jCdiY4NpXrFm/9z+Hy3wTPqyxOnfnX1S3vHLYe66Bc/l0/+GDBm1f67ED7AQBcrZaC" + "tSVOThsJISAkpFgqBQw+b6Kjed9rf+BNuDDBnRNBKyOs7qDBcR3523r6kBHqWPPci1GXB7W7" + "iS4vKlNSMTzjGVKalOIuzuRnFxN3zRZfuJn+exW9yY75L54Y1xlCHS8zK6ZNmlTMLNf/Y5ez" + "OXK7sNF5pu396pyrA24ohKDsvmXV6z+FpkSjvBx13Yr8YI6w/B/Otdd2cx8HkUqqm5trWFas" + "mZ3T+p/DvDoLDJhxI+iUPCQwXOwImzkCQDc3Vzc312t2mvc0W451uJr7fPagraedm8tVc9rj" + "P/3otrhTXpj3NNX/c3fxnedwN+or8/SVeZTL52zp8/e5AAOpksoyVdz+vRh0fHw88+JyNmEL" + "QlDw48rcayvs9T2UyydWy5TFqeynPosL+7EkNVjy5AcDL5jWD45yeyYJCYnECTXPUdh0wkwD" + "2UsRCGFxpJk0TS7qrRkv3XD0No85RNNl2eriuxYV/c8iT4fVY7JTbh8ikEglk2Wqor2Nwrtt" + "u79t4DroZdnqsvuD2SE9/bLjs7hS52p4dZdlqxe8e/MCuLmjsfaB1fMB4Ei/rf3Y3Xdz93zg" + "T3+qXBnMy3hj4Utrj93G3eFIAkb6lijJKXM0oua+oLM7FeU8LtnTiKsPWEgakJNCjmQ84XPU" + "/oNWEVfTM1HJbeQzt5JPd0K9/BF54Dpnp8vuvC72W5+QkFIpCQBp6YalywIjjk6dqrXubyVl" + "Iu5cRSwSQtr+8XH1jCzV5IDtLFJJJz94buf/bcF+GgAQpmLHZfV835S2ItiylBqUszascdSZ" + "vb0OQkRKM1Qj6UU8qxg3go7FIW1D1D8jt/1Ml6Yii+AImUSvyLykPPOSQIfVlicP+T0uAOBO" + "beHpdpz5yzZ7TU8ip+784rTX7Cr92WKRKmS2IFIuHlhr0Wt21m3YWXZ/SHuZVEq4U10z2E50" + "nnlyR8EtlYalQb1jfT6m7bXckfLZV87gvrFiIEnje6Lmv7kWAD6qBZXEf3GREQDW3eJjHOjc" + "DLRvz3iJIInZP5qdc81MbjgaQiDLjuplYuAlBeRS/49dskxVyqRYo2G9ZueJh7cs/nBNjH2S" + "4tfHbvvj9KCmFyd21IW3377lxRc3PvHM3Q+EJJjPSBGlKsgezrw/BJDFaHZnJIMh/IXKg0Qw" + "T+2vdRK1zpCpohGgTCiBmD8y7zrn3ThnwRXTePuUl5fCm6W9+1tP/TFCWrYrs27Tvp7K26gs" + "NVz87o3M8r7r34j4JmDpO9BqO2lSTQkm6kEESilLBeAXCxApKkhgoIwfQedNutP/RLS+e8T4" + "+SnDkiLD0iJVeXp4ahS5WmfrClr3tMdv/OxU63tHeMPrY9O7r/nw3aaca2dmnD+ZkMaxgmkv" + "Zd7daDsdqxXZ/W0D5aFK7+G/JFh8Vnfr24c7t5zGNOZNhDSsmBqc912yFQBQf+dSemhWcZqi" + "D7x8oPu7htxrK1KXFMaNMqZ9lHl3s3HTiRjNasrtP/HwF8X/c45heUnEHcxVLfUbvo868+pA" + "YTSdXR5MUQjBWsvk+0VvFaFYcqsV40I5/cj6u17YuCFugWVKOltK1zjJFjdNxntUE7nOIwam" + "8Zknvpn8q5WxU1Y4ars7Pj3R/V3jSNVr4jNuBB3RBCaCpgcldYshkI7Vb/MYPz9l/PyUWC1T" + "T89QlacrCnXSDJVYIyekorKll7rMPZTdixySmqe/693XnHRKFgJ7VRaX2m7eeeTIfi+W+mlM" + "IQSESCxRpMhUWqU2TanJSpFm4G6R9USn5XB7Im+L3r3NB6s70s8r087JptU+u7XN1tVuNxkd" + "5m6v007TPowwzAVEE/b6Ux3vfq/PL82eMleuGVQwRlKw46rTwiaLaKoxN/1pe06GUjc/Tz0t" + "Q1GolxqUpFKMCIL2UvaOzo5jh8zNtY5ek4+y0wQFGkBzCMIrJZ3yzRf/9YIP7hbL5cBx91Nu" + "f83T33VsPpl54WTV9EypQYlp7DU7rceNXVtrrScCnmg2V5THYTOePmxurrF1dbitvX6vBwBf" + "ddVVLpfr3Y0bdenphsxMSIY/Tn9pMJrOjCR6xHfhQmLNfGJ1IapIJ3IpDASAjMQpItCJ6AwZ" + "TiExAMRV82CxIpilpq6wTZ2LLi4nFuWhaamQq8Qa5jr7rG6Pi3QcqS/64VRCRqoKi2qeitUT" + "6Lb1ddYc7W2ps3V3uK29PrcLV2JEBX4XsVVN+DAtjtN6aD26p2vm7tj7SLsM0FB0d5d9IY2v" + "N7uUxakitYyQkrSXaq767viO90L2nhdclLVnKloncljhcINiJ7EbO1hmHKc48xKKnEr18SmA" + "h3dWEVrsc2cbPYYuTCaUYITwSaSdafL2yHNI8sAE7dNYfPpen8ZKJzirFUayznR5cx6Kl/uQ" + "G68CYcGC3rQee1FI5vHwVAH8M/dnQeLKOgN3eI5PZfNkG72ayL1tLIgmpcZ0eXs2SixhLDd6" + "nZZ6XLltHr058kyp0Tnvqqu4PnSWZI10xo3Oc7kkMjT0jbff3r13b4K1jY1u3zzmHsALlp+/" + "ISRXYsQucZ/K1jmjQ+GP06uJRcg2SWGdnjLz5/nhnzI/PZFpJiY3xi5H2mVQNhSFB4NDpHuP" + "C0/QHUUNnrTBpoFjaLk+g2m+C3HoYwKRNYUr6H6Fw5nfomjOT2z28ORB4Ek3OfNacTKzHNJi" + "r1fXm4igu/Jb3WmmBN8TnFphd2YnJillQ9T5DQZGxGcv5Mz91nr63h0Q6lhnltNU4Cxo8qQm" + "1C2BCcqd3eHT96pqyghXnDwErJpjjFdvTP33K19y22pDyICN9IEN9B8ZsIhifhdFAr2yyI/V" + "JxyKVg8tTw//XbjjbBPh7AwcHF3GjaBLu9I8GSFDOt0ZnZTUo2woJHxDMP0CF4xoR3GjN0yb" + "kF8k7tOI3ArwE0DSlMztU1tp6UAmvvDoesLVHPlFYkcK4ZISfjEA0CKfX+H0q+w8U9ST1i3t" + "ShPZI8T5DDds7DPPsY7kHvOUWiQPuRTIT0qsGsIlJ3wijGhK7vFpLNzLRcnc1vJT6hNTCU/8" + "obAY43fe2fbFF/uGfOwE15M+SMcLw0iqOdq7I8bsRZTMbZt8hneLKpWy6dOLs7NT/7W5EYDO" + "afXxfheR1R/jd6FtclyXkyJGCCF3ppEOjVaQ9OpIm1LkihruRdrl8uZcAPCkd9GywEll7ZlM" + "mEPE6DWBxBk3gi5yKqSdaZ6MkA4fn7bPMvOovDVbaspAQ+V+QeAsafDqQyLYEE3IW3JlXelA" + "886C/QqXK7fNp43jZIgB6ZJJzKniXq3IpQhvcNBSr6O4npfDwJPWHVvQwwfZxyZxY4rrWH/m" + "VTEAdHdb7v/Zv5CE82BThKI1V2pKQzhUfRF49D2OwkYgAyY2LfbZS+vUJ8rjes82bdrzxRf7" + "eBvFVrXYrBM5/5+9846Torz/+OeZ2b57vRc4jjvKoQiKgIqKIhIbit2YXwwqShRji5hiisbk" + "ZxRrfiEGRWOJJrFhjb1gB0QFpAnHHXAcx5W9tr3M8/tj9uZmZ2dnZ+vt3c37ta/XzU7fndvP" + "fOfzfJ/vY316110cx+n1epPJ9NA//9nb2dl16NDWDWoriIk1PV7UFz2vKC+fPHFi5Pwd338v" + "flteVpafFzZc31rvJ+K31VsmEALhX+Xd65oE10Xst3BGb9/kHTT8uvzosnknn3ykXq8DsGjR" + "8cdf+3ZvLWZ+VBPHdXGaqdNsNrMAdP22voYd4oAjkOOw7B3L+KJ+J6zbYnZbvIV2kZpXWFqk" + "xYcHVjbr+2RSp/y5YWkCrMfM+GJFdbEyi0YGw0bQAVj2jeXMXsm1pGzQVbPfU95ubqk02ouS" + "d9U9ZYe84WrO+PU5Oyay8kEH0bksxs7iZAQ9d9sUvq6vLIzXYPt+Qu8RW8ShUMDqiLa+gBod" + "Txiybi1/w/D7Aw899GKYmvv0wc31Jk7ufkNh7CpivUaxCgSsDm9xp8KQSTc1vHfNK5NffDHs" + "lsP49bbddbr+UO9Vl8sFwOPx9Pf3X/qDUI+hH/4wrJbLittu27lzJ6IgFHj54+GPCV1JZbnn" + "nnsUliqE56ecfPIpJ58cOX/ZjWF2/KmnnHLMrLAhKn7fckfY+s+fJdlDpG9OCeeYsFus5oxf" + "n7Nz4oIFco0lA9el9/DtQnfsmNcFgM5hs+6rcdY0C3M4nd9Rvztn+2TpvVxE0OxxjQ8VLtX3" + "5loORO9H2lZuapNp3JYURjYfrDB0yCVEiiHyFT5GGMOm6z8AQpmc7ycaOmWuHGf0Ouuaeg//" + "zltoT2asNM7gc1WHX3hKbN9PiKLmIRiPfOqhGliPSUHNeUiQNXaGpX9xxmSLPqaK1177fN8+" + "kYRRBLfVUqe53R2M5rfqHDbTobBh7N0VB5WuGqF/vu0FKsrHJgFdzrYGQc1TgljEBXEP45GN" + "eGSjZF68YxJlDHflwYB4wAAK6+461iX/b8x3JdU5bI5JYR0UYlwXAIDxULHknzNgc7rG7Yu2" + "PmWD/fW7+FYQxmuwNdalO7UhGtN22/jXkBw9TQwnQQcAjtj21Nr2jCcBGREMmj3O+sbew7/z" + "FXYnJuvuilaE95M0tVZEFoSRwCYj6LF2ziO5Z1A2La2CEh7YPp9/RVuhp8fx3/+GpW1wB4tp" + "7+AvJJqsSwSdM3kVnjl8+d1BS1gGumXvWNab+HceDeXAXA1D0hYaWdSF0/s9FWGjuBg7SvT9" + "OQh/bjv+2reFaV7Tx/w7rHCQ8nURjm9prtGF3yq8JR1CdsqdZRz/AgBQR20TZ/YAIJSx7aoX" + "egimkPkbFvOvaCtIdHwkafpwE3QAIIbOorzNU43tJbL39qDZ7ajf3XvYVl9eD+JJgqEM5ysJ" + "awglHGuWe+KTnhDHxtswm9NYn7N9Us72SZaWqM+bYYeQXqm0d66TjC4UucJNDe999NG3fn9Y" + "8kR+1aLIIuORms54DawnrMO6vyCqZyVpOGE9JqNd+pSW8uxbmSD96hm4eoZ4RpLh+ZJrrklm" + "cwW8pR3SuOTgYCfkmxreO/7at8VqLsB4DYG8MIVVuC4ChGNcuh6fPiwrxjWuOWB1DOh4CE/F" + "If/AWN7W5nE6l6poJi4khSX4CaF27mVnNYwk+Y5kOHnoYpiA3to8znyo3FXR6ivqiozHgxaX" + "Y9IufV+uZe8YZcNEIJDfK8mH03flx/RDQufjMUqa+5VhHdYMDVScRugr/1oP0a+YdVp0WzfJ" + "dkQSKnwNruwyBU2Dcbff5pCtSMLp/f7csAZhQ1eR7O0sUtPt4cMqHV+8aH6gDLEQTvvCyhVR" + "RsAIIBWpiqsffjiu9VVDvUVhudus0yJ5oFEYz8iXp9P1Dt6ko10XCeXfznnpqpqTNr8o1LCm" + "hN5lC/vdXf3ShD/fFboipvbS2K53SrlMVDR7BDNcBZ2HcZtse8YHD1Z6Klu9hTKy7s/t6z18" + "m+lgmflAlUIrTWjliNEwDD35smtGYuwsZt1mAKwv9VZA9iCuksiZfEKiAo+hLw+K/UvFss74" + "wwRRUnxNIJDXJ3kc0femt65TzGzrvat0NUsTHHQiTYgH64l2XVTCmcN+JtGuSyTnPbrXXVnl" + "rg4NP7By7wzJCn/728v8L1TntJn3Zq53z7TdtmkYFWqO4Wm5SGHdJmvj+LwtUw2dclkuhHoq" + "2/oP2x6zITFy1Gmd6qxYY0eJtXmctXmcqVVaYGuYIjZb+WnJw6w/wl3lb2k8fFlqOntuqZmV" + "xLm8sS7pI0p1Adk+XAGrM3wG4cemyQzRlP3WU26VzMmenkTK10VAUiqdZ8PJQcqG/YKiXRdZ" + "zAcr9N35kFNzAH19LgDEr7PtqosZXSWMZDwANQbLpvrYOWPDheEdoYthPSbbnvFca5W7qlXy" + "yAkgYHH1TdmWs61BoTEtGN7/gnBM7OTWFEGZYNDmCphdnNnL6X2c3k/ZIGWCYMDHp2nqG6mM" + "cuIjZ5IONRk0u70l4ZWh9rxAZ08CkLdnZ78/7CO4jE5pSr8+QLxSlZE0hzJ+HeHSblalcOjR" + "5ClsCbOJll0Uo7VA1XUBAOQGZP6p9D3Shw/Z6yIPxYN9dYheSo5hiHV3nUKWekrgNX3kZbCo" + "YeQIOg/jMVoba41tJc7xTUFz2H82p/c7J+zO3TolWpqUpKAK8euRTAqkCigT9BXbvUVdwRwH" + "TX87Z2qJbDNwh2dWhKDNAFAb+2GQytVh5wxhd1mJUZM+FIyXlc9JR0fKZHheszSwd5XSz1bt" + "dQFKZPs4RwywKFyXlY03C23F0YaIurPsXtn5y2o2AjA1j9H3J+uYHZz2qRFKxqayjm+qd4xg" + "oR8JlkskOqctd+sUfYQDHrC4fEXRBzGQ9GqUdgpNLdRb0tEzfbNzXHMgp39YqLl0cDs21edM" + "ZALGoOQuq66NOrUoW+pJqrmtIDU3g8HkxfRcl3iHbI3EYC80tZXGXi8WCqPfxYzKR5K7IstI" + "i9AFCMfadtX3T94ZCG/q9BXZZbsmASA0PHZPn54T6qht8hXL1LEifp3OaWO9JsarZ4J6BBlC" + "CSj8uX2e8qF3acN6JKb6hmf3cpG9EgkbPjZOBp0n2SA9MjxPhsTUPEaQnoZARL2aF35+CwD7" + "cXJxejqDlphB91OvbwcwDSO51CJGsKADIJTY9ozvOWJzWK0JizPqBkEWukEDkdOlK5PBVXUg" + "Qs2JsaPI2F6qc1pk7yRUH2ddxvQT6WXnfjdFZWZxtGK87ZBmNw7tk4ug6dGc9AyYLb6pm/kJ" + "w5Yj1KyfwHWJTGFElFbT51uX867LhZUrovXDysuTT6rxFdk9EZ2EU8KYu5UcmE31DiEPHRHS" + "P8Ji9mFjuXBGL2f0Ul18usZ4DYaeAvEcqo8q05K2GqoLxF3eVgVBk0fSi49wTM72idamWp3T" + "mm7XPoUwHqmdLWm0UEDIgSk5aV6MjkjhIXlmusjK0u4OpjY8V4M4hOeVna/DrpA3mcx1iYtX" + "m+ziFz9Tr9c3HfbbaJu4a/YHbJkT0E31jhGm1zEZNhF6z7TNAMwHK8z75QuzRUPXb/MVDPrm" + "CoPbsm6zJHMxYHEm34YjwVvSIRFty96alB8lA0SWSA3aXOiKo7eImox1JqDnDIP5pjRtj02y" + "8GXiL7z9A9mlyYfnju6yhD30SOOFv0fqtr8uWTPmdVHoZxTvWc2ePVu4B/9c36rvz+mftEt4" + "0KKgh47cX/FlfcpLXvMs9h/DT6S1Ml02M2widB7xb1slJBj2GZnorWo6h/Sx1J8fY4SXBAjk" + "hXn6JMgao3j6WQ7rsEpKFksKYapEOWM96A775XNGn8qBisLKxqaC519LvNKLQi9/R7fUgqAK" + "QQeAiMGSJKTquiRAQ0PDq9wi4a3lQJW+N8/cEjbei9nrcNbvSSYLINIupxyFSM0RpVjFaGCY" + "CXowfkGXeCxM9Dx0Q680K8Zb1EXlUi+SIWgMe/5l3eahqjaXJIRj9L1hbmnQ7ApEdM5Su7d1" + "a+nsuZGyTsO7EVHCqTMQqLO2ObEzEbPs7rXL7l5bamYj1Tyu8DyuXv5+/+CtSCz3kR66rPGS" + "2HWJ1s8o5tkKlJWVTZs2TXh7W1eQ/8c2H6zUd4edjz+nzzPmgGTzmJXgED2JhfMPmRGXbQwz" + "QU8gQveHe3ZsRBguwHiMkqXU4JdUhkoeqQusLichO/Maje3StBRP9YGEGzKFUJ2XdX4m7ZVe" + "L19u7HJR7orY45pmLU5XmPgathzBv8QzlYP01F4XNbj6eubMmfO3fYPjPfOjbgEAha2pTtKh" + "z11x0FfQLbyNWQlOOR9x/51OlV75yG4RxbATdGrwxfV/yRl8/rww20TSRiohspq+u7pFfTkL" + "NUi7vKtwBoImj7tKGtFkA/refEndVF9+j7c0qVF9pe2l3XmShmJfSaey6+IrsrsjAsBkSHdP" + "Ir0uzArv6lI1Lqts6yj/1SV2XaIF6Q9sn+/zbfb5NkfbMBjwf/rMo0bjoGT/9lDYPzkJsLZd" + "9ZL/fOf4pmBEp9ZIZKWc0Yftih8/L7JYxShkuAk6ofFkE1JXzX7xj5/1mPR9SqMiGLsLJdXP" + "KcP1T/5eXBcw5kGV5UaShBA0eZQ9hECOo2/K9gQeTTIBhaW5RiK4zppmb2l8jzWU4SQfcFDW" + "WaNBaiB4Ogvbou3KW9LhGL8HoDHHns4ecnLC/if3NDfHtNGDwUEzRMZ4SfS6SDSdAffqH48V" + "3kbT9K/feLFrf7Ns/RYB1mWxNI0LO0c26JjQqFDTQiEqN+SF/YgCNgcf593U8B7/Ei/lcxYJ" + "h2k3jvAkdAw7QQfgmLTLV9CtomWMuqoPiPNbAFhaqmMY1hTWPbUSG4TT+3oP2+YpPUQVD0p1" + "AW9Ze+/UrcpVwCITWpzjmmTrH1Em6Ko60Dd5R4ZTO+JC57CZD4S1eoHAOa7ZWd8Ye/hsgoDN" + "4Ry3t+fIb31yY/jxmm7IO1Uynxl/oCO/rd0T9qUFDV5H3R5nbTMIJZTkNNYl8HEiyUBH/7Ky" + "sHbRQ4cObdm6VXZN1s+u++yLe/7wvxu+WAdF4yWZ60IAU9BR7Ntf49ry7be7lVdu+mbd7nVh" + "Q57yfYsiMXYVGQ+F9RQNml2u2maASoLrmB0+g3vCDJyg2eOLkr9AmaC12VP6nt28VxqTvXX+" + "WwqHGKYMm7RFgYDV6Ziwm/EaTR0lhq5C2UbOoMXtGrvfnxtutnQU6e2xy+GybrOtcbxjwp4w" + "b4flXOP2eaoOGuxF+r4cxm1kOB2loLogZ/QGrU5/br/f1q8mAcPQUewpC1OEQI6jd+pWU1uZ" + "rj+HDegpoUGjJ5DX5y3plJSXETOo8pQMSYd4AfOBCs7gFUao4fEW2r0F3fq+XH1vHus0Mz4j" + "/8RN2SBn8AXN7qDN6c/ti1lEnqxbawDVzxrvxx7RXMpO3E+rO7q6cy3UADYYsDr9OX1CSGpt" + "qo0cbs2f2wd+5DO/IeFi3OnoSTSxvn77jh3iOU88/fQP5s8/bMqU3Jwcc7/Z2m8taC8o21tW" + "2Vz5qP/vAE6cdxK/5rLlN65c8aBs39HErsuUfU5XcR9LVeUIdbfu37DmWUQprxiJZd/YoNUl" + "TkX3FnWx/VZTexmv6Sr77usrcyS/bmf9nuCBCn1vHhvQU0o5oy9ocfly+wL5fYWfBwE46syS" + "PZ/24mkjz0MffoLOwxm9ruoWV3UL6zbpHDbWayYBlhKOM/kCtv6ImqvQ9+Rbm8ep7LZj6C60" + "7oarbo8kJOf0fk9Zm6cs6vO+GnQui7GjRFL9jjN6XTUv8f31AAAgAElEQVRRh2FkvAZDZ7Gn" + "KqxsUvdR3/AT+p78nO8nhG1A4C1Werj226SV32Wr8QkY7IWK9wxiba4lfp2nMvybIdSf1ytp" + "w0gIYv0mt+9wvUT9icUDiyfSCzO3VMtWd/Dn9/BjebNOi0pBz0xPollHH/36m2+KXRSv1/vq" + "G2+8+sYbABZhUfRNBxE0XVQbPcHrIi4Gc++/ts2bdxQ/bTAcAQBmD5PvALB7w2fbPno7GAh7" + "fJx5KGo+jz+vjzN49b25kr5FvC869o9WAH2NXG6dfJ8MsfgaOotcVQfE8RNlgu4xLe4xLdGO" + "rrzDEcOwEXTLgSpPSUeklRw0x/CgQWE6WGFuqSLxdMI02gtZj9FZ15TaFlEey96xnNGrMjvY" + "0Flk3VfD6b0SQVeA0riT9pTX1/fnxngIoLC0jNH35zrH7Y3ttERAKMP6lXpvM369befE/sk7" + "Y7hPFJZ9Y0yHYo8aqJaNGwFgRij8TFNH//z8/DNPP/3V16UdgqKh1+vzCwafNfkgXX7V5K4L" + "JUyQMUoGq2PyXMzEfQD42Bzh4fnMmTMbGxtl9+YtafcVdsssINRVs3/HowAwduHYSEGPVF7G" + "Z7AcqHJVq5VvypKgZfgPEaaCYSPopgOVptYKf06/r8juy+9W6ME/CIWhp8B0oFIXZbBzZXQu" + "a+6Ww3wlnZ7yNpWdp3X9NmN7CeONUeKVcIxt50R31QFvRZuCL69z2sz7q/R9uQAYbhgMhKTv" + "zcvfMtVT3O4t71DZjMy4TaauYmNHCfHH+FfUuSx5W6c4xjcFIgaW4qEuE7drbF+PzZSiATBW" + "PndzSNDTz4JTTgn4/W++845yc6grx3XJgh+dNP/kXLl6KdGKdiVwXXzE6NAX9emKgyQOiVhW" + "szG1uZEKQbSptZwSzl3ZqhynMT5DzwyDY4IlaBpsLyzpvgDA/A3hxeZGBMNG0AGAEn1frr4v" + "10rGBcyuYI4jYHEGzR7O4KO6AGUoARBgGJ+RdZn1jhx9d36SPYwJiLGjxNhRHLS6fXk9Aasj" + "aPJyBh8YCkIJxzIBHfHqWbdZ57Dpe/PUH45QYmmpNh0q9ZXY/Tm9AbMbhgClIEGW8Rj1/TkG" + "e4G4tAvhWMZnyNJcFzEcMbWXmdpLgxa3P68vYHUETR7O4KMsx7dVkoCO8RlZj0nnsOp6c1iP" + "SX35GsZrzN0+yZ/X7yvu9Nv6OWMQAOvTBXrNXEcB7cznW7wjxy9NnBmDsWda63ARQs48/fSZ" + "M2Z8sX7997t2dXR0uD0ejuP0en23pbu/sL+rvKuttq2zovPZGc9Hbq4UpPPEc112X+sM5Op8" + "r0ofdGYtWbF+tbSDlUr3PF5U+CHEfKDK0FXkLe705/ZxJi9lgyCUcAzx61iPWeew6vvydA7b" + "3sX7xZvxas4zf8PiEabpJOXDpWtoZJJohRuRnKYP7SgWYiQjFjmPinpT5zWdD9Lp7Lmn/rWW" + "nx+vZvF5fr5XKiMXrV+9/NUm+9NzHuPf/vizK4//0eOh8xSSWx7ZCGDZ3Wuj7T9mqdvUutv8" + "xxEGiRYLOuL/crKc4Ze2qKEhRqFwIz94aQL7zB41TwA+LV1Qc4QPBqsewzkybTazlqwQvxXU" + "XCVqklhGZFtlxtAEXWMkEHNM6qE6sUyiXA8gAdRXW/z0mSsG31w9IzI8zx4p7yh4QZgeYeE5" + "hpmHrjGyECLHVP2uhGHYStethagqyI/Gva3eWB/W4TmPQrX05Pnjnx6rAQCsGqeq8SPDBosa" + "OgpeGKnPAVqErjE0iH2AxDwBWYRQXVzj6ZnmH/ATIz5UF4J06QCwiaImSA8Lz0VkT1Q+etAi" + "dI0RCFm3FpAvxKocqo+A8FzoO/rudU38ECLpIGZ4nlWDNQstoiMeTdA1RgWSEZ9VOjDDTs3F" + "jJv+/t510h94AjaX7HhGApHh+SP0EYW9KUg5Pz6UQnpMqhjBjwWaoGukniuelRkI+PFLw8Tx" + "vZlPpNxD54ksqH3jYj9mz+WNdQVZz/yQoWkiWlq6xOZK+GuPFp4nLOWJIVzoUVssNxJN0DVS" + "iayUixeJZT0dOQYSNed/6rz8CO2lEie93R2UDdWHdXjOM1DUJVnWr14uSVjkEcLztnEvyKr5" + "W+e/ddqLp0GdmkeLzQ9O+7Ri0/GSmZIxMaJpOp+EPnrQBH20kMLn2Ssa50ZdNjv87bodkuVX" + "PFsmCdUzhvKY1MkMGZq1yLouArwmqgxvBU1/a1tYeN427oUoWwApqmgYqeYa0dAEXUMtSjoe" + "jdmTQxMiZY8M1SWwZzYr7DL4xri4T0OEIOuRDoyYLAnP1XcTlSDruohtrjNtocpWCuGtMkub" + "6amKap4lVvXoaRGFJuijh4Rj80gd/9UfDqrc9q7fVYSm5JRdjFjE/3LxTxT2eT2eFKYjxf2m" + "hvfUWKuSjPUR457HhLe5lMdijsb61cvtx92rZs0Zr/cCmCG6ofzpH1/cdvmxj9+YspKHKi90" + "JFlym0kTmqBrREUi5ep1PHITqbKv2yF4L7yUK4u4GPGavLhLZF3lz1sI1f/2c2l5qSwJz1NC" + "qmx0CUub5csq8lIeyW2XHwvgigdDz0MpUXatLTQSrTiXhjxiNVeW8nfKKwAsaIst94OyDmDd" + "jiefWYd4pDwa1/9HRtahOgsim3PPZS2XH59/ydMv/lvN5uJyXRKUvxyhLZEfh3Nl480AxOG5" + "IOinHggV8u1d+I+Y5zNv6XmSOSmM2WXZ9OB+ieWiRegaow5BzROIyhXg93bX7yqevP5JPJMC" + "Kefh9yOJ1gXBuuSS2/+9/fZomp7Nai5mTa0dwDvdjgUFNpVqrkxc4e0j9JG3zn8LAwMfvfBZ" + "LqoGI/HVV/Ve2PaSmv18sCq0mqDsfMyeblkfPWiCrhGG+sBcQE1sLubJ659MlZSLEWRdEqr/" + "+9+3p/xYGYZXcx5e0zN2aKHD5+q242RXWH1VL4Dny89Tqek8vLKLZT1Nmj6qWkSh1XLRECMO" + "zFMbm/NM7nxncuc76VBzgb9c/BP2zGblPBmB7A/P19TaxWoeL3xpl8RqdV12VoOghov9xwjz" + "bR8tSPh8JHyw6iUhZhfs9bQysv0WaIKuIZAmm0WAl/K0qjkPf5RbblktzFFpL2Sbmq/VJzXe" + "VsJM222TBLaOk94Rv5W1y58vl/rjKhFremZkfQSjWS4aQKbUXGbBVgDAYfHsS90mf7n4J7hl" + "tULS+jBNVUyr3xKz1G0Kw3MxYgcmffbLaECL0DUGybSapxneflG5craF55Gc21SYgJqrdF0U" + "St1eMKdP/Pah85ZG20nCQTpPhu2XEYkWoY8mco2ozZfO3HSID8+TVHOz2aDXDQZWDoeHoxQx" + "1Tyu2Dz+Tf5y8U8im0kxTMLzuX6/4Lqc21QoWWp9dAsA51VTVe5NtiIKVETlAo8VvojzXlRe" + "h28drX/qDf7t7svOVLlzng9WvTRv6Xn75lw5fwOQdLUf9R9txKBF6KOJChu5YLLklUiHfjkK" + "863lZfnCi9WxGLrYXIyaOD0l4fmSa65JficSBB1PpmmUJwE1f+r17ZLwXA2CmkumVbJvzpXC" + "dApHPsEoaBGFFqEPMRU2MmcMavNgMwIUfT609tOddnzbBk6+J15S7Oyivx3oNJhrJMsHUxeS" + "N1sOHOzmJybWVyivOeSkKTxf/fDDKd+nWMclmq4+NheGvBD3MIop5ZI5jxXGiM01sgFN0IeO" + "mjxy+REghH51kLT2w8BifD4aisiUYrqjEy5/xk4kq6zzmb0AsCkHvtQ9PYqNF0HNBX2c6/ev" + "be4HcEy11agb+c+sylLO991/CgDw6l1VGTkjjZQx8v99sxayYDxYhr62C6/tohvb6BcH6DNb" + "6Yf7hvq8hpjZPZjdAwOX+B58M/X8S2EdcbS7Vq9/v7H3/cZebyANT0UpRe/fwb8S2zzmIJ/R" + "KrEohOeR/YnuuvUxYTpeDx3AuS80nftCEz899rPH0tFAuvIXc/lq0iMPTdCHjiobALKzSzyP" + "dHsyfBZpCs/H2z8ZEvdcrOPiad5Jz9q20MJXWgpfaYmcL24LFQrevuGofqfb8U53HI4wn+vS" + "s6In2gri8Zr5bJNkwvO7bn1s92VnJqDmAgqbH5z2qZo9jMIWUWiWy1BCAYAawlJu6b5e8n4z" + "AuFRCQGmlODoClKZA7MOgSC6PLSpB+/sQWAglNUxmFREJhWh2oZ8E/QsvEG6vw9vNqLdmcDZ" + "MQyTn2fJsZkMBj0Avz/Q2+fu6XFIglijUV9YYLWYjSzLcBz1+xPplAhgZi+IaNfT+wYtl249" + "dlnDVtZTHNGPCV0oYMBwXLeR2WHFt7ngCABs3Mc9sz70BV4HvF08sLnBet3Ojfz8r9pajz62" + "sml3N8XgcA2f7es3DVguxVb91DJzYp+FZ8k116TEVRc03Td1M4A3HNXCopSUARB0PFosHNM9" + "v7DtpciExXiLAQisePU6yRxJZnpi412IW0QzMGzpUKFF6ENHUw8Acu4k5BoHZ9rd9KO98Ikc" + "Bwa4oIFcMoVU5WDDAbyyE1+2wmYgx1ZBbPgeVU4umYKaXOzuwZt76Jt70Och9QXkEvlaFhfv" + "PUZ2Po9Ox46tLiouygkEgu2dfR2dfRylJcU5FRUF4tVybOaxY4pzbGZ/INjX73a5vBgQ5afO" + "jC8leVYPZvVi1sAT//T+0NtZvZjoClvTFsTFrTi2G/0Un3jxSTHjZ3BcD07rDK0wrohccjSb" + "byYADhlwaODbffjiB78qegzApoJnn8n56dNLljQ19jbt7m7aHWrO/WK/48OmPv713aFE7oJi" + "4lJz+znV9nOqkZ5UmWiIo3IBleH5rKNCYr3+6/MgZ7ykBCEzPVWMYLOFR4vQh47XduHyaajJ" + "IzfMol8ewGf7ZRtCyXFjcEQpnH7696/REzJkCKU4cWzkynTV13CFYmS6rYP8fDZKrLDohJnq" + "IJXlBQaDrsve32UP/eB7+1w1Y4ptVpPVYnS6vAB0Ora8NI8ArW3dDsegU5RYlsvKmtDEdXsB" + "4IkqOOT+NwnF6e3ID2B9PtaH6rZiaw4uacV4F2rcMGzw+2bqi6ykPJfc/2GgzId8P/p0AEAJ" + "V+s4cXfOe5+U3g/Qrx8eTFX83fstAG6ZU5FrGuI+igq3AcOWI/ggPTH4XJeeFT35y/PVJ/Al" + "k9yScJCukTBahD5k0G4P/dtGfN4CFuTEMeSW2WRBLSzhMsYAc8YAoB/vE9QcAO2KsNq/t9On" + "toQJd+/AOrr4RMpiMZhM+iDH2bsHo1RKab/DA8BmM1EuSLlgfp6ZMMTp9IjVPN2M8aDMBw+L" + "jXmDM4PALgsA1LsAwLDBb9jgr28MfFIAAAs6kRMETDNOPPQLhho+KL8DyPbGz2j49ZPFHkti" + "fousmvN+Cx8RX2k/P4Hdymp3kn1HhVNKrGn06kdnXP1o2Ogly+5eO4L9FmgR+hDjCdA3G/FZ" + "C5lTjaMrccJYMrOSvtWIr9tCmlNkhU0PAOFtp9jRSR93wSf6L+/xhBSfABY9DCyiZ+Bd0TjX" + "Ke14OIjNYgTgcfsoDRO+QCAIwNvR9O7tlwG45K5nUTDJ4VI7ymUMgsJnUbr91HgA4KARkt+3" + "kwWAovBz2ZKDCi8mOnFaB7b7z5/Y94Pnai7zMS4Mh47+CmSsfO7ZvzpwzqrMHCrFjM4WUWiC" + "nhX0eembjfh4P1lQi6PKyaJJMOnoZy0AkGcIrdPjDdvE5adN3Vt7v9jWv87ua6OgOfrC6cdf" + "MOXkc9mxBdAn9eCl07EArFaTrHmSP3bSgj+8/tHdP8orHwsgEEiwFVTKdVdh8yYAeHajwlq2" + "AADUukLOjARDROT9YRGKfSjzouzQr9+t+I3d2Jiasx2eyPYwkiAJz19Zesw5q75U3i03cONP" + "beto8jxyVeh/aTT0EeXRBD1rcPromp3wBsmxVZgzBp+1ACDBAYkikrXpe4f+9b1j4+zC086q" + "WKIjBs+C0ry5R1K3Dx/vxd4+6vDBT8nPZyVwInxg3t68c/Pb/wKF3pJjKaiomHaSzmgBwA10" + "YdUbzQBoqtyLhx8PTcgptQDfWHzQiO9yZJb6pd9SGHQgjWZYh+cpQaLpYr9F4OxfHVC5t1+8" + "EVL8FWcdm6ITDIMv8KJVYVSD5qEPGeSK6TJf/4ZWACGbBRj0zUst4rX2OL/73rHxyPyTjy5Y" + "YGFzDbk5eSceCaD/yU/oR/toUw86XOhxJ3JalLZs+RSA0ZpfNuvCyhN+zBaMX/ev+9pb9vX1" + "u/v63Q6nB0DplON8HhcAhgkT0cldKRq3N4o0L6gsADDJZNxpReRrj0W6/kldsHC9n5c8BODk" + "tt8U+GoVjkkV7wcjDNn6i4m55yvOOvaYmtDYpyl30h/8ZPN3bXYAd/3tpXX2txLbyXd9nyd8" + "AsMLTdCHjlAJl3BMOmCwPZP2eNDhAoAZYe7H9v71AJmeH0rAIoUWXgHNrQDwxN47Vjbe/Pd9" + "v4w8pivYv7Lx5hmYcQbO4Od88fAN795+9ucrr3O07wPQvuPLTa/9A0BeSdnW/9y5dsVlTR//" + "h9EZInfVtW8XAJMxrEMmHTNd9edXQifXU3RNQ21JqQVAX6/36erY3V4Od2CSk75TcdvXhU9t" + "yX9ez5lPb737UEVbtPUDweHaWKoevocRj0JN3Syp3NLr8bU73BNL8imlH6/fNs46RVg04hMQ" + "E0MT9CGlNi8sFGUI5tYAwKb20BwKunYfADKzErMqhZXbPfvGjDnCYgu1bNKBfEd9TTGAH4+9" + "7adTH/zp7/8beUA9MZ5YfN6tuFWYU1Q3ve6kS11dre7uNgAHNr7TuXfnri/fBXDeH/4594aV" + "Lntb/Sk/thRUAPj6H7/c8sxv3vndWS0b3mxc/z6A/DyLQc8C8Ll6e7e8YceAFdK0B5dfihNm" + "4rKL0TTgXDv68Zf7cN6ZOGEmTjkeSy7D9q2SM/T6PQBKB5o3GaCcbz7oaAeQk2soq7AC2PxN" + "e1F4kmduABWihoZSH06wY33xI/usXwD4tPT+dtPWQm/dazu6I2XbpGcAtPaH9shR2tKbosZe" + "dUTrKZpuxJqeWHgeScwg/YaXVvGvmLva3t5dX5xnYJmde1oDgWCpcYyaE5C0iEYWGhvBaB76" + "0EFBLmjA8WPpjk5i91CrjhxRhgob9vXRj0UVXTYfQrkNx1eThRMwpxoH+gGck/9Y0Zg6unIj" + "3A4A6HKhqRe1efjxVOy26whBXT46XDTIEZbBGXXY3olN7cg16mvLpmLM0e2T62yhQxx9/rUA" + "rBZdaVU1Bbr3bgXQeuBQpctrtRinHDm99PePBonBUlBmNLAT//Sk3d7X3t79xcPXf/f+i7Mu" + "ut5g0NWMLfX5Ajp9WaCuau/rKwsu/iWAM7vZjYsW77Tvw1OPobUVtXXwerHsarQdxG/vwNGz" + "0LIfP1uKAy1oCCtwvr+tqX5Mw0l2jHeBBSo8cLD4t7ELVy/Gju0AGg4vCfi5rk73D11oM6JX" + "BxYo9KHQj29ycdAYUvZjeuBj7a3mb/ndcgjssa0t9Rz2bZsr16SryTdMKDIJBx1fYNzW7n5l" + "R/f2DneQ4/b1+HKM7LWzy9J38bOE/v7+lY13rlwIAPbj7uVnFn+xvMxmrlsa6nrm9gfe/b5l" + "S5u91+PVM0xZjuXcw2vH5Culkci2jt7z4Tcn11f9c8MaYc4NL62SHS4jwHG/e3vDwnMWvbT5" + "CwDLX/8Cr38B4G+9Pz8y/+TjihZiRPf2TAZN0IeOB9bRqaWkvpDMroJJRwIc2p30zUasa0VQ" + "5DhQ0LcbSaMdx1RhbB6mlsLH0YPdO95YM6m7ZHCdf3+HBXVkSjFpKKJdHvLhXvrFAfe1kyyl" + "peSwEvT56KZ2vh46gI+BE7Cc37S8LB9A+aU/A8X3jQcDXheAoroZB1q7c3NMuTmWgqpaltVx" + "lPp8gS67o7fPw+gMAAl4Pftbu0qLc61Wk0HPOt3e1/932aULT+FPvbC8xtJQg1zg4w9CJ/nm" + "a9j9PX7xGxw/FwDqJ6JGxtH++Jt32Pb2cdOPq+f0DhZNFmzJAf7yCDo7zl375Zq5x7AsmT6j" + "/Bc/vq7hhDNLayeXe+En6NZjfR625gBAhRenhnqNFk63/6jFsh4AIeSYzmtDh2juq84NE/Sz" + "JuVzHG3s9m495Mo1shNLzLOqrNIzSyd8N9HMYzQaFy1aNLEMv9wy2J/+1InV7+86UDfw9u9f" + "bOt2ey+eXj+hOK/T6V71xbYul0dZ0GWp/eGdz61e/k8Va7IM88fTZlFv69sG/VWzGypyLa+1" + "955wdEPP28cRMpoaOuJHE/Qhg3Z78PG+sGBcYeXd3RjooQ7g9b1/YIlu0thfD67hCuDlnfTl" + "naH1AQDrfveHrX1fLKu7P7TOQD30KxrnzsCM6pmnT1m4THokQkCp3pIDUL4VVOGsggHuYNtg" + "vafO5m3AKX+9dAZOPwu/uSM097d3orgEADZuABBSc57f3wmbNFvF5XG+cd/N+Cw8efGTtRhf" + "j6Lic7/bHZrTvvv7u67Bmx9GnhXfQApTWI8SDsE/nBJVNG0G9tJpxQqfNLWoLPNS2BL2iOA8" + "KjUuEJ+8yE8bDIbjjjvulAaCLaGljxW+OL+wmm+H5Gntc15wxPjDygoAVOZaS20yJW4qZ8zB" + "3jCnRTZIn7VkhZozJAAhpMPpCXJcRa6FgGzesfeGy8/86J1ELOJPFz4wt+SCBDYcjmiCPiyp" + "MNXucnzjCPTYdBFDyiUHqzME/V5Pb6e5IG7DQW8eiNqMosbe8QOhXn8/AOSJunhWqK7n19WJ" + "zg6cGJ6FycTx886qVMV0DIWRDLV3ScPeS6bXrxO9nVI22A/th0dOMOul6YOtGz9Teax861E9" + "zq/5aYXhSQE02/vGFeYwhBzqdwMYV10K4K5vlvzqyNUKW3k4FzBKexVBE/RhypTcY3Y5vllv" + "f3te6cWi2ZSjHEOSytXNKa/t2b+j6ZMXppwdEbzHomTSbKXFhUUA0N4Wh44L5OaitBxPPKt2" + "/fDwXEMlQnJLeU5YBqjVMCgUhZaI1KwobFi9fGZESH74T+5S1nEAr2/bu3ZPKz+99Nm3AfwO" + "AHDXN7EPOntPqfgt3yK6tuOFtR0vXFB1Q5mpJsp2IwQty2VYUm2ecETeCdv7173f/q9D3n09" + "/o5G5+b5Gy5f8NWV8zcs5ijHvygoAOEtAF70g3zPeY7jq7JQbtCyr5v3PwBavnpz22sru3Z/" + "Y2/a3PTJC4e2fkqDAQAD64c63g++pRTAhPmXKZ30sXMA4KXnE/nAc07E7u/x/c5Eth2K8Hyt" + "Xs+/MnxclYiTF5e8HFsEetwybo+k4KKY+qfeqH/qjZfscY+DuvTZt5c++/Zr3+7oGyDePcgy" + "Pf+k86p+VmAY+a3cWoQ+XDmheFGxsWpL76drDvwfgBe6OoRFC7664tzCQjyyETgZV894eM8t" + "AHJ0BZfV/NYVdPyj+ff8A3/LxrdbNr4NoOqoBYctup7ftqhu+piZZ+zf8N+Dmz468NVbDKs3" + "5ZcyOoO1ZIyttGbD479s3/0fAPj1GwbDEe/efg6/1am3v0LAGKx5nJsDAI4L1WYhZNAYOWUB" + "Xl2DZ5+Gy4W586DTYdt3qKzGvPmAqJYLf3cR3jIMCMHSZdi4ATdeg8uuwOQp4Djs3oXODlx7" + "vcxXM9ThuVjH1+r1c/2ZG00wGc44sOLLxf+FXEXyz/e2ndWgNrYVDwz9q3uuFA9gxCMuBsAH" + "4CpRNlsUyNMXV5iU+pSNGDRBH76QhpxZDTnynfuX1d2/cmBCPN/C5iyru/+KxrmIPlZRw1nX" + "5FZP3L/udcehZko5ndFceeR8S1EVgJCaAwB8vs0GwxEAzPmlhGG9ju619/z4XX7Zq2vw6hoA" + "OGsRfvXb0AYMgxUP4anH8c5beHUNDAZMmIRrfhZaKtRy4RHs8o/Xg2VRXILHnsY/VuO5f6H9" + "EIxGTJyECy5R8zVllXuebYjD88oZc/gJjlJGlExSV5S3trHVGwhOLS9kGbKvx1FkMR1RUSTe" + "D18BglNRCOK9+3m/JarrknPfUfxE/8+/FmZufXelwaBTLtwWyVvnv4XLawBQynGUYwiJ2gV5" + "pEAkP3iNYcr8DYvFb9+b+US0FfhFypoejdd/GVaE/aw/y6ToJDY2dMqICM+HxG8Rv004Qk9V" + "lov10S0AnFdNlcxfueJBQdCXlH/+0kuhqHnW2NILj6h7ZSAP/Yy/ff7+7pZvDnR2u706hqnK" + "tZ7RMLa2MBcis+X51uXCbteEOy2n6JSiRkG+xYil/NqTjl67p/Xlp38PQE0tl8heRZ8ufICf" + "vmb8vQwZ4SazFqGPEN6b+YREssWI5X7+hsWRK8hyzXXH8RMP/3WYlMIYIjW3FYSO4uguAzDX" + "7xc0PZv9FnF4ftvlxx7rk7m7f3rwfz49939WvHrdaZNkBlQREMpy8RbK+wM1OCPVXFbBxYjV" + "fNWlP5hWWTStskhhfTGyfURHVcyqCfrIQaVMq0RQc36a1/Sz/rxPCNJlw/NRiKDm/LSg6UN3" + "RlIiY3MJqxdxp4DMW3pevEO+PbZDcE7CLBRBx2PKtxiJlAvT85aeB3XhuYYm6KOUx+vWXtE4" + "967fVUS6Lu+UVwCINrRlTB3fUbzg+v88OQSuSxLheaHIJLFnkxZL0Pt38BN+/eQkd+Wd8xc1" + "qx1f8U9xPfSYbZhxKbhANCnXiBdN0EcafAk6SaULZUNmdBIp4oXZmmXII6g5P528pvOsXiRX" + "2RIA8N+5dwBA9JqGicm3GLGUm0zNiF7gRUMNmqCPFqLpuCRI58PzBW0HH/7rwYQ99CEI0uMP" + "z8WRuCDlCYTnju4yiYeeJt5whEoXnGkLq8sYrc1Tgcjw/P3t9JQGIg7AZTU1eQUXE6nmPGJN" + "n7f0vBkH5wFYhgSrca1svFnNaiPDatcEfaShvgod77oorDBs2kIjUG+2LLnmmpdWr04yQhfr" + "uMo6LfGypnYwdeQNR7VE0xNG99bVP42+NLXyLcYp3gMAACAASURBVCbSY1FTTVeZ2FVzH9kI" + "AFfLd1MQdH9YK7sm6COKg9M+rdh0fOz1whEH6Qva4ktkjEZGg/QkehKJ1Twl7nmq1HytXs+L" + "+LlNMuN5i/0W9bF5sN8DIHDaI9FWSJ+CC4ilfP7NqwAg+qCjfHPoxooPFFpEBSF+BFE/V1wM" + "a2XXBH1EEa+aC0G6bOuoGMGKSeb0MoPK8JyPx7OzCVScyb6m1h6p6WpsFl6+FdC9dXUGFFxA" + "RspFPHTeUiFIl3jo0dRcjZciJKEDUWPzaPD7H16yrgn6aCem8ZIwGQrSEwrPJfF4qsLz9HFu" + "U6HguiwokK8mGFPBc+47qvvdn4rfpur0lBFLOeTUnC8GINFxPjyXRaUtDsBeeLea1Qrtv1A+" + "1nCRdU3QNZRSGAWGRWwOdeH5kMh38g2nYh3nY3M1Ch5tUcGpf0/sNOIl0i6/UG7Y6OfDjRdB" + "zSPDc/Vqrh5B96Mp+8rGm4eFpmuCrjGIRNNt3z7umH5FMjvkg/STb7+df3vu9qZk9iZDnOF5" + "NJsl3fou2/lIAXFfU8FvSUa+ecTheQZIPrtcpZrbC+9+oatAPCfhcUQVlH1YaLpWy0UjhGC8" + "xFXghffWfYv10TociXucIrWaHmeqYmKBeUpSEsWCrn5XkloufROktWTj9UwEQU93eK5GyiOD" + "dAwMMC3bNTSalPMT0QT91Z+Uqz/tSGQD9mzWTC1C1wihvoFU4PVfjjU84Rems7kYQJJqDnWR" + "dVpJ0vLOTHiefFQua50rq3n6sBfePbxC9RFee0wjLh6vC+Ww3/W7irt+V6FmE99ivW/xUHSw" + "VB2eF+r1Q97mKb4TDO1dAekMz+NSc9lURSFsF4fnkWpuL7w7A2qucKx0+PgpQRN0jUFO/fCm" + "/fuO2r8vFAmq1HQB27ePR84U90768Pbbr//Pk8mcYTQU1Nzu92dDBouju4x/DfWJpIX+n38t" + "qPmqS3+QZD0W5TpcGZPyIT9oAmgeusYgp354kzA9ZuxgtKXgwMRVfJG/Qzx5fdK5jOrC8yQD" + "c77PZ2a69csi8dDpq/UZPgE1JOmxyDrpMz+MGp7LCqvEQL+gqPvsJ9v46SQ9dAkS+yULxVMT" + "9JFDYt1ExYgFHeGajvhHwxAjCfafvP5JAInLerigR6q5mk5Dha+0ALCfU53gOSSK+jtElgu6" + "WMqvnLxKGGI0XiI1XRB0NWqODAo6sl7TtUbRkUOSah4J770Isi6IsnpljzRt+H3Ow1EAcO8N" + "SEDWY6UqDrljrsBavR6OagBn2lqGtpX1/C1HvDh1c8KbS9Q8sZ3w7Z/PvxJ6+6t7ruQn7rr1" + "MXGQzpMlpodsM2n2oAm6RgwESz1S2RPYiZh5tzwEJCrrA0jCc/VqnvnYXNyhP4UFthIjYTWX" + "eCzCKHRxIU5lefgcXPPKoJpjYGjp9auXy22aXWRbxosm6BpqiVR29ZsoIJZ1HiVxjx6eZ3Nt" + "lvThvy1kdOj/lIiwxoVYynetXQVg3tLz1i/F87fPAzDr1diWS2RKYqj98+Sg8oYK4bnEb8kA" + "2Ryka4KuETdqZDpeQrLOIxJ3CX8Jl3ohPM9mm4VnbURt3uT9FkHN+en0abpYym/ZlQsAlVja" + "ukK8jkLplUgkeSyRBguAWUtWJBCkX1DUHe8mSZJVQbom6BpZh1jc3z15sFreyufkk3+Ho5pL" + "Bh2VtH9GMlQtopK6WiE1BwCsquTVdsWFt38AACqMdIV8xLtufUzsoYsXqXfP3zr/rQswW+XK" + "yZC1Qbom6BqxWfTW1wBePi1zpVYjjxip5vbqQ1luswgyLR6eAlFKnGchMoF5dAb0PZLn+D/6" + "i5TaDGZ+yEp0HPEH6ae9eBrSmeKS/WiCrjHIuyc/IMlcjJcEpJ/aQs/IxCE1Q8XheSRDFZjH" + "jKZTiOhOMCtyqf5P56XJQxdL+Rlrfw9gSmV8ezh94MzfbCrkNd3/XLWypqeKTw/+D4A1F9Su" + "3Y259Y9m4IjZgyboGrFRFmgFRY6JsC0/LeyBP+K7A8PpyZgttfZ41VzwPebKbZhWmRZXM1cb" + "nm/cCAC1oXcv37B+0UPymp6KExxEEpVva41xgy94bXn3whUAuheuKHgtFE2fLnoiOb3WLmi6" + "MjM/ZDdEtI7OWrICL0Udxjpmi+ja3VeJNX3JSetWf5QJT2ao0ARdIykkipwJW6bWDtU2i6zp" + "sVavz7zpkf02i1jK//73v+8+5daU7v4i4LmYQXqkpv/qnivX3gNAVazNt4iuuaA22gojW82h" + "CbpG9hMWntfa0VQIINvVMSHEOfWFKJM472lFrOZsjglA/fv3xKXpl353JXAlQh5LVOIyXsTJ" + "6ZJYW0MWTdA1wkjeRudR6cMQR4GwpkwMK3lMH1DzZDj3hSYASHxY6RC+gY45hi1HqN9K5Xin" + "PGKjRtZvSQmRUp4Al343qLy8xxLuofNclLDxokxJ9wUDk48CuO+zO38+57f8+9F2D9AEXSMp" + "xIosaLfEh4nhNnSoOAyvDomquW/qZqDlDUfKuob6RN0sfVM3izU9LsmOifDVUaQ+bTElUh6N" + "KHG6KuMlLkRqPhjF3/fZndCyXDQ0EH+Qzuv4og4izFljS6lXkFxgLohvqKv9jDiC88iWzAG9" + "DlPt1Ip4BlAp5fXv37OtIVS3hwsCAKNU1zZlCEG6JDldMpZ55vuIZj+aoI8Kki/EqIxYzVNM" + "KmyWuBDUWdwbaE2tXTY3ZjiiRs2XLb9x5YoHxXNWzwKAqzfK7/PZwx8TXBdlDz1eIpPTNRTQ" + "BrgYFcSr5soJ4DEReyyJZ3fU2qOp+ZpaO/9KYK/26kPKLzU7yaoRiNQjHoaCzTHFZbM0nB9j" + "hWcPf+zNpkIVan4RAP9zg/bXcy337XFuAbC244V19rf4mbL9iU47b1CvAgjlMnYUvCDMzJhj" + "np3dRKFF6BrRSLJ1NNksveiBuVjH19TaIw8kEWVHd2oGepYwjHQcSdjlZ2+veLUh8Tr4MXEG" + "ert97WPMkwDa5Np6evnl/PxldfdvgHzTqJv6f+Z8/gP/9/cgVCKC1/TMV3HhyZ5CLtAEfTQw" + "f8NifuK9mU+k6RAvl9BUui7x2CxqYurExHeu36/cFyk7efmG9fwEnxiTsJRHui7poNm1rdo8" + "Qc8YOrwtHA2WGscIi9avXj5ryQrJ+qedx6x5EacbptxpOfOzdJ9cFLI2PIcm6CMeQc356bg0" + "Pa4g/eUSyk8kpey1dgD0oVnkbOmSQWs78b3HzTDScR5BzfnpU3SDP/CU57HwONsHp/9zHqYv" + "xqSIaxdJ0Od/fM8vAjT09QojE/2t8edH5p98XNFCAMvq7l+5+uZITTcT/fmG6VnSIppV4Tk0" + "QdeQRWhETcB4SVzZBwJzBTXHsA2ch5AkpVzBdXF14eXFOGMg9WXS2Vh7B4y5GHdSrFPS666q" + "vQugT+y9Y2HF1UWGyv+2PT7OOmVKzjGExPi3Oe085q2XOIgSFjsKXsiY35LN4Tm0RlENWcSN" + "qAk3kL5cQoWXqg2i2CyRpspcv59/JXZio4d4Wz4lLFt+o/IKXz8Cl6gbwfSfIKcKW/+jYteE" + "MITpC9iDNFBsrCSEHPI0V5rqGMIQDAr6srr7o7WOitPPxdORFP55fuGf56s4p9hk+YCi0AR9" + "xCP2WBL20JNMeoFI3BPYtrClLJMFDocv/T//WuyxLCiwpfuIzWtRKOrw1H32itwqdO5Qu/lB" + "z54KUy0B0+1rB1BgKI1cJ17RHLXDQ/NolsvIJyVtobymJ18VgNf0BHx2QdOHXS+eDCBu+UyH" + "jp+9veIfcvNdnXB14Hksv7Ay5HQfWA+iIkr88oGnNze+xk+LDXSW6K6q/V+WhOmSbOuoeuy/" + "fC/hbQWy3GkR0ARdIw5SVeklGcTRuibuSHMPfuVcF1MurOU4/1l0LwzNidbzSMxfp07G43/C" + "438qtp50csnFFaba99ufLTJUTc+fC0Ci5pBLYVzyaF4HXhB76HF8pDiRlfLsDM+hCbpGvKQq" + "VBczODSoOmtFVBhrVIftaZVyCUWLb8KLUudt7In4/nV07oT6igB/FZXB6XR+9LPJb7JE1+bZ" + "OzXvhEgpF5Ct2CXo+IyC3WCKVJ9CHAwvNYcm6BoKrPzFXADL7pZJFExY1t89+YFoQ4PaCg75" + "CjYjVv1C2cJYoy1sz6SUi+EGRJVhAIJZy9C6Af+9Bgutofnf/QvODsy+Xu0OdUTvCPQ4g33i" + "DHRZFKowBinHdxxNYQGKYSflPJqgjxwe2B5qyr+pIQWmoRrEjaWy4n5G+ZaYp8Trr9CZEwMy" + "/chRjwhzrv76avVnNbLd9sxLOe+6nL294tOBii4AlqwHw8JSgnOfxtergU9C8/e8i8MuiW//" + "Bz3NJYYqhfA8JrN67+Un5ujGE5yT8H6g6JVnv5pDE/QRg6Dm/HQCmh55P5CNzaMRmQmT/CkJ" + "LLso9FuKFt3LIgnbl1xzzeqHH074HLKBoQrMeWT9cXMh5tyK7gFBP/vxGDu5bsuOv06dzE/z" + "/xITbNMn2KarOYGYpdI/C+xJrARdzDbPYaHm0ARdgyeF4psAhS1lvNkiIITnm+od4vnLLrr/" + "JrwnnK36wSUKW8pwG15qeWmYhu3pk/J3ukPfcAbSHHmu27IjmXroSx7NU7NaqvJShouU82h5" + "6KOOB7bP518ZO+Ibjuo3HNV8EQJJiC3Iq1ia+elN9Q6Jmgvc1PAe/1p20f1C8K4SPqt9mOa2" + "J9lRKBJBzSXTEvgeRvXv35PCQyfGzA+l7a+rr+pNJqlRgWV19w8vNYcWoY8Ybmp4T42HnslI" + "nD8l8ThB8zcsXtkk9UwEYRU0fdlF929CVHGJRKzpiXky6Q7bC19pAWA/J/EhkzJvsKQncn8O" + "QAqHKxJYVnc/n8/+6cJkO8ENOxEXown6yCEZdVZ5P0hgt+LqYGqIN+KOtvnK526OHG8oGplJ" + "khlGJr4kck+RpsceUDRhNpwcXIaBS98Yx01dYFjruIAm6BohMuyb80h8D9/UzdiempOJWTY9" + "5imlUNlDsfk5WafmCwpsKiNxPtel/v17dp9yazJHTEd4LmFkSHNiaB766EIslJlRcHHhAYmq" + "ShRTnGCecot/eLntkiM6j/Kl71gLCmz8K32HAJAqs2Xa7qjnqZwAM0rQIvRRR+Yj8UFND3/m" + "zrxQZr/bniWoj9zVkS6zZfVVvWna8zBFi9A1hiUHp32qvELMMpN8zD6MwvYMExm5K+S6FLwW" + "KnLbvTAy4SSk5hkwW6IF6fM3LOZf6T6BIUeL0DUyRMyIOK6GWTXDXqssM5mqsH1I2jwzn0Ue" + "JyE1v3Pdt39AcQaOt+HkoCS1MZlBu4YdmqBrZAW8qg5Jw2zkaSAxZc94x6X05KKkikGb5c51" + "3w7heYwqNEHX0JBBc9tlUZ3rMhiYp/DokS2issUAIoP00YPmoWtkAmVNTDL3PN0MuduuUJE8" + "K0mLmkcSrSOxhJQM2jVc0CJ0DUA0KrSGAkMYtq9c8WDkCJ+pzkWJi8jElb3CVCY9FjVB+ojX" + "cQFN0DUAdW2McaG+eTPLw/NopKQAZFxH5ON0sazr/TvOtAGAXz85rl0lw4Dr0rz7lHGyK2iO" + "+RCiCbpG6lFfMUZZzRVG2MgeMhC2712lA1CzNABRqK73Dw7GrPfvyKSm80iE+zoUKKz8h/vS" + "mOKSgJM+LP61EkDz0DXSTlwyN6xJq9vOyzqGn6WeGiQtohIDfdS2gkrQInSNISOm8A3fACrh" + "sP3wI48EUInK1tdaI5fuXaUT4vQbbzwt6dNMEN51KVgSGpqoe/W/h+pMlFEI0ofvv5YyWoQ+" + "Msl80XMxma8Yk82oD9srF1bGXGfvKh0fqj/44FvCzMz7LeLbiaDs0Uir3yIgq92jrcCLFqGP" + "QIZ2+CEe4aDR4tNh2haaDMphuxo1F+BDdV7TI7NfNEYtWoSuoTEEiMP2yoWVYjVvfa1V1m+R" + "MFws9cyE5zxakK4JusYQ+DMjIzyPWSBMDZLAXI2UC4g1PcOyzps8l1xyOxQ99CTVXCiqpdAi" + "mpKrMGIgo7kY/AhGfRq4RMdT7s/IWi4jQ9AjEepAqenJssZ9r2TOueZb+InBL23jRqhoweNb" + "SpFZ+4W/hfzE1iPMue6PoczFv/6mG6lQc/HbjoIXhGnlPqKyIfkoSYPRPPSRSZY0RSqoeTpG" + "vBtakq/qJ0i8KGxfCAADQh8NcfZLhi31Jx35Yk0XyKTToiGgWS4aQ4Ck2XYIz2RYsMZ9r+xL" + "vE7mLXWFO8fQqvlodtK1CH20k6bhoaMxUs2WBDjXfEuk6xIX0s3DlXxIsl+eaf4BP5H8/9J7" + "M58QHnrEfosaZPuOjgY0D32Ec+f/TuEnfvvrbRk+dKTfIqh5uo37eOGF49wXmpBcl5O4PHQe" + "iSifK+euJKn7YnYdaE7VriB6GuBdF0lCeqouq3If0WiMTiddi9BHLIKUZyEZfiyQEPhlmCFQ" + "fHz1V4f4siR5Se5ZQcdpHhO8plAyU/fnTkmcvsZ9b6Smy6o8EhL6CVXjZOcnJvR8l1F++g/3" + "FT+wJIF9pIvRWSpdE/QRSHZKucRsGcKonB5lEr/tcHXyE2sumA7gvfR0CidGIjmugBpNj7ah" + "7PzMC70a03zkNYNnIZqgjyhkpVxstnALrMEl4VXxWgP6G9v4yeCledyiHGEJ+dqj+3NnWk50" + "SJGMVlzw+pHtro60H7U9KBw3eFsJN80oXpi8ny7ZmzAtzmiMptoKqBT6mqWBvat0Pxr3tsRD" + "FzyoM22D33nGei+PwiBdE/QRQkwp5yEtAeYDJzfdhEIWAPOBk/QM/seTPT7mAyc9wkSLWeYD" + "J9nrT+aUll10v2Cjp68tNPm4r2PtPsw089NDOBJCkprOnWaj4/QA2L93i+eLMxoVwu14tT7a" + "+j8aBwClZhYDar63b3+ft39LB35ZmxvXIQQ21TsEG12lgT5q0RpFhz0qpVyMECFKYlWewPIi" + "OtMcuSiBFr90k5LGVf7zIsq3kQ6Uv//EUP4UCfc8SiCol3DF+8/wD0B/nTpYQSyTrsuoah3V" + "IvRhTDQpn79h8fxTZyGlypt8r5kMkKZRC9J3J1v5i7mZqeMqjtMRj6xHC+qTEXqxmmfGWP/0" + "byEj6Phr307fUbIBTdCHJQpR+bBQ3qElrgFUR8z3KTvsUcJIhJ6/T2x4kHyGB6JtEinZmSkL" + "Kqg5P81r+kh10jVBH2YkYLAkCd+O+mZT6Md2eu18CtC51uAZNlqjgw9km5f9Zy9pkTfc6RGm" + "4ElWTNDTQhZ6Aj8lPUHSGiQ7vGS9m+yPslW1ns63cocZUa6jRgIvRVeQafSRjR7mc5ewGp/+" + "eMkP77hz9fL/u3/r0gkGlOv8z1RBT+DhSEuQ+cjJvOcAF7bzZAZQ5RqM3DwLGoy0SAeAdAbI" + "Zg/zuoMcDMh/kGKWO8NGp5louQ4sQX+QdARpSUhKkgzPuTNzuDOsoQPlhfYZWFkettLBgO6P" + "gy3b4lD9rKvmfm7vbnS6ewJBAAUG88SckpPKJpQYrcL6B9y9927/ULy/MZb8myefJLx9rPHL" + "73rbcMo4AAWnYO5vfxX41lN8Qb5wYu097TAQ2ROL9rmy0NwbLmiCPmyIlPLM9xUCANB3HnuV" + "WzaQKmMCPcoUmGjQLz+ErnCzkiC4OJ873QYAHkr2+OHmYCao0nPTdJhmxHk5+h8dkO6eAXdJ" + "bvCcXBCAA9njIy6OVulRqeMqdTjMKBZ0ADc1vFfy4PkP7dmHRTngKNkfYA4EaB5Da/S0ngnW" + "58NEmFf7k//YQcp917kteEcJAPQEyTYPDAR1Bu5UG3eSlb3fzmx0SzbhjrcEf1rAy1mIPFZQ" + "3uShFkJLpD9hyZycyjwPwlKV9q7Sjb2WK1h0+IN79gLI1evqrSYfNe139Xze2bzBvv8ntTMP" + "ywuJr5HRTc4t6/a5Dnn6AVh1xnHWsGz6akt+p8/V5u7TeQKebQH0cSpPjHio7IdS80gUl1Fj" + "eMIPwLdYL5k/IoN0TdCzi8iOnfGG5OIO0ykJcJiP3cy3nsCyItpgAPD23Wu4i3K3d+bu6My9" + "8PGvuR/mckeaYGO4hTnME2FFmmiDkVdz5n0n+0QPvAM/YAbcJGNIGSMIXhJKnSQ7vOz/dZOO" + "AAAQcLPNwZuLZDeh+QwA9iE7s9GNAZmgkwzB35dQHTFdXnHib89P+KsY+D7pN+2bO1ydCIJ9" + "tJv5yMlH/bSADd5aROsMwRsKmBt86B68pXHTjMGfFYIA7QH2X33MNi91ccTG0BJd8Ip8PiMl" + "Sdjn+9jn+/hpSaNoWKnCDceGfXwGe/JKaU8fS8jFleXHFuYSEL9+cq/f81jjl/tdPU83f/Xr" + "KfNz9SYAxUbr0vpjPUH//Ts+6vA63UHfkQVV4nM4qaz+m+4DZtZQ9vUBndu/YQ8B0PVUd2nE" + "iUU2it7080MJeOjJGDUSD33kabom6FmERLsTdldS/KDq4eAB8VFeKbkLcpknej6ZWgeANPuY" + "v9i5RyqgJ9w0k6TSG50eSrVmn+4dVHMAHJjtXq6XoxYCySY1eu6cHABoD+r+twueAa+Egnzn" + "VThH0hFgPguL3MlOX5GtqNNjdwXcSM7+fm/mE9w8a/CnBQCYZ3uYD5yDR+kO6v5m999XDhMT" + "PM3G/qs3tIAFd1UBCEgfp/tNB3qCAAgAb5B0BUkvJx+dZgTuJCs90gRgYVnxcYWDnWPz9KZL" + "a466e/sH3mDgk46mMysbhEUmVn9F3TEP7ljr5QL/aNpwy+STeLmnwHN7v2339F9Vf+wH73yf" + "wMlkonzQ3WsB3HS3NN1l/ax5AGZ+OKIGF9WqLWYLMdX8t7/eNkQeSxjM5y72v45ld6/lfyfE" + "yZEmPwBaKo10qD6k1zPfXSSpbQ2AbHQzu32SmdypVhAAYF/pH1Rzfn0HBwcHOXS3HNL9RqZn" + "EMOwACilAM59oYnPgUkEAm5hDgB4KPu2U7p0f4B0BhHeAZUeZaalOgDMmw70ZFOVKNFnmVsU" + "Mk8efPCtlSsetD66pe6fewsMZgDbeg9Ktis35VxccySAfr/niaYNAcoB+KS98evulh9UTG7I" + "LUvVCYrvu+/NfGLlL+YmfuHCGQ1VGLUIPStQ7qyfDTouIPFVAKCfAwC9NNxmdvq4MwFgw8Fv" + "6vNrT/jy0k+OeVZYKun/wkMPC2lipB8NQPeAHXLPx7yepg9arKNVOgDMTh98crF1dxDFLB2j" + "AwPeiuEGnk7IJpkPkgGiOW/iz3LrZe/zM2uWDm6Ypzd3+9xtnn6OUoaEXdMjC6r2ubo/OrS7" + "ydH1ast3RxZUvXLgu8PyyhdUTMJAXZeZN9IND0r/EyTEjMqVn6VSVQho1voPEt42a9EEfehR" + "UPOsknIe0hcRJkfxD8h6d6WtotVx0M/5t9u/327/HveVM9u8ZJuH2eKVDbf5MJ94qdiMHtzh" + "Fo8wLVWrQpY71kwnGWmFjuYxMDKEQbujQ3gETSqfpCL0M6HVOklhrxCVOgBgCLUwxMEBoGNC" + "FjlpG7IAUF4W5T5LIwDgpprvAOzvNULHcJR6gn6LziDZemHlYftdPY39nZ907Flv319gMP9o" + "3FEEMRScJzHxlb1wCev4iC8GoAn6EDMkhbQoHZBgAkSqMaPq96mAoLYUKLOWNPXu6/H0AMAY" + "HTdGhx9YgxzINx72P72kOTxtUUcAwEtlzkpu/08vWfI/G1a/c89L3Hm5fPBO+jhyMIA+HwkA" + "kw20gEXSjQp0IE2FFrEoUvrlE93AmrkDq7nkbaKhQuGzSLykIJU5c4aQC8ZMu3vb+wC8Qf/F" + "Y6ebWanoZzkju1S6JuhDyZCVRRQyxvQk0kMgekKTaLQT2+UEKLeUlltKfUHfRzetoYcb6eEm" + "WqEDAzrDFJhu0t3dSb4djLuJi6NWBhYieBfK/Hj16n19LdyFuQBIs499pIc0+oSbQWB5kVCk" + "JRmIM/T7Zz5xsf9nV7UJgeI9c8iI+VmEIgE5crUhOUpf3L8ZAAGhoP9t3TY5t9TMhh5HeNcl" + "hWNcaMSLJujZSLqdFtIVCGlMMYtWaf8OWsSQ3hTElQEuwFHu42Of5QWNAfCFe/6GxS6/a0/v" + "3v39B8Ai+OM8nUjQcSCAiQaqI3SsXhq8R2Fv334A4KD7cxfs6Ym89gdAAQKuzqD2ybyfQwUA" + "IJeJbBSlKUhZBKKVOlC+F8b6LMpFAl5v3ba7v+PE0rpCg+Xlli2dXuezzRuvqDtGeKa78cbT" + "hJWlOYXqbtIpJFqX4BEcpGtZLtkCn8SSmVQWPi8FADfZKFlErQyt0CO5Oos8O7sb39/3Mc0f" + "1A0+eLfoLYcVN+QZcwHQqjBtY74JiTs3z4roiC0Uh9cJgHQFItWcJGsdDezHwTFbvQBQqaMT" + "VDkMZN/AN1wnXZ870kSnSL/2FEIjWqfFqPkse1fpZEco3dTT+uGhXeOshQurDjuxtI5PSP+u" + "t+2DNqWExaYJxWpOLB0k0yV4mKJF6EPJULV5Mt94uAClOsItsAp9ZHjoCRYwYL6KIzejaULx" + "OJEBK86vAIByNrKFkwAsYQFIFpH3HGRRDjUSboGN+cZDvvEgcksAVKTpT1XBRGgeC75CwADc" + "LDOdLjUNEu5yxbzYxx1eAiCwrFB/R4dsmy0Mg/4V+dqD+VYA9DQbvnYLpgudbAzeVAgfDes+" + "mihhsbmQpl+hg/jhJiIuVvlZxKH6suU3HvL0/6v5a+ryLp46S0cYABfXHNnq7jvk6X+jdftY" + "a8GEHPmeYgFuIGqMdWKZZMS0gkpgZxX+IPZaGiMMH6W5LJ1gQAGLHJZs8RK+3+MkQ/DaQvRx" + "7KpuEv4zpydaabkOgNA1UcC+sDjf5Bcv2vPot3se/bbX6KT1BlrEws0RO4cAHX/1dAAUaHMe" + "aurdB4D9r4NsHewxRLwU3RydaQYBN8eCHIY4gsQD6ECr9fR4a3BJAfncTfwiV3qCgVbqwRJU" + "6EmznwQorTZwl+RyP8oTWnfZl/vBkvnrmV0nPQAABc1JREFUFgsbjb96+p5H+WHnwM2xoEov" + "+9EGT6wjSPSgk43IYbgTLYQSuCjxUegYWsbSmabgRXncbDPzeehGSNqCdLYZeSwt12GMjrgp" + "ynXcGbbglfnMV170BVGmA8Bs8cLEyCQOxQ+t0tPDjQBQwJIdPkIJHaun863BpQXMm2E1xNV/" + "lt6NTP7RHIB169atK/L1+73XTjmx0hzqi6QjzKSc0vX2fQHKbe9rP6pwjInVcWwxy4UqDfB+" + "S6HBp/LENJJHq4c+WjGS4K+LuQYjAPQGyV4/bAwdbyBOjv1TJxF1+aFHmLh5FnqYieYxAJjP" + "XeQrD/OpCwD0JLisgDYY+WQS5nMXafYzL4cKp4SNf8SBHPSTbq5gZoXT5/QEvQCYL13MX7pJ" + "QNpmyM2zBq/IjxbD6i5vJc5BBaTV+sAfS2CRmofMpy7oCHfMQKNoa+D0OSF7lx9BtPPTUN1w" + "WqdHHgs+rBYf6MEuiOuNEATPsnGX5EVm3IeWf+nW3d81eGLj9IHbpSdGvvXo7u0KLi8WRiwi" + "G9y6FV1IGlrMBh8op0bpuREv1f04omCO+s9SqjPckec36XxWPRvgJhdVLqk7Rljt+X3fbu87" + "1O1zAyg2WktNOWdUNrz8139goLhj3CemDm00u2hoEfpoJQjyqZv0cchlUKRDuZ5wYD51s/9n" + "Jy1hzaR0mpE7JxemgXS3MXpyMMBs8QKAgQSvL4KZERbBj5DWA8x3XmaDh9iD8FPoCIpZWqFz" + "u13BNi/zrYd9upd5pZ/Ixaakyc+sdcEPmBhiYaAj8FHSFmA2eph/9zHhBRpJH8d86YaNofkM" + "jAxxcmSTh32sh33NQSsGglYA/dyEsfX85KaO7/6/vft5iSKM4zj+nZlViowsKDCiQzcPspf8" + "AyKhwkP/ghdPdfHP6KSXAuli9ygKgoq9CBJGBIGBEREIloRFhuvW7qrbYWz2cX/kzM7sPPM8" + "834xh1FknZ2B7zzzeZ55nkq9IiOFg+2Ykgkom/u0fOhRQMT9WPMWK1IVGXTkuHsweeTmnvvu" + "j/tw23186Os4W/vu698y7MkZTwqOs173Hm17D7Zkt/m4IyLO192gXR/GRnHp5LeLHU5apeGs" + "VBvnPDnlScGRyr77qea83Cnc+3lo3oWI36Vx1qveHN4b9ESk4Trfq+VrI80pWZ58ef+jenC5" + "K3v1zWq5ePr8jStX37xaHr68/+ut28OBHUmdy+X67Usv7n7u4UNsRQsdORIpQ+/TchlZEL6F" + "qw4UCb/skd+VGjTSk5XIMlW2olMUiYm0cIQWdsyvHTNwUAvikXc49YL2vOwRUkMLHTBJ/PZp" + "8AnPyhfU34e/24VpqqfTSKd53oIWeh5ZHCb0hgIRScuIxvQPgMvUDS8WIe9aFkzQeCTpSKQa" + "dnzzCNoRuSDvMtLJFv4pIcHniZiLWwXZi/yLX07cXxGRnekx6XPqgo4410Bc8XuDIy2rluAt" + "J2YvsV+so8YvJH79Q+SCvFPrY2+1MuNje7pJZDGgjeKSGr/sTI/5zXNoQeQC6Kcl9km2pdw+" + "9GWg/sHfoQ8zNRR0oEnjUPowybhfgmtTA5ktkUFZV+fRFWp6WohcgCaN4cnMaMnfuv2BEaNx" + "6ALVi4IORLNRXNL1r2tTA7WphFbH6BtqukYUdCCa7HeBJtLbGcfafGFu7nnwo7qPvuJeCqQn" + "TkY/M1oy6I3WtfnCzHxJHaiOFNApCvMYVNfg13RymHQQuSCjukXVKfQNao8sbKKuUIp+40Qj" + "o/4fTbTMFJgR2Z9AGHYjcoFhZlcnep73Fe1iTueiC/MHdETkAsMknpvPrk74W7If68t4ehNU" + "85Z9GIqCjlwz4m2d1Bh0Bm7dWaR53o6CDvOo4UDGgwLj6o5BNR3t6BSFkTJex01RGl8IkpbJ" + "oXWtx4IE0EJHrsWfO9d0pfGFyaF1qrkdGOUCgHe1LEHkAoA6bgkiFwCwBAUdACxBQQcAS1DQ" + "AcASfwHe9K0xabrlBgAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +TheKid = PyEmbeddedImage( + "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" + "a9zlvVY5xpJgn2H7Jkevv3eruhfAeXe263vvN1VpaiGu1BsKpFmbmlYVcJWMyDudY5vwrxfa" + "/i215XaV2DcHbVCy1W2259nmRd6VCLweV5xMVc6O24blu9DtnExo99WxbAZ1Y8lkId52lufv" + "DkHemm/u/Tw8iXxAlv/1X/Lerz689rvs5kt/Sqab79eOF4ToNAnRqnQ0Z/KC6csXuNYcznu9" + "37nz2Znx34U+K7SANe8AbaN4NnTqmrRTqvK6Xss8zct5WqTKuTnVu8M54dzQrDFCm0jzThLh" + "3HEaXFy1YbIYdNksikix/Z1z3shkWK6t5VeLVmv5PWsW325UCT8L3dzCS3vZEpSbcwKe9FEx" + "/rnDofsvb274wOQk3/IIcvmx3/7JfPrKf6Dzk59Upoed9xq8Y5omDCOnVLH3uaE3w10r4edO" + "sn3N3WPu/oHyveuyC5ef3ZWTt7VUxKFUpM02fef1XNlKsVLe/TrW98p3HOFd3qvmQu3/l56T" + "DcXc/t0q/Ww2gHfmN+0+vROSlmvPa1L+DgjLWe5T2MPidCuvsIG7le6uxz+Sy0dfna+e/Zvw" + "+gdiZte31EGGT/zEd4X5G/+hi1e/30kehmEQ5xzjNNaeijVv2NYatom3iGxM913yD1b25yx5" + "Xl+17OIL9LK7ecJKqTbGp1GiLflfqdNziLTCudXJmsQ82zsr7tsI2HKLZtQt4myh1PbYu9As" + "hLDJSVaYuIVIS087K8XbiAfdKJq3kHKbu7RwdZbQnyX37Z4LTs1bnj89PP+8TY9f+LkPQo3k" + "W+cgL35+P6Rv/rtduvkjIvmyC168c8Q4M89FFjEMO+Z5OoNMIYQlmrRdzem22isLPoe7RrqJ" + "LuUfQK2O14R3S2e2HXiRmrSkuL5PmXl1lyJeOwS3BlWcqSx1ulQgmvO905lX3F+Ypw15sNih" + "LO8tsn6eRu8uzlAh1NJX4tdZXbq99vrfViiwbkCbomTVt20j0LZQ2c5b/r/pvsCpkCw/hPh9" + "/UcfXU9vfvnnuburfZutb5WD6OH+4V8dpuO/jMzPhdBpHwLTNJJiXnqpGyW5woCWI6wwo30x" + "KdUw33D8HSNqdYL25W6RRYMH65cqd758d2bEdyFL6fE+L8pBgVlLqJJ1F2/HLTdjI0NZGLCq" + "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") + +#---------------------------------------------------------------------- +Carrot = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAfRJ" + "REFUWIXFV9uRgzAMXNnXEaklJdACNdACJVALlJT4PkBm/Qyvy+0ME5MYdiWtBBExFnfBvV9O" + "12Ks8DlDjBW/vkuAe7+ca4lkADBmNs4A+k3Ez1+QJ4QxOsD1LyfGymUBSi4DwCJcC8hzIUOf" + "ClBcEqDkuSC9iB5pKZ7b8pIHOPUzgEeUBU8yRF+MiwgxVk4LqNY9wgygwZapxypIjBVziv0D" + "OGIlB30yTglg4+Uw0W9KOiPvlcMCSqlnMQ0WLyih+gP6Saa8VAKOlNfzKkjr3qy/PwYsLUip" + "OCQgjl5vrGSltc9ARxeu2N0FpYHD0MC47pp6dAhboT/ZBVPFfEquhgvIeQNhlwCOXg3GYMcH" + "vd6F+3gCKg6N4lLqs1nhZwAri/AxA7m2i8nUdJ54JefnfglVAaWBoxFz2z14z05yYGcJpsj9" + "HLHQXC+9AdVQzEDNeEJTTYyVINomvAdGpPWnPdUSzEiNN2ObanvTDCB8KXlu12YFaPTcsuyD" + "w+QVJB7ITTyNmut9BzlQyACnvlrv0sVHIMb6A4Bz7XIAcFO7HAAc76sdvBeAw7hdH5+LsVsJ" + "4vc7//jEvSmPkZTgcMovQsTY5PX6isvde/nDEcyAPhxUfO+gC76R8hy86fYaba8ZYwPGJhVj" + "YbTnvx21wvwnOQD8AjaMF/ZJlUR1AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Pointy = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAalJ" + "REFUWIXFl2GSgyAMhR90byRnkjPRM8GRNPtjDRskINraZoZpK8X38UJiawAQxQDjPIx9GHw4" + "LL+hGEDrQl8D+BaEBQDj/NcgrJb3T0LkFEgXJMTdIMbYx5/gJkQx1F+6sUL+HdgE9k4w1F1O" + "ZAeymOJESgkA4PyzgL0FQELEMBfCDMUuvQXE2Ic6ABAPioFimIvPFAMBoNb60fHT2j3vOKWU" + "dyzTkq+tC73iRAEg838oXF67DFGcAVoXimGuct4SLm50sVQrgLPCAIBpAoRjZ0CqM3BKWIhj" + "mmSVDKfE9iabXVE2q008v+Jc4+oCdIVlvAAxDKABvQNiCMA4jxjm3BnVkOIKRAukWQWtQ5hS" + "ymVaze8hlI3sD6fqAO84LxL5n7ad8XySQooDMrSUFACSzvlnFtnDyFRIN44c0CDUpyGAipQ7" + "JFsuH9ExzNmZnnix2S0dTYAjIAlSQQyGcb7twChM79lw1EWN8+1W3F24nRVaF2o2J/y5c+TK" + "5UbEINrgeeefZZVo97iSgtGQP+32TvAhfMmBo2A3ek7c6oCMfRXlvwGfAmjFL1FBV3kCEik9" + "AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +Pencil = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAArlJ" + "REFUWIXFl6tu3EAUhj8nlQJa4gcIGbK00lkQqSBNdvMKIQVhzgOE5BX6CB4UUBRWUOZcDCIV" + "5EiRCqIQK6C8KGDB7hT4srZ39ubdqkcymPHY3z//OTNjB8HOLv8z3m3zZW4ydr7+YGc3+KcC" + "SrCTyHs/UOvmiQg2TUEJj+MYgCRJuM5CiPI29rwU4XViIwFuMnb39/cA7O/vA2CMwVo7FVKH" + "eUTsbAtujMEYQ5qm9Ho9hsMhp+ZP45lYopk66VQDJfzw08eqL03Txpher8fe3ntOf3znOgux" + "c961toByBocvn+GlgPdyMenDUzXu9fU3o9Hb0vetlQI3GbtHB48ONMovgA8XF+jBoOHIaPRG" + "lmUYYwh03vzXcKCE10MsEDmEvK70YMDhzxvShyeyLMv7VGtPzApZyYFFcOy0qCVS9GBQtVW1" + "EgKWhpYili7DVeH1UCtchmEFz7KMiHz+5Wq5ub0LYIkDXeAAl2FIkiRQAH0xOD5yg+MjN1dA" + "V7it2WyMQUTyfiAMw5nx3iJ0k7GLY0FsK2mrwFWg4IhIVYRhGHoFzDhQwiMRkCi/itDzPqqy" + "EC4yFa2qJEnSgLdT4nUgKmxTyQ+UEqko4qnkJnwqcBn85vYumFsDJbwtTIWGC234ZTYtwGVw" + "8KQgjv0W10XMg9djFTi0UuAmY1cHAIiez4hQAWw+rgFXSHS57fW2NwVV7j1wmLrQhvdV14JD" + "y4HS/nngMqxqgd0MDrWtuP6h4B7933YlHIpNSTaDQ8uBq6tvPD//Iuh/9Qqp4FpYvyG8IWA4" + "HHJ29oUgmB1va8eYqBZVuDm8EuAmYycinJycNG4GfdtYlqJK3wIs3l5XhVcCYLpttkNsPtMy" + "2lDfabcqHIoinPdHsw60CxwWfJKtA+0KrwT4/lhEZKEr24BXArpGV2hnAdsAtuMv2rGEjWiw" + "u+IAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +WXPdemo = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAWlJ" + "REFUWIW1V1sSwjAIBMebeBU9db2KZ8EPmxbCI4TUnXGskWaXDQktwhjErjERP4XRhER08iPi" + "5SKiyQR5JyI7xxB3j7wn5GI6V2hFxM0gJtjYANFBiIjQu7L/1lYlwR0QxLDZhE0II1+CtwRC" + "RI8riBva7DL7CC9VAwDbbxwKtdDXwBi7K+1zCP99T1vDFedd8FBwYd6BCAUXuACEF7QsbET/" + "FaHs+gDQw4vOLNHkMojAnTw8nlNipIiwmR0DCXJbjCXkFCAL23BnpQgRWt1EMbyujCK9AZzZ" + "f+b3sX0oSqJQ6EorFeT4NiL6Wtj0+LXnQAzThYoAAsN6ehqR3sHExmcEqGeFApQLcTvm5Kt9" + "wkHGgb+RZwSkyc1dwOcpCtCoNKSz6FRCUQ3o7Nn+5Y+Lg+y5CIXlcyAk99ziiQS32+svz/UY" + "vClJoLpIC8gi+VwwfDecEiEtT/WZTJDf94uk1Ru8vbz0cvoF7S2DnpeVL9UAAAAASUVORK5C" + "YII=") + +#---------------------------------------------------------------------- +_rt_alignleft = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEJJ" + "REFUOI1jZGRiZqAEMFGkm4GBgYWBgYHBx9vrPzmat2zdxshIqRdIcsGWrdsY0cXo6wJsLhoN" + "g2ERBhRnJooNAACQdhhQZbXeGAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_alignright = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAADxJ" + "REFUOI1jZGRiZqAEMFGkm4GBgYWBgYHBx9vrPzmat2zdxshIqRdYsAkS6yLquWA0DEZ8GFCc" + "mSg2AADQZxhQFG0xxgAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_bold = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEtJ" + "REFUOI3NUkEKACAMyq3//7jWNQwWY0HzKNOJCIi2DCSlfmHQmbA5zBNAFG4CPoAodo4fFOyA" + "wZGvHTDqdwCecnQHh0EU/ztIGyy1dBRJuH/9MwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_centre = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAEJJ" + "REFUOI1jZGRiZqAEMFGkm4GBgYWBgYHBx9vrPzmat2zdxshIqRdYkDnEumTL1m2MMDZ1XDAa" + "BiM+DCjOTBQbAAAwdhhQDziCqAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_colour = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAPZJ" + "REFUOI1jZGRiZqAEsOCS+Mcu9h+bONPPV4wofEKa37Lz4zWYEd0LuGzG5RKsLiAFDEIDllTz" + "MWxtyGJ4yiWKofgfCyTSkGMCJRDd/hr/Z2BgYGCZ5cAg8v0jg++C9wy6zx8ysP37zfCYXYFh" + "g1gww+VfUSiGwg2AaRZ/JcPw6v0fhv/qLxg4vv1jCOv5zPBvZgrDSukghp8/ZRkY/rFiGgDT" + "jBV84mX4572WgekzL8O/v5hBxoRXMwMDw/+3QgwM/3CHNeFY+MvMwMDyE6vtRBnAKPqWgUH2" + "OQUu4P/IwGh8HrcFBAORgYFhF/NZRhetP1jVAACsCFJPHjA77wAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_copy = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAATlJ" + "REFUKJGFk71OwzAURo/tpE2AdihiAAmQWNiKWICpDIhnQEi8A0+ASsXAzDsgIcTEA3QANsZu" + "XTMQBiqkUkFF04aB2sRJSO90bV+f+33+EUIqzq7bMam471UA6JzuiPRaMqROltc2KS9tMFhY" + "JVArAJw31qlfPWfguYCqp6j5Lou+S81XpmAWRGgLe1t13r8i+sMxYdAtasrFyYGx5eik4v11" + "DYHW8T6dl0/6w4i3wYjXjxFh0KV51ADasYYYQNUzKXlQDQYsiNnluzLJA6CsBKQgrdtHa2x2" + "zJdkeoq5koLvsYEc7m5bdqxqRwk8V5C4GFwlDCRKKdR2Egq01IkpUhJgCsmKtkdKJiHTOSFA" + "xoWQ7NFbgF8F+ZAU4PLuKbMopYBJXAhxwH5ZgPW5ZkH+tdC8eShyZ+IHUNNZHhrzal0AAAAA" + "SUVORK5CYII=") + +#---------------------------------------------------------------------- +_rt_cut = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAbBJ" + "REFUKJGdk0FLG1EQx3/vpRdv7sG49CKYxvSmVDwkpd78ALbSShQkbU81guAH8BN4EE0KGlCQ" + "5iAIoiaIwWAP3bi0WXZLW1q2WfGmJ8mhV19Pu+xqWsSBx/Bm/vObmQcPIWP4Jz83r96vb6pw" + "LJxzXfdWThKyuJR8/2rjOI4Kxz8ZDQUwkHosuGERwOLKsohLydpaKSIqfyjfrOsM8C2VSlKr" + "1RRAtVJRAK8mJ+8GWFxZFldui93dPTzvTFWqhwCMPnt6a3yAB52CWjLBSCLBwcH+P0f/7wpX" + "bouLywvys+/uB9CSCfRendVCkezMm/tN8PnwiKHBQX59axKXHWUACCFjAHyp15VX2gIgbdg0" + "MkO8LG+I7WxO+XeARwt5ngwPBw8q/eLe1wtI75y25QTCsG9bDtI7p+fFW6xmU0UAXmkLU9eY" + "OK0LNf0cIOji+4ezOSZO68LUNX4vrUbfIG3YXPf3AdD9o4Wpa5E9TV3jT8MC4Lq/j7RhRwGm" + "rtG2HPx9u6bGI4CuqXHShs12NqfalhNtIGSMn8cnaiczpnYyY6paKHb8jdVCMdA0Tz4Gmr9P" + "zKg0oZ3GfwAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_font = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAIpJ" + "REFUOI21k8ENgCAMRSmMpwzAgenUsgDMhweCgUpRJDYhJG362v8DAFKJmZBT3W8A67LFz4Bj" + "T835HgY4V99DADqV24IF5Kk+WOht0QTkabm5twW03kHPeQoVIFV1EDFqjZHmtU55xLp2k8Bp" + "NaZdrwCcdhqlF5cHVHcJ4TzxwULTxJH4/zM9xQmi7UCACkKFWgAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_idea = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAVtJ" + "REFUWIXtl2FOwkAQhd8u3gAJp1EXuQEBrmOU24DxBtoWjmA8BAlXsOsPXNjadjtvRImJ708T" + "pnS+fTudnRpjezinLjR/Wq5K//W3+cwazbMM40BIPJ3c1GKPT4UKRASQShxruyuwWYMC6QRY" + "rkpfTZwBGCUhAGCzlkFYCeUxcTW5Ma521/Ay7RIFcFx9VouF5E0QAHB13VysFEBd7dbHYlxo" + "BUitXgohcYFwQLZ6VoJGpE+834oieQ9ZA5zCK3kWAEnyJMB8Zk1or1pJmpHaAe/zylUrRSvu" + "VjgTJK1YdRwD1Q4YuyDd+6DOLWBqgT2IAGIekGwFY30QVYQpJ+JZgJEYILUqzSASRBXh2+sd" + "Bn3XGBv0gTzPASyYR/JvwT7J6UQDOOdaYxq4fwcogPuHhQHQOuF8xilRHyaxspfnA8jodqz6" + "KvoWgC/fDwDG9n4f4FT60ZHsTwB8AA6FjDfFEDh8AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_indentless = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAHRJ" + "REFUOI3Nkm8KgCAMxfe2TlftCJ0u6ATa9eyTIqZiKdEDYfj25+eQwEKlo6qu5oOFABbq0eSD" + "dZldbBh7Ir3LaSTB7ozdEJstBOyL3xJA9bgVpyTVBmAJBK1PMPYMefx0YpagR7/6B2WCeGnD" + "CbhmfrKDC/GuLg9MR0atAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_indentmore = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAHlJ" + "REFUOI3NkmEKgCAMhbfZ6aododMJncB5PftlTE2TkuiBID7f9jkEJAO1xcyh5SMZQCQDbzTF" + "zbrMQRtOPOZnVxpJYIOTDbXZQ0BpwN4GciHzXoRykmaBOIPYXYdrT3DizzuUGv2dC4Kn+tU/" + "qBPooQ0noJb5yQwOwa4uD/KzgEcAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_rt_italic = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAGdJ" + "REFUOI3Vk1EOgDAIQwt4/2P0lopfS6YOgsEfl+xntK8kMBE1dI623F8Atqzox+73N1GTcgez" + "mOTDPEThJekAHIBHmhQwzCTfAyrpKaCSHgKq6SGgmi5qkHmVV3Nfzf5S+/9faANOrocplI0e" + "xSoAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_rt_open = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAbpJ" + "REFUKJGlkz1IW1EUx39X3zNRgwFBMaCoQ0sFJwfpICgBccgkQQlOIUWE0lJCVTS0KWhU0KhY" + "LeigoIMaQXCwgx9YR3XoIC2lpYMu4uLg0/jy8gLPQfLwGePimc79n3t+5+NyhcjJ5TkmPSbW" + "BwaM++ejhbDICqjy9hoPxaOFsKgPDBirUQ8APjCyQSSAd54mi7hVUWZE/B583TGmwy9YjXqy" + "QkR1W7/xEKBoOopyxXXihuPTc758dFDjasTdGTPvnKyPCoCcx9oqssmUlxTzqqI8Izb9oSNz" + "BICZ7/uWQKnTYfqq8QdoBOD91DIAVd5eo7bSZX2Fr2992GUZm02mZ26NN8M/AbgAdpKD9H+D" + "5rzPuDtj/F0Zwts3czeCoqoAxFWNhK6jaTpjXe3Mh+osXaWTfy2G2T74jbmDpb1DAi0NXN0k" + "LJCIv9WEpJMPZ0Noeoq5jR9sTgSFOUKBJKFpuqWiXZaJ+Fv5FIKRyxg740GSqSSQZ13i65fV" + "KKpKEfkZW09DnMWFxNW7Av9Oz6wAhz0XXUuhkB2SiCehEFBhcm2LzYmgAJCcBXZ2j/9nJD1l" + "tZUu0xfP/Y230rSdugX3RssAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_rt_paste = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAXNJ" + "REFUKJGFkzsvREEYhp/vzDnWWHuxdnsJjd+wRKPYgkIUKqHVKtYlQoi4FX6BiGQTolEpFBIU" + "/gUJtbXWdSMuo1jGHueceJvJN5nvmff9JiPiKH6UL5YMITrfGJWwfQARR5EvlsxY8pqr6gvL" + "60u+A3NT8wCcOd2hICdfLJmT/k+AQPPPXke6hcP241CHbmOxtboW5TRS0jO9a06HM5j7MgAf" + "lRsAzE2N15cLBm77A02NURxLSmUBUJlcvc5pYi1dAGxODDI7WgDgaHHEF8UBkERbJAQgrV2y" + "rZ510AixM5BEG+bxDkllMfdlVCZn46T071MXFvZ9cVwAiScxzw+hEIAm5ZDSsD05RLX2Tvnp" + "jZXS0S8AnUAgFALQ7AlQh/yVHSI6gcSTNo5vJiI0e/LtRJHWrh8gno6EAHhKLCTepHwzqaNi" + "McRVmNpTIA5U6J3ZC3r3AZz6IroV3j8wYCFn4532cN/OZeA/uAC98weRN/ynL78NdulpYuMM" + "AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_redo = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAg5J" + "REFUKJGdkr9rU1EcxT/3vbz2vfS924qRpmopVmIsFCWDiFkCAXHs5CDoJqSrJIP+BS5tXCw0" + "EHDo4FBUguDgULVQImJJLe0Qu2hqWyKNMT9q0p/XofRHmtrBA9/l3HPPPffcK4Sms4fxyRn1" + "NDXFYqG0z4Wv+kg+uC34B8SeQTSRUq/S87SbLU2iUn2D6/5unj+612AUTaSUEJpO/OV7Nfb2" + "Mx5TA2B9W6OyuYVjuGjVdxq4zGhMHD5QCE0nFB1RHl1h6DrZ4hrhgI/+nk7mvueZyCzQK00M" + "XadS32G5VuNyTydLywUqm1u4AMprNXxdkmp9m3DAx3BkoPHOg0PKf6qNrg4Dx9TYKJa45HEz" + "vVJGA3AMF7bpxjZ1zp1pb+ogMxoT2eIaAN4Oh+7THdimG2A3AYCUDtK2SE3NH9u2bLOwTTdS" + "OvucY6zuGlzrv0C1XuOsI/G0NL9YYHBIhXq9SMtqWtMAhiMDYjpXQNoWtwJ9hKIjak9w5/GY" + "AljIr5L7XaBcqyFtC2lbiBbj4B/cfzKupLZN0H+RX+Uqzz5+JR2PNMQZn5xR2cU887mfLC0X" + "+FH5c2AAcPNhQt290cf5Tg8r+SIjH+aaTJogNL1hgrGkejExq2az39Trd19UMJZURzWHRztq" + "mI5HxPCbT6yW1rni7ybo954YwHUcmY5HRNxOKmm1nrgZaOzgf/AXUUy2DjrCDG0AAAAASUVO" + "RK5CYII=") + +#---------------------------------------------------------------------- +_rt_sample = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAMNJ" + "REFUWIXtl0sawiAMhGcoN2mvqIeoV6RHUVwoC5VqiOkXFsyahJ+8ADJM8FRw3X0A9AAQfy3I" + "t2vWOGaYaAIAAPN8atp82y7ite4pEAOktCKl1Q/gKLkDiIpQovfCk3aPGQAA5MaGJYGo7XMr" + "RQD4RiCaJi8q3mSWHRVhSSDr5MtyPgTAPQJEOftOBFpq4OlIbElKbsOaIT5vO203uafAHcB0" + "Ej7UNjk6isBO/7dI48IsBdI3YBXg/7PrxfE1GwDeAHen2yjnZJXsxQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_save = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAQ1J" + "REFUKJFjjE/L/c9AJlg0ZxojCwMDA8Oee78YvOzNGGbVJBHUFFc7hWHfiSsMLkpsDAwMDAws" + "DAwMDPE+rgyvP39kYGBgYNi7bz9Ozc5Ojgww9U+vHUQYgE0RsQDDAGJcgNcAsl0gysvPEFc7" + "haAGWRFJ3C5AlyTJBTCw7fxVvBq8DLVxG7Dt/FWG0kBLOF+In5eBn5eHgYeXl4Gfl49BTlKQ" + "wTChCcUQDBcwMDAwlE1Zy6CppsrAwMDA0JTkjtdFTHhlGRgYfv3+x8D89wfD7z9/yDOA+d93" + "hq9/WBh+/f2LVR7DC3KifAwrGhMZhKXkGTQVJAiZz8DIyMTMEJeSRXKOXDRnGiMDAwMDALeo" + "P7cp9rvcAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_smiley = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAATpJ" + "REFUWIXtV9EWwiAIRdeH7dP3Y0UPxiIHXjR31kO8VIPuvQNFTCkvdKXdRv7EjzvXz1Je0qkC" + "NCkf6IlSevt7xCRUAiG2SH3QuJCMyJn7yIlKPLNdqtrMDIy8tU/w+nSy4WZgBrngtLJxECBp" + "tyyBiiI/FIDImX0S5Pey0FyENbgA1STI3xKxC/DeXoNrIPQ7Wg6YAQ3eswaiizhUgjMtE7UX" + "nzYUE8XQ6+A3MvAXgKy3w/XEZ6JyUES22LQYdTCFB5JNARDZ/UFi1ihoVIB0ts0QoomFvG94" + "UfMA6gciwrMI+XAJiD57vBayKn8PeXlWTUTRrtjb9y1yImMbRnaEkI7Mi1DALmRoyrdxvLcv" + "/sZYHi1HkxyM5s1OKOUY6YQR8hIbvBvim5H6PvNmhMSMkH4tYKZdfhw/Ad89rp/htXYGAAAA" + "AElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_underline = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAFdJ" + "REFUOI1jZGRiZqAEMFGkmxoGsKAL/P/39z8yn5GJmRGbGE4XIEvC2NjEcBpAKhg1gIABS5cs" + "/o9MYwOMuJIyetwzMGBGIV4DiAUEUyI2gJKwBjw3AgDOdhYrghF5ggAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_rt_undo = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAPCAYAAADtc08vAAAABHNCSVQICAgIfAhkiAAAAhVJ" + "REFUKJGNkstrE1EYxX8zmcSZZDJp2rSNfSg22CANYhYijWjAjcviwkVxW2hBVyZ/gZu6aOtK" + "aLC7dicqwcdGiIrUoCIhpUVDsPZhq4GENqE2aUu5LuqkLxv94Fvce885995zPkmSLRxVffce" + "ikQ6W123N7i41XOR65fPSeaeFH3wTAz390h7ib2D4+J9ZhGXajskWqxscq27C5MjP0nOEInF" + "hQkIDgyJpeUCvjoVjyrjtCoAOK0KHlXGV6eSSGUZefxaACgu1cbH6W/0Do6LL/M5WjQNpyqz" + "tb3NbKnClaCPwMlmpudzJFJZ/G4Hhm2b+OQMAApAp8fOykoRv9uBrlpYq+yQU6NRKbXn+ZFY" + "XCzNLeN22Jj9UdoV0FU7umoHYK2yTmblF6nR6D5fAFobXRR/5tBVO07r+o6A06pgGM59QMOx" + "9ddU4pMzhDu8ICtAHgAZwDhmrXZbYz3hDi/BgSFxUMBjkzA0jbXNMucDp3YEJJsVQ9cwdI1S" + "uczCaoFsLl+N0ySHI/fF1eAZDF3j00KhGqOyWCgy8TZNa0sDXSeauNTuqw6KaWD37Zi4caGT" + "ekPnXeYrp9uaePPnTKo1iSb5ZjjA8WY333N5JpKfeXm3f9dgSbYc2aHomHj6Ki2mMnPiUWJK" + "hKJj4iBGrnV7yO/lrL+dfHGD4RcfSI70H4q25hdME0vlDZ7f6TtE/i8P/lW/AfYJsF99ZciZ" + "AAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_rt_zebra = PyEmbeddedImage( + "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" + "OwcAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_bp_btn1 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAABLpJ" + "REFUOI2NlVtsFFUYx39nzlx2Z7eX7S5FyrVcKrcW5WLLTVJAiZAGCQFjJEGixsTERHyQxER4" + "wQf1RcODl8CLiRElJBARqGBUioi0GKDY0lIopaVAW3Zpt9vd2Z2d8WGgC3LRk3wvc+b8zne+" + "//+cT/CfY7MfXyqCo5tgu0g7QVLvgx3W41aJR84Ym6txeQ1pPItRMArdrwKQTqSx4p1kU0eR" + "7CT5acP/A5vvjyKb+gyzeF14eiVzq8oon1bEiJCOnYVrPRZnzvfRWN9MvO1Ph2TsK4L2FqI7" + "Bh4NDmwpJ+vsN8sWlb60cRmvrgpQOgJsG1JpyDreb1YWznfC1wdiHNtXi3214TSKfJHkx10P" + "gn3vjkXIusi8mvHbP1jM2kq4EYP2m5CwPKgiQCqgKBAwAAX2HIfduw6RbP75NIH00ruZy2Gw" + "rPwmOG3ZMx9tX87quXChC/rikMmCpsL0sd4G0UFI2xBPwVAKykaDHZpC26VoidN7PUT25I85" + "sP7OavLHbd20eT0bl6mcvQL9Q2BlQFdhaQWMCUOBCX9d9sBp25tPWlAShqvWaHrbGmcjZh3E" + "PtmtAKCob46ZvYD1S31c6ILeAYgnQZNQXQ5Bn3eopg6b/gQMpnIxkISsDeUzQpilVQpCvAGg" + "kr+tCE2fX7WwDJ8KrZ1eNqOL4Pmn79QSOHTKovaciqqCEDmBhOLVPpIHoUnTSF2pW+4UbDMV" + "ZHaULHyicOqkApquQnMXSAEr5+Sg9S1p/rioUpQvKQh4303DE7E/AQNDXtb54QhqMDwGKzte" + "VTWRb+SFEFLhTLuXzYYl4NdzLqyYqPPU5JyFHBdc13PK57Vwus0TWGo6MlCgq5lbERXVj2ao" + "JNJwLQZjitw7Nc050dAeuEbDIxx06RsUDGUg7YJmaLhSF6rwGYOQZijjcispaG+DD/dm2Lpe" + "G4bXNWU42eqQ5/cydVxwHM85R5pU+pMSBPgMG+HaGambMdVQ1BsZKz54Oz4UjBQFSMcE+89r" + "+Pw279WogKBigsZ39S7H6sFQPfBd+QwNAkHQNRjojeO41o2EonbIdPTwkFa8aoUZGTlh4uQQ" + "iQyYpqD5psJAwqZqkoJPE1TPEHTEBDFLEAwITL/A9INheJEXhJtt7fR3tx9IX3j7WwVASrnz" + "aksbWdehJAJmAIpCgtpLKjuP24CLX4NX5oM/AIF7wgzAyDBgW0Q7LiJ1Y9fwzUsv3vC36I4v" + "w/CPmzojjCbBlWD6BK23FAaTNhETjrS69CQVfD7QNNB0iOSDzweNvzfR19m5p79+0yf3SR9a" + "snumKmXdvBULCudWlpDOQH8KbAfsrIvEwREKqiJwAU2BQr/3EJ34tZ1zvzVcVhy5qK9u7fX7" + "PQWEl+6rlqrYO2txRWjh4nEU5ikMWZDM5J5MVQFTB58OvVGbY7+003yqqUPBrek5uqYxJ+u/" + "xsjnfpjpKnxRPG7UwllzxvLklELCBTqa1z+wMi59UYvmltucbbhCtLvvgKbYb3X/tKbzXs7D" + "W9O672VxIvgyKK+b+f45oaK8oBnw4bouicEksWi8PzWYOgF82XPwhf0PQzy65909QU1tqeOI" + "MgcngiNdKd2bmm23XDu8sutx6/4BbTzYDeu8eUUAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_bp_btn2 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAABLxJ" + "REFUOI2NlFtsVFUUhr99zj7nzKWdtjO9DBWkYGnLrS3XREIaMCZAguCFCCQGQV7wFkzQaHyQ" + "QEKMDz54iRITA0ZjeBGJmCCJUoMiBEEQBCmUll7odWbaubTTOTPnbB8GC6gVVrKTneysb/1Z" + "+19LcF+xU0Kvmb9PsmFX7l4ZYsKX4M4AyaEnUPpqpDUbXRYB4OTi5DKXEO5hCt1DxD5I3D/Y" + "2r4Z4XlLlNdMe3DWHGbUVVJR5sNV0Nc/yrWWHm5e+QM12NKOm9lN5r399wDvlHjieyms2tq4" + "ahVb19fQNBeKfOA4kHPAdmAgAccvwoGvr9LSfAQSNz5lrGjbnS3S7+Ka8/Zp4YYtm3ds4v0d" + "YeZMgZ4odAxAVwT6h2E4Ba4DNZWwZFGIYX897e3R+Wq0owrn1KF/g61XXiY4442trz3D7s0+" + "4im4MQAjGUiNwaRiUAoiCRjLwtAIKBfqqw2iZi2drZ0N2DUxnFOnb4O9L1ZCwYGH12/0vf1C" + "Kb1R6IqC60JiFMIl8MhcmF4B/XG4GYGcC2kbcjl4oMLgWryceOuFhRgLviB7KqUBoIxNVtW8" + "0ueenkpyBNr6YcyGSBI6ItATcVCuQuqwch5MLYdYElJpGB4BQ4OG+VMxpzSU4YpNAHmw7ltT" + "t6iBuslwpTuvJJHOtyKZht87ND7/wcZxFLoGaxfDjMp84UQa4iNQGYTi6kaE5V0LICl5vQgj" + "UDt7VpiBIfizO99yQ+ZVaxpIKTjXZSKPZ9mwzEDXBBuWgp2Dky1gynxOYUWYIV+gNmu+Gpb4" + "9QIpAwWBgIdzbdATg+dXwszJt35Xu+1MxzVB5U2qCXh2GQzG4Xw7SAmG5UH3BwpIpkLSqwLC" + "tTzCQaMzCpquWDAdTGPioRwvJSBUqIiNCEaz4AgNaXqEY5ia1P1yDOlmRu2sEbMlfUOCN7+0" + "aaxSQF6ZJgSZnMJvwZrFJqbMF22+mGPfT4LkmI4CLDOLkG5G042kTBVejXtHG7tjw6m6YKWX" + "aBp+vG5y7JpCiLwqpcBnwZ51jENPXMmx6xuBLXT8fjAMiPelQNndGcPXq3H2k6zQRXN3Zw9F" + "ASgKQLAESkOCUFBQUiKYVC54Z6OgqS4P/bUtx57vBLpHpygAhYVQXAxjQz04SjTTuj2jAUhL" + "7u9ra1GJVJopFeDzg78gf0wPNNXBkofyfT3fmePdZoH06gQC4CuA8hCobJpYR4uSutw/PnmZ" + "3sM3zYq1VRlHNs6sD+OxwNXANMGywMGlqsjlesTl41OCnK7jtcAwoTQAHg9cOHGZWHfvZ/Hf" + "tnx0166Q1etOpAaH1rjSW1o3s4RiPygdpAk2gpNdirN9GpqpY1ng80C4GLxeOPNLG21nL16x" + "TbXR7jg4mjfnHRFafqhW19S3NYtnVzctr6I8ZJC2b+0E95YADXwmeEwYiGU5fuwGV09fanVc" + "sTra/HjLbdf/I0pXfDUJ1/gwGA49Wb9wGrNqSygNWuO+trOKSCzD5ZYhLpxpJ9YXPYiWfSly" + "9Kneuzw+kfnLVhxZoXRtm98nlwaChaX+Ai8AI6k0iVgyMjJq/ywc9g4eXXX0P4dnIvDfUf7Y" + "9xUq51S7qDIADTEopN46cPjR/v/L+wte8dZC22ApeAAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_bp_btn3 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAAA/9J" + "REFUOI21029MVXUcx/H37/y7594ul1tASKL8UTHTxD9zUxwYK3OK5sgVlG2WzuZKe+TaatNm" + "60mbzc3+Th9UWipNzdkqjRqwGsGGdsNpjslVQLjA9R4E7p9zL5dzemCY6FVarc+j8+D3ee37" + "O7994X+KGPtQK+prM9P00ril2EKRpIgpx0yhvMOx2btTNjfFXkKTdiMpHkmSbEXCTtqctfaK" + "JQDK2DkNueSNF/Idj8x5gIuGxQV/XPvyZP+7g+suTeXY9NfGo9EdXo/YaauqEh8VTHnwxoT+" + "bhZYfx2Rxs5GLHnX+0f7k0P9Jo/NcDB3pofKVblSRpZrG8/3HL+Jbox+UjhJ2pWXoylCFuRn" + "g6ZAdx9W0mLPHb8CgJVnqjz3OT7bsWGyvrDYy4/t4POP0uQbxgjbtSja8PypaqXLrYlzvZB9" + "P9g2dAYYSSTZzkdi7xglj4Mv7Tsfn7nV13BupCLLI+vLZjnoCUsMjGhEE9I0VVVnOZya6LgO" + "GV5IJqGjl2jSZjMfiv0pH29cqtqLsPX6zSvTcyqWujjQLPjpPERNkCSYnAlmAgJBBmyL1Xws" + "Gm8npFQuNdPacIsl+2sTbftOJaheYLOoAEbtG+hQBHqCdNsyZanQu088lpe7XZgZtSWPaiWb" + "HhfUtsHJFohGacVBOXuEcbfqvWGAt2yFHo7PyWONqsFvfhqwWMU+Eb1XbWL4Bi7Rx5uAixhv" + "87kwJ6r8DZeeKCMUrGQkKlBUGU2/itO9n6ZnU1/3mTo3MX0jsjwD1FEUFRTtO2qKfhgHO8sO" + "DzxZmu2VVY2wKbjSNUTbReN33GlP0PDUtdtvIFp+rRPu9DLb4cHtknE6BIYRiyQPFrrhlpWO" + "Dw6E8rILvdteXcTVsODMHwkOH2otPtPU4WPZ6dU0rPABsLypQG1pPJU3Pbso5MxD0RWmZIIR" + "uE7QSA6NeTcXxM6uONLcGKjoHUhklS6exKisoWY8hGnLnr6A8RwPbz7N7FdUt5psmj8vNy+S" + "lk9CkpnstejvCtHVOdyJ0Mpofe/6OJi+byNMq/7igs8ob+8M564ozULRVUJ2BnFb0weCQ+tl" + "rC2LFhZkhhy5BE1BjidJz5Vr9Aci59Hkcg7mdt75eLdmbs2J4sU5a3e9Po+OaBoH6uCyP0Q8" + "YSPcmeguyHQmCFy5xqAxUs9X+eW3E3Iql76jR/q0dbktrYPzV5Ski+lTdX5udzGYcOFNB49q" + "0tMeZDic+JqaglWpiNQwwNVD3xjp661fzoZLl81zSUuLnXQZMBqN0OsPWrGY9QFHCl+8a3/C" + "LG/ekP60z9z5vWFvOR62qb48QpV/+0S1f7Z5a8+t0XTHp6quqhFTbKUm/+C/n/Q/5k/sN4aU" + "VfMVHQAAAABJRU5ErkJggg==") + +#---------------------------------------------------------------------- +_bp_btn4 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABYAAAAWCAYAAADEtGw7AAAABHNCSVQICAgIfAhkiAAABG9J" + "REFUOI2N03tM1XUYx/H373bO7xzgAAJGCOEN5CaCXEZpstlkZbY516i2bJUuHEvTudpaLWZt" + "6VotyaVhzWbrolRbFy+ltnA6UQyVywTxriTXA5zOjfM7v0t/oISh4vPn9/s8r3337PMVuM+S" + "ircfcwhCnm8ouJlE9zsc3qDfs/++1Kxamxqlb/xoU5nLriqPtv3lryDuCTfu/WfuNiLcXasS" + "yUlOwNJsmKIqO6T6nd88ExeT5KL+SBe7vmrgQvO1FkSxkrOvHp0YLq2S6Ut4C8F60RGpxDlU" + "WTJNC1WRHBVvLxPM6GgcdtBDBqeOXub4vkaz+2p3Haa4ko41l+8M526dTDh8OG32lIziRbNx" + "PZCArChYgAiINic9AREskBVwOMHwh+hpaud0XUvoRo93u3Wmcs3tcGmVTN+klvR5uRnZi+fh" + "CysMayCKN18gQBTgDoIogGWNnEt2iI+DYNs5/txVpw2fWGUHkEfh/rh3J01LzshevIBhXUSV" + "YNgzgHfQCwJIokD89CRcThlMsKkg28DdOciRX0/T13ahG1lYf4v7DxbE50rKcslMFTFNqN/T" + "RP1PxzRdN3sBUbbLiYVV5eL0xFjsCgz2B2g41EpTXbM/5PFto33d62O3OgpHudSkksIYZiTD" + "pQsDnNzbYOq6sYTW1QfJqrUJkqczPVVJiI03+f3nNg78cEp3dw58j2pbS/u63v9nYBQOaqbx" + "xQeHsNkky+fXhIBm9tK6+uBoo12Srp69zo597VZL/fUGnMpKOta2jkvVuFQU1pTi1SYT1g3s" + "koLTfoXGihOj9wWfbRY1s9QM6ZvoWLP7buB4+F6VWZ0P0kZUuZ3Tq9aOnhdtTycYSiVs6gii" + "jFMa4FRl48TwnI9j8LIlOT3+2UVPZcq1u1v8fr82lcaKfgDyt52LdqkzIyJslm5YwsBAIKCf" + "fCUKxqZibKV+qaJ63rTbnetLl+ZELHs+H9OE775uNgmK5shqah5UQtpDK9Y/JuYVpXDj+hAf" + "vvGLo/8mMR7OqX5ZFAPvzSrJSZr/5FxSpsXytw88Xf9ghLQI0I6TsyVMUEuZXTZHdSalcKkP" + "Os4HGfQEPIyD82oeIWxscz2UlJu9sJCUzCkMmdDdPrIwp+Agb+lCUdetNMuycERHkjg9iaYr" + "oDqhfm8rhqb/MQ62ycZv859+OCoiNw+PFzp7AGsENS2Y5FCISEvDGFkEpjnyvWMjLM7XnaGz" + "paMf1fbaODgcFmsvHm9/Ya5TVtIyZmGpCgE/mAaYQKLTQlE0DNNCEMDULbx9blr2t9J87KIb" + "m7KExoquW97tqciqzsKyPk+eOaWkZHGRmFOcgiiL+IfBHvTx4yd7CA5rmiiJ+IOG1d3r91lh" + "/QA2VyVNLw2Npe4ct+zqMgxpa0bB1Bnly4vIL56Mt8fHiuXf+sMDwccxxH7sQJT9Go0VgTsa" + "96xZ1auFnE/d5RuOWDsbuqzIBTt8FNTE38/oxD+voMaJP/R+TFzkKl/Y6NR90VmcLdcmGvsX" + "ZajORhkOFtcAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_book_red = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAApVJ" + "REFUOI2Fk09IFHEUxz+/mdmdddddd7Usc/2LYoSWsbVqWIfoIEgQUd2yTt4ju3SocxBdO3Qq" + "6BAEUVFRJCGBWaQZ/gs127RyXV1T193ZndmZ6dAallZfePAO733gve97gn9LrMvt/xWIyyBO" + "VFAnUoRtD/vdW/yhlKbrnSOpjlcQBTIbAKkGDtp5ol0u8O8Tqjtkuz1+NT8PLAucKmQ1Hj8f" + "fXps2r5gwPifEPlSqLRPKalsc+4NVcuW7cqW1mCU1GDuPoTZeBhFT1MrrdYE55Z89zXeAyuA" + "9QtwPujoUgu8+VlDIGcSJMLtSEXbkPLyUUwDSXXB7AS7A44GZXrFeGEyCiTXIPJZR7q1uK5s" + "Z+LjNK6S7SjRCHL0M+pAN1LfExh9C0YGyamIRp8jvPg1Nd9vMwmkAFtuMpnf5dBPu4PFIrGY" + "wp2OI8fnwNBBkn/u2bLANHDlC6lJyraMzJtTkxABNKljmddjkwv3hJ0hvfAdPAGwLTBNMA3I" + "apBcYnV8jpHeGIMle9ymEPVAFeBUAO1RlCvlQ1/aixurXEuRGH6vDrMLRKMmo4WlTFW0YJxp" + "xRVuIVhepj2rq1YBDyApgHUxy3D9p+Sto+Wxzp5IkoXgTpaaT6HvDePz+/F5vRR6PLi9frbK" + "dl5XMc6rMTTAUnJupO8sc620O3byRtvxQFnoALWVFRT5CgiILDVf37F17A0F/T1a//S3QWEC" + "4AfUNYB9GyJHUlyvtNMXG1cmaO59SWB4wE5OzIzfjfPhoUF8wMLUbZaBmZyV9m+nvAd2nHPx" + "QBdkbmpMDkFmBdJADPiSi1lgGUgAq+sBAA6gGmgF3Oua4sBqzvs0YJJ7rj8BACoQAKRcgwbo" + "a6NuUr+pxF/gG/QDEGYH9mMazfQAAAAASUVORK5CYII=") + +#---------------------------------------------------------------------- +_book_green = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAopJ" + "REFUOI2Nk0tPEwEUhb+ZQgeYtrQ8lPAsTwkREgJUUKLooibEhSG60YWu/AWGhb/AjSvjxr0m" + "bn0gC6MkoBgCATGCsVILyMOW8ui0006nM+NmICjxcVY3ufd+yc05V+DvEg7V1r8GBK4i0kUr" + "CgGhkJ6KMrkrmdJV5UH2BmF+ANpRwGMuYDBY6fJ0+wRnZ6kkebwuJ5qaxZF1ocsZxp4vv9Tv" + "M4xO6HeI49yt+rnGQv/5YEOt34jnS3WOVqrMNk5VBDldFSS+twXVieYNKeVmlg+AApgHgLJL" + "8p36Go8Ujwukswku+i9TWlyOLLlI51LITplwcgHZX9ARs1SdBRaB1D7EobZrA4N9zY0Toe9U" + "VBSxvLlKRA0xtjnCWGyU2d1ZNMNCdIpCfo0joOxpMSJ8BVTAcmjHjbjos661t5QLS5EMirzB" + "lh5DswwEnJiI5EwLLZdDlC1Rr8n16StWmCgRIC3yhPF3b9dGJMtCM1K4hBJypoCBhSYYpEWN" + "HXOPcHSXb/MJ2pKdRYicBOoBZx6gah9zd1+PR4IDA/X5b+aiOI5prMd22IlCtVJJt3mWM6X9" + "9J3opbaqWm0abpIAGRDzAJNXzHyp23rU1Oy5ufF+mwZnC9e9/QRKevD5vbiL3bhcMt5iH6LX" + "KCKAkynSgJlnu5ExFrj3bDQ8NLR8xdPX0UtjbQNutwfdoTGVmWB6c5KJ2Hh6Y3lv3g6gD5D2" + "ARaThGjhYVbO3F7IfmJk6QUzqWkzsa2ECPOZJbaJomOgACu2ldavUfZTSw9PUVFYJMw6GhnS" + "QAxYA1aBTWDXDlTyMAAgH2gC+oECe2ENiANJ2/sMYGA/1+8A7EWf3VOBNJA9OPU/JfwBfkQ/" + "AU/kDpSM2ckCAAAAAElFTkSuQmCC") + +#---------------------------------------------------------------------- +_book_blue = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAn9J" + "REFUOI2NkztMFGEQx3+77Hnc3e4dRwSJPETeBEwk8lIphEITqaAyxkQ7GitjLEyMrY2thZ2F" + "DQUFCSpGEiNBjJHwChHlkRM45Y7Hcdw+WW7XwoMgxMe/msnM/DLzfTMCf5dwwHb/lSBAr8g1" + "oQZVbMYnNyEHz2Fu67y6f5PEWAywjgJuL3cg2FdRvI14jQbwBRF9oBuImDiuBNNDLxnouQf2" + "3GFIVlHXnYkChfZUcXGpP77uPSNbNAc1Oms9dNf5WU1axMivJLtcYWlwEkgBzh5AXNkyBU9u" + "LvnrUcy0QHtdgJpShRyfRMKAsyUySBJUXrxBw4Me4CQg7XdA/pVLdkt9uXdhCS0QYjWmMhNL" + "0zelMTyRZPLLBpgauGkBpaiZHc8am+PzgA64WXiqN0y57Hp2dbmgrCwQUSUSSQssC9wdSNuw" + "u/vLd1wRX+l5jO1F1PkIYIhMPxxm9O2LuCNiih7C0g7YFti7YNlgpUG1Ia5DdIOGQsMvCOl6" + "4DRwTAJ0vn54xLvKy8mOVk945D3YPkgYoKY4EUzQWqhxoT2Llio/RcUFesWz114gAIgS4PDj" + "yRjTtc93K2puGYvjNOebtNVD4ymRUEhGCYWQAzLhHAXNV+CnsPsY0T4DcPZe0+T78GMG8ro7" + "C/qDTTV1lFVWEVQCmK6fNxEfI5Eshj5rBt8Gp3AEAQgD3j2AS6x3jry2p7pw/O5MXGZgQeBT" + "xHFSq2tzqB9nSY5uoi/YuHYKWAI0wP19lXMaSsjr6sdWU2wOLaLNWqQ1A1gDosAysApsZRZK" + "PQgA8AAVQBuQnSmIAhuAmvl7E0iTOa7DADKF4UxMBwxgZ3/U/5TwB/gR/QQ8K/3nl/ZkqAAA" + "AABJRU5ErkJggg==") + + +# ***************** Catalog starts here ******************* + +catalog = {} +index = [] + +#---------------------------------------------------------------------- +book = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAhBJ" + "REFUOI2lk89LVFEUxz8Td8yGnBmTsnSKfviIRGph7QZCIYNoIfQvuGoTtGoVtGrfxkULF0E7" + "F0IFtol2FhqSbVQEbRYFI4SvUXz3nPNui+c8FKaVZ3nO/X7P55x7LxwzCgBTrxdG84yAIIgI" + "b5+MLwFMvnw3KpLlRATZE0T2+DL9eKmQiQuLl/pKpKlhlpKakXhh6/efm957BvtOfycYqoqK" + "oKr82PhFsXTqtgtpukjhBM8eXs8h0jRl/tsWqz+b86bKvVs1Hty5egR9dOoVXcXiogMwMwBW" + "VlYwyzqNjYxw5Yy70NNT5mJ/L8vLy5gZrVaLer2O9wniu3AAqgpAFEWYGSJCo9GgsbnJ8PAw" + "SVIiiiJEhDiOAfBJgj/ZhQsBVASAtbU10jRFRKhUKsRxTJIkeU1VabVaDAwM4L1HvMelpsiB" + "QRRF2aJUaTabhBDymYeGhlBVdnZ2ssvyHhHBqSriPSEE1tfX8x2Uy+Vc3K61CWq1WmbgDxkc" + "JvDes729TQghp2gTtHcgIqh4nEomAOju7s47lkolqtUq1WoV5xzFYvGIYXtUJ+LxScLdpzOI" + "F0R8jjdZv0EIgTcfFrKOqtiB0MxQUZyIcHnwbMd3Pvv5KyrK/YmxjvW5ufe4/f19NuO/B52P" + "EpzvP4eZMf/xU0eC1Cz7TJ3i2qMXM7u7rXFTpVzpXd2YfT7xv7PHin/ZG4/t2teD9QAAAABJ" + "RU5ErkJggg==") +index.append('book') +catalog['book'] = book + +#---------------------------------------------------------------------- +clipboard = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAf5J" + "REFUOI2tkUFLVFEYhp977h1znAnSCRKbEaGwNgZF0K4gV22iP9Am6Dc0ENU2cKFCtKtlq+gX" + "ZLRqIS2MiNAkyKLSgZm8jV7vnPN9X4vJQRlrU9/ucM778HzvgX+c6E8Xs7Ozp8rl8lMzk2az" + "ebVer6/9FeAfTE1z5Ph9xU02pBI3T14vlkZPuEKhQHN1UY68f7gz4r+JBVayfKs+enttASDp" + "oSq1GVepnE2OllluXOHShct47wEYG7sWv8yT0rQ8Jmxn58PnjzPAuX0A0WgyGSnz6PUUb989" + "59XiG0QEAOccjY0Gn05f5Eb1BZLb5G6uB7CgIJ7iUIm5ufl9e4pACHD3Th1qEUECfQA1hRAw" + "U9rtwOrqNnGckKbrbG5+pVqtYgao4n+b7Qd0chCPqlEuJ4yPHyKKHHl+jCwbZnDw8K4rqgcB" + "VByimBmtlrC0lDEwUKDdXidNvzAxUeuFvA/W34HsRISAiCGiOJdjJjinxDFEkQMMRFEV7Tfw" + "HkQwM7LMk6bfKRQSvN+i0/lJp9PZVcVrL7+3xEDXIMK5IYaHS8SxI4SEYjGhVKp0SzRD9YBf" + "IHQNyFvMz93qPt4zZlCrlLqWcpBBCCv5ZnrmZnUBahGo0qOo9s6tjQZm9qEPsJX+uBc0PFOx" + "yEzAjKCKiBJECCKICEHDMlnnCf9rfgG9Rixh8s0DuQAAAABJRU5ErkJggg==") +index.append('clipboard') +catalog['clipboard'] = clipboard + +#---------------------------------------------------------------------- +code = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAw9J" + "REFUOI1V001oXFUYxvH/OXPv3MxMnJlOk6atQR0XdmGtVNCYRYyg1YXgVkuL1HShC4VQW4La" + "nR+LFqEoSoIbwRaKFEQkRYwupBG1kAoumqih1U4bms6Mkzsf9+vcc46LmqE+8Gx/vPDyCP7L" + "S19ce0xIe+r+cm48UIZAGZQxBKnxhbUdK2gIhMbSAppI87nXaHzrbALWpGN7tg2OvzE5zJ3p" + "JaYUJKbUivRooqATa/5qdDm/2t0XFivTfUCn6UgxKwCobWhcIXAEZBzwXMk9niQjJW4G9o7m" + "2FkqVD795cYHsg8kqlg2EamBTiLwFbTbEX4EfgTNEG51NQBvnrnGeLXA7uHscB8YDDdGnvhq" + "jvTlQ/QiTfXEDEOffUTg9+jEhm5kCRMwgNBtfr7SYulvf00C2MOHKzNLZ58tOCFKOASxReHg" + "0mH73EmiVodebOgpAxbW2zGnFlbbOlGHZHzw4Ithu3Njxza3ZGpNakffJQUu7Z8mue6TFT0e" + "ODqFt/gDUSowFrSrceK0+uXrjy5IHUZzydjuAXNpBY7N0B6sICToYoU/X3gNfv0dNfYgd8+e" + "QCqFtZDGMS3V0wCSKHxFnl+MTHUn4vjb2Ft1JJas36A6+x7pfTsQ84vUpqYRWRelNd1eL/1u" + "5uk2gMzPz5+dHZ0cu7K6gRr0qB6ZAgu73j9GpugQtAyXZ8/hT+wj50KzG5PGyTpC2NsXAPND" + "u5IPJw7gxJCp10FIZKNO4MPV4ydRhRJYyDuSeitEJ8na5vecySNnhtI0euehPXvpTp/m++WE" + "Qkfz0ydfM+BaXAeymdst5mG1FqCSeL0PRGH8lLT2uaXlq7RCh25sUdoSK0GSGlJtMNZSKZV4" + "9Znt3GwG6FjV+4BRySPPP/lw7q0Dj/9vA9qC0pYkBSx8/M0aeRc63QCdJs07AHX1ZsPn9MIy" + "5cEc5eIA5YJHqeBxVz6Ll5V4jmT/xAieA/V/OuhEXe8DJPG5CxdXRi9cXL5XCLEV2Ap2i0Vs" + "wdpSzsu6AwMuxUKOcjHPbyu1P8iYHzeBfwEwiol55ANRRAAAAABJRU5ErkJggg==") +index.append('code') +catalog['code'] = code + +#---------------------------------------------------------------------- +core = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAmJJ" + "REFUOI2lkk1LG1EYhZ+ZuQljPsSQkFAwbbMICKnQRXfRRegvEALG7uxPKbjJVuii9AdM3LpQ" + "F+4rLUERi1QUP5MRgwmaxNzJzZ0urCGpiy569ud5z3k5huM4Pv8hAZBIJLi5uSEWiyGEYHNz" + "k42NDbrdLq1Wi06ng+8/3TFQqk86naZcLmM4juMXCgXa7TZKKbTW9Ho9pJQopZBSorXG9w36" + "CnzdQWuDqakparXaY4JkMkkymRyL5vs+vu9jGAbdbg+tGkSsn6C6DCJFhBBUKpVHwKju7u64" + "vb1FKUWz2eTs7IzvP3Z59ybE21yKF6/yqHaXQMACwBw1NxoNTk9PkVLSbDa5vr7m5OSEr18+" + "8+HjJ365rwlEsvT7cvyJAFJK9vb2sCyLer1OrVajXq9zfn6O1++j+pLd6jfeF/L4vo9pmuOA" + "w8NDdnZ2ME2Ti4sLXNfl8vKS4+Nj2u02AGtraywvL2PbNpZljQOurq5wHId0Oo3ruriuS6PR" + "wPO8x66mycPDA0ophBDPE8TjcY6Ojtjf38c0TbTWAASDQSYnJwmFQmQyGSYmJjAMYwgwAQaD" + "AbOzsxSLRQC01gQCARKJBJlMhmw2SzQaZWFhgXA4PNzGMIFhGAghKJfLuK7L9vY28XicVCqF" + "bdtorVlaWiIWi7G+vv58yk+RhRCsrKwwPz/PwcEBANFolHw+z9zcHNVqlcXFRQAqlQqlUiky" + "NqRwOMzMzAy5XA4pJZ7nEQqFCAaD3N/fA9Bqtdja2qJUKtmAHAJs2+Zv2KienvbHbIxVWF1d" + "rXue15+enn7JPzRqBvgN0r4cgCHFMd4AAAAASUVORK5CYII=") +index.append('core') +catalog['core'] = core + +#---------------------------------------------------------------------- +custom = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAvpJ" + "REFUOI2lk19MlXUcxj+/933PezwvdF4OCBxg5g4cp9IQDHQsxWq6YsNlUW7pNKYXtLm5vGhz" + "y7zLorpwja0CabU2HVt1YUuT/jAxU0eaOEUMEUqSIxzOOXA4vH/Ov7c7Jce66bl7novPvnv2" + "fOF/Sjwa7Fu39HBFQeagLDs5yYxD3BbG6Kzr6Infw28vBpAXmtZa38GqUucd7TGhKm6BJAvA" + "cQnSDQXeXOn2lHn2UYC00Kz1Z9s0TYhYPEN0LkPCgqykosiK8LlSBxa74F+AmbkMJU/vY+f+" + "Qzz70l5C8woRS8FQ8tA8suej/Y3u/+ygc/fyyO4Pf8hP3uklYZhMR2fx5mrolVvoadser2vM" + "b80YwW45t4r56T6w7rUoCwFmVhsy717ZkHYvxZeTxldYSiItQ3QYfZkaydU3d3sqGtADa5kZ" + "W8lQT9cHD0us7XDdSSzZ9Hj4m+qamipQvQhJQXUsrvzURk1Ts+4rqxdzE7eQkwaat5jZyT8V" + "ARBsPO2OEdvrofjjM531DHbsxMEBIN83T13jBvTy57FD3ZgRwdQfBknTjlh24ikZHJEKDOzS" + "1WXHejrXc1VoXF6xg5HyHWRLSnihxkYPbsWa6ERSDaCI1Mi1SdOwnqt74/Sgsrr5i21lUvjz" + "199s5lxEZtBwSFngv/8te4IX0YMvYt37BMmVJhkPMP7zb3x2Y9WnR491DABIxyvf//pES5TJ" + "m99zaQKMmKDw71O87LtA0RNNJO93IasOdnw5ob7LFAWq2a73vfVgB5IQkuLWOH9pmqBi4Bvp" + "5tWCi2SdUkLX28liMR8t4+4vtzhydRsuzYssS8pDwIoth8Z6v0wvSYbSJ4/3s97sonJjK+7x" + "8wyf/JWBnij9Z65xoLeJPGfcGD33le2p3HzkAWDNa+3vafWb8v1+/FMziY6h21MkB78jUN1A" + "Ts5KxvqHeffsM7G/UkU/qi41oD1ZV7impf3woksEeGVjnllbUaysW12O47Iv2OHwnq1t10cX" + "+wOAfwAJ9yQGhieeeAAAAABJRU5ErkJggg==") +index.append('custom') +catalog['custom'] = custom + +#---------------------------------------------------------------------- +deleteperspective = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAnpJ" + "REFUOI2Fk0tIVVEUhr+9z9nnmrc0095RVIJSCNFAGkiEFDXIRk6aNCkIoiALIiKiJpZBEyuK" + "GkQIEUhCCGVQg8pKJJWil/nonXY1vd6Hj3PuOatB96aV1IIN/2Ctf63//9mqufXlYF7OzJAv" + "QqYCgYkxF8/zGBiKat8NhqOx0S27dmx+wZ/1tKNrLAgCmfp835fkmCexuCcdz3ulq6dPmu62" + "D1yuu73hz3n9FyOglEJrUDpAW5oFCwvYUFZSUFS47M61Gw8q/0sggAIcx+bd+0+0tLTT9uwV" + "fmrcScSi9UePn6v6JwGA0gqtYG7BHNxA8a1/hO6eTzhZDvHESHWmz552GNBKkfJSlKwpxh33" + "GIxPMNTXhzEOrS3N00gIfHjdCp1tBEBKIGUMid5e9OkDmHsNmOwwjmOw9OTeSfT5LTxpgmQU" + "+dhLsqwS+dBJXu0RQveamLH0Md7qUvS8xSjFNAQLV8KyIrjbgNV5hfDTR+jubszD+3iLVjC8" + "9wRWwXyMCtIiMwRpPK5t1PpK1OgE5vpFQi8bITKMt2oNQ8fO4y0vxkoksGwbNeUEO2NCygdl" + "LGydhfoSga8DEB+HL99RgUI5BkuBpTJBp00MMs57Lk7dWUI1h2FgBH/tOoJwPqbtDflbNxG6" + "1QgzstPbJy/4lYLd3IQ5fwr6B3G37yR+9Q7JM5eQnFysSITZB/ehI/2IcX6LfFJCaTmqfBuy" + "pBB3VxUigldRQbT+JtmH9pPcvYdgVi6Wl/pNgh2kcTgvB05eQAAD+D6IgL9xPW5HO8oTwkkX" + "2zZMzdEeiceT1TW1Ka0NP+3xUViI+IiApH+GiIAISmmSsdhEhuAH7okWfiVuCWIAAAAASUVO" + "RK5CYII=") +index.append('deleteperspective') +catalog['deleteperspective'] = deleteperspective + +#---------------------------------------------------------------------- +demo = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAuZJ" + "REFUOI2lk0tPYwUARs9te7l9pDCEPmCGkQ6FlostwlCKCk5MGFw4asDEmBg2Jv4B1vMDZONa" + "F5MMW6LRhWhmYWYzwvAsj2mTYkcqhZa+L7X0cft0OwsXk8xZf/lW58AbIrzGRj8+Pj7o8/ne" + "uXdv9r1cTiktLy8/BFr/e9Df339rampq1O/3TU1M3PUNDDi8JpN5QK21xVpNZVR2IsuyNxwO" + "BwF0w8PDg/Pz83Ozs9N+r8czYbX2DjXbuq5kpsJ1IUkicUmpkiRfMpFIpOjr7WFhYeHByspK" + "EEBYW1v748Enn86tP9kjGM4QT6kIooXJt0184Ldhtd1C1GmoVss82z7DeqNJp6m25fe/PwO0" + "NKenL5PxeJKH3z5l9ccoh+EGoqjHK1uotuycXTaIXqhkFJBdb3GZLjEyIk86nU4ZQGswGPuW" + "vvri493DS7JKg2arib27jMncSyzZJpnKUShWySkq2ZxCJltk6I5F+28h98/m5vNNbbVaFZeW" + "vvw6kSoLhyGFZqOGpC1wXdaRzLbpNOupVK5JJBVSqSy/PjlC39Fi7sMx06NHjx9rYrHYyelp" + "9HJs1I5eMnL7tpNqy06v1cBNmw67xcC4dxDZ1YcoXFMsi+wcxHG7R3wul8utAXJ7+8ehYYeV" + "HkeRtlik54aHeK4TS7eRmzYd3eYajUqCZiXCRzMi05P9mExdHYuLi59rAAKBwF63WUQed3I1" + "s0He8RtdRg3FUoXIyzP29wOYjS3enb5L5vwZumaUi4sLJZ1OCwKAx+NZ+PmntV9enGj50/w7" + "Y2YH7roHq02i0yyh0YCiKI1A4Ci6urr6dyQSuV+v15/GYrHPBABJkobW19ePBwfvGCSMIDTI" + "FFKcnPx1vrsbeLGzs/M8FApt5/P5IJCRJOkbvV7/faFQ+E4HoKpqbGNj4+DqShnZ2to+Ojg4" + "2A4Gg1vpdPoYOAcar+ququoP9Xq9QxAEy6stuIEOIAJUXzPGN+c/irhDxtglzjIAAAAASUVO" + "RK5CYII=") +index.append('demo') +catalog['demo'] = demo + +#---------------------------------------------------------------------- +dialog = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAJ5J" + "REFUOI2tk1EOgjAQRN8ULkXizSrRkHoySHus9cMULQJa8f1sMtmdTnZTyTUcQWEI9utwf72o" + "BfC9R7p9PWjmkYRcgwOqhpf9bXasRToDPBJk0pSqKgBhCGZmFsdYVQGTa54GtSZvBn9J8Aow" + "N6/p2WBe4tqCulO3qRdnzKKk4lRpSpt6pkhgZsQxzjUnWNOLBMsXatDR3+g+t+xzB+jeEF9n" + "B4s2AAAAAElFTkSuQmCC") +index.append('dialog') +catalog['dialog'] = dialog + +#---------------------------------------------------------------------- +exit = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAthJ" + "REFUOI2lk91vU3UYxz/nre26ttkGpZvdWJ0LkF3AhWSijMQoaEKMLwn/gqIJAYyaQLwwxmAm" + "S9BLLzSazBhRYBqXErKEYTJggwwYvgADRgPr1rOenb31nLZn53d+XhibSORGv5dP8nzyPM/3" + "+cL/lPJw4SvYpGvKgUQm80p9e/vawPdZyOXswsxstuyLTw/Br48EfA17W7ufPLZx//5o83PP" + "YxUKBHMWSemTPzfM2KkB/8btqfeBYx+CD6D93dwPezftefXzp7/9zmjY9gylhUUmxy5j2zb1" + "5QrpJzrZ0Namera1617BdEbgfG2Cfuhq7t46/uzgYERPprAnJijncshkEgm4AwPUS0k8kESX" + "bL45fVpcnzW7P4Mr6l+LKPu63nk7oidT3Dl5ktz4OPlLl1B8H9XzKObzWFu2cGfqLsK02P5Y" + "WtNV5TCAChBPp15LeUUWhs8QqBqdO3dCfhpWV1GEQE5Pk+npofH1N5j67Tp6UKEhFtsFoANE" + "081rguwJCvdWaP5xCOvE96TXJNEjEdA0WkoO5ie9tB7t42JDE9EHU8RDRqwGCAJJtVRGiYSQ" + "noe4PIoqA6o3bgES6S5TGR1FlF1CmQzVyd8RkSg1wKK9uFB9fP06LV9Ea2zAt2zun8kihn7C" + "XwVn3qFp+w70WAJpmkhFZanqubUbFPNm1lJj6PNzeCMXSB3pxUilqcw6uJZDfdNaOvr6qN78" + "A3fiCm5dmJlK9ZeajUdhc3vXhvGeznV6aXKGllNZRDyKM/AzUggSL7+EEQpxbfduqrnbjKEG" + "V1ecHcfhggYwBObm4rwr400vtCR0lr/4EsOoo27bU4TbWqmcO8vdt96kcj/HLd3g4nLpyHHo" + "/8crfwC6B+92dLR/vDEWUhJzFroICHzBilOmaBjcVFSuldzeEnw0CO6/hukgbDXC4fcaw6EX" + "w4qMCSFYEtI1V73hJT/o+wFGHp3N/6A/AcbQQIv/cYpDAAAAAElFTkSuQmCC") +index.append('exit') +catalog['exit'] = exit + +#---------------------------------------------------------------------- +expansion = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAlhJ" + "REFUOI2VkjtrXVcQhb/9uPdcS4okSyCQwSkCEqRwogRsFzaCgGzsVk4d0qQQpE+RPj8ivZpA" + "qrhKcws3TiOnMNgqLGxDGgkhoat7HnvvmUlxpCiPKl+zGZhZzJq13a0f3v66fL36IicjTQup" + "FlIjpLqQGyG1hdwKqRZynSmdol3BSoO178dxZWVu87P1pXh6CudnMJ3C5AymZ31tHrKAeEgK" + "mujxgD7djMuVy2tzVBMHeQ7OJ9AuQNNC20BTX7wNNFNIHaiBx9j/Pea4tmx8/QkcHR3z4sUe" + "W48eAGAAAXBgBppBiiIqaDGqAXz1vScGYOBh4ARJNdWAK45fQn0MzmErn6OjGUoxNBpVgIE3" + "IloAUDNCiPyd9udvkFe/QYD47TPs5j2kGKqGB4oYUbRvrqqKg4MDdnd36bqOjdv32Vhcpput" + "wAeMQBEwVUQUdaCmRMwAyDmzurrK1tYWZsa1mVnK6xmYWQAfEAKmhogiYhQMFSPahYCZMRwO" + "WVxcvKihfPlTn1YB7RKlqVHtLRQMMyOqGv/GDEpWZOgxIPs+Oi2GmKKqeLsQQPWvQeeuBGzg" + "sV924N1zQgjIwx+RpVtoN0XE8GqYcXUDgMnknMPDQ1LKVAtLfHC0j/3xEh8C1k5Q9Yj0FtQb" + "mBEv5+fn56lGI8bjMV2XWP/0Lrd9pmQBFUQFUVC1fgP6zWPo/xyj0Ygn29v/uEV2O7iPHmM4" + "qusfEqiRIKiHYTRicLg73+2dfHxjMNfVmZIKpU2UnCidIDYiF0dOCW1PQAuXhoN37L85Pf9P" + "Av+XPwHwQHwFXrN+IwAAAABJRU5ErkJggg==") +index.append('expansion') +catalog['expansion'] = expansion + +#---------------------------------------------------------------------- +find = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAtRJ" + "REFUOI1tk8FvFFUcxz/vzcyb2e7utMx2d1tbLCutuCExHDCKJCpRSDAGDkQPhGjiDbjoCf0P" + "9AInOTZKjCHhwkVJwNgQMcRYisJa6oaWggI17K7d7my309mZ56F2s2v4Jr/k977J75Nv3u89" + "wX+amiqllOfdzGcSo3Gsg00/0hCsI6o13y7Pl88cP/rWpzxNF6/dSd9ZqC7Fcay7qx3HutKI" + "9Uy5pmfKFT154dqZ7jnZfYi7eq01WmskoKwNb8izeXv/yx+d//bGWbQWAGY3wDQFa80W09Nl" + "gvUQp89maGgLQ1tHSKccZu8+IgKk6jt+6rOv3c/hWAdQmatS9ltcXlgkU9jGeGGUhCl4XG2w" + "9PcsYxPjZAezzC8+QmMihXwHeK4DuHLlUi4/OuzsOHCQ4hsFMhYowBnL82D2L+7fXSCZyeOm" + "k5gqga0sAcgOIAzWPgzcQn9qrEDtHwgToCSsaVhJDdN+WGNYrZBKpTGVjaksDegOIIqjFyst" + "l8oSWAH4yY1bbaxBzZckwiRjJjiOwlI2liF7t9D0V6t2vILXB/0KPBvSCmwNoi3QgY8UEsdW" + "JBwL0xC9gJV6/Zv6/C9tGS6zYxwmRqC4FZ4vQNZ4QiKqk/SyGKaJIUHI/yV4/b3914vbs9Uf" + "zk3y+89zCL+F8Fs8vP0H965fpemHcP8SYn0ZwwKxufpNwOFDhxlMmizeLvH9xcvcnHJxEg7e" + "QD8j+QxPpr8knatiBFeJdp1GmE4voFKt4Nk5Dhzcy2tvvkKt3kRriTuQYrWxzMyvJ9miMjgT" + "Fo3ZU4TNlzQQ9TzlzViOMngm6zKSS5FUMJgZYOeJ7/jtp2XCuRu4xT5elZPOqEuuk6A/9PTc" + "vT+bt0q34hgZaCCKQeuNEpbLUvYTSuc+Nt7Xsdqz+1lnT9E70gHs25f33/3gxN4LX50doPdf" + "dckOt6WjXLvy4xfrLxzbVVrd2fgXbJkZTtWGQBcAAAAASUVORK5CYII=") +index.append('find') +catalog['find'] = find + +#---------------------------------------------------------------------- +findnext = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAuVJ" + "REFUOI1tk0tsG1UUhr8Ze8bjPDzOuH6QOA/nUccqoBaBRNoKqPqQyiJdIFghENkgyooFahft" + "nlXEAthUiqCLqhIbxAKkFIgMilIgpdC6YCoaKlBFq9iJXY89M57HZdHYiqX+0pGO7uLTf85/" + "j8SOVlZKA6phXE8notkgEE7n3RcwdGFR9z1P/NOfuDp3/v2D7JLcaepKSDIGI4OTw7o2nY3r" + "nZoZjeue4xA9cEAax567eubctccCAIJdvRACIQQy4DWbCM9DHRtj2LOeWXvr7T8QQgII7waE" + "wxJ202J9/TZO20Xri5DJDBG2LALbxjNN1KkpktWfZr88+vKdeZjsAirlKrdNi+WNuyRyE0zn" + "skTDEv9VG2TqdXzbpl2tAqDm80w+eJD7NpO51wVcufJ1Kp19QsufOEnhpRwJBVRAG0/TrtUI" + "HAe/0UBSFCQgsCzavl/uAlzHXnBiOX1gPMfWNrhRUGWwBWg7DnbmZLtY5C8RcRc2N9/pAvzA" + "f7pixajcB8UBs//RVhs25Gs1PNNEUhS2i0WaE7NsHJ5vNb5f9rspNM1WNRI8xOgDXQUjAoMq" + "RAS4rRbCttleXcWeeZLRDy8QDkm9MT6s1y/V7/zsyW6N/DTMjEBhFPbmwBeCytoa5t6nSH/w" + "ESEZJFnuBbz42vG1wlSy+t3FJW79WEYyLSTT4t7NP7F9nw19hOTCMaR2jZACUif6DuDU/Cn2" + "9Ie5e7PEN18sc30lhhbVMOI62uJlNtc/5fDWEiGniL9/ESms9QIq1QpGJMWJk4d44ejzbNWb" + "CCETiw/QatT45dd3GVITaDMKjd/P4DafE4Df85U7tjQ1xHAyxkhqgH4V9iTi7Dv9Fb+t1nDL" + "14gV+jgoL2nZGKmuA901RPnvf5s3SjeCANkRgB+AEI9KUmLcT56ldPG90BsiUOeeHdPmCsYr" + "XcCRI2nz1TdPH/r8s0/i9N7VLkXciUE/5VV++Lg9+/r+Umtf438yITEwJvx/5AAAAABJRU5E" + "rkJggg==") +index.append('findnext') +catalog['findnext'] = findnext + +#---------------------------------------------------------------------- +frame = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAHhJ" + "REFUOI3tkzEKhEAUQ1/+zK1dUWT2ZC56rG8xiIKg+7U1TZokpEgkSzyBylD8rrntO2WApm2Q" + "vpcG96qrLGQJA/4y73V7fV6To5A+ALXBivk3hxiAMhR3d5/GKcSAy9IWEA05BLwN7jfIdRQK" + "D2kb1MM32rXkHAss9IUYpp5t/QAAAABJRU5ErkJggg==") +index.append('frame') +catalog['frame'] = frame + +#---------------------------------------------------------------------- +images = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAylJ" + "REFUOI1lk11oWwUAhb/7k581XfqXNF1tunbVLVVr7ag4ZVrrNsaQbiJaZKBDmRWLoi8b+jSK" + "MPVBQV8UXwT1xfmDLXMZVijinNrJOqzdZtquadIuTdI2aXZzf3Jv7vVBmJqdx4/DgQPnCFQo" + "ej5+PNzkOyYJwk3mAKYlUCgaxGLXxhIz4y+MjIzYAHJlgOz1+TvbGgJCBb9hQCKl0HV35HmP" + "16XCyCsAYmUASz/rzi0QRBFEUaCxzsPeh3e+/Pno5FsA0n9Np57CLWZmBr1uqzf96xfk539j" + "I3kV16ZqqmoD6JaLpVQGQ9fRTXZ3Pzjwb9HRAQarG+uHN3f19y4S8SFWs6PFhZ25Qj4Vpyrc" + "Q/jxEyzlbObnFlE0i3Q2YwoApw9xsnXvwBudh9/morqN937yUJag20zy7D6Vufg0N858jGD7" + "2HH0U5azKiWjxJXY/IY0OsBQ/faOd5xNNd+rid8zq+Wq8JtnAly6DG1alKmmT5iouobZ2kEk" + "Nsvs1RkCXQdwy5BdyxvS0L7gV3Wd93gvfnZ2KPHHdHxX35ZDnSGDbmeS1x7NcTL1JRPajwTT" + "RV7t3c/k6VOE7h/E568nlU4bsi8UaLnrycdkX430tSg40paQyDMtv0BEB1Pg3dUI55d9HLSa" + "cDfEqHVraNk4weatuEQJeenPhfHgufED7fdtDyCUYGURNAVKGhgaexydPQtNlL0PUfgrCsUN" + "cGzcbgFREpDzBf3IxAffHvTfVnO0py+ya1tH3T8mQwW9SNkqsh69TmAxQVZMkt5p097YjAgI" + "goA0Noc6tsBUv9/45vL0cri5Qe6q8QOKArqOYOkoSoHVdI5Mi0Wi9XbufeJ1JFEmnrxu3Fzi" + "8DlyhsLweDR2yczlwNZAKyIUVEI9Zba+WGY+CO19Q3h9XsAGxP8v8YcUxgN3BNs21tXdm0s5" + "3JaGpFnkCw7fTcFaaz+PvPQ+luUgCiLx5Ipxy5nufO4js71e58LZD3HSs7iwWTO91O0/zNNH" + "TiB6PGiqjccl4pIkT+XpiF5IHy/p68dKSgFFUSiXQZJdVNcGKZsGhq5jOw6SKLG8ki38DbMJ" + "XHT2R43dAAAAAElFTkSuQmCC") +index.append('images') +catalog['images'] = images + +#---------------------------------------------------------------------- +inspect = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAp9J" + "REFUOI3Fk+tLk1Ecx79ne+Yed2tuc8vlLTJF1HlJcoqaaEZaJHQjsIJAqBdlQr0JohDqVVGZ" + "78JukHTRl0mYUEpleWFD0OVyCtN5mc+e5Ww3t7WnN3tirD+gL/zg/M7ly+d3fucA/1skcYLj" + "uLIHd9/0OFbspZFIFKyLASUSWy623y4pLyfhxP3C+KS6+lCK/xdZqKkzqNUpYq/danWbJ8xs" + "Tr5h5/vBlzeNlU29ZvOIO/4MFZ8U5le47bYp5+nWZkW6Ji0SmKZnRZodrom3H5ZzG/YUOZnF" + "uURqnoB0XLp3/OvwO+OJA61MyA025IsE7JbVFXbZ48lS5vnMpuFwzeEjGYaiKurb2OAIAC6e" + "gJJK5V0bqy7vjwFmxiZkQ5BEWUoe2fQEWY+YStaVZ9ZzTsdi3ja15jKAWwC2AEAQMxBvBX1p" + "almalxAq/DsS3WCdLtvo5JfPNmba5AttzhFQDLu25iksqJADSOJL4A2ENC3r9wR/0kKBICIg" + "glASJfJxhLBBzrtOU8kbhGDLUFIi02/PHI+/O37APe7p7JZSyl6Xb02ilab75GK10qhv0AHR" + "CEegHF0Y2jVw/VmqsbL+Al9/PEF41bXEtJxqm31lerh33edQyZLkegWdUqQQq4q/r0/uO3Oj" + "pdZinZ8am/xoA/D3PfAtEQJIBZB5paPrqnXaXG8ZH3fQAklArlPI+ode5LgtT+cNKlKQcfT+" + "boeDsfMm8T2VANDFAgcbT5bptFKtP+R39fW9NgEQtjdnn23eX9s266GzOjofLSJBAgBSABkA" + "DAAqAFQBMAIoBZANQHbtWE73nfO13NLMp6ZEAnAcRwghIgB0LIQAogCCAAIxbK61SvNEn5V7" + "Tq9Vdf3zmRKIeEUTFxuLNc89/nDdH/xlAzHUigZXAAAAAElFTkSuQmCC") +index.append('inspect') +catalog['inspect'] = inspect + +#---------------------------------------------------------------------- +layout = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAZ1J" + "REFUOI2lkrFrFEEYxX+zHBE0G9BCRBCVJIqdoI0YK5FUgkXSaor8AynSWQhWtqkEtbHTRiwO" + "q5QprzHgoSSQFBaKJIGA2b2Z73sWu7e3ASMJPphi2J03v/fmg/9UAHi80lsKcJkQZoBbyAUh" + "4CLLAlkAd8eS9sY6bFy/NHEbF8tzNwIAT1Z6r3RCvXj/RQAdAAXuAbxZ22nQ9A/sxbvn6G/v" + "lY0BxoXhx+nzp6ps4e+Hv/4oASiKwdiIQDo9vPXbz/JY5ck9jAjcO0O048rNaRFUrzH/bJXC" + "HRd0nz/g4etZ8jzH3ZtlZnxY6CK3loFXbr8OIvdvXqTb+w5Ano8zNXmFOiaS83m9X+1TZZBV" + "BlXn+4URJX6XCQAzJ3C4zWRWp04jglATlGXkIBpWxPonRxIgkJCE1TcrDVoRWq+u1gCkZLis" + "ieAS5sN9i8CjiXqsP61tNQb5+Bk2NreJMTKIEUtGFjLq3kaTaO5bwNX1l48O5X07946jJNdu" + "Y4Dp4/zT1WuO7gTXWfcEcuSGPIEMNX24QPsKWf9I95PoDxEAIhVEfbTGAAAAAElFTkSuQmCC") +index.append('layout') +catalog['layout'] = layout + +#---------------------------------------------------------------------- +miscellaneous = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAklJ" + "REFUOI21kklIVXEUxn//+67ac0LNCQcUSpMCUxdRhhLWQl0k4qoBMV0kiGATEVSrCNq1iEAN" + "sxZtkiipwLICtQg0DC2TJIee+nJKvW9S37vvtEglrKCIPjir7/w45/Ad+N/Sq+y7NpX3nf17" + "skKSa14tSYNDpNEpEn6459Yfs1FlNyoPDIkcGRY5ulrloyJRlbaOnzb85dpmoN4eBOEfwPAB" + "AmmRkH8lKe9+024rvPas9Wo/glLCPsfp1BHd5/digJEIOTrszYDEBHjwBbjbm/fTRCkk3Gwo" + "dcrwU5GhJ9J86qSflyJ0iWR2i1i6RFSnCC9E6uWa6NeT69ZYy3JVRIul9tJtFZEQyOwEzNrI" + "Sg1SMy2f6E7OJkZgygC8kHKvk4yCj+TszCh8mzKW7H1otCp3dewj654dxQwMgx4KpsDiPMTF" + "c6gt39N37qrV3j5IVvUJrFoISgO/8jNp2um/3HdGc7lNmFmE2BiwfQanE4qOQVYh6dONb/Tw" + "4tH5mmzs5iSP3z+nbbADp25QEJWPZUHF6Y5lIXrO9f2g9AyQEOjvhrkxPB5BaSvLzAQwyAi5" + "aTk4zRWcC8vU25vB60Ovffb1YuvmsGLN6wUPMDcBIqAUbpepjQ7Zeom0bENpjLvmsLntiPhB" + "QYDPjwJICmLrQFnCUFiAArvBtFdjf4dx550pxwGntS725tJ2VZEYFse4YwqlFJYew+Zrchet" + "RxkK0YOlqVISrHUC8RujDjwYfH5LY64EX4h2E0jRRn891t8Zq8rc+Hz/rG+GvgB5gkbPfgAA" + "AABJRU5ErkJggg==") +index.append('miscellaneous') +catalog['miscellaneous'] = miscellaneous + +#---------------------------------------------------------------------- +modifiedexists = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAAAkAAAAOCAYAAAD9lDaoAAAABHNCSVQICAgIfAhkiAAAAWFJ" + "REFUKJFlkEsrhGEYhq/3fT9jxviM6TOnnEJW4gcgKX6AJhuUhYWyIAt7+Q0KS0OWsrWxUVYk" + "hySNxkyGkZzGZ2GQxwKD3PWsnqvuuwulDd9X4pRKsDssxLRMzExK8ae0AWB4dkQC8QjnJseZ" + "m0FtvtC+08rc/ILSALUNNdI82EJ51KaypAK7MQD1huWVZQA0gCjhxJxxzCm3T3dkuODxIk+8" + "Lw6ABeAv85PMJnEbCpg3yOPyvH1FYmlfFSFtNLn3a96zcBvL4+yW464+8h0N4PP7MPcK77VF" + "KB3ASdlE7PBfyAk6GFfxVnjFysLNRo7B/oEiVFQQ6olKsCOMu/dA6DLAwc6h+qG+hI1OjwlN" + "ljhtYfktWGnzWWc6vOKZchhaH8W7VYfV7hN+RQP0dvaQTCVJPWXwpBU1kWompsblz6ZoS0y8" + "iRj3lS72kQdrsUB67fT/Jl9VmVBnxOmK/tv0AbSrcOMtNiLbAAAAAElFTkSuQmCC") +index.append('modifiedexists') +catalog['modifiedexists'] = modifiedexists + +#---------------------------------------------------------------------- +morecontrols = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAp1J" + "REFUOI2F0jFLG2Ecx/HvPXeJUROiPUmgmA4FqUUdpBTEaNFJHaSLxfQVuPQNFNpRhAwuvoAu" + "Qk86OJQSBUVXaUkrImjFOKjxSkIaNNE8591zHWyN6eJvffh/+D/P89Msy/K5Jz+/fkVkMvia" + "hhof58nz57dnBkBHRweFQoH29nYMw2BlZYVMJsPl5SXlcpmA4/D53TvwPCbn5ijMz5NIJEin" + "02iWZfmjo6NUKhVc10UpRa1WQ0qJ67pIKclubjKq6/iuy5py6RkYpK2tjXw+f7NBLBYjFos1" + "rF2pVAAQQlDOHeH/+I7vXtP3LMSLkRF0XSeXy90Ad3N+fk6pVOLL4CAPe3vxpMTzfUgkENfX" + "eJ9KbHx8iVKK82y2ESgWi+TzeZqamojF4/R2dSGkhFqNy1IJ3/N4Gm3H9X1c36cajdYBKSXb" + "29vous7Z2Rkr+/usHR3hui5etcqb/n5wHD58+0YgEkHXNH79/l0H9vb22NraQgjB8fExlYkJ" + "9k5OODw8xK9Webu/D75P9/v3vJqZIRwOs7y8XAdOT0+xLItEIoFt29i2TbFYxHEcOoAH/f1o" + "SuFcXWEYBkKIeg8ATNPk4OCAnZ0dhBAopQAIBoO0GAbbuRxC19GEQNO0RsDzPPr6+piammJx" + "cRGlFIFAgGg0immadD1+zMdwmPGxMV5PTiKlpLm5uQ5omoZhGKTTaWzbZn19HdM0icfjhEIh" + "CqUSA8kkKhxmbWOj4duNf2VRSmEYBrOzswwPD7O7uwtAJBIhmUwyNDRENptlenoagKWlJVKp" + "VLihB62trXR3d9PT04OUEsdxaGlpIRgMcnFxAUC5XGZ1dZVUKhUC5C0QCoX4H7ubf4/2d1hr" + "uMLCwsKZ4zjXnZ2dj7gnd4cB/gA1hCWaJRLM3gAAAABJRU5ErkJggg==") +index.append('morecontrols') +catalog['morecontrols'] = morecontrols + +#---------------------------------------------------------------------- +moredialog = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAaJJ" + "REFUOI3VksFLG1EQxn8vu4poK1KtYFhCscaDpVpKLyu59D9oi+A/UDS5e4uKSDx59yJaj3rw" + "Li20h4Tdg5deSpMSQnJoS1vUGoiaxed4cdeNrujV7zK8mfd9880wBneA8dJ425t+uNX5uiPT" + "rJ/+kd9S9Gsqt5iT2wRKP0uMvn+GFs339RLJ+DAAs/OzygTIzmVRaulGgY5+TXLKQ4tma1tz" + "/DeLUgoAE7iB7PkmwdAc6X9o0ShDo9SC/6nLBBDJXqM/WbV4Zb0gpoR2ATHbENG8WftPgwLV" + "2hDls9ovM0xyCy52ysYtuDzt7Wc8OQgxj1Ma7B3tI6J5PtyDp4WRxCN2vnndZhTZTtnsTpep" + "fj3k5PiEZqzJxGQC4YzVDy59D/qoVCpgsk9uMSc+nLwTGWeWZiRd7pJ0uVNWNlfEyTsCSLDE" + "KAfhGE/Eae8ZAwXFH0Uyk5nLucMOwgACB8sby/LusyUTXyzhMS0OAoGrtoHgXW/U5aP7SaoH" + "NRmwBoJ6ywh2yg6O4+pYUXkfsXBSRHDyThD9HUTlfVxcYmuH+4VzlkEmgUrj7QoAAAAASUVO" + "RK5CYII=") +index.append('moredialog') +catalog['moredialog'] = moredialog + +#---------------------------------------------------------------------- +overview = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAkVJ" + "REFUOI19kUlMU1EUhr/7+mj7Sm1BSgsU4hCDgQ0JjhCTJiQu3NVEo7KRVdW4dOfClSv2sjBd" + "uHGjiUMwURwaIhICCBEhQashDGppqbQQOtE3uKCQloJ/cnPucP7/nP9cQQGhUCin63qePSCE" + "MEWj0Ynu7u5LwHJZgt1uv6iqqrHfymQyRjgcNoLB4BjgKOZKhWjsVbkYqVSKnp6eU319fW8A" + "126B/0KWZVRVJR6PEwgEOnp7e/uBOgBRsOBPJpPPtwnL8TWevJ5kJZHGwKDGodBcb8LrqULT" + "NKqrq/H5fDcikchDubiSYRh8GJllaCrGdX8nRxsUMpsGv1eyPHoxwmkZzne2oigKQghTmYXV" + "tTQvhxY40dbM8JdFUuk80z+iDE7M09l+nLfjMZIbuVJ7xYf+wRmEcpB344vYbRXEXn1nfSPH" + "ylqWgdEl5iNpnr2f4fa1c3sLTP2MM/3HQl7VqHdXcudKGwMTvwg++IyWzyNJJr7Ore7fgcks" + "MxfPIoBwdJVvkQ00IIeMcsAKQIV5y7Wu65TNoKPFg2QxY7ZacToqMVfIWGUJZ5UdxWZFViyc" + "aXHv30HXycO0f/pLQtThtmk4LYKmGoXWJgcpoxK7HuPC2SMlAhKApmmFtjTu+t14s2M01lbx" + "dCRDaFZwrNGDd3OSe34XQmx99zanpANd1/HW13L/Vhcfh0dZWlhHSIJ2jwPfTR82mw3DMHb8" + "lwm4XK6dx6uXG0qES4ZtMu3sRSEe8ng8Ab0oczep6F4AJBKJx8DsP7f3ACwAunutAAAAAElF" + "TkSuQmCC") +index.append('overview') +catalog['overview'] = overview + +#---------------------------------------------------------------------- +process = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAA2pJ" + "REFUOI11k11oWwUYht/zl5NzcpaTk98lNI1JOc2kbbqxYqpTx2y6Ib2Y28hovRFkbFi88CLi" + "TWWgFVRkFnH4AxWcd4PBmBtM98Na0+ykFdKltN3SLMsMC5u1PelfTtrkpF7YyhT9bt/vfS4+" + "vgf4n2lrO/pVd/fgitkc6LNa/d3R6Md3+/uHbgGwP71H/FdZlqNnZTncL4ocaNoAQTDB4dgB" + "j8eBROKnxLlzp48BePwPAMNIrXv3vv6DptVIq9UbCgScEEUBgmACxxnBMBSampzQdQax2Hs3" + "8/lLPQDWqW1Aa2vfNUFobHe7na7jx19GJLIbsuwBz3PQ9Tp4ngVJEiAIwGDgbJnMxNj6+tqD" + "vwGS1PpWIOB3nTx5CDabGYqSQzx+D4qShtttQUODHRRFwmrl0dX1HEtRjS+Mj98aoQDA5+v+" + "Yteu51/t7d1PmUw8rl+fRSIxXk2nlfvx+NnY8nKV3rfvlWZRZMFxNESRxeamYIvHx5boUOjY" + "18Fg1ymvV0Jjox03btxFKjVVHRv77rO1td8uAkhr2mqIYRhYLH/dolgsgaLq6OzsjdHBYOSU" + "wyHA53NBVTVMTWUwOvrNkKYVzgNIS5Iv3Nf35tGdOzkwDIlCQcXs7CMUiypKJVUjS6UHv7As" + "C12vY2mpDFUtQdMKSQCTZnNDx8DAt1d7el7yWSwG1Go6ZmYeYXIyB0WZWFWU4Q/I0dHvTwMk" + "eJ7DxoYOSdpRYVm7LRzu/XRg4MvLBw92mAmiCkFg4fGIWF4uI5OZWcpmL3xULhev0LLcErRY" + "eLAsDY5jcPjwi7Tff2YwEtnvcDqNMJkIGI0mWCwcdH0TLEtgbu7KcKmUuwSgSEWjb3/S0hLy" + "u1wCGIaCKPJke3vQZLcbQNMEKpUqbDYTarU6RkayqNdpzM9XrA8fjg8DWKAmJn7+kedd4ebm" + "0DM0TcDlEsFxJGiaxNzc70gmc0ilClhc3MCTJ6tIpXKYnk5rCwtT5wGo26/s2LPnjYuyvLvz" + "xIlD9Y4OmZ6eLuD27fu4cyeHTOaeJor0Y1VdJMvlCpHPXx3StD8uA8g/JRPbZDQ6XvN63cZY" + "7PNBSTIjkZhFMvnrWjZ74cP5+dw1ALUtf8pbMq38W0QDAN7pbHvnyJEzKwcOvL/I8653ATwL" + "QNrKDQDo7cKfzfc7KseZc4UAAAAASUVORK5CYII=") +index.append('process') +catalog['process'] = process + +#---------------------------------------------------------------------- +pyshell = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAg5J" + "REFUOI2tkk1I03EYxz+//1+2Of9L52r24uYaBSXdutShlDp0CYzohbpY0cFDL3gWi7oUQmAl" + "QUJ18mAzmNjBoiDQELwoxWa25Qs5TciJNcZ0//+eLmrOF4roOT2/5/s83+/z8oP/aZebmsQX" + "CuUex2Lib2sToP1PNdoKv86f+inHu7qU0dvLpoYGOsPhM39PENxZd/LiJbW5upr32QUGIxHu" + "fpsS2/UrAtg2IlAAmsuVLOnvdxfriozA95kktnQaezqFVrmP2arDWIlJtWEHnndv3Ps/DzOj" + "6xgTCey6RuZGI5mWR1imhZjmerWS99oDosE0EDXankhZX49UfB0Xd/dLAQIrcx1HDonn/p3f" + "BHtLS+VBMLgc8L7tloovMfF8GBTN7xvIU3I6Q+6nrWv2IsDYoj9WNhQVfzwmRvM9AcqXF1bs" + "el0+OWGpkpLn680EgLu1RQIjcfEORQVNhVdiWzpfiLP+at7sWn45z4qqjqJrimxfD+TkRB4a" + "8OGqrQW4sFZaqdtbPw7kdo2PyI54XIDI6hTd650Oxj+J4+xpWRIvWMSMwvprjXangUIx392B" + "7eCBSmUU5Z/KNJmfGMV96yZT7aHdwHDBMriQYd6yyClFYc05CmvOw6r7iwhZy2TuYTNAAhZ/" + "4lIXuIwOtm87BlDsK2cuOYNud2DN/gCxIGvCyOgr4BSQWruHf7BfnoPGjBi/kJoAAAAASUVO" + "RK5CYII=") +index.append('pyshell') +catalog['pyshell'] = pyshell + +#---------------------------------------------------------------------- +recent = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAUBJ" + "REFUOI3t0j1rUwEUxvHfTW9rIHfRpd1cVBxc1MHsOhecHRXLLUVwMZ/AIXERQe4iCDppB8Gt" + "Szct6AeILYKm+BKHXN9SE4K9xyFa7ezaBw6c4TmH/3nhQEl03ESOAhPkwkPkEh/wFW8lCpVj" + "oKaukqspREcZozLi0YWIjn4M+9N8MowotyI+vox4tRpxO4tYuzqNtm4MuhF3FyIV6tI6i4+5" + "cyQzl7FwlsmQeyc+mcvmLfU4vcLR81Pu8ZeTZjN2+u9SVKJic5Vmq7E3XP0wV7bmjQa8fsqZ" + "FX6OmTnEuRaDLnTTvYK1pR3Xyr8Nxp+nBLyRzDRd/8H2OpPvHL/I/VNQ1Pat9EWb2cZ+gksb" + "TdXuSOzyrcf7Z9RSyk3JDU+SaLv1zxUaErlQSFxGDwPh+W/PA1R/PEnL8v8/woH8Ah0VioYI" + "i9+mAAAAAElFTkSuQmCC") +index.append('recent') +catalog['recent'] = recent + +#---------------------------------------------------------------------- +saveperspective = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAA1FJ" + "REFUOI1tk21MU3cUxp97WwqVS1tx0mLvaKtrYUB94SbjRaUms8bICg1RXGVQZgwuTRYTY9Rt" + "H5bgB8eWJbo4k82Ixrg4om4TMjuXofgWgcGQzW3oWlrWW0opb6Ug9NLy3xdrkHk+nl+eJ+fk" + "PEeEl5TD4WBMJlMbgLU+n68NwEKC2e12hdls/qSubt9Ft3sgm36ZQSAQ2rR9e1lJcckWB4DV" + "i5lKpTx+5MhHB+Ry9YpgMPh/g6qqqqK3bdWX4gugKcGXtEbDHkywmpoaQ17e+uq7937FiRPH" + "Z8bGRhpEi8W1tbWlFdZdTrksXT4R6MZ7jkrKmM9yvb0Daes3cEM7dpTf6enpU3xw9OD1wUHX" + "YQA/UQmxzWYzWa27WhgmXRYOdqC8YhNSGRVApnDt++sLvf3iWd4fSDl/7tTX8XjckdCJno1m" + "sliqWhhGIRvx/oK3LEVIU4gQnxnH/a4xiKUsRcWmJU1nTj6amHpqWTy1qL6+vtJSvvu7ZakM" + "M+q9jWx9OhixBJ2nnXAPzSGarkNf9yNsLlyBsq25K/sfPsnkQ1M/PjfQ6XT2ybCweWHqW7p6" + "pwrK18zw97pBBiKYfPgPXP7HqHhnI4RoEvKNORSXv5LrevAHG5x42ppYoaO15XIr7x9VFL4R" + "zaH4MDXaHYOWVUJwOvFvextyayth0EowO0PjVcPrFKeXFXj/fqLxBKeviUKhkADAPzI6dznW" + "Gd1XrN8o176yCp6ms3DNj0NdtxdqHcFyaQCDvgguOYPgCrTYWqzZ0PXgd70YAD4GxDINe8P6" + "4TE2Iy0V/BefgZ/mEW04A7YgC6zkL0TCEbCaLKz2/gZCa0CEOczH45zIDqRk6rTt7371ZalS" + "SlMTpz/HnZ4+nJelRLVqCb2NW0VNDvO42A7I4UXptjy4e/ph29/o+ZOP1KBBldE0dPUbEnNe" + "IeNlheSGSkpykpN9AN7UyunDraf2zgvDLeRm8yESfnyWdP3QSAwZjAdALgCgc49VID83k1hl" + "CbmlTCbrkpICAAoTZ1JK8f6VT/cIZLaddFw9RrIzlrkAGJ4H4eSazGG/2UiaVVJiENEuANzS" + "/1Az2N9YXzRnzFJ4AOhfgDlAkRG4KaeoCwDUS8WLImsGsHZp/z+rvEoNBUEjtAAAAABJRU5E" + "rkJggg==") +index.append('saveperspective') +catalog['saveperspective'] = saveperspective + +#---------------------------------------------------------------------- +customcontrol = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAAnFJ" + "REFUOI2lkz2LlGcUhq/zPO/M7M7OTtaJu7K76kaIaKHiF341miqkCcTKdCkCAZv8AklnYyCE" + "/IJU2vgDRLTSWIghqPiBijDqiBtdM7uTmffrnGPxjiJCIODdHLjhuTj34X7gIyWLe86cOXTg" + "wPfmpZQlqApqoArFeGpB5VnlmQbSXL17+9fTyfbP1n118sSWmcEwZ5RBmsl4QlZAmsIogyyH" + "USqMCiiKwMqa8fzx/NGkNVPLFucbqNUxAzNAhAjkpeMmpKWjFjBz1AT3QK4JT+4mZVKrRRbm" + "W0y3m+9yvfin4Gq3YP9Sg2Hh7J1LAAc33B2AvIi0p4QEYOwBcOVRyo2e8kqFS/eWqU9McHip" + "ya5ZYetcIC8M9yqelmUFeF+X7/RZbrSor7zi5f0uT/ol1xY3s2/bBn45FnEBNa+iooT3H68M" + "lG7WYOOnkxw/OMfZU0f47eReFhrOlZ7y8/USLRXcMTVcPwAEgcs3e1x78JpRrUEQZ9/nTX78" + "chPr17V43De0NMwqgOEVQEQA+KQZ+f3bjXRqgYcDuPg00H3tTE0Fts0KVktYHni1gTuokkSE" + "GGPVKoFOu8a9Xp9HL4fs3zLN6tY2a5nTDhl/PHhO3LkeVRsfXqsjhlglcXeWOnW+2zkBqjzL" + "RjRtggt/LTMzM81PX3ToNCEtDDOpADGJ0qi/3UBoTQZ+ODYLppz7c0BIc77ePk1/VLJn0yRm" + "RhKdEAJEkaS/msvKmhAjaFk10VQxdw7NN8GURALukf5aiZkhAsNRxr+rwyixteObhc27jwdx" + "MX3bKEOBCKjmgI47XoIXgFIUBX/3bp3////2P/QGWsxIJsvdP+sAAAAASUVORK5CYII=") +index.append('customcontrol') +catalog['customcontrol'] = customcontrol + +#---------------------------------------------------------------------- +deletedocs = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QAAAAAAAD5Q7t/AAAA" + "CXBIWXMAAA3WAAAN1gGQb3mcAAACTUlEQVQ4y82SPUxTURTH/6f3fb9a2tDSIqSPhIogMSom" + "TNVB487o4qCLm0bdJEad1MnNxN1FIw6ExagkJn4UURI+JA0fBQyg0DxqGyTl9r17HbBAkcXN" + "311ucs755fxvLmEPzwdeQ4UAh1InIDuEkCd8ITqFkAc5598Wl5bvElC4feMyAECpDva/eo9A" + "gAIVz++sCNEjhTwnheiQQFjTNMUyDORdt+S6a88URf1QnVMA4OHjJxgbn2CtqdQ1xth1IWWC" + "iMg0DUQjITQnouCco7iWH3fz3/O2bW9vzADAh8TsTDbqCXogibVpmk6hoIloOIiQrQPCh/Ar" + "En7lDfzy23t3eguF0jqGMh9BAHD0ZDeE8NONTU5/On06crgtBcvQEI9GkIjHIaSE73lQFQbO" + "eYaIzuu6vpBMJrciEAGln2sjXd2nBtoPtV5ItTRjcmoGRECl4qFcLoMpCgzThmHoLGTpqHmD" + "Rqcd6bM9G1LwpdFsDosrLlqcJBoSCdiGinAoCMuyMJbNYXAwM9J79dLCxSu3AAABAJBSgogA" + "CQSYivpYAqZlgbEAgsEgwnV1W/UtJAB4vtgR7EXW3KunlqpwX8G/8L8IJPZJ+Te0O/xuwdzU" + "KB7dv4lyeUMlItS2/Gkkgud5KBULKhGxL+9eAsDOR9JtU8lNT46pmpaL1UecyAGLCSEgfAHO" + "OX6srIoXfU/l8OfhziPHu1oYo9ltQfHXOhBr8qazE32lYmF2dWn+jOM4xxrjDTHbMuF7FXdu" + "fv7r0KfMMt/cXFYUZaW62W+bkO7zu6lNiAAAACJ6VFh0U29mdHdhcmUAAHjaKy8v18vMyy5O" + "TixI1csvSgcANtgGWBBTylwAAAAASUVORK5CYII=") +index.append('deletedocs') +catalog['deletedocs'] = deletedocs + +#---------------------------------------------------------------------- +#---------------------------------------------------------------------- +spinning_nb0 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAANBJ" + "REFUOI21kmGOAyEIRh+b3sheqUyPtHCllSuV/TGa6saZNmmWhBjRDx6oCMf2gASQ3ZdXv070" + "+NlhM/kXghvkA3IbYgmZLeGMcODWBIMwl3c/beE0QUc/Ek8Jvs0yIqBAiUIQ+0Hfl3jGW+zu" + "m4gAN9VU1UOKiKCUMgTAcXxzMLP1cE7czFJVE8hLRPBTa46V/q7drn6FMhOJmSUwI75oJSKI" + "CNydSxe7+7L6imYiU9Wstb49h1prqmo28hRrz/dO9XF1dwT2Z1z+8RfWP9cvJcCY3mA4ykUA" + "AAAASUVORK5CYII=") +index.append('spinning_nb0') +catalog['spinning_nb0'] = spinning_nb0 + +#---------------------------------------------------------------------- +spinning_nb1 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAANJJ" + "REFUOI21klFuw0AIRN9WuRG5UnCPVLhSd64U+hE7iS1vHCkqElqJHWAYoAEjd6iCAmqIa4zt" + "ektewLvQrxf55KvP2f6HwQXqCjU9xeqhx4bCwGNOqCMhPx3hXuAnoiRhZki6AzKT8EAmTIYQ" + "GJiM75xaa8DFvdx9yGQp/AhAkuSUEBHjIxnpE1HuXkCdJPHbez132r6LnfMMtmbUIqKANcWD" + "USQhiczktCRn5m73PTYrZu5evfe3dei9l7vXzLxabNb37puZNLitcfdED2w5rD84JJ1LvGPz" + "hQAAAABJRU5ErkJggg==") +index.append('spinning_nb1') +catalog['spinning_nb1'] = spinning_nb1 + +#---------------------------------------------------------------------- +spinning_nb2 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAANJJ" + "REFUOI21k2FuwzAIRh9Tb0SuVLIrwZUGVyr7kTRqVMebNA0JWYIP84xtEf5mH7PkHfoB3dBX" + "GpkRPPZC2XwonRLELPmvBM+zry+xvpqFXLjvBS+FPdLdjq7urVWUKlRRABFHEzPbQQAFLeUz" + "VhEB7ma9C95sWRYy8xwsCIJYA9x9iDZzd28za6BvVcVXZgNUFar6th40sYByiou7N3ASXtnr" + "xlVFRGxDVFUiYth9RHMiM7POzF/PITPbzHonb3H3/qnraI0IBLZrnP22K3s+7W83QZdyusVt" + "lAAAAABJRU5ErkJggg==") +index.append('spinning_nb2') +catalog['spinning_nb2'] = spinning_nb2 + +#---------------------------------------------------------------------- +spinning_nb3 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAANNJ" + "REFUOI21k1uOwzAIRQ+j7sjZUsksqbClwpbKfCRNXSXxfFRFQrZ53ottET6Tnw/zxwWuUA+o" + "gjqLkRGFx5ooix6GDhHMI+dXEdxW7t7Z6mQWG4KbamVrtEwSwB3rAwFVXQ4NWjZ+fRYR4Kpa" + "m7OTNk1bckS8HAmO47ODmZW8eO4U2PnNrFS1gLpkJveIAshMWmu7lZX75BM0ejtiZgVshpH0" + "hTMTd+fyTHb3w+4HaN72qGpFxHAOvUZEqWqtyEvMrP7rerS6OwLLNY4+y5k8X+YflwSO08m0" + "TxoAAAAASUVORK5CYII=") +index.append('spinning_nb3') +catalog['spinning_nb3'] = spinning_nb3 + +#---------------------------------------------------------------------- +spinning_nb4 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAANdJ" + "REFUOI21kk1ywzAIhT91fCN8paAeqXClwpVCF7acOBM7i6TMMCzE+9GTWuO9+noT/88EP1BX" + "qII62mlnGVxXYFv66eqpg352+CkHG8HFrCSTBHDHAAeUPVJVARARvntvE8BFtVQERJBliz7P" + "2AqqlSQiNiJ3p6Aws2o3m7uu2wvsdsysVLWAmjKT34gCyExEZJueSe99KNcsMwDZl3OAZmY1" + "7vSq7gUyE3dnGmB336kfzXuikWpFxGEOjx0Rpaq1Oq9mZvVK9dl0dxq0NtJ+GcBDjY/1B8KZ" + "jqC9Dj6pAAAAAElFTkSuQmCC") +index.append('spinning_nb4') +catalog['spinning_nb4'] = spinning_nb4 + +#---------------------------------------------------------------------- +spinning_nb5 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAANNJ" + "REFUOI21k1uOwzAIRQ+j7sjZUsksqbClwpbKfCRNXSXxfFRFQrZ53ottET6Tnw/zxwWuUA+o" + "gjqLkRGFx5ooix6GDhHMI+dXEdxW7t7Z6mQWG4KbamVrtEwSwB3rAwFVXQ4NWjZ+fRYR4Kpa" + "m7OTNk1bckS8HAmO47ODmZW8eO4U2PnNrFS1gLpkJveIAshMWmu7lZX75BM0ejtiZgVshpH0" + "hTMTd+fyTHb3w+4HaN72qGpFxHAOvUZEqWqtyEvMrP7rerS6OwLLNY4+y5k8X+YflwSO08m0" + "TxoAAAAASUVORK5CYII=") +index.append('spinning_nb5') +catalog['spinning_nb5'] = spinning_nb5 + +#---------------------------------------------------------------------- +spinning_nb6 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAANJJ" + "REFUOI21k2FuwzAIRh9Tb0SuVLIrwZUGVyr7kTRqVMebNA0JWYIP84xtEf5mH7PkHfoB3dBX" + "GpkRPPZC2XwonRLELPmvBM+zry+xvpqFXLjvBS+FPdLdjq7urVWUKlRRABFHEzPbQQAFLeUz" + "VhEB7ma9C95sWRYy8xwsCIJYA9x9iDZzd28za6BvVcVXZgNUFar6th40sYByiou7N3ASXtnr" + "xlVFRGxDVFUiYth9RHMiM7POzF/PITPbzHonb3H3/qnraI0IBLZrnP22K3s+7W83QZdyusVt" + "lAAAAABJRU5ErkJggg==") +index.append('spinning_nb6') +catalog['spinning_nb6'] = spinning_nb6 + +#---------------------------------------------------------------------- +spinning_nb7 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAANJJ" + "REFUOI21klFuw0AIRN9WuRG5UnCPVLhSd64U+hE7iS1vHCkqElqJHWAYoAEjd6iCAmqIa4zt" + "ektewLvQrxf55KvP2f6HwQXqCjU9xeqhx4bCwGNOqCMhPx3hXuAnoiRhZki6AzKT8EAmTIYQ" + "GJiM75xaa8DFvdx9yGQp/AhAkuSUEBHjIxnpE1HuXkCdJPHbez132r6LnfMMtmbUIqKANcWD" + "USQhiczktCRn5m73PTYrZu5evfe3dei9l7vXzLxabNb37puZNLitcfdED2w5rD84JJ1LvGPz" + "hQAAAABJRU5ErkJggg==") +index.append('spinning_nb7') +catalog['spinning_nb7'] = spinning_nb7 + +#---------------------------------------------------------------------- +spinning_nb8 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABHNCSVQICAgIfAhkiAAAANBJ" + "REFUOI21kmGOAyEIRh+b3sheqUyPtHCllSuV/TGa6saZNmmWhBjRDx6oCMf2gASQ3ZdXv070" + "+NlhM/kXghvkA3IbYgmZLeGMcODWBIMwl3c/beE0QUc/Ek8Jvs0yIqBAiUIQ+0Hfl3jGW+zu" + "m4gAN9VU1UOKiKCUMgTAcXxzMLP1cE7czFJVE8hLRPBTa46V/q7drn6FMhOJmSUwI75oJSKI" + "CNydSxe7+7L6imYiU9Wstb49h1prqmo28hRrz/dO9XF1dwT2Z1z+8RfWP9cvJcCY3mA4ykUA" + "AAAASUVORK5CYII=") +index.append('spinning_nb8') +catalog['spinning_nb8'] = spinning_nb8 + diff --git a/demo/infoframe.py b/demo/infoframe.py new file mode 100644 index 00000000..14d744b8 --- /dev/null +++ b/demo/infoframe.py @@ -0,0 +1,148 @@ + +import sys + +import wx +import wx.lib.infoframe + +#---------------------------------------------------------------------- + +class MyFrame(wx.Frame): + def __init__(self, output): + wx.Frame.__init__(self, None, -1, "Close me...", size=(300,100)) + + menubar = wx.MenuBar() + + # Output menu + menu = wx.Menu() + + # Enable output menu item + mID = wx.NewId() + menu.Append(mID, "&Enable output", "Display output frame") + self.Bind(wx.EVT_MENU, output.EnableOutput, id=mID) + + # Disable output menu item + mID = wx.NewId() + menu.Append(mID, "&Disable output", "Close output frame") + self.Bind(wx.EVT_MENU, output.DisableOutput, id=mID) + + # Attach the menu to our menu bar + menubar.Append(menu, "&Output") + + # Attach menu bar to frame + self.SetMenuBar(menubar) + + # Point to ourselves as the output object's parent. + output.SetParent(self) + + # Associate menu bar with output object + output.SetOtherMenuBar(menubar, menuname="Output") + + self.Bind(wx.EVT_CLOSE, self.OnClose) + # We're going to set up a timer; set up an event handler for it. + self.Bind(wx.EVT_TIMER, self.OnTimer) + + # Set up a timer for demo purposes + self.timer = wx.Timer(self, -1) + self.timer.Start(1000) + + # Get a copy of stdout and set it aside. We'll use it later. + self.save_stdout = sys.stdout + + # Now point to the output object for stdout + sys.stdout = self.output = output + # ... and use it. + print "Hello!" + + def OnClose(self,event): + # We stored a pointer to the original stdout above in .__init__(), and + # here we restore it before closing the window. + sys.stdout = self.save_stdout + + # Clean up + self.output.close() + self.timer.Stop() + self.timer = None + + self.Destroy() + + # Event handler for timer events. + def OnTimer(self, evt): + print "This was printed with \"print\"" + + +#---------------------------------------------------------------------- + +overview = wx.lib.infoframe.__doc__ + +def runTest(frame, nb, log): + """ + This method is used by the wxPython Demo Framework for integrating + this demo with the rest. + """ + win = MyFrame(wx.lib.infoframe.PyInformationalMessagesFrame()) + frame.otherWin = win + win.Show(1) + +#---------------------------------------------------------------------- + +if __name__ == "__main__": +## class MyFrame(wxFrame): +## def __init__(self,output): +## wxFrame.__init__(self,None,-1,"Close me...",size=(300,100)) +## EVT_CLOSE(self,self.OnClose) +## menubar = wxMenuBar() +## menu = wxMenu() +## mID = wxNewId() +## menu.Append(mID,"&Enable output","Display output frame") +## EVT_MENU(self,mID,output.EnableOutput) +## mID = wxNewId() +## menu.Append(mID,"&Disable output","Close output frame") +## EVT_MENU(self,mID,output.DisableOutput) +## menubar.Append(menu,"&Output") +## self.SetMenuBar(menubar) +## output.SetOtherMenuBar(menubar,menuname="Output") + +## def OnClose(self,event): +## if isinstance(sys.stdout,wx.lib.infoframe.PyInformationalMessagesFrame): +## sys.stdout.close() +## self.Destroy() + + class MyApp(wx.App): + + # Override the default output window and point it to the + # custom class. + outputWindowClass = wx.lib.infoframe.PyInformationalMessagesFrame + + def OnInit(self): + + # At this point, we should probably check to see if self.stdioWin + # is actually pointed to something. By default, wx.App() sets this + # attribute to None. This causes problems when setting up the menus + # in MyFrame() above. On the other hand, since there's little that + # can be done at this point, you might be better served putting + # an error handler directly into MyFrame(). + # + # That's in practice. In the case of this demo, the whole point + # of the exercise is to demonstrate the window, so we're being + # just a little lazy for clarity's sake. But do be careful in + # a 'real world' implementation :-) + + frame = MyFrame(self.stdioWin) + frame.Show(True) + self.SetTopWindow(frame) + + # Associate the frame with stdout. + if isinstance(sys.stdout, wx.lib.infoframe.PyInformationalMessagesFrame): + sys.stdout.SetParent(frame) + + print "Starting.\n", + return True + + # *extremely important* + # + # In this demo, if the redirect flag is set to False, the infoframe will not + # be created or used. All output will go to the default stdout, which in this + # case will cause the app to throw an exception. In a real app, you should + # probably plan ahead and add a check before forging ahead. See suggestion above. + app = MyApp(True) + app.MainLoop() diff --git a/demo/paper.xml b/demo/paper.xml new file mode 100644 index 00000000..e6bad5a9 --- /dev/null +++ b/demo/paper.xml @@ -0,0 +1,85 @@ + + + + + +]> + +Using SGML to make footprints in the sand +footprintssand +JaneDoe +Empress +
    Universe Corporation +1 Main Street +Perfect City +Dorado +Neutral999999 ++55 555 555 5550 ++55 555 555 5555 +jane@universe.com +www.universe.com +
    +Jane Doe is the Empress of the Universe , a position to which she has always aspired. +
    +FredBloggs +Designer +
    Fred (The Shoe) Bloggs Ltd +1 Shoe Lane +Perfect City +Dorado +Neutral999999 ++55 555 555 1122 ++55 555 555 1133 +fred@shoebloggs.com +www.shoebloggs.com
    +Fred has always wanted to create the perfect shoe for making footprints in the sand. Now with SGML and XML, he has been able to document his design. +
    + +easedocumentationIt's not easy being an Empress of the Universe (), but with the right pair of shoes and the right documentation on how to make footprints in the sand of life, it's easier than it was. Since the introduction of SGMLStandard Generalized Markup Language and XMLExtensible Markup Language it is now possible to identify and manage the key bits of information on this process. + +
    +
    Introduction +documentationSince its inception, the Universe has always had sand, now it has an Empress, a good shoe design, and SGML / XML documentation. The time is now ripe for making footprints in the sand.
    +
    Footprints - truly a push technologypush +One could safely say that making footprints is a push technology. This is even more true when the footprint maker is the Empress of the Universe. +The sands of timetime +The 1st think to remember about the Universe is the time/space continuum to which it conforms. This then confuses the sands of time to be something more like the sands of time/space continuum because if you wait on those sands long enough they may be somewhere else - not necessarily because of the time/space continuum but because the winds will push them down the beach. +Identifying the footprints +In order to truly understand who has walked on the sands and left the footprints, it is important to identify the characteristicscharacteristics of the footprint. In the graphic , we can see the footprints are large, well shaped, and evenly distributed from front to back and side to side. +
    Footprint in SandNote the evenly distributed shape and indention
    +This footprint begs the question, 'What kind of remarkable shoeshoe could make such a wonderful footprint?' + + +Shoe TypeRemarkability Rating +Acme ShoeUnremarkable +Budget ShoeNot worth remarking on +Super Duper ShoeAbsolutely Remarkable +
    +The Shoe What Made the Footprint +The remarkable footprint is made by a combination of a terrific shoe worn on a fantastic foot propelled by a one-of-a-kind Empress. As can be seen in Figure , the shoe is worthy of an Empress. +
    The Terrific Shoe
    +The design goals of the shoe were: + +
  • to minimize time-consuming manual tasks such as shoelace tying;
  • +
  • to allow different decorations to be placed on the toes; and
  • +
  • to enforce a good arch.
  • +
    Documenting the Shoe +Documenting the shoe was the best part for Fred Bloggs. His superior design could be captured for all time in a neutrally-encoded, content-specific manner. An excerpt from his DTD gives an insight into the type of information he captured in his documentation. +<!DOCTYPE shoedoc [ +<!ELEMENT shoedoc - - (design, mfg, care, recycle) > +<!ATTLIST shoedoc designer CDATA #REQUIRED + date CDATA #REQUIRED> +<!ELEMENT design - - (specs, desc) > +etc. + +An excerpt from the documentation also gives us insights. + + +The arch shall be high. The toe shall be narrow, but not pinch. The heel shall not come off in grates. Sand shall not get in.]]> + +
    + +The authors wish to express our thanks to the Universe for being there and to gravity for holding the sand down long enough to see the footprints. + +Barrett 00Barrett, B., Being Empress Made Easy, Galaxy Division of Universal Publishers. 0000
    diff --git a/demo/pyTree.py b/demo/pyTree.py new file mode 100644 index 00000000..24892a90 --- /dev/null +++ b/demo/pyTree.py @@ -0,0 +1,229 @@ +""" +Hello, and welcome to this test of the wxTreeItemData +class. + +The wxTreeItemData class can be used to associate a python +object with a wxTreeCtrl item. In this sample, its use is +demonstrated via a tree control that shows the contents of a +python namespace according to the standard dir() +command. Every item in the tree has its label taken from the +dir() output, and 'behind it' a reference to the python +object is stored in a wxTreeItemData object. + +As you may have guessed by now, this sample automatically +displays '__doc__' strings if the selected python object +happens to have one. Please expand the pyTree object to +learn more about the implementation. + +Version 1.0, April 4 1999. +Harm van der Heijden (H.v.d.Heijden@phys.tue.nl) + +P.S. Check out the string module. It's imported in this +sample not because it's used, but because it's so +beautifully documented... +""" + +import string # Used for demo purposes, nothing more. :-) +import sys + +import wx + +#---------------------------------------------------------------------- + +def _getindent(line): + """Returns the indentation level of the given line.""" + indent = 0 + for c in line: + if c == ' ': indent = indent + 1 + elif c == '\t': indent = indent + 8 + else: break + return indent + +def _sourcefinder(func): + """Given a func_code object, this function tries to find and return + the python source code of the function.""" + try: + f = open(func.co_filename,"r") + except: + return "(could not open file %s)" % (func.co_filename,) + + for i in range(func.co_firstlineno): + line = f.readline() + + ind = _getindent(line) + msg = "" + + while line: + msg = msg + line + line = f.readline() + # the following should be <= ind, but then we get + # confused by multiline docstrings. Using == works most of + # the time... but not always! + if _getindent(line) == ind: break + + return msg + +#---------------------------------------------------------------------- + +class pyTree(wx.TreeCtrl): + """ + This wx.TreeCtrl derivative displays a tree view of a Python namespace. + Anything from which the dir() command returns a non-empty list is a branch + in this tree. + """ + + def __init__(self, parent, id, root): + """ + Initialize function; because we insert branches into the tree + as needed, we use the ITEM_EXPANDING event handler. The + ITEM_COLLAPSED handler removes the stuff afterwards. The + SEL_CHANGED handler attempts to display interesting + information about the selected object. + """ + wx.TreeCtrl.__init__(self, parent, id) + self.root = self.AddRoot(str(root), -1, -1, wx.TreeItemData(root)) + + if dir(root): + self.SetItemHasChildren(self.root, True) + + self.Bind(wx.EVT_TREE_ITEM_EXPANDING, self.OnItemExpanding, id=self.GetId()) + self.Bind(wx.EVT_TREE_ITEM_COLLAPSED, self.OnItemCollapsed, id=self.GetId()) + self.Bind(wx.EVT_TREE_SEL_CHANGED, self.OnSelChanged, id=self.GetId()) + + self.output = None + self.Expand(self.root) + + + def SetOutput(self, output): + """ + Set output function (accepts single string). Used to display string + representation of the selected object by OnSelChanged. + """ + self.output = output + + + def OnItemExpanding(self,event): + """ + The real workhorse of this class. First we retrieve the object + (parent) belonging to the branch that is to be expanded. This + is done by calling GetPyData(parent), which is a short-cut for + GetPyItemData(parent).Get(). + + Then we get the dir() list of that object. For each item in + this list, a tree item is created with associated + wxTreeItemData referencing the child object. We get this + object using child = getattr(parent, item). + + Finally, we check wether the child returns a non-empty dir() + list. If so, it is labeled as 'having children', so that it + may be expanded. When it actually is expanded, this function + will again figure out what the offspring is. + """ + item = event.GetItem() + + if self.IsExpanded(item): # This event can happen twice in the self.Expand call + return + + obj = self.GetPyData( item ) + lst = dir(obj) + + for key in lst: + new_obj = getattr(obj,key) + new_item = self.AppendItem( item, key, -1, -1, + wx.TreeItemData(new_obj) ) + + if dir(new_obj): + self.SetItemHasChildren(new_item, True) + + def OnItemCollapsed(self, event): + """ + We need to remove all children here, otherwise we'll see all + that old rubbish again after the next expansion. + """ + item = event.GetItem() + self.DeleteChildren(item) + + def OnSelChanged(self, event): + """ + If an output function is defined, we try to print some + informative, interesting and thought-provoking stuff to it. + If it has a __doc__ string, we print it. If it's a function or + unbound class method, we attempt to find the python source. + """ + if not self.output: + return + + obj = self.GetPyData( event.GetItem() ) + msg = str(obj) + + if hasattr(obj, '__doc__'): + msg = msg+"\n\nDocumentation string:\n\n%s" % ( getattr(obj, '__doc__'),) + + # Is it a function? + func = None + + if hasattr(obj, "func_code"): # normal function + func = getattr(obj, "func_code") + + elif hasattr(obj, "im_func"): # unbound class method + func = getattr(getattr(obj, "im_func"), "func_code") + + if func: # if we found one, let's try to print the source + msg = msg+"\n\nFunction source:\n\n" + _sourcefinder(func) + + apply(self.output, (msg,)) + +#---------------------------------------------------------------------- + +overview = __doc__ + +def runTest(frame, nb, log): + """ + This method is used by the wxPython Demo Framework for integrating + this demo with the rest. + """ + thisModule = sys.modules[__name__] + win = wx.Frame(frame, -1, "PyTreeItemData Test") + split = wx.SplitterWindow(win, -1) + tree = pyTree(split, -1, thisModule) + text = wx.TextCtrl(split, -1, "", style=wx.TE_MULTILINE) + split.SplitVertically(tree, text, 200) + tree.SetOutput(text.SetValue) + tree.SelectItem(tree.root) + win.SetSize((800,500)) + frame.otherWin = win + win.Show(1) + + + +#---------------------------------------------------------------------- +if __name__ == '__main__': + + class MyFrame(wx.Frame): + """Very standard Frame class. Nothing special here!""" + + def __init__(self): + """Make a splitter window; left a tree, right a textctrl. Wow.""" + import __main__ + wx.Frame.__init__(self, None, -1, "PyTreeItemData Test", size=(800,500)) + split = wx.SplitterWindow(self, -1) + tree = pyTree(split, -1, __main__) + text = wx.TextCtrl(split, -1, "", style=wx.TE_MULTILINE) + split.SplitVertically(tree, text, 200) + tree.SetOutput(text.SetValue) + tree.SelectItem(tree.root) + + class MyApp(wx.App): + """This class is even less interesting than MyFrame.""" + + def OnInit(self): + """OnInit. Boring, boring, boring!""" + frame = MyFrame() + frame.Show(True) + self.SetTopWindow(frame) + return True + + app = MyApp(False) + app.MainLoop() + + diff --git a/demo/quotes.xml b/demo/quotes.xml new file mode 100644 index 00000000..b8f56e34 --- /dev/null +++ b/demo/quotes.xml @@ -0,0 +1,13 @@ + + + + + + + + + + +]> +We will perhaps eventually be writing only small modules which are identified by name as they are used to build larger ones, so that devices like indentation, rather than delimiters, might become feasible for expressing local structure in the source language. Donald E. Knuth, "Structured Programming with goto Statements", Computing Surveys, Vol 6 No 4, Dec. 1974 The infinities aren't contagious except in that they often appear that way due to to their large size. Tim Peters on the IEEE 754 floating point standard, 27 Apr 1998 diff --git a/demo/run.py b/demo/run.py new file mode 100755 index 00000000..645f0e88 --- /dev/null +++ b/demo/run.py @@ -0,0 +1,164 @@ +#!/usr/bin/env python +#---------------------------------------------------------------------------- +# Name: run.py +# Purpose: Simple framework for running individual demos +# +# Author: Robin Dunn +# +# Created: 6-March-2000 +# RCS-ID: $Id$ +# Copyright: (c) 2000 by Total Control Software +# Licence: wxWindows license +#---------------------------------------------------------------------------- + +""" +This program will load and run one of the individual demos in this +directory within its own frame window. Just specify the module name +on the command line. +""" + +import wx +import wx.lib.inspection +import wx.lib.mixins.inspection +import sys, os + +# stuff for debugging +print "Python", sys.version +print "wx.version:", wx.version() +print "pid:", os.getpid() +##print "executable:", sys.executable; raw_input("Press Enter...") + +assertMode = wx.PYAPP_ASSERT_DIALOG +##assertMode = wx.PYAPP_ASSERT_EXCEPTION + + +#---------------------------------------------------------------------------- + +class Log: + def WriteText(self, text): + if text[-1:] == '\n': + text = text[:-1] + wx.LogMessage(text) + write = WriteText + + +class RunDemoApp(wx.App, wx.lib.mixins.inspection.InspectionMixin): + def __init__(self, name, module, useShell): + self.name = name + self.demoModule = module + self.useShell = useShell + wx.App.__init__(self, redirect=False) + + + def OnInit(self): + wx.Log.SetActiveTarget(wx.LogStderr()) + + self.SetAssertMode(assertMode) + self.InitInspection() # for the InspectionMixin base class + + frame = wx.Frame(None, -1, "RunDemo: " + self.name, pos=(50,50), size=(200,100), + style=wx.DEFAULT_FRAME_STYLE, name="run a sample") + frame.CreateStatusBar() + + menuBar = wx.MenuBar() + menu = wx.Menu() + item = menu.Append(-1, "&Widget Inspector\tF6", "Show the wxPython Widget Inspection Tool") + self.Bind(wx.EVT_MENU, self.OnWidgetInspector, item) + item = menu.Append(wx.ID_EXIT, "E&xit\tCtrl-Q", "Exit demo") + self.Bind(wx.EVT_MENU, self.OnExitApp, item) + menuBar.Append(menu, "&File") + + ns = {} + ns['wx'] = wx + ns['app'] = self + ns['module'] = self.demoModule + ns['frame'] = frame + + frame.SetMenuBar(menuBar) + frame.Show(True) + frame.Bind(wx.EVT_CLOSE, self.OnCloseFrame) + + win = self.demoModule.runTest(frame, frame, Log()) + + # a window will be returned if the demo does not create + # its own top-level window + if win: + # so set the frame to a good size for showing stuff + frame.SetSize((640, 480)) + win.SetFocus() + self.window = win + ns['win'] = win + frect = frame.GetRect() + + else: + # It was probably a dialog or something that is already + # gone, so we're done. + frame.Destroy() + return True + + self.SetTopWindow(frame) + self.frame = frame + #wx.Log_SetActiveTarget(wx.LogStderr()) + #wx.Log_SetTraceMask(wx.TraceMessages) + + if self.useShell: + # Make a PyShell window, and position it below our test window + from wx import py + shell = py.shell.ShellFrame(None, locals=ns) + frect.OffsetXY(0, frect.height) + frect.height = 400 + shell.SetRect(frect) + shell.Show() + + # Hook the close event of the test window so that we close + # the shell at the same time + def CloseShell(evt): + if shell: + shell.Close() + evt.Skip() + frame.Bind(wx.EVT_CLOSE, CloseShell) + + return True + + + def OnExitApp(self, evt): + self.frame.Close(True) + + + def OnCloseFrame(self, evt): + if hasattr(self, "window") and hasattr(self.window, "ShutdownDemo"): + self.window.ShutdownDemo() + evt.Skip() + + def OnWidgetInspector(self, evt): + wx.lib.inspection.InspectionTool().Show() + + +#---------------------------------------------------------------------------- + + +def main(argv): + useShell = False + for x in range(len(sys.argv)): + if sys.argv[x] in ['--shell', '-shell', '-s']: + useShell = True + del sys.argv[x] + break + + if len(argv) < 2: + print "Please specify a demo module name on the command-line" + raise SystemExit + + name, ext = os.path.splitext(argv[1]) + module = __import__(name) + + + app = RunDemoApp(name, module, useShell) + app.MainLoop() + + + +if __name__ == "__main__": + main(sys.argv) + + diff --git a/demo/snippets/__init__.py b/demo/snippets/__init__.py new file mode 100644 index 00000000..4534d003 --- /dev/null +++ b/demo/snippets/__init__.py @@ -0,0 +1,13 @@ +# snippet list generation +import os + +# list of snippet files +snip_list = [x[:-3] for x in os.listdir (os.path.dirname (__file__)) + if not x.startswith('_') and x.endswith('.py')] +snip_list.sort() + +# function used by some or all snippets +def snippet_normalize (ctx, width, height): + size = min(width, height) + ctx.scale(size, size) + ctx.set_line_width (0.04) diff --git a/demo/snippets/arc.py b/demo/snippets/arc.py new file mode 100644 index 00000000..b4e6e5db --- /dev/null +++ b/demo/snippets/arc.py @@ -0,0 +1,21 @@ +xc = 0.5 +yc = 0.5 +radius = 0.4 +angle1 = 45.0 * (M_PI/180.0) #/* angles are specified */ +angle2 = 180.0 * (M_PI/180.0) #/* in radians */ + +snippet_normalize (cr, width, height) + +cr.arc (xc, yc, radius, angle1, angle2) +cr.stroke () + +#/* draw helping lines */ +cr.set_source_rgba (1,0.2,0.2,0.6) +cr.arc (xc, yc, 0.05, 0, 2*M_PI) +cr.fill () +cr.set_line_width (0.03) +cr.arc (xc, yc, radius, angle1, angle1) +cr.line_to (xc, yc) +cr.arc (xc, yc, radius, angle2, angle2) +cr.line_to (xc, yc) +cr.stroke () diff --git a/demo/snippets/arc_negative.py b/demo/snippets/arc_negative.py new file mode 100644 index 00000000..1d8cd344 --- /dev/null +++ b/demo/snippets/arc_negative.py @@ -0,0 +1,21 @@ +xc = 0.5 +yc = 0.5 +radius = 0.4 +angle1 = 45.0 * (M_PI/180.0) #/* angles are specified */ +angle2 = 180.0 * (M_PI/180.0) #/* in radians */ + +snippet_normalize (cr, width, height) + +cr.arc_negative (xc, yc, radius, angle1, angle2) +cr.stroke () + +#/* draw helping lines */ +cr.set_source_rgba (1,0.2,0.2,0.6) +cr.arc (xc, yc, 0.05, 0, 2*M_PI) +cr.fill () +cr.set_line_width (0.03) +cr.arc (xc, yc, radius, angle1, angle1) +cr.line_to (xc, yc) +cr.arc (xc, yc, radius, angle2, angle2) +cr.line_to (xc, yc) +cr.stroke () diff --git a/demo/snippets/clip.py b/demo/snippets/clip.py new file mode 100644 index 00000000..84562351 --- /dev/null +++ b/demo/snippets/clip.py @@ -0,0 +1,13 @@ +snippet_normalize (cr, width, height) + +cr.arc (0.5, 0.5, 0.3, 0, 2 * M_PI) +cr.clip () + +cr.rectangle (0, 0, 1, 1) +cr.fill () +cr.set_source_rgb (0, 1, 0) +cr.move_to (0, 0) +cr.line_to (1, 1) +cr.move_to (1, 0) +cr.line_to (0, 1) +cr.stroke () diff --git a/demo/snippets/clip_image.py b/demo/snippets/clip_image.py new file mode 100644 index 00000000..39a84abf --- /dev/null +++ b/demo/snippets/clip_image.py @@ -0,0 +1,13 @@ +snippet_normalize (cr, width, height) + +cr.arc (0.5, 0.5, 0.3, 0, 2*M_PI) +cr.clip () + +image = cairo.ImageSurface.create_from_png ("data/romedalen.png") +w = image.get_width() +h = image.get_height() + +cr.scale (1.0/w, 1.0/h) + +cr.set_source_surface (image, 0, 0) +cr.paint () diff --git a/demo/snippets/curve_rectangle.py b/demo/snippets/curve_rectangle.py new file mode 100644 index 00000000..eace586b --- /dev/null +++ b/demo/snippets/curve_rectangle.py @@ -0,0 +1,53 @@ +#/* a custom shape, that could be wrapped in a function */ +x0 = 0.1 #/*< parameters like cairo_rectangle */ +y0 = 0.1 +rect_width = 0.8 +rect_height = 0.8 +radius = 0.4 #/*< and an approximate curvature radius */ + +snippet_normalize (cr, width, height) + +x1=x0+rect_width +y1=y0+rect_height +#if (!rect_width || !rect_height) +# return +if rect_width/2 +

    DemoName

    + +Say something nice here + + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/throbImages.py b/demo/throbImages.py new file mode 100644 index 00000000..213577ff --- /dev/null +++ b/demo/throbImages.py @@ -0,0 +1,1277 @@ +#---------------------------------------------------------------------- +# This file was generated by encode_bitmaps.py +# +from wx.lib.embeddedimage import PyEmbeddedImage + +catalog = {} +index = [] + +_001 = PyEmbeddedImage( + "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") +index.append('001') +catalog['001'] = _001 + +#---------------------------------------------------------------------- +_002 = PyEmbeddedImage( + "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") +index.append('002') +catalog['002'] = _002 + +#---------------------------------------------------------------------- +_003 = PyEmbeddedImage( + "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") +index.append('003') +catalog['003'] = _003 + +#---------------------------------------------------------------------- +_004 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAIAAAC1JZyVAAAAA3NCSVQICAjb4U/gAAAHNUlE" + "QVRIib1XyY7bVha94yMl1RS7bNjVLiCuJAgCGA4CZ5nOL/cP9Kr33iUIMgCBkdjpqpKoicMj" + "33B7Qaqqgs62+wEiIYHk4bn3nPOuAP4vCwHg9Zu/O1eoOhZhYiRGRDMDsOkqGw82fTE8/Ip/" + "9bzpbIAAZmb/+uc/BACcK8py7opyRKIRBgzMLEPOIQw+hi4OfQg+hSGllDMAsWrhyvl8caqu" + "AABEPGCgASCCZcuWAEAAQNW5oizLmRaliGOi8WVi6MPQ5NjMHOp8gXhsACnFYQjD0Pfed127" + "WVar69+Pz84fnT9fHJ+OKIgAgAholnPOEwyLqDotSudKVcfMADh0G4bu6KSczR+VrhRlAMjJ" + "htDv980w9N77tmvnTb2v95vVh9Xth2cXV5cff46ECAiIiGCWUzywYWIWEXGqTtUBQB72ixme" + "nb04PTlZLI7K2YwIc0pDGIZ+eP/Hjfe9K1p1ZeEKUSfM2+3m5x/e1vvNZ198NZsfASICghnS" + "AQaJiZiJmBkAINanJ8WT8xdPnz49P39ycnoszH3ft23ru6Zt/WrTAgoiATIiARIiAWDK+bd3" + "P3rfvX7zzXx+jIhmmRIdYBBHbADMw/70pLi4+Nvl5eXV1cuL5xdmebfbb7brlGKMQV0mZlHJ" + "uTCzu9uJkIgQsbp9/9P3b7/8+tsRe1SlwCg6MDAYus1ihk/OX1xeXr569eqTq5cpheub265r" + "urbtfR9CiDGYAZGIGiISCzOzMDEzi6gWrri9fvfrL9+9/PQVmFk+FA3AwCyGnqE7O3vx9OnT" + "q6uXn1y9NLPlslqv1+v1pq733vsYIgIyMyEyUxJhEWZmVmJRceoKp06Ebz68e3z+7Oj4zO6U" + "BgCWIQzN0Ul5enJyfv7k4vlFSmG5rJbLZVVV+/2u7/ucMxISEBEBEeU8lmokwiIqqk6FCRDM" + "bpY37+eL05ztHibnkGMzmz86Ojo6OT02y9c3t+v1uqqq3W7b9/1ousl7SAAGxIyESMRCLCIq" + "IqIqzIiYU95u197XquUBxiAMfuawdGVRzoR5t9t3XbNeb0Yef7I2AiIaIIKNnTcDZkrMxGMN" + "CRFTin3vm/325CN3zyaGTucLUSbCvu8323XXtnW9v8d4mG5wsDkYIgEAADODiAgTEyJYjEPX" + "tX3fWH58UBpYHHrEYwDIKbVtm1Lsfe+9zznjxONBNI65iPdiHjmaMbMQEYKlGI+OGr+ssj2Q" + "QAjeAHKyEAbfNTGGEEIMEQnvA/dhHuPhgzQuREKELBkRAHKKw3w+I7LRW5OgUxhSikPo+35o" + "W68uxxgQkIAAAf8r7+GQkUSEhEREIgQIAISEYDn2ZTlTFbiHMUwpxRCHYfC+63yZcjIzEUGY" + "4uGOCiI8OlsAICEhIgsTsYiIChMDYAhDU++qPIx72FjuO0FDP/RD79uuK4sy5ywiRETEgGBT" + "J6bj47OjsR9EONlFVVVFFMC87ysy39SiwvSQDRgQ9963Xdc1TeucgRVFwcxm2Q6ERikf2j46" + "k+9DRp2IAEAIiYiAEMBIJD+AQdWibZumafd17ZxDBCIaCSHSGNx/gTHZf2QkIpotI2EGy9lS" + "TIBTtaaTK+ebZdXUu3o+c06JSURVlaf9YRTSWKgResoYVafOOXXqnLCEGC3nFGMMQwjBgB4q" + "DeaL09X179vdzhWlijCziowwLHIIfGIepTXGMouIOle4oigLVTWDlFI/BO99533dtAb8Jzbq" + "iuOz883qg1MdX9OpirqxIplZBIhw6sUoLdEpk8tCVYk4xtD3fdu0TdM2dT2EDEgPJQAA8Oj8" + "+er2w3pdISIzjTmoqioqwjbmGZKIMIuO44OKOjdi5Jy71u/39W6/3e92q2o9xHuHyZ3RFsen" + "zy6ufv7hbc6ZiFRVnTu0VkWjmoz9lzH1J7OIGcQYutZvttuqqqpqXa1XTRcM6G6okgfOg8uP" + "P6/3m9/e/YiIcoAR0TF3mYVZJOs0HAJkyyHGlFLf9/t9XVXVcrlcLW+vb6ohZMRx43nAZqJE" + "+NkXX3nfVbfvi6Jw6pgIiQAhm1k2yzaunHIIiQhzzv0Q2qbd7bdVtV4tb9//cd36BEgwGeBh" + "0aaBB2fzo9dvvvnp+7e31+/GQSebpZSHEIZhWPSD97OiKESEiDNYitF3vmnb/W5XrVfXN9WI" + "cUDA+7DBaRsZAwzn8+Mvv/7211++u/nw7ubm36MHvO/aplss6lk506JQFiDM2WIYOu+bul5V" + "66YLo7oQ4DBVPZCAHajcjYuI9PLTV4/Pny1v3m82a+993dTHxyeLxbws56qOhQEsxRRCqJt2" + "CHmIYECIdBcUU70e9GYsejbLYGaWARDMjo7P5otT7+tmv+37xt9Wq9VKVVQdk5AIoBiQAcP0" + "4njYh+7/GNyngJllSznnFBNSokSGYDlZzjmbannykbP8OFs2s+k+szydR92NMTFl+bTXjtfm" + "u533f7/+A7mYNW7IcoqBAAAAAElFTkSuQmCC") +index.append('004') +catalog['004'] = _004 + +#---------------------------------------------------------------------- +_005 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAIAAAC1JZyVAAAAA3NCSVQICAjb4U/gAAAHqUlE" + "QVRIib1XTXMbxxHtr5nFF0GKNGRZlEQzFcd2ypHtsqtyieNTKtf80/yBnFLJybFzsGPLSqTI" + "kkmKJAiC2K+Z2ZnpHBYg6aqcPYXCAluLedOvX79uAPwsCwHg8SefWVsYY1mEiZEYEVUVQNdP" + "af+m6y+Km7v4//ZbXxUQQFX1r3/5swCAtcVgMLLFoEeiHgYUVDWDaoxdm6KPnY/Bx9Sl2KWk" + "QMJibDEejqbGFgCAiBsMVABE0KxZEwAIABhjbTEYDIamGIhYJuoPk2NIXZNjOx6zyBQRQSHl" + "3HVdCN61rq7L8vJkcX40me7d2bs33truURABABFQNeec1zAsYow1xcDagTGWmQEwdSVCmGxP" + "RqO7RVEYYxAx5xxjDCF43zaNq6tytVpdrZaXi9cX58dv3j98ePAuEiIgICKCak5xEw0Ts4iI" + "NcYaYxEBc729JTs7j6bb08l4MhoNmRkAYowxBue8a9uqrstytbpajS7H1hYX8/nz7/9ZrZbv" + "vP/xcDQBRAQEVaQNDBITMRMxMyIItLt3xrPZ7O5stvfGG9s724WxWVMIwTnnXNs0TdM0o9Fw" + "OBwOB8NiUFhrmDmmdPTyqWubx59+NhptIaJqpkQbGMQeGwAx17t3xvv7+w8ePDg4OLj/1j1j" + "TfChaZu6rohQc845r0WHSITMLMyIVDchZ11cnHz/r3989OnniASAvSoFetGBgkLqyu0tmc1m" + "Dx48eO+99w4PHxJJVZU5p5RiCKELXUpJsyKiMUZVmVhEjDVHp6vJdJdYbFEszn/877+/Pnzn" + "N6CqeUMagIJqjgEh7Ow8ms1mjx49Oni0b4xdrUrnnPNutVpVVe29izEqgIggoYhEE8XI6bwC" + "KsaTbWOMtVZYzk9f7t29P5ls67XSAEAzpK6ZbE+2plt7e7t3786IZXW1atrWOXe5uCzLMoQQ" + "U0REZgYiBs4pM0vr4/miHY7GfVwiQkQApxdnP45G05z1FozGHNvhcDYejceTCWherVYhBO/c" + "5eXlqiy996qZkBSU+qoAIKSU9cnz86IoWJhZRIywMBNoury8cq42ptjAKMSuHY/Z2mIwKAip" + "aV1MKQS/ulpVdeW9B9WNSBCJAEBzRsTvnp3GmMRYYiEWFmFmZgRNwbumXG7dmd1Ek6Jn3hJh" + "AAjBV1VprfHO100dQlDNPUYfRG8pSHR0tlwsS2ICQAblLMxCREyAEINr2tDc5EZBY+cRp6qQ" + "UmpdWzQ2ePbBhxBiTIS3MHDtpKvKPXn2GhERqK98ZWVmIiICxDTZmrbzRdZbEojBg0LOMfjg" + "W9cYQ0Q5pS7G3kY3jN249jdPj3JKCIiERIxEiKhZCYlQCVIcjZkWqjcS0Ji6mFIIXeh861tp" + "WERUVVWJCdbnvcH47tnrqmkJEJGICAmFGImAgagPrYvFoLAGbmAUU+x6321b5xonzMYYRGJm" + "VFhbxE1TwcurBtfu0SMxMRMzIhEnREW10VhjTQYAAFpLIGkI3jnXNm3d1G3beudj1/UJBICe" + "4mub/+1Hh/v39vpgkIhp7QbGiOkvYsUIEcNt0oDEta5tXdPWw7oQZlBQUBbmzIC4yf86Bsv0" + "4a8f3n/zztdPTwCAmcWIsCGiTAkggSFEJDJ6qzyRxTRN1dR1VVXWFsQMCEQUJfbiQSC4pol6" + "pnj/rd3Z3s5X3/7ofCcsYoSQUgLIrISaUwbuKVgrzRbj1eK4rMrBcGCMYSYmEhEWEZaelV5S" + "RER90piYeDg1f/z88fNXi2c/nIsRBETMmDDklFKngLeVBsPRdHF+VJZXRVGICBMxkRgxxhgR" + "EQEFBKS+LxH3xtJnY1AUH39w+Iu39//+5bMUg2ZIkHIKVdWkTD+JxthiMt1bLk5ETE8SMxtj" + "jBgjRowRVSRk6hstC4sY0/txURSDohiPx3/6w0d/++LJyUmlyXvXND72w80NDADc2bt3cX58" + "ubjs+WdiWW9jjTF9dwFEJhIxRsTYzTKGmVU1pfSrg91QX7y4qOfzhff5eqCSa5WOt7bfvH/4" + "7MlXKSdEFBFj+k2MNbb/2CMR0ZoyEWFBpJSz92F5dXV6duqaq7Ypy9onxeuhSgBuZriHB+9W" + "q+XRy6eEuOGjsMYaY4hZmIWNCGs2oKqqOeeu67rYhdCVZXk+n58cnxwfn7w6Omtc2gwd8BPS" + "ABAJ33n/Y+fa+fy4GAystdzXNhEggkJWzZpVIaVsYmRiBei6rq6b5XJ5dnZ2evr6+YujZek3" + "pXY7GuhLAhBwOJo8/uR3T7/98vzsVT+wIWDPexc674Nzfjgc9idAwJhS27ZVVS6XV/P5/NXR" + "2bL0eoOAep2bje1if4TRaOvDT37/4j/fnJ/+oPo659TF6L1vXVvX9XA1HAwGRiwxqmoIXQ/z" + "+nR+VbrGpc3QSYh0TVTfb3AzKF5XOr39yw92Z28tzo/mF0vXtnVVleV0PJ4Mh0NrCxEGwJRi" + "13Wrsq7bzvmcFK/dqLcK2Jj62tM0q2ruJ3PVDICgOplsj0ZT5+q2uqp9U59eMF0U1hhriJjI" + "ZOCsmDIpIPSvdXe9+WNw4wKqmjXlnFNMSIkSKYLmpDnnrMYUvPOG5pw1qyqoJoCkqkn738Lm" + "zIig2mtlfU9VISv8bOt/F1Z0xNATclgAAAAASUVORK5CYII=") +index.append('005') +catalog['005'] = _005 + +#---------------------------------------------------------------------- +_006 = PyEmbeddedImage( + "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" + "RAR+OL38BvZvmV1aiXteypoAAAAASUVORK5CYII=") +index.append('006') +catalog['006'] = _006 + +#---------------------------------------------------------------------- +_007 = PyEmbeddedImage( + "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" + "RK5CYII=") +index.append('007') +catalog['007'] = _007 + +#---------------------------------------------------------------------- +_008 = PyEmbeddedImage( + "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") +index.append('008') +catalog['008'] = _008 + +#---------------------------------------------------------------------- +_009 = PyEmbeddedImage( + "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" + "SUVORK5CYII=") +index.append('009') +catalog['009'] = _009 + +#---------------------------------------------------------------------- +_010 = PyEmbeddedImage( + "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") +index.append('010') +catalog['010'] = _010 + +#---------------------------------------------------------------------- +_011 = PyEmbeddedImage( + "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") +index.append('011') +catalog['011'] = _011 + +#---------------------------------------------------------------------- +_012 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAIAAAC1JZyVAAAAA3NCSVQICAjb4U/gAAAHEUlE" + "QVRIib2XyXIbRxKGM2vr6sZKUCYlSnIoRrJoxciMcOgwF+uZ5wXmNA9gXzyOsDhaaEkgADaF" + "Ru9LVeUcCt2EHHN2HoAA0Kgv88+lqgD+EkMAuHj1WqlASsWF4Iwj44hIRAC0f4r8C+0/EPbf" + "4v9bb/9OgABERP/+1z8FACgVaB2pQHsS8xggICIHQMbaxpnGmsaYxhljTGcsETDGlVSRHk2k" + "DAAAEXsGEgAikCNHFgAEAEipVKC1DmWghVCcMe+Mcx3YClwXSMl4wJARgDGm67qmaeqqKsuy" + "SK+T22U0WRwtTqPJzFMQAQARkMg55/YYLoSUSgZaKS2l4pwDINqCMzsZTbU+ZVwCMOtc23Zt" + "07Zd27aNDqswqiaTSZruttvVl3h58uDJo2/PkSECAiIiEDlr+mg441wIIZSUSkrFGEqspjM1" + "nZ7ocMRlYBxWjSnLxpq6hap1zBASQybZo28W222klIrj+N3vv+S75NmLH8NoDIgICETIegwy" + "zhjnjHHOGUMtmpPjydHRcTSeCRl1judla5u8sVR1bdli20LXoW3xaDY/PZ1KKTnniGitXX66" + "rOrq4tVPUTRBRCLHLOsxiJ4NgBKrk8Xk5OTBdH6sR0cooqIyRZsYV3cWjAHrmHXMWjQOH52d" + "zucB6w0RGWObzfXlbz9fvHqNyADQV6UAX3RAQIC2mM7U0eJ4MjueLc70aGFI7MpNVjRlVdV1" + "0xnjnCUiQATGz589draTUkoplVJCiCAItNar1ccPb3998vQlEJHrRQMgIHKu48xOpyfReBaO" + "j/RoocLp+vP19fXq9jbOs6yuq65rnbWIyLh4fHpvcTRr21YppZQKgkAppbVWSnHOb9cfF/ce" + "jMczGioNAMgB2GoymupwJGSEIjIk1p+vP7y/urnZZFla15XpOkdEgICMc/b9s4dhGMregiDw" + "MXHOAYBouY2XUTR1ju4wQAZcp/Upl0HneFGZXbm5vl7d3GzSdFdVpbUWAIh8UyAAff/szC8q" + "hDgMiDFGRNba1TpumkKIoMcQWNsEUjIujMW8bIs2yYrm9jbOsrSqSufcPnsAgAyBFouj+XQE" + "AJxzInLO+YCGkmvbtiiKqtiNpvfuonGmkTKMwhAY36V5Z+uyqnw+rLVE/QTrp8nF+SPG2EHH" + "o4/GU5umKcsyTdNdXt/lhoCsaTjnoVbnT+/PF9/cJs1/3ny6udmYruuH5sGURPjubye+DYZq" + "BgDnHOfcOVdVVZZl8/k8LdaODkrAmMY/Z4wRjB7fHz88ef6Pi7O3f9xcfti8v1odUo4X8/kk" + "GjA+PT4sxpi1djqdTiaT8Xgs+YborgTIGWOMadu2rus8z6MostZyBi+e3v/7d2edcf+9unnz" + "fvXuagUEP5w/9EL5ODzGk6SUzrnRaBSGYRiGWitzhyE0pvNzt6qqqqp8z3LOvRo6kC+fn718" + "ftY03eXVzbcPF9gb59xj/MjxemittdZBECipOgsHolnyjKIowjC01vqWFkJ4Mfc8rX44f3gY" + "B+d8mAKcc2utHwdCCM45Mg7mQDQCVpZlURRZlmmticgzPGAop8EGrQ77Rghhra3rehhxyMRh" + "bpBx5Rm73S4IAiLyQgshhkIaAF4rzxhC8ZimaRDROWe9OebV2osmVZSl10mSjEYjpRQAeLm9" + "4r7phtrlvfmW9HNMKeWfsdb6amqaxlg4jAb0aJLcLpMkCcPQR+B99AH5R/8E8H74VIdh6BPT" + "dV1d12VZlmW5TTKf/4NoZBBNFtvtymfyEKOUcs55T0Vvg1BKKe8ZEXVd55s/TdM8z/Oyc4T+" + "WNSPToCjxemXeBnHsV/RDw8/Df2iPj1/Yni3PCPLsiRJttttkiSfl5u8NMPiewwiRpPZyYMn" + "737/xVrrl/OAoDd/RjnsFd+SXqssy+I43mw2cRzHcfxlVxo3zDyP6QfJo2/P812y/HTJGDvM" + "7ZASL+ZQSE3TMMa8VkmSbDab1Wq1Xq/fXa3SvOsPHfCVaACIDJ+9+LGqq83metgHfQX7aW+t" + "9X2ulKrr2odS13WaptvtNo7j9Xr95u3H26QCRED8Ohrw5ypAwDAaX7z66fK3n1erj/0+SN7x" + "qqqm0+loNNJa+2r0SJ/2JEniOH53tbpNKkcDAWnIzb4aAL0LUTS5ePX6w9tfb9cfiZZ+jyrL" + "MsuyyWQShuGAGX7K8/zzcvNlV6Z5129BDJF9VQLUhzIcFxHZk6cvF/cebOPlah0XRZGm6Xw+" + "H4/HYRge7pJN02yTLC+7vDTG+SX2K+z1OsgNkSMiR+SA/PkcgWg8nkXRtGmKqtjt8jot1pJv" + "tFZKKmQcmbCOGQudBbe/I+wPe4cXg7spQESOrHPOGovMMssIgZwl55wjIYLR9B4558gRkSHq" + "LIAh/3//6n1G9GeS/r5CQETg+tvLX2D/A1kVdrbjRxLPAAAAAElFTkSuQmCC") +index.append('012') +catalog['012'] = _012 + +#---------------------------------------------------------------------- +_013 = PyEmbeddedImage( + "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" + "IMOTlboAAAAASUVORK5CYII=") +index.append('013') +catalog['013'] = _013 + +#---------------------------------------------------------------------- +_014 = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAIAAAC1JZyVAAAAA3NCSVQICAjb4U/gAAAG6UlE" + "QVRIib1XXY/bVg4leb8k2eNxJplxUrSDYNoiKBAEKNKnRfKb9w/s0/6A9qUo0AYJEkw7sV05" + "lmV9Wvde7gNtj9Pu6y4fZNiWeC55yEMK4P9iCAAvXr621hljldaKFJJCRGYG4P1dLBfef2E8" + "/Ir/zd/+kwEBmJn//a9/agCw1iVJZl0iSCQwwMDMEYB9CH30ffC993303vvBB2YgUtbYLBmd" + "GeMAABEPGMgAiMCRIwcA0ABgjLUuSZLUuERrq4jkMDEOEFpkn1irVKqUAgDvfdN2fd93bds0" + "TVV+LFZ32dnFg4tZdnYuKIgAgAjIHGOMexiltTHWuMTaxBirlAJADLVRcTKejkajJEmstYgY" + "Y9ztdu9vF7tdn6RtmrVJmlXbclPMP+V3V0+efnn9DAkREBARgTkGf4hGkVJaa22NscZYIjTY" + "nk/dw4dfTKfTyWSSZZnWOsbove+67rcPG8/IhGQoHSlSWmldrNfvfv2p2hTffPd9mo0BEQGB" + "GekAg6SIlCJSShFhovvHjyaPHz+ezWZXV1fT6dQYIwBt21ZV1exgGDDsMATioIESl8TJOYcQ" + "7n5/03bti5evsuwMEZkjBTrAIAo2ABpsn1yef/XVV9fX1zc3N7PZjIiGYajruizLEEKWZSFS" + "COgjDgHZE0cF6FwCDy4QCVf5xze//Pji5WtEAkCpSg1SdMDAgKE+n7rZbHZ9ff38+fPLy0sA" + "iDEOB4sxhhCYGRCBlFLWM0YGRiCFSUaX1iQu+fPP2/dvf3769XNg5nhIGgADc4yDUfHhwy9m" + "s9nNzc3l5aV0Twhhs9mUZdk0Tdd1IQREJKU1UiQFSIgqeAVRERnnnLNOa71a3F48ejIen/Ox" + "0gCAI0BoJ+PpdDq9urqazWYSZQghz/P1et00zW63Q0SlFCApRYQxIiESkSaiEDTwoCw7Z5Ui" + "gOU6v8uySYx8DwPskf1oNJpMJtPplIgkP3mer1arqqpijETEzESESAAMpAgRkIgCkaIwcDRM" + "wVjnrEbgfLXu+1prd4BhCKFPrE2SJMsyY4wwsdls1ut1VVXMfGg5JCJEZEAERlSIzERICkkx" + "e4SAClJrFUHXtW29GU0e3UcTfa9Uaq3VWnvv67oehkH4iDEeMY7KJd8ZGBEJkBQrpWPUzB4V" + "KwNjA9O22TbdPTcMHHyvlJI+77quLMthGIQPIjoREGQWSQSQXgcEJAJgAmQFrEEFpTE1ajKZ" + "VG0e+aQEvO+ldr33bduGEARP/H6GcVRHaTQkFLYQFANzUKTIkEvMaDw2+Uoe2Rd09N57v9vt" + "uq6rqirLshBCCEEpRUQS0D3GvewjEu0JIwUAwFpR1Bqt5ZAkSWL9PQyj98MwDH3ft23btq04" + "FYy/e/7HD88A9rWgtBZB1FojEnD0fhd2dd8UeeyssUM4qAAA+MCCUdd1mqYhBK21c05rLck8" + "ZejVD99KiEopY4w9mFIqhFDX9Xw+//AhlkWOpMCfJI2Bmqap63q73SZJwsyCIQBHbo4mGFpr" + "uQqM1jqE0HWdHAIRkfQpN0jKCsZms3HOCe3GGK31kZsjgGiBYBhjjgFprfu+l3IVakPc53yf" + "NGOzbfmxKIrRaGStBQCttbhQSkmt08HUwYwxzjkZejL3iCiEINXU970PcBoNJKOzYnVXFEWa" + "phKBnFECklv/AiDnSJLEOZemqRAzDEPXdU3TNE2zLrbC/0k0xmVnF+v1XJg8hbHWihAQkT7Y" + "KfNyMmaWji7LsizLqqqqZogsnXyUToAHF7NP+V2e5+LRWuucc84dwYSev2DIsQRju90WRbFe" + "r4ui+ONuWTX+6FwfuyE7O7968vTdrz/JRJH6keyLyY4i/KtDsyCi5Gq73eZ5vlwu8zzP8/zT" + "pvHxXgi1KIfYl9fPqk1x9/sbIjrl9kiJJPNYSH3fywhvmqYoiuVyOZ/PF4vFuw/zshoOSwd8" + "ljTRp2+++77t2uXyo2CIa1Ez8S66Z60VxZNGKctyvV7neb5YLH57e7sqWkAExM+jAdmrAAHT" + "bPzi5as3v/w4n9/K/iczVDRiMpnI2ibVKJBCe1EUeZ6/+zBfFW3kIwLykZt9Nex1HbPs7MXL" + "1+/f/rxa3DLfhRB2u13TNNvt9uzsLE3TI8zxr6qq/rhbfto0ZTUcZoYM2ZMS4EMox3URkZ5+" + "/fzi0ZN1fjdf5LI9TafT8XicpqlzThpWolwX26oZqsb7KC72Hvb5OuGGOTJzZI7Asp8jMI/H" + "51k26fu6rTebqivrhVHLJLHWWCSFpEMkH2AIEPfvCPsZdPpicK8CzBw5xBiDD0iBAjECx8Ax" + "xshau9HkEccYOTKzZx4CgGd5/jCEGOQVQJYE2P/GzBD/NqX+d/Yfb+tv8v+Co5YAAAAASUVO" + "RK5CYII=") +index.append('014') +catalog['014'] = _014 + +#---------------------------------------------------------------------- +_015 = PyEmbeddedImage( + "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") +index.append('015') +catalog['015'] = _015 + +#---------------------------------------------------------------------- +_016 = PyEmbeddedImage( + "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" + "RAR+OL38BvZvmV1aiXteypoAAAAASUVORK5CYII=") +index.append('016') +catalog['016'] = _016 + +#---------------------------------------------------------------------- +_017 = PyEmbeddedImage( + "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" + "RK5CYII=") +index.append('017') +catalog['017'] = _017 + +#---------------------------------------------------------------------- +_018 = PyEmbeddedImage( + "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") +index.append('018') +catalog['018'] = _018 + +#---------------------------------------------------------------------- +_019 = PyEmbeddedImage( + "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" + "SUVORK5CYII=") +index.append('019') +catalog['019'] = _019 + +#---------------------------------------------------------------------- +_020 = PyEmbeddedImage( + "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") +index.append('020') +catalog['020'] = _020 + +#---------------------------------------------------------------------- +_021 = PyEmbeddedImage( + "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") +index.append('021') +catalog['021'] = _021 + +#---------------------------------------------------------------------- +_022 = PyEmbeddedImage( + "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") +index.append('022') +catalog['022'] = _022 + +#---------------------------------------------------------------------- +_023 = PyEmbeddedImage( + "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" + "IMOTlboAAAAASUVORK5CYII=") +index.append('023') +catalog['023'] = _023 + +#---------------------------------------------------------------------- +_024 = PyEmbeddedImage( + "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" + "RK5CYII=") +index.append('024') +catalog['024'] = _024 + +#---------------------------------------------------------------------- +_025 = PyEmbeddedImage( + "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") +index.append('025') +catalog['025'] = _025 + +#---------------------------------------------------------------------- +_026 = PyEmbeddedImage( + "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" + "AAAASUVORK5CYII=") +index.append('026') +catalog['026'] = _026 + +#---------------------------------------------------------------------- +_027 = PyEmbeddedImage( + "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") +index.append('027') +catalog['027'] = _027 + +#---------------------------------------------------------------------- +_028 = PyEmbeddedImage( + "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" + "g8KYtwAAAABJRU5ErkJggg==") +index.append('028') +catalog['028'] = _028 + +#---------------------------------------------------------------------- +_029 = PyEmbeddedImage( + "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" + "/d+vfwN3mDeHwwQzHwAAAABJRU5ErkJggg==") +index.append('029') +catalog['029'] = _029 + +#---------------------------------------------------------------------- +_030 = PyEmbeddedImage( + "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") +index.append('030') +catalog['030'] = _030 + +#---------------------------------------------------------------------- +logo = PyEmbeddedImage( + "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAABHNCSVQICAgIfAhkiAAAAZRJ" + "REFUWIW1V0FuxCAM9EB/0j6leTV9Sr6SuIcNrAFjAmRHWmlFEDNMBpsAzpMFPg+O/+E8zMkT" + "+OqRMyd+AsBPi2gKKMmJiJiZAGSDq4JUAZntQCKXQsTzJVdcScznwRTEGHMiBECaK1LwKJID" + "JTEFnTAKieSrMEMYRZR4gjgCcL7evYWtygBReI3PZMH1pxS4XIm/JDzQVBYQC9GQCy1MuDDu" + "gIUJF5IAOA/aiGgzZlvPJpGdAjiP/Tz4u0W0+ooUQDaj/Tz4x3iHmb2WGJGFXjNLDvTIywV4" + "uxY2hFRVdTuqsj0dQjiPlBtjTpYrJaSO6L37fTDBr46pPBBEPaHoXUjukuNPmVRmIdTjz9YB" + "Ay0XhgXEll1az7/K5FZhEuO3BWh3hVFoLtjtWJB/oggR3XDgk+RdASPk6imQ68wIUDHTkEI7" + "Q+a1vNq9OL/A+yRYu5ciNCzXAZO85Va2kUYlbL5/Ude7uIjKDMiGdOsYZhi4vKZdGl3W7AXD" + "R1BYfvdu2G1Gyb6WkAnSIQGVkHKBxY/Tf6WKCaeNieprAAAAAElFTkSuQmCC") +index.append('logo') +catalog['logo'] = logo + +#---------------------------------------------------------------------- +rest = PyEmbeddedImage( + "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") +index.append('rest') +catalog['rest'] = rest + diff --git a/demo/version.py b/demo/version.py new file mode 100644 index 00000000..120436de --- /dev/null +++ b/demo/version.py @@ -0,0 +1,3 @@ +# This file was generated by setup.py... + +VERSION_STRING = '2.9.5.0' diff --git a/demo/viewer.py b/demo/viewer.py new file mode 100644 index 00000000..a0332d98 --- /dev/null +++ b/demo/viewer.py @@ -0,0 +1,100 @@ +#!/usr/bin/env python + +""" + Run wxPython in a second thread. + + Overview: + Importing this module creates a second thread and starts + wxPython in that thread. Its single method, + add_cone(), sends an event to the second thread + telling it to create a VTK viewer window with a cone in + it. + + This module is meant to be imported into the standard + Python interpreter. It also works with Pythonwin. + It doesn't seem to work with IDLE (on NT anyways). + It should also work in a wxPython application. + + Applications already running a wxPython app do not + need to start a second thread. In these cases, + viewer creates the cone windows in the current + thread. You can test this by running shell.py + that comes with wxPython, importing viewer and + calling add_cone. + + Usage: + [user]$ python + Python 1.5.2 (#1, Sep 17 1999, 20:15:36) ... + Copyright 1991-1995 Stichting Mathematisch Centrum, Amsterdam + >>> import viewer + >>> viewer.add_cone() # pop up a cone window + >>> a = 1 + 1 + >>> viewer.add_cone() # create another cone window + + Why would anyone do this?: + When using wxPython, the call to app.Mainloop() takes over + the thread from which it is called. This presents a + problem for applications that want to use the standard + Python command line user interface, while occasionally + creating a GUI window for viewing an image, plot, etc. + One solution is to manage the GUI in a second thread. + + wxPython does not behave well if windows are created in + a thread other than the one where wxPython was originally + imported. ( I assume importing wxPython initializes some + info in the thread). The current solution is to make the + original import of wxPython in the second thread and then + create all windows in that second thread. + + Methods in the main thread can create a new window by issuing + events to a "catcher" window in the second thread. This + catcher window has event handlers that actually create the + new window. +""" + +class viewer_thread: + def start(self): + """ start the GUI thread + """ + import time + import thread + thread.start_new_thread(self.run, ()) + + def run(self): + """ + Note that viewer_basices is first imported ***here***. + This is the second thread. viewer_basics imports + wxPython. if we imported it at + the module level instead of in this function, + the import would occur in the main thread and + wxPython wouldn't run correctly in the second thread. + """ + import viewer_basics + + try: + self.app = viewer_basics.SecondThreadApp(0) + self.app.MainLoop() + except TypeError: + self.app = None + + def add_cone(self): + """ + send an event to the catcher window in the + other thread and tell it to create a cone window. + """ + import viewer_basics + + if self.app: + evt = viewer_basics.AddCone() + viewer_basics.wxPostEvent(self.app.catcher, evt) + else: + viewer_basics.add_cone() + +viewer = viewer_thread() +viewer.start() + +def add_cone(): + viewer.add_cone() + + diff --git a/demo/viewer_basics.py b/demo/viewer_basics.py new file mode 100644 index 00000000..fb857774 --- /dev/null +++ b/demo/viewer_basics.py @@ -0,0 +1,73 @@ +# 11/15/2003 - Jeff Grimmett (grimmtooth@softhome.net) +# +# o Updated for wx namespace +# o No idea what this does. +# + +import wx +import wx.lib.vtk as vtk + +#--------------------------------------------------------------------------- +class VtkFrame(wx.Frame): + """ + Simple example VTK window that contains a cone. + """ + def __init__(self, parent, id, title): + wx.Frame.__init__(self, parent, id, title, size=(450, 300)) + win = vtk.VTKRenderWindow(self, -1) + + renWin = win.GetRenderWindow() + + ren = vtk.vtkRenderer() + renWin.AddRenderer(ren) + cone = vtk.vtkConeSource() + coneMapper = vtk.vtkPolyDataMapper() + coneMapper.SetInput(cone.GetOutput()) + coneActor = vtk.vtkActor() + coneActor.SetMapper(coneMapper) + ren.AddActor(coneActor) + +#--------------------------------------------------------------------------- +# Using new event binder +wx_EVT_ADD_CONE = wx.NewEventType() +EVT_ADD_CONE = wx.PyEventBinder(wx_EVT_ADD_CONE, 1) + +class AddCone(wx.PyEvent): + def __init__(self): + wx.PyEvent.__init__(self) + self.SetEventType(wx_EVT_ADD_CONE) + + +class HiddenCatcher(wx.Frame): + """ + The "catcher" frame in the second thread. + It is invisible. It's only job is to receive + Events from the main thread, and create + the appropriate windows. + """ + def __init__(self): + wx.Frame.__init__(self, None, -1, '') + self.Bind(EVT_ADD_CONE, self.AddCone) + + def AddCone(self,evt): + add_cone() + + +#--------------------------------------------------------------------------- + +class SecondThreadApp(wx.App): + """ + wxApp that lives in the second thread. + """ + def OnInit(self): + catcher = HiddenCatcher() + #self.SetTopWindow(catcher) + self.catcher = catcher + return True + +#--------------------------------------------------------------------------- + +def add_cone(): + frame = VtkFrame(None, -1, "Cone") + frame.Show(True) + diff --git a/demo/widgetTest.py b/demo/widgetTest.py new file mode 100644 index 00000000..73b962f7 --- /dev/null +++ b/demo/widgetTest.py @@ -0,0 +1,72 @@ +# +# This file is used for the wx.HtmlWindow demo. +# + +import sys + +import wx +import wx.html as html + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, id=-1, size=wx.DefaultSize, bgcolor=None): + wx.Panel.__init__(self, parent, id, size=size) + + if bgcolor: + self.SetBackgroundColour(bgcolor) + + wx.StaticText(self, -1, 'Name:', (10, 10)) + wx.StaticText(self, -1, 'Email:', (10, 40)) + + self.name = wx.TextCtrl(self, -1, '', (50, 10), (100, -1)) + self.email = wx.TextCtrl(self, -1, '', (50, 40), (100, -1)) + + wx.Button(self, -1, 'Okay', (50, 70)) + self.Bind(wx.EVT_BUTTON, self.OnButton) + + + def OnButton(self, event): + name = self.name.GetValue() + email = self.email.GetValue() + dlg = wx.MessageDialog( + self, 'You entered:\n %s\n %s' % (name, email), + 'Results', style = wx.OK | wx.ICON_INFORMATION + ) + + dlg.ShowModal() + dlg.Destroy() + + + +#---------------------------------------------------------------------- + +class TestHtmlPanel(wx.Panel): + def __init__(self, parent, id=-1, size=wx.DefaultSize): + + import About + + wx.Panel.__init__(self, parent, id, size=size) + self.html = html.HtmlWindow(self, -1, (5,5), (400, 350)) + py_version = sys.version.split()[0] + self.html.SetPage(About.MyAboutBox.text % + (wx.VERSION_STRING, + ", ".join(wx.PlatformInfo[1:]), + py_version)) + ir = self.html.GetInternalRepresentation() + self.html.SetSize( (ir.GetWidth()+5, ir.GetHeight()+5) ) + self.Fit() + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestHtmlPanel(frame) + return win + +#---------------------------------------------------------------------- + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + diff --git a/demo/wxpdemo.ico b/demo/wxpdemo.ico new file mode 100644 index 00000000..3ed4f08c Binary files /dev/null and b/demo/wxpdemo.ico differ