//menu 菜单
namespace win.ui 

/******************************
                                 ┌────┐
                 ┌ ─ ─ ─ ─> │win.form│
                 │              └────┘
          ┌─────┐ menubase.add(lable,proc)
          │  menubase│ menubase.close()
          └─────┘ menubase.redraw()
            △    △
            /      \
           /        \　   ┌─┐
          /          \   1│　↓n
 ┌────┐       ┌─────┐
 │ menu   │ 1-->n │ popmenu  │popmenu.popup()
 └────┘       └─────┘
  
******************************/
 
var handle2menu = { @{ _weak = "kv" } }
//菜单基类
menubase = class {

	ctor( winform,resid,inst){
		if( ! winform[["hwnd"]] ){
			if(type(winform)==type.number){
				winform = {hwnd=winform;_mapCommandProc={}}
			}
			else {
				error("第一个构造参数必须指定有效窗口",3)
			} 
		} 
   		this.parent = winform; 
   		
   		if( type(resid) == type.number ){ 
   			if( type(inst) == type.string  ){
   				this.dll = ..raw.loadDll(inst);
   				inst = this.dll.gethandle();
   			}
   			this.handle = LoadMenu(inst,topointer(resid):resid); 
   			handle2menu[this.handle] = this;
   		}
   		else if( type(resid) == type.pointer ){ 
   			this.handle = resid;
   			handle2menu[this.handle] = this;
   		}  
   	}; 
   	 
   	//如果在第三个参数里传入 0x4/*_MF_BITMAP*/ 则第一个参数必须是位图句柄(指针)
	add = function(lable,proc,flag=0,id){  
    	var subMenu,bitmap,bmpUnchecked;
     	if( type(lable) == "table"){
     		bitmap = lable.bitmap;
     		bitmapCheckd = lable.bitmapCheckd; 
     		proc = lable.proc ;
     		flag = lable.flag : 0;
     		id = lable.id;
     		subMenu = lable.menu;
     		
     		lable = lable.text;
     	}
     	else if( type(proc)==type.table ){
     		subMenu = proc;
     		proc = null;
     	}
     			
    	if( !lable ){
         	AppendMenu(this.handle,0x800/*_MF_SEPARATOR*/, 0,null );
         	return;
     	}
     	
    	if( subMenu ){
    		if( ! subMenu[["handle"]] ){
    			subMenu = ..win.ui.popmenu( this.parent ).addTable( subMenu ,2 )  
			}  
         	AppendMenu(this.handle,0x10/*_MF_POPUP*/,tonumber(subMenu.handle),lable );
         	return subMenu; 
    	}
    	else{
    		if(!id)
    			id = this.parent._getFreeCommandId();
    		
    		if(proc){
    			if( type(proc)!=type.function) { 
    				error("参数二必须是一个回调函数",2	);
    			}
    				
    			this.parent._mapCommandProc[id] = proc; 
    		}
    		
    		AppendMenu(this.handle,0/*_MF_STRING*/ | flag,id ,lable );
    		if( bitmap || bitmapCheckd){
            	this.setBitmap(id,bitmap,bitmapCheckd,0x0/*_MF_BYCOMMAND*/)
        	}  
    		return id;
    	} 
    		
	} 
	addTable = function(args,lev=1){
		var arg;  
		for(i=1;#args;1){
			arg = args[i] 
			if(type(arg)!=type.table)
				error("包含无效的菜单项参数 " + tostring(arg),lev+1)
			
			if(#arg){	
				if( type(arg[2])==type.table && ( ! arg[2].handle) ){
					arg[2] = ..win.ui.popmenu( this.parent ).addTable( arg[2] ,lev+1 ) 
				} 
				this.add(arg[1],arg[2]  ,arg[3],arg[4]); 
			}
			else{
				if( arg.menu && ( ! arg.menu.handle) ){
					arg.menu = ..win.ui.popmenu( this.parent ).addTable( arg.menu ,lev+1 ) 
				} 
				this.add( arg ); 
			}
		} 
		return this;  
	}  
	insert = function(position=1 ,lable,proc,flag=0x400/*_MF_BYPOSITION*/,id){
		var subMenu,bitmap,bmpUnchecked;
     	if( type(position) == "table"){
     		bitmap = position.bitmap;
     		bitmapCheckd = position.bitmapCheckd;
     		lable = position.text;
     		proc = position.proc;
     		flag = position.flag : 0x400/*_MF_BYPOSITION*/;
     		id = position.id;
     		subMenu = position.menu;
     		
     		position = position.position;
     	}
     	else if( type(proc)==type.table ){
     		subMenu = proc;
     		proc = null;
     	}
     	
		var realpos = position; 
		if( flag&0x400==0x400 ){
			position = position - 1; 
		} 
		 
		if( !lable ){
         	InsertMenu(this.handle,position,0x800/*_MF_SEPARATOR*/| flag, 0,null );
         	return;
     	}
     	 
    	if(  subMenu ){
    		if( ! subMenu[["handle"]] ){
    			subMenu = ..win.ui.popmenu( this.parent ).addTable( subMenu ,2 )  
			}  
         	InsertMenu(this.handle,position,0x10/*_MF_POPUP*/| flag,tonumber(subMenu.handle),lable );
    	}
    	else{
    		if( (proc!==null) ? type(proc)!=type.function)
    			error("参数二必须是一个回调函数",2) ;
    			
    		if(!id)
    			id = this.parent._getFreeCommandId();
    	 
    		this.parent._mapCommandProc[id] = proc : this.oncommand; 
    		InsertMenu(this.handle,position,0/*_MF_STRING*/ | flag,id ,lable );
    		if( bitmap || bitmapCheckd){
            	this.setBitmap(id,bitmap,bitmapCheckd,0x0/*_MF_BYCOMMAND*/)
        	}    
    		return id;
    	}
	}
	delete = function(position,flag=0x400/*_MF_BYPOSITION*/){
		this.reset(null,position,flag);
		if( flag&0x400==0x400 ){ 
			position = position - 1;  
		}   
		return DeleteMenu(this.handle, position, flag); 
	}
	remove = function(position,flag=0x400/*_MF_BYPOSITION*/){
		this.reset(null,position,flag);
		if( flag&0x400==0x400 ){ 
			position = position - 1;  
		}   
		return RemoveMenu(this.handle, position, flag); 
	}  
	getSubMenu = function(position){
		var h = GetSubMenu(this.handle,position);
		return h ? handle2menu[h] : ..win.ui.menubase( this.parent,h );
	} 
	getId = function(position,flag=0x400/*_MF_BYPOSITION*/){
		if( flag&0x400==0x400 ){
			return GetMenuItemID(this.handle,position-1);
		}  
		return position;
	}   
	getPos = function(id,flag=0x0/*_MF_BYCOMMAND*/){
		if( flag&0x400==0x400 ){
			return id;
		}  
		for(i=1;this.count() ){ 
			if(this.getId(i)==id)
				return i;	 
		} 
	} 
	count = function(){
		return GetMenuItemCount(this.handle);
	}
	reset = function(proc,position=1 ,flag=0x400/*_MF_BYPOSITION*/){
		var id = this.getId(position,flag);
		if(id)
			this.parent._mapCommandProc[id] = proc;
	}  
	close = function(){
		handle2menu[this.handle] = null;
		DestroyMenu(this.handle)
		
		//如果是主菜单
		if( this._onClose ){ 
		    this._onClose(); 
		}
		this.handle = null;
	} 
	check = function(id,chk=true,flag=0x400/*_MF_BYPOSITION*/){ 
		chk = chk ? 0x8/*_MF_CHECKED*/ : 0x0/*_MF_UNCHECKED*/ 
		CheckMenuItem(this.handle,flag&0x400==0?id:id-1,flag | chk );
	}
	enable = function(id,enb=true,flag=0x400/*_MF_BYPOSITION*/ ){ 
		if( enb === false)
			enb =   0x1/*_MF_GRAYED*/ 
		else
			enb = 0;
		EnableMenuItem(this.handle,flag&0x400==0?id:id-1,flag | enb );
	}
	checked = function(id ,flag=0x400/*_MF_BYPOSITION*/){
		return ( GetMenuState(this.handle,flag&0x400==0?id:id-1, flag ) & 0x8/*_MF_CHECKED*/ ) == 0x8/*_MF_CHECKED*/
	} 
	getString = function(id,flag=0x400/*_MF_BYPOSITION*/){
		var len,str = GetMenuString(this.handle,flag&0x400==0?id:id-1, 128,128,flag ) 
		if(len)return str;
	}
	setString = function(id,str,flag=0x400/*_MF_BYPOSITION*/){
		var len,str = ModifyMenuString(this.handle,flag&0x400==0?id:id-1, flag | 0x0/*_MF_STRING*/,this.getId(id,flag),str) 
		if(len)return str;
	};
	setBitmap = function(position,bitmap,bmpUnchecked,flag=0x400/*_MF_BYPOSITION*/){
    	if( type(bitmap) == "string") {
    		var img = ..com.picture.load(bitmap);//转化为句柄
    		bitmap = img.CopyHandle();
    	}
    	if( type(bitmapCheckd) == "string") {
    		var img = ..com.picture.load(bitmapCheckd);//转化为句柄
    		bitmapCheckd = img.CopyHandle();
    	}
    	
    	return SetMenuItemBitmaps(this.handle,this.getId(position,flag),0x111/*_WM_COMMAND*/,bitmap,bitmapCheckd);
	};
	click = function(position,flag=0x400/*_MF_BYPOSITION*/){ 
		::PostMessage(this.parent.hwnd, 0x111/*_WM_COMMAND*/,this.getId(position,flag) ,0);
	}   
}
var menubase = menubase;

