winamp/Src/Wasabi/api/wnd/contextmenu.cpp

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;
}