171 lines
4.4 KiB
C++
171 lines
4.4 KiB
C++
|
#include <precomp.h>
|
||
|
|
||
|
#include "contextmenu.h"
|
||
|
#include <api/service/svcs/svc_contextcmd.h>
|
||
|
#include <bfc/string/StringW.h>
|
||
|
|
||
|
#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<ContextMenuEntry*>(p1);
|
||
|
ContextMenuEntry *e2 = static_cast<ContextMenuEntry*>(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<StringW> 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<intptr_t>(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<intptr_t>(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<ContextMenuEntry*>(result);
|
||
|
if (entry == NULL) return ;
|
||
|
entry->svc->onCommand(entry->item, entry->pos);
|
||
|
}
|
||
|
|
||
|
PopupMenu *ContextMenu::popupMenuCallback(PopupMenu *parent, intptr_t param)
|
||
|
{
|
||
|
ContextMenuEntry *entry = reinterpret_cast<ContextMenuEntry*>(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;
|
||
|
}
|