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 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:
+ +
+ 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. +
+ ++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 = """\ +
+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 = """\ +
+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 = """\ +
+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 = """
+
+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 = """ +
+""" + 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 = """
+
+
+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 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. '))
+else:
+ extra = '\n See the docstring in the wx.lib.wxcairo module for details about installing dependencies.'
+
+
+
+overview = """ '))
+else:
+ extra = '\n See the docstring in the wx.lib.wxcairo module for details about installing dependencies.'
+
+
+overview = """ 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.)
+
+
+
+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 = """ 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 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 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 = """ 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 = """
+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,
+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:
+
+
+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:
+
+ Styles supported:
+
+ Init:
+ Methods:
+ 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:
+
+
+ The EventManager class has three public methods. First get a
+reference to it:
+
+ ...and then invoke any of the following methods. These methods are
+'safe'; duplicate registrations or de-registrations will have no
+effect.
+
+ Registering a listener:
+
+ De-registering by window:
+
+ De-registering by listener:
+
+ Simple Example:
+
+ 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 = """ This module exports four main methods::
+ In addition, the module exports one class::
+ The text can supportsuperscripts and subscripts, text
+in different sizes, colors,
+styles, weights and
+families. It also supports a limited set of symbols,
+currently 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 = """ 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 = """
+You can look at the sources for these samples to learn a lot about how
+the new classes work.
+
+
+
+
+
+
+"""
+
+
+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.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 = """
+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 = """\
+
+ The following image handlers are available.
+
+
+ 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 = """ 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 = """
+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 = """ 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:
+ 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.
+
+ 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.
+
+ 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!
+
+
+ Different methods are provided to retrieve the POV data for a CTS hat
+versus a four-way hat.
+
+ 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 = """
+ This is a control that simulates an LED clock display. It only accepts
+numeric input.
+
+ Styles
+
+ Methods (and best guesses at what they do)
+
+ 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 = """
+ 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.
+
+
+ When anchored on both sides the control will stretch horizontally.
+
+ 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.
+
+ 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 = """ To intercept events from a list control, use the event table macros described in
+ 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:
+ Interesting methods to override are 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 This mix-in class was written by Erik Westra
+
+ 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.
+
+ 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:
+ 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
+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 = """ This class supports the following window %s:\n' \
+ ' Checking for documentation on the wxWidgets website, please stand by... " + 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 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)
+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 = """\
+
+
+
+"""
+
+
+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 = """\
+
+
+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 = """ 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 = """ 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 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 = """ Classes demonstrated here:
+
+
+
+
+
+
+
+ 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 = """\
+
+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 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 = """
+
+
+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.
+
+ This allows you to set up how the plot will be printed. This
+ is built into the library itself.
+
+ 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.
+
+ Surprise! It prints the current plot to your printer! :-)
+
+ 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.
+ Different data with different plot formats, including one empty
+ plot.
+
+ 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.
+
+ Plots can have different styles of grids, and and these grids can
+ be turned on or off as needed.
+
+ Plot can have legends or not, the contents which are definable
+ by you.
+
+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 = """ 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 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:
+ 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. %s 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:
+
+
+
+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 = """ 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 = """\
+ Allows the application to ask for details about the system. This can include settings such as standard colours, fonts, and user interface
+element sizes.
+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 = """ %s
+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 = """
+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 = """
+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 """
+
+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 = """\
+
+ A validator has three major roles:
+
+ 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 = """
+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 = """ 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 = \
+ " 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: 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:" \
+ " " \
+ " " \
+ " " \
+ " " \
+ ""
+
+ 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> To intercept events from a list control, use the event table macros described in
+ 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:
+ Interesting methods to override are 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 This mix-in class was written by Erik Westra
+
+ 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.
+
+ "
+ 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 paragraph done Subsampling is shown there:
+ This is "default" table - with no sizes givev:
+
+click here to go to IMAGEMAPs test page!
+
+
+This is - - default text, now switching to
+ center, now still ctr, now exiting 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.
+ Right now, centered REALLY Big Text,
+how do you like (space) it? Blue italic text is displayed there....
+ And yes, we're in HTML DOCUMENT
+ hello?
+ This is new par?
+ We switched to BOLD
+ This is new paragraph Bold is off now.
+ new par
+ -----------
+ Hello
+ 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
+
+
+The button below is added to the page like this:
+
+
+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!BitmapButton
+
+
+
+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 = """
+
+
+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 = "\nwx.lib.wxcairo
\n%s" % (
+ wx.lib.wxcairo.__doc__.replace('\n\n', '\n
+
+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 = "\nwx.lib.wxcairo
\n%s" % (
+ wx.lib.wxcairo.__doc__.replace('\n\n', '\n
+
+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.
+
+
+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
+
+
+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
+
+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).
+
+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("
+
+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 = """
+
+
+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 = """
+
+
+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 = """
+
+
+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 = """
+
+
+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.
+
+
+
+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.)
+
+
+
+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 = """
+
+
+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 = """
+
+
+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 = '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.
+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
+
+ 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
+
+
+
+"""
+
+
+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.
+
+
+
+
+
+ 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")
+
+
+
+
+
+
+"""
+
+
+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
+
+
+
+
+
+Usage
+
+
+ from wxPython.lib.evtmgr import eventManager
+
+
+
+ eventManager.Register(listener, event, event-source)
+
+
+
+
+ eventManager.DeregisterWindow(event-source)
+
+
+
+
+ eventManager.DeregisterListener(listener)
+
+
+
+ from wxPython.lib.evtmgr import eventManager
+
+ aButton = wxButton(somePanel, -1, 'Click me')
+ eventManager.Register(self.someMethod, EVT_BUTTON, aButton)
+
+
+
+
+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 FancyText -- methods for rendering XML specified text
+
+
+ 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.
+
+
+ class StaticFancyText(self, window, id, text, background, ...)
+
+This class works similar to StaticText except it interprets its text
+as FancyText.
+
+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.
+
+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 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 = """
+
+
+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 = """
+
+
+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.
+
+
+
+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.
+
+
+
+
+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 = """
+
+
+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:
+
+
+
+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 = """
+
+
+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
+
+Internationalization (I18N)
+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.
+
+
+
+
+
+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.
+
+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!)
+
+
+
+Img2PyArtProvider is an ArtProvider class that publishes images from
+modules generated by img2py.
+
+
+
+An info bar is a transient window shown at top or bottom of its parent
+window to display non-critical information 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/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 = """
+
+ 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")
+
+
+
+
+ min
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+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.
+
+
+
+
+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
+
+
+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.
+
+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.
+
+
+
+
+
+
+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)
+
+
+
+
+
+
+
+LayoutAnchors
+ A class that implements Delphi's Anchors with wxLayoutConstraints.
+
+ ctrl.SetConstraints(LayoutAnchors(ctrl, left=0, top=0, right=1, bottom=1))
+
+ +=========+ +===================+
+ | +-----+ | | |
+ | | * | -> | |
+ | +--*--+ | | +-----+ |
+ +---------+ | | * |
+ | +--*--+ |
+ +-------------------+
+ * = anchored edge
+
+
+ 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.
+
+
+
+wxListEvent.
+
+Mix-ins
+This example demonstrates how to use mixins. The following mixins are available.
+
+ColumnSorterMixin
+
+ColumnSorterMixin(numColumns)
+
+
+
+
+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.
+
+ list.SetItemData.
+
+ 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.
+GetColumnSorter,
+GetSecondarySortValues, and GetSortImages.
+
+Methods
+
+
+
+SetColumnCount(newNumColumns)
+EVT_LIST_COL_CLICK events.
+
+SortListItems(col=-1, ascending=1)
+GetColumnWidths()
+GetSortImages()
+GetColumnSorter()
+GetSecondarySortValues(col, key1, key2)
+ListCtrlAutoWidthMixin
+
+ListCtrlAutoWidthMixin()
+
+EVT_SIZE event in your ListCtrl,
+make sure you call event.Skip() to ensure that the mixin's _OnResize method is
+called.
+
+Methods
+
+
+
+
+
+resizeLastColumn(minWidth)
+ListCtrlSelectionManagerMix
+
+ListCtrlSelectionManagerMix()
+
+Methods
+
+
+
getPopupMenu()
+setPopupMenu(menu)
+afterPopupMenu()
+getSelection()
+listmix.ListCtrlAutoWidthMixin.__init__(self, startcol, endcol)
+(Look at the general ListCtrl demo for more information about the
+ListCtrlAutoWidthMixin)
+
+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
+
+
+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' \
+ '
'.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 += "
"
+
+ 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 += "wxPython
+
+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
+""" + 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 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.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.
+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 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 = """
+
+
+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
+msg
+title
+lst
+pos
+size
+style
+Methods
+
+
+
+
+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 = """\
+
+GetValue
+GetValueString
+wx.Notebook
+Object Graphics Library
+
+The Object Graphics Library is a library supporting the creation and
+manipulation of simple and complex graphic images on a canvas.
+
+
+
+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.
+
+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 = """
+
+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 = """
+
+
+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
+
+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.
+
+
+""" + 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.
+
+
+
+
+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.
+
+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 PyPlot
+
+
+
+
+
+
+
+
+%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 = """\
+
+
+
+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.
+
+
+
+
+
+
+
+
+
+"""
+
+
+
+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 = """
+
+
+
+"""
+
+
+
+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 = """
+
+
+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.
+
+
+
+would now 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 ...
+
+
+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.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 ...
+wx.Window.SetSizerProps Quick Reference
+
+wx.Window.SetSizerProps(<props>)
+
+
+
+"""
+
+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 = """
+
+
+
+Parameter Values Summary
+
+
+
+expand True/False
+Whether 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.
+Sound
+This class represents a short wave file, in Windows WAV format, that can
+be stored in memory and played.
+
+
+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 = """
+
+
+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 = """
+
+
+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 = """
+
+
+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.
+
+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.
+
+
+""" + 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 = """
+
+
+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
+
+
+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
+
+
+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 = """
+
+
+
+
"""
+ if n % 2 == 0:
+ return "This is item# %d" % n
+ else:
+ return "This is item# %d
+
+col 1
+ Lorem ipsum dolor
+ sit amet, consectetuer adipiscing elit.
+ foobar
+
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 = """
+
+
+
+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.
+
+
+
+
+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.
+
+""" + \
+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'''
+
+
+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'''
+
+
+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 = """
+
+
+An info bar is a transient window shown at top or bottom of its parent
+window to display non-critical information to the user.
+
+Welcome to AUI
" \
+ "
Overview
" \
+ "" \
+ "
" \
+ "" \
+ "
" \
+ "
" \
+ "
" \
+ "
" \
+ "
" \
+ "" \
+ "
" \
+ "wxListEvent.
+
+Mix-ins
+This example demonstrates how to use mixins. The following mixins are available.
+
+ColumnSorterMixin
+
+ColumnSorterMixin(numColumns)
+
+
+
+
+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.
+
+ list.SetItemData.
+
+ 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.
+GetColumnSorter,
+GetSecondarySortValues, and GetSortImages.
+
+Methods
+
+
+
+SetColumnCount(newNumColumns)
+EVT_LIST_COL_CLICK events.
+
+SortListItems(col=-1, ascending=1)
+GetColumnWidths()
+GetSortImages()
+GetColumnSorter()
+GetSecondarySortValues(col, key1, key2)
+ListCtrlAutoWidthMixin
+
+ListCtrlAutoWidthMixin()
+
+EVT_SIZE event in your ListCtrl,
+make sure you call event.Skip() to ensure that the mixin's _OnResize method is
+called.
+
+Methods
+
+
+
+
+
+resizeLastColumn(minWidth)
+ListCtrlSelectionManagerMix
+
+ListCtrlSelectionManagerMix()
+
+Methods
+
+
+
getPopupMenu()
+setPopupMenu(menu)
+afterPopupMenu()
+getSelection()
+
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", "
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. 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
\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 = "\n" + newLine
+ widgetsFound += 1
+ elif line.strip().endswith(";"):
+ newLine = "%s
%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 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(
+ "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"
+ "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(
+ "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAAA3NCSVQICAjb4U/gAAAI7klE"
+ "QVRogdWaS2wb1xWGv8vh8KGhKJGSKMmWVNlxLEFy3LpyYqBG0biB06CwA2dTBPA+0xSFN0F3"
+ "DooAySroMjFoBOgmAbJrEAdF0AB1snAWhR8Bksiu4xqy5cqiJdOmRIm0hjO3i6GoITkcDmnK"
+ "Qf8VRc499//POfcx50iA5P8ZwU4ZkjOipefFpc44TlQi4M2gfr5WGfu33NpwnwLKuOj4fPBx"
+ "5q3j0a6MsgC/7MVrW3/Ks+UPnVPShgx/AmzHO9k7YSuplmFKDInp4KNd8c1JtCCjmQBv6k5s"
+ "BmTtACbkTbImaxam5BfXAL4WL9sPKAQ0gknCMVQFoSBUAgqBLTsHwXc0PAVcbOb1zV9NrCLm"
+ "Csaw/NBjsjfFAUAlkCA8SixJOIyiEewjEkeNoJRlbGpwoVunqrGARuzrqCvyAw/SjXBKTMdQ"
+ "IygJwuN0j6IN0lWWIT/wXldOGQ0EePtevPY41J14RYxrBIfoGkXbTbwiQ5N/9amh3YNMnlXa"
+ "HFmFv8k54LgYW2R9njVbxhixn4IhUX1sjQJka+7fNhwXYz2EhugaJ/ZH+fXCfgZULw12EAIN"
+ "f3/iOCdv36Pwbx5eYhmYLbJkYDTbiuoE/Ejut/EP+d91SousAxfXm2iwE8f3Gqhmb5oYBpZF"
+ "IICqonRiQdg2z60t/FYbBmYL5e+n8MolfwKq2RsGDx6wtESxiKYxOEhPD4HHS0bLYmWFTIa1"
+ "Nd777i6QKYEPDT4EONgLkbY/fPWVPjvLygojI8zMEI0SibRJvWLz2jX98mXu3CEe5/591k3u"
+ "0VxDMwFu7IHZWS5dolikVOLpp7GsqkF2MphmrTFF8cq3ycn0O+/oV6+WfZH+F384xFKJ2QIC"
+ "FEFQ0B8kUK3BU0DjVXvvHsvLSEmhgGEgN9eZaVIssrLC/fusrVVpUBQ0jb4+4nEiEXcZhQKr"
+ "q+Tz3LvH6ip/z3B8iKUS14poAZIKWgCtemCbB5mrg50hcuL0aR1QVRIJxscZG2N4mEQCVXV5"
+ "2A6mbV9KLMkGLJeY2+AnG6RUooGqIDQW0MqmGYu5U7fx9ttp4MQJXdO4dYvxcaanmZhgYMBd"
+ "gxPnVznSzSOLRYObjxgNEa8OQgfeiQ8f9mJfwSefpI8e1XO5cnYBwSD9/b6mMCFnMm8wv8Fg"
+ "dRAabH6+3W971ye++CJdKLC4yLVrfP89d+9SKDQfdX4VS24FIWNQsMB5lehUgaCCEyf0kyd1"
+ "159UFcNgeZm5OW7fZmXFr01nEFYsrE3KbhFoJfvtBVrBmTP6W2/pBw5w6BCffqpfuVIr4/PP"
+ "06rKxgaLi9y8SSbja5ZKEDIGtzbIltjYFNCBNXDhgr5/P+Fw+XjO54GtHdMwdFWtSrPeXrJZ"
+ "cjnm55mfb2EiE/IW2RJ5i8rBU47A4xZnBKpKXx9PPcW+fezbx549pFJoGsEgUlbF4eOP04rC"
+ "o0dkMty61cIslqQkKUoeWZRcIyAu2SdSmxUrRfF7q7MF5PNks61NYcpyuSBvAhbOK9hmEDpT"
+ "b+s4zq8ClCQPTO5ssPPb72CDH+uFxjRRFGIxkskWB24uA8iDxZMRUHPFePVVvVQiGCSRYGSk"
+ "NVOWxJT8+e5pMO1yxLYLqL8gPXyIZREKkUgwMPC49rdXgOv1zjBQVZJJhoZIJFq2eS533Pln"
+ "x/oDNWh0M33hBV1VGRhgYoLJSb93IRtf5p+v/3JbBDRi/+KLeihEfz+Tk8zMMDHRTgRq0HkB"
+ "jdi/9JLe28uOHeza1cJ1uik6LMCVfSVt9u5l3z527fJ6oWmGACiggmIfWZ0U4M1+aoqZGSYn"
+ "SSYbvlL6gAIxSELM3oFqBQghpWx+GEejxGLlD6qKaDDi2DFdCPr6ykk/NdUkbTzMCvE82IQT"
+ "MAIJCLkI8Inx8a0P8Xj5RiKl7gzCu+/qd+4QDjM66jfpXc1WozYCW02+CrwjYFk8fMjCQvke"
+ "lkyyYwe9vVuTCZFeX9cXFvjhBzIZ4nHGxhgZIZn0Ym+aZLMsLJDLlQ/poaGqetmRbr7M/xri"
+ "cAB+A89AF20cZEIQjRKPo2loGvE40WhVrDc29JUVcjlMk1iMvj5SqeZL1i4lSYmmMTzMzp10"
+ "d9dG4Gj3P2vcj2sKeSwDO0MyGX1ujuvXAfbuJRIhHEaIqkX8/vv64iKBALt3k0rVVr5cbd64"
+ "wfXrSMmePYTDRKNbzxzpJiAIB3hj8MO/ZH4HSXsBuAvwngkYHEyfOaN/8w1AqUR/vx2Hqi3o"
+ "8mWWl8trcXKyoYB6m3YusVmzqARBgR6FURUYhXglAm4plBZNG53ZLNksS0vlElo9v+VlVlcp"
+ "FCiVvNzvxOuvp+1lcOMGN27w4AGGAQ73D6nsDrOw/wBsRadBBNJNdtJkkp4eikWCQfe6tJ0A"
+ "/f2kUi7Z3Ag9PUiJotTuyxX324Utp9/rBGxSr18Jzl1yagooV6fr97uPPtLn5iiVSKWYmqK/"
+ "n1DInbHTpl3xzmZJJtm7t7zua9xvV7WcaLwG3IJgv57b/YG+vnJ/IJUiFCr/ZFnkcmQy7NmD"
+ "lMRiDAyQSHhFoMZmoUA0ujUqIAgJ+oOMhxgLEQ/UVqfrzoFq3rJBt8mjQ+OsrXvX05vafCFO"
+ "SDAQZDrKcxrTkXJ53VlDabILibPuGjwKEP5rE94DK+ynosx0MREmUdccwM9BJra9tecCJ/uD"
+ "XUxFGraYfO0OT1iDN/uaGpzfq8QT0+Df9zZauAs9AQ1CHO0KMKQy7Y89rV7mtlWDEMcg9Vnu"
+ "jZkuntPc2dfXcFu/jZ7tvIzjvQhxEibgWfjVL2NM+/C9jTZfaMRZsJC/b2/0Fl5JoAWYiPBZ"
+ "7lnYDaMw+LOr+dLPY4q/Im2Tg6w52pVxKkVMISJIBBkP8fJ/rsAgxCECiut/kLn2AFzeyFrW"
+ "AFhgQBH5J6+n3hwGUAWJIKMhkgrhAFqAZ2YXKtQrD9drcBXQoapEAMKgIt4DC07lIA9ZWIOq"
+ "fvKFicOKKHetd36bA8VRJvFCoxZMhyJQD70ERg17B3yRdgahFQE8tga9k21POSM8OmDbUJ3u"
+ "KHua9e8aCGibRKfZN8X/AG65ainoKqzxAAAAAElFTkSuQmCC")
+
+#----------------------------------------------------------------------
+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(
+ "iVBORw0KGgoAAAANSUhEUgAAAHQAAAEECAIAAAB2rYcFAAAAA3NCSVQICAjb4U/gAAAdrklE"
+ "QVR4nO1dXZAdxXU+92pk7UpahARXUoiFVi4sx7sCY/BSdkxZwnG5EolKuWyjSuE4glfBg6pC"
+ "4eRBllQkfjB+4CHoIQ8ByrErDiZAsGQbDFoMcRkJjPjZNRjH7GKIFl1Wsu5qfyR2Z/LQ9/bt"
+ "6T7nTHdPz9y7wqdUq7kz/XPmzJnvfN19ZqaSJAkAAEDr/6a8/z4sXdrekH8tZX4eogjm57NL"
+ "xgmxf8GtysICLFkCC3QtUSZDmRiqVYhjB33iBKoVRKV4AaoAkCQpywoLqqYUG3I/L9Kgwr6M"
+ "xAmuk/hXXWJbZWGhaTXGdrxZhTUpy1L6SGU0leRlqEqzSlNqZhXWlH8p51WdVJoV9VyhE2VW"
+ "eQ6ap5hVVIMuwa6EZnHh2qk2DZtqllVVkvqgBtV0FhuVOE4AAwFgTakKb8pU3ywCVJcgt14e"
+ "BODLSJtq3iqsiYIAhwBYlar6w8mymqvylrVBACdXtUEAxlUpb0XNpLoqhQCoW1TiODGDFW9Z"
+ "zVWZwFWmq4ICEWhJylVBMY2mEuWqgFnTrFI5d65d1cZbuxMBhDBmBSCDFaqPKwKgVargHqzy"
+ "IIB6SkwVVwRAf6rxCsA5WFkiAFMl5bmmdCcC8Lc/2NFVSwTwiG9SQ9K4oUYBTmbNFN70DKoy"
+ "+jD6u5pVU6+qHUbpKt43S1f9EIChq2rJkumqqjxVUVNSSNtzuxYBZBm0cAl0lanCn0Ll3Lkk"
+ "JwJQKMZUKQEB7AkAVZ7RP1M9AEiSFizkQQB0wIpW8RiwIsrEqQ0KATRltA2tPLAIgCpJqScm"
+ "asSkQmV6mmML3TZgBZauIlXKQgAwphWbs2KUWl04YAXaVTVNgPC+UMFKiuqqslmhko4Flq6K"
+ "3nSaQsJMmTbViqnlNWDV4pUQoZLKAaoVXCvGrFSVTLNq7avXOOW5qKsCwWOYKrxC5iGUAABN"
+ "rSig52dX+WDF3HCoaDPg2mVr/k2gWgRdzYkA3UZXpTAIYOpTrWCYi6KYrEmZlVJIHjKLMQig"
+ "KgOsWcEwUMp9iMEYesMxnmHpqlpfVbWCBwI4za14IEDKKZRz8JhdZVzVEgEyXVVjGlVTmyLo"
+ "qjcC2NNVU3kgroGqJLgggNad6artvyL+q8CqFbUJVqZmKh/0RgDtlAIiQGZs8EMAtDyGuYt5"
+ "faW0YKUigOYWsnyb5+ahq+vWVsjDrJyYSNDBXnC6ypxFJl3VrNm2aUKGKCFVsEYAU2zmX3hB"
+ "EaAIupoHAUybymLCJ1IXQ9o9gchUyERMUwhf2E9WQCRVmBrRA5DegZ4wq15TUFc1ESDTpmBc"
+ "cpwtgLWr2hRzkm6gq/Inw6sy9TEvczVTIak0um1ovy9J9pGHDekSuirNiqvH6qNtNH+K0B2E"
+ "roaS7qSrZkUgzCpsKg1SpTRzoqs5pcvpqlnGvNjapJ0QZPlBjQba9LDKUqnBFS37zV0bPpzN"
+ "4d4cS9kgeLBS6ao52m43RVA95vRTXifAVzUo46oB0cBSbBBAigcCMGsTlKtSRliIAaTnSuRV"
+ "+YDaEBCuimrDSILhJiWVllv7TVqbdLVdJiHLq2XwJSLaqxZiWFJtWnYhhoihAaqreo/B8gvF"
+ "AYLT1XZTGALwd6owK7R8VggejPgV1o5LQXQVWASgZCFuu6omKePy2esAkBD/HMW3XsF0FUUA"
+ "HlVNg6YUk62oG1T6aqeks3RVE2nQBcxK8mInCURAuypu02a+Aw7BlcoBXKMcoiFA8GDlBKza"
+ "htaRqlWlAlVm0hpdRuuUoN5HjQI8RiV5EWAJLMzrMbbpuWbp1PnYwuN+y3Ku4soBgECAIBxA"
+ "1UciQLyQupmFldtraDG23mNt1gKlzAGrENVVUWDVtJJmlbFBNB4BNjhhpkpRQYuIHt8cS8So"
+ "b1N/LqZMAWsJdFV2BNB2VS3otIOtynMpBAjls5mTgTZCIYC2oZb3oKvahtq4RJuFeQDQEUC6"
+ "qtY+soZmzq52Q2SzRICcA9ZULYyZqAiQ2XgEtJMywSGfuOEDigBmmeKClQ0CpFpo7dfX0LRz"
+ "CGVWp/kaUzpLV6WIs2Aa1w6lh780inmLNg/gIR2nqxoHwJVkJssdpt2IsRkvslmv2ohKUCJd"
+ "Zdrn+62Co2t4SJCQ2EG6irbP9dsiSJElignxdrt4AV5/PbFcX9Hruq+vhKWrlp2CsQSVomKZ"
+ "2esewsyt2KyvaBsQCAEW5qFSCYkA6FpJZXw8QYC1Vc75+RX66S+zC8qsOemqXou9LWzoKtcv"
+ "a6IqigDBEwLVLlynrPxmV0XjarBCz0K2b0pGv6yJxBBRX1r3WwqUPylUhbT1S6CrABkI4Oeq"
+ "YGFWKamkkG5LB0LFkq4miT4P4E1Xm/1mmSg2kkUjvlqmq4JFsALCrIuFrvJpKMzkQeS0cA0a"
+ "YgZaX/nGnTtwJbLkn751iBmwBgxWrmYFwJ6g7Kp0oEyhJkA65araz7ZxgyBAPrr6NVxrXL6H"
+ "7u2gWc3Tj6AUBEjtLyDFpCMIIM9Xe/5YVolUDtDBdCAhhw7dDAA7dnw/u2hLusFV1dNXq6Rm"
+ "xXK6qlrMg656iOBVlISiq6n9ilmpEZAUZFZMDzhpszIjKxQBnOiq68xvOXQVWifOAKA5sgdI"
+ "z4rh8cp9ysp7hZUVJIId2J/N4fZ+81Cz3yIRQC0vL0BzDc0GWDVVwg5YC5USEAAwtEzxXO9g"
+ "BXwszpqyspdDhxwK79gBQCOAPV3la1G2SuTEjYkAYQes//gPnmOwIsSVrlJVUAhWw0ZUBAIw"
+ "yQCdFT+6ylShzCokoopCAcGKuqcdvVo2Y1svbLBiRttShB2q1IAVdVXvdKAOCmUme14FtKua"
+ "iQOqHfSAVlw6UFNESNqBO92NNzqMzTzEFQGYYGWKede2UkjDra9IVaj1lY5ITLwwC1quio4C"
+ "wPBrylVR92rnioVaX2HSgbIEn+jKKfnpKli7aruRGEAuUKp7i0gH6rhYDlhRBEDjFY6EcfOv"
+ "eMg0UvdSkn99hReURQhU3vvNQ2IU8K1/DsCU7V0VaA6Au1f6qV3xN+pU7qqlBH9lRmqnHV0F"
+ "xr3o1/gmMfEEZXHJAOULjwCqOAUreXaqqzbbiSERnqt1UFw6UB5JW8cfH0IFK/S5/SSGSrVp"
+ "ViGtvIWCEwK9BaX0zo04Bitto9mIEqxMs2obIuJVwY4GmJIzHahkyUNXKQQQplT/atUjxqaU"
+ "5EoHIsZmluJRO1ZSRT3pKuaqlWpzg2nEePNzi3KjzwSpXeJnUgTg5iYMlQppVm2j2SP9xmnN"
+ "rPz8X3uBUogwq4hX7RZzr7AK8XBaqdid32iz4SBTVvZ0FdLBSjUrUHAq2QI1Cig0d9VPOkJX"
+ "bRBAbUpK5fkXEC2CJAPkXF/JrGXvqkDP2aMGbbZj7OQn/s1G9EGEJQegxCYlGNnv+CJv19lV"
+ "3sVQXqVadiGNA2Y7lE0iqRnaE6qNKQWlAzFVSkMAdYOiaIieAnO7OR1ILe8RrFCzAjFg1TZc"
+ "EQDdz03cdDwdCMINWIGmqxoCiGuD0glXW5GvvuqGdKCAA1ZgXdUcnplNeYxCI60oI+WnA6kS"
+ "BAFc6SrQNuFt1TxrWdTGVb05QHErrKkWHOdW0EZkUx58SXMgdrI8UPY6X8t1hVXbaDbCBiv7"
+ "ASvkcFXTjfAvzIXNXqequAYr1RZHf3kXrkSWXH3NXieb8oeAuOEAINYe8ltEdDWg+JmVYodq"
+ "7kf7Fa+Ljq4CAMBWXDNcntb1CYcAZkZdHGc95Lco6Kqr5HdV06ygnLhshHzILwgCuAYrmwGr"
+ "dv57934OAO666+f4aZin4Ai4QLNDzazZEzfoRAmkeRUYl66gdCB+fSWI8PNQ6Fmk7n12kivj"
+ "2zyy3S5BAMmr1Jb93psTFgHQxsn3inWQrtqsr9iJHsEA4OXj2RxuYHCvKwK0SyqH9FwxMBBA"
+ "6yMUAlA6oQhgrrCWJlr+p9MkgwILi2F21WwkExP27s0ooMpdilur3upHMPQFSnBEAFXCzq6+"
+ "8LznGCyIyHjlYdY2FaNWrgoNVpbpQDbiHdAY4YHV3tzI3EI5dFUVZn2FuqelV9tZVjZjdTe4"
+ "mpXar3+xuny6yqQDdY/4TD/GLBUrga5aJQOIkHQX7nT2YzMPyQO4YL7itWS6mjm72inJD7ig"
+ "UbGCstfBNx3IQpBhQn5xnX/g1tC6ga7anEOnxNuLESoWcH1F28hctrIXlEUIVB4Y3AsAcQKv"
+ "jeZiyjkBF4B+O5MQewRotxMuGcBbciajBwFcQN/OJKQb0oH8JHNuxadNLy+OTLraPelAfoI1"
+ "4o8Peby4DQtdmA7UQckPuNB8Uab7+komXbVEgG6zqZAgVCyOWw+cdGc6UFOIsRlXXWncvTbX"
+ "WuYh1SP1XLES6Cp3iH3NlqUEvBucPMP0yIg6IKWD6UCQJxIBXLF5L99vKMqFxqTWxA3tqkEG"
+ "rJYIkNNh7fv1vKtYBFBjktyoHP5JolqWmrFmqFVYBNBeBRPKEGGroO6IswXVsgA6tWIkIAKg"
+ "6UAB+y0aAVCJoCy6GioZwOlQcFelEABtpPU0jzGyCkhXvdOB8vQb1qzyqBnwmUaiQgesORGg"
+ "g4BLsVKnRloppGFPb/EjABhO6tEv/koAv7Zg8QcrcxI1T7/GKwFC01VLatVBwHVFAPvGI+qA"
+ "bXN27y4tAT0n6/eQDbHSt2qPR7CyOaR/DtyyLVg8CGAvgVVNiEelFnOw+jRZFJFfhuu3tV9Z"
+ "fHDB3EVCV13Fyb14V9XE6nWDiwsB9uz5NADcc88vM8qF65fKrmOfWu92BMiuYi85EaC9U/uU"
+ "AV9Ca658BCgaGYK4KmBkFH/1FfiatYMDVilsxi6CFbPT2RxuWe+eZr/WqeCAfpsnVbN0uupR"
+ "RY6sihOntxfI8Ug7V2wxIoDYqY2sMtOh9+zJKKDKPZhbk/d3egCN5IoVhwA5Hf/Mac8xWChh"
+ "EACdl0Detg++CFAaaHRE8PubXi+PZWZ5TmAtuoqKqtQ9Lb3a7hEU2YzV3YDc3/R6udxOf5un"
+ "++gqervxEvzhHk1QoAdA/DfqTlcF3qwiJKGxJsfYjJeYWEajVI1jj4mbUhDA9IJugGANAVQl"
+ "UVsHmCwvCAHUc3CRotxW+4neVToVo+pn7g9YBUWxbnBVUygEQF3Y53WDoUCDQjE/s6IsQqDy"
+ "0p7mwffn/JkypR7Fw4B69VVHEMDvmvmJ6xPDjGeA4cVSbF832CkECGVWjajmoWsM4GqSMVke"
+ "1lXtESCsq2IDVh98oAAXKZlAtUJjbrchQMfjG48A7Z3Km0WwVwJ0iK4WbdY87WQiQIx9BDFX"
+ "3kIQuuoDuMTYjBGhlXiJmnttTh9z0UuW9MxbsDGrXyN8FT/JxCLLFvSdib6hlQww/HVFAE+a"
+ "3DqBPHO6SWUP+rZClKtS+qAIgBa2Hf4WTVfJfvM9xau2bzNg5fVhEACV7LyFQumqjatKWbJ0"
+ "D78QQKmaYFfd3qxmhka28gJzO0VXnVyVWgoE1kaZCGBJV02tLM/XloqVQFf9VlipSWswbIfa"
+ "lFLJFQHQQxnD33Loqv3LtoC4zECbj3JtfI8jAvAMhKRiJdBVDwQAen3F7KjQYMWbVRBqBHNL"
+ "oKv2b4aU+phAz6jqigCmVn5m1T6nlRqhlUlX23uskwG8EYBxVRu6yu8Xgr70vf3sL3oOrt0E"
+ "QQDXYMXvR5UJhQD89wmi8oMVZCEAGJcZ6Etub1ZvuooK/30CAEjidEArx1Xt04HkfobGAHEN"
+ "NGXy0FVNeLOqT/lyEzd+hy48uiok8wsl5qP+zpPlRdNVsf3FL4yQ3bBy+CeD4I4AoVw1VSsO"
+ "krcQlK7y55kpwRFA21CFMSsALKnmzFvIgQA2FApgLdk3IidNrYLQVVNQs8oHfZdUYX4B5hd8"
+ "P5NY9IA1v5SMAADNd1MkCSzEzdVlx7yFsuiqlIGBWqUCIyN1XCFrzflDkBsBhKtWKqlPUlvn"
+ "LYSjq04cIEg+aHEIIH+iX0/P+ExiTL/InKKr2ob6035oEERi9uubma6axPiLlORbqrTXYKpf"
+ "dIypiZumZt1EVwk5ae766x3ZHO6Rxwad6KoQHgGkZDzkF5CuahtqFXTQVY542FT9iSIAaqKM"
+ "r0oFpKt+3CAzY25wkDuqyQjm1jauCoDbFFgTuX3KANzpKmXTv/yi1Ris0AccLOmqq1nl+FD/"
+ "qpTq2KZZ1Q30p2WwKg0BULEMVgIBhGXNYEU9GaluZH/KALIQAAxjMfs1oe5px5kF2YznjIRH"
+ "sFKFmsogP2UA4RDA/Nkl4oQA2kbzJzuVgX9VymPA6rEQ0DyHgcFKhYg14DA2cxWVBqgcwHRV"
+ "3EQWk5mpwaa0GpXkb9Zn9iNQiy0FFv1MnikCW01Rv+bEuKr2t7kfO9/slxPzdBXdrwkFSRaC"
+ "DBOKEJ6uNg+5T2aSLycOQlddFSpZLOmq99q7vkDJB6XiVlg1QVmEQOWHHmke/MqXPLkBuHOA"
+ "1H7rycz2GhrPqyw5gMcKa/ki6aoTAti4qtYFkreg1inNVZ0k/xerqYm9nNk32jwZkp/rSlcD"
+ "pgPZCGZZN3zgX+WT2m+NAOb3jRLzdYM8DwurUMclSJqIOasrN5AFSj8OUJyropLnm4oMNfRG"
+ "AEibVQiXQmqpU16zEmMzSjSzOtYGgEIQAN2PwALSQTHpQJ2SIMEKMFfVDmXkLRSdDuTPVAF+"
+ "8MNBm3mAgoIVeqg90lOpGKNQ0elAfuI9YA0VrEh91ClHHRbKSgd66JFBy2UrVYoesJq9aHuo"
+ "Q8icSYKtoXVJOhCwy1baRvNn5xAgfaz5P72GVgACuKYDQdDZ1VT50AgA0Lap3G98DtyXVxWR"
+ "DtTu2nF9pXwEkPqokvdTBoWmA0EWAkCO2GBPV20QAPVi/08ZBEEAftV6ESGAeQiZW8jU1SN7"
+ "vVmxXAQoOlhRh/C5BUZRIXlcVf1pnw7UPBQaAXxcFZq2411V27D6lEFOBPBOByqfroIvAqCN"
+ "c5nlfggQMB1Ik25BANpV8clyTUqjq902YAVwcFWmfX3iRsgf6Sp/iEIAtN/Wl/wCPb9yQdJV"
+ "sHBVtN8IIBevusAGrOahhPBZm34j5rlgVD6AdNW7Xx1zFxFdBQtvCkJXPW4RPaAFGbDC4qer"
+ "YHHNLC9z84vVpqDByhsBUvu7BAHcgxXTL1olQrPX4QKgq1AqAqCapzA3Z7CCTiBACXQVPcRU"
+ "gZZ7pb5YnZOuXkgI4Af0kHav1BerPzh01a9fBgF099LYAl6nCwasHaerNgjQ1kGxSYTWWSx0"
+ "FTlUpKtqKqXcC9MnAjtXhdwIsIjoqnko01VRVSPNW2HRDVjdgxXTrwMCWKjKPuTXDcGqpWuX"
+ "BCsbsyp5CwQHMOt/YOkqWCAAuh/5BuUf6Spo7uWuqrBMVTumuWpMvMbk7Nn62bOpB0eTJKVc"
+ "kuj/zJKx9oKXpPkvNt/90jrDycnRo88dUNs8+tyBU5OjVL+ohpSq8vRTdNVRVdViVaRFIG0q"
+ "D/3Xgzcefe5uTTP+HOQexnb6/tYh2cu7E8feeXtYNd87bw/PzNa1fh//6U7ZwMgrBzMvM5ju"
+ "lXWZTVVNoxnvW6DeJKR48fEXD545MzZx4hhqO/HvvTriTZTtEF2TlFllI43GGKqeZrvrr79X"
+ "7nz2mdsYL461v2mXtFGVub+dP2UwM1P/n2cOfPLa3b94dr9UVG5Mvjf6wvN3T0wcm5mu77r1"
+ "1Z7e2rsTx9783eGLVvX3b9re01sDgKnG+K9H7l/Z17/pI9uX9dQA4LXRBxqNsSs237RmzcBU"
+ "Y/zXo/dfedXuV14+WKsN9W/aniQwM1t/bfSB+fnpc3P1teuGtH5nZ04ef/E7ALB5867e5TUA"
+ "+N3/PjiwZfdvXn+g0RgDgBeeP9DX17/5Y7t++IMtX9n56isvfWfdZVsB4O23Dm/efEvP8o3V"
+ "KszN1n/z+gNxPL3pI7f0XbTx+AsHLq0Nzc3V5+bqV3x0V09PzT4UyYnGqo2rypNJEjj+4kEA"
+ "uPqTuz+8Ydvv33paQ4CHH9qxbv3Q13e9+omrd587P3Pkydsf/+mtAHD8xYOP/+RWAJg6M/4f"
+ "37vu/PvTb/9++MiTtwHA00/d/uKv7j5/fvqnh3c2zow3GmO/Hrn/+9/dcv789FM/u7XRGJ+Z"
+ "rT/60A1/OD0yPz/92zceXLp0herOAPDsz2+fnT156tTIY4/eMDtTl94qrqWQnp5aksDp0yNP"
+ "PrHznXeGn/jxjUee2Hni/4affeY2Ydkf/+iGiRPDjTNjTz2xAwBOnBj+2eM7Jk4MT5wYfv7o"
+ "nZb3t/YCEqtPGUgfmZwc/cWz+y+5dPC/H9n59u+HJyaOXfanW9UptPn5mZeOH5yZrl919W4A"
+ "eOn4vX/7dyMnTx6bnTl5zbV3QAJHnrrtyk/svu7T+0T5qcb4b9948Oavv9rbW3v2GfjtGw+u"
+ "Wz80NTX2uW33brly97sTx6YaY43G2Lr1Q9s+fx8ARNEKVR8hWz9/3+WXbweA4SO3jo8f3vyx"
+ "XWL/hg3bN2zY/qvn919z7T5QUPWLf/Wjf/vXys1fP/mH06NHntwZx/Dy8bsvuXTo+q33TZx4"
+ "empqDBKo1YZqtaFrhr49N1d/7OEtcdZLPBOMjOrvWzBdVT2TV1+5v6+vf3DLLZ//i3u/9OVD"
+ "b40Pq7NoSQJ/87WjAwO3jL15+NGHb5ycHO3tXfvjwzvfe2/kqzuHr/joTXECY28euvKq3a06"
+ "0GiMrblkQLhVFK04f346iaG3d+3glt0SExuNsZV9/eRpAURR05dXruyfmhpDlZeWveEL/ymg"
+ "s6entnb91tnZkwBQrx+7YvMtKq+KohXiQvb01EQZxlUTw2hCqkAjQKqVBJIERl554DOf3X/t"
+ "p+645NKB1WsG3504ZgarT37qjp03P/fuxNHentr789Nf/uqRP7/+2yv6Nj595Papxnhv79rZ"
+ "2boIDo3GeF9ff+PM2PRMPUngrfHD69YNAcDFqwfUrleu7H9r/LAMaGCELyFzs/U3Xr//8su3"
+ "m3Q1NQRIIE5g9erB06ebIXf67PjSpSvOTo0BwLJltfPn6u2KMbxXP9aHXVrzFUTatYzNFFLT"
+ "pnJj8r3RKFo+uKV5061atXHVqv5Tk6MXr2naYqox/h/fu27NJQONM2NXfPSmi9cMfPzjt/z7"
+ "A1vEnuUr1kbR8q03/MvDP7xhzSUDpyZHr/zE7ms/ta9/046HfnAdANTWDV2+cfs77zytqfGx"
+ "P9s1OnLw+9/dFEUrps6OrV+/TdPtR49u+5PLtp2dGttw+Y5La0MAsHr1oM490ub+0LLa7Gx9"
+ "1cWwbv22qamxq67ed/ix6974zf3nz9Xn5upTjfFqBV5/7eCJE8ONM6Of+ex9cuIFCASQjauj"
+ "sMod30hMm2pmRQ+hw5XZ2fqpydFlvbU1isUbjbGLLurv69so6ooyfRf19/VtFE2dPjUKAKvX"
+ "DIgCp0+Nrl4zkCQwdXa8b+VG0c6pU6Ozs/XLLts6NTW+srUTAM6eHU9imDo71reyf/nKjfoI"
+ "M4G5ufqHljUj29xcvaenBgBvv3X40tpQT09tamp8xcqN4tCZP4yuunhg/v2Z5Ss2vvrSgdnZ"
+ "+sb+m1as7BcFpE2T1hI4Y1ZxOSt/f6duJDUQo+bu8gErpw99SLuDXz5+AACuunofGK4KaVOY"
+ "NpX7I7OCg1ktzkFr1s92FFgBe3qWquL8X9CSLAQADdDT+1OT5dQ5eExZ2bsq02+mqzrNrjqN"
+ "Aj4+cIdrv/qst5gs90CAkmdXNZWcZlfNQ650NbNffda7tRHZemspCODgqoxKXq7q1y+zP5b5"
+ "ueUEK/NQOQhg76pmv+0Nd3NH3YYAlneipar5EUA2zugDhllFv/rjqVpb1CHtLi4HAUIFK49+"
+ "zWBFVYnJiZtwCJCfrpaJAB7BSlOVns91D1Zg2Kg76WqzUj66qu43VWWWbCL+jis7WLX6LRsB"
+ "KBcGxKzyUOa6rYG5RbqquqdMumrZL4UAWhX7VRsFcwlrFjRgBcM1upaugrWrahItIroKOcza"
+ "3nA3t9+bKOKYmFv4YNFV4xDkMGuKiqlzCxf2gDVssLI5FPE2Wlx0leoXrL04p6tqQk7cLEa6"
+ "mn/Aioq3F2dPlv+RrtofQqhYHgRYRHRV3RkcAfDhb8JOll9gdJXv15tyUftTmNv9dNUPAXLS"
+ "Ve8q+mR5QAQoIlgVPWC1UdW+SgYVU3WF7kCALglW/CFxFv8P3yIaZaXHbBEAAAAASUVORK5C"
+ "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(
+ "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAIAAAD8GO2jAAAAA3NCSVQICAjb4U/gAAAFeklE"
+ "QVRIib1WQWgUSRR9mmyGEBlTsGZFbBzq0tvMjhpqLg4mg1Cw5CBeNmEZd4mL0DkFkSzEk2BY"
+ "hDmIaC5ah5DA2ohz2UMgsBQs4zBmUeuSSGIjFC6jDHtYCkICGSS6hz9pNeawh7j/0HR3Vf/3"
+ "//vv/2rgM9s+AE/fPf1M3vP78vs/fWuU2UOMXQD2FmMngFFGSrmHGLtkwJ0DkEr17AnGRwBJ"
+ "+ABarQ3sRR6dO56T8AcGTtVqi48ePYRqL/m+f6B44L84HRtToRAiFDsBrLUKCIUA0Gg0BgZO"
+ "AaBruVw2xiCCEGJXvI9yNSZVGNw9AyklnCOntdri6Oh5Ap6cnGw0GnEcG2O2nRhEANqQCbcj"
+ "IyPj45d3oWi9uu6c01r7vu8xxjnnnLd549xa63me53mJow9Na00BTU/fhBCt1kYohEkAmGUj"
+ "5bLT2jlnAGnt0NBQ4p0yqNUWKS2tdYKR7JFSaq2VMUKIQmFw9Juv6R5AB4Du7m7e3d1sNoeH"
+ "h3l3dxDkzp07a60tl8vkbmlpaXGxLoTQWltrjTF9fX39/f1JBIwxxphbWalvbqbX116/6zh5"
+ "8TgAdU3tB0DMAAiCXBiGAObm7jUajSDIBUFOKRXHsXauVls0xmitgyDned6VK1estdbaJJsg"
+ "yDmttXMkcbL9AAqFQSmlECKTOVqrLdLCxMTE6uryo0cPU6keY4wAWq0NxlhCOsUEQCk1N3fP"
+ "WjswcIpJ+TQMPyxPJ4DV1WXnHICXL1/Ro3aOvnTOKaU451JKY4wBwjCkDVLKRqPx8uUrpdSD"
+ "Bw+Sesw9e04dQNYBgNg/cuTI48d//tb4y25uhkIwxjjXzvHhYSq/s9ae5nx+fp4x1gQqt2/P"
+ "zs5Wq38wKQ+/6zh58jgAMz+/vr6Wldl2clSDyclJAO0AhaB7rbUxAoDWbb1evToF4MaNGwBg"
+ "DIAwBOfcVirT0zfz+Xy1Wv1UwfsAzM7+ShIkcq21QZBLdkxNXSWdtCU4ej6fzxOl9J5kWqlU"
+ "pJQGgDF3n96l1faBk/Rto9EgLQFotTaoyCRBCEFVnZu7h+1pIaUMw5CENzw8rLV+z/2HRQZQ"
+ "LpeJKM/zCIbMbPeLMcZae+HCDwCEEOQOQCrVA2BoaAjbck+U9p6iMAzJOwDyvrCwQN8QJFFH"
+ "okp2kmvKVRnzYHISwMjIiHNuZmaG5mB+X74TQKlUItdRFBljIASM4ZyH24qmbnLOMcaSOUGh"
+ "xHGMbWlwzsfHL09NXY2iKCyG7ykiWuI4LpVKBhgvDE4Dyhgo5fs+raZSPZS71jr8uJUWFhaC"
+ "IJf0wQ6KOgBcunRpaWmls7Ortzf9bS7X25v+fXbWraycPn36yZMnZa3/WV7u6/uyVCplMhml"
+ "lLVWSknFv3PnjlIqnT7QbDaFEOn0gUql0mw2N+1mVmbVNdUBIJvNXr/+y+jojwCiKOrq6hJC"
+ "1Ov1+fl5a203598VBi9e/CmTyQghUqme+y9iW69ba589e37/RSyz2UJh8MyZonOOc55K9Wxt"
+ "vanX62fDs+qa6iSFzMzMAJiYmKDjQ0rp+34URVpryVgmc9RaSySMjp6fnr6pARLreGGQVJ5Q"
+ "RI8GWK+ut2sghIjjWBkDQDLm+z6AYrEYRRGASqVCQzsIcnRQf1iD1dXlVmsjDMNqtVosFpPh"
+ "CmPi5Dy4devW69d//1z6/vDho4cOfdXbm6ZZn06nT5wQS190oNm01j7eesM2N7e23pBGOzu7"
+ "trbeMMZ833/79m1/f3+1Wl1bWzt48OCxYx5jzBhjjNk5KnYYzUuKFEAQ5GjWp1I9rdYGtQLd"
+ "ZDJH4zi21mrnqCe01mNjY5/8tnCeHJCc8+SkTHqK/mgIm3owMc/zarXFAEgOlf/D/gW/qPIS"
+ "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:>,.<<<<
+
+
+
+
+
+
+
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
+////////////////////////////////////////////////////////////////////////////
+// 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)
+Top right
+
+
+Bottom left
+
+Bottom right
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+a
+
+b
+
+
+
+c
+
+d
+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
+
+
+
+
+
+
+
+
+
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 @@
+
+
+
+
+
+
+
+
+Hello
+
+lkfdsjlk 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 kj
+
+shortebn formo lr lk
+
+djsf lkjlf poer oi pjr po kpk
+
+
+
+a
+
+b
+
+c
+
+d
+
+
+
+1
+
+2
+
+3
+
+
+A
+
+B
+
+
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.
+
+
+
we are right now
+
+
+this is normal
+
This is heading one.
+This is CENTERED heading one

and this is text......
+
and
+this is text......
+
(try clicking on the image :-) and
+this is text......
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Heading 1
+Italic text now...
+
+Heading 2
+and now?
+
+Heading 3
+
+
+Heading 4
+
+
+Heading 5
+
+
+Heading 6
+And this is normal text, once again :-)
+
+
+
+
+
+
+
+
+this is standalone :-)
+
+Now, you will see some PRE text:(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
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
+// 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 @@
+
+
+
+
+
+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.
+
+
+<center><wxp module="wx" class="Button" width="50%">
+ <param name="label" value="It works!">
+ <param name="id" value="ID_OK">
+</wxp></center>
+
+
+
+
+
+
+
+
+
+
+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(
+ "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"
+ "u533f7/+A7mYNW7IcoqBAAAAAElFTkSuQmCC")
+index.append('004')
+catalog['004'] = _004
+
+#----------------------------------------------------------------------
+_005 = PyEmbeddedImage(
+ "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")
+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(
+ "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")
+index.append('012')
+catalog['012'] = _012
+
+#----------------------------------------------------------------------
+_013 = PyEmbeddedImage(
+ "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"
+ "IMOTlboAAAAASUVORK5CYII=")
+index.append('013')
+catalog['013'] = _013
+
+#----------------------------------------------------------------------
+_014 = PyEmbeddedImage(
+ "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"
+ "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(
+ "iVBORw0KGgoAAAANSUhEUgAAACIAAAAiCAIAAAC1JZyVAAAAA3NCSVQICAjb4U/gAAAHGUlE"
+ "QVRIib1X2W5bRxKt6u1u3EQ7kuXYijzeJkhgIPBDgEH8kPnh+YF5mg9IgEHgIFbsSLBFkdSV"
+ "eMm79F26u+ahySt6Zp5TDyLEpU9XnVOn6gL8KYEA8Or1G6UCKRUXgjOOjCMiEQHQ9lvk/9D2"
+ "H8Ldu/j/ztu+EiAAEdG//vkPAQBKBWEYqyD0SMzDAAEROQAy1jbONNY0xjTOGGM6Y4mAMa6k"
+ "isNkKGUAAIi4w0ACQARy5MgCgAAAKZUKwjCMZBAKoThj/jLOdWA1uC5UUoiIcw4Axpiu65qm"
+ "qaqqLMt8c5XdzOLh9GB6FA/HHgURABABiZxzbgvDhZBSySBUKpRScc4BEG3JmR0mozA8Ylwe"
+ "jAeMMedc27ZN02ity7LM8zzLsizLVqv5bTo7PD59dPISGSIgICICkbNmlw1nnAshhJJSSakY"
+ "Q4l6NFaj0WEYJVwGxuHR/YPpJDbG1HXdY6zX6yRJoihSSqVp+uG3n4t19uzr76J4AIgICETI"
+ "djDIOGOcM8Y5ZwxD0RzeGx4c3IsHYyHjzvGiamsXPH78WGtdFIXWOoqiMAyDIFBKCSE454ho"
+ "rZ19OtO1fvX6hzgeIiKRY5btYBA9NgBK1IfT4eHh8WhyL0wOUMSlNmWbXVze/v1vibU2jmMA"
+ "cM4REREBANsFIjLGlsurs7c/vXr9BpEBoFelAC86ICBAW47G6mB6bzi+N54+DJOpIbGulnnZ"
+ "VFq/Pbt8+EVirSUiznkQBIgohJBSSil9WkEQhGE4n388f//L6dNvgYjcrmgABETOdZzZ0egw"
+ "HoyjwUGYTFU0WlxeXV3Nb27SIs///ev5dPjUWusx9gGUUr6AYRgqpTjnN4uP0/vHg8GYeqUB"
+ "ADkAq4fJKIwSIWMUsSGxuLw6/+Pi+nqZ55u61r+++/Tj988454wxIYRzrkeSUgZB4CG97olm"
+ "q3QWxyPn6A4GyIDrwvCIy6BzvNRmXS2vrubX18vNZq11Za0FgN8vrp999YX/heeDcy6E2E+I"
+ "MUZE1tr5Im2aUohgB0NgbRNIybgwFouqLdssL5ubmzTPN1pXzjnP3u8X1y//8sBLwBPOOSci"
+ "55xPqJdc27ZlWepynYzu32XjTMN4AMB1a1xXdLautC7yvK61tZZo62Bnfyzhx20q8FnHo8/G"
+ "o3qP2Gw266K+44aArGkYMutcVTWNpc5CXTd1rU3X7UwTAcCY5ux8+fz0sG+DXs0+Rc65c05r"
+ "nef5ZDLZlAtHexIwpiGAtu2sqXXXGgtdZ7quddveuLPes/PF89ND3EVPj0+LMWatHY1Gw+Fw"
+ "MBhIvtz21lZoxhhj2qbVWldVpXXdto01xjkHQIB3hv/uw7Iv1L4KfMckSRLHsXegKIrCUAH1"
+ "SiM0puu6ru3a1rG2BesYESEiIPOODuBtAk6+nK4LPRnGPhvOuYeRUvqKGWPCMNxakVSdhb2i"
+ "WWqbpm2bzmHXoXUIgIwLzhkACRm8ePLg+ZOjk4fTMJD7eXDO+yblnFtrvR1sjY5xMHd9QwRM"
+ "1zqoNTG0LRqHwHgowxdPv/zr0+MXTx54y/pfSvb7Rghhra3rurc4ZILuigbIuKrKKoo0kwwg"
+ "ePhg+vzJo29enniT77XrAXytPMa+3wghmqZBROec9eG2ut8WTaq43Fwlg8HReHTy+GgymRwc"
+ "xG3b+or7puu1y3fhW9L7mFLKf8daa4zx089Y2M8GwmSY3cyKfDMcJLe3t4wxf0cppRCiN/x9"
+ "AE+7pzqKIk9M13V1XVdVVVXVKss9/3vZyCAeTleruWdyH0Yp1VuL2EVfKKVUFEX+Kl3X+ebf"
+ "bDZFURRV5wj9WrSzToCD6dFtOkvT1J/ozcO7oT/U0/NfGP5aHsOvBqvVKsuyy9myqEx/uOjp"
+ "jYfjw+PTD7/9bK31x3mAYBd+R9nvFd/8vlZ5nqdpulwu0zRN0/R2XRnXe56H2fX4o5OXxTqb"
+ "fTpjjO1z21Pii9kLqWkaxpivVZZly+VyPp8vFosPF/NN0e2WDvisaACIDJ99/Z2u9XJ51c9B"
+ "r2Dv9tZa3+dKqbqufSp1XW82m9VqlabpYrF49/7jTaYBERA/zwb8XgUIGMWDV69/OHv703z+"
+ "cTcHyV9caz0ajZIkCcNQCOHXNmOMpz3LsjRNP1zMbzLtqEdA6rnZqgHQXyGOh69evzl//8vN"
+ "4iPRzM+oqqryPB8Oh3518jD9R0VRXM6Wt+tqU3S7EcQQ2WcSoF0q/bqIyE6ffju9f7xKZ/NF"
+ "WpblZrOZTCaDwSCKov0p2TTNKsuLqisqY5w/YnvCtl573BA5InJEDsjv5whEg8E4jkdNU+py"
+ "vS7qTbmQfBmGSkmFjCMT1jFjobPgts8I22Vv/8HgzgWIyJF1zlljkVlmGSGQs+SccyREkIzu"
+ "k3OOHBEZos4CmO282009Aj8waDs2/HtEBG739PInxH8AbJN3HxvdDPcAAAAASUVORK5CYII=")
+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