# 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 GridCellEditor < Director def setup super spec.gc_as_marked # tailored tracking method # use custom free func to be able to account for more complex inheritance spec.add_header_code 'extern void GC_free_GridCellEditor(void *ptr);' spec.add_swig_code '%feature("freefunc") wxGridCellEditor "GC_free_GridCellEditor";' if spec.module_name == 'wxGridCellEditor' spec.post_processors << :fix_gridcelleditor # exposing the mixin wxClientDataContainer/wxSharedClientDataContainer has no real upside # for wxRuby; far easier to just use member variables in derived classes spec.override_inheritance_chain('wxGridCellEditor', []) spec.regard('wxGridCellEditor::~wxGridCellEditor') # add method for correctly wrapping PGEditor output references spec.add_header_code <<~__CODE extern VALUE mWxGRID; // declare external module reference extern VALUE wxRuby_GridCellEditorInstance(wxGridCellEditor* wx_edt); extern void wxRuby_RegisterGridCellEditor(wxGridCellEditor* wx_edt, VALUE rb_edt); extern VALUE wxRuby_WrapWxGridCellEditorInRuby(const wxGridCellEditor *wx_gce) { // If no object was passed to be wrapped. if ( ! wx_gce ) return Qnil; // check for registered instance VALUE rb_gce = wxRuby_GridCellEditorInstance(const_cast (wx_gce)); if (rb_gce && !NIL_P(rb_gce)) { return rb_gce; } const void *ptr = 0; wxString class_name; if ((ptr = dynamic_cast (wx_gce))) { class_name = "GridCellActivatableEditor"; } else if ((ptr = dynamic_cast (wx_gce))) { class_name = "GridCellBoolEditor"; } else if ((ptr = dynamic_cast (wx_gce))) { class_name = "GridCellEnumEditor"; } else if ((ptr = dynamic_cast (wx_gce))) { class_name = "GridCellChoiceEditor"; } else if ((ptr = dynamic_cast (wx_gce))) { class_name = "GridCellDateEditor"; } else if ((ptr = dynamic_cast (wx_gce))) { class_name = "GridCellFloatEditor"; } else if ((ptr = dynamic_cast (wx_gce))) { class_name = "GridCellNumberEditor"; } else if ((ptr = dynamic_cast (wx_gce))) { class_name = "GridCellAutoWrapStringEditor"; } else if ((ptr = dynamic_cast (wx_gce))) { class_name = "GridCellTextEditor"; } VALUE r_class = Qnil; if ( ptr && class_name.Len() > 0 ) { wxCharBuffer wx_classname = class_name.mb_str(); VALUE r_class_name = rb_intern(wx_classname.data ()); // wxRuby class name (minus 'wx') if (rb_const_defined(mWxGRID, r_class_name)) r_class = rb_const_get(mWxGRID, r_class_name); } // If we cannot find the class output a warning and return nil if ( r_class == Qnil ) { rb_warn("Error wrapping object; class `%s' is not (yet) supported in wxRuby", (const char *)class_name.mb_str() ); return Qnil; } // Otherwise, retrieve the swig type info for this class and wrap it // in Ruby. Make it owned to manage the ref count if GC claims the object. // wxRuby_GetSwigTypeForClass is defined in wx.i swig_type_info* swig_type = wxRuby_GetSwigTypeForClass(r_class); rb_gce = SWIG_NewPointerObj(const_cast (ptr), swig_type, 0); wxRuby_RegisterGridCellEditor(const_cast (wx_gce), rb_gce); return rb_gce; } extern void GC_free_GridCellEditor(void *ptr) { wxGridCellEditor* gc_edt = (wxGridCellEditor*)ptr; if (ptr) gc_edt->DecRef(); } __CODE elsif spec.module_name == 'wxGridCellActivatableEditor' spec.post_processors << :fix_gridcelleditor spec.override_inheritance_chain('wxGridCellActivatableEditor', %w[wxGridCellEditor]) spec.no_proxy %w[ wxGridCellActivatableEditor::BeginEdit wxGridCellActivatableEditor::Create wxGridCellActivatableEditor::Destroy wxGridCellActivatableEditor::EndEdit wxGridCellActivatableEditor::ApplyEdit wxGridCellActivatableEditor::HandleReturn wxGridCellActivatableEditor::PaintBackground wxGridCellActivatableEditor::Reset wxGridCellActivatableEditor::SetSize wxGridCellActivatableEditor::Show wxGridCellActivatableEditor::StartingClick wxGridCellActivatableEditor::StartingKey wxGridCellActivatableEditor::IsAcceptedKey wxGridCellActivatableEditor::GetValue ] else spec.post_processors << :fix_gridcelleditor case spec.module_name when 'wxGridCellEnumEditor' spec.override_inheritance_chain(spec.module_name, %w[wxGridCellChoiceEditor wxGridCellEditor]) when 'wxGridCellChoiceEditor' # unnecessary overload spec.ignore 'wxGridCellChoiceEditor::wxGridCellChoiceEditor(size_t, const wxString [], bool)' spec.override_inheritance_chain(spec.module_name, %w[wxGridCellEditor]) when 'wxGridCellAutoWrapStringEditor', 'wxGridCellFloatEditor', 'wxGridCellNumberEditor' spec.override_inheritance_chain(spec.module_name, %w[wxGridCellTextEditor wxGridCellEditor]) else spec.override_inheritance_chain(spec.module_name, %w[wxGridCellEditor]) end # due to the flawed wxWidgets XML docs we need to explicitly add these here # otherwise the derived editors won't be allocable due to pure virtuals spec.extend_interface spec.module_name, 'void BeginEdit(int row, int col, wxGrid *grid)', 'wxGridCellEditor * Clone() const', 'void Create(wxWindow *parent, wxWindowID id, wxEvtHandler *evtHandler)', 'bool EndEdit(int row, int col, const wxGrid *grid, const wxString &oldval, wxString *newval)', 'void ApplyEdit(int row, int col, wxGrid *grid)', 'void Reset()', 'wxString GetValue() const' end unless spec.module_name == 'wxGridCellEditor' # type mapping for Clone return ref spec.map 'wxGridCellEditor*' => 'Wx::GRID::GridCellEditor' do add_header_code 'extern VALUE wxRuby_WrapWxGridCellEditorInRuby(const wxGridCellEditor *wx_gce);' map_out code: '$result = wxRuby_WrapWxGridCellEditorInRuby($1);' end end # handled; can be suppressed spec.suppress_warning(473, "#{spec.module_name}::Clone") end # helper methods for custom wrapper to handle wxGridActivationResult and wxGridActivationSource # in wxGridCellEditor::TryActivate as SWIG cannot handle the, admittedly seriously flawed, # wxWidgets interface WRAPPER_HELPERS = <<~__HEREDOC static WxRuby_ID ga_ignore_id("ignore"); static WxRuby_ID ga_show_editor_id("show_editor"); static WxRuby_ID ga_change_id("change"); static WxRuby_ID ga_program_id("program"); static WxRuby_ID ga_key_id("key"); static WxRuby_ID ga_mouse_id("mouse"); inline wxGridActivationResult array_to_wxGridActivationResult(VALUE self, const char* method, VALUE rbarr) { if (rbarr == Qnil || !(TYPE(rbarr) == T_ARRAY || TYPE(rbarr) == T_SYMBOL)) { Swig::DirectorTypeMismatchException::raise(self, method, SWIG_ErrorType(SWIG_ArgError(SWIG_ERROR)), "in output value of type 'wxGridActivationResult'"); } if (TYPE(rbarr) == T_SYMBOL) { if (SYM2ID(rbarr) == ga_ignore_id()) return wxGridActivationResult::DoNothing(); else if (SYM2ID(rbarr) == ga_show_editor_id()) return wxGridActivationResult::DoEdit(); else Swig::DirectorTypeMismatchException::raise(self, method, SWIG_ErrorType(SWIG_ArgError(SWIG_ERROR)), "in output value of type 'wxGridActivationResult'"); } else { VALUE rbAction = rb_ary_shift(rbarr); VALUE rbStr = rb_ary_shift(rbarr); // could be nil if (rbAction == Qnil || TYPE(rbAction) != T_SYMBOL) { Swig::DirectorTypeMismatchException::raise(self, method, SWIG_ErrorType(SWIG_ArgError(SWIG_ERROR)), "in output value of type 'wxGridActivationResult'"); } else if (SYM2ID(rbAction) == ga_change_id() && rbStr != Qnil) { return wxGridActivationResult::DoChange(RSTR_TO_WXSTR(rbStr)); } else { if (SYM2ID(rbAction) == ga_ignore_id()) return wxGridActivationResult::DoNothing(); else if (SYM2ID(rbAction) == ga_show_editor_id()) return wxGridActivationResult::DoEdit(); else Swig::DirectorTypeMismatchException::raise(self, method, SWIG_ErrorType(SWIG_ArgError(SWIG_ERROR)), "in output value of type 'wxGridActivationResult'"); } } // silence compiler; should never be reached return wxGridActivationResult::DoNothing(); } inline VALUE wxGridActivationResult_to_array(const wxGridActivationResult& result) { VALUE rbresult = rb_ary_new(); wxGridActivationResult::Action act = result.GetAction (); switch (act) { case wxGridActivationResult::Ignore: rb_ary_push(rbresult, ga_ignore_id.get_sym()); break; case wxGridActivationResult::Change: rb_ary_push(rbresult, ga_change_id.get_sym()); rb_ary_push(rbresult, WXSTR_TO_RSTR(result.GetNewValue())); break; case wxGridActivationResult::ShowEditor: rb_ary_push(rbresult, ga_show_editor_id.get_sym()); break; } return rbresult; } inline wxGridActivationSource array_to_wxGridActivationSource(VALUE rbarr, int argnum) { if (rbarr == Qnil || !(TYPE(rbarr) == T_ARRAY || TYPE(rbarr) == T_SYMBOL)) { rb_raise(rb_eArgError, "Expected Symbol or Array of Symbol and optional event for %d.", argnum); } if (TYPE(rbarr) == T_SYMBOL) { if (SYM2ID(rbarr) != ga_program_id()) rb_raise(rb_eArgError, ":key or :mouse activation sources need an event for %d.", argnum); else return wxGridActivationSource::FromProgram(); } else { VALUE rbOrg = rb_ary_shift(rbarr); VALUE rbEvt = rb_ary_shift(rbarr); // could be nil if (rbOrg == Qnil || TYPE(rbOrg) != T_SYMBOL) { rb_raise(rb_eArgError, "expected Symbol or Array of Symbol and optional event for %d.", argnum); } else if (SYM2ID(rbOrg) == ga_program_id()) { return wxGridActivationSource::FromProgram(); } else if (rbEvt != Qnil) { const wxEvent* evt = (const wxEvent*)DATA_PTR(rbEvt); if (SYM2ID(rbOrg) == ga_key_id()) return wxGridActivationSource::From(*(const wxKeyEvent*)evt); else if (SYM2ID(rbOrg) == ga_mouse_id()) return wxGridActivationSource::From(*(const wxMouseEvent*)evt); rb_raise(rb_eArgError, "unknown activation source for %d.", argnum); } else { rb_raise(rb_eArgError, ":key or :mouse activation sources need an event for %d.", argnum); } } } inline VALUE wxGridActivationSource_to_array(const wxGridActivationSource& arg) { VALUE rbresult = rb_ary_new(); wxGridActivationSource::Origin org = arg.GetOrigin (); switch (org) { case wxGridActivationSource::Program: rb_ary_push(rbresult, ga_program_id.get_sym()); break; case wxGridActivationSource::Key: rb_ary_push(rbresult, ga_key_id.get_sym()); #ifdef __WXRB_DEBUG__ rb_ary_push(rbresult, wxRuby_WrapWxEventInRuby(0, const_cast (&arg.GetKeyEvent()))); #else rb_ary_push(rbresult, wxRuby_WrapWxEventInRuby(const_cast (&arg.GetKeyEvent()))); #endif break; case wxGridActivationSource::Mouse: rb_ary_push(rbresult, ga_mouse_id.get_sym()); #ifdef __WXRB_DEBUG__ rb_ary_push(rbresult, wxRuby_WrapWxEventInRuby(0, const_cast (&arg.GetMouseEvent()))); #else rb_ary_push(rbresult, wxRuby_WrapWxEventInRuby(const_cast (&arg.GetMouseEvent()))); #endif break; } return rbresult; } __HEREDOC end # class GridCellEditor end # class Director module SwigRunner class Processor # special post-processor for GridCellEditor class FixGridcelleditor < Processor def run skip_lines = false helpers_added = false update_source do |line| if skip_lines if /\A}\s*\Z/ =~ line skip_lines = false else line = nil end elsif line["wxGridActivationResult SwigDirector_#{module_name}::TryActivate("] skip_lines = true # append new method implementation line << "\n" << <<~__METHOD__ static WxRuby_ID try_activate_id("try_activate"); VALUE obj0 = Qnil ; VALUE obj1 = Qnil ; VALUE obj2 = Qnil ; VALUE obj3 = Qnil ; VALUE SWIGUNUSED result; obj0 = SWIG_From_int(static_cast< int >(row)); obj1 = SWIG_From_int(static_cast< int >(col)); obj2 = SWIG_NewPointerObj(SWIG_as_voidptr(grid), SWIGTYPE_p_wxGrid, 0 ); obj3 = wxGridActivationSource_to_array(actSource); result = rb_funcall(swig_get_self(), try_activate_id(), 4,obj0,obj1,obj2,obj3); return array_to_wxGridActivationResult(swig_get_self(), "try_activate", result); __METHOD__ elsif !helpers_added && line["SwigDirector_#{module_name}::SwigDirector_#{module_name}(VALUE self"] # insert helper methods line = [Director::GridCellEditor::WRAPPER_HELPERS, line] helpers_added = true elsif line["_wrap_#{module_name}_TryActivate(int argc, VALUE *argv, VALUE self) {"] skip_lines = true # append new method implementation line << "\n" << <<~__METHOD__ #{module_name} *arg1 = (#{module_name} *) 0 ; int arg2 ; int arg3 ; wxGrid *arg4 = (wxGrid *) 0 ; void *argp1 = 0 ; int res1 = 0 ; int val2 ; int ecode2 = 0 ; int val3 ; int ecode3 = 0 ; void *argp4 = 0 ; int res4 = 0 ; Swig::Director *director = 0; bool upcall = false; VALUE vresult = Qnil; if ((argc < 4) || (argc > 4)) { rb_raise(rb_eArgError, "wrong # of arguments(%d for 4)",argc); SWIG_fail; } res1 = SWIG_ConvertPtr(self, &argp1,SWIGTYPE_p_#{module_name}, 0 | 0 ); if (!SWIG_IsOK(res1)) { SWIG_exception_fail(SWIG_ArgError(res1), Ruby_Format_TypeError( "", "#{module_name} *","TryActivate", 1, self )); } arg1 = reinterpret_cast< #{module_name} * >(argp1); ecode2 = SWIG_AsVal_int(argv[0], &val2); if (!SWIG_IsOK(ecode2)) { SWIG_exception_fail(SWIG_ArgError(ecode2), Ruby_Format_TypeError( "", "int","TryActivate", 2, argv[0] )); } arg2 = static_cast< int >(val2); ecode3 = SWIG_AsVal_int(argv[1], &val3); if (!SWIG_IsOK(ecode3)) { SWIG_exception_fail(SWIG_ArgError(ecode3), Ruby_Format_TypeError( "", "int","TryActivate", 3, argv[1] )); } arg3 = static_cast< int >(val3); res4 = SWIG_ConvertPtr(argv[2], &argp4,SWIGTYPE_p_wxGrid, 0 | 0 ); if (!SWIG_IsOK(res4)) { SWIG_exception_fail(SWIG_ArgError(res4), Ruby_Format_TypeError( "", "wxGrid *","TryActivate", 4, argv[2] )); } arg4 = reinterpret_cast< wxGrid * >(argp4); director = dynamic_cast(arg1); upcall = (director && (director->swig_get_self() == self)); try { if (upcall) { #{ if module_name == 'wxGridCellActivatableEditor' 'Swig::DirectorPureVirtualException::raise("wxGridCellActivatableEditor::TryActivate");' else "vresult = wxGridActivationResult_to_array((arg1)->#{module_name}::TryActivate(arg2,arg3,arg4,array_to_wxGridActivationSource(argv[3], 4)));" end } } else { vresult = wxGridActivationResult_to_array((arg1)->TryActivate(arg2,arg3,arg4,array_to_wxGridActivationSource(argv[3], 4))); } } catch (Swig::DirectorException& e) { rb_exc_raise(e.getError()); SWIG_fail; } return vresult; fail: return Qnil; __METHOD__ end line end end end # class FixGridcelleditor end end end # module WXRuby3