int TrackPopupMenu(HMENU hMenu, int flags, int xpos, int ypos, int resvd, HWND hwnd, const RECT *r) { if (!hMenu || m_trackingMenus.GetSize()) return 0; ReleaseCapture(); m_trackingPar=hwnd; m_trackingFlags=flags; m_trackingRet=-1; m_trackingPt.x=xpos; m_trackingPt.y=ypos; submenuWndProc(new HWND__(NULL,0,NULL,"menu",false,submenuWndProc,NULL),WM_CREATE,0,(LPARAM)hMenu); printf("enter trackpopupmenu loop\n"); while (m_trackingRet<0 && m_trackingMenus.GetSize()) { void SWELL_RunMessageLoop(); SWELL_RunMessageLoop(); Sleep(10); } printf("leave trackpopupmenu loop\n"); int x=m_trackingMenus.GetSize()-1; while (x>=0) { HWND h = m_trackingMenus.Get(x); m_trackingMenus.Delete(x); if (h) DestroyWindow(h); x--; } if (!(flags&TPM_NONOTIFY) && m_trackingRet>0) SendMessage(hwnd,WM_COMMAND,m_trackingRet,0); return m_trackingRet>0?m_trackingRet:0; }
int TrackPopupMenu(HMENU hMenu, int flags, int xpos, int ypos, int resvd, HWND hwnd, const RECT *r) { if (!hMenu || m_trackingMenus.GetSize()) return 0; ReleaseCapture(); m_trackingPar=hwnd; m_trackingFlags=flags; m_trackingRet=-1; m_trackingPt.x=xpos; m_trackingPt.y=ypos; // HWND oldFoc = GetFocus(); // bool oldFoc_child = oldFoc && (IsChild(hwnd,oldFoc) || oldFoc == hwnd || oldFoc==GetParent(hwnd)); HWND hh; submenuWndProc(hh=new HWND__(NULL,0,NULL,"menu",false,submenuWndProc,NULL),WM_CREATE,0,(LPARAM)hMenu); SetProp(hh,"SWELL_MenuOwner",(HANDLE)hwnd); while (m_trackingRet<0 && m_trackingMenus.GetSize()) { void SWELL_RunMessageLoop(); SWELL_RunMessageLoop(); Sleep(10); } int x=m_trackingMenus.GetSize()-1; while (x>=0) { HWND h = m_trackingMenus.Get(x); m_trackingMenus.Delete(x); if (h) DestroyWindow(h); x--; } // if (oldFoc_child) SetFocus(oldFoc); if (!(flags&TPM_NONOTIFY) && m_trackingRet>0) SendMessage(hwnd,WM_COMMAND,m_trackingRet,0); return m_trackingRet>0?m_trackingRet:0; }
static LRESULT WINAPI submenuWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { const int itemheight = 12, lcol=12, rcol=12, mcol=10; switch (uMsg) { case WM_CREATE: m_trackingMenus.Add(hwnd); SetWindowLongPtr(hwnd,GWLP_USERDATA,lParam); if (m_trackingPar && !(m_trackingFlags&TPM_NONOTIFY)) SendMessage(m_trackingPar,WM_INITMENUPOPUP,(WPARAM)lParam,0); { HDC hdc = GetDC(hwnd); HMENU__ *menu = (HMENU__*)lParam; int ht = menu->items.GetSize()*itemheight, wid=100,wid2=0; int xpos=m_trackingPt.x; int ypos=m_trackingPt.y; int x; for (x=0; x < menu->items.GetSize(); x++) { MENUITEMINFO *inf = menu->items.Get(x); if (inf->fType == MFT_STRING && inf->dwTypeData) { RECT r={0,}; const char *pt2 = strstr(inf->dwTypeData,"\t"); DrawText(hdc,inf->dwTypeData,pt2 ? pt2-inf->dwTypeData : -1,&r,DT_CALCRECT|DT_SINGLELINE); if (r.right > wid) wid=r.right; if (pt2) { r.right=r.left; DrawText(hdc,pt2+1,-1,&r,DT_CALCRECT|DT_SINGLELINE); if (r.right > wid2) wid2=r.right; } } } wid+=lcol+rcol + (wid2?wid2+mcol:0); ReleaseDC(hwnd,hdc); RECT tr={xpos,ypos,xpos+wid,ypos+ht},vp; SWELL_GetViewPort(&vp,&tr,true); if (tr.bottom > vp.bottom) { tr.top += vp.bottom-tr.bottom; tr.bottom=vp.bottom; } if (tr.right > vp.right) { tr.left += vp.right-tr.right; tr.right=vp.right; } if (tr.left < vp.left) { tr.right += vp.left-tr.left; tr.left=vp.left; } if (tr.top < vp.top) { tr.bottom += vp.top-tr.top; tr.top=vp.top; } SetWindowPos(hwnd,NULL,tr.left,tr.top,tr.right-tr.left,tr.bottom-tr.top,SWP_NOZORDER); } SetWindowLong(hwnd,GWL_STYLE,GetWindowLong(hwnd,GWL_STYLE)&~WS_CAPTION); ShowWindow(hwnd,SW_SHOW); SetFocus(hwnd); SetTimer(hwnd,1,250,NULL); break; case WM_PAINT: { PAINTSTRUCT ps; if (BeginPaint(hwnd,&ps)) { RECT cr; GetClientRect(hwnd,&cr); HBRUSH br=CreateSolidBrush(GetSysColor(COLOR_3DFACE)); HPEN pen=CreatePen(PS_SOLID,0,GetSysColor(COLOR_3DSHADOW)); HGDIOBJ oldbr = SelectObject(ps.hdc,br); HGDIOBJ oldpen = SelectObject(ps.hdc,pen); Rectangle(ps.hdc,cr.left,cr.top,cr.right-1,cr.bottom-1); SetBkMode(ps.hdc,TRANSPARENT); int cols[2]={ GetSysColor(COLOR_BTNTEXT),GetSysColor(COLOR_3DHILIGHT)}; HMENU__ *menu = (HMENU__*)GetWindowLongPtr(hwnd,GWLP_USERDATA); int x; for (x=0; x < menu->items.GetSize(); x++) { MENUITEMINFO *inf = menu->items.Get(x); RECT r={lcol,x*itemheight,cr.right,(x+1)*itemheight}; bool dis = !!(inf->fState & MF_GRAYED); SetTextColor(ps.hdc,cols[dis]); if (inf->fType == MFT_STRING && inf->dwTypeData) { const char *pt2 = strstr(inf->dwTypeData,"\t"); DrawText(ps.hdc,inf->dwTypeData,pt2 ? pt2-inf->dwTypeData : -1,&r,DT_VCENTER|DT_SINGLELINE); if (pt2) { RECT tr=r; tr.right-=rcol; DrawText(ps.hdc,pt2+1,-1,&tr,DT_VCENTER|DT_SINGLELINE|DT_RIGHT); } } else { MoveToEx(ps.hdc,r.left - lcol/2,(r.top+r.bottom)/2,NULL); LineTo(ps.hdc,r.right - rcol*3/2,(r.top+r.bottom)/2); } if (inf->hSubMenu) { RECT r2=r; r2.left = r2.right - rcol; DrawText(ps.hdc,">",-1,&r2,DT_VCENTER|DT_RIGHT|DT_SINGLELINE); } if (inf->fState&MF_CHECKED) { RECT r2=r; r2.left = 0; r2.right=lcol; DrawText(ps.hdc,"X",-1,&r2,DT_VCENTER|DT_CENTER|DT_SINGLELINE); } } SelectObject(ps.hdc,oldbr); SelectObject(ps.hdc,oldpen); DeleteObject(br); DeleteObject(pen); EndPaint(hwnd,&ps); } } break; case WM_TIMER: if (wParam==1) { HWND h = GetFocus(); if (h!=hwnd) { int a = h ? m_trackingMenus.Find(h) : -1; if (a<0 || a < m_trackingMenus.Find(hwnd)) DestroyWindow(hwnd); } } break; case WM_DESTROY: { int a = m_trackingMenus.Find(hwnd); m_trackingMenus.Delete(a); if (m_trackingMenus.Get(a)) DestroyWindow(m_trackingMenus.Get(a)); } break; case WM_LBUTTONUP: case WM_RBUTTONUP: { RECT r; GetClientRect(hwnd,&r); if (GET_X_LPARAM(lParam)>=r.left && GET_X_LPARAM(lParam)<r.right) { int which = GET_Y_LPARAM(lParam)/itemheight; HMENU__ *menu = (HMENU__*)GetWindowLongPtr(hwnd,GWLP_USERDATA); MENUITEMINFO *inf = menu->items.Get(which); if (inf) { if (inf->fState&MF_GRAYED){ } else if (inf->hSubMenu) { int a = m_trackingMenus.Find(hwnd); HWND next = m_trackingMenus.Get(a+1); if (next) DestroyWindow(next); m_trackingPt.x=r.right; m_trackingPt.y=r.top + which*itemheight; ClientToScreen(hwnd,&m_trackingPt); submenuWndProc(new HWND__(NULL,0,NULL,"menu",false,submenuWndProc,NULL),WM_CREATE,0,(LPARAM)inf->hSubMenu); } else if (inf->wID) m_trackingRet = inf->wID; } else DestroyWindow(hwnd); } else DestroyWindow(hwnd); } break; } return DefWindowProc(hwnd,uMsg,wParam,lParam); }