contextmenu.cpp 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #include <precomp.h>
  2. #include "contextmenu.h"
  3. #include <api/service/svcs/svc_contextcmd.h>
  4. #include <bfc/string/StringW.h>
  5. #define DD_CONTEXTMENUENTRY "ContextMenuEntry v1"
  6. class ContextMenuEntry
  7. {
  8. public:
  9. ContextMenuEntry(DragItem *_item, svc_contextCmd *_svc, int _pos, const wchar_t *txt, int _sortval, int _addorder) :
  10. svc(_svc), item(_item), pos(_pos), text(txt), sortval(_sortval), addorder(_addorder) { }
  11. svc_contextCmd *svc;
  12. DragItem *item;
  13. int pos;
  14. StringW text, submenu_text;
  15. int sortval;
  16. int addorder;
  17. };
  18. class ContextMenuEntryCompare
  19. {
  20. public:
  21. static int compareItem(void *p1, void* p2)
  22. {
  23. ContextMenuEntry *e1 = static_cast<ContextMenuEntry*>(p1);
  24. ContextMenuEntry *e2 = static_cast<ContextMenuEntry*>(p2);
  25. int ret = CMP3(e1->sortval, e2->sortval);
  26. if (ret == 0) ret = CMP3(e1->addorder, e2->addorder);
  27. return ret;
  28. }
  29. };
  30. ContextMenu::ContextMenu(ifc_window *sourceWnd, DragItem *_item, bool autopop, const wchar_t *_menu_path)
  31. : PopupMenu(sourceWnd), item(_item), menu_path(_menu_path)
  32. {
  33. populate();
  34. if (autopop) popAtMouse();
  35. }
  36. ContextMenu::ContextMenu(ifc_window *sourceWnd, int x, int y, DragItem *_item, bool autopop, const wchar_t *_menu_path)
  37. : PopupMenu(sourceWnd), item(_item), menu_path(_menu_path)
  38. {
  39. populate();
  40. if (autopop) popAtXY(x, y);
  41. }
  42. ContextMenu::ContextMenu(DragItem *_item, const wchar_t *_menu_path)
  43. : item(_item), menu_path(_menu_path)
  44. {
  45. populate();
  46. }
  47. ContextMenu::~ContextMenu()
  48. {
  49. entries.deleteAll();
  50. // release all services
  51. for (int i = 0; i < svclist.getNumItems(); i++)
  52. SvcEnum::release(svclist.enumItem(i));
  53. }
  54. void ContextMenu::addDragItem(DragItem *_item, const wchar_t *_menu_path)
  55. {
  56. menu_path = _menu_path;
  57. item = _item;
  58. populate();
  59. }
  60. void ContextMenu::populate()
  61. {
  62. if (item == NULL) return ;
  63. ContextCmdEnum cce(item, menu_path);
  64. svc_contextCmd *svc;
  65. int i, j, addorder = 0;
  66. // make a list of all context cmd services that match the menu path
  67. for (i = 0; (svc = cce.getNext()) != NULL; i++)
  68. {
  69. for (j = 0; ; j++)
  70. {
  71. const wchar_t *text = svc->getCommand(item, j);
  72. if (text == NULL) break;
  73. if (!wcscmp(text, L"~~~SEP~~~")) text = NULL; // sorry, magic value
  74. ContextMenuEntry *entry = new ContextMenuEntry(item, svc, j, text, svc->getSortVal(item, j), addorder++);
  75. entries.addItem(entry);
  76. }
  77. // save the service * to release later
  78. svclist.addItem(svc);
  79. }
  80. // sorting is implicit but just making sure
  81. entries.sort();
  82. PtrList<StringW> submenu_list;
  83. #ifdef WASABI_COMPILE_COMPONENTS
  84. GUID prev = INVALID_GUID;
  85. #endif
  86. // populate the menu from the list
  87. int n = entries.getNumItems();
  88. for (i = 0; i < n; i++)
  89. {
  90. ContextMenuEntry *entry = entries.enumItem(i);
  91. if (entry->text.isempty())
  92. {
  93. addSeparator();
  94. }
  95. else
  96. {
  97. svc_contextCmd *svc = entry->svc;
  98. #ifdef WASABI_COMPILE_COMPONENTS
  99. GUID g = WASABI_API_SVC->service_getOwningComponent(svc);
  100. if (g != prev && prev != INVALID_GUID && i < n - 1)
  101. addSeparator();
  102. prev = g;
  103. #endif
  104. if (!svc->getSubMenu(item, menu_path))
  105. {
  106. int checked = entry->svc->getChecked(item, entry->pos);
  107. int enabled = entry->svc->getEnabled(item, entry->pos);
  108. addCommand(entry->text, reinterpret_cast<intptr_t>(entry), checked, !enabled);
  109. }
  110. else
  111. {
  112. entry->submenu_text = svc->getSubMenuText(menu_path);
  113. if (!entry->submenu_text.isempty())
  114. {
  115. for (j = 0; j < submenu_list.getNumItems(); j++)
  116. if (!WCSICMP(*submenu_list[j], entry->submenu_text)) break;
  117. if (j >= submenu_list.getNumItems())
  118. {
  119. submenu_list.addItem(new StringW(entry->submenu_text));
  120. addSubMenuCallback(entry->submenu_text, this, reinterpret_cast<intptr_t>(entry));
  121. }
  122. }
  123. }
  124. }
  125. }
  126. submenu_list.deleteAll();
  127. }
  128. void ContextMenu::onPostPop(intptr_t result)
  129. {
  130. //if (result == -1 || result == -2 || result == -3) return; //FUCKO need real enums
  131. if (result < 0) return ;
  132. ASSERT(result != 0xcccccccc);
  133. ContextMenuEntry *entry = reinterpret_cast<ContextMenuEntry*>(result);
  134. if (entry == NULL) return ;
  135. entry->svc->onCommand(entry->item, entry->pos);
  136. }
  137. PopupMenu *ContextMenu::popupMenuCallback(PopupMenu *parent, intptr_t param)
  138. {
  139. ContextMenuEntry *entry = reinterpret_cast<ContextMenuEntry*>(param);
  140. StringW path = menu_path;
  141. if (!path.isempty())
  142. path.cat(L"/");
  143. path.cat(entry->submenu_text);
  144. ContextMenu *ret = new ContextMenu(entry->item, path);
  145. if (ret->getNumCommands() <= 0)
  146. {
  147. delete ret;
  148. ret = NULL;
  149. }
  150. return ret;
  151. }