listWidgetItem.cpp 67 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854
  1. #include "main.h"
  2. #include "./listWidgetInternal.h"
  3. #include "../nu/AutoWide.h"
  4. #include <strsafe.h>
  5. #define LISTWIDGETITEM_OFFSET_LEFT_DLU 0
  6. #define LISTWIDGETITEM_OFFSET_TOP_DLU 0
  7. #define LISTWIDGETITEM_OFFSET_RIGHT_DLU 0
  8. #define LISTWIDGETITEM_OFFSET_BOTTOM_DLU 2
  9. #define LISTWIDGETITEM_IMAGE_OFFSET_LEFT_DLU 2
  10. #define LISTWIDGETITEM_IMAGE_OFFSET_TOP_DLU 2
  11. #define LISTWIDGETITEM_IMAGE_OFFSET_RIGHT_DLU 2
  12. #define LISTWIDGETITEM_IMAGE_OFFSET_BOTTOM_DLU 2
  13. #define LISTWIDGETITEM_SPACEBAR_OFFSET_DLU 1
  14. #define LISTWIDGETITEM_SPACEBAR_HEIGHT_DLU 8
  15. #define LISTWIDGETITEM_TITLE_OFFSET_DLU 1
  16. #define LISTWIDGETITEM_TITLE_MIN_WIDTH_DLU (8 * 4)
  17. #define LISTWIDGETITEM_TITLE_EDITOR_MARGIN_HORZ_DLU 2
  18. ListWidgetItem*
  19. ListWidget_CreateItemFromDevice(ListWidget *self, ifc_device* device)
  20. {
  21. ListWidgetItem *item;
  22. ifc_deviceactivity *activity;
  23. wchar_t buffer[1024] = {0};
  24. if (NULL == device || NULL == device->GetName())
  25. return NULL;
  26. item = new ListWidgetItem();
  27. if (NULL == item)
  28. return NULL;
  29. item->name = AnsiString_Duplicate(device->GetName());
  30. if (NULL == item->name)
  31. {
  32. delete item;
  33. return NULL;
  34. }
  35. if (SUCCEEDED(device->GetDisplayName(buffer, ARRAYSIZE(buffer))))
  36. item->title = String_Duplicate(buffer);
  37. else
  38. item->title = NULL;
  39. ListWidgetItem_UnsetTextTruncated(item);
  40. SetSize(&item->titleSize, -1, -1);
  41. item->image = NULL;
  42. if (FAILED(device->GetTotalSpace(&item->spaceTotal)))
  43. item->spaceTotal = 0;
  44. if (FAILED(device->GetUsedSpace(&item->spaceUsed)))
  45. item->spaceUsed = 0;
  46. item->connection = NULL;
  47. if (NULL != self)
  48. {
  49. item->connection = ListWidget_FindConnection(self, device->GetConnection());
  50. if (NULL == item->connection)
  51. {
  52. item->connection = ListWidget_CreateConnection(device->GetConnection());
  53. if (NULL != item->connection)
  54. ListWidget_AddConnection(self, item->connection);
  55. }
  56. }
  57. item->activity = NULL;
  58. if (S_OK == device->GetActivity(&activity) && NULL != activity)
  59. {
  60. if (FALSE != activity->GetActive())
  61. {
  62. ListWidget_CreateItemActivity(item);
  63. ListWidget_UpdateItemActivity(item, activity);
  64. }
  65. activity->Release();
  66. }
  67. return item;
  68. }
  69. void
  70. ListWidget_DestroyItem(ListWidgetItem *item)
  71. {
  72. if (NULL == item)
  73. return;
  74. if (NULL != item->image)
  75. DeviceImage_Release(item->image);
  76. ListWidget_DeleteItemActivity(item);
  77. AnsiString_Free(item->name);
  78. String_Free(item->title);
  79. delete item;
  80. }
  81. BOOL
  82. ListWidget_SetItemTitle(ListWidgetItem *item, const wchar_t *title)
  83. {
  84. if (NULL == item)
  85. return FALSE;
  86. String_Free(item->title);
  87. SetSize(&item->titleSize, -1, -1);
  88. ListWidgetItem_UnsetTextTruncated(item);
  89. item->title = String_Duplicate(title);
  90. if (NULL != title && NULL == item->title)
  91. return FALSE;
  92. return TRUE;
  93. }
  94. size_t
  95. ListWidget_RemoveItem(ListWidget *self, HWND hwnd, const char *name)
  96. {
  97. size_t iCategory, iItem;
  98. ListWidgetCategory *category;
  99. ListWidgetGroup *group;
  100. ListWidgetItem *item;
  101. size_t removed;
  102. RECT rect;
  103. POINT origin;
  104. ListWidgetItem *selectItem;
  105. removed = 0;
  106. selectItem = NULL;
  107. if (NULL == self || NULL == name)
  108. return 0;
  109. if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))
  110. ZeroMemory(&origin, sizeof(POINT));
  111. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  112. {
  113. category = self->categories[iCategory];
  114. BOOL categoryModified = FALSE;
  115. size_t iGroup = category->groups.size();
  116. while(iGroup--)
  117. {
  118. group = category->groups[iGroup];
  119. iItem = group->items.size();
  120. while(iItem--)
  121. {
  122. item = group->items[iItem];
  123. if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, item->name, -1, name, -1))
  124. {
  125. removed++;
  126. categoryModified = TRUE;
  127. if (NULL != item->activity)
  128. ListWidget_UnregisterActiveItem(self, hwnd, item);
  129. if (self->selectedItem == item)
  130. {
  131. self->selectedItem = NULL;
  132. if (NULL != self->activeMenu)
  133. EndMenu();
  134. ListWidget_UpdateSelectionStatus(self, hwnd, FALSE);
  135. selectItem = ListWidget_GetNextGroupItem(self, group, item);
  136. if (NULL == selectItem)
  137. {
  138. selectItem = ListWidget_GetPreviousGroupItem(self, group, item);
  139. if (NULL == selectItem)
  140. {
  141. selectItem = ListWidget_GetNextCategoryItem(self, category, item);
  142. if (NULL == selectItem)
  143. selectItem = ListWidget_GetPreviousCategoryItem(self, category, item);
  144. }
  145. }
  146. }
  147. if (self->hoveredItem == item)
  148. self->hoveredItem = NULL;
  149. group->items.erase(group->items.begin() + iItem);
  150. ListWidget_DestroyItem(item);
  151. if (0 == group->items.size())
  152. {
  153. category->groups.erase(category->groups.begin() + iGroup);
  154. ListWidget_DestroyGroup(group);
  155. break;
  156. }
  157. }
  158. }
  159. }
  160. if (FALSE != categoryModified)
  161. {
  162. ListWidget_ResetCategoryCounter(category);
  163. if (FALSE == category->collapsed)
  164. {
  165. ListWidget_UpdateLayout(hwnd, ListWidgetLayout_UpdateNow | ListWidgetLayout_KeepStable);
  166. }
  167. else
  168. {
  169. CopyRect(&rect, &category->rect);
  170. OffsetRect(&rect, origin.x, origin.y);
  171. InvalidateRect(hwnd, &rect, FALSE);
  172. }
  173. }
  174. }
  175. if (0 != removed && NULL != selectItem)
  176. ListWidget_SelectItem(self, hwnd, selectItem, FALSE);
  177. return removed;
  178. }
  179. BOOL
  180. ListWidget_GetItemMetrics(WidgetStyle *style, ListWidgetItemMetric *metrics)
  181. {
  182. if (NULL == metrics || NULL == style)
  183. return FALSE;
  184. WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(metrics->offsetLeft, style, LISTWIDGETITEM_OFFSET_LEFT_DLU, 1);
  185. WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->offsetTop, style, LISTWIDGETITEM_OFFSET_TOP_DLU, 1);
  186. WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(metrics->offsetRight, style, LISTWIDGETITEM_OFFSET_RIGHT_DLU, 1);
  187. WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->offsetBottom, style, LISTWIDGETITEM_OFFSET_BOTTOM_DLU, 1);
  188. WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(metrics->imageOffsetLeft, style, LISTWIDGETITEM_IMAGE_OFFSET_LEFT_DLU, 2);
  189. WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->imageOffsetTop, style, LISTWIDGETITEM_IMAGE_OFFSET_TOP_DLU, 2);
  190. WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(metrics->imageOffsetRight, style, LISTWIDGETITEM_IMAGE_OFFSET_RIGHT_DLU, 2);
  191. WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->imageOffsetBottom, style, LISTWIDGETITEM_IMAGE_OFFSET_BOTTOM_DLU, 2);
  192. WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->spacebarOffsetTop, style, LISTWIDGETITEM_SPACEBAR_OFFSET_DLU, 1);
  193. WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->spacebarHeight, style, LISTWIDGETITEM_SPACEBAR_HEIGHT_DLU, 2);
  194. metrics->spacebarHeight = 14;
  195. WIDGETSTYLE_DLU_TO_VERT_PX_MIN(metrics->titleOffsetTop, style, LISTWIDGETITEM_TITLE_OFFSET_DLU, 1);
  196. WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(metrics->titleMinWidth, style, LISTWIDGETITEM_TITLE_MIN_WIDTH_DLU, 32);
  197. return TRUE;
  198. }
  199. static HBITMAP
  200. ListWidget_GetDeviceBitmap(ifc_device *device, int width, int height,
  201. DeviceImageFlags flags, DeviceImage **imageOut)
  202. {
  203. HBITMAP bitmap;
  204. wchar_t path[MAX_PATH*2] = {0};
  205. const wchar_t *defaultImage;
  206. DeviceImage *image;
  207. DeviceImageCache *imageCache;
  208. ifc_devicetype *type;
  209. if (NULL == device)
  210. return NULL;
  211. imageCache = Plugin_GetImageCache();
  212. if (NULL == imageCache)
  213. return NULL;
  214. if (SUCCEEDED(device->GetIcon(path, ARRAYSIZE(path), width, height)))
  215. {
  216. image = DeviceImageCache_GetImage(imageCache, path, width, height, NULL, NULL);
  217. if (NULL != image)
  218. {
  219. bitmap = DeviceImage_GetBitmap(image, flags);
  220. if (NULL != bitmap)
  221. {
  222. if (NULL != imageOut)
  223. *imageOut = image;
  224. else
  225. DeviceImage_Release(image);
  226. return bitmap;
  227. }
  228. }
  229. }
  230. if (NULL != WASABI_API_DEVICES &&
  231. S_OK == WASABI_API_DEVICES->TypeFind(device->GetType(), &type))
  232. {
  233. if (SUCCEEDED(type->GetIcon(path, ARRAYSIZE(path), width, height)))
  234. {
  235. image = DeviceImageCache_GetImage(imageCache, path, width, height, NULL, NULL);
  236. if (NULL != image)
  237. {
  238. bitmap = DeviceImage_GetBitmap(image, flags);
  239. if (NULL != bitmap)
  240. {
  241. if (NULL != imageOut)
  242. *imageOut = image;
  243. else
  244. DeviceImage_Release(image);
  245. type->Release();
  246. return bitmap;
  247. }
  248. }
  249. }
  250. type->Release();
  251. }
  252. defaultImage = Plugin_GetDefaultDeviceImage(width, height);
  253. if (NULL != defaultImage)
  254. {
  255. image = DeviceImageCache_GetImage(imageCache, defaultImage, width, height, NULL, NULL);
  256. if (NULL != image)
  257. {
  258. bitmap = DeviceImage_GetBitmap(image, flags);
  259. if (NULL != bitmap)
  260. {
  261. if (NULL != imageOut)
  262. *imageOut = image;
  263. else
  264. DeviceImage_Release(image);
  265. return bitmap;
  266. }
  267. }
  268. }
  269. return NULL;
  270. }
  271. HBITMAP
  272. ListWidget_GetItemImage(ListWidget *self, WidgetStyle *style, ListWidgetItem *item)
  273. {
  274. HBITMAP bitmap;
  275. if (NULL == item)
  276. return NULL;
  277. if (NULL != item->image)
  278. return DeviceImage_GetBitmap(item->image, DeviceImage_Normal);
  279. if (NULL == self || NULL == style)
  280. return NULL;
  281. ifc_device *device;
  282. if (NULL == WASABI_API_DEVICES ||
  283. S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
  284. {
  285. return NULL;
  286. }
  287. bitmap = ListWidget_GetDeviceBitmap(device, self->imageSize.cx, self->imageSize.cy,
  288. DeviceImage_Normal, &item->image);
  289. device->Release();
  290. return bitmap;
  291. }
  292. BOOL
  293. ListWidget_CalculateItemBaseSize(ListWidget *self, WidgetStyle *style, SIZE *baseSize, long *itemTextWidth)
  294. {
  295. ListWidgetItemMetric metrics;
  296. if (NULL == baseSize)
  297. return FALSE;
  298. if (FALSE == ListWidget_GetItemMetrics(style, &metrics))
  299. ZeroMemory(&metrics, sizeof(metrics));
  300. baseSize->cx = self->imageSize.cx;
  301. baseSize->cy = self->imageSize.cy;
  302. baseSize->cx += metrics.imageOffsetLeft + metrics.imageOffsetRight;
  303. if (baseSize->cx < metrics.titleMinWidth)
  304. baseSize->cx = metrics.titleMinWidth;
  305. if (FALSE != itemTextWidth)
  306. *itemTextWidth = baseSize->cx;
  307. baseSize->cx += metrics.offsetLeft + metrics.offsetRight;
  308. baseSize->cy += metrics.offsetTop + metrics.offsetBottom +
  309. metrics.imageOffsetTop + metrics.imageOffsetBottom +
  310. metrics.spacebarHeight + metrics.spacebarOffsetTop +
  311. metrics.titleOffsetTop;
  312. if (FALSE != itemTextWidth)
  313. *itemTextWidth = baseSize->cx - (metrics.offsetLeft + metrics.offsetRight);
  314. return TRUE;
  315. }
  316. ListWidgetItem *
  317. ListWidget_GetItemFromPointEx(ListWidget *self, POINT point,
  318. ListWidgetCategory **categoryOut, ListWidgetGroup **groupOut)
  319. {
  320. size_t iCategory, iGroup, iItem;
  321. ListWidgetCategory *category;
  322. ListWidgetGroup *group;
  323. ListWidgetItem *item;
  324. if (NULL == self)
  325. return NULL;
  326. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  327. {
  328. category = self->categories[iCategory];
  329. if (FALSE == category->collapsed)
  330. {
  331. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  332. {
  333. group = category->groups[iGroup];
  334. for(iItem = 0; iItem < group->items.size(); iItem++)
  335. {
  336. item = group->items[iItem];
  337. if (FALSE != PtInRect(&item->rect, point))
  338. {
  339. if (NULL != categoryOut)
  340. *categoryOut = category;
  341. if (NULL != groupOut)
  342. *groupOut = group;
  343. return item;
  344. }
  345. }
  346. }
  347. }
  348. }
  349. if (NULL != categoryOut)
  350. *categoryOut = NULL;
  351. if (NULL != groupOut)
  352. *groupOut = NULL;
  353. return NULL;
  354. }
  355. ListWidgetItem *
  356. ListWidget_GetItemFromPoint(ListWidget *self, POINT point)
  357. {
  358. return ListWidget_GetItemFromPointEx(self, point, NULL, NULL);
  359. }
  360. ListWidgetItem *
  361. ListWidget_GetFirstItem(ListWidget *self)
  362. {
  363. size_t iCategory, iGroup;
  364. ListWidgetCategory *category;
  365. ListWidgetGroup *group;
  366. if (NULL == self)
  367. return NULL;
  368. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  369. {
  370. category = self->categories[iCategory];
  371. if (FALSE == category->collapsed)
  372. {
  373. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  374. {
  375. group = category->groups[iGroup];
  376. if (group->items.size() > 0)
  377. return group->items[0];
  378. }
  379. }
  380. }
  381. return NULL;
  382. }
  383. ListWidgetItem *
  384. ListWidget_GetLastItem(ListWidget *self)
  385. {
  386. size_t iCategory, iGroup, iItem;
  387. ListWidgetCategory *category;
  388. ListWidgetGroup *group;
  389. if (NULL == self)
  390. return NULL;
  391. iCategory = self->categories.size();
  392. while(iCategory--)
  393. {
  394. category = self->categories[iCategory];
  395. if (FALSE == category->collapsed)
  396. {
  397. iGroup = category->groups.size();
  398. while(iGroup--)
  399. {
  400. group = category->groups[iGroup];
  401. iItem = group->items.size();
  402. if (iItem > 0)
  403. return group->items[iItem - 1];
  404. }
  405. }
  406. }
  407. return NULL;
  408. }
  409. ListWidgetItem *
  410. ListWidget_GetNextItem(ListWidget *self, ListWidgetItem *baseItem)
  411. {
  412. size_t iCategory, iGroup, iItem;
  413. ListWidgetCategory *category;
  414. ListWidgetGroup *group;
  415. ListWidgetItem *item;
  416. BOOL returnNext;
  417. if (NULL == self || NULL == baseItem)
  418. return NULL;
  419. returnNext = FALSE;
  420. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  421. {
  422. category = self->categories[iCategory];
  423. if (FALSE == category->collapsed)
  424. {
  425. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  426. {
  427. group = category->groups[iGroup];
  428. for(iItem = 0; iItem < group->items.size(); iItem++)
  429. {
  430. item = group->items[iItem];
  431. if (item == baseItem)
  432. returnNext = TRUE;
  433. else if (FALSE != returnNext)
  434. return item;
  435. }
  436. }
  437. }
  438. }
  439. return NULL;
  440. }
  441. ListWidgetItem *
  442. ListWidget_GetPreviousItem(ListWidget *self, ListWidgetItem *baseItem)
  443. {
  444. size_t iCategory, iGroup, iItem;
  445. ListWidgetCategory *category;
  446. ListWidgetGroup *group;
  447. ListWidgetItem *item;
  448. BOOL returnPrevious;
  449. if (NULL == self || NULL == baseItem)
  450. return NULL;
  451. returnPrevious = FALSE;
  452. iCategory = self->categories.size();
  453. while(iCategory--)
  454. {
  455. category = self->categories[iCategory];
  456. if (FALSE == category->collapsed)
  457. {
  458. iGroup = category->groups.size();
  459. while(iGroup--)
  460. {
  461. group = category->groups[iGroup];
  462. iItem = group->items.size();
  463. while(iItem--)
  464. {
  465. item = group->items[iItem];
  466. if (item == baseItem)
  467. returnPrevious = TRUE;
  468. else if (FALSE != returnPrevious)
  469. return item;
  470. }
  471. }
  472. }
  473. }
  474. return NULL;
  475. }
  476. ListWidgetItem *
  477. ListWidget_GetNextCategoryItem(ListWidget *self, ListWidgetCategory *category, ListWidgetItem *baseItem)
  478. {
  479. size_t iGroup, iItem;
  480. ListWidgetGroup *group;
  481. ListWidgetItem *item;
  482. BOOL returnNext;
  483. if (NULL == self || NULL == baseItem ||
  484. NULL == category || FALSE != category->collapsed)
  485. {
  486. return NULL;
  487. }
  488. returnNext = FALSE;
  489. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  490. {
  491. group = category->groups[iGroup];
  492. for(iItem = 0; iItem < group->items.size(); iItem++)
  493. {
  494. item = group->items[iItem];
  495. if (item == baseItem)
  496. returnNext = TRUE;
  497. else if (FALSE != returnNext)
  498. return item;
  499. }
  500. }
  501. return NULL;
  502. }
  503. ListWidgetItem *
  504. ListWidget_GetPreviousCategoryItem(ListWidget *self, ListWidgetCategory *category, ListWidgetItem *baseItem)
  505. {
  506. if (NULL == self || NULL == baseItem ||
  507. NULL == category || FALSE != category->collapsed)
  508. {
  509. return NULL;
  510. }
  511. BOOL returnPrevious = FALSE;
  512. size_t iGroup = category->groups.size();
  513. while(iGroup--)
  514. {
  515. ListWidgetGroup *group = category->groups[iGroup];
  516. size_t iItem = group->items.size();
  517. while(iItem--)
  518. {
  519. ListWidgetItem *item = group->items[iItem];
  520. if (item == baseItem)
  521. returnPrevious = TRUE;
  522. else if (FALSE != returnPrevious)
  523. return item;
  524. }
  525. }
  526. return NULL;
  527. }
  528. ListWidgetItem *
  529. ListWidget_GetNextGroupItem(ListWidget *self, ListWidgetGroup *group, ListWidgetItem *baseItem)
  530. {
  531. if (NULL == self || NULL == baseItem || NULL == group)
  532. return NULL;
  533. BOOL returnNext = FALSE;
  534. for(size_t iItem = 0; iItem < group->items.size(); iItem++)
  535. {
  536. ListWidgetItem *item = group->items[iItem];
  537. if (item == baseItem)
  538. returnNext = TRUE;
  539. else if (FALSE != returnNext)
  540. return item;
  541. }
  542. return NULL;
  543. }
  544. ListWidgetItem *
  545. ListWidget_GetPreviousGroupItem(ListWidget *self, ListWidgetGroup *group, ListWidgetItem *baseItem)
  546. {
  547. if (NULL == self || NULL == baseItem || NULL == group)
  548. return NULL;
  549. BOOL returnPrevious = FALSE;
  550. size_t iItem = group->items.size();
  551. while(iItem--)
  552. {
  553. ListWidgetItem *item = group->items[iItem];
  554. if (item == baseItem)
  555. returnPrevious = TRUE;
  556. else if (FALSE != returnPrevious)
  557. return item;
  558. }
  559. return NULL;
  560. }
  561. ListWidgetItem *
  562. ListWidget_GetNextLineItem(ListWidget *self, ListWidgetItem *baseItem)
  563. {
  564. size_t iCategory, iGroup, iItem;
  565. ListWidgetCategory *category;
  566. ListWidgetGroup *group;
  567. ListWidgetItem *item;
  568. size_t itemLinePos, itemsPerLine, targetLinePos;
  569. if (NULL == self || NULL == baseItem)
  570. return NULL;
  571. itemsPerLine = MAX(self->itemsPerLine, 1);
  572. targetLinePos = -1;
  573. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  574. {
  575. category = self->categories[iCategory];
  576. if (FALSE == category->collapsed)
  577. {
  578. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  579. {
  580. group = category->groups[iGroup];
  581. if (-1 == targetLinePos)
  582. {
  583. itemLinePos = 0;
  584. for(iItem = 0; iItem < group->items.size(); iItem++, itemLinePos++)
  585. {
  586. if (itemLinePos == itemsPerLine)
  587. itemLinePos = 0;
  588. item = group->items[iItem];
  589. if (item == baseItem)
  590. {
  591. size_t test;
  592. targetLinePos = itemLinePos;
  593. test = iItem + (itemsPerLine - itemLinePos);
  594. if (test < group->items.size())
  595. {
  596. test += targetLinePos;
  597. if (test >= group->items.size())
  598. test = group->items.size() - 1;
  599. return group->items[test];
  600. }
  601. break;
  602. }
  603. }
  604. }
  605. else if (group->items.size() > 0)
  606. {
  607. size_t test;
  608. if (targetLinePos < group->items.size())
  609. test = targetLinePos;
  610. else
  611. test = group->items.size() - 1;
  612. return group->items[test];
  613. }
  614. }
  615. }
  616. }
  617. return NULL;
  618. }
  619. ListWidgetItem *
  620. ListWidget_GetPreviousLineItem(ListWidget *self, ListWidgetItem *baseItem)
  621. {
  622. size_t iCategory, iGroup, iItem;
  623. ListWidgetCategory *category;
  624. ListWidgetGroup *group;
  625. ListWidgetItem *item;
  626. size_t itemLinePos, itemsPerLine, targetLinePos;
  627. if (NULL == self || NULL == baseItem)
  628. return NULL;
  629. itemsPerLine = MAX(self->itemsPerLine, 1);
  630. targetLinePos = -1;
  631. iCategory = self->categories.size();
  632. while(iCategory--)
  633. {
  634. category = self->categories[iCategory];
  635. if (FALSE == category->collapsed)
  636. {
  637. iGroup = category->groups.size();
  638. while(iGroup--)
  639. {
  640. group = category->groups[iGroup];
  641. if (-1 == targetLinePos)
  642. {
  643. itemLinePos = 0;
  644. for(iItem = 0; iItem < group->items.size(); iItem++, itemLinePos++)
  645. {
  646. if (itemLinePos == itemsPerLine)
  647. itemLinePos = 0;
  648. item = group->items[iItem];
  649. if (item == baseItem)
  650. {
  651. targetLinePos = itemLinePos;
  652. if (iItem >= (itemLinePos + 1))
  653. {
  654. size_t test = iItem - (itemLinePos + 1);
  655. if (test >= (itemsPerLine - (itemLinePos + 1)))
  656. test -= itemsPerLine - (itemLinePos + 1);
  657. return group->items[test];
  658. }
  659. break;
  660. }
  661. }
  662. }
  663. else if (group->items.size() > 0)
  664. {
  665. size_t test = group->items.size();
  666. test = test/itemsPerLine + ((0 != test%itemsPerLine) ? 0 : - 1);
  667. test = test * itemsPerLine;
  668. test += targetLinePos;
  669. if (test >= group->items.size())
  670. test = group->items.size() - 1;
  671. return group->items[test];
  672. }
  673. }
  674. }
  675. }
  676. return NULL;
  677. }
  678. static ListWidgetItem *
  679. ListWidget_FindLastVisibleLine(ListWidget *self, long viewBottom)
  680. {
  681. size_t iCategory, iGroup, iItem;
  682. ListWidgetCategory *category;
  683. ListWidgetGroup *group;
  684. ListWidgetItem *item;
  685. ListWidgetItem *lineItem;
  686. lineItem = NULL;
  687. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  688. {
  689. category = self->categories[iCategory];
  690. if (FALSE == category->collapsed)
  691. {
  692. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  693. {
  694. group = category->groups[iGroup];
  695. for(iItem = 0; iItem < group->items.size(); iItem++)
  696. {
  697. item = group->items[iItem];
  698. if (item->rect.top < viewBottom)
  699. {
  700. if (NULL == lineItem ||
  701. item->rect.top != lineItem->rect.top)
  702. {
  703. if (item->rect.bottom <= viewBottom)
  704. lineItem = item;
  705. else
  706. return (NULL != lineItem) ? lineItem : item;
  707. }
  708. }
  709. else
  710. return lineItem;
  711. }
  712. }
  713. }
  714. }
  715. return lineItem;
  716. }
  717. static ListWidgetItem *
  718. ListWidget_FindFirstVisibleLine(ListWidget *self, long viewTop)
  719. {
  720. size_t iCategory, iGroup, iItem;
  721. ListWidgetCategory *category;
  722. ListWidgetGroup *group;
  723. ListWidgetItem *item;
  724. ListWidgetItem *lineItem;
  725. lineItem = NULL;
  726. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  727. {
  728. category = self->categories[iCategory];
  729. if (FALSE == category->collapsed)
  730. {
  731. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  732. {
  733. group = category->groups[iGroup];
  734. for(iItem = 0; iItem < group->items.size(); iItem++)
  735. {
  736. item = group->items[iItem];
  737. if (NULL == lineItem ||
  738. item->rect.top != lineItem->rect.top)
  739. {
  740. lineItem = item;
  741. if (item->rect.top >= viewTop)
  742. return lineItem;
  743. }
  744. }
  745. }
  746. }
  747. }
  748. return lineItem;
  749. }
  750. static ListWidgetItem *
  751. ListWidget_FindNextLine(ListWidget *self, ListWidgetItem *baseItem)
  752. {
  753. size_t iCategory, iGroup, iItem;
  754. ListWidgetCategory *category;
  755. ListWidgetGroup *group;
  756. ListWidgetItem *item;
  757. BOOL foundItem;
  758. foundItem = FALSE;
  759. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  760. {
  761. category = self->categories[iCategory];
  762. if (FALSE == category->collapsed)
  763. {
  764. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  765. {
  766. group = category->groups[iGroup];
  767. for(iItem = 0; iItem < group->items.size(); iItem++)
  768. {
  769. item = group->items[iItem];
  770. if (item == baseItem)
  771. foundItem = TRUE;
  772. if (FALSE != foundItem &&
  773. item->rect.top != baseItem->rect.top)
  774. {
  775. return item;
  776. }
  777. }
  778. }
  779. }
  780. }
  781. return NULL;
  782. }
  783. static ListWidgetItem *
  784. ListWidget_FindPreviousLine(ListWidget *self, ListWidgetItem *baseItem)
  785. {
  786. size_t iCategory, iGroup, iItem;
  787. ListWidgetCategory *category;
  788. ListWidgetGroup *group;
  789. ListWidgetItem *item;
  790. BOOL foundItem;
  791. foundItem = FALSE;
  792. iCategory = self->categories.size();
  793. while(iCategory--)
  794. {
  795. category = self->categories[iCategory];
  796. if (FALSE == category->collapsed)
  797. {
  798. iGroup = category->groups.size();
  799. while(iGroup--)
  800. {
  801. group = category->groups[iGroup];
  802. iItem = group->items.size();
  803. while(iItem--)
  804. {
  805. item = group->items[iItem];
  806. if (item == baseItem)
  807. foundItem = TRUE;
  808. if (FALSE != foundItem &&
  809. item->rect.top != baseItem->rect.top)
  810. {
  811. return item;
  812. }
  813. }
  814. }
  815. }
  816. }
  817. return NULL;
  818. }
  819. static ListWidgetItem *
  820. ListWidget_FindLineItemAtPos(ListWidget *self, ListWidgetItem *beginLine, ListWidgetItem *linePosition)
  821. {
  822. size_t iCategory, iGroup, iItem;
  823. ListWidgetCategory *category;
  824. ListWidgetGroup *group;
  825. ListWidgetItem *item;
  826. BOOL foundLine;
  827. foundLine = FALSE;
  828. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  829. {
  830. category = self->categories[iCategory];
  831. if (FALSE == category->collapsed)
  832. {
  833. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  834. {
  835. group = category->groups[iGroup];
  836. for(iItem = 0; iItem < group->items.size(); iItem++)
  837. {
  838. item = group->items[iItem];
  839. if (item == beginLine)
  840. foundLine = TRUE;
  841. if (FALSE != foundLine)
  842. {
  843. if (beginLine->rect.top == linePosition->rect.top)
  844. {
  845. if (item->rect.top != beginLine->rect.top)
  846. {
  847. return (iItem > 0) ? group->items[iItem - 1] : beginLine;
  848. }
  849. }
  850. else
  851. {
  852. if (item->rect.left == linePosition->rect.left)
  853. return item;
  854. }
  855. }
  856. }
  857. if (FALSE != foundLine)
  858. {
  859. if (group->items.size() > 0)
  860. return group->items[group->items.size() - 1];
  861. return NULL;
  862. }
  863. }
  864. }
  865. }
  866. return NULL;
  867. }
  868. ListWidgetItem *
  869. ListWidget_GetNextPageItem(ListWidget *self, HWND hwnd, ListWidgetItem *baseItem)
  870. {
  871. ListWidgetItem *lineItem;
  872. RECT rect;
  873. POINT origin;
  874. long viewBottom;
  875. if (NULL == self || NULL == baseItem)
  876. return NULL;
  877. if (FALSE == GetClientRect(hwnd, &rect))
  878. return NULL;
  879. if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))
  880. OffsetRect(&rect, -origin.x, -origin.y);
  881. if (baseItem->rect.bottom < rect.top)
  882. viewBottom = baseItem->rect.top + RECTHEIGHT(rect);
  883. else
  884. viewBottom = rect.bottom;
  885. lineItem = ListWidget_FindLastVisibleLine(self, viewBottom);
  886. if (NULL == lineItem)
  887. return NULL;
  888. if (lineItem->rect.top <= baseItem->rect.top)
  889. {
  890. viewBottom = baseItem->rect.top + RECTHEIGHT(rect);
  891. lineItem = ListWidget_FindLastVisibleLine(self, viewBottom);
  892. if (NULL == lineItem)
  893. return NULL;
  894. if (lineItem->rect.top <= baseItem->rect.top)
  895. {
  896. lineItem = ListWidget_FindNextLine(self, baseItem);
  897. if (NULL == lineItem)
  898. return NULL;
  899. }
  900. }
  901. return ListWidget_FindLineItemAtPos(self, lineItem, baseItem);
  902. }
  903. ListWidgetItem *
  904. ListWidget_GetPreviousPageItem(ListWidget *self, HWND hwnd, ListWidgetItem *baseItem)
  905. {
  906. ListWidgetItem *lineItem;
  907. RECT rect;
  908. POINT origin;
  909. long viewTop;
  910. if (NULL == self || NULL == baseItem)
  911. return NULL;
  912. if (FALSE == GetClientRect(hwnd, &rect))
  913. return NULL;
  914. if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))
  915. OffsetRect(&rect, -origin.x, -origin.y);
  916. if (baseItem->rect.top > rect.bottom)
  917. viewTop = baseItem->rect.bottom - RECTHEIGHT(rect);
  918. else
  919. viewTop = rect.top;
  920. lineItem = ListWidget_FindFirstVisibleLine(self, viewTop);
  921. if (NULL == lineItem)
  922. return NULL;
  923. if (lineItem->rect.top >= baseItem->rect.top)
  924. {
  925. viewTop = baseItem->rect.bottom - RECTHEIGHT(rect);
  926. lineItem = ListWidget_FindFirstVisibleLine(self, viewTop);
  927. if (NULL == lineItem)
  928. return NULL;
  929. if (lineItem->rect.top >= baseItem->rect.top)
  930. {
  931. lineItem = ListWidget_FindPreviousLine(self, baseItem);
  932. if (NULL == lineItem)
  933. return NULL;
  934. }
  935. }
  936. return ListWidget_FindLineItemAtPos(self, lineItem, baseItem);
  937. }
  938. BOOL
  939. ListWidget_EnsureItemVisisble(ListWidget *self, HWND hwnd, ListWidgetItem *item, ListWidgetVisibleFlags flags)
  940. {
  941. RECT rect;
  942. POINT pt;
  943. int dx, dy;
  944. if (NULL == self || NULL == item || NULL == hwnd)
  945. return FALSE;
  946. if (FALSE == GetClientRect(hwnd, &rect))
  947. return FALSE;
  948. if (FALSE != ListWidget_GetViewOrigin(hwnd, &pt))
  949. OffsetRect(&rect, -pt.x, -pt.y);
  950. if (0 == (VISIBLE_ALIGN_ALWAYS & flags))
  951. {
  952. if (item->rect.left >= rect.left &&
  953. item->rect.right <= rect.right &&
  954. item->rect.top >= rect.top &&
  955. item->rect.bottom <= rect.bottom)
  956. {
  957. return FALSE;
  958. }
  959. }
  960. if (0 != (VISIBLE_PARTIAL_OK & flags))
  961. {
  962. if (item->rect.left < rect.right &&
  963. item->rect.right > rect.left &&
  964. item->rect.top < rect.bottom &&
  965. item->rect.bottom > rect.top)
  966. {
  967. return FALSE;
  968. }
  969. }
  970. if (item->rect.right > rect.right)
  971. dx = item->rect.right - rect.right;
  972. else
  973. dx = 0;
  974. if ((item->rect.left - dx) < rect.left)
  975. dx = item->rect.left - rect.left;
  976. dy = 0;
  977. if (0 != (VISIBLE_ALIGN_TOP & flags))
  978. {
  979. dy = item->rect.bottom - rect.bottom;
  980. }
  981. else if (0 != (VISIBLE_ALIGN_BOTTOM & flags))
  982. {
  983. SCROLLINFO scrollInfo;
  984. scrollInfo.cbSize = sizeof(scrollInfo);
  985. scrollInfo.fMask = SIF_RANGE | SIF_PAGE;
  986. if (FALSE != GetScrollInfo(hwnd, SB_VERT, &scrollInfo))
  987. {
  988. dy = scrollInfo.nMax - rect.bottom;
  989. }
  990. }
  991. if ((item->rect.bottom - dy) > rect.bottom)
  992. dy = item->rect.bottom - rect.bottom;
  993. if ((item->rect.top - dy) < rect.top)
  994. dy = item->rect.top - rect.top;
  995. if (0 == dx && 0 == dy)
  996. return FALSE;
  997. if (FALSE == WIDGET_SCROLL(hwnd, dx, dy, TRUE))
  998. return FALSE;
  999. ListWidget_UpdateHover(self, hwnd);
  1000. return TRUE;
  1001. }
  1002. BOOL
  1003. ListWidget_AddItem(ListWidgetGroup *group, ListWidgetItem *item)
  1004. {
  1005. if (NULL == group || NULL == item)
  1006. return FALSE;
  1007. group->items.push_back(item);
  1008. return TRUE;
  1009. }
  1010. ListWidgetItem *
  1011. ListWidget_FindGroupItemEx(ListWidgetGroup *group, const char *name, size_t max)
  1012. {
  1013. size_t index, count;
  1014. if (NULL == group || NULL == name)
  1015. return NULL;
  1016. count = group->items.size();
  1017. if (max < count)
  1018. count = max;
  1019. for(index = 0; index < count; index++)
  1020. {
  1021. ListWidgetItem *item = group->items[index];
  1022. if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, name, -1, item->name, -1))
  1023. return item;
  1024. }
  1025. return NULL;
  1026. }
  1027. ListWidgetItem *
  1028. ListWidget_FindGroupItem(ListWidgetGroup *group, const char *name)
  1029. {
  1030. return ListWidget_FindGroupItemEx(group, name, -1);
  1031. }
  1032. ListWidgetGroup *
  1033. ListWidget_GetItemOwner(ListWidget *self, ListWidgetItem *baseItem, ListWidgetCategory **categoryOut)
  1034. {
  1035. size_t iCategory, iGroup, iItem;
  1036. ListWidgetCategory *category;
  1037. ListWidgetGroup *group;
  1038. ListWidgetItem *item;
  1039. if (NULL == self || NULL == baseItem)
  1040. return NULL;
  1041. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  1042. {
  1043. category = self->categories[iCategory];
  1044. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  1045. {
  1046. group = category->groups[iGroup];
  1047. for(iItem = 0; iItem < group->items.size(); iItem++)
  1048. {
  1049. item = group->items[iItem];
  1050. if (item == baseItem)
  1051. {
  1052. if (NULL != categoryOut)
  1053. *categoryOut = category;
  1054. return group;
  1055. }
  1056. }
  1057. }
  1058. }
  1059. if (NULL != categoryOut)
  1060. *categoryOut = NULL;
  1061. return NULL;
  1062. }
  1063. ListWidgetItem *
  1064. ListWidget_FindItem(ListWidget *self, const char *name,
  1065. ListWidgetCategory **categoryOut,
  1066. ListWidgetGroup **groupOut)
  1067. {
  1068. size_t iCategory, iGroup, iItem;
  1069. ListWidgetCategory *category;
  1070. ListWidgetGroup *group;
  1071. ListWidgetItem *item;
  1072. if (NULL == self || NULL == name)
  1073. return NULL;
  1074. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  1075. {
  1076. category = self->categories[iCategory];
  1077. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  1078. {
  1079. group = category->groups[iGroup];
  1080. for(iItem = 0; iItem < group->items.size(); iItem++)
  1081. {
  1082. item = group->items[iItem];
  1083. if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, name, -1, item->name, -1))
  1084. {
  1085. if (NULL != categoryOut)
  1086. *categoryOut = category;
  1087. if (NULL != groupOut)
  1088. *groupOut = group;
  1089. return item;
  1090. }
  1091. }
  1092. }
  1093. }
  1094. return NULL;
  1095. }
  1096. BOOL
  1097. ListWidget_FindItemPos(ListWidget *self, ListWidgetItem *item,
  1098. size_t *categoryOut, size_t *groupOut, size_t *itemOut)
  1099. {
  1100. size_t iCategory, iGroup, iItem;
  1101. ListWidgetCategory *category;
  1102. ListWidgetGroup *group;
  1103. if (NULL == self || NULL == item)
  1104. return FALSE;
  1105. for (iCategory = 0; iCategory < self->categories.size(); iCategory++)
  1106. {
  1107. category = self->categories[iCategory];
  1108. for(iGroup = 0; iGroup < category->groups.size(); iGroup++)
  1109. {
  1110. group = category->groups[iGroup];
  1111. for(iItem = 0; iItem < group->items.size(); iItem++)
  1112. {
  1113. if (item == group->items[iItem])
  1114. {
  1115. if (NULL != categoryOut)
  1116. *categoryOut = iCategory;
  1117. if (NULL != groupOut)
  1118. *groupOut = iGroup;
  1119. if (NULL != itemOut)
  1120. *itemOut = iItem;
  1121. return TRUE;
  1122. }
  1123. }
  1124. }
  1125. }
  1126. return FALSE;
  1127. }
  1128. BOOL
  1129. ListWidget_DisplayItemContextMenu(ListWidget *self, HWND hwnd, ListWidgetItem *item, POINT pt)
  1130. {
  1131. HMENU menu;
  1132. ifc_device *device;
  1133. unsigned int commandId;
  1134. BOOL succeeded;
  1135. char *itemName;
  1136. if (NULL == self || NULL == item)
  1137. return FALSE;
  1138. if (NULL != self->activeMenu)
  1139. return FALSE;
  1140. if (NULL == WASABI_API_DEVICES ||
  1141. S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
  1142. {
  1143. return FALSE;
  1144. }
  1145. menu = CreatePopupMenu();
  1146. if (NULL != menu)
  1147. {
  1148. if (0 == Menu_InsertDeviceItems(menu, 0, 100, device, DeviceCommandContext_ViewMenu))
  1149. {
  1150. DestroyMenu(menu);
  1151. menu = NULL;
  1152. }
  1153. }
  1154. device->Release();
  1155. if (NULL == menu)
  1156. return FALSE;
  1157. succeeded = FALSE;
  1158. self->activeMenu = menu;
  1159. itemName = AnsiString_Duplicate(item->name);
  1160. if (FALSE != ListWidget_RemoveHover(self, hwnd, TRUE))
  1161. UpdateWindow(hwnd);
  1162. commandId = Menu_TrackPopup(Plugin_GetLibraryWindow(), menu,
  1163. TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_VERTICAL | TPM_RETURNCMD,
  1164. pt.x, pt.y, hwnd, NULL);
  1165. self->activeMenu = NULL;
  1166. if (0 != commandId)
  1167. {
  1168. const char *command;
  1169. command = (const char*)Menu_GetItemData(menu, commandId, FALSE);
  1170. succeeded = ListWidget_SendItemCommand(itemName, command, hwnd, 0, TRUE);
  1171. }
  1172. else
  1173. {
  1174. if (ERROR_SUCCESS == GetLastError())
  1175. succeeded = TRUE;
  1176. }
  1177. Menu_FreeItemData(menu, 0, -1);
  1178. AnsiString_Free(itemName);
  1179. if (FALSE != ListWidget_UpdateHover(self, hwnd))
  1180. UpdateWindow(hwnd);
  1181. return succeeded;
  1182. }
  1183. size_t
  1184. ListWidget_GetItemCommands(ListWidgetItem *item, ListWidgetCommand **buffer, size_t bufferMax)
  1185. {
  1186. size_t count;
  1187. ifc_device *device;
  1188. if (NULL == item)
  1189. return 0;
  1190. count = 0;
  1191. if (NULL != WASABI_API_DEVICES &&
  1192. S_OK == WASABI_API_DEVICES->DeviceFind(item->name, &device))
  1193. {
  1194. count = ListWigdet_GetDeviceCommands(buffer, bufferMax, device);
  1195. device->Release();
  1196. }
  1197. return count;
  1198. }
  1199. BOOL
  1200. ListWidget_SendItemCommand(const char *name, const char *command, HWND hostWindow, ULONG_PTR param, BOOL enableIntercept)
  1201. {
  1202. BOOL succeeded;
  1203. ifc_device *device;
  1204. BOOL commandProcessed;
  1205. if (NULL == name ||
  1206. NULL == command ||
  1207. NULL == WASABI_API_DEVICES ||
  1208. S_OK != WASABI_API_DEVICES->DeviceFind(name, &device))
  1209. {
  1210. return FALSE;
  1211. }
  1212. commandProcessed = FALSE;
  1213. succeeded = FALSE;
  1214. if (FALSE != enableIntercept)
  1215. {
  1216. if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, command, -1, "view_open", -1))
  1217. {
  1218. succeeded = Navigation_SelectDevice(device->GetName());
  1219. commandProcessed = succeeded;
  1220. }
  1221. else if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, command, -1, "rename", -1))
  1222. {
  1223. succeeded = Navigation_EditDeviceTitle(device->GetName());
  1224. commandProcessed = succeeded;
  1225. }
  1226. }
  1227. if (FALSE == commandProcessed &&
  1228. SUCCEEDED(device->SendCommand(command, hostWindow, param)))
  1229. {
  1230. succeeded = TRUE;
  1231. }
  1232. device->Release();
  1233. return succeeded;
  1234. }
  1235. BOOL
  1236. ListWidget_CreateItemActivity(ListWidgetItem *item)
  1237. {
  1238. if (NULL == item)
  1239. return FALSE;
  1240. if (NULL == item->activity)
  1241. {
  1242. item->activity = (ListWidgetActivity*)malloc(sizeof(ListWidgetActivity));
  1243. if (NULL == item->activity)
  1244. return FALSE;
  1245. }
  1246. item->activity->step = 0;
  1247. item->activity->cancelable = FALSE;
  1248. item->activity->percent = (unsigned int)-1;
  1249. item->activity->title = NULL;
  1250. SetSizeEmpty(&item->activity->titleSize);
  1251. return TRUE;
  1252. }
  1253. BOOL
  1254. ListWidget_DeleteItemActivity(ListWidgetItem *item)
  1255. {
  1256. if (NULL == item ||
  1257. NULL == item->activity)
  1258. {
  1259. return FALSE;
  1260. }
  1261. String_Free(item->activity->title);
  1262. free(item->activity);
  1263. item->activity = NULL;
  1264. return TRUE;
  1265. }
  1266. ListWidtetActivityChange
  1267. ListWidget_UpdateItemActivity(ListWidgetItem *item, ifc_deviceactivity *activity)
  1268. {
  1269. ListWidgetActivityChange changed;
  1270. BOOL cancelable;
  1271. unsigned int percent;
  1272. wchar_t buffer[512] = {0};
  1273. if (NULL == item || NULL == item->activity || NULL == activity)
  1274. return ListWidgetActivityChanged_Nothing;
  1275. changed = ListWidgetActivityChanged_Nothing;
  1276. cancelable = activity->GetCancelable();
  1277. if (item->activity->cancelable != cancelable)
  1278. {
  1279. changed |= ListWidgetActivityChanged_Cancelable;
  1280. item->activity->cancelable = cancelable;
  1281. }
  1282. if(FAILED(activity->GetProgress(&percent)))
  1283. percent = (unsigned int)-1;
  1284. if (item->activity->percent != percent)
  1285. {
  1286. changed |= ListWidgetActivityChanged_Percent;
  1287. item->activity->percent = percent;
  1288. }
  1289. if (FAILED(activity->GetDisplayName(buffer, ARRAYSIZE(buffer))))
  1290. buffer[0] = L'\0';
  1291. if (NULL == item->activity->title ||
  1292. CSTR_EQUAL != CompareString(LOCALE_SYSTEM_DEFAULT, 0, item->activity->title, -1, buffer, -1))
  1293. {
  1294. changed |= ListWidgetActivityChanged_Title;
  1295. String_Free(item->activity->title);
  1296. item->activity->title = String_Duplicate(buffer);
  1297. SetSizeEmpty(&item->activity->titleSize);
  1298. }
  1299. return changed;
  1300. }
  1301. BOOL
  1302. ListWidget_GetItemImageRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
  1303. {
  1304. if (NULL == item || NULL == rect)
  1305. return FALSE;
  1306. if (FALSE == CopyRect(rect, &item->rect))
  1307. return FALSE;
  1308. if (NULL != metrics)
  1309. {
  1310. rect->left += metrics->offsetLeft + metrics->imageOffsetLeft;
  1311. rect->top += metrics->offsetTop + metrics->imageOffsetTop;
  1312. rect->right -= metrics->offsetRight - metrics->imageOffsetRight;
  1313. rect->bottom = rect->top + self->imageSize.cy;
  1314. }
  1315. return TRUE;
  1316. }
  1317. BOOL
  1318. ListWidget_GetItemFrameRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
  1319. {
  1320. if (NULL == item || NULL == rect)
  1321. return FALSE;
  1322. if (FALSE == CopyRect(rect, &item->rect))
  1323. return FALSE;
  1324. if (NULL != metrics)
  1325. {
  1326. rect->bottom = rect->top + metrics->offsetTop +
  1327. metrics->imageOffsetTop + metrics->imageOffsetBottom +
  1328. self->imageSize.cy;
  1329. }
  1330. return TRUE;
  1331. }
  1332. static BOOL
  1333. ListWidget_CalcItemActivityTitleSize(ListWidget *self, HDC hdc, ListWidgetActivity *activity)
  1334. {
  1335. BOOL result;
  1336. HDC windowDC;
  1337. HFONT prevFont;
  1338. RECT rect;
  1339. if (NULL == hdc)
  1340. {
  1341. windowDC = GetDCEx(NULL, NULL, DCX_WINDOW | DCX_CACHE | DCX_NORESETATTRS);
  1342. if (NULL == windowDC)
  1343. {
  1344. SetSizeEmpty(&activity->titleSize);
  1345. return FALSE;
  1346. }
  1347. hdc = windowDC;
  1348. }
  1349. else
  1350. windowDC = NULL;
  1351. prevFont = SelectFont(hdc, self->activityFont);
  1352. SetRect(&rect, 0, 0, self->activityMetrics.titleWidth, self->activityMetrics.titleHeight);
  1353. result = DrawText(hdc, activity->title, -1, &rect,
  1354. DT_CALCRECT | DT_NOPREFIX | DT_WORDBREAK | DT_EDITCONTROL | DT_WORD_ELLIPSIS);
  1355. if (FALSE == result)
  1356. SetSizeEmpty(&activity->titleSize);
  1357. else
  1358. {
  1359. TEXTMETRIC textMetrics;
  1360. if (FALSE == GetTextMetrics(hdc, &textMetrics))
  1361. ZeroMemory(&textMetrics, sizeof(textMetrics));
  1362. if (rect.right > self->activityMetrics.titleWidth)
  1363. rect.right = self->activityMetrics.titleWidth;
  1364. if (rect.bottom > self->activityMetrics.titleHeight)
  1365. {
  1366. textMetrics.tmHeight = self->activityMetrics.fontHeight;
  1367. rect.bottom = (self->activityMetrics.titleHeight/textMetrics.tmHeight)*textMetrics.tmHeight;
  1368. }
  1369. activity->titleSize.cx = rect.right + textMetrics.tmAveCharWidth/2;
  1370. activity->titleSize.cy = rect.bottom;
  1371. }
  1372. SelectFont(hdc, prevFont);
  1373. if (NULL != windowDC)
  1374. ReleaseDC(NULL, windowDC);
  1375. return result;
  1376. }
  1377. static BOOL
  1378. ListWidget_GetItemActivityWorkRect(ListWidget *self, HDC hdc,
  1379. ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
  1380. {
  1381. ListWidgetActivityMetric *activityMetrics;
  1382. long length;
  1383. if (FALSE == ListWidget_GetItemActivityRect(self, item, metrics, rect))
  1384. return FALSE;
  1385. if (0 == item->activity->titleSize.cy &&
  1386. FALSE == ListWidget_CalcItemActivityTitleSize(self, hdc, item->activity))
  1387. {
  1388. return FALSE;
  1389. }
  1390. activityMetrics = &self->activityMetrics;
  1391. length = 0;
  1392. if (0 != activityMetrics->progressWidth)
  1393. {
  1394. if (0 != length)
  1395. length += activityMetrics->spacing;
  1396. length += activityMetrics->progressWidth;
  1397. }
  1398. if (0 != item->activity->titleSize.cx)
  1399. {
  1400. if (0 != length)
  1401. length += activityMetrics->spacing;
  1402. length += item->activity->titleSize.cx;
  1403. }
  1404. if (0 != activityMetrics->percentWidth)
  1405. {
  1406. if (0 != length)
  1407. length += activityMetrics->spacing;
  1408. length += activityMetrics->percentWidth;
  1409. }
  1410. rect->top += activityMetrics->offsetTop;
  1411. rect->bottom -= activityMetrics->offsetBottom;
  1412. rect->left += activityMetrics->offsetLeft;
  1413. rect->right -= activityMetrics->offsetRight;
  1414. rect->left += ((rect->right - rect->left) - length)/2;
  1415. rect->right = rect->left + length;
  1416. return TRUE;
  1417. }
  1418. BOOL
  1419. ListWidget_GetItemActivityRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
  1420. {
  1421. if (NULL == self ||
  1422. NULL == item ||
  1423. NULL == metrics ||
  1424. NULL == rect)
  1425. {
  1426. return FALSE;
  1427. }
  1428. rect->bottom = item->rect.top + self->imageSize.cy /*+ metrics.imageOffsetBottom*/;
  1429. rect->bottom += metrics->offsetTop + metrics->imageOffsetTop;
  1430. rect->top = rect->bottom - self->activityMetrics.height;
  1431. rect->left = item->rect.left + (self->itemWidth - self->activityMetrics.width)/2;
  1432. rect->right = rect->left + self->activityMetrics.width;
  1433. return TRUE;
  1434. }
  1435. BOOL
  1436. ListWidget_GetItemActivityProgressRect(ListWidget *self, HDC hdc,
  1437. ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
  1438. {
  1439. if (0 == self->activityMetrics.progressWidth ||
  1440. FALSE == ListWidget_GetItemActivityWorkRect(self, hdc, item, metrics, rect))
  1441. {
  1442. return FALSE;
  1443. }
  1444. rect->right = rect->left + self->activityMetrics.progressWidth;
  1445. rect->top +=((rect->bottom - rect->top) - self->activityMetrics.progressHeight)/2;
  1446. rect->bottom = rect->top + self->activityMetrics.progressHeight;
  1447. return TRUE;
  1448. }
  1449. BOOL
  1450. ListWidget_GetItemActivityPercentRect(ListWidget *self, HDC hdc,
  1451. ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
  1452. {
  1453. if (0 == self->activityMetrics.percentWidth ||
  1454. FALSE == ListWidget_GetItemActivityWorkRect(self, hdc, item, metrics, rect))
  1455. {
  1456. return FALSE;
  1457. }
  1458. rect->left = rect->right - self->activityMetrics.percentWidth;
  1459. rect->top += ((rect->bottom - rect->top) - self->activityMetrics.percentHeight)/2;
  1460. rect->bottom = rect->top + self->activityMetrics.percentHeight;
  1461. return TRUE;
  1462. }
  1463. BOOL
  1464. ListWidget_GetItemActivityTitleRect(ListWidget *self, HDC hdc,
  1465. ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
  1466. {
  1467. if (0 == self->activityMetrics.titleWidth ||
  1468. FALSE == ListWidget_GetItemActivityWorkRect(self, hdc, item, metrics, rect))
  1469. {
  1470. return FALSE;
  1471. }
  1472. if (0 != self->activityMetrics.progressWidth)
  1473. rect->left += self->activityMetrics.progressWidth + self->activityMetrics.spacing;
  1474. rect->right = rect->left + item->activity->titleSize.cx;
  1475. rect->top += ((rect->bottom - rect->top) - item->activity->titleSize.cy)/2;
  1476. rect->bottom = rect->top + item->activity->titleSize.cy;
  1477. return TRUE;
  1478. }
  1479. BOOL
  1480. ListWidget_InvalidateItemActivity(ListWidget *self, HWND hwnd, ListWidgetItem *item, ListWidgetActivityChange changes)
  1481. {
  1482. ListWidgetItemMetric metrics;
  1483. WidgetStyle *style;
  1484. POINT origin;
  1485. RECT rect;
  1486. BOOL invalidated;
  1487. if (ListWidgetActivityChanged_Nothing == changes)
  1488. return FALSE;
  1489. style = WIDGET_GET_STYLE(hwnd);
  1490. if (NULL == style ||
  1491. FALSE == ListWidget_GetItemMetrics(style, &metrics))
  1492. {
  1493. return FALSE;
  1494. }
  1495. if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))
  1496. {
  1497. origin.x = 0;
  1498. origin.y = 0;
  1499. }
  1500. invalidated = FALSE;
  1501. if (0 != (ListWidgetActivityChanged_Percent & changes))
  1502. {
  1503. if (FALSE != ListWidget_GetItemActivityPercentRect(self, NULL, item, &metrics, &rect))
  1504. {
  1505. OffsetRect(&rect, origin.x, origin.y);
  1506. if (FALSE != InvalidateRect(hwnd, &rect, FALSE))
  1507. invalidated = TRUE;
  1508. }
  1509. }
  1510. if (0 != (ListWidgetActivityChanged_Title & changes))
  1511. {
  1512. if (FALSE != ListWidget_GetItemActivityTitleRect(self, NULL, item, &metrics, &rect))
  1513. {
  1514. OffsetRect(&rect, origin.x, origin.y);
  1515. if (FALSE != InvalidateRect(hwnd, &rect, FALSE))
  1516. invalidated = TRUE;
  1517. }
  1518. }
  1519. return invalidated;
  1520. }
  1521. BOOL
  1522. ListWidget_InvalidateItemImage(ListWidget *self, HWND hwnd, ListWidgetItem *item)
  1523. {
  1524. ListWidgetItemMetric metrics;
  1525. WidgetStyle *style;
  1526. POINT origin;
  1527. RECT rect;
  1528. style = WIDGET_GET_STYLE(hwnd);
  1529. if (NULL == style ||
  1530. FALSE == ListWidget_GetItemMetrics(style, &metrics))
  1531. {
  1532. return FALSE;
  1533. }
  1534. if (FALSE == ListWidget_GetItemImageRect(self, item, &metrics, &rect))
  1535. return FALSE;
  1536. if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))
  1537. OffsetRect(&rect, origin.x, origin.y);
  1538. return InvalidateRect(hwnd, &rect, FALSE);
  1539. }
  1540. BOOL
  1541. ListWidget_GetItemSpacebarRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
  1542. {
  1543. if (NULL == item || NULL == rect)
  1544. return FALSE;
  1545. if (0 == item->spaceTotal ||
  1546. FALSE == CopyRect(rect, &item->rect))
  1547. {
  1548. return FALSE;
  1549. }
  1550. if (NULL != metrics)
  1551. {
  1552. rect->left += metrics->offsetLeft;
  1553. rect->top += metrics->offsetTop + metrics->imageOffsetTop +
  1554. self->imageSize.cy + metrics->imageOffsetBottom +
  1555. metrics->spacebarOffsetTop;
  1556. rect->right -= metrics->offsetRight;
  1557. rect->bottom = rect->top + metrics->spacebarHeight;
  1558. }
  1559. return TRUE;
  1560. }
  1561. BOOL
  1562. ListWidget_GetItemTitleRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, BOOL exactSize, RECT *rect)
  1563. {
  1564. if (NULL == item || NULL == rect)
  1565. return FALSE;
  1566. if (FALSE == CopyRect(rect, &item->rect))
  1567. {
  1568. return FALSE;
  1569. }
  1570. if (NULL != metrics)
  1571. {
  1572. rect->left += metrics->offsetLeft;
  1573. rect->top += metrics->offsetTop + metrics->imageOffsetTop +
  1574. self->imageSize.cy + metrics->imageOffsetBottom;
  1575. if (0 != item->spaceTotal)
  1576. rect->top += metrics->spacebarOffsetTop + metrics->spacebarHeight;
  1577. rect->top += metrics->titleOffsetTop;
  1578. rect->right -= metrics->offsetRight;
  1579. rect->bottom -= metrics->offsetBottom;
  1580. }
  1581. if (-1 != item->titleSize.cy)
  1582. {
  1583. long max;
  1584. if (FALSE != exactSize)
  1585. {
  1586. max = rect->right - rect->left;
  1587. if (max > item->titleSize.cx)
  1588. {
  1589. rect->left += (max - item->titleSize.cx)/2;
  1590. rect->right = rect->left + item->titleSize.cx;
  1591. }
  1592. }
  1593. max = rect->top + item->titleSize.cy;
  1594. if (rect->bottom > max)
  1595. rect->bottom = max;
  1596. }
  1597. return TRUE;
  1598. }
  1599. BOOL
  1600. ListWidget_GetItemConnectionRect(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics, RECT *rect)
  1601. {
  1602. if (NULL == item || NULL == rect)
  1603. return FALSE;
  1604. if (NULL == metrics)
  1605. return FALSE;
  1606. SetRect(rect, 0, 0, self->connectionSize.cx, self->connectionSize.cy);
  1607. OffsetRect(rect,
  1608. item->rect.right - metrics->offsetRight - metrics->imageOffsetRight - rect->right - 2,
  1609. item->rect.top + metrics->offsetTop + metrics->imageOffsetTop + self->imageSize.cy - rect->bottom - 2);
  1610. if (rect->left < (item->rect.left + metrics->offsetLeft) ||
  1611. rect->top < (item->rect.top + metrics->offsetTop))
  1612. {
  1613. return FALSE;
  1614. }
  1615. return TRUE;
  1616. }
  1617. ListWidgetItemPart
  1618. ListWidget_GetItemPartFromPoint(ListWidget *self, ListWidgetItem *item, ListWidgetItemMetric *metrics,
  1619. POINT pt, ListWidgetItemPart mask, RECT *partRect)
  1620. {
  1621. RECT rect;
  1622. if (NULL == self ||
  1623. NULL == item ||
  1624. NULL == metrics)
  1625. {
  1626. if (NULL != partRect)
  1627. SetRectEmpty(partRect);
  1628. return ListWidgetItemPart_None;
  1629. }
  1630. if (NULL != item->activity &&
  1631. FALSE != ListWidget_GetItemActivityRect(self, item, metrics, &rect) &&
  1632. FALSE != PtInRect(&rect, pt))
  1633. {
  1634. if (0 != (ListWidgetItemPart_Activity & mask))
  1635. {
  1636. if (NULL != partRect)
  1637. CopyRect(partRect, &rect);
  1638. return ListWidgetItemPart_Activity;
  1639. }
  1640. mask &= ~(ListWidgetItemPart_Command | ListWidgetItemPart_Connection);
  1641. }
  1642. if (0 != (ListWidgetItemPart_Command & mask) &&
  1643. FALSE != ListWidgetItem_IsInteractive(item))
  1644. {
  1645. size_t index = self->commandsCount;
  1646. while(index--)
  1647. {
  1648. if (FALSE != ListWidget_GetCommandRect(self->commands[index], &rect))
  1649. {
  1650. OffsetRect(&rect, item->rect.left, item->rect.top);
  1651. if (FALSE != PtInRect(&rect, pt))
  1652. {
  1653. if (FALSE == ListWidget_GetCommandDisabled(self->commands[index]))
  1654. {
  1655. if (NULL != partRect)
  1656. CopyRect(partRect, &rect);
  1657. return ListWidgetItemPart_Command;
  1658. }
  1659. break;
  1660. }
  1661. }
  1662. }
  1663. }
  1664. if (0 != (ListWidgetItemPart_Connection & mask) &&
  1665. FALSE != ListWidget_GetItemConnectionRect(self, item, metrics, &rect) &&
  1666. FALSE != PtInRect(&rect, pt))
  1667. {
  1668. if (NULL != partRect)
  1669. CopyRect(partRect, &rect);
  1670. return ListWidgetItemPart_Connection;
  1671. }
  1672. if (0 != (ListWidgetItemPart_Image & mask) &&
  1673. FALSE != ListWidget_GetItemImageRect(self, item, metrics, &rect) &&
  1674. FALSE != PtInRect(&rect, pt))
  1675. {
  1676. if (NULL != partRect)
  1677. CopyRect(partRect, &rect);
  1678. return ListWidgetItemPart_Image;
  1679. }
  1680. if (0 != (ListWidgetItemPart_Frame & mask) &&
  1681. FALSE != ListWidget_GetItemFrameRect(self, item, metrics, &rect) &&
  1682. FALSE != PtInRect(&rect, pt))
  1683. {
  1684. if (NULL != partRect)
  1685. CopyRect(partRect, &rect);
  1686. return ListWidgetItemPart_Frame;
  1687. }
  1688. if (0 != (ListWidgetItemPart_Spacebar & mask) &&
  1689. FALSE != ListWidget_GetItemSpacebarRect(self, item, metrics, &rect) &&
  1690. FALSE != PtInRect(&rect, pt))
  1691. {
  1692. if (NULL != partRect)
  1693. CopyRect(partRect, &rect);
  1694. return ListWidgetItemPart_Spacebar;
  1695. }
  1696. if (0 != (ListWidgetItemPart_Title & mask) &&
  1697. FALSE != ListWidget_GetItemTitleRect(self, item, metrics, FALSE, &rect) &&
  1698. FALSE != PtInRect(&rect, pt))
  1699. {
  1700. if (NULL != partRect)
  1701. CopyRect(partRect, &rect);
  1702. return ListWidgetItemPart_Title;
  1703. }
  1704. return ListWidgetItemPart_None;
  1705. }
  1706. static BOOL
  1707. ListWidget_FilterItemTitle(wchar_t *buffer, size_t bufferMax)
  1708. {
  1709. size_t read, write;
  1710. for(read = 0, write = 0;; read++)
  1711. {
  1712. if (read == bufferMax)
  1713. return FALSE;
  1714. if (L'\r' == buffer[read])
  1715. continue;
  1716. if (L'\n' == buffer[read] ||
  1717. L'\t' == buffer[read] ||
  1718. L'\b' == buffer[read])
  1719. {
  1720. buffer[write] = L' ';
  1721. }
  1722. buffer[write] = buffer[read];
  1723. if (L'\0' == buffer[read])
  1724. break;
  1725. write++;
  1726. }
  1727. return TRUE;
  1728. }
  1729. static HRESULT
  1730. ListWidget_GetDeviceStatus(ifc_device *device, wchar_t *buffer, size_t bufferMax)
  1731. {
  1732. HRESULT hr;
  1733. ifc_deviceactivity *activity;
  1734. if(NULL == buffer)
  1735. return E_POINTER;
  1736. buffer[0] = L'\0';
  1737. if (NULL == device)
  1738. return S_OK;
  1739. hr = device->GetActivity(&activity);
  1740. if (S_OK == hr && NULL != activity)
  1741. {
  1742. hr = activity->GetStatus(buffer, bufferMax);
  1743. if (FAILED(hr) || L'\0' == buffer[0])
  1744. hr = activity->GetDisplayName(buffer, bufferMax);
  1745. activity->Release();
  1746. }
  1747. if (FAILED(hr) || L'\0' == buffer[0])
  1748. hr = device->GetStatus(buffer, bufferMax);
  1749. if (E_NOTIMPL == hr)
  1750. {
  1751. hr = S_OK;
  1752. buffer[0] = L'\0';
  1753. }
  1754. return hr;
  1755. }
  1756. BOOL
  1757. ListWidget_FormatItemCommandTip(ListWidget *self, ListWidgetItem *item, const RECT *commandRect, wchar_t *buffer, size_t bufferMax)
  1758. {
  1759. size_t index;
  1760. RECT rect;
  1761. if (NULL == self)
  1762. return FALSE;
  1763. for(index = 0; index < self->commandsCount; index++)
  1764. {
  1765. ListWidgetCommand *command = self->commands[index];
  1766. if (FALSE != ListWidget_GetCommandRect(command, &rect) &&
  1767. FALSE != EqualRect(&rect, commandRect))
  1768. {
  1769. const wchar_t *value;
  1770. wchar_t *cursor;
  1771. size_t remaining;
  1772. cursor = buffer;
  1773. remaining = bufferMax;
  1774. value = ListWidget_GetCommandTitle(command);
  1775. if (FALSE == IS_STRING_EMPTY(value))
  1776. StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1777. value = ListWidget_GetCommandDescription(command);
  1778. if (FALSE == IS_STRING_EMPTY(value))
  1779. {
  1780. if (cursor != buffer)
  1781. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1782. StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1783. }
  1784. return (cursor != buffer);
  1785. }
  1786. }
  1787. return FALSE;
  1788. }
  1789. BOOL
  1790. ListWidget_FormatItemTip(ListWidget *self, ListWidgetItem *item, wchar_t *buffer, size_t bufferMax)
  1791. {
  1792. ifc_device *device;
  1793. ifc_devicetype *type;
  1794. ifc_deviceconnection *connection;
  1795. wchar_t value[1024], valueName[512], *cursor;
  1796. size_t remaining;
  1797. uint64_t totalSpace, usedSpace;
  1798. if (NULL == item ||
  1799. NULL == WASABI_API_DEVICES ||
  1800. S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
  1801. {
  1802. return FALSE;
  1803. }
  1804. cursor = buffer;
  1805. remaining = bufferMax;
  1806. if (FALSE != ListWidgetItem_IsTextTruncated(item))
  1807. {
  1808. if (SUCCEEDED(device->GetDisplayName(value, ARRAYSIZE(value))) &&
  1809. L'\0' != value[0])
  1810. {
  1811. ListWidget_FilterItemTitle(value, ARRAYSIZE(value));
  1812. StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1813. }
  1814. }
  1815. if (SUCCEEDED(device->GetModel(value, ARRAYSIZE(value))) &&
  1816. L'\0' != value[0])
  1817. {
  1818. if (cursor != buffer)
  1819. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1820. WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_MODEL_SHORT, valueName, ARRAYSIZE(valueName));
  1821. HRESULT hr;
  1822. if (L'\0' != valueName[0])
  1823. hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
  1824. else
  1825. hr = S_OK;
  1826. if (SUCCEEDED(hr))
  1827. StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1828. }
  1829. if (NULL != WASABI_API_DEVICES &&
  1830. S_OK == WASABI_API_DEVICES->TypeFind(device->GetType(), &type))
  1831. {
  1832. const char* typeStr = device->GetDisplayType();
  1833. if (typeStr && *typeStr)
  1834. {
  1835. if (cursor != buffer)
  1836. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1837. WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_TYPE_SHORT, valueName, ARRAYSIZE(valueName));
  1838. if (L'\0' != valueName[0])
  1839. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
  1840. StringCchCopyEx(cursor, remaining, AutoWide(typeStr), &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1841. }
  1842. else
  1843. {
  1844. if (SUCCEEDED(type->GetDisplayName(value, ARRAYSIZE(value))) &&
  1845. L'\0' != value[0])
  1846. {
  1847. if (cursor != buffer)
  1848. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1849. WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_TYPE_SHORT, valueName, ARRAYSIZE(valueName));
  1850. if (L'\0' != valueName[0])
  1851. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
  1852. StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1853. }
  1854. }
  1855. type->Release();
  1856. }
  1857. if (NULL != WASABI_API_DEVICES &&
  1858. S_OK == WASABI_API_DEVICES->ConnectionFind(device->GetConnection(), &connection))
  1859. {
  1860. if (SUCCEEDED(connection->GetDisplayName(value, ARRAYSIZE(value))) &&
  1861. L'\0' != value[0])
  1862. {
  1863. if (cursor != buffer)
  1864. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1865. WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_CONNECTION_SHORT, valueName, ARRAYSIZE(valueName));
  1866. if (L'\0' != valueName[0])
  1867. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
  1868. StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1869. }
  1870. connection->Release();
  1871. }
  1872. if (FAILED(device->GetTotalSpace(&totalSpace)) ||
  1873. 0 == totalSpace)
  1874. {
  1875. totalSpace = ((uint64_t)-1);
  1876. }
  1877. if (FAILED(device->GetUsedSpace(&usedSpace)))
  1878. usedSpace = ((uint64_t)-1);
  1879. else if (((uint64_t)-1) != totalSpace && usedSpace > totalSpace)
  1880. usedSpace = totalSpace;
  1881. if (((uint64_t)-1) != totalSpace && ((uint64_t)-1) != usedSpace)
  1882. {
  1883. if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), totalSpace - usedSpace))
  1884. {
  1885. WASABI_API_LNGSTRINGW_BUF(IDS_FREE_SPACE, valueName, ARRAYSIZE(valueName));
  1886. if (L'\0' != valueName[0])
  1887. {
  1888. if (cursor != buffer)
  1889. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1890. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: %s",
  1891. valueName, value);
  1892. }
  1893. }
  1894. }
  1895. if (((uint64_t)-1) != totalSpace)
  1896. {
  1897. if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), totalSpace))
  1898. {
  1899. WASABI_API_LNGSTRINGW_BUF(IDS_TOTAL_SPACE, valueName, ARRAYSIZE(valueName));
  1900. if (L'\0' != valueName[0])
  1901. {
  1902. if (cursor != buffer)
  1903. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1904. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: %s",
  1905. valueName, value);
  1906. }
  1907. }
  1908. }
  1909. // status
  1910. /*if (SUCCEEDED(ListWidget_GetDeviceStatus(device, value, ARRAYSIZE(value))) &&
  1911. L'\0' != value[0])
  1912. {
  1913. if (cursor != buffer)
  1914. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1915. WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_STATUS_SHORT, valueName, ARRAYSIZE(valueName));
  1916. if (L'\0' != valueName[0])
  1917. hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
  1918. else
  1919. hr = S_OK;
  1920. if (SUCCEEDED(hr))
  1921. hr = StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1922. }
  1923. */
  1924. device->Release();
  1925. return (cursor != buffer);
  1926. }
  1927. BOOL
  1928. ListWidget_FormatItemTitleTip(ListWidget *self, ListWidgetItem *item, wchar_t *buffer, size_t bufferMax)
  1929. {
  1930. BOOL result;
  1931. ifc_device *device;
  1932. if (NULL == item ||
  1933. FALSE == ListWidgetItem_IsTextTruncated(item) ||
  1934. NULL == WASABI_API_DEVICES ||
  1935. S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
  1936. {
  1937. return FALSE;
  1938. }
  1939. if (SUCCEEDED(device->GetDisplayName(buffer, bufferMax)))
  1940. {
  1941. ListWidget_FilterItemTitle(buffer, bufferMax);
  1942. result = TRUE;
  1943. }
  1944. else
  1945. result = FALSE;
  1946. device->Release();
  1947. return result;
  1948. }
  1949. BOOL
  1950. ListWidget_FormatItemSpaceTip(ListWidget *self, ListWidgetItem *item, wchar_t *buffer, size_t bufferMax)
  1951. {
  1952. ifc_device *device;
  1953. wchar_t value[1024], valueName[512], *cursor;
  1954. size_t remaining;
  1955. uint64_t totalSpace, usedSpace;
  1956. if (NULL == item ||
  1957. NULL == WASABI_API_DEVICES ||
  1958. S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
  1959. {
  1960. return FALSE;
  1961. }
  1962. cursor = buffer;
  1963. remaining = bufferMax;
  1964. if (FAILED(device->GetTotalSpace(&totalSpace)) ||
  1965. 0 == totalSpace)
  1966. {
  1967. totalSpace = ((uint64_t)-1);
  1968. }
  1969. if (FAILED(device->GetUsedSpace(&usedSpace)))
  1970. usedSpace = ((uint64_t)-1);
  1971. else if (((uint64_t)-1) != totalSpace && usedSpace > totalSpace)
  1972. usedSpace = totalSpace;
  1973. if (((uint64_t)-1) != usedSpace)
  1974. {
  1975. if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), usedSpace))
  1976. {
  1977. WASABI_API_LNGSTRINGW_BUF(IDS_USED_SPACE, valueName, ARRAYSIZE(valueName));
  1978. if (L'\0' != valueName[0])
  1979. {
  1980. if (cursor != buffer)
  1981. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1982. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: %s",
  1983. valueName, value);
  1984. }
  1985. }
  1986. }
  1987. if (((uint64_t)-1) != totalSpace && ((uint64_t)-1) != usedSpace)
  1988. {
  1989. if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), totalSpace - usedSpace))
  1990. {
  1991. WASABI_API_LNGSTRINGW_BUF(IDS_FREE_SPACE, valueName, ARRAYSIZE(valueName));
  1992. if (L'\0' != valueName[0])
  1993. {
  1994. if (cursor != buffer)
  1995. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  1996. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: %s",
  1997. valueName, value);
  1998. }
  1999. }
  2000. }
  2001. if (((uint64_t)-1) != totalSpace)
  2002. {
  2003. if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), totalSpace))
  2004. {
  2005. WASABI_API_LNGSTRINGW_BUF(IDS_TOTAL_SPACE, valueName, ARRAYSIZE(valueName));
  2006. if (L'\0' != valueName[0])
  2007. {
  2008. if (cursor != buffer)
  2009. StringCchCopyEx(cursor, remaining, L"\r\n", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2010. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: %s",
  2011. valueName, value);
  2012. }
  2013. }
  2014. }
  2015. device->Release();
  2016. return (cursor != buffer);
  2017. }
  2018. BOOL
  2019. ListWidget_FormatItemStatus(ListWidget *self, ListWidgetItem *item, wchar_t *buffer, size_t bufferMax)
  2020. {
  2021. ifc_device *device;
  2022. ifc_devicetype *type;
  2023. ifc_deviceconnection *connection;
  2024. HRESULT hr;
  2025. wchar_t value[512], valueName[128], *cursor;
  2026. size_t remaining;
  2027. if (NULL == item ||
  2028. NULL == WASABI_API_DEVICES ||
  2029. S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
  2030. {
  2031. return FALSE;
  2032. }
  2033. hr = S_OK;
  2034. cursor = buffer;
  2035. remaining = bufferMax;
  2036. if (FALSE != ListWidgetItem_IsTextTruncated(item))
  2037. {
  2038. if (SUCCEEDED(device->GetDisplayName(value, ARRAYSIZE(value))) &&
  2039. L'\0' != value[0])
  2040. {
  2041. ListWidget_FilterItemTitle(value, ARRAYSIZE(value));
  2042. hr = StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2043. }
  2044. }
  2045. if (cursor == buffer &&
  2046. SUCCEEDED(device->GetModel(value, ARRAYSIZE(value))) &&
  2047. L'\0' != value[0])
  2048. {
  2049. WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_MODEL_SHORT, valueName, ARRAYSIZE(valueName));
  2050. if (L'\0' != valueName[0])
  2051. hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
  2052. if (SUCCEEDED(hr))
  2053. hr = StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2054. }
  2055. if (cursor == buffer &&
  2056. NULL != WASABI_API_DEVICES &&
  2057. S_OK == WASABI_API_DEVICES->TypeFind(device->GetType(), &type))
  2058. {
  2059. if (SUCCEEDED(type->GetDisplayName(value, ARRAYSIZE(value))) &&
  2060. L'\0' != value[0])
  2061. {
  2062. WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_TYPE_SHORT, valueName, ARRAYSIZE(valueName));
  2063. if (L'\0' != valueName[0])
  2064. hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
  2065. if (SUCCEEDED(hr))
  2066. hr = StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2067. }
  2068. type->Release();
  2069. }
  2070. else
  2071. {
  2072. const char* typeStr = device->GetDisplayType();
  2073. if (typeStr && *typeStr)
  2074. {
  2075. if (cursor != buffer)
  2076. hr = StringCchCopyEx(cursor, remaining, L", ", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2077. WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_TYPE_SHORT, valueName, ARRAYSIZE(valueName));
  2078. if (L'\0' != valueName[0])
  2079. hr = StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
  2080. if (SUCCEEDED(hr))
  2081. StringCchCopyEx(cursor, remaining, AutoWide(typeStr), &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2082. }
  2083. }
  2084. if (NULL != WASABI_API_DEVICES &&
  2085. S_OK == WASABI_API_DEVICES->ConnectionFind(device->GetConnection(), &connection))
  2086. {
  2087. if (SUCCEEDED(connection->GetDisplayName(value, ARRAYSIZE(value))) &&
  2088. L'\0' != value[0])
  2089. {
  2090. if (cursor != buffer)
  2091. StringCchCopyEx(cursor, remaining, L", ", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2092. WASABI_API_LNGSTRINGW_BUF(IDS_DEVICE_CONNECTION_SHORT, valueName, ARRAYSIZE(valueName));
  2093. if (L'\0' != valueName[0])
  2094. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE, L"%s: ", valueName);
  2095. StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2096. }
  2097. connection->Release();
  2098. }
  2099. if (cursor == buffer &&
  2100. SUCCEEDED(device->GetDisplayName(value, ARRAYSIZE(value))))
  2101. {
  2102. ListWidget_FilterItemTitle(value, ARRAYSIZE(value));
  2103. StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2104. }
  2105. if (SUCCEEDED(ListWidget_GetDeviceStatus(device, value, ARRAYSIZE(value))) &&
  2106. L'\0' != value[0])
  2107. {
  2108. if (cursor != buffer)
  2109. StringCchCopyEx(cursor, remaining, L", ", &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2110. StringCchCopyEx(cursor, remaining, value, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE);
  2111. }
  2112. device->Release();
  2113. return (cursor != buffer);
  2114. }
  2115. BOOL
  2116. ListWidget_FormatItemSpaceStatus(ListWidget *self, ListWidgetItem *item, wchar_t *buffer, size_t bufferMax)
  2117. {
  2118. ifc_device *device;
  2119. wchar_t *cursor;
  2120. size_t remaining;
  2121. uint64_t totalSpace, usedSpace;
  2122. if (NULL == item ||
  2123. NULL == WASABI_API_DEVICES ||
  2124. S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))
  2125. {
  2126. return FALSE;
  2127. }
  2128. cursor = buffer;
  2129. remaining = bufferMax;
  2130. if (FAILED(device->GetTotalSpace(&totalSpace)) ||
  2131. 0 == totalSpace)
  2132. {
  2133. totalSpace = ((uint64_t)-1);
  2134. }
  2135. if (FAILED(device->GetUsedSpace(&usedSpace)))
  2136. usedSpace = ((uint64_t)-1);
  2137. else if (((uint64_t)-1) != totalSpace && usedSpace > totalSpace)
  2138. usedSpace = totalSpace;
  2139. if (((uint64_t)-1) != totalSpace)
  2140. {
  2141. if (((uint64_t)-1) != usedSpace)
  2142. {
  2143. wchar_t value1[64] = {0}, value2[64] = {0};
  2144. if (NULL != WASABI_API_LNG->FormattedSizeString(value1, ARRAYSIZE(value1), totalSpace - usedSpace) &&
  2145. NULL != WASABI_API_LNG->FormattedSizeString(value2, ARRAYSIZE(value2), totalSpace))
  2146. {
  2147. wchar_t format[128] = {0};
  2148. WASABI_API_LNGSTRINGW_BUF(IDS_STATUS_SPACE_TEMPLATE, format, ARRAYSIZE(format));
  2149. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE,
  2150. format, value1, value2);
  2151. }
  2152. }
  2153. else
  2154. {
  2155. wchar_t value[64] = {0};
  2156. if (NULL != WASABI_API_LNG->FormattedSizeString(value, ARRAYSIZE(value), totalSpace))
  2157. {
  2158. wchar_t valueName[128] = {0};
  2159. WASABI_API_LNGSTRINGW_BUF(IDS_TOTAL_SPACE, valueName, ARRAYSIZE(valueName));
  2160. if (L'\0' != valueName[0])
  2161. {
  2162. StringCchPrintfEx(cursor, remaining, &cursor, &remaining, STRSAFE_NULL_ON_FAILURE,
  2163. L"%s %s", value, valueName);
  2164. }
  2165. }
  2166. }
  2167. }
  2168. device->Release();
  2169. return (cursor != buffer);
  2170. }
  2171. static void CALLBACK
  2172. ListWidget_EndTitleEditCb(HWND editorWindow, BOOL canceled, const wchar_t *text, void *user)
  2173. {
  2174. HWND hwnd;
  2175. ListWidget *self;
  2176. char *itemName;
  2177. hwnd = GetAncestor(editorWindow, GA_PARENT);
  2178. self = WIDGET_GET_SELF(hwnd, ListWidget);
  2179. itemName = (char*)user;
  2180. if (NULL != self)
  2181. {
  2182. ListWidgetItem *item;
  2183. if (self->titleEditor == editorWindow)
  2184. self->titleEditor = NULL;
  2185. item = ListWidget_FindItem(self, itemName, NULL, NULL);
  2186. if (NULL != item)
  2187. {
  2188. ListWidgetItemMetric metrics;
  2189. WidgetStyle *style;
  2190. POINT origin;
  2191. RECT rect;
  2192. ListWidgetItem_UnsetTextEdited(item);
  2193. style = WIDGET_GET_STYLE(hwnd);
  2194. if (NULL != style &&
  2195. FALSE != ListWidget_GetItemMetrics(style, &metrics) &&
  2196. FALSE != ListWidget_GetItemTitleRect(self, item, &metrics, FALSE, &rect))
  2197. {
  2198. if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))
  2199. OffsetRect(&rect, origin.x, origin.y);
  2200. InvalidateRect(hwnd, &rect, FALSE);
  2201. }
  2202. }
  2203. if (FALSE == canceled)
  2204. {
  2205. ifc_device *device;
  2206. if (NULL != WASABI_API_DEVICES &&
  2207. S_OK == WASABI_API_DEVICES->DeviceFind(itemName, &device))
  2208. {
  2209. wchar_t buffer[1024] = {0};
  2210. if (FAILED(device->GetDisplayName(buffer, ARRAYSIZE(buffer))) ||
  2211. CSTR_EQUAL != CompareString(LOCALE_USER_DEFAULT, 0, buffer, -1, text, -1))
  2212. {
  2213. HRESULT hr;
  2214. hr = device->SetDisplayName(text);
  2215. if (FAILED(hr))
  2216. {
  2217. wchar_t title[256] = {0}, message[1024] = {0};
  2218. WASABI_API_LNGSTRINGW_BUF(IDS_MESSAGEBOX_TITLE, title, ARRAYSIZE(title));
  2219. WASABI_API_LNGSTRINGW_BUF(IDS_MESSAGE_UNABLE_TO_RENAME, message, ARRAYSIZE(message));
  2220. MessageBox(hwnd, message, title, MB_OK | MB_ICONERROR);
  2221. }
  2222. }
  2223. device->Release();
  2224. }
  2225. }
  2226. }
  2227. EMBEDDEDEDITOR_SET_USER_DATA(editorWindow, NULL);
  2228. AnsiString_Free(itemName);
  2229. }
  2230. HWND
  2231. ListWidget_BeginItemTitleEdit(ListWidget *self, HWND hwnd, ListWidgetItem *item)
  2232. {
  2233. RECT rect;
  2234. WidgetStyle *style;
  2235. ListWidgetItemMetric metrics;
  2236. HWND editor;
  2237. POINT origin;
  2238. unsigned long editorStyleEx, editorStyle;
  2239. char *itemName;
  2240. ifc_device * device;
  2241. BOOL blockEditor;
  2242. if (NULL == self || NULL == item)
  2243. return NULL;
  2244. style = WIDGET_GET_STYLE(hwnd);
  2245. if (NULL == style)
  2246. return NULL;
  2247. if (NULL != WASABI_API_DEVICES &&
  2248. S_OK == WASABI_API_DEVICES->DeviceFind(item->name, &device))
  2249. {
  2250. blockEditor = (FALSE == DeviceCommand_GetEnabled(device, "rename",
  2251. DeviceCommandContext_ViewMenu));
  2252. device->Release();
  2253. }
  2254. else
  2255. blockEditor = TRUE;
  2256. if (FALSE != blockEditor)
  2257. return NULL;
  2258. if (FALSE == ListWidget_GetItemMetrics(style, &metrics))
  2259. return NULL;
  2260. if (FALSE == ListWidget_GetItemTitleRect(self, item, &metrics, FALSE, &rect))
  2261. return NULL;
  2262. if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))
  2263. OffsetRect(&rect, origin.x, origin.y);
  2264. editorStyleEx = WS_EX_CLIENTEDGE;
  2265. editorStyle = WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
  2266. ES_CENTER | ES_NOHIDESEL | ES_MULTILINE | ES_AUTOVSCROLL;
  2267. EmbeddedEditor_AdjustWindowRectEx(&rect, editorStyleEx, editorStyle);
  2268. editor = CreateWindowEx(editorStyleEx, WC_EDIT, item->title, editorStyle,
  2269. rect.left, rect.top, 0, 0,
  2270. hwnd, NULL, NULL, 0L);
  2271. if (NULL == editor)
  2272. return NULL;
  2273. itemName = AnsiString_Duplicate(item->name);
  2274. if (FALSE == EmbeddedEditor_Attach(editor, ListWidget_EndTitleEditCb, itemName))
  2275. {
  2276. AnsiString_Free(itemName);
  2277. DestroyWindow(editor);
  2278. return NULL;
  2279. }
  2280. ListWidgetItem_SetTextEdited(item);
  2281. EMBEDDEDEDITOR_SET_ANCHOR_POINT(editor, rect.left, rect.top);
  2282. EMBEDDEDEDITOR_SET_MAX_SIZE(editor, RECTWIDTH(rect), 0);
  2283. SendMessage(editor, WM_SETFONT, (WPARAM)WIDGETSTYLE_TEXT_FONT(style), 0L);
  2284. ListWidget_UpdateTitleEditorColors(editor, style);
  2285. SendMessage(editor, EM_SETSEL, 0, -1);
  2286. ShowWindow(editor, SW_SHOW);
  2287. SetFocus(editor);
  2288. return editor;
  2289. }
  2290. int
  2291. ListWidget_CompareItemPos(ListWidget *self, ListWidgetItem *item1, ListWidgetItem *item2)
  2292. {
  2293. size_t iCategory1, iGroup1, iItem1;
  2294. size_t iCategory2, iGroup2, iItem2;
  2295. if (FALSE == ListWidget_FindItemPos(self, item1, &iCategory1, &iGroup1, &iItem1) ||
  2296. FALSE == ListWidget_FindItemPos(self, item2, &iCategory2, &iGroup2, &iItem2))
  2297. {
  2298. return _NLSCMPERROR;
  2299. }
  2300. if (iCategory1 != iCategory2)
  2301. return (int)(iCategory1 - iCategory2);
  2302. if (iGroup1 != iGroup2)
  2303. return (int)(iGroup1 - iGroup2);
  2304. return (int)(iItem1 - iItem2);
  2305. }
  2306. BOOL
  2307. ListWidget_GetViewItemPos(HWND hwnd, ListWidgetItem *item, POINT *pt)
  2308. {
  2309. if (NULL == hwnd ||
  2310. NULL == item ||
  2311. NULL == pt)
  2312. {
  2313. return FALSE;
  2314. }
  2315. if (FALSE == ListWidget_GetViewOrigin(hwnd, pt))
  2316. {
  2317. pt->x = 0;
  2318. pt->y = 0;
  2319. }
  2320. pt->x = item->rect.left - pt->x;
  2321. pt->y = item->rect.top - pt->y;
  2322. return TRUE;
  2323. }