//message 简单信息框
//光庆封装
//..godking.message._version := 3.5;
//..godking.message._date := "2024-03-05";

/*****
	参考文档： https://blog.csdn.net/sdlgq/article/details/129294167
	更新日志：
	3.5		信息框去掉阴影，避免出现窗口隐藏时阴影残留的问题。
	3.4.3 	增加信息框实例对winform的操作。
	3.4.2 	修复 提示信息高度自动调整后挡住progress进度的问题。
	3.4.1 	修复 topmost 导致窗口启动的时候闪烁一下的问题。
	3.4.0 	修正 this.trasparent 初始值为100。
	3.3.9 	修正 input() 在不同dpi下的错位问题。修正 winform.msgXX() 系列函数失效的问题。
	3.3.8 	增加 escClose 属性。
	3.3.7 	增加创建屏幕右下角弹出提示框组功能。
	3.3.6 	设置窗口在最前，增加透明度和鼠标穿透功能。
	3.3.5 	增强 进度条 窗口，增加 getPlus() 函数。
	3.3.4 	调整 select 的默认选中值，支持选项内容。
	3.3.3 	调整dpi缩放相关算法。
	3.3.2 	select函数添加选中值数组参数
*****/

import win.ui;
import fonts.fontAwesome;
import win.ui.ctrl.plus;
import win.region.round;
import gdi;

/*信息框窗口类{{*/
class simpleWindow_godking{
	ctor( winform,fontSize,width=33,height=27,marginRight=0,marginTop=0){{
		this.targetForm = winform._parentForm || winform;
		var ws = ..win.getStyle(this.targetForm.hwnd);
		var font = LOGFONT(name='Marlett';charset=2/*_SYMBOL_CHARSET*/;h=fontSize); 
		winform.add(
			titlebarClose={cls="plus";text="r";top=marginTop;height=height;width=width;marginRight=marginRight;dr=1;dt=1;font=font;z=3}; 
			titlebar={cls="static";text="";left=0;top=marginTop;marginRight=width*3+marginRight;bottom=height*2;dl=1;dr=1;dt=1;notify=1;center=1;clip=1;transparent=1;z=4}
		)
		winform.titlebarClose.skin(style);
		winform.titlebarClose.oncommand = function(id,event){
			this.targetForm.close()
		};
		if( ws & 0x20000/*_WS_MINIMIZEBOX*/ ){
			winform.add( 
				titlebarMin={cls="plus";text="0";top=marginTop;height=height;width=width;marginRight=width+marginRight;dr=1;dt=1;font=font;z=2}; 
			)
			winform.titlebarMin.skin(style); 
			winform.titlebarMin.oncommand = function(id,event){
				this.targetForm.hitMin()
			}
		}
		winform.titlebar.wndproc = {
			[ 0x201/*_WM_LBUTTONDOWN*/ ] = function(hwnd,message,wParam,lParam){
				this.targetForm.hitCaption();
			} 
		}
		..win.setPos(winform.titlebar.hwnd,,,,,0x1/*_HWND_BOTTOM*/);
		this._form = winform;
		this.titlebarClose = winform.titlebarClose; 
		this.titlebarMin = winform.titlebarMin;
		this.titlebar = winform.titlebar;
	}};
	skin = function(style){
		if(this.titlebarMin) this.titlebarMin.skin(style);
		this.titlebarClose.skin(style);
	};
}
namespace simpleWindow_godking{
    style = {  
		background = { 
			hover = 0xff99ffcc;
			active = 0xffff6666; 
			default = 0x00000000; 
		}
		color = { 
			hover = 0xff666666;
			active = 0xffffffff; 
			default = 0xffffffff; 
		}
	}
}
/*}}*/