namespace menubase{ 
	
	ModifyMenuString = ::User32.api("ModifyMenuA","int(pointer menu,int nPosition,int wFlags,int wIDNewItem,string lpString)")
	GetMenuString = ::User32.api("GetMenuStringA","int(pointer menu,int wIDItem,str& lpString,int nMaxCount,int wFlag)")
	AppendMenu = ::User32.api("AppendMenuA","int(pointer menu,INT flags,INT newId,string newItem)" ) 
	InsertMenu = User32.api("InsertMenuA","int(pointer menu,INT position,INT flag,INT idNew,str newItem)");
	DestroyMenu  = ::User32.api("DestroyMenu","int(pointer menu)" ) 
	
	GetMenuState = ::User32.api("GetMenuState","int(pointer menu,int wID,int wFlags)")
	CheckMenuItem = User32.api("CheckMenuItem","INT(pointer menu,INT uIDCheckItem,INT uCheck)");
	EnableMenuItem = User32.api("EnableMenuItem","INT(pointer menu,INT uIDEnableItem,INT uEnable)");
	DeleteMenu = ::User32.api("DeleteMenu","int(pointer menu,int position,int flags)")
	RemoveMenu = ::User32.api( "RemoveMenu", "bool(pointer menu,INT position,INT flags)");
	GetMenuItemID = ::User32.api("GetMenuItemID","int(pointer menu,int nPos)")
	
