#include "main.h" #include "./listWidgetInternal.h" #include "../nu/AutoWide.h" #include #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; }