aardio从高级选项卡中分离出独立窗口

就像很多浏览器一样,标签页可以变成独立窗口。arrdio的高级选项卡也可以。

 总的思路很简单,就是把选项卡窗体的父窗口和样式修改一下。

里面有一个关键点,就是必须把独立出来的窗体从选项卡容器(container)的子窗口队列中移除。因为tbs.loadform的本质是tbs.container.loadform,也就是mainform.custom.loadform。而custom 控件的 loadForm 函数会将窗体加载为子窗口, 自动维护一个子窗口队列,显示一个子窗口就会隐藏其他子窗口。如果不从这个队列中移除,就会出现,一切换选项卡,窗体就看不见了的情况。这个队列就是custom._forms。虽然它的名字带下划线,像个常量,其实可以移除其中的元素。

此外还有一些细节,代码里有说明。

下面的代码是aardio工程模板“横版导航”,其中50-93行是我们增加的代码,其余没有修改。

import fonts.fontAwesome;
import win.ui;
/*DSG{{*/
mainForm = win.form(text="高级选项卡分离为独立窗口";right=1040;bottom=642;bgcolor=16777215;border="none")
mainForm.add(
caption={cls="bkplus";text="选项卡变独立窗口";left=35;top=12;right=160;bottom=30;color=15780518;dl=1;dt=1;font=LOGFONT(h=-16);z=5};
custom={cls="custom";left=0;top=40;right=1040;bottom=643;bgcolor=16777215;db=1;dl=1;dr=1;dt=1;z=1};
logo={cls="bkplus";text='\uF0AD';left=6;top=9;right=35;bottom=34;color=15780518;dl=1;dt=1;font=LOGFONT(h=-18;name='FontAwesome');z=4};
navFirst={cls="plus";text="主页";left=166;top=5;right=260;bottom=40;align="left";color=16777215;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-19;name='FontAwesome');padding={left=12;top=4}};iconText='\uF00A';notify=1;paddingLeft=1;paddingRight=1;paddingTop=3;textPadding={left=39;bottom=1};x=0.5;y=0.2;z=3};
navHelp={cls="plus";text="帮助";left=462;top=5;right=556;bottom=40;align="left";color=16777215;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-19;name='FontAwesome');padding={left=12;top=4}};iconText='\uF06A';notify=1;paddingLeft=1;paddingRight=1;paddingTop=3;textPadding={left=39;bottom=1};x=0.5;y=0.2;z=7};
navHotkey={cls="plus";text="热键";left=265;top=5;right=359;bottom=40;align="left";color=16777215;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-19;name='FontAwesome');padding={left=12;top=4}};iconText='\uF11C ';notify=1;paddingLeft=1;paddingRight=1;paddingTop=3;textPadding={left=39;bottom=1};x=0.5;y=0.2;z=8};
navSetting={cls="plus";text="设置";left=363;top=5;right=457;bottom=40;align="left";color=16777215;dl=1;dt=1;font=LOGFONT(h=-16);iconStyle={align="left";font=LOGFONT(h=-19;name='FontAwesome');padding={left=12;top=4}};iconText='\uF0AD';notify=1;paddingLeft=1;paddingRight=1;paddingTop=3;textPadding={left=39;bottom=1};x=0.5;y=0.2;z=6};
titleBar={cls="bkplus";left=0;top=0;right=1042;bottom=41;bgcolor=14977280;dl=1;dr=1;dt=1;z=2}
)
/*}}*/

import win.ui.simpleWindow;
win.ui.simpleWindow( mainForm );

import win.ui.tabs;
var tbs = win.ui.tabs( 
	mainForm.navFirst,
	mainForm.navHotkey,
	mainForm.navSetting,
	mainForm.navHelp
);
	
tbs.skin({
	foreground={
		active=0xFFFFFFFF;
		default=0x00FFFFFF;
		hover=0x38FFFFFF
	};
	color={
		default=0xFFFFFFFF; 
	};
	checked={
		foreground={default=0xFFFFFFFF;}; 
		color={default=0xFF42A875;};
	}
})
	
tbs.loadForm(1,"\dlg\first.aardio" );  
tbs.loadForm(2,"\dlg\hotkey.aardio" );  
tbs.loadForm(3,"\dlg\setting.aardio" ); 
tbs.loadForm(4,"\dlg\help.aardio" ); 

tbs.selIndex = 1; 

//为每个选项卡设置两个事件函数
for(i=1;tbs.count()){
	//鼠标按下事件,记录按下时间,主要为了防止误触,和主功能无关,也可以写在tbs的事件里。
	tbs.strips[i].onMouseDown = function(wParam,lParam){
	    tbs.strips[i].tick=time.tick();		
	}
	//鼠标拖动事件。tbs没有这个事件,只能写在选项卡里。
	tbs.strips[i].onMouseDrag = function(wParam,lParam){
		//200毫秒以内视为误触,不做响应
		if time.tick()-tbs.strips[i].tick<200 return ; 
		//记录下已经分离了,避免重复响应
		if tbs.strips[i].gone return ; 
		tbs.strips[i].gone=true	;
		//关键点一:将该窗体从选项卡容器的子窗口队列中移除
		var frm=tbs.forms[i];
		table.removeByValue(tbs.container._forms,frm);
		//关键点二:修改窗体样式和父窗口	
		frm.modifyStyle(0x40000000/*_WS_CHILD*/,0x40000/*_WS_SIZEBOX*/|0xC00000/*_WS_CAPTION*/);
	    win.setParent(frm.hwnd,0);
	    //选项卡布局调整。如果用delete,布局会自动调整,但是这里测试一旦delete,窗口就关闭了,不可以	
		//因此使用close或者hide,然后人工调整布局。
		tbs.strips[i].close();//tbs.strips[i].hide=true		
		for (j=i+1;tbs.count()){
			tbs.strips[j].left-=(tbs.strips[i].width+tbs.itemMargin);
			tbs.strips[j].right-=(tbs.strips[i].width+tbs.itemMargin);
			}
		//显示其他选项卡,右侧临近优先,左侧临近其次。不切换的话,会显示空白,不好看。
		var newindex;
		for (j=i+1;	tbs.count()){
			if !tbs.strips[j].gone {newindex=j;break;}
			}
		if !newindex{
			for (j=i-1;	1;-1){
				if !tbs.strips[j].gone {newindex=j;	break;}
				}
			}	
		tbs.selIndex=newindex;
		//分离出来的窗口移动到当前鼠标位置,开始拖动
	    var x,y = win.getMessagePos(lParam);
	    x,y=win.toScreen(owner.hwnd,x,y);
	    frm.setPos(x-frm.width/2,y-10)	;
		frm.hitCaption();
	}
}

mainForm.show();
return win.loopMessage();