	LoadMenu = ::User32.api("LoadMenuA","pointer(pointer hinst,string string)") 
	GetSubMenu = ::User32.api("GetSubMenu","pointer(pointer menu,int position)")
	GetMenuItemCount = ::User32.api("GetMenuItemCount","int(pointer menu)")
	
	SetMenuItemBitmaps = ::User32.api("SetMenuItemBitmaps","bool(pointer menu,int position,int flags,pointer hBmp,pointer hBmpChecked)")
}
 
menu = class{
	ctor( winform,resid,inst )begin 
		if(winform[["menu"]])
    		winform.menu.close(); 
    	
   		this = menubase(winform,resid,inst);//继承基类
   		
   		if(!this.handle){
   			this.handle = ::CreateMenu();
   			handle2menu[this.handle] = null;
   		}
    	SetMenu(winform.hwnd,this.handle);  
    	winform.menu = this;
	end; 
	
	redraw = function(){
		DrawMenuBar(this.parent.hwnd);
	}
	_onClose = function(){
		SetMenu(this.parent.hwnd,null );
		this.parent.menu = null; //取消绑定
		this.redraw()
	}  
}

//类有独立的名字空间
namespace menu{
	SetMenu = ::User32.api("SetMenu","int(int hWnd,pointer menu)" ) 
	CreateMenu =  User32.api("CreateMenu","pointer()" )
	DrawMenuBar = User32.api("DrawMenuBar","int(int hWnd)" ) 
}
 
