
AI升级版
// 自定义弹出菜单(支持子级菜单)@Mr_MAO
import win.ui;
import fonts.fontAwesome;
import inet.http;
import gdip.bitmap;
class customPopMenu {
ctor(parent){
this.parentWnd = parent;
this.ownerMenu = null;
this.childMenu = null;
this.menuFrm = null;
this.hoverIdx = null;
this.inClosing = false;
this.items = {};
this.itemHeight = 32;
this.minWidth = 100;
this.fontSize = 12;
this.iconSize = 16;
this.backgroundColor = 0xFFf0f0f0;
this.createArrowBitmap = function(){
if(this.arrowBitmapDefault) return;
var sz = 16;
var fnt = ..gdip.font("FontAwesome", 10);
var fmt = ..gdip.stringformat();
fmt.setAlignment(1);
fmt.setLineAlignment(1);
this.arrowBitmapDefault = ..gdip.bitmap(sz, sz);
var g1 = this.arrowBitmapDefault.getGraphics();
g1.setTextRenderingHint(3);
var brush1 = ..gdip.solidBrush(0xFF333333);
g1.drawString('\uF054', fnt, ::RECTF(0,0,sz,sz), fmt, brush1);
g1.dispose();
brush1.dispose();
this.arrowBitmapHover = ..gdip.bitmap(sz, sz);
var g2 = this.arrowBitmapHover.getGraphics();
g2.setTextRenderingHint(3);
var brush2 = ..gdip.solidBrush(0xFF0078D4);
g2.drawString('\uF054', fnt, ::RECTF(0,0,sz,sz), fmt, brush2);
g2.dispose();
brush2.dispose();
fnt.dispose();
fmt.delete();
};
this.createArrowBitmap();
};
add = function(text, callback, icon, submenu){
var item = {
text = text;
callback = callback;
icon = icon;
submenu = submenu;
disabled = false;
};
..table.push(this.items, item);
return item;
};
addSeparator = function(){
..table.push(this.items, { isSeparator = true });
};
getRoot = function(){
var menu = this;
while(menu.ownerMenu) menu = menu.ownerMenu;
return menu;
};
closeChain = function(){
this.inClosing = true;
if(this.childMenu){
this.childMenu.closeChain();
this.childMenu = null;
}
if(this.menuFrm){
this.menuFrm.close();
this.menuFrm = null;
}
this.inClosing = false;
};
closeChild = function(){
if(this.childMenu){
this.childMenu.closeChain();
this.childMenu = null;
this.hoverIdx = null;
}
};
openSubmenu = function(itemIndex, itemTop, submenuRef){
this.closeChild();
submenuRef.backgroundColor = this.backgroundColor;
var formRect = this.menuFrm.getRect(true);
var subX = formRect.right;
var subY = formRect.top + itemTop;
submenuRef.ownerMenu = this;
submenuRef.popup(subX, subY, true);
this.childMenu = submenuRef;
this.hoverIdx = itemIndex;
};
calcWidth = function(){
var bmp = ..gdip.bitmap(10, 10);
var g = bmp.getGraphics();
var fnt = ..gdip.font("Microsoft YaHei", this.fontSize, 3);
var layoutRect = ::RECTF(0, 0, 9999, 9999);
var iconArea = 35;
var arrowArea = 22;
var padding = 16;
var maxWidth = 0;
for(i, item in this.items){
if(item.isSeparator) continue;
var rect = g.measureString(item.text, fnt, layoutRect);
var itemW = iconArea + ..math.ceil(rect.width) + padding;
if(item.submenu) itemW += arrowArea;
if(itemW > maxWidth) maxWidth = itemW;
}
g.dispose();
bmp.dispose();
return ..math.max(maxWidth, this.minWidth);
};
popup = function(x, y, isSubmenu){
if(this.menuFrm) this.closeChain();
if( !(x && y) ){
x, y = ..win.getMessagePos();
}
this.width = this.calcWidth();
var totalH = 6;
for(i, item in this.items){
totalH += item.isSeparator ? 6 : this.itemHeight;
}
if(!isSubmenu){
x += 20; y += 20;
}
var screenRect = ..win.getWorkArea();
if(isSubmenu && this.ownerMenu && this.ownerMenu.menuFrm){
if(x + this.width > screenRect.right){
var parentRect = this.ownerMenu.menuFrm.getRect(true);
x = parentRect.left - this.width;
}
}
else {
if(x + this.width > screenRect.right){
x = x - this.width - 50;
}
}
if(y + totalH > screenRect.bottom) y = screenRect.bottom - totalH;
if(x < screenRect.left) x = screenRect.left;
if(y < screenRect.top) y = screenRect.top;
var frm = ..win.form(
parent = this.parentWnd; title = false;
right = this.width; bottom = totalH;
border = "dialog frame"; exmode="toolwindow"; mode="popup";
bgcolor = this.backgroundColor;
);
this.menuFrm = frm;
var currentY = 3;
var menuRef = this;
var arrowBmpDefault = this.arrowBitmapDefault;
var arrowBmpHover = this.arrowBitmapHover;
for(i, item in this.items){
if(item.isSeparator){
frm.add({
["sep" ++ i] = {
cls="plus"; left=8; top=currentY+2; right=menuRef.width-8;
bottom=currentY+3; bgcolor=0xE0E0E0; z=i
}
});
currentY += 6;
continue;
}
var hasSubmenu = !!item.submenu;
var isDisabled = item.disabled;
var ctrlArgs = {
cls="plus"; left=0; top=currentY; right=menuRef.width; bottom=currentY+menuRef.itemHeight;
text=item.text; align="left";
font=LOGFONT(h=-menuRef.fontSize); color=isDisabled ? 0xFFBBBBBB : 0x333333;
textPadding={left=35; right=hasSubmenu ? 16 : 8};
notify=1; z=i;
};
var iconIsBitmap = false;
if(item.icon){
if(type(item.icon)==type.string && #item.icon<=8){
ctrlArgs.iconText = item.icon;
ctrlArgs.iconStyle = {
font=LOGFONT(h=-menuRef.iconSize; name='FontAwesome');
align="left"; padding={left=7};
};
}
else {
ctrlArgs.foreground = item.icon;
ctrlArgs.foreRepeat = "point";
ctrlArgs.foreAlign = "left";
ctrlArgs.x = 8; ctrlArgs.y = (menuRef.itemHeight-16)/2;
iconIsBitmap = true;
}
}
if(hasSubmenu){
if(iconIsBitmap){
ctrlArgs.iconText = '\uF054';
ctrlArgs.iconStyle = {
font=LOGFONT(h=-10; name='FontAwesome');
align="right"; padding={right=9};
};
}
else {
ctrlArgs.foreground = arrowBmpDefault;
ctrlArgs.foreRepeat = "point";
ctrlArgs.foreAlign = "left";
ctrlArgs.x = menuRef.width - 22;
ctrlArgs.y = (menuRef.itemHeight - 16) / 2;
}
}
var ctrl = frm.add({ ["item" ++ i] = ctrlArgs })["item" ++ i];
if(isDisabled){
ctrl.skin({
background={default=menuRef.backgroundColor};
color={default=0xFFBBBBBB};
});
}
else {
var skinArgs = {
background={default=menuRef.backgroundColor; hover=0xFFE8F0FE; active=0xFFD0E0FC};
color={default=0xFF333333; hover=0xFF0078D4};
};
if(hasSubmenu && !iconIsBitmap){
skinArgs.foreground = {default=arrowBmpDefault; hover=arrowBmpHover; active=arrowBmpHover};
}
ctrl.skin(skinArgs);
}
var callback = item.callback;
var submenuRef = item.submenu;
var itemIndex = i;
var itemTop = currentY;
if(!isDisabled){
ctrl.onMouseHover = function(){
if(hasSubmenu){
if(menuRef.hoverIdx == itemIndex) return;
menuRef.openSubmenu(itemIndex, itemTop, submenuRef);
}
else {
menuRef.closeChild();
}
};
if(!hasSubmenu){
ctrl.onMouseClick = function(){
menuRef.getRoot().closeChain();
if(callback) callback();
};
}
}
currentY += menuRef.itemHeight;
}
frm.wndproc = function(hwnd, message, wParam, lParam){
if(message == 0x111/*_WM_COMMAND*/){
if(wParam & 0xFFFF == 2/*_IDCANCEL*/){
menuRef.getRoot().closeChain();
return true;
}
}
if(message == 0x6/*_WM_ACTIVATE*/){
if((wParam & 0xFFFF) == 0){
frm.setTimeout(function(){
if(menuRef.inClosing) return;
var activeHwnd = ..win.getForeground();
var isOwn = false;
var scan = menuRef.getRoot();
while(scan){
if(scan.menuFrm && scan.menuFrm.hwnd == activeHwnd){
isOwn = true;
break;
}
scan = scan.childMenu;
}
if(!isOwn){
menuRef.getRoot().closeChain();
}
}, 100);
}
}
}
frm.setPos(x, y);
if(isSubmenu){
frm.show(0x4/*_SW_SHOWNOACTIVATE*/);
}
else {
..win.setForeground(frm.hwnd);
frm.show();
}
};
}
var imgPath1 = "https://cdn-icons-png.flaticon.com/512/724/724713.png";
var bmpIcon = gdip.bitmap(imgPath1).resize(18,18);
// ==================== 演示 ====================
/*DSG{{*/
var winform = win.form(text="自定义弹出菜单 - 支持子级菜单";right=759;bottom=469)
winform.add(
hint={cls="bk";text="右键点击窗口,弹出自定义菜单";left=192;top=178;right=551;bottom=266;color=0x999999;db=1;dl=1;dr=1;dt=1;font=LOGFONT(h=-16);z=1}
)
/*}}*/
winform.wndproc = function(hwnd, message, wParam, lParam) {
if(message == 0x205/*_WM_RBUTTONUP*/){
var subMenu1 = customPopMenu(winform);
subMenu1.add("新建文件", function(){
winform.msgbox("点击了: 新建文件","提示");
}, '\uF016');
subMenu1.add("打开文件", function(){
winform.msgbox("点击了: 打开文件","提示");
}, '\uF07C');
subMenu1.addSeparator();
subMenu1.add("保存文件", function(){
winform.msgbox("点击了: 保存文件","提示");
}, '\uF0C7');
var subMenu2 = customPopMenu(winform);
subMenu2.add("用户管理", function(){
winform.msgbox("点击了: 用户管理","提示");
}, '\uF007');
subMenu2.add("角色管理", function(){
winform.msgbox("点击了: 角色管理","提示");
}, '\uF0C0');
var privacyMenu = customPopMenu(winform);
privacyMenu.add("密码策略", function(){
winform.msgbox("点击了: 密码策略","提示");
}, '\uF023');
privacyMenu.add("登录日志", function(){
winform.msgbox("点击了: 登录日志","提示");
}, '\uF02B');
privacyMenu.add("IP白名单", function(){
winform.msgbox("点击了: IP白名单","提示");
}, '\uF0AC');
subMenu2.add("隐私与安全", null, '\uF023', privacyMenu);
var menu = customPopMenu(winform);
menu.backgroundColor = 0xFFFFFFFF;
menu.add("账户信息", function(){
winform.msgbox("点击了: 账户信息","提示");
}, '\uF007');
menu.add("搜索查找", function(){
winform.msgbox("点击了: 搜索查找","提示");
}, '\uF002');
menu.add("文件操作", null, '\uF15B', subMenu1);
menu.add("系统设置", null, '\uF013', subMenu2);
menu.add("位图图标子菜单", null, bmpIcon, subMenu1);
var exportItem = menu.add("导出数据", function(){
winform.msgbox("点击了: 导出数据","提示");
}, '\uF1C3');
exportItem.disabled = true; // 禁用项示例
menu.addSeparator();
menu.add("返回主页", function(){
winform.msgbox("点击了: 返回主页","提示");
}, '\uF015');
menu.add("反馈与交流", function(){
winform.msgbox("点击了: 反馈与交流","提示");
}, '\uF075');
menu.addSeparator();
menu.add("退出程序", function(){
winform.close();
}, '\uF011');
menu.popup();
}
}
winform.show();
win.loopMessage();