aboutsummaryrefslogtreecommitdiff
path: root/Src/Plugins/Library/ml_devices/navigation.cpp
diff options
context:
space:
mode:
authorJean-Francois Mauguit <jfmauguit@mac.com>2024-09-24 09:03:25 -0400
committerGitHub <noreply@github.com>2024-09-24 09:03:25 -0400
commitbab614c421ed7ae329d26bf028c4a3b1d2450f5a (patch)
tree12f17f78986871dd2cfb0a56e5e93b545c1ae0d0 /Src/Plugins/Library/ml_devices/navigation.cpp
parent4bde6044fddf053f31795b9eaccdd2a5a527d21f (diff)
parent20d28e80a5c861a9d5f449ea911ab75b4f37ad0d (diff)
downloadwinamp-bab614c421ed7ae329d26bf028c4a3b1d2450f5a.tar.gz
Merge pull request #5 from WinampDesktop/community
Merge to main
Diffstat (limited to 'Src/Plugins/Library/ml_devices/navigation.cpp')
-rw-r--r--Src/Plugins/Library/ml_devices/navigation.cpp1073
1 files changed, 1073 insertions, 0 deletions
diff --git a/Src/Plugins/Library/ml_devices/navigation.cpp b/Src/Plugins/Library/ml_devices/navigation.cpp
new file mode 100644
index 00000000..25fade94
--- /dev/null
+++ b/Src/Plugins/Library/ml_devices/navigation.cpp
@@ -0,0 +1,1073 @@
+#include "main.h"
+#include "./navigation.h"
+
+#include <strsafe.h>
+
+#define DEVICES_NAVITEM_PREFIX L"ml_devices_"
+
+static HNAVITEM navigationRoot = NULL;
+static size_t deviceHandler = 0;
+
+static HNAVITEM
+NavigationItem_Insert(HNAVITEM parent,
+ HNAVITEM insertAfter,
+ unsigned int mask,
+ int itemId,
+ const wchar_t *name,
+ const wchar_t *displayName,
+ unsigned int style,
+ int image,
+ LPARAM param)
+{
+ NAVITEM *item;
+ NAVINSERTSTRUCT nis = {0};
+
+ nis.hInsertAfter = insertAfter;
+ nis.hParent = parent;
+ item = &nis.item;
+
+ item->cbSize = sizeof(NAVITEM);
+ item->id = itemId;
+
+ if (0 != (NIMF_IMAGE & mask))
+ mask |= NIMF_IMAGESEL;
+
+ item->mask = mask;
+ item->pszText = (wchar_t*)displayName;
+ item->pszInvariant = (wchar_t*)name;
+ item->style = style;
+ item->styleMask = style;
+ item->iImage = image;
+ item->iSelectedImage = image;
+ item->lParam = param;
+
+ if (!wcsnicmp(L"ml_devices_all_sources", item->pszInvariant, 22))
+ {
+ // and this will allow us to make the cloud library
+ // root do a web page or a sources view as needed...
+ return NULL;
+ }
+
+ return MLNavCtrl_InsertItem(Plugin_GetLibraryWindow(), &nis);
+}
+
+static BOOL
+NavigationItem_Delete(HNAVITEM item)
+{
+ return MLNavCtrl_DeleteItem(Plugin_GetLibraryWindow(), item);
+}
+
+static HNAVITEM
+NavigationItem_GetFromMessage(INT msg, INT_PTR param)
+{
+ return (msg < ML_MSG_NAVIGATION_FIRST) ?
+ MLNavCtrl_FindItemById(Plugin_GetLibraryWindow(), param) :
+ (HNAVITEM)param;
+}
+
+static HNAVITEM
+NavigationItem_Find(HNAVITEM root, const wchar_t *name, BOOL allow_root = 0)
+{
+ NAVCTRLFINDPARAMS find = {0};
+ HNAVITEM item;
+ HWND libraryWindow;
+
+ if (NULL == name)
+ return NULL;
+
+ libraryWindow = Plugin_GetLibraryWindow();
+ if (NULL == libraryWindow)
+ return NULL;
+
+ find.pszName = (wchar_t*)name;
+ find.cchLength = -1;
+ find.compFlags = NICF_INVARIANT;
+ find.fFullNameSearch = FALSE;
+
+ item = MLNavCtrl_FindItemByName(libraryWindow, &find);
+ if (NULL == item)
+ return NULL;
+
+ if (!allow_root)
+ {
+ // if allowed then we can look for root level items which
+ // is really for getting 'cloud' devices to another group
+ if (NULL != root &&
+ root != MLNavItem_GetParent(libraryWindow, item))
+ {
+ item = NULL;
+ }
+ }
+
+ return item;
+}
+
+static wchar_t *
+NavigationItem_GetNameFromDeviceName(wchar_t *buffer, size_t bufferMax, const char *name)
+{
+ wchar_t *cursor;
+ size_t length;
+ BOOL allocated;
+
+ if (NULL == name || '\0' == *name)
+ return NULL;
+
+ length = MultiByteToWideChar(CP_UTF8, 0, name, -1, NULL, 0);
+ if (ARRAYSIZE(DEVICES_NAVITEM_PREFIX) > bufferMax ||
+ length > (bufferMax - (ARRAYSIZE(DEVICES_NAVITEM_PREFIX) - 1)))
+ {
+ bufferMax = length + ARRAYSIZE(DEVICES_NAVITEM_PREFIX) - 1;
+ buffer = String_Malloc(bufferMax);
+ if (NULL == buffer)
+ return NULL;
+
+ allocated = TRUE;
+ }
+ else
+ allocated = FALSE;
+
+ if (FAILED(StringCchCopyEx(buffer, bufferMax, DEVICES_NAVITEM_PREFIX, &cursor, &length, 0)) ||
+ 0 == MultiByteToWideChar(CP_UTF8, 0, name, -1, cursor, (int)length))
+ {
+ if (FALSE != allocated)
+ String_Free(buffer);
+
+ return NULL;
+ }
+
+ return buffer;
+}
+
+static HNAVITEM
+NavigationItem_FindFromDeviceName(HNAVITEM root, const char *name)
+{
+ wchar_t buffer[1], *itemName;
+ HNAVITEM item;
+
+ if (NULL == root)
+ return NULL;
+
+ itemName = NavigationItem_GetNameFromDeviceName(buffer, ARRAYSIZE(buffer), name);
+ if (NULL == itemName)
+ return NULL;
+
+ item = NavigationItem_Find(root, itemName);
+
+ if (itemName != buffer)
+ String_Free(itemName);
+
+ return item;
+}
+
+static HNAVITEM
+NavigationItem_FindFromDevice(HNAVITEM root, ifc_device *device)
+{
+ if (NULL == device)
+ return NULL;
+
+ return NavigationItem_FindFromDeviceName(root, device->GetName());
+}
+
+static BOOL
+NavigationItem_DisplayDeviceMenu(HNAVITEM item, const char *deviceName, HWND hostWindow, POINT pt)
+{
+ HMENU menu;
+ ifc_device *device;
+ unsigned int commandId;
+ BOOL succeeded;
+ HWND libraryWindow;
+
+ libraryWindow = Plugin_GetLibraryWindow();
+
+ if (NULL == item|| NULL == deviceName)
+ return FALSE;
+
+ if (NULL == WASABI_API_DEVICES ||
+ S_OK != WASABI_API_DEVICES->DeviceFind(deviceName, &device))
+ {
+ return FALSE;
+ }
+
+ menu = CreatePopupMenu();
+ if (NULL != menu)
+ {
+ if (0 == Menu_InsertDeviceItems(menu, 0, 100, device, DeviceCommandContext_NavigationMenu))
+ {
+ DestroyMenu(menu);
+ menu = NULL;
+ }
+ }
+
+ device->Release();
+
+ if (NULL == menu)
+ return FALSE;
+
+ succeeded = FALSE;
+
+ if (item == MLNavCtrl_GetSelection(libraryWindow))
+ {
+ commandId = Menu_FindItemByAnsiStringData(menu, "view_open");
+ if ((unsigned int)-1 != commandId)
+ EnableMenuItem(menu, commandId, MF_BYCOMMAND | MF_DISABLED);
+ }
+
+ commandId = Menu_TrackPopup(Plugin_GetLibraryWindow(), menu,
+ TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_VERTICAL | TPM_RETURNCMD,
+ pt.x, pt.y, hostWindow, NULL);
+
+ if (0 != commandId)
+ {
+ const char *command;
+
+ command = (const char*)Menu_GetItemData(menu, commandId, FALSE);
+ if (NULL != command)
+ {
+ if (NULL != WASABI_API_DEVICES &&
+ S_OK == WASABI_API_DEVICES->DeviceFind(deviceName, &device))
+ {
+ BOOL commandProcessed;
+
+ commandProcessed = FALSE;
+
+ if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, command, -1, "view_open", -1))
+ {
+ succeeded = MLNavItem_Select(libraryWindow, item);
+ commandProcessed = succeeded;
+ }
+ else if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, command, -1, "rename", -1))
+ {
+ succeeded = MLNavItem_EditTitle(libraryWindow, item);
+ commandProcessed = succeeded;
+ }
+
+ if (FALSE == commandProcessed &&
+ SUCCEEDED(device->SendCommand(command, hostWindow, 0)))
+ {
+ succeeded = TRUE;
+ }
+
+ device->Release();
+ }
+ }
+ }
+ else
+ {
+ if (ERROR_SUCCESS == GetLastError())
+ succeeded = TRUE;
+ }
+
+ Menu_FreeItemData(menu, 0, -1);
+
+ return succeeded;
+}
+
+static BOOL
+NavigationItem_DisplayRootMenu(HNAVITEM item, HWND hostWindow, POINT pt)
+{
+ HMENU pluginMenu, menu;
+ BOOL succeeded;
+
+ if (NULL == item)
+ return FALSE;
+
+ pluginMenu = Plugin_LoadMenu();
+ if (NULL == pluginMenu)
+ return FALSE;
+
+ succeeded = FALSE;
+
+ menu = GetSubMenu(pluginMenu, 0);
+ if (NULL != menu)
+ {
+ HWND libraryWindow;
+ HNAVITEM selectedItem;
+
+ libraryWindow = Plugin_GetLibraryWindow();
+
+ selectedItem = MLNavCtrl_GetSelection(libraryWindow);
+
+ EnableMenuItem(menu, ID_VIEW_OPEN, MF_BYCOMMAND | ((item != selectedItem) ? MF_ENABLED : MF_DISABLED));
+ SetMenuDefaultItem(menu, ID_VIEW_OPEN, FALSE);
+
+ unsigned int commandId = Menu_TrackPopup(Plugin_GetLibraryWindow(), menu,
+ TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_VERTICAL | TPM_RETURNCMD,
+ pt.x, pt.y, hostWindow, NULL);
+
+ if (0 != commandId)
+ {
+ switch(commandId)
+ {
+ case ID_VIEW_OPEN:
+ MLNavItem_Select(libraryWindow, item);
+ break;
+ case ID_DISCOVERY_BEGIN:
+ Plugin_BeginDiscovery();
+ break;
+ case ID_PLUGIN_HELP:
+ Plugin_ShowHelp();
+ break;
+ }
+ }
+ else
+ {
+ if (ERROR_SUCCESS == GetLastError())
+ succeeded = TRUE;
+ }
+ }
+
+ DestroyMenu(pluginMenu);
+
+ return succeeded;
+}
+
+static BOOL
+Navigation_GetDeviceTitle(ifc_device *device, wchar_t *buffer, size_t bufferMax)
+{
+ size_t read, write;
+
+ if (NULL == device ||
+ FAILED(device->GetDisplayName(buffer, bufferMax)))
+ {
+ return FALSE;
+ }
+
+ for(read = 0, write = 0;; read++)
+ {
+ if (read == bufferMax)
+ return FALSE;
+
+ if (L'\r' == buffer[read])
+ continue;
+
+ if (L'\n' == buffer[read] ||
+ L'\t' == buffer[read] ||
+ L'\b' == buffer[read])
+ {
+ buffer[write] = L' ';
+ }
+
+ buffer[write] = buffer[read];
+ if (L'\0' == buffer[read])
+ break;
+
+ write++;
+ }
+
+ return TRUE;
+}
+
+static BOOL
+Navigation_DeviceAdd(HNAVITEM root, ifc_device *device)
+{
+ HNAVITEM item, insertAfter = NCI_LAST;
+ wchar_t nameBuffer[256] = {0}, *itemName;
+ wchar_t title[512] = {0};
+ int iconIndex;
+
+ if (NULL == device)
+ return FALSE;
+
+ itemName = NavigationItem_GetNameFromDeviceName(nameBuffer, ARRAYSIZE(nameBuffer), device->GetName());
+ if (NULL == itemName)
+ return FALSE;
+
+ if (NULL != NavigationItem_Find(root, itemName))
+ {
+ if (itemName != nameBuffer)
+ String_Free(itemName);
+
+ return FALSE;
+ }
+
+ if (FALSE == Navigation_GetDeviceTitle(device, title, ARRAYSIZE(title)))
+ title[0] = L'\0';
+
+ iconIndex = NavigationIcons_GetDeviceIconIndex(device);
+
+ // filter the cloud devices to their own group
+ if (!lstrcmpiA(device->GetConnection(), "cloud"))
+ {
+ HNAVITEM cloud = NavigationItem_Find(navigationRoot, L"cloud_sources", TRUE);
+ if (cloud != NULL)
+ {
+ root = cloud;
+ HNAVITEM transfers = NavigationItem_Find(0, L"cloud_transfers", TRUE);
+
+ // to maintain some specific orders, we need to alter the insert position
+ if (!wcsnicmp(L"ml_devices_hss", itemName, 14))
+ {
+ insertAfter = transfers;
+ if (!insertAfter) insertAfter = NCI_LAST;
+ }
+ else if (!wcsnicmp(L"ml_devices_local_desktop", itemName, 24))
+ {
+ insertAfter = NavigationItem_Find(0, L"ml_devices_hss", TRUE);
+ if (!insertAfter) insertAfter = NCI_LAST;
+ }
+
+ // when adding children, change from the cloud source to the open/closed arrow
+ HWND libraryWindow = Plugin_GetLibraryWindow();
+ if (NULL != libraryWindow && transfers)
+ {
+ NAVITEM itemInfo = {0};
+ itemInfo.hItem = cloud;
+ itemInfo.cbSize = sizeof(itemInfo);
+ itemInfo.mask = NIMF_IMAGE | NIMF_IMAGESEL;
+ itemInfo.iImage = itemInfo.iSelectedImage = -1;
+ MLNavItem_SetInfo(libraryWindow, &itemInfo);
+ }
+ }
+ }
+
+ item = NavigationItem_Insert(root, insertAfter,
+ NIMF_TEXT | NIMF_TEXTINVARIANT | NIMF_IMAGE | NIMF_IMAGESEL | NIMF_STYLE,
+ 0, itemName, title, NIS_ALLOWEDIT, iconIndex, 0L);
+
+ if (NULL == item)
+ NavigationIcons_ReleaseIconIndex(iconIndex);
+
+ if (itemName != nameBuffer)
+ String_Free(itemName);
+
+ if (NULL == item)
+ return FALSE;
+
+ device->SetNavigationItem(item);
+
+ return TRUE;
+}
+
+static BOOL
+Navigation_DeviceRemove(HNAVITEM root, ifc_device *device)
+{
+ HNAVITEM item;
+
+ item = NavigationItem_FindFromDevice(root, device);
+ if (NULL == item)
+ return FALSE;
+
+ return NavigationItem_Delete(item);
+}
+
+static BOOL
+Navigation_DeviceTitleChanged(HNAVITEM root, ifc_device *device)
+{
+ NAVITEM itemInfo;
+ wchar_t buffer[1024] = {0};
+
+ itemInfo.hItem = NavigationItem_FindFromDevice(root, device);
+ if (NULL == itemInfo.hItem)
+ return FALSE;
+
+ if (FALSE == Navigation_GetDeviceTitle(device, buffer, ARRAYSIZE(buffer)))
+ return FALSE;
+
+ itemInfo.cbSize = sizeof(itemInfo);
+ itemInfo.pszText = buffer;
+ itemInfo.cchTextMax = -1;
+ itemInfo.mask = NIMF_TEXT;
+
+ return MLNavItem_SetInfo(Plugin_GetLibraryWindow(), &itemInfo);
+}
+
+static BOOL
+Navigation_DeviceIconChanged(HNAVITEM root, ifc_device *device)
+{
+ NAVITEM itemInfo;
+ int iconIndex;
+ HWND libraryWindow;
+
+ if (NULL == root || NULL == device)
+ return FALSE;
+
+ libraryWindow = Plugin_GetLibraryWindow();
+
+ itemInfo.hItem = NavigationItem_FindFromDevice(root, device);
+ if (NULL == itemInfo.hItem)
+ return FALSE;
+
+ iconIndex = NavigationIcons_GetDeviceIconIndex(device);
+
+ itemInfo.cbSize = sizeof(itemInfo);
+ itemInfo.mask = NIMF_IMAGE;
+
+ if (FALSE == MLNavItem_GetInfo(libraryWindow, &itemInfo))
+ {
+ NavigationIcons_ReleaseIconIndex(iconIndex);
+ return FALSE;
+ }
+
+ if (itemInfo.iImage == iconIndex)
+ {
+ NavigationIcons_ReleaseIconIndex(iconIndex);
+ return TRUE;
+ }
+
+ NavigationIcons_ReleaseIconIndex(itemInfo.iImage);
+ itemInfo.mask = NIMF_IMAGE | NIMF_IMAGESEL;
+ itemInfo.iImage = iconIndex;
+ itemInfo.iSelectedImage = iconIndex;
+
+ if (FALSE == MLNavItem_SetInfo(libraryWindow, &itemInfo))
+ {
+ NavigationIcons_ReleaseIconIndex(iconIndex);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+Navigation_AddExistingDevices(HNAVITEM root)
+{
+ ifc_device *device;
+ ifc_deviceobject *object;
+ ifc_deviceobjectenum *enumerator;
+
+ if (NULL == WASABI_API_DEVICES)
+ return;
+
+ if (FAILED(WASABI_API_DEVICES->DeviceEnumerate(&enumerator)))
+ return;
+
+ while(S_OK == enumerator->Next(&object, 1, NULL))
+ {
+ if (SUCCEEDED(object->QueryInterface(IFC_Device, (void**)&device)))
+ {
+ if (FALSE == device->GetHidden() &&
+ FALSE != device->GetAttached())
+ {
+ Navigation_DeviceAdd(root, device);
+ }
+ device->Release();
+ }
+ object->Release();
+ }
+ enumerator->Release();
+}
+
+static void
+Navigation_DeviceCb(ifc_device *device, DeviceEvent eventId, void *user)
+{
+ HNAVITEM rootItem;
+ rootItem = (HNAVITEM)user;
+
+ switch(eventId)
+ {
+ case Event_DeviceAdded:
+ if (FALSE != device->GetAttached())
+ Navigation_DeviceAdd(rootItem, device);
+ break;
+ case Event_DeviceRemoved:
+ if (FALSE != device->GetAttached())
+ Navigation_DeviceRemove(rootItem, device);
+ break;
+ case Event_DeviceHidden:
+ if (FALSE != device->GetAttached())
+ Navigation_DeviceRemove(rootItem, device);
+ break;
+ case Event_DeviceShown:
+ if (FALSE != device->GetAttached())
+ Navigation_DeviceAdd(rootItem, device);
+ break;
+ case Event_DeviceAttached:
+ Navigation_DeviceAdd(rootItem, device);
+ break;
+ case Event_DeviceDetached:
+ Navigation_DeviceRemove(rootItem, device);
+ break;
+ case Event_DeviceDisplayNameChanged:
+ Navigation_DeviceTitleChanged(rootItem, device);
+ break;
+ case Event_DeviceIconChanged:
+ Navigation_DeviceIconChanged(rootItem, device);
+ break;
+ }
+}
+
+static BOOL
+Navigation_RegisterDeviceHandler(HNAVITEM root)
+{
+ HWND eventRelay;
+ DeviceEventCallbacks callbacks;
+
+ if (0 != deviceHandler)
+ return FALSE;
+
+ eventRelay = Plugin_GetEventRelayWindow();
+ if (NULL == eventRelay)
+ return FALSE;
+
+ ZeroMemory(&callbacks, sizeof(callbacks));
+ callbacks.deviceCb = Navigation_DeviceCb;
+
+ deviceHandler = EVENTRELAY_REGISTER_HANDLER(eventRelay, &callbacks, root);
+ return (0 != deviceHandler);
+}
+
+BOOL
+Navigation_Initialize(void)
+{
+ HWND libraryWindow;
+ wchar_t buffer[128] = {0};
+
+ if (NULL != navigationRoot)
+ return FALSE;
+
+ libraryWindow = Plugin_GetLibraryWindow();
+
+ MLNavCtrl_BeginUpdate(libraryWindow, NUF_LOCK_TOP);
+
+ WASABI_API_LNGSTRINGW_BUF(IDS_DEVICES_NAVIGATION_NODE, buffer, ARRAYSIZE(buffer));
+
+ navigationRoot = NavigationItem_Insert(NULL, NULL,
+ NIMF_ITEMID | NIMF_TEXT | NIMF_STYLE | NIMF_TEXTINVARIANT |
+ NIMF_PARAM | NIMF_IMAGE | NIMF_IMAGESEL,
+ ML_TREEVIEW_ID_DEVICES,
+ DEVICES_NAVITEM_PREFIX L"root",
+ buffer,
+ NIS_HASCHILDREN | NIS_ALLOWCHILDMOVE | NIS_DEFAULTIMAGE,
+ -1,
+ -1L);
+
+ if (NULL == navigationRoot)
+ return FALSE;
+
+ Navigation_AddExistingDevices(navigationRoot);
+ Navigation_RegisterDeviceHandler(navigationRoot);
+
+ MLNavCtrl_EndUpdate(libraryWindow);
+
+ return TRUE;
+}
+
+void
+Navigation_Uninitialize(void)
+{
+ if (0 != deviceHandler)
+ {
+ HWND eventRelay;
+ eventRelay = Plugin_GetEventRelayWindow();
+ if (NULL != eventRelay)
+ {
+ EVENTRELAY_UNREGISTER_HANDLER(eventRelay, deviceHandler);
+ }
+ deviceHandler = NULL;
+ }
+
+ if (NULL != navigationRoot)
+ {
+ NavigationItem_Delete(navigationRoot);
+ navigationRoot = FALSE;
+ }
+
+ NavigationIcons_ClearCache();
+}
+
+BOOL
+Navigation_SelectDevice(const char *name)
+{
+ HNAVITEM item;
+
+ item = NavigationItem_FindFromDeviceName(navigationRoot, name);
+ if (NULL == item)
+ return FALSE;
+
+ return MLNavItem_Select(Plugin_GetLibraryWindow(), item);
+}
+
+BOOL
+Navigation_EditDeviceTitle(const char *name)
+{
+ HNAVITEM item;
+
+ item = NavigationItem_FindFromDeviceName(navigationRoot, name);
+ if (NULL == item)
+ return FALSE;
+
+ return MLNavItem_EditTitle(Plugin_GetLibraryWindow(), item);
+}
+
+static void
+Navigation_DestroyCb()
+{
+}
+
+static BOOL
+NavigationItem_IsMine(HNAVITEM item, ifc_device **device)
+{
+ NAVITEM info;
+ wchar_t buffer[128] = {0};
+ INT nameLength;
+ INT prefixLength;
+
+ if (NULL == item)
+ return FALSE;
+
+ if (item == navigationRoot)
+ {
+ if (NULL != device)
+ *device = NULL;
+ return TRUE;
+ }
+
+ info.cbSize = sizeof(NAVITEM);
+ info.hItem = item;
+ info.mask = NIMF_TEXTINVARIANT;
+ info.cchInvariantMax = ARRAYSIZE(buffer);
+ info.pszInvariant = buffer;
+
+ if (FALSE == MLNavItem_GetInfo(Plugin_GetLibraryWindow(), &info))
+ return FALSE;
+
+ // to maintain some specific orders, we need to alter the insert position
+ BOOL swappped = FALSE;
+ if (!wcsnicmp(L"cloud_sources", info.pszInvariant, 13))
+ {
+ // and this will allow us to make the cloud library
+ // root do a web page or a sources view as needed...
+ lstrcpynW(info.pszInvariant, L"ml_devices_all_sources", ARRAYSIZE(buffer));
+ swappped = TRUE;
+ }
+
+ nameLength = (NULL != info.pszInvariant) ? lstrlen(info.pszInvariant) : 0;
+ prefixLength = ARRAYSIZE(DEVICES_NAVITEM_PREFIX) - 1;
+
+ if (nameLength <= prefixLength)
+ return FALSE;
+
+ if (CSTR_EQUAL != CompareString(CSTR_INVARIANT, 0,
+ DEVICES_NAVITEM_PREFIX, prefixLength, info.pszInvariant, prefixLength))
+ {
+ return FALSE;
+ }
+
+ if (NULL != device)
+ {
+ char name[ARRAYSIZE(buffer)] = {0};
+ nameLength = WideCharToMultiByte(CP_UTF8, 0,
+ info.pszInvariant + prefixLength, nameLength - prefixLength,
+ name, ARRAYSIZE(name), NULL, NULL);
+ name[nameLength] = '\0';
+
+ if (0 == nameLength ||
+ NULL == WASABI_API_DEVICES ||
+ S_OK != WASABI_API_DEVICES->DeviceFind(name, device))
+ {
+ *device = NULL;
+ if (swappped) return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+static HWND
+Navigation_CreateViewErrorWidget(HWND hostWindow, void *user)
+{
+ return InfoWidget_CreateWindow(WIDGET_TYPE_VIEW_ERROR,
+ MAKEINTRESOURCE(IDS_INFOWIDGET_TITLE),
+ MAKEINTRESOURCE(IDS_CREATE_DEVICE_VIEW_FAILED),
+ NULL,
+ hostWindow, 0, 0, 0, 0, FALSE, 0);
+}
+
+static HWND
+NavigationItem_CreateViewCb(HNAVITEM item, HWND parentWindow)
+{
+ HWND hwnd;
+ ifc_device *device;
+
+ if (NULL == item ||
+ FALSE == NavigationItem_IsMine(item, &device))
+ return NULL;
+
+ if (NULL != device)
+ {
+ hwnd = device->CreateView(parentWindow);
+ device->Release();
+
+ if (NULL == hwnd)
+ {
+ hwnd = WidgetHost_Create(0, 0, 0, 0, 0, parentWindow, Navigation_CreateViewErrorWidget, NULL);
+ }
+ }
+ else
+ {
+ hwnd = ManagerView_CreateWindow(parentWindow);
+ }
+ return hwnd;
+}
+
+static BOOL
+NavigationItem_ShowContextMenuCb(HNAVITEM item, HWND hostWindow, POINTS pts)
+{
+ POINT pt;
+ ifc_device *device;
+
+ if (NULL == item ||
+ FALSE == NavigationItem_IsMine(item, &device))
+ return FALSE;
+
+ POINTSTOPOINT(pt, pts);
+
+ if (item != navigationRoot)
+ {
+ if (NULL != device)
+ {
+ char *deviceName = AnsiString_Duplicate(device->GetName());
+ device->Release();
+ device = NULL;
+
+ if (NULL != deviceName)
+ {
+ NavigationItem_DisplayDeviceMenu(item, deviceName, hostWindow, pt);
+ AnsiString_Free(deviceName);
+ }
+ }
+ }
+ else
+ {
+ NavigationItem_DisplayRootMenu(item, hostWindow, pt);
+ }
+
+ if (NULL != device)
+ device->Release();
+
+ return TRUE;
+}
+
+static BOOL
+NavigationItem_ShowHelpCb(HNAVITEM item, HWND hostWindow, POINTS pts)
+{
+ if (NULL == item ||
+ FALSE == NavigationItem_IsMine(item, NULL))
+ {
+ return FALSE;
+ }
+
+ Plugin_ShowHelp();
+ return TRUE;
+}
+
+static BOOL
+NavigationItem_DeleteCb(HNAVITEM item)
+{
+ ifc_device *device;
+
+ if (NULL == item ||
+ FALSE == NavigationItem_IsMine(item, &device))
+ return FALSE;
+
+ if (NULL != device)
+ {
+ device->SetNavigationItem(NULL);
+ device->Release();
+ }
+
+ if (item != navigationRoot)
+ {
+ NAVITEM itemInfo;
+ HWND libraryWindow;
+
+ libraryWindow = Plugin_GetLibraryWindow();
+
+ itemInfo.cbSize = sizeof(itemInfo);
+ itemInfo.mask = NIMF_IMAGE;
+ itemInfo.hItem = item;
+
+ if (FALSE != MLNavItem_GetInfo(libraryWindow, &itemInfo) &&
+ -1 != itemInfo.iImage)
+ {
+ NavigationIcons_ReleaseIconIndex(itemInfo.iImage);
+ }
+ }
+
+ return TRUE;
+}
+
+static BOOL
+NavigationItem_KeyDownCb(HNAVITEM item, NMTVKEYDOWN *keyData)
+{
+ ifc_device *device;
+
+ if (NULL == keyData ||
+ NULL == item ||
+ FALSE == NavigationItem_IsMine(item, &device))
+ {
+ return FALSE;
+ }
+
+ if (NULL == device)
+ return TRUE;
+
+ switch(keyData->wVKey)
+ {
+ case VK_F2:
+ MLNavItem_EditTitle(Plugin_GetLibraryWindow(), item);
+ break;
+ }
+
+ device->Release();
+ return TRUE;
+}
+
+static int
+NavigationItem_DropTargetCb(HNAVITEM item, unsigned int dataType, void *data)
+{
+ ifc_device *device;
+ int result;
+
+ if (NULL == item ||
+ FALSE == NavigationItem_IsMine(item, &device))
+ {
+ return 0;
+ }
+
+ if (NULL == device)
+ return -1;
+
+ result = -1;
+
+ if (NULL == data)
+ {
+ if (S_OK == device->GetDropSupported(dataType))
+ result = 1;
+ }
+ else
+ {
+ if (SUCCEEDED(device->Drop(data, dataType)))
+ result = 1;
+ }
+
+ device->Release();
+
+ return result;
+}
+
+static BOOL
+NavigationItem_TitleEditBeginCb(HNAVITEM item)
+{ // return TRUE to cancel ediging (only on own items!!!);
+
+ ifc_device *device;
+
+ BOOL blockEditor;
+
+ if (NULL == item ||
+ FALSE == NavigationItem_IsMine(item, &device))
+ {
+ return FALSE;
+ }
+
+ if (NULL == device)
+ return TRUE;
+
+ blockEditor = (FALSE == DeviceCommand_GetEnabled(device, "rename",
+ DeviceCommandContext_NavigationMenu));
+
+ device->Release();
+
+ return blockEditor;
+}
+
+
+static BOOL
+NavigationItem_TitleEditEndCb(HNAVITEM item, const wchar_t *title)
+{
+ HRESULT hr;
+ ifc_device *device;
+
+ if (NULL == title)
+ return FALSE;
+
+ if (NULL == item ||
+ FALSE == NavigationItem_IsMine(item, &device) ||
+ NULL == device)
+ {
+ return FALSE;
+ }
+
+ hr = device->SetDisplayName(title);
+ device->Release();
+
+ if (FAILED(hr))
+ {
+ HWND libraryWindow;
+ wchar_t title[256] = {0}, message[1024] = {0};
+
+ libraryWindow = Plugin_GetLibraryWindow();
+
+ WASABI_API_LNGSTRINGW_BUF(IDS_MESSAGEBOX_TITLE, title, ARRAYSIZE(title));
+ WASABI_API_LNGSTRINGW_BUF(IDS_MESSAGE_UNABLE_TO_RENAME, message, ARRAYSIZE(message));
+
+ MessageBox(libraryWindow, message, title, MB_OK | MB_ICONERROR);
+ return FALSE;
+ }
+
+ return FALSE;
+}
+
+
+BOOL
+Navigation_ProcessMessage(INT msg, INT_PTR param1, INT_PTR param2, INT_PTR param3, INT_PTR *result)
+{
+ if (msg == ML_MSG_NO_CONFIG)
+ {
+ *result = TRUE;
+ return TRUE;
+ }
+
+ if (msg < ML_MSG_TREE_BEGIN || msg > ML_MSG_TREE_END)
+ return FALSE;
+
+ HNAVITEM item;
+ switch(msg)
+ {
+ case ML_MSG_TREE_ONCREATEVIEW:
+ item = NavigationItem_GetFromMessage(msg, param1);
+ *result = (INT_PTR)NavigationItem_CreateViewCb(item, (HWND)param2);
+ return TRUE;
+
+ case ML_MSG_NAVIGATION_CONTEXTMENU:
+ item = NavigationItem_GetFromMessage(msg, param1);
+ *result = (INT_PTR)NavigationItem_ShowContextMenuCb(item, (HWND)param2, MAKEPOINTS(param3));
+ return TRUE;
+
+ case ML_MSG_NAVIGATION_HELP:
+ item = NavigationItem_GetFromMessage(msg, param1);
+ *result = (INT_PTR)NavigationItem_ShowHelpCb(item, (HWND)param2, MAKEPOINTS(param3));
+ return TRUE;
+
+ case ML_MSG_NAVIGATION_ONDELETE:
+ item = NavigationItem_GetFromMessage(msg, param1);
+ *result = (INT_PTR)NavigationItem_DeleteCb(item);
+ return TRUE;
+
+ case ML_MSG_TREE_ONKEYDOWN:
+ item = NavigationItem_GetFromMessage(msg, param1);
+ *result = (INT_PTR)NavigationItem_KeyDownCb(item, (NMTVKEYDOWN*)param2);
+ return TRUE;
+
+ case ML_MSG_TREE_ONDROPTARGET:
+ item = NavigationItem_GetFromMessage(msg, param1);
+ *result = (INT_PTR)NavigationItem_DropTargetCb(item, (unsigned int)param2, (void*)param3);
+ return TRUE;
+
+ case ML_MSG_NAVIGATION_ONBEGINTITLEEDIT:
+ item = NavigationItem_GetFromMessage(msg, param1);
+ *result = (INT_PTR)NavigationItem_TitleEditBeginCb(item);
+ return TRUE;
+
+ case ML_MSG_NAVIGATION_ONENDTITLEEDIT:
+ item = NavigationItem_GetFromMessage(msg, param1);
+ *result = (INT_PTR)NavigationItem_TitleEditEndCb(item, (const wchar_t*)param2);
+ return TRUE;
+
+ case ML_MSG_NAVIGATION_ONDESTROY:
+ Navigation_DestroyCb();
+ *result = 0L;
+ return TRUE;
+
+ }
+ return FALSE;
+} \ No newline at end of file