popmenu = class{
	
	ctor( winform,resid,inst ) { 
   		this = menubase(winform,resid,inst);//继承基类 
   		winform = this.parent;
   		
   		if(!this.handle){
   			this.handle = CreatePopupMenu(); 
   			handle2menu[this.handle] = null;
   		}
	}  
 
	popup = function(x,y,screen,flag=2){  
		//在指定坐标(x,y)弹出菜单
		if( type(x) == type.table ) {
			y = x.y;
			x = x.x;
		}
		elseif( !(x && y ) ){
			x,y = ..win.getMessagePos();
			screen = true;
		}
		 
		if( (type(x)!=type.number) || (type(y) != type.number) )
			error("菜单弹出坐标必须是数字",2)
		
		var pt = ::POINT();
		pt.x = x;
		pt.y = y;
		
		if(!screen){
			::ClientToScreen( this.parent.hwnd,pt);
		} 
		return TrackPopupMenu( this.handle,flag ,pt.x,pt.y , 0,this.parent.hwnd,null);
	} 
	popId = function(x,y,screen,flag = 0x2){ 
		return this.popup(x,y,screen,flag | 0x0100/*_TPM_RETURNCMD*/)
	}
	fireId = function(id,hwnd,...){ 
		var func = id ? this.parent._mapCommandProc[id];
		if( func ){ 
			func(id,hwnd,...);	
		}
		else{ 
			::PostMessage( hwnd[["hwnd"]] : hwnd : this.parent.hwnd, 0x111/*_WM_COMMAND*/, id,0)
		}
	}   
}

//类有独立的名字空间
namespace popmenu { 
	CreatePopupMenu := ::User32.api("CreatePopupMenu","pointer()" )
	TrackPopupMenu := User32.api("TrackPopupMenu","int(pointer menu,INT uFlags,int x,int y,int nReserved,int hWnd, pointer prcRect)" ) 
}

var getSystemMenuA = ::User32.api( "GetSystemMenu", "pointer(int hwnd,bool revert)")
var getMenuA = ::User32.api("GetMenu","int(int hwnd)")
getSysMenu = function(winform,revert=false){
	var hmenu = getSystemMenuA( winform[["hwnd"]] : winform, revert );
	return popmenu(winform,hmenu)
} 
getMenu = function( winform ){
	var hmenu = getMenuA( winform[["hwnd"]]  );
	return menu(winform,hmenu)
} 
 
