# Copyright (c) 2023 M.J.N. Corino, The Netherlands # # This software is released under the MIT license. ### # wxRuby3 wxWidgets interface director ### module WXRuby3 class Director class PropertyGridInterface < Director include Typemap::DateTime include Typemap::PGProperty include Typemap::PGEditor include Typemap::PGPropArg def setup super spec.gc_as_untracked 'wxPropertyGridInterface' # actually no GC control necessary as this is a mixin only # turn wxPropertyGridInterface into a mixin module spec.make_mixin 'wxPropertyGridInterface' # add typedef to work around flaky define in wxWidgets spec.add_swig_code 'typedef const wxPGPropArgCls& wxPGPropArg;' # for Append, AppendIn, Insert, ReplaceProperty spec.disown 'wxPGProperty *property', 'wxPGProperty *newProperty' spec.ignore 'wxPropertyGridInterface::RemoveProperty' # too problematic bc of GC issues # ignore ALL but the Wx::Variant overload spec.ignore 'wxPropertyGridInterface::SetPropertyValue', ignore_doc: false spec.regard 'wxPropertyGridInterface::SetPropertyValue(wxPGPropArg, wxVariant)' # SWIG chokes on the specified 'defaultCategory' default arg spec.ignore 'wxPropertyGridInterface::SetPropertyValues', ignore_doc: false # so redeclare in way SWIG can process (type map takes care of the defaults; no need for wxVariantList overload) spec.extend_interface 'wxPropertyGridInterface', 'void SetPropertyValues(const wxVariant &list, const wxPGPropArgCls& defaultCategory = 0)' # optionals spec.ignore_unless 'USE_LONGLONG', 'wxPropertyGridInterface::GetPropertyValueAsLongLong', 'wxPropertyGridInterface::GetPropertyValueAsULongLong' spec.ignore_unless 'USE_DATETIME', 'wxPropertyGridInterface::GetPropertyValueAsDateTime' spec.ignore_unless 'USE_VALIDATORS', 'wxPropertyGridInterface::GetPropertyValidator' # fix incorrect XML documentation spec.ignore 'wxPropertyGridInterface::SetPropertyImage', ignore_doc: false # ignore non-const BitmapBundle arg decl # and add correct decl spec.extend_interface 'wxPropertyGridInterface', 'void SetPropertyImage(wxPGPropArg id, const wxBitmapBundle &bmp)' # don't expose property grid iterators; add a more Ruby-like extension spec.ignore 'wxPropertyGridInterface::GetIterator', 'wxPropertyGridInterface::GetVIterator' # add basic property enumerator; will wrap this in pure Ruby still for improved argument handling spec.add_extend_code 'wxPropertyGridInterface', <<~__HEREDOC VALUE each_property(int flags, VALUE start, bool reverse) { VALUE rc = Qnil; if (NIL_P(start) && !reverse) { // use faster forward-only iterating over all containers wxPGVIterator prop_it = self->GetVIterator(flags); while (!prop_it.AtEnd()) { wxPGProperty* pp = prop_it.GetProperty(); VALUE rb_prop = SWIG_NewPointerObj(SWIG_as_voidptr(pp), SWIGTYPE_p_wxPGProperty, 0); rc = rb_yield(rb_prop); prop_it.Next(); } } else { wxPropertyGridIterator prop_it; if (NIL_P(start)) { prop_it = self->GetIterator(flags, wxBOTTOM); // reverse -> start at end } else if (TYPE(start) == T_DATA) { void* ptr; int res = SWIG_ConvertPtr(start, &ptr,SWIGTYPE_p_wxPGProperty, 0); if (!SWIG_IsOK(res)) { VALUE msg = rb_inspect(start); rb_raise(rb_eArgError, "Expected Integer or PGProperty for 2 but got %s", StringValuePtr(msg)); } wxPGProperty* pp = static_cast (ptr); prop_it = self->GetIterator(flags, pp); } else if (TYPE(start) == T_FIXNUM || wxRuby_IsAnEnum(start)) { prop_it = self->GetIterator(flags, (int)NUM2INT(start)); } else { VALUE msg = rb_inspect(start); rb_raise(rb_eArgError, "Expected Integer or PGProperty for 2 but got %s", StringValuePtr(msg)); } while (!prop_it.AtEnd()) { wxPGProperty* pp = prop_it.GetProperty(); VALUE rb_prop = SWIG_NewPointerObj(SWIG_as_voidptr(pp), SWIGTYPE_p_wxPGProperty, 0); rc = rb_yield(rb_prop); reverse ? prop_it.Prev() : prop_it.Next(); } } return rc; } __HEREDOC # don't expose wxPGAttributeStorage; add a more Ruby-like extension spec.ignore 'wxPropertyGridInterface::GetPropertyAttributes' spec.add_extend_code 'wxPropertyGridInterface', <<~__HEREDOC VALUE each_property_attribute(const wxPGPropArgCls& proparg) { const wxPGAttributeStorage& att_store = self->GetPropertyAttributes(proparg); wxPGAttributeStorage::const_iterator it = att_store.StartIteration(); wxVariant att_var; VALUE rc = Qnil; while (att_store.GetNext(it, att_var)) { VALUE rb_att_var = SWIG_NewPointerObj(new wxVariant(att_var), SWIGTYPE_p_wxVariant, SWIG_POINTER_OWN); rc = rb_yield(rb_att_var); } return rc; } __HEREDOC spec.map 'wxPGProperty::FlagType' => 'Integer' do map_in code: '$1 = NUM2UINT($input);' end # type mapping for 'wxArrayPGProperty *targetArr' (GetPropertiesWithFlag) spec.map 'wxArrayPGProperty *targetArr' => 'Array' do map_in ignore: true, temp: 'wxArrayPGProperty tmp', code: '$1 = &tmp;' map_argout code: <<~__CODE $result = rb_ary_new(); for (size_t i = 0; i < $1->GetCount(); i++) { wxPGProperty* pp = $1->Item(i); VALUE rb_pp = SWIG_NewPointerObj(SWIG_as_voidptr(pp), SWIGTYPE_p_wxPGProperty, 0); rb_ary_push($result, rb_pp); } __CODE end # for GetSelectedProperties spec.map 'const wxArrayPGProperty &' => 'Array' do map_out code: <<~__CODE $result = rb_ary_new(); for (size_t i = 0; i < $1->GetCount(); i++) { wxPGProperty* pp = $1->Item(i); VALUE rb_pp = SWIG_NewPointerObj(SWIG_as_voidptr(pp), SWIGTYPE_p_wxPGProperty, 0); rb_ary_push($result, rb_pp); } __CODE end # GetState is missing from the XML docs but we want to add a customized version anyway # to be able to return either a PropertyGridPage (for PropertyGridManager) or a PropertyGridPageState # (for PropertyGrid). spec.include 'wx/propgrid/manager.h' spec.add_header_code <<~__CODE extern VALUE mWxPG; // declare external module reference static WxRuby_ID pgi_PropertyGridPageState_id("PropertyGridPageState"); static WxRuby_ID pgi_PropertyGridPage_id("PropertyGridPage"); __CODE spec.add_extend_code 'wxPropertyGridInterface', <<~__HEREDOC VALUE get_state() { // attempt cast wxPropertyGridManager* wx_pgm = dynamic_cast (self); if (wx_pgm) { return wxRuby_WrapWxObjectInRuby(wx_pgm->GetCurrentPage()); } else { wxPropertyGridPageState* wx_pgps = self->GetState(); VALUE klass = rb_const_get(mWxPG, pgi_PropertyGridPageState_id()); swig_type_info* swig_type = wxRuby_GetSwigTypeForClass(klass); return SWIG_NewPointerObj(SWIG_as_voidptr(wx_pgps), swig_type, 0); } } __HEREDOC # In wxRuby PropertyGridPageState is folded into PropertyGridPage so it is not actually # derived from PropertyGridPageState but is one in the sense of Ruby's duck typing so we have # some tinkering to do to make RefreshGrid accept either a PropertyGridPageState (returned from # PropertyGridInterface#GetSate for a PropertyGrid) or a PropertyGridPage (returned either by # PropertyGridInterface#GetState for a PropertyGridManager or any of the PropertyGridManager#GetXXXPage # methods). spec.ignore 'wxPropertyGridInterface::RefreshGrid', ignore_doc: false spec.add_extend_code 'wxPropertyGridInterface', <<~__HEREDOC void RefreshGrid(VALUE rb_state) { wxPropertyGridPageState *state = 0; if (!NIL_P(rb_state)) { VALUE klass = rb_const_get(mWxPG, pgi_PropertyGridPageState_id()); if (rb_obj_is_kind_of(rb_state, klass)) { swig_type_info* swig_type = wxRuby_GetSwigTypeForClass(klass); int res = SWIG_ConvertPtr(rb_state, SWIG_as_voidptrptr(&state), swig_type, 0); if (!SWIG_IsOK(res)) { VALUE msg = rb_inspect(rb_state); rb_raise(rb_eArgError, "Expected PropertyGridPage or PropertyGridPageState for 1 but got %s", StringValuePtr(msg)); } } else { wxPropertyGridPage *wx_pg = 0; VALUE klass = rb_const_get(mWxPG, pgi_PropertyGridPage_id()); swig_type_info* swig_type = wxRuby_GetSwigTypeForClass(klass); int res = SWIG_ConvertPtr(rb_state, SWIG_as_voidptrptr(&wx_pg), swig_type, 0); if (!SWIG_IsOK(res)) { VALUE msg = rb_inspect(rb_state); rb_raise(rb_eArgError, "Expected PropertyGridPage or PropertyGridPageState for 1 but got %s", StringValuePtr(msg)); } state = wx_pg; } } self->RefreshGrid(state); } __HEREDOC spec.map 'wxPropertyGridPageState *state' => 'Wx::PG::PropertyGridPage,Wx::PG::PropertyGridPageState', swig: false do map_in end spec.do_not_generate :variables, :defines, :enums, :functions # with pgproperty end end # class PropertyGridInterface end # class Director end # module WXRuby3