#--------------------------------------------------------------------------- # Name: etg/window.py # Author: Robin Dunn # # Created: 27-Nov-2010 # Copyright: (c) 2013 by Total Control Software # License: wxWindows License #--------------------------------------------------------------------------- import etgtools import etgtools.tweaker_tools as tools from etgtools import ClassDef, MethodDef, ParamDef PACKAGE = "wx" MODULE = "_core" NAME = "window" # Base name of the file to generate to for this script DOCSTRING = "" # The classes and/or the basename of the Doxygen XML files to be processed by # this script. ITEMS = [ 'wxVisualAttributes', 'wxWindow' ] OTHERDEPS = [ 'src/window_ex.cpp', # some helper C++ code ] #--------------------------------------------------------------------------- def run(): # Parse the XML file(s) building a collection of Extractor objects module = etgtools.ModuleDef(PACKAGE, MODULE, NAME, DOCSTRING) etgtools.parseDoxyXML(module, ITEMS) #----------------------------------------------------------------- # Tweak the parsed meta objects in the module object as needed for # customizing the generated code and docstrings. c = module.find('wxWindow') assert isinstance(c, etgtools.ClassDef) module.addGlobalStr('wxPanelNameStr', c) # First we need to let the wrapper generator know about wxWindowBase since # AddChild and RemoveChild need to use that type in order to be virtualized. winbase = ClassDef(name='wxWindowBase', bases=['wxEvtHandler'], abstract=True, items=[MethodDef(name='AddChild', isVirtual=True, type='void', protection='public', items=[ParamDef(name='child', type='wxWindowBase*')]), MethodDef(name='RemoveChild', isVirtual=True, type='void', protection='public', items=[ParamDef(name='child', type='wxWindowBase*')]) ]) module.insertItemBefore(c, winbase) # Now change the base class of wxWindow c.bases = ['wxWindowBase'] # And fix the arg types we get from Doxy c.find('AddChild.child').type = 'wxWindowBase*' c.find('RemoveChild.child').type = 'wxWindowBase*' # We now return you to our regularly scheduled programming... c.includeCppCode('src/window_ex.cpp') # ignore some overloads that will be ambiguous afer wrapping c.find('GetChildren').overloads = [] c.find('GetChildren').noCopy = True for name in ['GetVirtualSize', 'GetPosition', 'GetScreenPosition']: c.find(name).findOverload('int *').ignore() # Fix ClientToScreen/ScreenToClient int * overloads for name in ['ClientToScreen', 'ScreenToClient']: c.find(name).findOverload('int *').find('x').inOut = True c.find(name).findOverload('int *').find('y').inOut = True # Like the above, but these also need to transplant the docs from the # ignored item to the non-ignored overload. for name in ['GetClientSize', 'GetSize']: c.find(name).findOverload('int *').ignore() item = c.find(name) ov = item.overloads[0] item.briefDoc = ov.briefDoc item.detailedDoc = ov.detailedDoc # Release the GIL for potentially blocking or long-running functions c.find('PopupMenu').releaseGIL() c.find('ProcessEvent').releaseGIL() c.find('ProcessWindowEvent').releaseGIL() c.find('ProcessWindowEventLocally').releaseGIL() # Add a couple wrapper functions for symmetry with the getters of the same name c.addPyMethod('SetRect', '(self, rect)', 'return self.SetSize(rect)') c.addPyProperty('Rect GetRect SetRect') c.addPyMethod('SetClientRect', '(self, rect)', 'return self.SetClientSize(rect)') c.addPyProperty('ClientRect GetClientRect SetClientRect') m = c.find('GetTextExtent').findOverload('int *') m.pyName = 'GetFullTextExtent' m.find('w').out = True m.find('h').out = True m.find('descent').out = True m.find('externalLeading').out = True c.find('GetHandle').type = 'wxUIntPtr*' c.find('GetHandle').setCppCode("return new wxUIntPtr(wxPyGetWinHandle(self));") c.addCppMethod('void*', 'GetGtkWidget', '()', """\ #ifdef __WXGTK__ return (void*)self->GetHandle(); #else return NULL; #endif """) c.addCppMethod('void', 'AssociateHandle', '(long handle)', doc="Associate the window with a new native handle", body="self->AssociateHandle((WXWidget)handle);") c.addCppMethod('void', 'DissociateHandle', '()', doc="Dissociate the current native handle from the window", body="self->DissociateHandle();") # Add some new methods c.addCppMethod('wxWindow*', 'GetTopLevelParent', '()', 'return wxGetTopLevelParent(self);', briefDoc="Returns the first ancestor of this window which is a top-level window.") c.addCppMethod('bool', 'MacIsWindowScrollbar', '(const wxWindow* sb)', """\ #ifdef __WXMAC__ return self->MacIsWindowScrollbar(sb); #else return false; #endif """, pyArgsString="(sb)", briefDoc="Is the given widget one of this window's built-in scrollbars? Only applicable on Mac.") c.addCppMethod('void', 'SetDimensions', '(int x, int y, int width, int height, int sizeFlags=wxSIZE_AUTO)', pyArgsString="(x, y, width, height, sizeFlags=SIZE_AUTO)", body="""\ self->SetSize(x, y, width, height, sizeFlags); """) c.addPyCode("Window.SetDimensions = wx.deprecated(Window.SetDimensions, 'Use SetSize instead.')") # Make the Register/UnregisterHotKey functions be available on Windows, # and empty stubs otherwise c.find('RegisterHotKey').setCppCode("""\ #if wxUSE_HOTKEY return self->RegisterHotKey(hotkeyId, modifiers, virtualKeyCode); #else return false; #endif """) c.find('UnregisterHotKey').setCppCode("""\ #if wxUSE_HOTKEY return self->UnregisterHotKey(hotkeyId); #else return false; #endif """) c.find('RegisterHotKey').isVirtual = False c.find('UnregisterHotKey').isVirtual = False c.find('SetDoubleBuffered').setCppCode("""\ #if defined(__WXGTK20__) || defined(__WXGTK3__) || defined(__WXMSW__) self->SetDoubleBuffered(on); #endif """) c.addPyMethod('__nonzero__', '(self)', doc="Can be used to test if the C++ part of the window still exists, with \n" "code like this::\n\n" " if theWindow:\n" " doSomething()", body="""\ import wx.siplib return not wx.siplib.isdeleted(self) """) c.addPyCode('Window.__bool__ = Window.__nonzero__') # For Python 3 c.addPyMethod('DestroyLater', '(self)', doc="""\ Schedules the window to be destroyed in the near future. This should be used whenever Destroy could happen too soon, such as when there may still be events for this window or its children waiting in the event queue. """, body="""\ self.Hide() wx.GetApp().ScheduleForDestruction(self) """) c.addPyMethod('DLG_UNIT', '(self, dlg_unit)', doc="""\ A convenience wrapper for :meth:`ConvertDialogToPixels`. """, body="""\ return self.ConvertDialogToPixels(dlg_unit) """) # MSW only. Do we want them wrapped? c.find('GetAccessible').ignore() c.find('SetAccessible').ignore() # Make some of the protected methods visible and overridable from Python c.find('SendDestroyEvent').ignore(False) c.find('Destroy').transferThis=True c.addPyMethod('PostCreate', '(self, pre)', 'pass', deprecated='PostCreate is no longer necessary.') # transfer ownership of these parameters to the C++ object c.find('SetCaret.caret').transfer = True c.find('SetToolTip.tip').transfer = True c.find('SetDropTarget.target').transfer = True c.find('SetConstraints.constraints').transfer = True c.find('SetSizer.sizer').transfer = True c.find('SetSizerAndFit.sizer').transfer = True # Define some properties using the getter and setter methods c.addProperty('AcceleratorTable GetAcceleratorTable SetAcceleratorTable') c.addProperty('AutoLayout GetAutoLayout SetAutoLayout') c.addProperty('BackgroundColour GetBackgroundColour SetBackgroundColour') c.addProperty('BackgroundStyle GetBackgroundStyle SetBackgroundStyle') c.addProperty('EffectiveMinSize GetEffectiveMinSize') c.addProperty('BestSize GetBestSize') c.addProperty('BestVirtualSize GetBestVirtualSize') c.addProperty('Border GetBorder') c.addProperty('Caret GetCaret SetCaret') c.addProperty('CharHeight GetCharHeight') c.addProperty('CharWidth GetCharWidth') c.addProperty('Children GetChildren') c.addProperty('ClientAreaOrigin GetClientAreaOrigin') c.addProperty('ClientSize GetClientSize SetClientSize') c.addProperty('Constraints GetConstraints SetConstraints') c.addProperty('ContainingSizer GetContainingSizer SetContainingSizer') c.addProperty('Cursor GetCursor SetCursor') c.addProperty('DefaultAttributes GetDefaultAttributes') c.addProperty('DropTarget GetDropTarget SetDropTarget') c.addProperty('EventHandler GetEventHandler SetEventHandler') c.addProperty('ExtraStyle GetExtraStyle SetExtraStyle') c.addProperty('Font GetFont SetFont') c.addProperty('ForegroundColour GetForegroundColour SetForegroundColour') c.addProperty('GrandParent GetGrandParent') c.addProperty('TopLevelParent GetTopLevelParent') c.addProperty('Handle GetHandle') c.addProperty('HelpText GetHelpText SetHelpText') c.addProperty('Id GetId SetId') c.addProperty('Label GetLabel SetLabel') c.addProperty('LayoutDirection GetLayoutDirection SetLayoutDirection') c.addProperty('MaxHeight GetMaxHeight') c.addProperty('MaxSize GetMaxSize SetMaxSize') c.addProperty('MaxWidth GetMaxWidth') c.addProperty('MinHeight GetMinHeight') c.addProperty('MinSize GetMinSize SetMinSize') c.addProperty('MinWidth GetMinWidth') c.addProperty('Name GetName SetName') c.addProperty('Parent GetParent') c.addProperty('Position GetPosition SetPosition') c.addProperty('ScreenPosition GetScreenPosition') c.addProperty('ScreenRect GetScreenRect') c.addProperty('Size GetSize SetSize') c.addProperty('Sizer GetSizer SetSizer') c.addProperty('ThemeEnabled GetThemeEnabled SetThemeEnabled') c.addProperty('ToolTip GetToolTip SetToolTip') c.addProperty('UpdateClientRect GetUpdateClientRect') c.addProperty('UpdateRegion GetUpdateRegion') c.addProperty('Validator GetValidator SetValidator') c.addProperty('VirtualSize GetVirtualSize SetVirtualSize') c.addProperty('WindowStyle GetWindowStyle SetWindowStyle') c.addProperty('WindowStyleFlag GetWindowStyleFlag SetWindowStyleFlag') c.addProperty('WindowVariant GetWindowVariant SetWindowVariant') c.addProperty('Shown IsShown Show') c.addProperty('Enabled IsEnabled Enable') c.addProperty('TopLevel IsTopLevel') c.addProperty('MinClientSize GetMinClientSize SetMinClientSize') c.addProperty('MaxClientSize GetMaxClientSize SetMaxClientSize') ##c.addProperty('GtkWidget GetGtkWidget') tools.fixWindowClass(c) tools.addSipConvertToSubClassCode(c) # for compatibility with Classic c.addPyMethod('GetPositionTuple', '(self)', 'return self.GetPosition()', deprecated='Use GetPosition instead') c.addPyMethod('GetSizeTuple', '(self)', 'return self.GetSize()', deprecated='Use GetSize instead') c.addPyMethod('MoveXY', '(self, x, y)', 'return self.Move(x, y)', deprecated='Use Move instead.') c.addPyMethod('SetSizeWH', '(self, w, h)', 'return self.SetSize(w,h)', deprecated='Use SetSize instead.') c.addPyMethod('SetVirtualSizeWH', '(self, w, h)', 'return self.SetVirtualSize(w,h)', deprecated='Use SetVirtualSize instead.') c.addPyMethod('GetVirtualSizeTuple', '(self)', 'return self.GetVirtualSize()', deprecated='Use GetVirtualSize instead.') c.addPyMethod('SetToolTipString', '(self, string)', 'return self.SetToolTip(string)', deprecated='Use SetToolTip instead.') c.addPyMethod('ConvertDialogPointToPixels', '(self, point)', 'return self.ConvertDialogToPixels(point)', deprecated='Use ConvertDialogToPixels instead.') c.addPyMethod('ConvertDialogSizeToPixels', '(self, size)', 'return self.ConvertDialogToPixels(point)', deprecated='Use ConvertDialogToPixels instead.') c.addPyMethod('SetSizeHintsSz', '(self, minSize, maxSize=wx.DefaultSize, incSize=wx.DefaultSize)', 'return self.SetSizeHints(minSize, maxSize, incSize)', deprecated='Use SetSizeHints instead.') # TODO: the C++ DoEraseBackground is protected in wxMSW. We need a way to # unprotect it, like adding a shim in the sip class... #c.addHeaderCode("""\ # #ifdef __WXMSW__ # #include # #endif # """) #c.addCppMethod('bool', 'DoEraseBackground', '(wxDC* dc)', # doc="Default erase background implementation.", # body="""\ # #ifdef __WXMSW__ # return self->DoEraseBackground(((wxMSWDCImpl*)dc->GetImpl())->GetHDC()); # #else # dc->SetBackground(wxBrush(self->GetBackgroundColour())); # dc->Clear(); # return true; # #endif # """) # this is a nested class c.find('ChildrenRepositioningGuard').addPrivateCopyCtor() module.insertItem(0, etgtools.TypedefDef(type='wxWindow::ChildrenRepositioningGuard', name='ChildrenRepositioningGuard')) #----------------------------------------------------------------------- # Other stuff module.addPyCode('''\ class FrozenWindow(object): """ A context manager to be used with Python 'with' statements that will freeze the given window for the duration of the with block. """ def __init__(self, window): self._win = window def __enter__(self): self._win.Freeze() return self def __exit__(self, exc_type, exc_val, exc_tb): self._win.Thaw() ''') module.addPyCode('''\ def DLG_UNIT(win, dlg_unit, val2=None): """ Convenience function for converting a wx.Point, wx.Size or (x,y) in dialog units to pixels. """ if val2 is not None: dlg_unit = (dlg_unit, val2) return win.ConvertDialogToPixels(dlg_unit) DLG_PNT = wx.deprecated(DLG_UNIT, "Use DLG_UNIT instead.") DLG_SZE = wx.deprecated(DLG_UNIT, "Use DLG_UNIT instead.") ''') # Add a wrapper for wxWindowList and a new iterator class for it that # makes wxWindowList quack like a read-only Python sequence. module.addItem(tools.wxListWrapperTemplate('wxWindowList', 'wxWindow', module)) module.addCppFunction('wxWindowList*', 'GetTopLevelWindows', '()', noCopy=True, briefDoc="Returns a list-like object of the the application's top-level windows, (frames,dialogs, etc.)", body="return &wxTopLevelWindows;") module.addPyCode("PyWindow = wx.deprecated(Window, 'Use Window instead.')") module.find('wxFindWindowAtPointer.pt').out = True module.addCppFunction('wxWindow*', 'FindWindowById', '(long id, const wxWindow* parent=NULL)', doc="""\ FindWindowById(id, parent=None) -> Window Find the first window in the application with the given id. If parent is None, the search will start from all top-level frames and dialog boxes; if non-None, the search will be limited to the given window hierarchy. The search is recursive in both cases. """, body="return wxWindow::FindWindowById(id, parent);") module.addCppFunction('wxWindow*', 'FindWindowByName', '(const wxString& name, const wxWindow* parent=NULL)', doc="""\ FindWindowByName(name, parent=None) -> Window Find a window by its name (as given in a window constructor or Create function call). If parent is None, the search will start from all top-level frames and dialog boxes; if non-None, the search will be limited to the given window hierarchy. The search is recursive in both cases. If no window with the name is found, wx.FindWindowByLabel is called.""", body="return wxWindow::FindWindowByName(*name, parent);") module.addCppFunction('wxWindow*', 'FindWindowByLabel', '(const wxString& label, const wxWindow* parent=NULL)', doc="""\ FindWindowByLabel(label, parent=None) -> Window Find a window by its label. Depending on the type of window, the label may be a window title or panel item label. If parent is None, the search will start from all top-level frames and dialog boxes; if non-None, the search will be limited to the given window hierarchy. The search is recursive in both cases.""", body="return wxWindow::FindWindowByLabel(*label, parent);") #----------------------------------------------------------------- tools.doCommonTweaks(module) tools.runGenerators(module) #--------------------------------------------------------------------------- if __name__ == '__main__': run()