/**intellisense()
!menu.handle = 菜单句柄
!menu.redraw() = 重绘菜单 
!menu.add() = 添加分隔线 
!menu.add(标题,回调函数) = @.add("菜单标题",function(){\n	__/*回调函数*/\n	\n})
!menu.add(参数表) = @.add(\n	text = "标题";\n	bitmap = "位图句柄或路径、或图像数据,可选参数";\n	bitmapCheckd = "选中位图句柄或路径、或图像数据,可选参数";\n	proc = function(id){\n		__/*回调函数*/\n	};\n	id = 可选参数;\n	flag = 可选参数;\n};
!menu.addTable = @.addTable( {\n	{ "菜单文本";  function(id){\n		__/*菜单事件回调函数*/\n	} }; { /*分隔线*/ }\n	{ "退出程序"; function(id){  \n		winform.close() \n 	} };\n} )
!menu.insert( 1__ ) = 在指定位置插入分隔线
!menu.insert(位置,标题,回调函数) = @.insert(1,"菜单标题",function(){\n	__/*回调函数*/\n	\n})
!menu.insert(参数表) = @.insert(\n	position = 1;\n	text = "标题";\n	bitmap = "位图句柄或路径、或图像数据,可选参数";\n	bitmapCheckd = "选中位图句柄或路径、或图像数据,可选参数";\n	proc = function(id){\n		__/*回调函数*/\n	};\n	id = 可选参数;\n	flag = 可选参数;\n};
!menu.delete( 1__ ) = 删除指定位置菜单\n被移除的如果是子菜单则销毁,不可重用
!menu.delete( 1__,0x0/*_MF_BYCOMMAND*/) = 删除指定ID菜单\n被移除的如果是子菜单则销毁,不可重用
!menu.remove( 1__ ) = 移除指定位置菜单\n被移除的如果是子菜单并不销毁,可重用
!menu.remove( 1__,0x0/*_MF_BYCOMMAND*/) = 移除指定ID菜单\n被移除的如果是子菜单并不销毁,可重用
!menu.getId( 1__ ) = 返回指定位置菜单ID 
!menu.click( 1__ ) = 模拟点击指定位置菜单
!menu.getPos( id__ ) = 根据菜单ID返回菜单位置
!menu.count() = 返回菜单子项数目
!menu.getSubMenu(1__) = 返回指定位置子菜单
!menu.getSubMenu() = !menu.
!menu.reset(.(新的回调函数,菜单位置) = 重设菜单回调函数 
!menu.reset(.(新的回调函数,菜单ID,0x0/*_MF_BYCOMMAND*/) = 重设菜单回调函数
!menu.close() = 关闭菜单
!menu.check(.(菜单项序号) =选中菜单项
!menu.check(.(菜单项序号,false) =取消选中菜单项
!menu.enable(.(菜单项序号) = 启用菜单项
!menu.enable(.(菜单项序号,false) = 禁用菜单项
!menu.checked(__/*菜单项序号*/) = 返回菜单项是否选中状态 
!menu.getString(__/*菜单项序号*/) = 返回菜单文本
!menu.setString(__/*菜单项序号*/,"") = 设置菜单文本
!menu.setBitmap(.(菜单序号或ID,位图,选中位图) = 选中位图为可选参数,\n图像可以是句柄指针,也可以是图像文件路径或数据
!popmenu.handle = 菜单句柄
!popmenu.add() = 添加分隔线
!popmenu.add(标题,回调函数) = @.add("菜单标题",function(){\n	__/*回调函数*/\n	\n})
!popmenu.add(参数表) = @.add(\n	text = "标题";\n	bitmap = "位图句柄或路径、或图像数据,可选参数";\n	bitmapCheckd = "选中位图句柄或路径、或图像数据,可选参数";\n	proc = function(id){\n		__/*回调函数*/\n	};\n	id = 可选参数;\n	flag = 可选参数;\n};
!popmenu.addTable = @.addTable( {\n	{ "菜单文本";  function(id){\n		__/*菜单事件回调函数*/\n	} }; { /*分隔线*/ }\n	{ "退出程序"; function(id){  \n		winform.close() \n 	} };\n} )
!popmenu.insert( 1__ ) = 在指定位置插入分隔线
!popmenu.insert(位置,标题,回调函数) = @.insert(1,"菜单标题",function(){\n	__/*回调函数*/\n	\n})
!popmenu.insert(参数表) = @.insert(\n	position = 1;\n	text = "标题";\n	bitmap = "位图句柄或路径、或图像数据,可选参数";\n	bitmapCheckd = "选中位图句柄或路径、或图像数据,可选参数";\n	proc = function(id){\n		__/*回调函数*/\n	};\n	id = 可选参数;\n	flag = 可选参数;\n};
!popmenu.delete( 1__ ) = 删除指定位置菜单\n被移除的如果是子菜单则销毁,不可重用
!popmenu.delete( 1__,0x0/*_MF_BYCOMMAND*/) = 删除指定ID菜单\n被移除的如果是子菜单则销毁,不可重用
!popmenu.remove( 1__ ) = 移除指定位置菜单\n被移除的如果是子菜单并不销毁,可重用
!popmenu.remove( 1__,0x0/*_MF_BYCOMMAND*/) = 移除指定ID菜单\n被移除的如果是子菜单并不销毁,可重用
!popmenu.getId( 1__ ) = 返回指定位置菜单ID
!popmenu.click( 1__ ) = 模拟点击指定位置菜单
!popmenu.getPos( id__ ) = 根据菜单ID返回菜单位置
!popmenu.count() = 返回菜单子项数目
!popmenu.getSubMenu(1__) = 返回指定位置子菜单
!popmenu.getSubMenu() = !menu.
!popmenu.reset(.(新的回调函数,菜单位置) = 重设菜单回调函数
!popmenu.reset(.(新的回调函数,菜单ID,0x0/*_MF_BYCOMMAND*/) = 重设菜单回调函数
!popmenu.fireId(.(id,hwnd) = 调用菜单回调函数\n可选指定接收命令的窗体句柄\n可添加任意个附加参数
!popmenu.close() = 关闭菜单
!popmenu.check(.(菜单项序号) =选中菜单项
!popmenu.check(.(菜单项序号,false) =取消选中菜单项
!popmenu.enable(.(菜单项序号) = 启用菜单项
!popmenu.enable(.(菜单项序号,false) = 禁用菜单项
!popmenu.checked(__/*菜单项序号*/) = 返回菜单项是否选中状态 
!popmenu.getString(__/*菜单项序号*/) = 返回菜单项文本
!popmenu.setString(__/*菜单项序号*/,"") = 设置菜单项文本
!popmenu.setBitmap(.(菜单序号或ID,位图,选中位图) = 选中位图为可选参数,\n图像可以是句柄指针,也可以是图像文件路径或数据
!popmenu.popup(.(x坐标,y坐标,是否屏幕坐标=false) = 弹出菜单\n如果不指定坐标,则自动调用 win.getMessagePos() 获取消息坐标
!popmenu.popId(.(x坐标,y坐标,是否屏幕坐标=false) = 弹出菜单\n并返回用户点选ID\n未选择或发生错误则返回零 
?win.ui.menu = !menu.
win.ui.menu() = !menu.
win.ui.getSysMenu()  = !popmenu.
?win.ui.getMenu = !menu.
?win.ui.popmenu = !popmenu.
win.ui.popmenu() = !popmenu.
?.getSubMenu = !menu.
win.ui.menu() = !menu.
win.ui.getMenu() = !menu.
win.ui.getMenu(hwnd) = 返回窗口菜单
win.ui.getSysMenu(hwnd) = 返回系统菜单
win.ui.getSysMenu(hwnd,true) = 返回系统菜单\n并重置为缺省状态
win.ui.menu = 菜单支持库
win.ui.menu(.(窗口) = 创建窗口菜单
win.ui.menu(.(窗口,菜单句柄) = 使用存在的菜单句柄创建菜单对象
win.ui.popmenu(.(窗口) = 创建弹出菜单
win.ui.popmenu(.(窗口,菜单句柄) = 使用存在的菜单句柄创建弹出菜单对象
_MENU_ITEM_IS_SUBMENU = @0xFFFFFFFF/*_MENU_ITEM_IS_SUBMENU*/
end intellisense**/
