#include #include "contextmenu.h" #include #include #define DD_CONTEXTMENUENTRY "ContextMenuEntry v1" class ContextMenuEntry { public: ContextMenuEntry(DragItem *_item, svc_contextCmd *_svc, int _pos, const wchar_t *txt, int _sortval, int _addorder) : svc(_svc), item(_item), pos(_pos), text(txt), sortval(_sortval), addorder(_addorder) { } svc_contextCmd *svc; DragItem *item; int pos; StringW text, submenu_text; int sortval; int addorder; }; class ContextMenuEntryCompare { public: static int compareItem(void *p1, void* p2) { ContextMenuEntry *e1 = static_cast(p1); ContextMenuEntry *e2 = static_cast(p2); int ret = CMP3(e1->sortval, e2->sortval); if (ret == 0) ret = CMP3(e1->addorder, e2->addorder); return ret; } }; ContextMenu::ContextMenu(ifc_window *sourceWnd, DragItem *_item, bool autopop, const wchar_t *_menu_path) : PopupMenu(sourceWnd), item(_item), menu_path(_menu_path) { populate(); if (autopop) popAtMouse(); } ContextMenu::ContextMenu(ifc_window *sourceWnd, int x, int y, DragItem *_item, bool autopop, const wchar_t *_menu_path) : PopupMenu(sourceWnd), item(_item), menu_path(_menu_path) { populate(); if (autopop) popAtXY(x, y); } ContextMenu::ContextMenu(DragItem *_item, const wchar_t *_menu_path) : item(_item), menu_path(_menu_path) { populate(); } ContextMenu::~ContextMenu() { entries.deleteAll(); // release all services for (int i = 0; i < svclist.getNumItems(); i++) SvcEnum::release(svclist.enumItem(i)); } void ContextMenu::addDragItem(DragItem *_item, const wchar_t *_menu_path) { menu_path = _menu_path; item = _item; populate(); } void ContextMenu::populate() { if (item == NULL) return ; ContextCmdEnum cce(item, menu_path); svc_contextCmd *svc; int i, j, addorder = 0; // make a list of all context cmd services that match the menu path for (i = 0; (svc = cce.getNext()) != NULL; i++) { for (j = 0; ; j++) { const wchar_t *text = svc->getCommand(item, j); if (text == NULL) break; if (!wcscmp(text, L"~~~SEP~~~")) text = NULL; // sorry, magic value ContextMenuEntry *entry = new ContextMenuEntry(item, svc, j, text, svc->getSortVal(item, j), addorder++); entries.addItem(entry); } // save the service * to release later svclist.addItem(svc); } // sorting is implicit but just making sure entries.sort(); PtrList submenu_list; #ifdef WASABI_COMPILE_COMPONENTS GUID prev = INVALID_GUID; #endif // populate the menu from the list int n = entries.getNumItems(); for (i = 0; i < n; i++) { ContextMenuEntry *entry = entries.enumItem(i); if (entry->text.isempty()) { addSeparator(); } else { svc_contextCmd *svc = entry->svc; #ifdef WASABI_COMPILE_COMPONENTS GUID g = WASABI_API_SVC->service_getOwningComponent(svc); if (g != prev && prev != INVALID_GUID && i < n - 1) addSeparator(); prev = g; #endif if (!svc->getSubMenu(item, menu_path)) { int checked = entry->svc->getChecked(item, entry->pos); int enabled = entry->svc->getEnabled(item, entry->pos); addCommand(entry->text, reinterpret_cast(entry), checked, !enabled); } else { entry->submenu_text = svc->getSubMenuText(menu_path); if (!entry->submenu_text.isempty()) { for (j = 0; j < submenu_list.getNumItems(); j++) if (!WCSICMP(*submenu_list[j], entry->submenu_text)) break; if (j >= submenu_list.getNumItems()) { submenu_list.addItem(new StringW(entry->submenu_text)); addSubMenuCallback(entry->submenu_text, this, reinterpret_cast(entry)); } } } } } submenu_list.deleteAll(); } void ContextMenu::onPostPop(intptr_t result) { //if (result == -1 || result == -2 || result == -3) return; //FUCKO need real enums if (result < 0) return ; ASSERT(result != 0xcccccccc); ContextMenuEntry *entry = reinterpret_cast(result); if (entry == NULL) return ; entry->svc->onCommand(entry->item, entry->pos); } PopupMenu *ContextMenu::popupMenuCallback(PopupMenu *parent, intptr_t param) { ContextMenuEntry *entry = reinterpret_cast(param); StringW path = menu_path; if (!path.isempty()) path.cat(L"/"); path.cat(entry->submenu_text); ContextMenu *ret = new ContextMenu(entry->item, path); if (ret->getNumCommands() <= 0) { delete ret; ret = NULL; } return ret; }