2854 lines
67 KiB
C++
2854 lines
67 KiB
C++
|
#include "main.h"
|
||
|
#include "./listWidgetInternal.h"
|
||
|
#include "../nu/AutoWide.h"
|
||
|
#include <strsafe.h>
|
||
|
|
||
|
#define LISTWIDGETITEM_OFFSET_LEFT_DLU 0
|
||
|
#define LISTWIDGETITEM_OFFSET_TOP_DLU 0
|
||
|
#define LISTWIDGETITEM_OFFSET_RIGHT_DLU 0
|
||
|
#define LISTWIDGETITEM_OFFSET_BOTTOM_DLU 2
|
||
|
#define LISTWIDGETITEM_IMAGE_OFFSET_LEFT_DLU 2
|
||
|
#define LISTWIDGETITEM_IMAGE_OFFSET_TOP_DLU 2
|
||
|
#define LISTWIDGETITEM_IMAGE_OFFSET_RIGHT_DLU 2
|
||
|
#define LISTWIDGETITEM_IMAGE_OFFSET_BOTTOM_DLU 2
|
||
|
#define LISTWIDGETITEM_SPACEBAR_OFFSET_DLU 1
|
||
|
#define LISTWIDGETITEM_SPACEBAR_HEIGHT_DLU 8
|
||
|
#define LISTWIDGETITEM_TITLE_OFFSET_DLU 1
|
||
|
#define LISTWIDGETITEM_TITLE_MIN_WIDTH_DLU (8 * 4)
|
||
|
#define LISTWIDGETITEM_TITLE_EDITOR_MARGIN_HORZ_DLU 2
|
||
|
|
||
|
ListWidgetItem*
|
||
|
ListWidget_CreateItemFromDevice(ListWidget *self, ifc_device* device)
|
||
|
{
|
||
|
ListWidgetItem *item;
|
||
|
ifc_deviceactivity *activity;
|
||
|
wchar_t buffer[1024] = {0};
|
||
|
|
||
|
if (NULL == device || NULL == device->GetName())
|
||
|
return NULL;
|
||
|
|
||
|
item = new ListWidgetItem();
|
||
|
if (NULL == item)
|
||
|
return NULL;
|
||
|
|
||
|
item->name = AnsiString_Duplicate(device->GetName());
|
||
|
if (NULL == item->name)
|
||
|
{
|
||
|
delete item;
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(device->GetDisplayName(buffer, ARRAYSIZE(buffer))))
|
||
|
item->title = String_Duplicate(buffer);
|
||
|
else
|
||
|
item->title = NULL;
|
||
|
|
||
|
ListWidgetItem_UnsetTextTruncated(item);
|
||
|
SetSize(&item->titleSize, -1, -1);
|
||
|
|
||
|
item->image = NULL;
|
||
|
|
||
|
if (FAILED(device->GetTotalSpace(&item->spaceTotal)))
|
||
|
item->spaceTotal = 0;
|
||
|
|
||
|
if (FAILED(device->GetUsedSpace(&item->spaceUsed)))
|
||
|
item->spaceUsed = 0;
|
||
|
|
||
|
item->connection = NULL;
|
||
|
if (NULL != self)
|
||
|
{
|
||
|
item->connection = ListWidget_FindConnection(self, device->GetConnection());
|
||
|
if (NULL == item->connection)
|
||
|
{
|
||
|
item->connection = ListWidget_CreateConnection(device->GetConnection());
|
||
|
if (NULL != item->connection)
|
||
|
ListWidget_AddConnection(self, item->connection);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
item->activity = NULL;
|
||
|
if (S_OK == device->GetActivity(&activity) && NULL != activity)
|
||
|
{
|
||
|
if (FALSE != activity->GetActive())
|
||
|
{
|
||
|
ListWidget_CreateItemActivity(item);
|
||
|
ListWidget_UpdateItemActivity(item, activity);
|
||
|
}
|
||
|
|
||
|
activity->Release();
|
||
|
}
|
||
|
return item;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
ListWidget_DestroyItem(ListWidgetItem *item)
|
||
|
{
|
||
|
if (NULL == item)
|
||
|
return;
|
||
|
|
||
|
if (NULL != item->image)
|
||
|
DeviceImage_Release(item->image);
|
||
|
|
||
|
ListWidget_DeleteItemActivity(item);
|
||
|
|
||
|
AnsiString_Free(item->name);
|
||
|
String_Free(item->title);
|
||
|
|
||
|
|
||
|
|
||
|
delete item;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_SetItemTitle(ListWidgetItem *item, const wchar_t *title)
|
||
|
{
|
||
|
if (NULL == item)
|
||
|
return FALSE;
|
||
|
|
||
|
String_Free(item->title);
|
||
|
SetSize(&item->titleSize, -1, -1);
|
||
|
ListWidgetItem_UnsetTextTruncated(item);
|
||
|
|
||
|
item->title = String_Duplicate(title);
|
||
|
|
||
|
if (NULL != title && NULL == item->title)
|
||
|
return FALSE;
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
size_t
|
||
|
ListWidget_RemoveItem(ListWidget *self, HWND hwnd, const char *name)
|
||
|
{
|
||
|
size_t iCategory, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
size_t removed;
|
||
|
RECT rect;
|
||
|
POINT origin;
|
||
|
ListWidgetItem *selectItem;
|
||
|
|
||
|
removed = 0;
|
||
|
selectItem = NULL;
|
||
|
|
||
|
if (NULL == self || NULL == name)
|
||
|
return 0;
|
||
|
|
||
|
if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))
|
||
|
ZeroMemory(&origin, sizeof(POINT));
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
BOOL categoryModified = FALSE;
|
||
|
|
||
|
size_t iGroup = category->groups.size();
|
||
|
while(iGroup--)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
iItem = group->items.size();
|
||
|
while(iItem--)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, item->name, -1, name, -1))
|
||
|
{
|
||
|
removed++;
|
||
|
categoryModified = TRUE;
|
||
|
|
||
|
if (NULL != item->activity)
|
||
|
ListWidget_UnregisterActiveItem(self, hwnd, item);
|
||
|
|
||
|
if (self->selectedItem == item)
|
||
|
{
|
||
|
self->selectedItem = NULL;
|
||
|
|
||
|
if (NULL != self->activeMenu)
|
||
|
EndMenu();
|
||
|
|
||
|
ListWidget_UpdateSelectionStatus(self, hwnd, FALSE);
|
||
|
|
||
|
selectItem = ListWidget_GetNextGroupItem(self, group, item);
|
||
|
if (NULL == selectItem)
|
||
|
{
|
||
|
selectItem = ListWidget_GetPreviousGroupItem(self, group, item);
|
||
|
if (NULL == selectItem)
|
||
|
{
|
||
|
selectItem = ListWidget_GetNextCategoryItem(self, category, item);
|
||
|
if (NULL == selectItem)
|
||
|
selectItem = ListWidget_GetPreviousCategoryItem(self, category, item);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (self->hoveredItem == item)
|
||
|
self->hoveredItem = NULL;
|
||
|
|
||
|
group->items.erase(group->items.begin() + iItem);
|
||
|
ListWidget_DestroyItem(item);
|
||
|
|
||
|
if (0 == group->items.size())
|
||
|
{
|
||
|
category->groups.erase(category->groups.begin() + iGroup);
|
||
|
ListWidget_DestroyGroup(group);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FALSE != categoryModified)
|
||
|
{
|
||
|
ListWidget_ResetCategoryCounter(category);
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
ListWidget_UpdateLayout(hwnd, ListWidgetLayout_UpdateNow | ListWidgetLayout_KeepStable);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
CopyRect(&rect, &category->rect);
|
||
|
OffsetRect(&rect, origin.x, origin.y);
|
||
|
InvalidateRect(hwnd, &rect, FALSE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (0 != removed && NULL != selectItem)
|
||
|
ListWidget_SelectItem(self, hwnd, selectItem, FALSE);
|
||
|
|
||
|
return removed;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetItemMetrics(WidgetStyle *style, ListWidgetItemMetric *metrics)
|
||
|
{
|
||
|
if (NULL == metrics || NULL == style)
|
||
|
return FALSE;
|
||
|
|
||
|
WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(metrics->offsetLeft, style, LISTWIDGETITEM_OFFSET_LEFT_DLU, 1);
|
||
|
WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->offsetTop, style, LISTWIDGETITEM_OFFSET_TOP_DLU, 1);
|
||
|
WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(metrics->offsetRight, style, LISTWIDGETITEM_OFFSET_RIGHT_DLU, 1);
|
||
|
WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->offsetBottom, style, LISTWIDGETITEM_OFFSET_BOTTOM_DLU, 1);
|
||
|
|
||
|
WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(metrics->imageOffsetLeft, style, LISTWIDGETITEM_IMAGE_OFFSET_LEFT_DLU, 2);
|
||
|
WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->imageOffsetTop, style, LISTWIDGETITEM_IMAGE_OFFSET_TOP_DLU, 2);
|
||
|
WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(metrics->imageOffsetRight, style, LISTWIDGETITEM_IMAGE_OFFSET_RIGHT_DLU, 2);
|
||
|
WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->imageOffsetBottom, style, LISTWIDGETITEM_IMAGE_OFFSET_BOTTOM_DLU, 2);
|
||
|
|
||
|
WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->spacebarOffsetTop, style, LISTWIDGETITEM_SPACEBAR_OFFSET_DLU, 1);
|
||
|
WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->spacebarHeight, style, LISTWIDGETITEM_SPACEBAR_HEIGHT_DLU, 2);
|
||
|
metrics->spacebarHeight = 14;
|
||
|
|
||
|
WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->titleOffsetTop, style, LISTWIDGETITEM_TITLE_OFFSET_DLU, 1);
|
||
|
WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(metrics->titleMinWidth, style, LISTWIDGETITEM_TITLE_MIN_WIDTH_DLU, 32);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static HBITMAP
|
||
|
ListWidget_GetDeviceBitmap(ifc_device *device, int width, int height,
|
||
|
DeviceImageFlags flags, DeviceImage **imageOut)
|
||
|
{
|
||
|
HBITMAP bitmap;
|
||
|
wchar_t path[MAX_PATH*2] = {0};
|
||
|
const wchar_t *defaultImage;
|
||
|
|
||
|
DeviceImage *image;
|
||
|
DeviceImageCache *imageCache;
|
||
|
ifc_devicetype *type;
|
||
|
|
||
|
if (NULL == device)
|
||
|
return NULL;
|
||
|
|
||
|
imageCache = Plugin_GetImageCache();
|
||
|
if (NULL == imageCache)
|
||
|
return NULL;
|
||
|
|
||
|
if (SUCCEEDED(device->GetIcon(path, ARRAYSIZE(path), width, height)))
|
||
|
{
|
||
|
image = DeviceImageCache_GetImage(imageCache, path, width, height, NULL, NULL);
|
||
|
if (NULL != image)
|
||
|
{
|
||
|
bitmap = DeviceImage_GetBitmap(image, flags);
|
||
|
if (NULL != bitmap)
|
||
|
{
|
||
|
if (NULL != imageOut)
|
||
|
*imageOut = image;
|
||
|
else
|
||
|
DeviceImage_Release(image);
|
||
|
|
||
|
return bitmap;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL != WASABI_API_DEVICES &&
|
||
|
S_OK == WASABI_API_DEVICES->TypeFind(device->GetType(), &type))
|
||
|
{
|
||
|
if (SUCCEEDED(type->GetIcon(path, ARRAYSIZE(path), width, height)))
|
||
|
{
|
||
|
image = DeviceImageCache_GetImage(imageCache, path, width, height, NULL, NULL);
|
||
|
if (NULL != image)
|
||
|
{
|
||
|
bitmap = DeviceImage_GetBitmap(image, flags);
|
||
|
if (NULL != bitmap)
|
||
|
{
|
||
|
if (NULL != imageOut)
|
||
|
*imageOut = image;
|
||
|
else
|
||
|
DeviceImage_Release(image);
|
||
|
|
||
|
type->Release();
|
||
|
return bitmap;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
type->Release();
|
||
|
}
|
||
|
|
||
|
defaultImage = Plugin_GetDefaultDeviceImage(width, height);
|
||
|
if (NULL != defaultImage)
|
||
|
{
|
||
|
image = DeviceImageCache_GetImage(imageCache, defaultImage, width, height, NULL, NULL);
|
||
|
if (NULL != image)
|
||
|
{
|
||
|
bitmap = DeviceImage_GetBitmap(image, flags);
|
||
|
if (NULL != bitmap)
|
||
|
{
|
||
|
if (NULL != imageOut)
|
||
|
*imageOut = image;
|
||
|
else
|
||
|
DeviceImage_Release(image);
|
||
|
return bitmap;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
HBITMAP
|
||
|
ListWidget_GetItemImage(ListWidget *self, WidgetStyle *style, ListWidgetItem *item)
|
||
|
{
|
||
|
HBITMAP bitmap;
|
||
|
|
||
|
if (NULL == item)
|
||
|
return NULL;
|
||
|
|
||
|
if (NULL != item->image)
|
||
|
return DeviceImage_GetBitmap(item->image, DeviceImage_Normal);
|
||
|
|
||
|
if (NULL == self || NULL == style)
|
||
|
return NULL;
|
||
|
|
||
|
ifc_device *device;
|
||
|
if (NULL == WASABI_API_DEVICES ||
|
||
|
S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
bitmap = ListWidget_GetDeviceBitmap(device, self->imageSize.cx, self->imageSize.cy,
|
||
|
DeviceImage_Normal, &item->image);
|
||
|
|
||
|
device->Release();
|
||
|
|
||
|
return bitmap;
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_CalculateItemBaseSize(ListWidget *self, WidgetStyle *style, SIZE *baseSize, long *itemTextWidth)
|
||
|
{
|
||
|
ListWidgetItemMetric metrics;
|
||
|
|
||
|
if (NULL == baseSize)
|
||
|
return FALSE;
|
||
|
|
||
|
if (FALSE == ListWidget_GetItemMetrics(style, &metrics))
|
||
|
ZeroMemory(&metrics, sizeof(metrics));
|
||
|
|
||
|
baseSize->cx = self->imageSize.cx;
|
||
|
baseSize->cy = self->imageSize.cy;
|
||
|
|
||
|
baseSize->cx += metrics.imageOffsetLeft + metrics.imageOffsetRight;
|
||
|
if (baseSize->cx < metrics.titleMinWidth)
|
||
|
baseSize->cx = metrics.titleMinWidth;
|
||
|
|
||
|
if (FALSE != itemTextWidth)
|
||
|
*itemTextWidth = baseSize->cx;
|
||
|
|
||
|
baseSize->cx += metrics.offsetLeft + metrics.offsetRight;
|
||
|
|
||
|
baseSize->cy += metrics.offsetTop + metrics.offsetBottom +
|
||
|
metrics.imageOffsetTop + metrics.imageOffsetBottom +
|
||
|
metrics.spacebarHeight + metrics.spacebarOffsetTop +
|
||
|
metrics.titleOffsetTop;
|
||
|
|
||
|
if (FALSE != itemTextWidth)
|
||
|
*itemTextWidth = baseSize->cx - (metrics.offsetLeft + metrics.offsetRight);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetItemFromPointEx(ListWidget *self, POINT point,
|
||
|
ListWidgetCategory **categoryOut, ListWidgetGroup **groupOut)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
|
||
|
if (NULL == self)
|
||
|
return NULL;
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
|
||
|
if (FALSE != PtInRect(&item->rect, point))
|
||
|
{
|
||
|
if (NULL != categoryOut)
|
||
|
*categoryOut = category;
|
||
|
|
||
|
if (NULL != groupOut)
|
||
|
*groupOut = group;
|
||
|
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL != categoryOut)
|
||
|
*categoryOut = NULL;
|
||
|
|
||
|
if (NULL != groupOut)
|
||
|
*groupOut = NULL;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetItemFromPoint(ListWidget *self, POINT point)
|
||
|
{
|
||
|
return ListWidget_GetItemFromPointEx(self, point, NULL, NULL);
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetFirstItem(ListWidget *self)
|
||
|
{
|
||
|
size_t iCategory, iGroup;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
|
||
|
if (NULL == self)
|
||
|
return NULL;
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
if (group->items.size() > 0)
|
||
|
return group->items[0];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetLastItem(ListWidget *self)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
|
||
|
if (NULL == self)
|
||
|
return NULL;
|
||
|
|
||
|
iCategory = self->categories.size();
|
||
|
while(iCategory--)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
iGroup = category->groups.size();
|
||
|
while(iGroup--)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
iItem = group->items.size();
|
||
|
if (iItem > 0)
|
||
|
return group->items[iItem - 1];
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetNextItem(ListWidget *self, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
BOOL returnNext;
|
||
|
|
||
|
if (NULL == self || NULL == baseItem)
|
||
|
return NULL;
|
||
|
|
||
|
returnNext = FALSE;
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
if (item == baseItem)
|
||
|
returnNext = TRUE;
|
||
|
else if (FALSE != returnNext)
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetPreviousItem(ListWidget *self, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
BOOL returnPrevious;
|
||
|
|
||
|
if (NULL == self || NULL == baseItem)
|
||
|
return NULL;
|
||
|
|
||
|
returnPrevious = FALSE;
|
||
|
iCategory = self->categories.size();
|
||
|
while(iCategory--)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
iGroup = category->groups.size();
|
||
|
while(iGroup--)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
iItem = group->items.size();
|
||
|
while(iItem--)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
if (item == baseItem)
|
||
|
returnPrevious = TRUE;
|
||
|
else if (FALSE != returnPrevious)
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetNextCategoryItem(ListWidget *self, ListWidgetCategory *category, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
size_t iGroup, iItem;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
BOOL returnNext;
|
||
|
|
||
|
if (NULL == self || NULL == baseItem ||
|
||
|
NULL == category || FALSE != category->collapsed)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
returnNext = FALSE;
|
||
|
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
if (item == baseItem)
|
||
|
returnNext = TRUE;
|
||
|
else if (FALSE != returnNext)
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetPreviousCategoryItem(ListWidget *self, ListWidgetCategory *category, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
if (NULL == self || NULL == baseItem ||
|
||
|
NULL == category || FALSE != category->collapsed)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
BOOL returnPrevious = FALSE;
|
||
|
size_t iGroup = category->groups.size();
|
||
|
while(iGroup--)
|
||
|
{
|
||
|
ListWidgetGroup *group = category->groups[iGroup];
|
||
|
size_t iItem = group->items.size();
|
||
|
while(iItem--)
|
||
|
{
|
||
|
ListWidgetItem *item = group->items[iItem];
|
||
|
if (item == baseItem)
|
||
|
returnPrevious = TRUE;
|
||
|
else if (FALSE != returnPrevious)
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetNextGroupItem(ListWidget *self, ListWidgetGroup *group, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
if (NULL == self || NULL == baseItem || NULL == group)
|
||
|
return NULL;
|
||
|
|
||
|
BOOL returnNext = FALSE;
|
||
|
for(size_t iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
ListWidgetItem *item = group->items[iItem];
|
||
|
if (item == baseItem)
|
||
|
returnNext = TRUE;
|
||
|
else if (FALSE != returnNext)
|
||
|
return item;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetPreviousGroupItem(ListWidget *self, ListWidgetGroup *group, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
if (NULL == self || NULL == baseItem || NULL == group)
|
||
|
return NULL;
|
||
|
|
||
|
BOOL returnPrevious = FALSE;
|
||
|
size_t iItem = group->items.size();
|
||
|
while(iItem--)
|
||
|
{
|
||
|
ListWidgetItem *item = group->items[iItem];
|
||
|
if (item == baseItem)
|
||
|
returnPrevious = TRUE;
|
||
|
else if (FALSE != returnPrevious)
|
||
|
return item;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetNextLineItem(ListWidget *self, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
size_t itemLinePos, itemsPerLine, targetLinePos;
|
||
|
|
||
|
if (NULL == self || NULL == baseItem)
|
||
|
return NULL;
|
||
|
|
||
|
itemsPerLine = MAX(self->itemsPerLine, 1);
|
||
|
targetLinePos = -1;
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
if (-1 == targetLinePos)
|
||
|
{
|
||
|
itemLinePos = 0;
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++, itemLinePos++)
|
||
|
{
|
||
|
if (itemLinePos == itemsPerLine)
|
||
|
itemLinePos = 0;
|
||
|
|
||
|
item = group->items[iItem];
|
||
|
if (item == baseItem)
|
||
|
{
|
||
|
size_t test;
|
||
|
targetLinePos = itemLinePos;
|
||
|
test = iItem + (itemsPerLine - itemLinePos);
|
||
|
if (test < group->items.size())
|
||
|
{
|
||
|
test += targetLinePos;
|
||
|
if (test >= group->items.size())
|
||
|
test = group->items.size() - 1;
|
||
|
return group->items[test];
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (group->items.size() > 0)
|
||
|
{
|
||
|
size_t test;
|
||
|
|
||
|
if (targetLinePos < group->items.size())
|
||
|
test = targetLinePos;
|
||
|
else
|
||
|
test = group->items.size() - 1;
|
||
|
return group->items[test];
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetPreviousLineItem(ListWidget *self, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
size_t itemLinePos, itemsPerLine, targetLinePos;
|
||
|
|
||
|
if (NULL == self || NULL == baseItem)
|
||
|
return NULL;
|
||
|
|
||
|
itemsPerLine = MAX(self->itemsPerLine, 1);
|
||
|
targetLinePos = -1;
|
||
|
|
||
|
iCategory = self->categories.size();
|
||
|
while(iCategory--)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
iGroup = category->groups.size();
|
||
|
while(iGroup--)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
if (-1 == targetLinePos)
|
||
|
{
|
||
|
itemLinePos = 0;
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++, itemLinePos++)
|
||
|
{
|
||
|
if (itemLinePos == itemsPerLine)
|
||
|
itemLinePos = 0;
|
||
|
|
||
|
item = group->items[iItem];
|
||
|
if (item == baseItem)
|
||
|
{
|
||
|
targetLinePos = itemLinePos;
|
||
|
if (iItem >= (itemLinePos + 1))
|
||
|
{
|
||
|
size_t test = iItem - (itemLinePos + 1);
|
||
|
if (test >= (itemsPerLine - (itemLinePos + 1)))
|
||
|
test -= itemsPerLine - (itemLinePos + 1);
|
||
|
return group->items[test];
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if (group->items.size() > 0)
|
||
|
{
|
||
|
size_t test = group->items.size();
|
||
|
test = test/itemsPerLine + ((0 != test%itemsPerLine) ? 0 : - 1);
|
||
|
test = test * itemsPerLine;
|
||
|
test += targetLinePos;
|
||
|
if (test >= group->items.size())
|
||
|
test = group->items.size() - 1;
|
||
|
return group->items[test];
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static ListWidgetItem *
|
||
|
ListWidget_FindLastVisibleLine(ListWidget *self, long viewBottom)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
ListWidgetItem *lineItem;
|
||
|
|
||
|
lineItem = NULL;
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
if (item->rect.top < viewBottom)
|
||
|
{
|
||
|
if (NULL == lineItem ||
|
||
|
item->rect.top != lineItem->rect.top)
|
||
|
{
|
||
|
if (item->rect.bottom <= viewBottom)
|
||
|
lineItem = item;
|
||
|
else
|
||
|
return (NULL != lineItem) ? lineItem : item;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
return lineItem;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return lineItem;
|
||
|
}
|
||
|
|
||
|
static ListWidgetItem *
|
||
|
ListWidget_FindFirstVisibleLine(ListWidget *self, long viewTop)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
ListWidgetItem *lineItem;
|
||
|
|
||
|
lineItem = NULL;
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
if (NULL == lineItem ||
|
||
|
item->rect.top != lineItem->rect.top)
|
||
|
{
|
||
|
lineItem = item;
|
||
|
if (item->rect.top >= viewTop)
|
||
|
return lineItem;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return lineItem;
|
||
|
}
|
||
|
|
||
|
static ListWidgetItem *
|
||
|
ListWidget_FindNextLine(ListWidget *self, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
BOOL foundItem;
|
||
|
|
||
|
foundItem = FALSE;
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
if (item == baseItem)
|
||
|
foundItem = TRUE;
|
||
|
if (FALSE != foundItem &&
|
||
|
item->rect.top != baseItem->rect.top)
|
||
|
{
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static ListWidgetItem *
|
||
|
ListWidget_FindPreviousLine(ListWidget *self, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
BOOL foundItem;
|
||
|
|
||
|
foundItem = FALSE;
|
||
|
|
||
|
iCategory = self->categories.size();
|
||
|
while(iCategory--)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
iGroup = category->groups.size();
|
||
|
while(iGroup--)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
iItem = group->items.size();
|
||
|
while(iItem--)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
if (item == baseItem)
|
||
|
foundItem = TRUE;
|
||
|
if (FALSE != foundItem &&
|
||
|
item->rect.top != baseItem->rect.top)
|
||
|
{
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
static ListWidgetItem *
|
||
|
ListWidget_FindLineItemAtPos(ListWidget *self, ListWidgetItem *beginLine, ListWidgetItem *linePosition)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
BOOL foundLine;
|
||
|
|
||
|
foundLine = FALSE;
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
if (FALSE == category->collapsed)
|
||
|
{
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
if (item == beginLine)
|
||
|
foundLine = TRUE;
|
||
|
|
||
|
if (FALSE != foundLine)
|
||
|
{
|
||
|
if (beginLine->rect.top == linePosition->rect.top)
|
||
|
{
|
||
|
if (item->rect.top != beginLine->rect.top)
|
||
|
{
|
||
|
return (iItem > 0) ? group->items[iItem - 1] : beginLine;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (item->rect.left == linePosition->rect.left)
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (FALSE != foundLine)
|
||
|
{
|
||
|
if (group->items.size() > 0)
|
||
|
return group->items[group->items.size() - 1];
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetNextPageItem(ListWidget *self, HWND hwnd, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
ListWidgetItem *lineItem;
|
||
|
RECT rect;
|
||
|
POINT origin;
|
||
|
long viewBottom;
|
||
|
|
||
|
if (NULL == self || NULL == baseItem)
|
||
|
return NULL;
|
||
|
|
||
|
if (FALSE == GetClientRect(hwnd, &rect))
|
||
|
return NULL;
|
||
|
|
||
|
if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))
|
||
|
OffsetRect(&rect, -origin.x, -origin.y);
|
||
|
|
||
|
if (baseItem->rect.bottom < rect.top)
|
||
|
viewBottom = baseItem->rect.top + RECTHEIGHT(rect);
|
||
|
else
|
||
|
viewBottom = rect.bottom;
|
||
|
|
||
|
lineItem = ListWidget_FindLastVisibleLine(self, viewBottom);
|
||
|
if (NULL == lineItem)
|
||
|
return NULL;
|
||
|
|
||
|
if (lineItem->rect.top <= baseItem->rect.top)
|
||
|
{
|
||
|
viewBottom = baseItem->rect.top + RECTHEIGHT(rect);
|
||
|
lineItem = ListWidget_FindLastVisibleLine(self, viewBottom);
|
||
|
if (NULL == lineItem)
|
||
|
return NULL;
|
||
|
if (lineItem->rect.top <= baseItem->rect.top)
|
||
|
{
|
||
|
lineItem = ListWidget_FindNextLine(self, baseItem);
|
||
|
if (NULL == lineItem)
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ListWidget_FindLineItemAtPos(self, lineItem, baseItem);
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_GetPreviousPageItem(ListWidget *self, HWND hwnd, ListWidgetItem *baseItem)
|
||
|
{
|
||
|
ListWidgetItem *lineItem;
|
||
|
RECT rect;
|
||
|
POINT origin;
|
||
|
long viewTop;
|
||
|
|
||
|
if (NULL == self || NULL == baseItem)
|
||
|
return NULL;
|
||
|
|
||
|
if (FALSE == GetClientRect(hwnd, &rect))
|
||
|
return NULL;
|
||
|
|
||
|
if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))
|
||
|
OffsetRect(&rect, -origin.x, -origin.y);
|
||
|
|
||
|
if (baseItem->rect.top > rect.bottom)
|
||
|
viewTop = baseItem->rect.bottom - RECTHEIGHT(rect);
|
||
|
else
|
||
|
viewTop = rect.top;
|
||
|
|
||
|
lineItem = ListWidget_FindFirstVisibleLine(self, viewTop);
|
||
|
if (NULL == lineItem)
|
||
|
return NULL;
|
||
|
|
||
|
if (lineItem->rect.top >= baseItem->rect.top)
|
||
|
{
|
||
|
viewTop = baseItem->rect.bottom - RECTHEIGHT(rect);
|
||
|
lineItem = ListWidget_FindFirstVisibleLine(self, viewTop);
|
||
|
if (NULL == lineItem)
|
||
|
return NULL;
|
||
|
if (lineItem->rect.top >= baseItem->rect.top)
|
||
|
{
|
||
|
lineItem = ListWidget_FindPreviousLine(self, baseItem);
|
||
|
if (NULL == lineItem)
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ListWidget_FindLineItemAtPos(self, lineItem, baseItem);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_EnsureItemVisisble(ListWidget *self, HWND hwnd, ListWidgetItem *item, ListWidgetVisibleFlags flags)
|
||
|
{
|
||
|
RECT rect;
|
||
|
POINT pt;
|
||
|
int dx, dy;
|
||
|
|
||
|
if (NULL == self || NULL == item || NULL == hwnd)
|
||
|
return FALSE;
|
||
|
|
||
|
if (FALSE == GetClientRect(hwnd, &rect))
|
||
|
return FALSE;
|
||
|
|
||
|
if (FALSE != ListWidget_GetViewOrigin(hwnd, &pt))
|
||
|
OffsetRect(&rect, -pt.x, -pt.y);
|
||
|
|
||
|
if (0 == (VISIBLE_ALIGN_ALWAYS & flags))
|
||
|
{
|
||
|
if (item->rect.left >= rect.left &&
|
||
|
item->rect.right <= rect.right &&
|
||
|
item->rect.top >= rect.top &&
|
||
|
item->rect.bottom <= rect.bottom)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (0 != (VISIBLE_PARTIAL_OK & flags))
|
||
|
{
|
||
|
if (item->rect.left < rect.right &&
|
||
|
item->rect.right > rect.left &&
|
||
|
item->rect.top < rect.bottom &&
|
||
|
item->rect.bottom > rect.top)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (item->rect.right > rect.right)
|
||
|
dx = item->rect.right - rect.right;
|
||
|
else
|
||
|
dx = 0;
|
||
|
|
||
|
if ((item->rect.left - dx) < rect.left)
|
||
|
dx = item->rect.left - rect.left;
|
||
|
|
||
|
dy = 0;
|
||
|
if (0 != (VISIBLE_ALIGN_TOP & flags))
|
||
|
{
|
||
|
dy = item->rect.bottom - rect.bottom;
|
||
|
}
|
||
|
else if (0 != (VISIBLE_ALIGN_BOTTOM & flags))
|
||
|
{
|
||
|
SCROLLINFO scrollInfo;
|
||
|
scrollInfo.cbSize = sizeof(scrollInfo);
|
||
|
scrollInfo.fMask = SIF_RANGE | SIF_PAGE;
|
||
|
if (FALSE != GetScrollInfo(hwnd, SB_VERT, &scrollInfo))
|
||
|
{
|
||
|
dy = scrollInfo.nMax - rect.bottom;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((item->rect.bottom - dy) > rect.bottom)
|
||
|
dy = item->rect.bottom - rect.bottom;
|
||
|
|
||
|
if ((item->rect.top - dy) < rect.top)
|
||
|
dy = item->rect.top - rect.top;
|
||
|
|
||
|
if (0 == dx && 0 == dy)
|
||
|
return FALSE;
|
||
|
|
||
|
if (FALSE == WIDGET_SCROLL(hwnd, dx, dy, TRUE))
|
||
|
return FALSE;
|
||
|
|
||
|
ListWidget_UpdateHover(self, hwnd);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_AddItem(ListWidgetGroup *group, ListWidgetItem *item)
|
||
|
{
|
||
|
if (NULL == group || NULL == item)
|
||
|
return FALSE;
|
||
|
|
||
|
group->items.push_back(item);
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_FindGroupItemEx(ListWidgetGroup *group, const char *name, size_t max)
|
||
|
{
|
||
|
size_t index, count;
|
||
|
|
||
|
if (NULL == group || NULL == name)
|
||
|
return NULL;
|
||
|
|
||
|
count = group->items.size();
|
||
|
if (max < count)
|
||
|
count = max;
|
||
|
|
||
|
for(index = 0; index < count; index++)
|
||
|
{
|
||
|
ListWidgetItem *item = group->items[index];
|
||
|
if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, name, -1, item->name, -1))
|
||
|
return item;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_FindGroupItem(ListWidgetGroup *group, const char *name)
|
||
|
{
|
||
|
return ListWidget_FindGroupItemEx(group, name, -1);
|
||
|
}
|
||
|
|
||
|
|
||
|
ListWidgetGroup *
|
||
|
ListWidget_GetItemOwner(ListWidget *self, ListWidgetItem *baseItem, ListWidgetCategory **categoryOut)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
|
||
|
if (NULL == self || NULL == baseItem)
|
||
|
return NULL;
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
|
||
|
if (item == baseItem)
|
||
|
{
|
||
|
if (NULL != categoryOut)
|
||
|
*categoryOut = category;
|
||
|
|
||
|
return group;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL != categoryOut)
|
||
|
*categoryOut = NULL;
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem *
|
||
|
ListWidget_FindItem(ListWidget *self, const char *name,
|
||
|
ListWidgetCategory **categoryOut,
|
||
|
ListWidgetGroup **groupOut)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
ListWidgetItem *item;
|
||
|
|
||
|
if (NULL == self || NULL == name)
|
||
|
return NULL;
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
item = group->items[iItem];
|
||
|
|
||
|
if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, name, -1, item->name, -1))
|
||
|
{
|
||
|
if (NULL != categoryOut)
|
||
|
*categoryOut = category;
|
||
|
|
||
|
if (NULL != groupOut)
|
||
|
*groupOut = group;
|
||
|
|
||
|
return item;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_FindItemPos(ListWidget *self, ListWidgetItem *item,
|
||
|
size_t *categoryOut, size_t *groupOut, size_t *itemOut)
|
||
|
{
|
||
|
size_t iCategory, iGroup, iItem;
|
||
|
ListWidgetCategory *category;
|
||
|
ListWidgetGroup *group;
|
||
|
|
||
|
if (NULL == self || NULL == item)
|
||
|
return FALSE;
|
||
|
|
||
|
for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
|
||
|
{
|
||
|
category = self->categories[iCategory];
|
||
|
|
||
|
for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
|
||
|
{
|
||
|
group = category->groups[iGroup];
|
||
|
for(iItem = 0; iItem < group->items.size(); iItem++)
|
||
|
{
|
||
|
if (item == group->items[iItem])
|
||
|
{
|
||
|
if (NULL != categoryOut)
|
||
|
*categoryOut = iCategory;
|
||
|
|
||
|
if (NULL != groupOut)
|
||
|
*groupOut = iGroup;
|
||
|
|
||
|
if (NULL != itemOut)
|
||
|
*itemOut = iItem;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_DisplayItemContextMenu(ListWidget *self, HWND hwnd, ListWidgetItem *item, POINT pt)
|
||
|
{
|
||
|
HMENU menu;
|
||
|
ifc_device *device;
|
||
|
unsigned int commandId;
|
||
|
BOOL succeeded;
|
||
|
char *itemName;
|
||
|
|
||
|
|
||
|
if (NULL == self || NULL == item)
|
||
|
return FALSE;
|
||
|
|
||
|
if (NULL != self->activeMenu)
|
||
|
return FALSE;
|
||
|
|
||
|
if (NULL == WASABI_API_DEVICES ||
|
||
|
S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
menu = CreatePopupMenu();
|
||
|
if (NULL != menu)
|
||
|
{
|
||
|
if (0 == Menu_InsertDeviceItems(menu, 0, 100, device, DeviceCommandContext_ViewMenu))
|
||
|
{
|
||
|
DestroyMenu(menu);
|
||
|
menu = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
device->Release();
|
||
|
|
||
|
if (NULL == menu)
|
||
|
return FALSE;
|
||
|
|
||
|
succeeded = FALSE;
|
||
|
|
||
|
self->activeMenu = menu;
|
||
|
itemName = AnsiString_Duplicate(item->name);
|
||
|
|
||
|
if (FALSE != ListWidget_RemoveHover(self, hwnd, TRUE))
|
||
|
UpdateWindow(hwnd);
|
||
|
|
||
|
commandId = Menu_TrackPopup(Plugin_GetLibraryWindow(), menu,
|
||
|
TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_VERTICAL | TPM_RETURNCMD,
|
||
|
pt.x, pt.y, hwnd, NULL);
|
||
|
|
||
|
|
||
|
self->activeMenu = NULL;
|
||
|
|
||
|
if (0 != commandId)
|
||
|
{
|
||
|
const char *command;
|
||
|
|
||
|
command = (const char*)Menu_GetItemData(menu, commandId, FALSE);
|
||
|
succeeded = ListWidget_SendItemCommand(itemName, command, hwnd, 0, TRUE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (ERROR_SUCCESS == GetLastError())
|
||
|
succeeded = TRUE;
|
||
|
}
|
||
|
|
||
|
Menu_FreeItemData(menu, 0, -1);
|
||
|
|
||
|
AnsiString_Free(itemName);
|
||
|
|
||
|
if (FALSE != ListWidget_UpdateHover(self, hwnd))
|
||
|
UpdateWindow(hwnd);
|
||
|
|
||
|
return succeeded;
|
||
|
}
|
||
|
|
||
|
size_t
|
||
|
ListWidget_GetItemCommands(ListWidgetItem *item, ListWidgetCommand **buffer, size_t bufferMax)
|
||
|
{
|
||
|
size_t count;
|
||
|
ifc_device *device;
|
||
|
|
||
|
if (NULL == item)
|
||
|
return 0;
|
||
|
|
||
|
count = 0;
|
||
|
|
||
|
if (NULL != WASABI_API_DEVICES &&
|
||
|
S_OK == WASABI_API_DEVICES->DeviceFind(item->name, &device))
|
||
|
{
|
||
|
count = ListWigdet_GetDeviceCommands(buffer, bufferMax, device);
|
||
|
device->Release();
|
||
|
}
|
||
|
|
||
|
return count;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_SendItemCommand(const char *name, const char *command, HWND hostWindow, ULONG_PTR param, BOOL enableIntercept)
|
||
|
{
|
||
|
BOOL succeeded;
|
||
|
ifc_device *device;
|
||
|
BOOL commandProcessed;
|
||
|
|
||
|
if (NULL == name ||
|
||
|
NULL == command ||
|
||
|
NULL == WASABI_API_DEVICES ||
|
||
|
S_OK != WASABI_API_DEVICES->DeviceFind(name, &device))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
commandProcessed = FALSE;
|
||
|
succeeded = FALSE;
|
||
|
|
||
|
if (FALSE != enableIntercept)
|
||
|
{
|
||
|
if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, command, -1, "view_open", -1))
|
||
|
{
|
||
|
succeeded = Navigation_SelectDevice(device->GetName());
|
||
|
commandProcessed = succeeded;
|
||
|
}
|
||
|
else if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, command, -1, "rename", -1))
|
||
|
{
|
||
|
succeeded = Navigation_EditDeviceTitle(device->GetName());
|
||
|
commandProcessed = succeeded;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FALSE == commandProcessed &&
|
||
|
SUCCEEDED(device->SendCommand(command, hostWindow, param)))
|
||
|
{
|
||
|
succeeded = TRUE;
|
||
|
}
|
||
|
|
||
|
device->Release();
|
||
|
|
||
|
return succeeded;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_CreateItemActivity(ListWidgetItem *item)
|
||
|
{
|
||
|
if (NULL == item)
|
||
|
return FALSE;
|
||
|
|
||
|
if (NULL == item->activity)
|
||
|
{
|
||
|
item->activity = (ListWidgetActivity*)malloc(sizeof(ListWidgetActivity));
|
||
|
if (NULL == item->activity)
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
item->activity->step = 0;
|
||
|
item->activity->cancelable = FALSE;
|
||
|
item->activity->percent = (unsigned int)-1;
|
||
|
item->activity->title = NULL;
|
||
|
SetSizeEmpty(&item->activity->titleSize);
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_DeleteItemActivity(ListWidgetItem *item)
|
||
|
{
|
||
|
if (NULL == item ||
|
||
|
NULL == item->activity)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
String_Free(item->activity->title);
|
||
|
|
||
|
free(item->activity);
|
||
|
item->activity = NULL;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
ListWidtetActivityChange
|
||
|
ListWidget_UpdateItemActivity(ListWidgetItem *item, ifc_deviceactivity *activity)
|
||
|
{
|
||
|
ListWidgetActivityChange changed;
|
||
|
BOOL cancelable;
|
||
|
unsigned int percent;
|
||
|
wchar_t buffer[512] = {0};
|
||
|
|
||
|
if (NULL == item || NULL == item->activity || NULL == activity)
|
||
|
return ListWidgetActivityChanged_Nothing;
|
||
|
|
||
|
changed = ListWidgetActivityChanged_Nothing;
|
||
|
|
||
|
cancelable = activity->GetCancelable();
|
||
|
if (item->activity->cancelable != cancelable)
|
||
|
{
|
||
|
changed |= ListWidgetActivityChanged_Cancelable;
|
||
|
item->activity->cancelable = cancelable;
|
||
|
}
|
||
|
|
||
|
if(FAILED(activity->GetProgress(&percent)))
|
||
|
percent = (unsigned int)-1;
|
||
|
|
||
|
if (item->activity->percent != percent)
|
||
|
{
|
||
|
changed |= ListWidgetActivityChanged_Percent;
|
||
|
item->activity->percent = percent;
|
||
|
|
||
|
}
|
||
|
|
||
|
if (FAILED(activity->GetDisplayName(buffer, ARRAYSIZE(buffer))))
|
||
|
buffer[0] = L'\0';
|
||
|
|
||
|
if (NULL == item->activity->title ||
|
||
|
CSTR_EQUAL != CompareString(LOCALE_SYSTEM_DEFAULT, 0, item->activity->title, -1, buffer, -1))
|
||
|
{
|
||
|
changed |= ListWidgetActivityChanged_Title;
|
||
|
|
||
|
String_Free(item->activity->title);
|
||
|
item->activity->title = String_Duplicate(buffer);
|
||
|
SetSizeEmpty(&item->activity->titleSize);
|
||
|
}
|
||
|
|
||
|
return changed;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetItemImageRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
|
||
|
{
|
||
|
if (NULL == item || NULL == rect)
|
||
|
return FALSE;
|
||
|
|
||
|
if (FALSE == CopyRect(rect, &item->rect))
|
||
|
return FALSE;
|
||
|
|
||
|
if (NULL != metrics)
|
||
|
{
|
||
|
rect->left += metrics->offsetLeft + metrics->imageOffsetLeft;
|
||
|
rect->top += metrics->offsetTop + metrics->imageOffsetTop;
|
||
|
rect->right -= metrics->offsetRight - metrics->imageOffsetRight;
|
||
|
rect->bottom = rect->top + self->imageSize.cy;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetItemFrameRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
|
||
|
{
|
||
|
if (NULL == item || NULL == rect)
|
||
|
return FALSE;
|
||
|
|
||
|
if (FALSE == CopyRect(rect, &item->rect))
|
||
|
return FALSE;
|
||
|
|
||
|
if (NULL != metrics)
|
||
|
{
|
||
|
rect->bottom = rect->top + metrics->offsetTop +
|
||
|
metrics->imageOffsetTop + metrics->imageOffsetBottom +
|
||
|
self->imageSize.cy;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
ListWidget_CalcItemActivityTitleSize(ListWidget *self, HDC hdc, ListWidgetActivity *activity)
|
||
|
{
|
||
|
BOOL result;
|
||
|
HDC windowDC;
|
||
|
HFONT prevFont;
|
||
|
RECT rect;
|
||
|
|
||
|
|
||
|
if (NULL == hdc)
|
||
|
{
|
||
|
windowDC = GetDCEx(NULL, NULL, DCX_WINDOW | DCX_CACHE | DCX_NORESETATTRS);
|
||
|
if (NULL == windowDC)
|
||
|
{
|
||
|
SetSizeEmpty(&activity->titleSize);
|
||
|
return FALSE;
|
||
|
}
|
||
|
hdc = windowDC;
|
||
|
}
|
||
|
else
|
||
|
windowDC = NULL;
|
||
|
|
||
|
prevFont = SelectFont(hdc, self->activityFont);
|
||
|
|
||
|
SetRect(&rect, 0, 0, self->activityMetrics.titleWidth, self->activityMetrics.titleHeight);
|
||
|
result = DrawText(hdc, activity->title, -1, &rect,
|
||
|
DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK | DT_EDITCONTROL | DT_WORD_ELLIPSIS);
|
||
|
|
||
|
if (FALSE == result)
|
||
|
SetSizeEmpty(&activity->titleSize);
|
||
|
else
|
||
|
{
|
||
|
TEXTMETRIC textMetrics;
|
||
|
if (FALSE == GetTextMetrics(hdc, &textMetrics))
|
||
|
ZeroMemory(&textMetrics, sizeof(textMetrics));
|
||
|
|
||
|
if (rect.right > self->activityMetrics.titleWidth)
|
||
|
rect.right = self->activityMetrics.titleWidth;
|
||
|
if (rect.bottom > self->activityMetrics.titleHeight)
|
||
|
{
|
||
|
textMetrics.tmHeight = self->activityMetrics.fontHeight;
|
||
|
rect.bottom = (self->activityMetrics.titleHeight/textMetrics.tmHeight)*textMetrics.tmHeight;
|
||
|
}
|
||
|
|
||
|
activity->titleSize.cx = rect.right + textMetrics.tmAveCharWidth/2;
|
||
|
activity->titleSize.cy = rect.bottom;
|
||
|
}
|
||
|
|
||
|
SelectFont(hdc, prevFont);
|
||
|
if (NULL != windowDC)
|
||
|
ReleaseDC(NULL, windowDC);
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
static BOOL
|
||
|
ListWidget_GetItemActivityWorkRect(ListWidget *self, HDC hdc,
|
||
|
ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
|
||
|
{
|
||
|
ListWidgetActivityMetric *activityMetrics;
|
||
|
long length;
|
||
|
|
||
|
if (FALSE == ListWidget_GetItemActivityRect(self, item, metrics, rect))
|
||
|
return FALSE;
|
||
|
|
||
|
if (0 == item->activity->titleSize.cy &&
|
||
|
FALSE == ListWidget_CalcItemActivityTitleSize(self, hdc, item->activity))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
activityMetrics = &self->activityMetrics;
|
||
|
|
||
|
length = 0;
|
||
|
if (0 != activityMetrics->progressWidth)
|
||
|
{
|
||
|
if (0 != length)
|
||
|
length += activityMetrics->spacing;
|
||
|
length += activityMetrics->progressWidth;
|
||
|
}
|
||
|
|
||
|
if (0 != item->activity->titleSize.cx)
|
||
|
{
|
||
|
if (0 != length)
|
||
|
length += activityMetrics->spacing;
|
||
|
length += item->activity->titleSize.cx;
|
||
|
}
|
||
|
|
||
|
if (0 != activityMetrics->percentWidth)
|
||
|
{
|
||
|
if (0 != length)
|
||
|
length += activityMetrics->spacing;
|
||
|
length += activityMetrics->percentWidth;
|
||
|
}
|
||
|
|
||
|
rect->top += activityMetrics->offsetTop;
|
||
|
rect->bottom -= activityMetrics->offsetBottom;
|
||
|
|
||
|
rect->left += activityMetrics->offsetLeft;
|
||
|
rect->right -= activityMetrics->offsetRight;
|
||
|
|
||
|
rect->left += ((rect->right - rect->left) - length)/2;
|
||
|
rect->right = rect->left + length;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetItemActivityRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
|
||
|
{
|
||
|
if (NULL == self ||
|
||
|
NULL == item ||
|
||
|
NULL == metrics ||
|
||
|
NULL == rect)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
rect->bottom = item->rect.top + self->imageSize.cy /*+ metrics.imageOffsetBottom*/;
|
||
|
rect->bottom += metrics->offsetTop + metrics->imageOffsetTop;
|
||
|
rect->top = rect->bottom - self->activityMetrics.height;
|
||
|
|
||
|
rect->left = item->rect.left + (self->itemWidth - self->activityMetrics.width)/2;
|
||
|
rect->right = rect->left + self->activityMetrics.width;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetItemActivityProgressRect(ListWidget *self, HDC hdc,
|
||
|
ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
|
||
|
{
|
||
|
if (0 == self->activityMetrics.progressWidth ||
|
||
|
FALSE == ListWidget_GetItemActivityWorkRect(self, hdc, item, metrics, rect))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
rect->right = rect->left + self->activityMetrics.progressWidth;
|
||
|
rect->top +=((rect->bottom - rect->top) - self->activityMetrics.progressHeight)/2;
|
||
|
rect->bottom = rect->top + self->activityMetrics.progressHeight;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetItemActivityPercentRect(ListWidget *self, HDC hdc,
|
||
|
ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
|
||
|
{
|
||
|
if (0 == self->activityMetrics.percentWidth ||
|
||
|
FALSE == ListWidget_GetItemActivityWorkRect(self, hdc, item, metrics, rect))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
rect->left = rect->right - self->activityMetrics.percentWidth;
|
||
|
rect->top += ((rect->bottom - rect->top) - self->activityMetrics.percentHeight)/2;
|
||
|
rect->bottom = rect->top + self->activityMetrics.percentHeight;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetItemActivityTitleRect(ListWidget *self, HDC hdc,
|
||
|
ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
|
||
|
{
|
||
|
if (0 == self->activityMetrics.titleWidth ||
|
||
|
FALSE == ListWidget_GetItemActivityWorkRect(self, hdc, item, metrics, rect))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (0 != self->activityMetrics.progressWidth)
|
||
|
rect->left += self->activityMetrics.progressWidth + self->activityMetrics.spacing;
|
||
|
|
||
|
rect->right = rect->left + item->activity->titleSize.cx;
|
||
|
|
||
|
rect->top += ((rect->bottom - rect->top) - item->activity->titleSize.cy)/2;
|
||
|
rect->bottom = rect->top + item->activity->titleSize.cy;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_InvalidateItemActivity(ListWidget *self, HWND hwnd, ListWidgetItem *item, ListWidgetActivityChange changes)
|
||
|
{
|
||
|
ListWidgetItemMetric metrics;
|
||
|
WidgetStyle *style;
|
||
|
POINT origin;
|
||
|
RECT rect;
|
||
|
BOOL invalidated;
|
||
|
|
||
|
|
||
|
if (ListWidgetActivityChanged_Nothing == changes)
|
||
|
return FALSE;
|
||
|
|
||
|
style = WIDGET_GET_STYLE(hwnd);
|
||
|
|
||
|
|
||
|
if (NULL == style ||
|
||
|
FALSE == ListWidget_GetItemMetrics(style, &metrics))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))
|
||
|
{
|
||
|
origin.x = 0;
|
||
|
origin.y = 0;
|
||
|
}
|
||
|
|
||
|
invalidated = FALSE;
|
||
|
|
||
|
if (0 != (ListWidgetActivityChanged_Percent & changes))
|
||
|
{
|
||
|
if (FALSE != ListWidget_GetItemActivityPercentRect(self, NULL, item, &metrics, &rect))
|
||
|
{
|
||
|
OffsetRect(&rect, origin.x, origin.y);
|
||
|
if (FALSE != InvalidateRect(hwnd, &rect, FALSE))
|
||
|
invalidated = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (0 != (ListWidgetActivityChanged_Title & changes))
|
||
|
{
|
||
|
if (FALSE != ListWidget_GetItemActivityTitleRect(self, NULL, item, &metrics, &rect))
|
||
|
{
|
||
|
OffsetRect(&rect, origin.x, origin.y);
|
||
|
if (FALSE != InvalidateRect(hwnd, &rect, FALSE))
|
||
|
invalidated = TRUE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return invalidated;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_InvalidateItemImage(ListWidget *self, HWND hwnd, ListWidgetItem *item)
|
||
|
{
|
||
|
ListWidgetItemMetric metrics;
|
||
|
WidgetStyle *style;
|
||
|
POINT origin;
|
||
|
RECT rect;
|
||
|
|
||
|
style = WIDGET_GET_STYLE(hwnd);
|
||
|
|
||
|
if (NULL == style ||
|
||
|
FALSE == ListWidget_GetItemMetrics(style, &metrics))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (FALSE == ListWidget_GetItemImageRect(self, item, &metrics, &rect))
|
||
|
return FALSE;
|
||
|
|
||
|
if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))
|
||
|
OffsetRect(&rect, origin.x, origin.y);
|
||
|
|
||
|
return InvalidateRect(hwnd, &rect, FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetItemSpacebarRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
|
||
|
{
|
||
|
if (NULL == item || NULL == rect)
|
||
|
return FALSE;
|
||
|
|
||
|
if (0 == item->spaceTotal ||
|
||
|
FALSE == CopyRect(rect, &item->rect))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (NULL != metrics)
|
||
|
{
|
||
|
rect->left += metrics->offsetLeft;
|
||
|
rect->top += metrics->offsetTop + metrics->imageOffsetTop +
|
||
|
self->imageSize.cy + metrics->imageOffsetBottom +
|
||
|
metrics->spacebarOffsetTop;
|
||
|
rect->right -= metrics->offsetRight;
|
||
|
rect->bottom = rect->top + metrics->spacebarHeight;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetItemTitleRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, BOOL exactSize, RECT *rect)
|
||
|
{
|
||
|
if (NULL == item || NULL == rect)
|
||
|
return FALSE;
|
||
|
|
||
|
if (FALSE == CopyRect(rect, &item->rect))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (NULL != metrics)
|
||
|
{
|
||
|
rect->left += metrics->offsetLeft;
|
||
|
rect->top += metrics->offsetTop + metrics->imageOffsetTop +
|
||
|
self->imageSize.cy + metrics->imageOffsetBottom;
|
||
|
|
||
|
if (0 != item->spaceTotal)
|
||
|
rect->top += metrics->spacebarOffsetTop + metrics->spacebarHeight;
|
||
|
|
||
|
rect->top += metrics->titleOffsetTop;
|
||
|
rect->right -= metrics->offsetRight;
|
||
|
rect->bottom -= metrics->offsetBottom;
|
||
|
}
|
||
|
|
||
|
if (-1 != item->titleSize.cy)
|
||
|
{
|
||
|
long max;
|
||
|
|
||
|
if (FALSE != exactSize)
|
||
|
{
|
||
|
max = rect->right - rect->left;
|
||
|
if (max > item->titleSize.cx)
|
||
|
{
|
||
|
rect->left += (max - item->titleSize.cx)/2;
|
||
|
rect->right = rect->left + item->titleSize.cx;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
max = rect->top + item->titleSize.cy;
|
||
|
if (rect->bottom > max)
|
||
|
rect->bottom = max;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetItemConnectionRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
|
||
|
{
|
||
|
if (NULL == item || NULL == rect)
|
||
|
return FALSE;
|
||
|
|
||
|
if (NULL == metrics)
|
||
|
return FALSE;
|
||
|
|
||
|
SetRect(rect, 0, 0, self->connectionSize.cx, self->connectionSize.cy);
|
||
|
OffsetRect(rect,
|
||
|
item->rect.right - metrics->offsetRight - metrics->imageOffsetRight - rect->right - 2,
|
||
|
item->rect.top + metrics->offsetTop + metrics->imageOffsetTop + self->imageSize.cy - rect->bottom - 2);
|
||
|
|
||
|
if (rect->left < (item->rect.left + metrics->offsetLeft) ||
|
||
|
rect->top < (item->rect.top + metrics->offsetTop))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
ListWidgetItemPart
|
||
|
ListWidget_GetItemPartFromPoint(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics,
|
||
|
POINT pt, ListWidgetItemPart mask, RECT *partRect)
|
||
|
{
|
||
|
RECT rect;
|
||
|
|
||
|
if (NULL == self ||
|
||
|
NULL == item ||
|
||
|
NULL == metrics)
|
||
|
{
|
||
|
if (NULL != partRect)
|
||
|
SetRectEmpty(partRect);
|
||
|
|
||
|
return ListWidgetItemPart_None;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
if (NULL != item->activity &&
|
||
|
FALSE != ListWidget_GetItemActivityRect(self, item, metrics, &rect) &&
|
||
|
FALSE != PtInRect(&rect, pt))
|
||
|
{
|
||
|
if (0 != (ListWidgetItemPart_Activity & mask))
|
||
|
{
|
||
|
if (NULL != partRect)
|
||
|
CopyRect(partRect, &rect);
|
||
|
|
||
|
return ListWidgetItemPart_Activity;
|
||
|
}
|
||
|
|
||
|
mask &= ~(ListWidgetItemPart_Command | ListWidgetItemPart_Connection);
|
||
|
}
|
||
|
|
||
|
if (0 != (ListWidgetItemPart_Command & mask) &&
|
||
|
FALSE != ListWidgetItem_IsInteractive(item))
|
||
|
{
|
||
|
|
||
|
size_t index = self->commandsCount;
|
||
|
while(index--)
|
||
|
{
|
||
|
if (FALSE != ListWidget_GetCommandRect(self->commands[index], &rect))
|
||
|
{
|
||
|
OffsetRect(&rect, item->rect.left, item->rect.top);
|
||
|
if (FALSE != PtInRect(&rect, pt))
|
||
|
{
|
||
|
if (FALSE == ListWidget_GetCommandDisabled(self->commands[index]))
|
||
|
{
|
||
|
if (NULL != partRect)
|
||
|
CopyRect(partRect, &rect);
|
||
|
|
||
|
return ListWidgetItemPart_Command;
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (0 != (ListWidgetItemPart_Connection & mask) &&
|
||
|
FALSE != ListWidget_GetItemConnectionRect(self, item, metrics, &rect) &&
|
||
|
FALSE != PtInRect(&rect, pt))
|
||
|
{
|
||
|
if (NULL != partRect)
|
||
|
CopyRect(partRect, &rect);
|
||
|
return ListWidgetItemPart_Connection;
|
||
|
}
|
||
|
|
||
|
if (0 != (ListWidgetItemPart_Image & mask) &&
|
||
|
FALSE != ListWidget_GetItemImageRect(self, item, metrics, &rect) &&
|
||
|
FALSE != PtInRect(&rect, pt))
|
||
|
{
|
||
|
if (NULL != partRect)
|
||
|
CopyRect(partRect, &rect);
|
||
|
return ListWidgetItemPart_Image;
|
||
|
}
|
||
|
|
||
|
if (0 != (ListWidgetItemPart_Frame & mask) &&
|
||
|
FALSE != ListWidget_GetItemFrameRect(self, item, metrics, &rect) &&
|
||
|
FALSE != PtInRect(&rect, pt))
|
||
|
{
|
||
|
if (NULL != partRect)
|
||
|
CopyRect(partRect, &rect);
|
||
|
return ListWidgetItemPart_Frame;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (0 != (ListWidgetItemPart_Spacebar & mask) &&
|
||
|
FALSE != ListWidget_GetItemSpacebarRect(self, item, metrics, &rect) &&
|
||
|
FALSE != PtInRect(&rect, pt))
|
||
|
{
|
||
|
if (NULL != partRect)
|
||
|
CopyRect(partRect, &rect);
|
||
|
return ListWidgetItemPart_Spacebar;
|
||
|
}
|
||
|
|
||
|
if (0 != (ListWidgetItemPart_Title & mask) &&
|
||
|
FALSE != ListWidget_GetItemTitleRect(self, item, metrics, FALSE, &rect) &&
|
||
|
FALSE != PtInRect(&rect, pt))
|
||
|
{
|
||
|
if (NULL != partRect)
|
||
|
CopyRect(partRect, &rect);
|
||
|
return ListWidgetItemPart_Title;
|
||
|
}
|
||
|
|
||
|
return ListWidgetItemPart_None;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
static BOOL
|
||
|
ListWidget_FilterItemTitle(wchar_t *buffer, size_t bufferMax)
|
||
|
{
|
||
|
size_t read, write;
|
||
|
|
||
|
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 HRESULT
|
||
|
ListWidget_GetDeviceStatus(ifc_device *device, wchar_t *buffer, size_t bufferMax)
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
ifc_deviceactivity *activity;
|
||
|
|
||
|
if(NULL == buffer)
|
||
|
return E_POINTER;
|
||
|
|
||
|
buffer[0] = L'\0';
|
||
|
if (NULL == device)
|
||
|
return S_OK;
|
||
|
|
||
|
hr = device->GetActivity(&activity);
|
||
|
if (S_OK == hr && NULL != activity)
|
||
|
{
|
||
|
hr = activity->GetStatus(buffer, bufferMax);
|
||
|
if (FAILED(hr) || L'\0' == buffer[0])
|
||
|
hr = activity->GetDisplayName(buffer, bufferMax);
|
||
|
|
||
|
activity->Release();
|
||
|
}
|
||
|
|
||
|
if (FAILED(hr) || L'\0' == buffer[0])
|
||
|
hr = device->GetStatus(buffer, bufferMax);
|
||
|
|
||
|
if (E_NOTIMPL == hr)
|
||
|
{
|
||
|
hr = S_OK;
|
||
|
buffer[0] = L'\0';
|
||
|
}
|
||
|
|
||
|
return hr;
|
||
|
|
||
|
}
|
||
|
BOOL
|
||
|
ListWidget_FormatItemCommandTip(ListWidget *self, ListWidgetItem *item, const RECT *commandRect, wchar_t *buffer, size_t bufferMax)
|
||
|
{
|
||
|
size_t index;
|
||
|
RECT rect;
|
||
|
|
||
|
if (NULL == self)
|
||
|
return FALSE;
|
||
|
|
||
|
for(index = 0; index < self->commandsCount; index++)
|
||
|
{
|
||
|
ListWidgetCommand *command = self->commands[index];
|
||
|
if (FALSE != ListWidget_GetCommandRect(command, &rect) &&
|
||
|
FALSE != EqualRect(&rect, commandRect))
|
||
|
{
|
||
|
const wchar_t *value;
|
||
|
wchar_t *cursor;
|
||
|
size_t remaining;
|
||
|
|
||
|
cursor = buffer;
|
||
|
remaining = bufferMax;
|
||
|
|
||
|
value = ListWidget_GetCommandTitle(command);
|
||
|
if (FALSE == IS_STRING_EMPTY(value))
|
||
|
StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
value = ListWidget_GetCommandDescription(command);
|
||
|
if (FALSE == IS_STRING_EMPTY(value))
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
|
||
|
return (cursor != buffer);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_FormatItemTip(ListWidget *self, ListWidgetItem *item, wchar_t *buffer, size_t bufferMax)
|
||
|
{
|
||
|
ifc_device *device;
|
||
|
ifc_devicetype *type;
|
||
|
ifc_deviceconnection *connection;
|
||
|
wchar_t value[1024], valueName[512], *cursor;
|
||
|
size_t remaining;
|
||
|
uint64_t totalSpace, usedSpace;
|
||
|
|
||
|
if (NULL == item ||
|
||
|
NULL == WASABI_API_DEVICES ||
|
||
|
S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
cursor = buffer;
|
||
|
remaining = bufferMax;
|
||
|
|
||
|
if (FALSE != ListWidgetItem_IsTextTruncated(item))
|
||
|
{
|
||
|
if (SUCCEEDED(device->GetDisplayName(value, ARRAYSIZE(value))) &&
|
||
|
L'\0' != value[0])
|
||
|
{
|
||
|
ListWidget_FilterItemTitle(value, ARRAYSIZE(value));
|
||
|
StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(device->GetModel(value, ARRAYSIZE(value))) &&
|
||
|
L'\0' != value[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_MODEL_SHORT, valueName, ARRAYSIZE(valueName));
|
||
|
HRESULT hr;
|
||
|
if (L'\0' != valueName[0])
|
||
|
hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
|
||
|
else
|
||
|
hr = S_OK;
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
|
||
|
if (NULL != WASABI_API_DEVICES &&
|
||
|
S_OK == WASABI_API_DEVICES->TypeFind(device->GetType(), &type))
|
||
|
{
|
||
|
const char* typeStr = device->GetDisplayType();
|
||
|
if (typeStr && *typeStr)
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_TYPE_SHORT, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
|
||
|
|
||
|
StringCchCopyEx(cursor, remaining, AutoWide(typeStr), &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (SUCCEEDED(type->GetDisplayName(value, ARRAYSIZE(value))) &&
|
||
|
L'\0' != value[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_TYPE_SHORT, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
|
||
|
|
||
|
StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
type->Release();
|
||
|
}
|
||
|
|
||
|
if (NULL != WASABI_API_DEVICES &&
|
||
|
S_OK == WASABI_API_DEVICES->ConnectionFind(device->GetConnection(), &connection))
|
||
|
{
|
||
|
if (SUCCEEDED(connection->GetDisplayName(value, ARRAYSIZE(value))) &&
|
||
|
L'\0' != value[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_CONNECTION_SHORT, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
|
||
|
|
||
|
StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
connection->Release();
|
||
|
}
|
||
|
|
||
|
if (FAILED(device->GetTotalSpace(&totalSpace)) ||
|
||
|
0 == totalSpace)
|
||
|
{
|
||
|
totalSpace = ((uint64_t)-1);
|
||
|
}
|
||
|
|
||
|
if (FAILED(device->GetUsedSpace(&usedSpace)))
|
||
|
usedSpace = ((uint64_t)-1);
|
||
|
else if (((uint64_t)-1) != totalSpace && usedSpace > totalSpace)
|
||
|
usedSpace = totalSpace;
|
||
|
|
||
|
if (((uint64_t)-1) != totalSpace && ((uint64_t)-1) != usedSpace)
|
||
|
{
|
||
|
if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), totalSpace - usedSpace))
|
||
|
{
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_FREE_SPACE, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: %s",
|
||
|
valueName, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (((uint64_t)-1) != totalSpace)
|
||
|
{
|
||
|
if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), totalSpace))
|
||
|
{
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_TOTAL_SPACE, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: %s",
|
||
|
valueName, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// status
|
||
|
/*if (SUCCEEDED(ListWidget_GetDeviceStatus(device, value, ARRAYSIZE(value))) &&
|
||
|
L'\0' != value[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_STATUS_SHORT, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
|
||
|
else
|
||
|
hr = S_OK;
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
hr = StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
device->Release();
|
||
|
return (cursor != buffer);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_FormatItemTitleTip(ListWidget *self, ListWidgetItem *item, wchar_t *buffer, size_t bufferMax)
|
||
|
{
|
||
|
BOOL result;
|
||
|
ifc_device *device;
|
||
|
|
||
|
if (NULL == item ||
|
||
|
FALSE == ListWidgetItem_IsTextTruncated(item) ||
|
||
|
NULL == WASABI_API_DEVICES ||
|
||
|
S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(device->GetDisplayName(buffer, bufferMax)))
|
||
|
{
|
||
|
ListWidget_FilterItemTitle(buffer, bufferMax);
|
||
|
result = TRUE;
|
||
|
}
|
||
|
else
|
||
|
result = FALSE;
|
||
|
|
||
|
device->Release();
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_FormatItemSpaceTip(ListWidget *self, ListWidgetItem *item, wchar_t *buffer, size_t bufferMax)
|
||
|
{
|
||
|
ifc_device *device;
|
||
|
|
||
|
wchar_t value[1024], valueName[512], *cursor;
|
||
|
size_t remaining;
|
||
|
uint64_t totalSpace, usedSpace;
|
||
|
|
||
|
if (NULL == item ||
|
||
|
NULL == WASABI_API_DEVICES ||
|
||
|
S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
cursor = buffer;
|
||
|
remaining = bufferMax;
|
||
|
|
||
|
if (FAILED(device->GetTotalSpace(&totalSpace)) ||
|
||
|
0 == totalSpace)
|
||
|
{
|
||
|
totalSpace = ((uint64_t)-1);
|
||
|
}
|
||
|
|
||
|
if (FAILED(device->GetUsedSpace(&usedSpace)))
|
||
|
usedSpace = ((uint64_t)-1);
|
||
|
else if (((uint64_t)-1) != totalSpace && usedSpace > totalSpace)
|
||
|
usedSpace = totalSpace;
|
||
|
|
||
|
if (((uint64_t)-1) != usedSpace)
|
||
|
{
|
||
|
if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), usedSpace))
|
||
|
{
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_USED_SPACE, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: %s",
|
||
|
valueName, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (((uint64_t)-1) != totalSpace && ((uint64_t)-1) != usedSpace)
|
||
|
{
|
||
|
if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), totalSpace - usedSpace))
|
||
|
{
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_FREE_SPACE, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: %s",
|
||
|
valueName, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (((uint64_t)-1) != totalSpace)
|
||
|
{
|
||
|
if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), totalSpace))
|
||
|
{
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_TOTAL_SPACE, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: %s",
|
||
|
valueName, value);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
device->Release();
|
||
|
return (cursor != buffer);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_FormatItemStatus(ListWidget *self, ListWidgetItem *item, wchar_t *buffer, size_t bufferMax)
|
||
|
{
|
||
|
ifc_device *device;
|
||
|
ifc_devicetype *type;
|
||
|
ifc_deviceconnection *connection;
|
||
|
|
||
|
HRESULT hr;
|
||
|
wchar_t value[512], valueName[128], *cursor;
|
||
|
size_t remaining;
|
||
|
|
||
|
if (NULL == item ||
|
||
|
NULL == WASABI_API_DEVICES ||
|
||
|
S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
hr = S_OK;
|
||
|
cursor = buffer;
|
||
|
remaining = bufferMax;
|
||
|
|
||
|
if (FALSE != ListWidgetItem_IsTextTruncated(item))
|
||
|
{
|
||
|
if (SUCCEEDED(device->GetDisplayName(value, ARRAYSIZE(value))) &&
|
||
|
L'\0' != value[0])
|
||
|
{
|
||
|
ListWidget_FilterItemTitle(value, ARRAYSIZE(value));
|
||
|
hr = StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (cursor == buffer &&
|
||
|
SUCCEEDED(device->GetModel(value, ARRAYSIZE(value))) &&
|
||
|
L'\0' != value[0])
|
||
|
{
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_MODEL_SHORT, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
hr = StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
|
||
|
if (cursor == buffer &&
|
||
|
NULL != WASABI_API_DEVICES &&
|
||
|
S_OK == WASABI_API_DEVICES->TypeFind(device->GetType(), &type))
|
||
|
{
|
||
|
if (SUCCEEDED(type->GetDisplayName(value, ARRAYSIZE(value))) &&
|
||
|
L'\0' != value[0])
|
||
|
{
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_TYPE_SHORT, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
hr = StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
|
||
|
type->Release();
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
const char* typeStr = device->GetDisplayType();
|
||
|
if (typeStr && *typeStr)
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
hr = StringCchCopyEx(cursor, remaining, L", ", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_TYPE_SHORT, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
|
||
|
|
||
|
if (SUCCEEDED(hr))
|
||
|
StringCchCopyEx(cursor, remaining, AutoWide(typeStr), &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (NULL != WASABI_API_DEVICES &&
|
||
|
S_OK == WASABI_API_DEVICES->ConnectionFind(device->GetConnection(), &connection))
|
||
|
{
|
||
|
if (SUCCEEDED(connection->GetDisplayName(value, ARRAYSIZE(value))) &&
|
||
|
L'\0' != value[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L", ", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_CONNECTION_SHORT, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
|
||
|
|
||
|
StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
connection->Release();
|
||
|
}
|
||
|
|
||
|
if (cursor == buffer &&
|
||
|
SUCCEEDED(device->GetDisplayName(value, ARRAYSIZE(value))))
|
||
|
{
|
||
|
ListWidget_FilterItemTitle(value, ARRAYSIZE(value));
|
||
|
StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
|
||
|
if (SUCCEEDED(ListWidget_GetDeviceStatus(device, value, ARRAYSIZE(value))) &&
|
||
|
L'\0' != value[0])
|
||
|
{
|
||
|
if (cursor != buffer)
|
||
|
StringCchCopyEx(cursor, remaining, L", ", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
|
||
|
StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
|
||
|
}
|
||
|
|
||
|
device->Release();
|
||
|
|
||
|
return (cursor != buffer);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_FormatItemSpaceStatus(ListWidget *self, ListWidgetItem *item, wchar_t *buffer, size_t bufferMax)
|
||
|
{
|
||
|
ifc_device *device;
|
||
|
|
||
|
wchar_t *cursor;
|
||
|
size_t remaining;
|
||
|
uint64_t totalSpace, usedSpace;
|
||
|
|
||
|
if (NULL == item ||
|
||
|
NULL == WASABI_API_DEVICES ||
|
||
|
S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
cursor = buffer;
|
||
|
remaining = bufferMax;
|
||
|
|
||
|
if (FAILED(device->GetTotalSpace(&totalSpace)) ||
|
||
|
0 == totalSpace)
|
||
|
{
|
||
|
totalSpace = ((uint64_t)-1);
|
||
|
}
|
||
|
|
||
|
if (FAILED(device->GetUsedSpace(&usedSpace)))
|
||
|
usedSpace = ((uint64_t)-1);
|
||
|
else if (((uint64_t)-1) != totalSpace && usedSpace > totalSpace)
|
||
|
usedSpace = totalSpace;
|
||
|
|
||
|
if (((uint64_t)-1) != totalSpace)
|
||
|
{
|
||
|
if (((uint64_t)-1) != usedSpace)
|
||
|
{
|
||
|
wchar_t value1[64] = {0}, value2[64] = {0};
|
||
|
if (NULL != WASABI_API_LNG->FormattedSizeString(value1, ARRAYSIZE(value1), totalSpace - usedSpace) &&
|
||
|
NULL != WASABI_API_LNG->FormattedSizeString(value2, ARRAYSIZE(value2), totalSpace))
|
||
|
{
|
||
|
wchar_t format[128] = {0};
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_STATUS_SPACE_TEMPLATE, format, ARRAYSIZE(format));
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE,
|
||
|
format, value1, value2);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
wchar_t value[64] = {0};
|
||
|
if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), totalSpace))
|
||
|
{
|
||
|
wchar_t valueName[128] = {0};
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_TOTAL_SPACE, valueName, ARRAYSIZE(valueName));
|
||
|
if (L'\0' != valueName[0])
|
||
|
{
|
||
|
StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE,
|
||
|
L"%s %s", value, valueName);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
device->Release();
|
||
|
|
||
|
return (cursor != buffer);
|
||
|
}
|
||
|
|
||
|
static void CALLBACK
|
||
|
ListWidget_EndTitleEditCb(HWND editorWindow, BOOL canceled, const wchar_t *text, void *user)
|
||
|
{
|
||
|
HWND hwnd;
|
||
|
ListWidget *self;
|
||
|
char *itemName;
|
||
|
|
||
|
hwnd = GetAncestor(editorWindow, GA_PARENT);
|
||
|
self = WIDGET_GET_SELF(hwnd, ListWidget);
|
||
|
|
||
|
itemName = (char*)user;
|
||
|
|
||
|
if (NULL != self)
|
||
|
{
|
||
|
ListWidgetItem *item;
|
||
|
|
||
|
if (self->titleEditor == editorWindow)
|
||
|
self->titleEditor = NULL;
|
||
|
|
||
|
item = ListWidget_FindItem(self, itemName, NULL, NULL);
|
||
|
if (NULL != item)
|
||
|
{
|
||
|
ListWidgetItemMetric metrics;
|
||
|
WidgetStyle *style;
|
||
|
POINT origin;
|
||
|
RECT rect;
|
||
|
|
||
|
ListWidgetItem_UnsetTextEdited(item);
|
||
|
|
||
|
style = WIDGET_GET_STYLE(hwnd);
|
||
|
|
||
|
if (NULL != style &&
|
||
|
FALSE != ListWidget_GetItemMetrics(style, &metrics) &&
|
||
|
FALSE != ListWidget_GetItemTitleRect(self, item, &metrics, FALSE, &rect))
|
||
|
{
|
||
|
if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))
|
||
|
OffsetRect(&rect, origin.x, origin.y);
|
||
|
|
||
|
InvalidateRect(hwnd, &rect, FALSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (FALSE == canceled)
|
||
|
{
|
||
|
ifc_device *device;
|
||
|
if (NULL != WASABI_API_DEVICES &&
|
||
|
S_OK == WASABI_API_DEVICES->DeviceFind(itemName, &device))
|
||
|
{
|
||
|
wchar_t buffer[1024] = {0};
|
||
|
|
||
|
if (FAILED(device->GetDisplayName(buffer, ARRAYSIZE(buffer))) ||
|
||
|
CSTR_EQUAL != CompareString(LOCALE_USER_DEFAULT, 0, buffer, -1, text, -1))
|
||
|
{
|
||
|
HRESULT hr;
|
||
|
|
||
|
hr = device->SetDisplayName(text);
|
||
|
|
||
|
if (FAILED(hr))
|
||
|
{
|
||
|
wchar_t title[256] = {0}, message[1024] = {0};
|
||
|
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_MESSAGEBOX_TITLE, title, ARRAYSIZE(title));
|
||
|
WASABI_API_LNGSTRINGW_BUF(IDS_MESSAGE_UNABLE_TO_RENAME, message, ARRAYSIZE(message));
|
||
|
|
||
|
MessageBox(hwnd, message, title, MB_OK | MB_ICONERROR);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
device->Release();
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
EMBEDDEDEDITOR_SET_USER_DATA(editorWindow, NULL);
|
||
|
AnsiString_Free(itemName);
|
||
|
}
|
||
|
|
||
|
HWND
|
||
|
ListWidget_BeginItemTitleEdit(ListWidget *self, HWND hwnd, ListWidgetItem *item)
|
||
|
{
|
||
|
RECT rect;
|
||
|
WidgetStyle *style;
|
||
|
ListWidgetItemMetric metrics;
|
||
|
HWND editor;
|
||
|
POINT origin;
|
||
|
unsigned long editorStyleEx, editorStyle;
|
||
|
char *itemName;
|
||
|
ifc_device * device;
|
||
|
BOOL blockEditor;
|
||
|
|
||
|
|
||
|
if (NULL == self || NULL == item)
|
||
|
return NULL;
|
||
|
|
||
|
style = WIDGET_GET_STYLE(hwnd);
|
||
|
if (NULL == style)
|
||
|
return NULL;
|
||
|
|
||
|
if (NULL != WASABI_API_DEVICES &&
|
||
|
S_OK == WASABI_API_DEVICES->DeviceFind(item->name, &device))
|
||
|
{
|
||
|
blockEditor = (FALSE == DeviceCommand_GetEnabled(device, "rename",
|
||
|
DeviceCommandContext_ViewMenu));
|
||
|
device->Release();
|
||
|
}
|
||
|
else
|
||
|
blockEditor = TRUE;
|
||
|
|
||
|
if (FALSE != blockEditor)
|
||
|
return NULL;
|
||
|
|
||
|
if (FALSE == ListWidget_GetItemMetrics(style, &metrics))
|
||
|
return NULL;
|
||
|
|
||
|
if (FALSE == ListWidget_GetItemTitleRect(self, item, &metrics, FALSE, &rect))
|
||
|
return NULL;
|
||
|
|
||
|
if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))
|
||
|
OffsetRect(&rect, origin.x, origin.y);
|
||
|
|
||
|
editorStyleEx = WS_EX_CLIENTEDGE;
|
||
|
editorStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
|
||
|
ES_CENTER | ES_NOHIDESEL | ES_MULTILINE | ES_AUTOVSCROLL;
|
||
|
|
||
|
EmbeddedEditor_AdjustWindowRectEx(&rect, editorStyleEx, editorStyle);
|
||
|
|
||
|
editor = CreateWindowEx(editorStyleEx, WC_EDIT, item->title, editorStyle,
|
||
|
rect.left, rect.top, 0, 0,
|
||
|
hwnd, NULL, NULL, 0L);
|
||
|
if (NULL == editor)
|
||
|
return NULL;
|
||
|
|
||
|
|
||
|
itemName = AnsiString_Duplicate(item->name);
|
||
|
if (FALSE == EmbeddedEditor_Attach(editor, ListWidget_EndTitleEditCb, itemName))
|
||
|
{
|
||
|
AnsiString_Free(itemName);
|
||
|
DestroyWindow(editor);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
ListWidgetItem_SetTextEdited(item);
|
||
|
|
||
|
EMBEDDEDEDITOR_SET_ANCHOR_POINT(editor, rect.left, rect.top);
|
||
|
EMBEDDEDEDITOR_SET_MAX_SIZE(editor, RECTWIDTH(rect), 0);
|
||
|
|
||
|
|
||
|
SendMessage(editor, WM_SETFONT, (WPARAM)WIDGETSTYLE_TEXT_FONT(style), 0L);
|
||
|
|
||
|
ListWidget_UpdateTitleEditorColors(editor, style);
|
||
|
|
||
|
SendMessage(editor, EM_SETSEL, 0, -1);
|
||
|
ShowWindow(editor, SW_SHOW);
|
||
|
SetFocus(editor);
|
||
|
|
||
|
return editor;
|
||
|
}
|
||
|
|
||
|
|
||
|
int
|
||
|
ListWidget_CompareItemPos(ListWidget *self, ListWidgetItem *item1, ListWidgetItem *item2)
|
||
|
{
|
||
|
size_t iCategory1, iGroup1, iItem1;
|
||
|
size_t iCategory2, iGroup2, iItem2;
|
||
|
|
||
|
if (FALSE == ListWidget_FindItemPos(self, item1, &iCategory1, &iGroup1, &iItem1) ||
|
||
|
FALSE == ListWidget_FindItemPos(self, item2, &iCategory2, &iGroup2, &iItem2))
|
||
|
{
|
||
|
return _NLSCMPERROR;
|
||
|
}
|
||
|
|
||
|
if (iCategory1 != iCategory2)
|
||
|
return (int)(iCategory1 - iCategory2);
|
||
|
|
||
|
if (iGroup1 != iGroup2)
|
||
|
return (int)(iGroup1 - iGroup2);
|
||
|
|
||
|
return (int)(iItem1 - iItem2);
|
||
|
}
|
||
|
|
||
|
BOOL
|
||
|
ListWidget_GetViewItemPos(HWND hwnd, ListWidgetItem *item, POINT *pt)
|
||
|
{
|
||
|
if (NULL == hwnd ||
|
||
|
NULL == item ||
|
||
|
NULL == pt)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (FALSE == ListWidget_GetViewOrigin(hwnd, pt))
|
||
|
{
|
||
|
pt->x = 0;
|
||
|
pt->y = 0;
|
||
|
}
|
||
|
|
||
|
pt->x = item->rect.left - pt->x;
|
||
|
pt->y = item->rect.top - pt->y;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|