ext/wxMenu.cpp
/*
* wxMenu.cpp
*
* Created on: 17.02.2012
* Author: hanmac
*/
#include "wxMenu.hpp"
#include "wxMenuItem.hpp"
#include "wxEvtHandler.hpp"
#include "wxApp.hpp"
VALUE rb_cWXMenu;
#if wxUSE_MENUS
#define _self unwrap<wxMenu*>(self)
namespace RubyWX {
namespace Menu {
macro_attr(Title,wxString)
macro_attr(Parent,wxMenu*)
macro_attr(EventHandler,wxEvtHandler*)
singlereturn(AppendSeparator)
singlereturn(PrependSeparator)
singlereturn(IsAttached)
singlefunc(Detach)
APP_PROTECT(wxMenu)
DLL_LOCAL VALUE _initialize(int argc,VALUE *argv,VALUE self)
{
VALUE title;
rb_scan_args(argc, argv, "01",&title);
if(NIL_P(title))
_self->SetTitle("");
else if(RB_SYMBOL_P(title))
_self->SetTitle(wxGetStockLabel(unwrapID(title)));
else
_setTitle(self,title);
if(rb_block_given_p()){
rb_yield(self);
}
return self;
}
singlereturn(GetMenuBar)
singlereturn(GetMenuItemCount)
DLL_LOCAL VALUE _setMenuBar(VALUE self,VALUE frame)
{
rb_check_frozen(self);
if(_self->IsAttached())
_self->Detach();
if(!NIL_P(frame)) {
_self->Attach(unwrap<wxMenuBar*>(frame));
}
return frame;
}
#define macro_attr_menu_item_func(attr,funcget,funcset,wrapget,wrapset, con) \
\
DLL_LOCAL VALUE _get##attr(VALUE self,VALUE idx)\
{\
wxMenuItem* item = _getItemBase(_self, idx); \
if(item && con)\
return wrapget(_self->funcget(item->GetId()));\
return Qnil;\
}\
DLL_LOCAL VALUE _set##attr(VALUE self,VALUE idx,VALUE val)\
{\
rb_check_frozen(self);\
wxMenuItem* item = _getItemBase(_self, idx); \
if(item && con)\
_self->funcset(item->GetId(),wrapset(val));\
\
return self;\
}
#define macro_attr_menu_item(attr,type) macro_attr_menu_item_func(attr, Get##attr, Set##attr, wrap, unwrap<type>, true)
#define macro_attr_menu_item_bool(attr, attr2, con) macro_attr_menu_item_func(attr, Is##attr, attr2, wrap, unwrap<bool>, con)
DLL_LOCAL wxMenuItem* _getItemBase(wxMenu *menu, VALUE val)
{
wxMenuItem* item = NULL;
if(rb_obj_is_kind_of(val, rb_cString)) {
item = menu->FindItem(menu->FindItem(unwrap<wxString>(val)));
} else {
wxWindowID id = unwrapID(val);
item = menu->FindItem(id);
}
if(!item) {
int cidx = RB_NUM2INT(val);
if(check_index(cidx,menu->GetMenuItemCount()))
item = menu->FindItemByPosition(cidx);
}
return item;
}
macro_attr_menu_item(Label, wxString)
macro_attr_menu_item(HelpString, wxString)
macro_attr_menu_item_bool(Enabled, Enable, true)
macro_attr_menu_item_bool(Checked, Check, item->IsCheckable())
DLL_LOCAL VALUE _getItem(VALUE self,VALUE val)
{
return wrap(_getItemBase(_self, val));
}
DLL_LOCAL VALUE _each(VALUE self)
{
RETURN_SIZED_ENUMERATOR(self,0,NULL,RUBY_METHOD_FUNC(_GetMenuItemCount));
for(std::size_t i = 0;i < _self->GetMenuItemCount();++i)
rb_yield(wrap(_self->FindItemByPosition(i)));
return self;
}
void bind_callback(wxMenu* menu,wxWindowID id)
{
if(rb_block_given_p()){
VALUE proc = rb_block_proc();
menu->Bind(wxEVT_MENU,RubyFunctor(proc),id);
}
}
DLL_LOCAL bool check_title(wxWindowID wid, VALUE id, VALUE text)
{
if(!wxIsStockID(wid) && (NIL_P(text) || RSTRING_LEN(rb_String(text)) == 0))
{
rb_raise(rb_eArgError,"id '%" PRIsVALUE "' (%d) needs an text", RB_OBJ_STRING(id), wid);
return false;
}
return true;
}
DLL_LOCAL bool check_menu_mitle(wxMenu *m,wxString &wtext)
{
if(wtext.empty())
{
if(m->GetTitle().empty())
{
rb_raise(rb_eArgError,"menu must have a title");
return false;
}
wtext = m->GetTitle();
}
return true;
}
DLL_LOCAL VALUE _append_base(int argc,VALUE *argv,VALUE self,wxItemKind kind)
{
VALUE id,text,help;
rb_scan_args(argc, argv, "12",&id,&text,&help);
wxWindowID wid(unwrapID(id));
if(check_title(wid,id,text))
{
wxMenuItem *item = _self->Append(wid,unwrap<wxString>(text),unwrap<wxString>(help),kind);
bind_callback(_self,item->GetId());
return wrap(item);
}
return Qnil;
}
/*
* call-seq:
* append_normal(id, text, [help]) -> WX::Menu::Item
* append_normal(id, text, [help]) {|event| ... } -> WX::Menu::Item
*
* adds a new normal menu item to the Menu widget.
* when block is given, bind the block to the event of the menu item.
* ===Arguments
* * id of the menu item: Symbol/Integer/nil
* * text is the Label of the menu item. String (can be nil if id is one of the system defined)
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when id is not a StockID and text is nil or empty
*
*/
DLL_LOCAL VALUE _appendNormalItem(int argc,VALUE *argv,VALUE self)
{
return _append_base(argc,argv,self,wxITEM_NORMAL);
}
/*
* call-seq:
* append_check(id, text, [help]) -> WX::Menu::Item
* append_check(id, text, [help]) {|event| ... } -> WX::Menu::Item
*
* adds a new check menu item to the Menu widget.
* when block is given, bind the block to the event of the menu item.
* ===Arguments
* * id of the menu item: Symbol/Integer/nil
* * text is the Label of the menu item. String (can be nil if id is one of the pre defined)
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when id is not a StockID and text is nil or empty
*
*/
DLL_LOCAL VALUE _appendCheckItem(int argc,VALUE *argv,VALUE self)
{
return _append_base(argc,argv,self,wxITEM_CHECK);
}
/*
* call-seq:
* append_radio(id, text, [help]) -> WX::Menu::Item
* append_radio(id, text, [help]) {|event| ... } -> WX::Menu::Item
*
* adds a new radio menu item to the Menu widget.
* when block is given, bind the block to the event of the menu item.
* ===Arguments
* * id of the menu item: Symbol/Integer/nil
* * text is the Label of the menu item. String (can be nil if id is one of the pre defined)
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when id is not a StockID and text is nil or empty
*
*/
DLL_LOCAL VALUE _appendRadioItem(int argc,VALUE *argv,VALUE self)
{
return _append_base(argc,argv,self,wxITEM_RADIO);
}
/*
* call-seq:
* append_menu(text, [help]) {|menu| ... } -> WX::Menu::Item
* append_menu(menu, text, [help]) -> WX::Menu::Item
*
* adds a new sub menu item to the Menu widget.
* when block is given, it created a new menu and yields it into the block.
* ===Arguments
* * text is the Label of the menu item. String
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when either menu hasn't a title and text is empty
* [TypeError]
* * when menu is nil
*
*/
DLL_LOCAL VALUE _append_menu(int argc,VALUE *argv,VALUE self)
{
VALUE text,help,menu;
wxMenu *m = NULL;
if(rb_block_given_p()){
rb_scan_args(argc, argv, "11",&text,&help);
m = new wxMenu;
rb_yield(wrap(m));
}else{
rb_scan_args(argc, argv, "12",&menu,&text,&help);
if(!nil_check(menu,"menu"))
return Qnil;
m = unwrap<wxMenu*>(menu);
}
wxString wtext(unwrap<wxString>(text));
if(check_menu_mitle(m,wtext))
return wrap(_self->AppendSubMenu(m,wtext,unwrap<wxString>(help)));
return Qnil;
}
DLL_LOCAL VALUE _appendShift(VALUE self,VALUE val)
{
if(rb_obj_is_kind_of(val,rb_cWXMenuItem)) {
_self->Append(unwrap<wxMenuItem*>(val));
} else if(NIL_P(val)){
_self->AppendSeparator();
} else {
wxWindowID id = unwrapID(val);
if(!wxIsStockID(id))
rb_raise(
rb_eArgError, "id \"%" PRIsVALUE "\" cant be fast added",
RB_OBJ_STRING(val)
);
_self->Append(id);
}
return self;
}
DLL_LOCAL VALUE _insert_base(int argc,VALUE *argv,VALUE self,wxItemKind kind)
{
VALUE idx,id,text,help;
rb_scan_args(argc, argv, "22",&idx,&id,&text,&help);
wxWindowID wid(unwrapID(id));
if(check_title(wid,id,text))
{
int cidx = RB_NUM2INT(idx);
if(check_index(cidx,_self->GetMenuItemCount()+1))
{
wxMenuItem *item = _self->Insert(cidx,wid,unwrap<wxString>(text),unwrap<wxString>(help),kind);
bind_callback(_self,item->GetId());
return wrap(item);
}
}
return Qnil;
}
/*
* call-seq:
* insert_normal(pos, id, text, [help]) -> WX::Menu::Item
* insert_normal(pos, id, text, [help]) {|event| ... } -> WX::Menu::Item
*
* inserts a new normal menu item to the Menu widget to the given position.
* when block is given, bind the block to the event of the menu item.
* ===Arguments
* * pos where the item should be added.
* * id of the menu item: Symbol/Integer/nil
* * text is the Label of the menu item. String (can be nil if id is one of the pre defined)
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when id is not a StockID and text is nil or empty
* [IndexError]
* * pos is greater than the count of MenuItems
*
*/
DLL_LOCAL VALUE _insertNormalItem(int argc,VALUE *argv,VALUE self)
{
return _insert_base(argc,argv,self,wxITEM_NORMAL);
}
/*
* call-seq:
* insert_check(pos, id, text, [help]) -> WX::Menu::Item
* insert_check(pos, id, text, [help]) {|event| ... } -> WX::Menu::Item
*
* inserts a new check menu item to the Menu widget to the given position.
* when block is given, bind the block to the event of the menu item.
* ===Arguments
* * pos where the item should be added.
* * id of the menu item: Symbol/Integer/nil
* * text is the Label of the menu item. String (can be nil if id is one of the pre defined)
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when id is not a StockID and text is nil or empty
* [IndexError]
* * pos is greater than the count of MenuItems
*
*/
DLL_LOCAL VALUE _insertCheckItem(int argc,VALUE *argv,VALUE self)
{
return _insert_base(argc,argv,self,wxITEM_CHECK);
}
/*
* call-seq:
* insert_radio(pos, id, text, [help]) -> WX::Menu::Item
* insert_radio(pos, id, text, [help]) {|event| ... } -> WX::Menu::Item
*
* inserts a new radio menu item to the Menu widget to the given position.
* when block is given, bind the block to the event of the menu item.
* ===Arguments
* * pos where the item should be added.
* * id of the menu item: Symbol/Integer/nil
* * text is the Label of the menu item. String (can be nil if id is one of the pre defined)
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when id is not a StockID and text is nil or empty
* [IndexError]
* * pos is greater than the count of MenuItems
*
*/
DLL_LOCAL VALUE _insertRadioItem(int argc,VALUE *argv,VALUE self)
{
return _insert_base(argc,argv,self,wxITEM_RADIO);
}
/*
* call-seq:
* insert_menu(pos, text, [help]) {|menu| ... } -> WX::Menu::Item
* insert_menu(pos, menu, text, [help]) -> WX::Menu::Item
*
* insert a new sub menu item to the Menu widget into the given position.
* when block is given, it created a new menu and yields it into the block.
* ===Arguments
* * pos where the item should be added.
* * text is the Label of the menu item. String
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when either menu hasn't a title and text is empty
* [TypeError]
* * when menu is nil
* [IndexError]
* * pos is greater than the count of MenuItems
*
*/
DLL_LOCAL VALUE _insert_menu(int argc,VALUE *argv,VALUE self)
{
VALUE idx,text,help,menu;
wxMenu *m = NULL;
if(rb_block_given_p()){
rb_scan_args(argc, argv, "21",&idx,&text,&help);
m = new wxMenu;
rb_yield(wrap(m));
}else{
rb_scan_args(argc, argv, "22",&idx,&menu,&text,&help);
if(!nil_check(menu,"menu"))
return Qnil;
m = unwrap<wxMenu*>(menu);
}
wxString wtext(unwrap<wxString>(text));
if(check_menu_mitle(m,wtext))
{
int cidx = RB_NUM2INT(idx);
if(check_index(cidx,_self->GetMenuItemCount()+1))
{
return wrap(_self->Insert(cidx,wxID_ANY,wtext,m,unwrap<wxString>(help)));
}
}
return Qnil;
}
DLL_LOCAL VALUE _InsertSeparator(VALUE self,VALUE idx)
{
int cidx = RB_NUM2INT(idx);
if(check_index(cidx,_self->GetMenuItemCount()+1))
{
return wrap(_self->InsertSeparator(idx));
}
return Qnil;
}
DLL_LOCAL VALUE _prepend_base(int argc,VALUE *argv,VALUE self,wxItemKind kind)
{
VALUE id,text,help;
rb_scan_args(argc, argv, "12",&id,&text,&help);
wxWindowID wid(unwrapID(id));
if(check_title(wid,id,text))
{
wxMenuItem *item = _self->Prepend(wid,unwrap<wxString>(text),unwrap<wxString>(help),kind);
bind_callback(_self,item->GetId());
return wrap(item);
}
return Qnil;
}
/*
* call-seq:
* prepend_normal(id, text, [help]) -> WX::Menu::Item
* prepend_normal(id, text, [help]) {|event| ... } -> WX::Menu::Item
*
* prepends a new normal menu item to the Menu widget.
* when block is given, bind the block to the event of the menu item.
* ===Arguments
* * id of the menu item: Symbol/Integer/nil
* * text is the Label of the menu item. String (can be nil if id is one of the pre defined)
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when id is not a StockID and text is nil or empty
*
*/
DLL_LOCAL VALUE _prependNormalItem(int argc,VALUE *argv,VALUE self)
{
return _prepend_base(argc,argv,self,wxITEM_NORMAL);
}
/*
* call-seq:
* prepend_check(id, text, [help]) -> WX::Menu::Item
* prepend_check(id, text, [help]) {|event| ... } -> WX::Menu::Item
*
* prepends a new check menu item to the Menu widget.
* when block is given, bind the block to the event of the menu item.
* ===Arguments
* * id of the menu item: Symbol/Integer/nil
* * text is the Label of the menu item. String (can be nil if id is one of the pre defined)
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when id is not a StockID and text is nil or empty
*
*/
DLL_LOCAL VALUE _prependCheckItem(int argc,VALUE *argv,VALUE self)
{
return _prepend_base(argc,argv,self,wxITEM_CHECK);
}
/*
* call-seq:
* prepend_radio(id, text, [help]) -> WX::Menu::Item
* prepend_radio(id, text, [help]) {|event| ... } -> WX::Menu::Item
*
* prepends a new radio menu item to the Menu widget.
* when block is given, bind the block to the event of the menu item.
* ===Arguments
* * id of the menu item: Symbol/Integer/nil
* * text is the Label of the menu item. String (can be nil if id is one of the pre defined)
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when id is not a StockID and text is nil or empty
*
*/
DLL_LOCAL VALUE _prependRadioItem(int argc,VALUE *argv,VALUE self)
{
return _prepend_base(argc,argv,self,wxITEM_RADIO);
}
/*
* call-seq:
* prepend_menu(text, [help]) {|menu| ... } -> WX::Menu::Item
* prepend_menu(menu, text, [help]) -> WX::Menu::Item
*
* prepends a new sub menu item to the Menu widget.
* when block is given, it created a new menu and yields it into the block.
* ===Arguments
* * text is the Label of the menu item. String
* * help shown in WX::StatusBar. String
* ===Return value
* WX::Menu::Item
* === Exceptions
* [ArgumentError]
* * when either menu hasn't a title and text is empty
* [TypeError]
* * when menu is nil
*
*/
DLL_LOCAL VALUE _prepend_menu(int argc,VALUE *argv,VALUE self)
{
VALUE text,help,menu;
wxMenu *m = NULL;
if(rb_block_given_p()){
rb_scan_args(argc, argv, "11",&text,&help);
m = new wxMenu;
rb_yield(wrap(m));
}else{
rb_scan_args(argc, argv, "12",&menu,&text,&help);
if(!nil_check(menu,"menu"))
return Qnil;
m = unwrap<wxMenu*>(menu);
}
wxString wtext(unwrap<wxString>(text));
if(check_menu_mitle(m,wtext))
return wrap(_self->Prepend(wxID_ANY,wtext,m,unwrap<wxString>(help)));
return Qnil;
}
#if wxUSE_XRC
DLL_LOCAL VALUE _load_xrc(VALUE self,VALUE name)
{
return wrap(wxXmlResource::Get()->LoadMenu(unwrap<wxString>(name)));
}
#endif
}
}
#endif
DLL_LOCAL void Init_WXMenu(VALUE rb_mWX)
{
#if 0
rb_mWXEvtHandler = rb_define_module_under(rb_mWX,"EvtHandler");
#endif
#if wxUSE_MENUS
using namespace RubyWX::Menu;
rb_cWXMenu = rb_define_class_under(rb_mWX,"Menu",rb_cObject);
rb_define_alloc_func(rb_cWXMenu,_alloc);
#if 0
rb_define_attr(rb_cWXMenu,"title",1,1);
rb_define_attr(rb_cWXMenu,"parent",1,1);
rb_define_attr(rb_cWXMenu,"menubar",1,1);
#endif
rb_define_method(rb_cWXMenu,"initialize",RUBY_METHOD_FUNC(_initialize),-1);
rb_include_module(rb_cWXMenu,rb_mWXEvtHandler);
rb_include_module(rb_cWXMenu,rb_mEnumerable);
rb_define_attr_method(rb_cWXMenu,"title",_getTitle,_setTitle);
rb_define_attr_method(rb_cWXMenu,"parent",_getParent,_setParent);
rb_define_attr_method(rb_cWXMenu,"menubar",_GetMenuBar,_setMenuBar);
rb_define_method(rb_cWXMenu,"each",RUBY_METHOD_FUNC(_each),0);
rb_define_method(rb_cWXMenu,"append_normal",RUBY_METHOD_FUNC(_appendNormalItem),-1);
rb_define_method(rb_cWXMenu,"append_check",RUBY_METHOD_FUNC(_appendCheckItem),-1);
rb_define_method(rb_cWXMenu,"append_radio",RUBY_METHOD_FUNC(_appendRadioItem),-1);
rb_define_method(rb_cWXMenu,"append_menu",RUBY_METHOD_FUNC(_append_menu),-1);
rb_define_method(rb_cWXMenu,"append_separator",RUBY_METHOD_FUNC(_AppendSeparator),0);
rb_define_method(rb_cWXMenu,"insert_normal",RUBY_METHOD_FUNC(_insertNormalItem),-1);
rb_define_method(rb_cWXMenu,"insert_check",RUBY_METHOD_FUNC(_insertCheckItem),-1);
rb_define_method(rb_cWXMenu,"insert_radio",RUBY_METHOD_FUNC(_insertRadioItem),-1);
rb_define_method(rb_cWXMenu,"insert_menu",RUBY_METHOD_FUNC(_insert_menu),-1);
rb_define_method(rb_cWXMenu,"insert_separator",RUBY_METHOD_FUNC(_InsertSeparator),1);
rb_define_method(rb_cWXMenu,"prepend_normal",RUBY_METHOD_FUNC(_prependNormalItem),-1);
rb_define_method(rb_cWXMenu,"prepend_check",RUBY_METHOD_FUNC(_prependCheckItem),-1);
rb_define_method(rb_cWXMenu,"prepend_radio",RUBY_METHOD_FUNC(_prependRadioItem),-1);
rb_define_method(rb_cWXMenu,"prepend_menu",RUBY_METHOD_FUNC(_prepend_menu),-1);
rb_define_method(rb_cWXMenu,"prepend_separator",RUBY_METHOD_FUNC(_PrependSeparator),0);
rb_define_method(rb_cWXMenu,"get_item_label",RUBY_METHOD_FUNC(_getLabel),1);
rb_define_method(rb_cWXMenu,"set_item_label",RUBY_METHOD_FUNC(_setLabel),2);
rb_define_method(rb_cWXMenu,"get_item_help_string",RUBY_METHOD_FUNC(_getHelpString),1);
rb_define_method(rb_cWXMenu,"set_item_help_string",RUBY_METHOD_FUNC(_setHelpString),2);
rb_define_method(rb_cWXMenu,"get_item_checked",RUBY_METHOD_FUNC(_getChecked),1);
rb_define_method(rb_cWXMenu,"set_item_checked",RUBY_METHOD_FUNC(_setChecked),2);
rb_define_method(rb_cWXMenu,"get_item_enabled",RUBY_METHOD_FUNC(_getEnabled),1);
rb_define_method(rb_cWXMenu,"set_item_enabled",RUBY_METHOD_FUNC(_setEnabled),2);
rb_define_method(rb_cWXMenu,"[]",RUBY_METHOD_FUNC(_getItem),1);
rb_define_method(rb_cWXMenu,"<<",RUBY_METHOD_FUNC(_appendShift),1);
#if wxUSE_XRC
rb_define_singleton_method(rb_cWXMenu,"load_xrc",RUBY_METHOD_FUNC(_load_xrc),1);
#endif
registerEventType<wxCommandEvent>("menu",wxEVT_MENU);
registerInfo<wxMenu>(rb_cWXMenu);
#endif
}