namespace godking;
class message{
	ctor(parent){ 
		this.parent = parent : ..win.getActive(); 
		this.icon = null;
		this.iconColor = null;
		this.textColor = 0x000000;
		this.bgcolor = 0xFFFFFF;
		this.btnBgColor = 0x7FBF67;
		this.progressBgColor = 0xFFeeeeee;
		this.progressForeColor = 0xFF00ee00;
		this.progressBorderColor = 0xFF00ee00;
		this.progressTextColor = 0xFF000000;
		this.fadeInterval = 12;
		this.fadeDuration = 400;
		this.cancelIcon = '\uF00D'
		this.cancelLabel = '取消';
		this.okIcon = '\uF00C'
		this.okLabel = '确定';
		this.colseUp = true;
		this.noFocus = false;
		this.showTitlebar = true;
		this.round = 0;
		this.pos = null;
		this.showOK = true;
		this.minWidth = 300;
		this.borderWidth = 1;
		this.borderColor = 0x55000000;
		this.modalMode = true;
		this.transparent = 100;
		this.layered = false;
		this.topmost = false;
		this.escClose = true;
		this.trasparent = 100;
		this.disableClose = function(){
			this.escClose = false
			this.modalMode = false
		}
		
		this.buttonStyle = { 
			color = {  
				default = 0xFFFFFFFF;
				hover = 16#FFFFFDC2;
				active = 16#FFFFFDC2;
			} 
			border = {
				default = {width=0;}
				hover = { bottom = 2;color= 16#FFFFFDC2; }
				active = { bottom = 2;color= 16#FFFFFDC2; }
			} 
		}
		this.titlebarStyle = { 
			color = {  
				default = 0xFFAAAAAA;
				hover = 0xFFFF0000;
				active = 0xFFFF0000;
			} 
		}
		var fade = function(winform,duration=400,interval=12){
			if(duration<interval){
				if this.trasparent<100 winform.transparent(this.transparent*2.55);
				if this.layered	winform.modifyStyleEx(,0x80000/*_WS_EX_LAYERED*/|0x20/*_WS_EX_TRANSPARENT*/);
				winform.show(); 
				return;
			}
			if this.layered	winform.modifyStyleEx(,0x80000/*_WS_EX_LAYERED*/|0x20/*_WS_EX_TRANSPARENT*/);
			winform.transparent( 1 ); 
			winform.show(); 
			var easeOutQuad = function (timestamp,beginning,change,duration){
				var x = timestamp/duration;
				return beginning+change*(-x*x + 2*x);
			}		
			var timestamp = 0;
			winform.setInterval(
				function(){
					var trans = easeOutQuad( timestamp, 0, 255, duration);
					timestamp = timestamp + interval;
					if ( trans > this.transparent*2.55 )  return false;
					winform.transparent( trans );
					if( trans > 245 ){
						winform.transparent(false);
						return false;
					}
				},interval
			)
			if this.escClose {
				winform.onClose = function(hwnd,message,wParam,lParam){
					var timestamp = 0;
					var shadow = winform._shadowWindow;
					var tmId = winform.setInterval( 
						function(){
							var trans = easeOutQuad( timestamp, 255,-255 , duration);
							timestamp = timestamp + interval;
							if trans<=this.transparent*2.55 {
								if(trans<=200 && shadow){
									shadow._form.close(); 
									shadow = null;
								}
								winform.transparent( trans ) ;
								if( trans < 10 ){
									winform.onClose = null;
									winform.close(); 
									return false;
								}
							}
						} ,interval
					)  
					return false
				}
			} else {
				winform.onClose = function(){
					return true; 
				}			
			}
		}; 
	};
	create = function(msg,showButtons,show){ 
		if (!#msg) error("文本不能为空",2);
		if this.iconColor !== null and this.iconColor&0xFF000000 this.iconColor=..gdi.rgbReverse(this.iconColor);
		if this.textColor !== null and this.textColor&0xFF000000 this.textColor=..gdi.rgbReverse(this.textColor);
		if this.bgcolor !== null and this.bgcolor&0xFF000000 this.bgcolor=..gdi.rgbReverse(this.bgcolor);
		if this.btnBgColor !== null and this.btnBgColor&0xFF000000 this.btnBgColor=..gdi.rgbReverse(this.btnBgColor);
		var parentForm = this.parent;
		if(parentForm){
			if( !..win.isWindow(this.parent[["hwnd"]] || this.parent) ){
				parentForm = ..win.getActive() || ..mainForm[["hwnd"]];
			}	
		}
		var winform = ..win.form(text="提示：";right=830;bottom=680;bgcolor=this.bgcolor;border="none";exmode="toolwindow";min=false;parent=parentForm;);
		if !winform	return;
		winform.add(
			icon={cls="plus";text=this.icon:this.form_icon;left=10;top=10;right=80;bottom=62;color=this.iconColor===null?this.form_iconColor:this.iconColor;dl=1;dt=1;font=LOGFONT(name='FontAwesome';h=-37);z=1};
			message={cls="plus";text=msg;left=80;top=24;right=777;bottom=654;align="left";color=this.textColor;dl=1;dr=1;dt=1;db=0;font=LOGFONT(h=-16);valign="top";z=2}; 
		);
		if( showButtons or this.showOK ){ 
			this.cancelIcon :="";
			this.cancelLabel :="";
			this.okIcon :="";
			this.okLabel:="";
			winform.add( 
				bk={cls="bk";left=0;top=620;right=831;bottom=681;db=1;dl=1;dr=1;forecolor=this.btnBgColor;z=1};
			);
			if showButtons {
				winform.add( 
					btnOk={cls="plus";text=this.okLabel;iconText=this.okIcon;left=280;top=630;right=350;bottom=670;color=16777215;db=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};textPadding={left=16};notify=1;z=3};
					btnCancel={cls="plus";text=this.cancelLabel;iconText=this.cancelIcon;left=480;top=630;right=550;bottom=670;color=16777215;db=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-16;name='FontAwesome')};textPadding={left=16};notify=1;z=4};
				);
			} else {
				winform.add( 
					btnOk={cls="plus";text=this.okLabel;left=300;top=630;right=400;bottom=670;color=16777215;db=1;font=LOGFONT(h=-16);notify=1;z=3};
				);
			}
			if winform.btnOk {
				winform.btnOk.oncommand = function(id,event){
					if winform.timerid winform.clearTimeout(winform.timerid);
					winform.timerid = null;
					winform.endModal(true);
				} 
				winform.btnOk.skin( this.buttonStyle );
			}
			if winform.btnCancel {
				winform.btnCancel.oncommand = function(id,event){
					if winform.timerid winform.clearTimeout(winform.timerid);
					winform.timerid = null;
					winform.endModal();
				}
				winform.btnCancel.skin( this.buttonStyle );
			}			
		}
		if this.escClose {
			winform.onOk = function(){
				if winform.timerid winform.clearTimeout(winform.timerid);
				winform.timerid = null;
				winform.endModal(true);
			}
			if this.escClose {
				winform.onCancel = function(){
					if winform.timerid winform.clearTimeout(winform.timerid);
					winform.timerid = null;
					winform.endModal();
				}
			} 
		}else {
			winform.onClose = function(){
				return true; 
			}
		}
		winform.onDestroy = function(){
			if this.destroyCallback this.destroyCallback(winform);
		}
		//根据文字长度,自动调整窗口宽度
		var rect = winform.message.measureString();
		var width = winform.message.left + rect.width + 50;
		if ( width < this.minWidth ) width = this.minWidth;
		winform.width = width;
		var height = winform.message.top + rect.height;
		if ( showButtons or this.showOK ) {
			height = height + winform.btnOk.height + 50;
			if showButtons {
				winform.btnOk.left= width/2-10-winform.btnOk.width;
				winform.btnOk.right = winform.btnOk.left+70;
				winform.btnCancel.left= width/2+10;
				winform.btnCancel.right= winform.btnCancel.left+70;
			} elseif this.showOK {
				winform.btnOk.left= width/2-35;
				winform.btnOk.right = winform.btnOk.left+70;
			}
		} else {
			height = height + 25;
		}
		winform.height = height;
		winform.message.width = rect.width +20;
		winform.message.height = rect.height +5;
		if( ..string.indexOf(msg,'\n') ){
			winform.message.valign="top";
			winform.icon.valign="top";
			winform.icon.top = winform.message.top;
		}
		winform.enableDpiScaling("init");
		if this.showTitlebar { //显示标题栏，就不能使用圆角窗口，不然角部有阴影
			var sw = ..simpleWindow_godking(winform,,,,this.borderWidth,this.borderWidth);
			sw.skin(this.titlebarStyle);
		} elseif this.round {
			..win.region.round(winform,,,this.round,this.round);
		}
		if this.borderWidth {
			var radius = !this.showTitlebar?(this.round?(this.round/2):0):0;
			winform.add(
				{
					borderPlus={cls="plus";dl=1;dt=1;dr=1;db=1;left=0;top=0;right=winform.width;bottom=winform.height;border={color=this.borderColor;radius=radius;width=this.borderWidth};clipBk=false;z=100};
				}
			)
		}
		winform.resize();
		if type(this.pos)==type.table {
			if this.pos.x!==null and this.pos.y!==null winform.setPos(this.pos.x,this.pos.y);
			elseif #this.pos>1 winform.setPos(this.pos[1],this.pos[2]);
		} else {
			winform.center(parentForm);
		}
		winform.showself = function(){
			if(this.fadeInterval) fade(winform,this.fadeDuration,this.fadeInterval);
			else {
				if this.trasparent<100 winform.transparent(this.trasparent*2.55);
				if this.layered	winform.modifyStyleEx(,0x80000/*_WS_EX_LAYERED*/|0x20/*_WS_EX_TRANSPARENT*/);
			}
		}
		if show winform.showself();
		winform.waitClose = function(){
			while(::User32.IsWindow(winform.hwnd)){
				..win.delay(1);
			}
		}
		winform.isExist = function(){
			return ::User32.IsWindow(winform.hwnd);
		}
		winform._close_raw := winform.close;
		winform.close = function(){
			winform.onClose = function(hwnd,message,wParam,lParam){
				var timestamp = 0;
				var shadow = winform._shadowWindow;
				var easeOutQuad = function (timestamp,beginning,change,duration){
					var x = timestamp/duration;
					return beginning+change*(-x*x + 2*x);
				}						
				var tmId = winform.setInterval( 
					function(){
						var trans = easeOutQuad( timestamp, 255,-255 , this.fadeDuration);
						timestamp = timestamp + this.fadeInterval;
						if trans<=this.transparent*2.55 {
							if(trans<=200 && shadow){
								shadow._form.close(); 
								shadow = null;
							}
							winform.transparent( trans ) ;
							if( trans < 10 ){
								winform.onClose = null;
								winform._close_raw(); 
								return false;
							}
						}
					} ,this.fadeInterval
				)  
				return false;
			}
			winform._close_raw();
		}
		if this.topmost {
			::SetWindowPos(winform.hwnd,-1,0,0,0,0,2/*_SWP_NOMOVE*/|1/*_SWP_NOSIZE*/|0x10/*_SWP_NOACTIVATE*/ );
		}
		return winform;	
	}
	createAndShow = function(modal,msg,showButtons,timeOut){
		if(!#msg) error("文本不能为空",2);
		var dlg = this.create(msg,showButtons);
		if(!dlg) return;
		if dlg.borderPlus {
			dlg.borderPlus.bottom = dlg.height;
			dlg.borderPlus.right = dlg.width;
		}		
		if(timeOut){ 
			if(this.fadeInterval) timeOut = timeOut+this.fadeDuration;
			if this.colseUp {
				dlg.timerid = dlg.setTimeout(function(){
						if dlg.btnOk dlg.btnOk.disabled = true;
						for(i=1;15;1){
							if 255-16*i < this.transparent*2.55	dlg.transparent(255-16*i);
							var l,t = dlg.getPos();
							dlg.setPos(l,t-8);
							if !..win.delay(10) ..win.quitMessage();
						}
						dlg.transparent(0);
						dlg.show(false);
						dlg.endModal();	
					},timeOut
				)
			} else {
				dlg.timerid = dlg.setTimeout(λ()dlg.endModal(),timeOut);
			}
		}
		dlg.showself();
		if modal===false return dlg; 
		if modal or this.modalMode 	return dlg.doModal();
		return dlg; 
	}
	info = function(msg,timeOut){
		this.form_icon = '\uF05A';
		this.form_iconColor = 0xD4883B;
		return this.createAndShow(null,msg,,timeOut);
	}
	warn = function(msg,timeOut){
		this.form_icon = '\uF071'
		this.form_iconColor = 0x5654E0;
		return this.createAndShow(null,msg,,timeOut);
	}
	ok = function(msg,timeOut){
		this.form_icon = '\uF046'
		this.form_iconColor = 0x54CC2E;
		return this.createAndShow(null,msg,,timeOut);
	}
	err = function(msg,timeOut){
		this.form_icon = '\uF05C'
		this.form_iconColor = 0x5654E0;
		return this.createAndShow(null,msg,,timeOut);
	}
	great = function(msg,timeOut){ 
		this.form_icon = '\uF164'
		this.form_iconColor = 0x54CC2E;
		return this.createAndShow(null,msg,,timeOut);
	}
	sorry = function(msg,timeOut){ 
		this.form_icon = '\uF165'
		this.form_iconColor = 0xD4883B;
		return this.createAndShow(null,msg,,timeOut);
	}
	smile = function(msg,timeOut){ 
		this.form_icon = '\uF118'
		this.form_iconColor = 0x54CC2E;
		return this.createAndShow(null,msg,,timeOut);
	}
	frown = function(msg,timeOut){ 
		this.form_icon = '\uF119'
		this.form_iconColor = 0xD4883B;
		return this.createAndShow(null,msg,,timeOut);
	}
	ask = function(msg){ 
		this.form_icon = '\uF059'
		this.form_iconColor = 0xD4883B;
		return this.createAndShow(true,msg,true);
	}
	link = function(text,callback,timeOut){
		this.form_icon = '\uF05A';
		this.form_iconColor = 0xD4883B;
		var msg = this.createAndShow(false,text,,timeOut);
		msg.message.skin(
			color = { 
				default = 0xFF000000;
				hover = 0xFFFF0000;
				active = 0xFFFF0000;
			}
		)
		if type(callback)==type.function {
			msg.message.oncommand = function(id,event){
				callback();
				msg.close();
			}
		}elseif type(callback)==type.string and ..string.startWith(callback,"http",true) {
			msg.message.oncommand = function(id,event){
				import process;
				process.openUrl(callback);
				msg.close();
			}
		}
		if this.modalMode return msg.doModal();
		else return msg; 
	}	
	input = function(msg,isPassword=false){
		this.form_icon = '\uF044';
		this.form_iconColor = 0xD4883B;
		if (!#msg) msg = "请输入：";
		var dlg = this.create(msg,this.showOK);
		if dlg.borderPlus {
			dlg.borderPlus.bottom = dlg.height;
			dlg.borderPlus.right = dlg.width;
		}		
		var icontext,password;
		if (isPassword){
			icontext='\uF023';
			password=1;
		}else{
			icontext='\uF040';
			password=0;
		}	
		dlg.add(
			plus={cls="plus";align="left";border={color=..gdi.argbReverse(this.btnBgColor);width=1};bgcolor=16777215;editable=1;left=0;top=0;right=1;bottom=1;font=LOGFONT(h=-16/(dlg.dpiScaleY:1));iconStyle={font=LOGFONT(h=-16/(dlg.dpiScaleY:1);name='FontAwesome');padding={right=200}};iconText=icontext;paddingLeft=26;paddingTop=2;password=password;z=1}
		)
		dlg.height = dlg.height+40;
		if this.showOK {
			dlg.plus.top = dlg.btnOk.top - 60*(dlg.dpiScaleY:1);
		} else {
			dlg.plus.top = dlg.height - 26*(dlg.dpiScaleY:1)-30;
		}		
		dlg.plus.height = 26*(dlg.dpiScaleY:1);
		dlg.plus.left = dlg.message.left;
		dlg.plus.right = dlg.width-50;
		dlg.plus.setFocus();
		dlg.plus.iconStyle.padding.right = (dlg.plus.width-dlg.plus.height)/(dlg.dpiScaleY:1);
		dlg.resize();
		dlg.center();
		if this.showOK {
			dlg.btnOk.oncommand = function( id,event ){
				dlg.endModal(dlg.plus.text);
			}
		}
		dlg.plus.editBox.onOk = function(){
			dlg.endModal(dlg.plus.text);
		}
		dlg.plus.editBox.onCancel = function(){
			dlg.endModal();
		}
		dlg.showself();
		return dlg.doModal();
	}
	progress = function(msg,pos=0,text=""){
		this.form_icon = '\uF16C';
		this.form_iconColor = 0xD4883B;
		if (!#msg) msg = "进度：";
		var dlg = this.create(msg,false);
		if dlg.borderPlus {
			dlg.borderPlus.bottom = dlg.height;
			dlg.borderPlus.right = dlg.width;
		}		
		dlg.add(
			progress={cls="plus";align="left";border={color=this.progressBorderColor;width=1};bgcolor=this.progressBgColor;forecolor=this.progressForeColor;color=this.progressTextColor;left=0;top=0;right=1;bottom=1;z=3};
		);
		dlg.progress.setProgressRange(0,100);
		dlg.getPlus = function(){
			return dlg.progress; 
		}
		dlg.progress.progressPos = pos;
		dlg.progress.align = "center";
		dlg.progress.text = text;
		dlg.height = dlg.height+40;
		if dlg["btnOk"] dlg.progress.top = dlg.btnOk.top-60;
		else dlg.progress.top = dlg.height-60;
		dlg.progress.height = 26;
		dlg.progress.left = dlg.message.left;
		dlg.progress.right = dlg.width-50;
		dlg.resize();
		dlg.center();
		dlg.showself();
		return dlg;
	}
	["select"] = function(multi,msg,item,selected,referer){
		item :={};
		this.form_icon = '\uF0CB';
		this.form_iconColor = 0xD4883B;
		if (!#msg) msg = "请选择：";
		var dlg = this.create(msg,true);
		if dlg.borderPlus {
			dlg.borderPlus.bottom = dlg.height;
			dlg.borderPlus.right = dlg.width;
		}		
		var vtop = dlg.message.bottom+10;
		var w = dlg.message.width;
		dlg.message.width = 1000;
		for(i=1;#item;1){
			var rectf = dlg.message.measureString(item[i]);
			w = ..math.max(w,rectf.width);
		}
		for(i=1;#item;1){
			if multi { //多选框
				var checked = false ;
				if selected {
					if referer checked=..table.find(referer,selected[[i]]);
					else checked=..table.find(selected,i):..table.find(selected,item[i]);
				};
				dlg.add({
					["rb"++i] = {cls="checkbox";dl=1;dt=1;text=item[i];bgcolor=this.bgcolor;left=dlg.message.left/(dlg.dpiScaleX:1);top=vtop/(dlg.dpiScaleY:1);right=(dlg.message.left+w+10)/(dlg.dpiScaleX:1);bottom=(vtop+20)/(dlg.dpiScaleY:1);font=LOGFONT(h=-16;name='FontAwesome');checked=checked;}
				});
			} else { //单选框
				var checked = false ;
				if selected {
					if referer checked=referer[[i]]===selected;
					else checked=(i===selected):(item[i]===selected);
				};
				dlg.add({
					["rb"++i] = {cls="radiobutton";dl=1;dt=1;text=item[i];bgcolor=this.bgcolor;left=dlg.message.left/(dlg.dpiScaleX:1);top=vtop/(dlg.dpiScaleY:1);right=(dlg.message.left+w+10)/(dlg.dpiScaleX:1);bottom=(vtop+20)/(dlg.dpiScaleY:1);font=LOGFONT(h=-16;name='FontAwesome');checked=checked;}
				});
			}
			vtop += 25;
		}
		dlg.width = dlg.message.left + w +30;
		dlg.height = dlg.height+25*#item;
		dlg.message.width = w;
		dlg.resize();
		dlg.center();
		if multi { //多选框
			dlg.btnOk.oncommand = function( id,event ){
				var r={};
				for(i=1;#item;1){
					if dlg["rb"++i].checked {
						if referer ..table.push(r,referer[[i]]);
						else ..table.push(r,i);
					}
				}
				dlg.endModal(r);
			}
		} else { //单选框
			dlg.btnOk.oncommand = function( id,event ){
				var r;
				for(i=1;#item;1){
					if dlg["rb"++i].checked{
						if referer r=referer[[i]];
						else r=i;
					}
				}
				dlg.endModal(r);
			}
		}
		dlg.onOk = dlg.btnOk.oncommand;
		dlg.showself();
		return dlg.doModal();
	}
	["form"] = function(msg,form,showcancel,timeOut,okfunc,...){
		this.form_icon = '\uF09D';
		this.form_iconColor = 0xD4883B;
		if (!#msg) msg = "加载子窗口";
		var width,height;
		if type(form) != type.string return ; 
		if ..io.exist(form) form=..string.load(form);
		var s = ..string.match(form,"win\.form\s*?\((.+?)\)");
		if !s return ;
		s = eval("{"++s++"}");
		if !s return ;
		width,height = s["right"],s["bottom"];
		if !width or !height return ; 
		var dlg = this.create(msg,showcancel);
		if dlg.borderPlus {
			dlg.borderPlus.bottom = dlg.height;
			dlg.borderPlus.right = dlg.width;
		}		
		width *= (dlg.dpiScaleX:1);
		height *= (dlg.dpiScaleY:1);
		dlg.add(
			custom={cls="custom";text="自定义控件";left=0;top=0;right=1;bottom=1;dl=1;dt=1;z=1}
		);
		dlg.custom.left = 30; //dlg.message.left;
		dlg.custom.width = width;
		dlg.custom.top = dlg.message.bottom+10;
		dlg.custom.height = height;
		var subform = dlg.custom.loadForm(form,...);
		subform.bgcolor = dlg.bgcolor;
		if type(okfunc)==type.function and dlg.btnOk {
			dlg.btnOk.oncommand = function( id,event ){
				dlg.endModal(okfunc(subform));
			}
		}
		dlg.onOk = function(){
			dlg.endModal(okfunc(subform));
		}
		if dlg.width<width+60 dlg.width=width+60;
		dlg.height = dlg.height+height;
		if dlg.btnOk and !dlg.btnCancel {
			dlg.btnOk.left = (dlg.width-dlg.btnOk.width)/2;
		}
		dlg.resize();
		dlg.center();
		if(timeOut){ 
			if(this.fadeInterval) timeOut = timeOut+this.fadeDuration;
			if this.colseUp {
				dlg.timerid = dlg.setTimeout(function(){
						if dlg.btnOk dlg.btnOk.disabled = true;
						for(i=1;15;1){
							dlg.transparent(255-16*i);
							var l,t = dlg.getPos();
							dlg.setPos(l,t-8);
							..win.delay(10);
						}
						dlg.transparent(0);
						dlg.show(false);
						dlg.endModal();	
					},timeOut
				)
			} else {
				dlg.timerid = dlg.setTimeout(λ()dlg.endModal(),timeOut);
			}
		}		
		dlg.showself();
		if this.modalMode {
			return dlg.doModal();
		} else {
			return dlg; 
		}
	}
	["img"] = function(msg,img,width,height,showcancel,timeOut){
		this.form_icon = '\uF09D';
		this.form_iconColor = 0xD4883B;
		var bmp = ..gdip.bitmap(img);
		if !bmp return ;
		if !#msg msg=" ";
		width := bmp.width;
		height := bmp.height;
		if !width or !height return ; 
		
		var dlg = this.create(msg,showcancel);
		
		if dlg.borderPlus {
			dlg.borderPlus.bottom = dlg.height;
			dlg.borderPlus.right = dlg.width;
		}
		width *= (dlg.dpiScaleX:1);
		height *= (dlg.dpiScaleY:1);
		dlg.add(
			plus={cls="plus";left=0;top=0;right=1;bottom=1;dl=1;dt=1;foreRepeat="stretch";z=1}
		);
		var top = 0;
		var pad = 0;
		if this.showOK or showcancel or msg!==" " {
			pad = 30*dlg.dpiScaleX;
			top = 30*dlg.dpiScaleX;
		}
		if msg==" " {
			dlg.icon.show(false)
			dlg.message.show(false)
			if this.showTitlebar top = 30*dlg.dpiScaleX;
		} else {
			top = 60*dlg.dpiScaleX;
		}

		dlg.plus.left = pad; 
		dlg.plus.width = width;
		dlg.plus.top = top;
		dlg.plus.height = height;
		dlg.plus.foreground = img;
		
		dlg.width = width+pad*2;
		top = top + height + pad;
		
		if dlg.btnOk {
			dlg.height = top + dlg.btnOk.height + 20*dlg.dpiScaleX ;
		} else {
			dlg.height = top;
		}
		if dlg.btnOk and !dlg.btnCancel {
			dlg.btnOk.left = (dlg.width-100*dlg.dpiScaleX)/2;
			dlg.btnOk.right = (dlg.width+100*dlg.dpiScaleX)/2;
		} elseif dlg.btnOk and dlg.btnCancel {
			dlg.btnOk.left = dlg.width/8*3-50*dlg.dpiScaleX;
			dlg.btnOk.right = dlg.width/8*3+50*dlg.dpiScaleX;
			dlg.btnCancel.left = dlg.width/8*5-50*dlg.dpiScaleX;
			dlg.btnCancel.right = dlg.width/8*5+50*dlg.dpiScaleX;
		}
		dlg.center();
	
		if(timeOut){ 
			if(this.fadeInterval) timeOut = timeOut+this.fadeDuration;
			if this.colseUp {
				dlg.timerid = dlg.setTimeout(function(){
						if dlg.btnOk dlg.btnOk.disabled = true;
						for(i=1;15;1){
							dlg.transparent(255-16*i);
							var l,t = dlg.getPos();
							dlg.setPos(l,t-8);
							..win.delay(10);
						}
						dlg.transparent(0);
						dlg.show(false);
						dlg.endModal();	
					},timeOut
				)
			} else {
				dlg.timerid = dlg.setTimeout(λ()dlg.endModal(),timeOut);
			}
		}
		dlg.showself();
		if this.modalMode {
			return dlg.doModal();
		} else {
			return dlg; 
		}
	}	
}


namespace message {

	..win.ui.ctrl.metaProperty.mixin({
		msgInfo = function(str,timeOut){
			..godking.message(owner).info( str,timeOut ); 
		};
		msgErr = function(str,timeOut){
			..godking.message(owner).err( str,timeOut ); 
		};
		msgWarn = function(str,timeOut){
			..godking.message(owner).warn( str,timeOut ); 
		};
		msgGreat = function(str,timeOut){
			..godking.message(owner).great( str,timeOut ); 
		};
		msgSmile = function(str,timeOut){
			..godking.message(owner).smile( str,timeOut ); 
		};
		msgFrown = function(str,timeOut){
			..godking.message(owner).frown( str,timeOut ); 
		};
		msgOk = function(str,timeOut){
			..godking.message(owner).ok( str,timeOut ); 
		};
		msgSorry = function(str,timeOut){
			..godking.message(owner).sorry( str,timeOut ); 
		};
		msgAsk = function(str){
			return ..godking.message(owner).ask( str ); 
		}; 
		msgInput = function(str){
			return ..godking.message(owner).input( str ); 
		}; 
	})

group = class {
		ctor (winform){
			this.winlist = {};
			this.bottom = 2;
			this.right = 2;
			var hwnd = ..win.find("Shell_TrayWnd","");
			if hwnd {
				var rect = ..win.getRect(hwnd);
				if rect {
					if rect["top"]>0 { // 任务栏在底边
						this.bottom = rect.height()+2;
					} elseif rect["left"]>0 { // 任务栏在右边
						this.right = rect.width()+2;
						this.bottom = 2;
					}
				}
			} 
			import win.timer;
			this.timer = ..win.timer(0,0);
			this.timer.onTimer = function(){
				var	allright = true
					var allh = this.bottom;
					var _,sch = ..win.getScreen();
					for(i=1;#this.winlist;1){
						allh = allh + this.winlist[i].height + 2;
						var alltop = sch - allh;
						if this.winlist[i].top < alltop {
							var l,t = this.winlist[i].getPos();
							var thistop = t + 10;
							if thistop > alltop thistop = alltop;
							this.winlist[i].setPos(l,thistop);
							allright = false;
						}
					}			
				if allright owner.disable();
			}
			this._message = ..godking.message(winform);
			this._message.colseUp = false;
			this._message.destroyCallback = function(winform){
				import thread
				thread.lock("messagegrouplock");				
					for(i=1;#this.winlist;1){
						if this.winlist[i].hwnd == winform.hwnd {
							..table.remove(this.winlist,i);
							this.timer.enable(10)
							break;
						}
					}
				thread.unlock("messagegrouplock");
			}
			this._message.showOK = false;
			this._message.modalMode = false;

		}
		setTopMost = function(v){
			this._message.topmost = v;
		}
		count = function(){
			return #this.winlist; 
		}
		addwin = function(msgwin){
			import thread
			thread.lock("messagegrouplock");
				..table.push(this.winlist,msgwin);
				var scw,sch = ..win.getScreen();
				var allh = this.bottom;
				for(i=1;#this.winlist;1){
					allh = allh + this.winlist[i].height + 2;
				}
				var left = scw - msgwin.width - this.right;
				var top = sch - allh;
				msgwin.setPos(left,top);
			thread.unlock("messagegrouplock")			
		}
		info = function(...){
			var msgwin = this._message.info(...);
			if !msgwin return ;		
			this.addwin(msgwin);
			return msgwin; 
		}
		err = function(...){
			var msgwin = this._message.err(...);
			if !msgwin return ;		
			this.addwin(msgwin);
			return msgwin; 
		}
		ok = function(...){
			var msgwin = this._message.ok(...);
			if !msgwin return ;		
			this.addwin(msgwin);
			return msgwin; 
		}
		frown = function(...){
			var msgwin = this._message.frown(...);
			if !msgwin return ;		
			this.addwin(msgwin);
			return msgwin; 
		}	
		sorry = function(...){
			var msgwin = this._message.sorry(...);
			if !msgwin return ;		
			this.addwin(msgwin);
			return msgwin; 
		}	
		warn = function(...){
			var msgwin = this._message.warn(...);
			if !msgwin return ;		
			this.addwin(msgwin);
			return msgwin; 
		}							
		smile = function(...){
			var msgwin = this._message.smile(...);
			if !msgwin return ;		
			this.addwin(msgwin);
			return msgwin; 
		}
		great = function(...){
			var msgwin = this._message.great(...);
			if !msgwin return ;		
			this.addwin(msgwin);
			return msgwin; 
		}
		link = function(...){
			var msgwin = this._message.link(...);
			if !msgwin return ;		
			this.addwin(msgwin);
			return msgwin; 
		}
		closeAll = function(){
			this.timer.disable();
			import thread
			thread.lock("messagegrouplock");
			for(i=1;#this.winlist;1){
				this.winlist[i].close();
			}
			this.winlist = {};
			thread.unlock("messagegrouplock")	
		}
		close = function(index){
			this.timer.disable();
			import thread
			thread.lock("messagegrouplock");
			if #this.winlist>=index{
				this.winlist[index].close();
				this.timer.enable(10);
			}
			..table.remove(this.winlist,index);
			thread.unlock("messagegrouplock")	
		}		
	}
}

/**intellisense()
godking.message = 简单信息提示框(光庆改)\n导入时为当前线程所有窗口安装msgInfo,msgAsk,msgErr等msg前缀的消息框函数
godking.message(winform) = 创建简单信息提示框\n参数：父窗口对象或父窗口句柄\n不指定父窗口时默认取当前线程活动窗口作为父窗口\n如果用在非窗口程序中，请用 win.loopMessage() 确保程序不退出。
godking.message() = !GK_winDlgMessage.
godking.message.group(winform) = 创建屏幕右下角弹出提示框组\n参数：父窗口对象或父窗口句柄\n不指定父窗口时，默认取当前线程活动窗口作为父窗口\n如果用在非窗口程序中，请用 win.loopMessage() 确保程序不退出。
godking.message.group() = !GK_winDlgMessage_group.
end intellisense**/

/**intellisense(!GK_winDlgMessage_group)
count() = 当前信息框数量
close(1) = 关闭指定信息框。参数：信息框索引
closeAll() = 关闭全部信息框

setTopMost(true) = 信息框是否总在最前显示。
_message = 简单信息框框架，可做整体设置。\n!GK_winDlgMessage.
bottom = 最底部距离屏幕底部距离。默认：50
info(__,0) = 显示提示框,\n参数1：信息内容；参数2：延时关闭的毫秒数
info() = !GK_Message_winform.
warn(__,0) = 显示警告提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
warn() = !GK_Message_winform.
ok(__,0) = 显示正确提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
ok() = !GK_Message_winform.
err(__,0) = 显示错误提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
err() = !GK_Message_winform.
great(__,0) = 显示竖大拇指图标提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
great() = !GK_Message_winform.
sorry(__,0) = 显示倒竖大拇指图标提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
sorry() = !GK_Message_winform.
smile(__,0) = 显示微笑图标提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
smile() = !GK_Message_winform.
frown(__,0) = 显示皱眉图标提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
frown() = !GK_Message_winform.
link(__,"http://",0) = 显示超链接。\n参数1：显示文本；参数2：点击回调函数或网址；参数3：延时关闭的毫秒数
link() = !GK_Message_winform.

end intellisense**/

/**intellisense(!GK_winDlgMessage)
disableClose() = 设置窗口为禁止手动关闭(按ESC键或ALT+F4)，可通过close()函数关闭。\n相当于设置了 escClose=false 、modalMode=false\n对于强制使用模态模式的窗口（ask、input等）无效。
escClose = 是否允许按ESC键（或ALT+F4）关闭（非模态）窗口。\n默认为 true。\n注意：必须设置 modalMode = false 才有效。模态窗口（ask、input等）不受此约束。
topmost = 窗口是否总在最前。默认为 true
transparent = 窗口透明度。0（全透明）- 100（不透明）
layered = 是否启用鼠标穿透。
modalMode = 是否采用模态窗口。以下窗口不可设置：ask、input、progress、select
borderWidth = 边框宽度，默认：1
borderColor = 边框颜色，默认：0x55000000
minWidth = 窗口最小宽度，默认：300
showOK = 显示确定按钮
btnBgColor = 按钮区背景颜色
pos = 窗口位置\n支持坐标和数组两种格式：{x=1,y=2} 或 {1,2}
round = 窗口圆角大小。显示标题栏时，圆角设置无效。
parent = 父窗口\n信息框显示在父窗口中间\n并在信息框关闭前禁用父窗口
showTitlebar = 是否显示标题栏（右上角关闭按钮）。显示标题栏时，圆角设置无效。
okLabel = 确定按钮文本，支持fontAwesome字体图标
okIcon = 确定按钮图标，fontAwesome字体图标
cancelLabel = 取消按钮文本
cancelIcon = 取消按钮图标，fontAwesome字体图标
icon = 提示图标，fontAwesome字体图标
iconColor = 提示图标颜色
textColor = 文本颜色
bgcolor =  窗口背景颜色
progressBgColor = 进度条背景颜色，默认：0xFFeeeeee;
progressForeColor = 进度条前景颜色，默认0xFF00ee00;
progressTextColor = 进度条文本颜色，默认0xFF000000;
progressBorderColor = 进度条边框颜色，默认0xFF00ee00;
fadeInterval = 淡入淡出动画时间间隔,设为0不显示动画
fadeDuration =  淡入淡出动画时长
colseUp = 超时关闭时窗口时，窗口位置是否向上移动
create(.(显示信息,是否显示确认取消按钮) =  创建信息框,返回窗体对象
create() = !GK_winDlgMessageForm.
createAndShow(.(是否为模态窗口,显示的信息文本,是否显示确认取消按钮,超时关闭时间) = 创建并显示信息框
createAndShow() = !GK_Message_winform.
info(__,0) = 显示提示框,\n参数1：信息内容；参数2：延时关闭的毫秒数
info() = !GK_Message_winform.
warn(__,0) = 显示警告提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
warn() = !GK_Message_winform.
ok(__,0) = 显示正确提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
ok() = !GK_Message_winform.
err(__,0) = 显示错误提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
err() = !GK_Message_winform.
great(__,0) = 显示竖大拇指图标提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
great() = !GK_Message_winform.
sorry(__,0) = 显示倒竖大拇指图标提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
sorry() = !GK_Message_winform.
smile(__,0) = 显示微笑图标提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
smile() = !GK_Message_winform.
frown(__,0) = 显示皱眉图标提示框\n参数1：信息内容；参数2：延时关闭的毫秒数
frown() = !GK_Message_winform.
link(__,"http://",0) = 显示超链接。\n参数1：显示文本；参数2：点击回调函数或网址；参数3：延时关闭的毫秒数
link() = !GK_Message_winform.

progress(__,0,"0%") = 显示进度提示框（非模态窗口）\n参数1：提示内容。参数2：初始进度值。参数3：初始进度文本\n为了便于随时更新进度，强制采用非模态窗口，不阻塞代码向下执行\n可以使用 waitClose() 函数等待窗口关闭
progress() = !GK_Message_progress.
img(msg,img,0,0,false,0) = 图像提示框\n参数1：提示内容。参数2：图片。参数3：宽度(可空)。参数4：高度(可空)。参数5：是否显示取消按钮。参数6：超时时间
img() = !GK_Message_progress.

ask(__) = 显示询问提示框（模态窗口）\n用户按确定或回车返回true，其他返回false或null\n强制采用模态窗口，等待窗口关闭。
input(__,false) = 显示输入框（模态窗口）\n用户按确定或回车返回输入的内容，其他返回null\n参数：1、输入框提示信息 2、是否密码模式\n强制采用模态窗口，等待窗口关闭。
select( false,"请选择",{},, ) = 选择框（模态窗口）\n参数：\n1：是否多选；\n2：提示信息；\n3：项目文本数组；\n4：默认选中项（索引或值，单选时为单个值，多选时为数组）\n      如果提供参数5，默认选中项与参数5中的成员做对比\n      否则，默认选中项与项目索引、项目值做对比；\n5：自定义项目返回值数组，项目选中时从该数组中获取对应的值作为返回值。\n      必须与项目一一对应。如果提供，则返回值从该数组中获取，如果省略，则返回选中的项目索引。\n\n返回值：单选时返回单个值，多选时返回数组\n强制采用模态窗口，等待窗口关闭。
form = @.form( "加载子窗口", "/a.aardio",true,0,function(winform){
        /*在信息框中加载子窗口，参数：1、信息文本；2、form子窗体代码；3、是否显示确认取消按钮；4、超时关闭时间；5、确定按钮事件函数；
        该函数的参数为加载的子窗体对象，该函数的返回值作为 modalMode=true 时 form() 函数的返回值*/
		return winform.text; 
});
form() = !GK_Message_winform.

buttonStyle = @.buttonStyle = { 
	/*确认、取消按钮风格*/
			color = {  
				default = 0xFFFFFFFF;
				hover = 16#FFFFFDC2;
				active = 16#FFFFFDC2;
			} 
			border = {
				default = {width=0;}
				hover = { bottom = 2;color= 16#FFFFFDC2; }
				active = { bottom = 2;color= 16#FFFFFDC2; }
			} 
}
titlebarStyle = @.titlebarStyle = { 
	/*标题栏×按钮文本风格*/
	color = {  
		default = 0xFFAAAAAA;
		hover = 0xFFFF0000;
		active = 0xFFFF0000;
	} 
} 
end intellisense**/

/**intellisense(!GK_winDlgMessageForm)
icon = 显示文字图标的plus控件\n!ui_ctrl_plus.
message = 显示文本消息的plus控件\n!ui_ctrl_plus.
btnOk = 确定按钮\n!ui_ctrl_plus.
btnCancel = 取消按钮\n!ui_ctrl_plus.
progress = 进度条,plus控件\n!ui_ctrl_plus.
icon = 图标控件\n!ui_ctrl_plus.
onMouseClick = @.onMouseClick = function(wParam,lParam){\n	var x,y = win.getMessagePos(lParam);__/*在窗口上单击并弹起鼠标左键触发此事件*/\n}
valid = 窗口是否有效\n如果用户关闭窗体则返回false
text = 窗口标题
hwnd = 窗口句柄\n\n句柄是一个数值，用于标识一种系统资源，如窗口、位图等等，\n如果你要操作一种系统资源，必须先获得句柄。 \n\n句柄在aardio中通常转换为指针(pointer)类型，\n而窗口句柄是个特例，onDestroy = @.onDestroy = function(){\n    __/*指定在窗体销毁以前执行的代码*/\n    \n}
beforeDestroy = @.beforeDestroy = function(){\n    __/*指定在窗体销毁以前执行的代码\n早于onDestroy触发*/\n    \n}
setPos(.(x坐标,y坐标,宽,高,插入位置,参数) = 调整窗口位置或排序,所有参数可选\n同时指定x,y坐标则移动位置\n同时指定宽高则改变大小\n指定插入位置(句柄或_HWND前缀常量)则调整Z序
show(.(true) = 显示窗口
show(.(false) = 隐藏窗口  
setRect(rc) = 设置窗口区块位置(::RECT结构体)  
center(.(目标窗口句柄) = 居中窗口,并调整以保证显示在可见范围内\n目标窗口句柄如果为空则取父窗口或所有者窗口,为0表示桌面
bgcolor = 背景颜色
close() = 关闭窗口
waitClose() = 等待窗口关闭
isExist() = 窗口是否存在
doModal(__/*请指定所有者窗口\n可省略此参数*/) = 此函数弹出模态对话框
endModal(__/*请指定模态对话框返回值*/) = 关闭模态对话框，\n调用endModal()函数的参数会被设置为 doModal()函数的返回值。
setInterval(回调函数,延时毫秒数,->->->) = @.setInterval( \n	function(){\n		__/*参数@1指定执行函数,参数@2指定执行间隔，\n可选指定一个或多个回调参数，不指定回调参数则默认为:\n hwnd,message,timerId,tick,\n\n如果在定时器中执行了win.delay等继续消息循环的代码，\n在定时器退出前不会再触发同一定时器（重入）。\n\n定时器回调函数返回数值可修改时间间隔,\n返回false取消该定时器*/\n	},1000 \n)
end intellisense**/

/**intellisense(!GK_Message_progress.)
winform = !GK_winDlgMessageForm.
close() = 关闭窗口。仅非模态窗口时有效。
waitClose() = 等待窗口关闭。仅非模态窗口时有效。
isExist() = 窗口是否存在。仅非模态窗口时有效。
getPlus() = 取进度条plus组件\n!ui_ctrl_plus.
progress.progressPos = 设置进度值，0 到 100
progress.text = 设置进度文本，如 “ 50% ”
progress.align = 设置进度文本对齐方式。"left" "center" "right"
end intellisense**/

/**intellisense(!GK_Message_winform.)
winform = !GK_winDlgMessageForm.
close() = 关闭窗口。仅非模态窗口时有效。
waitClose() = 等待窗口关闭。仅非模态窗口时有效。
isExist() = 窗口是否存在。仅非模态窗口时有效。
end intellisense**/

..godking.message._version := 3.5;
..godking.message._date := "2024-03-05";