#include #include #include #ifndef WASABI_WANT_FF_POPUP #include "popup.h" #ifdef _WIN32 #include "../../../Plugins/General/gen_ff/wa2frontend.h" extern HINSTANCE hInstance; #endif PopupMenu::PopupMenu() { hmenu = NULL; parent = NULL; } PopupMenu::PopupMenu(ifc_window *_parent) { hmenu = NULL; parent = _parent; } PopupMenu::PopupMenu(PopupMenu *_parent) { hmenu = NULL; parent = _parent->getParent(); } PopupMenu::~PopupMenu() { invalidateMenu(); entries.deleteAll(); sortedentries.removeAll(); } void PopupMenu::addSubMenu(PopupMenu *menu, const wchar_t *text, int disabled) { invalidateMenu(); PopupMenuEntry *e = new PopupMenuEntry(text, -1, menu, 0, disabled); entries.addItem(e); sortedentries.addItem(e); } void PopupMenu::addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param) { invalidateMenu(); PopupMenuEntry *e = new PopupMenuEntry(text, -1, NULL, 0, 0, cb, param); entries.addItem(e); sortedentries.addItem(e); } void PopupMenu::addCommand(const wchar_t *text, int command, int checked, int disabled, int addpos) { invalidateMenu(); PopupMenuEntry *e = new PopupMenuEntry(text, command, NULL, checked, disabled); entries.addItem(e); sortedentries.addItem(e, addpos); } void PopupMenu::addSeparator(int addpos) { invalidateMenu(); PopupMenuEntry *e = new PopupMenuEntry(NULL, -1, NULL, 0, 0); entries.addItem(e); sortedentries.addItem(e, addpos); }; void PopupMenu::checkCommand(int cmd, int check) { invalidateMenu(); PopupMenuEntry *e = sortedentries.findItem((const wchar_t *) & cmd); if (e) e->setChecked(check); } void PopupMenu::disableCommand(int cmd, int disable) { invalidateMenu(); PopupMenuEntry *e = sortedentries.findItem((const wchar_t *) & cmd); if (e) e->setDisabled(disable); } int PopupMenu::popAtXY(int x, int y, int native) { rebuildMenu(); #ifdef _WIN32 if (!native) return DoTrackPopup(getOSMenuHandle(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd())) - 1; else return TrackPopupMenuEx(getOSMenuHandle(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd()), NULL) - 1; #elif defined(__APPLE__) return PopUpMenuSelect(getOSMenuHandle(), x, y, 0); #endif } int PopupMenu::popAnchored(int type) { // dropped off the sourceWnd given above #ifdef _WIN32 int flag = 0; switch (type) { case POPUP_ANCHOR_UL: flag |= TPM_LEFTALIGN | TPM_TOPALIGN; break; case POPUP_ANCHOR_LL: flag |= TPM_LEFTALIGN | TPM_BOTTOMALIGN; break; case POPUP_ANCHOR_UR: flag |= TPM_RIGHTALIGN | TPM_TOPALIGN; break; case POPUP_ANCHOR_LR: flag |= TPM_RIGHTALIGN | TPM_BOTTOMALIGN; break; } #endif rebuildMenu(); int x, y; Wasabi::Std::getMousePos(&x, &y); #ifdef _WIN32 return DoTrackPopup(getOSMenuHandle(), flag | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd())) - 1; #elif defined(__APPLE__) return PopUpMenuSelect(getOSMenuHandle(), x, y, 0); #endif } int PopupMenu::popAtMouse() { rebuildMenu(); int x, y; Wasabi::Std::getMousePos(&x, &y); #ifdef _WIN32 return DoTrackPopup(getOSMenuHandle(), TPM_LEFTALIGN | TPM_TOPALIGN | TPM_NONOTIFY | TPM_RETURNCMD | TPM_LEFTBUTTON | TPM_RIGHTBUTTON, x, y, (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd())) - 1; #elif defined(__APPLE__) return PopUpMenuSelect(getOSMenuHandle(), x, y, 0); #endif } int PopupMenu::getNumCommands() { return entries.getNumItems(); } const wchar_t *PopupMenu::getCommandText(int command) { PopupMenuEntry *e = sortedentries.findItem((const wchar_t *) &command); if (e) return e->getText(); return NULL; } OSMENUHANDLE PopupMenu::getOSMenuHandle() { rebuildMenu(); return hmenu; } void PopupMenu::rebuildMenu() { #ifdef WIN32 if (hmenu != NULL) return ; hmenu = CreatePopupMenu(); int i = 0; foreach(entries) PopupMenuEntry *e = entries.getfor(); OSMENUHANDLE submenu = NULL; if (e->getCallback()) { PopupMenu *m = e->getCallback()->popupMenuCallback(this, e->getCallbackParam()); if (m) submenu = m->getOSMenuHandle(); } else if (e->isSubmenu()) { submenu = e->getSubmenu()->getOSMenuHandle(); } InsertMenuW(hmenu, i++, MF_BYPOSITION | (e->getChecked() ? MF_CHECKED : MF_UNCHECKED) | (e->getDisabled() ? MF_GRAYED : 0) | (e->isSeparator() ? MF_SEPARATOR : (e->isSubmenu() ? MF_POPUP : 0) | (e->getText() ? MF_STRING : 0)), e->isSubmenu() ? (UINT_PTR)submenu : e->getCommand() + 1, e->getText()); endfor; #else if (hmenu != NULL) return ; CreateNewMenu(0, 0, &hmenu); foreach(entries) PopupMenuEntry *e = entries.getfor(); OSMENUHANDLE submenu = NULL; if (e->getCallback()) { PopupMenu *m = e->getCallback()->popupMenuCallback(this, e->getCallbackParam()); if (m) submenu = m->getOSMenuHandle(); } else if (e->isSubmenu()) { submenu = e->getSubmenu()->getOSMenuHandle(); } const wchar_t *name = e->getText(); CFStringRef menuStr = CFStringCreateWithBytes(kCFAllocatorDefault, (UInt8 *)name, wcslen(name)*sizeof(wchar_t), kCFStringEncodingUTF32, false); MenuItemIndex newMenuItem; MenuItemAttributes menuAttr = kMenuItemAttrIgnoreMeta; if (e->getDisabled()) menuAttr|=kMenuItemAttrDisabled; if (e->isSeparator()) menuAttr|=kMenuItemAttrSeparator; AppendMenuItemTextWithCFString(hmenu, menuStr, menuAttr, e->getCommand(), &newMenuItem); if (submenu) SetMenuItemHierarchicalMenu(hmenu, newMenuItem, submenu); if (e->getChecked()) CheckMenuItem(hmenu, newMenuItem, true); CFRelease(menuStr); endfor; #endif } void PopupMenu::invalidateMenu() { #ifdef WIN32 if (hmenu) DestroyMenu(hmenu); #elif defined(__APPLE__) if (hmenu) DisposeMenu(hmenu); #endif hmenu = NULL; } void PopupMenu::abort() { #ifdef WIN32 HWND w = (parent ? parent->gethWnd() : WASABI_API_WND->main_getRootWnd()->gethWnd()); PostMessage(w, WM_LBUTTONDOWN, 0, 0xdeadc0de); PostMessage(w, WM_LBUTTONUP, 0, 0xdeadc0de); #elif defined(__APPLE__) CancelMenuTracking(hmenu, true, 0); #endif } #else // WASABI_WANT_FF_POPUP #include #include #include "popup.h" #include #include #include #include #include #include #include #include #include #include #include #include #ifndef WANT_NEW_POPUPMENU #define SELMARGIN 1 // todo: // check marks // more? PopupMenu::PopupMenu(ifc_window *sourceWnd) { ASSERT(sourceWnd != NULL); setStartHidden(1); setRenderRatio(1.0); parentRootWnd = sourceWnd; parentWnd = sourceWnd->getOsWindowHandle(); reverse_side = 0; kbdhooked = 0; keyctrl = 0; toplevelmenu = 0; chainmenu = NULL; lastxy.x = lastxy.y = -1; WASABI_API_WND->appdeactivation_push_disallow(this); init(sourceWnd->getOsModuleHandle(), parentWnd, TRUE); WASABI_API_WND->appdeactivation_pop_disallow(this); } PopupMenu::PopupMenu() { setStartHidden(1); setRenderRatio(1.0); parentRootWnd = NULL; parentWnd = INVALIDOSWINDOWHANDLE; chainmenu = NULL; reverse_side = 0; kbdhooked = 0; toplevelmenu = 0; keyctrl = 0; lastxy.x = lastxy.y = -1; WASABI_API_WND->appdeactivation_push_disallow(this); init(hInstance, WASABI_API_WND->main_getRootWnd()->gethWnd(), TRUE); WASABI_API_WND->appdeactivation_pop_disallow(this); } PopupMenu::PopupMenu(HWND sourceWnd) { parentRootWnd = NULL; parentWnd = sourceWnd; setStartHidden(1); setRenderRatio(1.0); reverse_side = 0; kbdhooked = 0; toplevelmenu = 0; keyctrl = 0; chainmenu = NULL; lastxy.x = lastxy.y = -1; WASABI_API_WND->appdeactivation_push_disallow(this); init(hInstance, sourceWnd, TRUE); WASABI_API_WND->appdeactivation_pop_disallow(this); } PopupMenu::PopupMenu(PopupMenu *sourceWnd) { parentRootWnd = sourceWnd; parentWnd = sourceWnd->gethWnd(); setStartHidden(1); setRenderRatio(1.0); reverse_side = 0; kbdhooked = 0; toplevelmenu = 0; chainmenu = NULL; keyctrl = 0; lastxy.x = lastxy.y = -1; WASABI_API_WND->appdeactivation_push_disallow(this); init(sourceWnd, TRUE); WASABI_API_WND->appdeactivation_pop_disallow(this); } int PopupMenu::onInit() { POPUPMENU_PARENT::onInit(); bdown = 0; lastitem = -1; rcp = 0; openmenuid = -1; timerset = 0; timeritem = -1; rcode = -1; toplevelmenu = 0; disable_autopop = 0; popupdelay = 250; //TODO: Config #ifdef WASABI_COMPILE_CONFIG // {9149C445-3C30-4e04-8433-5A518ED0FDDE} const GUID uioptions_guid = { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } }; setTransparency(_intVal(WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid), "Popup menu alpha", 255)); #else setTransparency(255); #endif tex = "wasabi.popup.menu.background"; ful = "wasabi.popup.menu.border.topLeft"; fur = "wasabi.popup.menu.border.topRight"; fll = "wasabi.popup.menu.border.bottomLeft"; flr = "wasabi.popup.menu.border.bottomRight"; fl = "wasabi.popup.menu.border.left"; fr = "wasabi.popup.menu.border.right"; ft = "wasabi.popup.menu.border.top"; fb = "wasabi.popup.menu.border.bottom"; sl = "wasabi.popup.menu.selection.left"; sr = "wasabi.popup.menu.selection.right"; sc = "wasabi.popup.menu.selection.center"; return 1; } PopupMenu::~PopupMenu() { if (kbdhooked) { WASABI_API_WND->unhookKeyboard(this); kbdhooked = 0; } int x, n; n = items.getNumItems(); for (x = 0; x < n; x ++) { if (items[x]) { if (items[x]->butt) delete items[x]->butt; if (items[x]->menu) delete items[x]->menu; delete items[x]; } } } void PopupMenu::addSubMenu(PopupMenu *menu, const wchar_t *text, int disabled) { ASSERT(text != NULL); ButtonWnd *b = new ButtonWnd(); b->init(this); b->setParent(this); b->setNotifyId( -1); b->setButtonText(translateButtonText(text), 14); // b->setTextJustification(BUTTONJUSTIFY_LEFT); b->setTextAlign(TEXTALIGN_LEFT); b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText"); if (disabled) b->enableButton(FALSE); ItemT *t = new ItemT; t->issep = 0; t->butt = b; t->menu = menu; t->cmd = -1; t->cb = NULL; items.addItem(t); } void PopupMenu::addSubMenuImage(PopupMenu *menu, const char *bitmap, const char *pushedbitmap, const char *highlightbitmap) { ButtonWnd *b = new ButtonWnd(); b->init(this); b->setParent(this); b->setBitmaps(bitmap, pushedbitmap, highlightbitmap); b->setBitmapCenter(1); b->setNotifyId( -1); b->setAutoDim(1); b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText"); ItemT *t = new ItemT; t->issep = 0; t->butt = b; t->menu = menu; t->cb = NULL; t->cmd = -1; items.addItem(t); } void PopupMenu::addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param) { ASSERT(text != NULL); ASSERT(cb != NULL); ButtonWnd *b = new ButtonWnd(); b->init(this); b->setParent(this); b->setNotifyId( -1); b->setButtonText(translateButtonText(text), 14); // b->setTextJustification(BUTTONJUSTIFY_LEFT); b->setTextAlign(TEXTALIGN_LEFT); b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText"); ItemT *t = new ItemT; t->issep = 0; t->butt = b; t->menu = 0; t->cb = cb; t->cbparam = param; t->cmd = -1; items.addItem(t); } void PopupMenu::addSeparator(int addpos) { ButtonWnd *b = new ButtonWnd(); b->init(this); b->setParent(this); b->setNotifyId( -1); b->setBitmaps("wasabi.popup.menu.seperator"); b->setBitmapCenter(0); b->enableButton(0); b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText"); ItemT *t = new ItemT; t->issep = 1; t->butt = b; t->menu = 0; t->cb = NULL; t->cmd = -1; items.addItem(t, addpos); } void PopupMenu::addCommandImage(const char *bitmap, const char *pushedbitmap, const char *highlightbitmap, int command, int checked, int disabled, int addpos) { ButtonWnd *b = new ButtonWnd(); b->init(this); b->setParent(this); b->setBitmaps(bitmap, pushedbitmap, highlightbitmap); b->setBitmapCenter(1); b->setNotifyId(command); b->enableButton(disabled ? 0 : 1); b->setChecked(checked ? 1 : 0); b->setAutoDim(1); b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText"); ItemT *t = new ItemT; t->issep = 0; t->butt = b; t->menu = 0; t->cb = NULL; t->cmd = -1; items.addItem(t); } void PopupMenu::addCommand(const wchar_t *_txt, int command, int checked, int disabled, int addpos) { if (!_txt) { addSeparator(); return ; } String txt = translateButtonText(_txt); ButtonWnd *b = new ButtonWnd(); b->init(this); b->setParent(this); b->setNotifyId(disabled ? -1 : command); #ifdef WASABI_COMPILE_LOCALES const wchar_t *bind = (command != 0) ? WASABI_API_LOCALE->locales_getBindFromAction(command) : NULL; if (bind) txt += StringPrintfW(L"\t%s", bind); #endif b->setButtonText(txt); // b->setTextJustification(BUTTONJUSTIFY_LEFT); b->setTextAlign(TEXTALIGN_LEFT); b->enableButton(disabled ? 0 : 1); b->setChecked(checked); if (checked == 2) b->setAlpha(128); b->setColors("wasabi.popup.text", "wasabi.popup.hiliteText", "wasabi.button.dimmedText"); ItemT *t = new ItemT; t->issep = 0; t->butt = b; t->menu = 0; t->cmd = command; t->cb = NULL; ASSERT(PTRLIST_POS_LAST == -1); //BU items.addItem(t, addpos); } void PopupMenu::disableCommand(int cmd, int disable) { for (int i = 0;i < items.getNumItems();i++) if (items.enumItem(i)->cmd == cmd) { if (items.enumItem(i)->butt) items.enumItem(i)->butt->enableButton(!!!disable); break; } } void PopupMenu::checkCommand(int cmd, int check) { for (int i = 0;i < items.getNumItems();i++) if (items.enumItem(i)->cmd == cmd) { if (items.enumItem(i)->butt) items.enumItem(i)->butt->setChecked(check); break; } } const wchar_t *PopupMenu::getCommandText(int command) { for (int i = 0;i < items.getNumItems();i++) if (items.enumItem(i)->cmd == command && items.enumItem(i)->butt) return items.enumItem(i)->butt->getName(); return NULL; } int PopupMenu::popAtXY(int x, int y) { toplevelmenu = 1; rcode = -1; if (items.getNumItems()) { POINT pt = {x, y}; #ifdef WIN32 HWND oldcw = GetCapture(); // nonportable ifc_window *oldcrw = (ifc_window*)GetWindowLong(oldcw, GWL_USERDATA); if (oldcrw != NULL) oldcrw->cancelCapture(); #endif WASABI_API_SYSCB->syscb_registerCallback(static_cast(this)); showAtXY(x, y, &rcode); beginCapture(); MSG msg; #ifdef WIN32 SetCursor(LoadCursor(NULL, IDC_ARROW)); // NONPORTABLE #endif while (rcode == -1 && GetMessage( &msg, INVALIDOSWINDOWHANDLE, 0, 0 )) { TranslateMessage(&msg); DispatchMessage(&msg); } endCapture(); hide(); // if (hadcapture && under) under->beginCapture(); #ifdef WIN32 if (rcode == -2 || rcode == -3) { DWORD p = GetMessagePos(); POINT pt; pt.x = (signed short)LOWORD(p); pt.y = (signed short)HIWORD(p); HWND w = WindowFromPoint(pt); ScreenToClient(w, &pt); p = (pt.x & 0xFFFF) | (pt.y << 16); //if (under) under->getRootParent()->wndProc(under->getRootParent()->gethWnd(), WM_MOUSEMOVE, 0, p); //PostMessage(w, (rcode == -2) ? WM_MOUSEMOVE : WM_RBUTTONDOWN, 0, p); //PostMessage(w, (rcode == -2) ? WM_LBUTTONDOWN : WM_RBUTTONDOWN, 0, p); } #else DebugString("portme: popup.cpp pass on click"); #endif } WASABI_API_SYSCB->syscb_deregisterCallback(static_cast(this)); //DebugString("appdeactivation_pop_disallow\n"); WASABI_API_WND->appdeactivation_pop_disallow(this); onPostPop(rcode); #ifdef WASABI_COMPILE_SKIN if (!switchskinto.isempty()) { WASABI_API_SKIN->skin_switchSkin(switchskinto.getNonConstVal()); switchskinto = ""; } #endif return rcode; } void PopupMenu::showAtXY(int x, int y, int *rc, int revside, int parentW) { int i, n; int w = 0, h = 0; lastitem = -1; rcp = rc; n = items.getNumItems(); for (i = 0; i < n; i ++) { if (items[i]->menu || items[i]->cb) items[i]->butt->setRightBitmap("wasabi.popup.menu.submenu"); if (!items[i]->butt->getChecked()) items[i]->butt->setChecked( -1); h += items[i]->butt->getHeight(); items[i]->butt->setUseBaseTexture(0); items[i]->butt->setBorders(0); int tw = items[i]->butt->getWidth(); if (w < tw)w = tw; } int neww = w + 6 + fl.getWidth() + fr.getWidth(); int newh = h + 6 + ft.getHeight() + fb.getHeight(); POINT p = {x, y}; RECT vp; Std::getViewport(&vp, &p); // maintain parent's reversal state reverse_side = revside; int savx = x; if (reverse_side) x -= (neww + parentW); if (x + neww > vp.right || x < 0) { reverse_side = !reverse_side; x = savx; if (reverse_side) x -= (neww + parentW); } if (y + newh > vp.bottom) y -= newh; if (x < vp.left) x = vp.left; if (y < vp.top) y = vp.top; resize(x, y, neww, newh); h = 0; for (i = 0; i < n; i ++) { int lh = h; h += items[i]->butt->getHeight(); items[i]->butt->resize(3 + fl.getWidth(), 3 + lh + ft.getHeight(), w, h - lh); items[i]->butt->setHilite(0); items[i]->butt->setPushed(0); } WASABI_API_WND->appdeactivation_push_disallow(this); #ifdef WIN32 SetWindowPos(gethWnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); #elif defined(LINUX) Atom NET_STATE = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE", True ); Atom state[2]; state[0] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", True ); state[1] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_ABOVE", True ); if ( NET_STATE && state[0] && state[1] ) { XChangeProperty( Linux::getDisplay(), gethWnd(), NET_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *)state, 2 ); } #endif WASABI_API_WND->appdeactivation_pop_disallow(this); setVisible(1); } void PopupMenu::onSetVisible(int v) { POPUPMENU_PARENT::onSetVisible(v); if (v && !kbdhooked) { WASABI_API_WND->hookKeyboard(this); kbdhooked = 1; } else if (!v && kbdhooked) { WASABI_API_WND->unhookKeyboard(this); kbdhooked = 0; } } void PopupMenu::hide() { if (lastitem >= 0 && items[lastitem]->menu) { items[lastitem]->menu->hide(); lastitem = -1; } setVisible(0); } int PopupMenu::popAnchored(int type) { RECT wr; if (parentRootWnd != NULL) { parentRootWnd->getWindowRect(&wr); } else if (parentWnd != INVALIDOSWINDOWHANDLE) { #ifdef WIN32 GetWindowRect(parentWnd, &wr); #else DebugString("portme PopupMenu::popAnchored\n"); #endif } else { ASSERTALWAYS("can't call popAnchored without instantiating with a parent window"); } switch (type) { case POPUP_ANCHOR_UL: return popAtXY(wr.left, wr.top); case POPUP_ANCHOR_LL: return popAtXY(wr.left, wr.bottom); case POPUP_ANCHOR_UR: return popAtXY(wr.right, wr.top); case POPUP_ANCHOR_LR: return popAtXY(wr.right, wr.bottom); } return 0; } int PopupMenu::popAtMouse() { int x, y; Std::getMousePos(&x, &y); return popAtXY(x, y); } int PopupMenu::childNotify(ifc_window *child, int msg, intptr_t p1, intptr_t p2) { if (msg == ChildNotify::BUTTON_LEFTPUSH || msg == ChildNotify::BUTTON_RIGHTPUSH) { for (int i = 0;i < items.getNumItems();i++) { if (child == items[i]->butt && (items[i]->menu || items[i]->cb)) { if (!items[i]->butt->getEnabled()) continue; if (items[i]->cb) initMenuCallback(i); if (!items[i]->menu) continue; if (openmenuid == i) continue; RECT r; if (openmenuid >= 0) { items[openmenuid]->menu->hide(); openmenuid = -1; } items[i]->butt->getWindowRect(&r); PopupMenu *p = items[i]->menu; p->showAtXY(r.right, r.top, rcp, reverse_side, r.right - r.left); if (p1) { p->selectFirst(); } openmenuid = i; } } // mig: changed this to call getNotifyId(); // *rcp=p1; *rcp = child->getNotifyId(); return 0; } if (msg == ChildNotify::POPUP_SUBMENUCLOSE) { for (int i = 0;i < items.getNumItems();i++) { if (child == items[i]->menu) { if (openmenuid != i) continue; items[openmenuid]->menu->hide(); openmenuid = -1; return 0; } } } return POPUPMENU_PARENT::childNotify(child, msg, p1, p2); } void PopupMenu::selectFirst() { ButtonWnd *b = NULL; int i; for (i = 0; i < items.getNumItems(); i++) { b = items.enumItem(i)->butt; if (b != NULL) break; } if (b == NULL) return ; lastitem = i; b->setHilite(1); invalidate(); } int PopupMenu::getWhichItem(POINT &p) { int x, n; RECT r2; getWindowRect(&r2); n = items.getNumItems(); for (x = 0; x < n; x ++) { RECT r; items[x]->butt->getWindowRect(&r); r.right = r2.right; r.left = r2.left; if (Std::pointInRect(r, p)) { return x; } } return -1; } int PopupMenu::isMine(int x, int y) { RECT r; getWindowRect(&r); POINT p = {x, y}; if (Std::pointInRect(r, p)) return 1; if (lastitem >= 0 && items[lastitem]->menu && items[lastitem]->menu->isMine(x, y)) return 1; return 0; } void PopupMenu::setFriendlyId(const char *id) { friendid = id; } int PopupMenu::onLeftButtonDown(int x, int y) { clientToScreen(&x, &y); onButtonDown(1, x, y); return 0; } int PopupMenu::onRightButtonDown(int x, int y) { clientToScreen(&x, &y); onButtonDown(2, x, y); return 0; } int PopupMenu::onMouseMove(int x, int y) { POPUPMENU_PARENT::onMouseMove(x, y); POINT pnt = {x, y}; clientToScreen(&pnt); if (keyctrl && lastxy.x == pnt.x && lastxy.y == pnt.y) return 1; keyctrl = 0; lastxy = pnt; if (lastitem >= 0) { if (openmenuid >= 0 && items[openmenuid]->menu && items[openmenuid]->menu->isMine(pnt.x, pnt.y)) { if (lastitem != openmenuid) { items[lastitem]->butt->setHilite(0); items[lastitem]->butt->setPushed(0); items[openmenuid]->butt->setHilite(1); items[openmenuid]->butt->setPushed(1); invalidateItem(lastitem); lastitem = openmenuid; invalidateItem(lastitem); } resetTimer( -1); items[openmenuid]->menu->screenToClient(&pnt); items[openmenuid]->menu->onMouseMove(pnt.x, pnt.y); return 0; } } int p = getWhichItem(pnt); if (p >= 0) { ItemT *it = items[p]; if (!it->issep) { if (p != lastitem) { if (lastitem >= 0) { /* if (items[lastitem]->menu) { items[lastitem]->menu->hide(); }*/ items[lastitem]->butt->setHilite(0); items[lastitem]->butt->setPushed(0); invalidateItem(lastitem); } invalidateItem(lastitem); lastitem = p; invalidateItem(lastitem); items[p]->butt->setHilite(1); if (bdown) items[p]->butt->setPushed(1); /* if (items[p]->menu) { RECT r; items[p]->butt->getWindowRect(&r); items[p]->menu->showAtXY(r.right,r.top,rcp); }*/ resetTimer(p); invalidateItem(lastitem); } } else { RECT _r; getClientRect(&_r); int inside = (x >= 0 && y >= 0 && x <= _r.right - _r.left && y <= _r.bottom - _r.top); if (lastitem >= 0 && !inside) { items[lastitem]->butt->setHilite(0); items[lastitem]->butt->setPushed(0); invalidateItem(lastitem); lastitem = -1; } } } else { if (!friendid.isempty()) { ifc_window *w = WASABI_API_WND->rootWndFromPoint(&pnt); if (w != NULL) { MenuButtonSurface *s = static_cast(w->getInterface(menuButtonSurfaceGuid)); if (s != NULL) { if (s->getParentWnd() != parentRootWnd) { const char *str = s->getParentMenuId(); if (STRCASEEQLSAFE(str, friendid)) { abort(); rcode = -4; chainmenu = s; } } } } } } return 0; } void PopupMenu::resetTimer(int p) { if (timerset) { killTimer(POPUP_TIMERID); timeritem = -1; } if (p >= 0 && !disable_autopop) { setTimer(POPUP_TIMERID, popupdelay); timeritem = p; timerset = 1; } } void PopupMenu::timerCallback(int id) { switch (id) { case POPUP_TIMERID: killTimer(POPUP_TIMERID); timerset = 0; if (timeritem == openmenuid) { timeritem = -1; break; } if (openmenuid >= 0 && items[openmenuid]->menu) { items[openmenuid]->menu->hide(); openmenuid = -1; } if (timeritem >= 0) { if (items[timeritem]->cb) initMenuCallback(timeritem); if (items[timeritem]->butt->getEnabled() && items[timeritem]->menu) { RECT r; items[timeritem]->butt->getWindowRect(&r); items[timeritem]->menu->showAtXY(r.right, r.top, rcp, reverse_side, r.right - r.left); openmenuid = timeritem; } timeritem = -1; } break; default: POPUPMENU_PARENT::timerCallback(id); break; } } void PopupMenu::initMenuCallback(int item) { int a = rcode; rcode = 0; PopupMenu *p = items[item]->cb->popupMenuCallback(this, items[item]->cbparam); rcode = a; if (p) { items[item]->cb = NULL; items[item]->menu = p; } } int PopupMenu::onLeftButtonUp(int x, int y) { clientToScreen(&x, &y); onButtonUp(1, x, y); return 0; } int PopupMenu::onRightButtonUp(int x, int y) { clientToScreen(&x, &y); onButtonUp(2, x, y); return 0; } void PopupMenu::onButtonDown(int wb, int x, int y) { POINT pos = {x, y}; RECT r; bdown |= wb; if (lastitem >= 0) { if (items[lastitem]->menu && items[lastitem]->menu->isMine(pos.x, pos.y)) { items[lastitem]->menu->onButtonDown(wb, x, y); return ; } } getWindowRect(&r); if (!Std::pointInRect(r, pos)) { rcode = (wb == 1) ? -2 : -3; } else { int item = getWhichItem(pos); if (item >= 0) items[item]->butt->setPushed(1); } } void PopupMenu::onButtonUp(int wb, int x, int y) { if (lastitem >= 0) { POINT pos = {x, y}; if (items[lastitem]->menu && items[lastitem]->menu->isMine(pos.x, pos.y)) { items[lastitem]->menu->onButtonUp(wb, x, y); return ; } } if (bdown & wb) { bdown &= ~wb; POINT pnt = {x, y}; int p = getWhichItem(pnt); if (p >= 0) { items[p]->butt->onLeftPush(x, y); if (!bdown) { items[p]->butt->setPushed(0); } } } } int PopupMenu::onKillFocus() { #ifndef LINUX if (rcode == -1) rcode = -2; #endif return POPUPMENU_PARENT::onKillFocus(); } // only translates the text, not the optional accelerator String PopupMenu::translateButtonText(const wchar_t *text) { PathParser pp(text, "\t"); String ret; for (int i = 0; i < pp.getNumStrings(); i++) { if (i == 0) ret += _(pp.enumString(i)); // translate first else ret += pp.enumString(i); if (i != pp.getNumStrings() - 1) ret += "\t"; } return ret; } int PopupMenu::onPaint(Canvas *canvas) { PaintBltCanvas paintcanvas; if (canvas == NULL) { if (!paintcanvas.beginPaint(this)) return 0; canvas = &paintcanvas; } POPUPMENU_PARENT::onPaint(canvas); RECT r, r2; getClientRect(&r); tex.getBitmap()->blitTile(canvas, &r); // left side ful.getBitmap()->blitAlpha(canvas, 0, 0); r2.left = 0; r2.right = fl.getWidth(); r2.top = ful.getHeight(); r2.bottom = r.bottom - fll.getHeight(); fl.getBitmap()->stretchToRectAlpha(canvas, &r2); fll.getBitmap()->blitAlpha(canvas, 0, r.bottom - fll.getHeight()); // right side fur.getBitmap()->blitAlpha(canvas, r.right - fur.getWidth(), 0); r2.left = r.right - fr.getWidth(); r2.right = r.right; r2.top = fur.getHeight(); r2.bottom = r.bottom - flr.getHeight(); fr.getBitmap()->stretchToRectAlpha(canvas, &r2); flr.getBitmap()->blitAlpha(canvas, r.right - flr.getWidth(), r.bottom - flr.getHeight()); // top r2.left = ful.getWidth(); r2.right = r.right - fur.getWidth(); r2.top = 0; r2.bottom = ft.getHeight(); ft.getBitmap()->stretchToRectAlpha(canvas, &r2); // bottom r2.left = fll.getWidth(); r2.right = r.right - flr.getWidth(); r2.top = r.bottom - fb.getHeight(); r2.bottom = r.bottom; fb.getBitmap()->stretchToRectAlpha(canvas, &r2); // selection bar if (lastitem != -1) { ItemT *it = items[lastitem]; RECT r3, c; it->butt->getClientRect(&r3); // left r2.left = r.left + fl.getWidth() + SELMARGIN; r2.top = r.top + r3.top; r2.right = r2.left + sl.getWidth(); r2.bottom = r2.top + (r3.bottom - r3.top); sl.getBitmap()->stretchToRectAlpha(canvas, &r2); c = r2; c.left = c.right - 1; // right r2.right = r.right - fr.getWidth() - SELMARGIN; r2.left = r2.right - sr.getWidth(); sr.getBitmap()->stretchToRectAlpha(canvas, &r2); c.right = r2.left; // center sc.getBitmap()->stretchToRectAlpha(canvas, &c); } return 1; } void PopupMenu::invalidateItem(int i) { if (i < 0 || i >= items.getNumItems()) return ; RECT r, r2, r3; getClientRect(&r); ItemT *it = items[i]; it->butt->getClientRect(&r3); r2.left = r.left + fl.getWidth(); r2.top = r.top + r3.top; r2.right = r.right - fl.getWidth(); r2.bottom = r2.top + (r3.bottom - r3.top); invalidateRect(&r2); } int PopupMenu::getNumCommands() { return items.getNumItems(); } #ifdef WASABI_COMPILE_SKIN int PopupMenu::skincb_onCheckPreventSwitch(const char *skinname) { switchskinto = skinname; rcode = -2; return 1; } #endif int PopupMenu::onSysKeyDown(int code, int d) { int a = POPUPMENU_PARENT::onSysKeyDown(code, d); /* if (d & (1<<29)) { //ALT key pressed, abort menu (mimics win32 popup behavior) abort(); if(getParent()) SendMessageW(getParent()->gethWnd(),WM_SYSKEYDOWN,code,d); return 0; }*/ if (a == 0) return onKeyDown(code); return 0; } int PopupMenu::onKeyDown(int code) { if (POPUPMENU_PARENT::onKeyDown(code)) return 1; switch (code) { case STDKEY_DOWN: navigate(1); return 1; case STDKEY_UP: navigate( -1); return 1; case STDKEY_RETURN: navigate(0, 1); return 1; case STDKEY_RIGHT: navigate(0, 0); return 1; case VK_LEFT: if (!toplevelmenu) notifyParent(ChildNotify::POPUP_SUBMENUCLOSE); return 1; case VK_ESCAPE: abort(); return 1; } return 0; } void PopupMenu::abort() { if (toplevelmenu) rcode = -2; else notifyParent(ChildNotify::POPUP_SUBMENUCLOSE); } void PopupMenu::navigate(int p, int f) { keyctrl = 1; int i = lastitem; ItemT *t = NULL; if (p == 0) { if (lastitem >= 0) { ItemT *t = items.enumItem(lastitem); if (f || t->menu || t->cb) { t->butt->setHilite(1); t->butt->setPushed(1); childNotify(t->butt, ChildNotify::BUTTON_LEFTPUSH, 1, 0); } } return ; } while (!t || t->issep) { i += p; i %= items.getNumItems(); if (i == -1) i = items.getNumItems() - 1; if (i >= items.getNumItems()) return ; t = items.enumItem(i); } if (t->butt) { int i; i = items.searchItem(t); t->butt->setHilite(1); if (lastitem != -1) { ItemT *s = items.enumItem(lastitem); if (s->butt) { s->butt->setPushed(0); s->butt->setHilite(0); } } lastitem = i; invalidate(); } } #else //------------------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------------------------------------------------ // 3rd level popup menu, yay #include "script/c_script/c_text.h" #include "script/c_script/c_rootobj.h" #include "script/c_script/c_button.h" #include "script/c_script/c_group.h" PopupMenu::PopupMenu(ifc_window *sourceWnd) { ASSERT(sourceWnd != NULL); myInit(); setParent(sourceWnd); sourceWnd->setAllowDeactivation(0); init(HINSTANCEfromHWND(getParent()->gethWnd()), sourceWnd->gethWnd(), TRUE); sourceWnd->setAllowDeactivation(1); } PopupMenu::PopupMenu() { myInit(); setParent(WASABI_API_WND->main_getRootWnd()); WASABI_API_WND->main_getRootWnd()->setAllowDeactivation(0); init(hInstance, WASABI_API_WND->main_getRootWnd()->gethWnd(), TRUE); WASABI_API_WND->main_getRootWnd()->setAllowDeactivation(1); } PopupMenu::PopupMenu(PopupMenu *sourceWnd) { myInit(); setParent(sourceWnd); sourceWnd->setAllowDeactivation(0); init(GetModuleHandle(NULL), sourceWnd->gethWnd(), TRUE); sourceWnd->setAllowDeactivation(1); } void PopupMenu::myInit() { setVirtual(0); setStartHidden(1); setRenderRatio(1.0); reverse_side = 0; rcode = 0; submenus = 0; c_grouplist = NULL; WASABI_API_WND->popupexit_register(this, this); } PopupMenu::~PopupMenu() { WASABI_API_WND->popupexit_deregister(this); delete c_grouplist; } int PopupMenu::onInit() { POPUPMENU_PARENT::onInit(); #ifdef WASABI_COMPILE_CONFIG // {9149C445-3C30-4e04-8433-5A518ED0FDDE} const GUID uioptions_guid = { 0x9149c445, 0x3c30, 0x4e04, { 0x84, 0x33, 0x5a, 0x51, 0x8e, 0xd0, 0xfd, 0xde } }; setTransparency(_intVal(WASABI_API_CONFIG->config_getCfgItemByGuid(uioptions_guid), "Popup menu alpha", 255)); #else setTransparency(255); #endif setContent("wasabi.popup.main.group"); return 1; } int PopupMenu::popAtXY(int x, int y) { rcode = -1; if (1 /*items.getNumItems()*/) { POINT pt = {x, y}; //DebugString("appdeactivation_push_disallow\n"); WASABI_API_WND->appdeactivation_push_disallow(this); showAtXY(x, y, &rcode); //MSG msg; /*while (rcode == -1 && GetMessage( &msg, NULL, 0, 0 )) { TranslateMessage(&msg); DispatchMessage(&msg); }*/ SetCursor(LoadCursor(NULL, IDC_ARROW)); // NONPORTABLE int quit = 0; while (!quit) { rcode = getGuiObject()->guiobject_runModal(); if (rcode & 0x40000000 && rcode != -2 && rcode != -1) { int submenuentry = rcode & ~0x40000000; ItemT *t = items.enumItem(submenuentry); if (t->cb != NULL) initMenuCallback(submenuentry); if (t->menu != NULL) { setAllowDeactivation(0); t->menu->showAtXY(0, 0, NULL, 0, 0); setAllowDeactivation(1); } } else quit = 1; } setVisible(0); } //DebugString("appdeactivation_pop_disallow\n"); WASABI_API_WND->appdeactivation_pop_disallow(this); onPostPop(rcode); return rcode; } void PopupMenu::showAtXY(int x, int y, int *rc, int revside /* =0 */, int parentW /* =0 */) { fillContent(); int neww = getPreferences(SUGGESTED_W); int newh = getPreferences(SUGGESTED_H);; POINT p = {x, y}; RECT vp; Std::getViewport(&vp, &p); // maintain parent's reversal state reverse_side = revside; int savx = x; if (reverse_side) x -= (neww + parentW); if (x + neww > vp.right || x < 0) { reverse_side = !reverse_side; x = savx; if (reverse_side) x -= (neww + parentW); } if (y + newh > vp.bottom) y -= newh; if (x < vp.left) x = vp.left; if (y < vp.top) y = vp.top; resize(x, y, neww, newh); WASABI_API_WND->appdeactivation_push_disallow(this); #ifdef WIN32 SetWindowPos(gethWnd(), HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE); #else Atom NET_STATE = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE", True ); Atom state[2]; state[0] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_SKIP_TASKBAR", True ); state[1] = XInternAtom( Linux::getDisplay(), "_NET_WM_STATE_ABOVE", True ); if ( NET_STATE && state[0] && state[1] ) { XChangeProperty( Linux::getDisplay(), gethWnd(), NET_STATE, XA_ATOM, 32, PropModeReplace, (unsigned char *)state, 2 ); } #endif WASABI_API_WND->appdeactivation_pop_disallow(this); setVisible(1); } int PopupMenu::popAnchored(int type) { RECT wr; getParent()->getWindowRect(&wr); switch (type) { case POPUP_ANCHOR_UL: return popAtXY(wr.left, wr.top); case POPUP_ANCHOR_LL: return popAtXY(wr.left, wr.bottom); case POPUP_ANCHOR_UR: return popAtXY(wr.right, wr.top); case POPUP_ANCHOR_LR: return popAtXY(wr.right, wr.bottom); } return 0; } int PopupMenu::popAtMouse() { int x, y; Std::getMousePos(&x, &y); return popAtXY(x, y); } void PopupMenu::onNewContent() { POPUPMENU_PARENT::onNewContent(); if (isVisible()) fillContent(); } void PopupMenu::fillContent() { GuiObject *grouplist = findObject("popup.content"); if (grouplist != NULL) { delete c_grouplist; c_grouplist = new C_GroupList(*grouplist); c_grouplist->removeAll(); c_grouplist->setRedraw(0); for (int i = 0;i < items.getNumItems();i++) { addItem(items.enumItem(i)); } c_grouplist->setRedraw(1); } } void PopupMenu::addItem(ItemT *i) { if (c_grouplist == NULL) return ; switch (i->type) { case POPUPITEM_TYPE_TEXT: { c_grouplist->instantiate("wasabi.popup.text.item", 1); ScriptObject *o = c_grouplist->enumItem(c_grouplist->getNumItems() - 1); if (o != NULL) { C_Group grp(o); C_RootObject g(o); g.notify("arrow", StringPrintfW(L"%d", (submenus) ? 1 : 0), 0, 0); g.notify("checkmark", StringPrintfW(L"%d", menuchecks ? 1 : 0), 0, 0); g.notify("id", StringPrintfW(L"%d", i->cmd), 0, 0); ScriptObject *check = grp.getObject("popup.item.checkmark"); if (check != NULL) { C_Button toggle(check); toggle.setActivated(i->checked); } ScriptObject *arrow = grp.getObject("popup.item.submenuarrow"); if (check != NULL) { C_Button sub(arrow); sub.setActivated((i->menu != NULL || i->cb != NULL)); } ScriptObject *txt = grp.getObject("popup.item.text"); if (txt != NULL) { C_Text itemtxt(txt); itemtxt.setText(i->txt); } } break; } case POPUPITEM_TYPE_IMAGE: c_grouplist->instantiate("wasabi.popup.image.item", 1); break; case POPUPITEM_TYPE_SEPARATOR: c_grouplist->instantiate("wasabi.popup.separator.item", 1); break; } } String PopupMenu::translateButtonText(const wchar_t *text) { PathParser pp(text, "\t"); String ret; for (int i = 0; i < pp.getNumStrings(); i++) { if (i == 0) ret += _(pp.enumString(i)); // translate first else ret += pp.enumString(i); if (i != pp.getNumStrings() - 1) ret += "\t"; } return ret; } void PopupMenu::addCommand(const wchar_t *_txt, int command, int checked, int disabled, int addpos) { if (!_txt) { addSeparator(); return ; } String txt = translateButtonText(_txt); #ifdef WASABI_COMPILE_LOCALES const char *bind = WASABI_API_LOCALE->locales_getBindFromAction(command); if (bind) txt += StringPrintfW(L"\t%s", bind); #endif ItemT *t = new ItemT; t->type = POPUPITEM_TYPE_TEXT; t->cmd = command; t->txt = txt; t->checked = checked; t->menu = NULL; t->cb = NULL; t->cmd = -1; ASSERT(PTRLIST_POS_LAST == -1); //BU items.addItem(t, addpos); } int PopupMenu::popupexitcb_onExitPopup() { getGuiObject()->guiobject_endModal( -2); return 1; } void PopupMenu::addSubMenu(PopupMenu *menu, const wchar_t *text) { ASSERT(text != NULL); submenus = 1; ItemT *t = new ItemT; t->type = POPUPITEM_TYPE_TEXT; t->cmd = items.getNumItems() | 0x40000000; t->txt = translateButtonText(text); t->checked = 0; t->menu = menu; t->cb = NULL; t->cmd = -1; t->cmd = -1; items.addItem(t); } void PopupMenu::addSubMenuCallback(const wchar_t *text, PopupMenuCallback *cb, int param) { ASSERT(text != NULL); ASSERT(cb != NULL); ItemT *t = new ItemT; submenus = 1; t->type = POPUPITEM_TYPE_TEXT; t->checked = 0; t->cmd = items.getNumItems() | 0x40000000; t->menu = NULL; t->cb = cb; t->cbparam = param; t->txt = translateButtonText(text); t->cmd = -1; items.addItem(t); } void PopupMenu::initMenuCallback(int item) { int a = rcode; rcode = 0; PopupMenu *p = items[item]->cb->popupMenuCallback(this, items[item]->cbparam); rcode = a; if (p) { items[item]->cb = NULL; items[item]->menu = p; } } #endif #endif //WASABI_WANT_FF_POPUP