| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096 | #include "main.h"#include "./listWidget.h"#include "./listWidgetInternal.h"#include <vector>#include <strsafe.h>#define LISTWIDGET_OFFSET_LEFT_DLU				0#define LISTWIDGET_OFFSET_TOP_DLU				1#define LISTWIDGET_OFFSET_BOTTOM_DLU			2#define LISTWIDGET_CATEGORY_OFFSET_TOP_DLU		0#define LISTWIDGET_CATEGORY_OFFSET_LEFT_DLU		1#define LISTWIDGET_CATEGORY_SPACING_DLU			2#define LISTWIDGET_CATEGORY_SPACING_COLLAPSED_DLU	0#define LISTWIDGET_ITEM_OFFSET_TOP_DLU			1#define LISTWIDGET_ITEM_OFFSET_LEFT_DLU			2#define LISTWIDGET_ITEM_SPACING_HORZ_DLU		2#define LISTWIDGET_ITEM_SPACING_VERT_DLU		10#define LISTWIDGET_ITEM_TITLE_MAX_LINES			3#define LISTWIDGET_IMAGE_MIN_HEIGHT				48#define LISTWIDGET_IMAGE_MAX_HEIGHT				256#define LISTWIDGET_IMAGE_DEFAULT_HEIGHT			160//128#define LISTWIDGET_IMAGE_DEFAULT_WIDTH			160//96#define LISTWIDGETTIMER_SHOW_COMMANDS_ID		3#define LISTWIDGETTIMER_SHOW_COMMANDS_DELAY		75#define LISTWIDGETTIMER_PROGRESS_TICK_ID		4#define LISTWIDGETTIMER_PROGRESS_TICK_DELAY		130#define LISTWIDGETTIMER_EDIT_TITLE_ID			5#define LISTWIDGET_CONNECTION_MIN_HEIGHT		20#define LISTWIDGET_CONNECTION_MAX_HEIGHT		48#define LISTWIDGET_CONNECTION_DEFAULT_HEIGHT	36#define LISTWIDGET_PRIMARYCOMMAND_MIN_HEIGHT		16#define LISTWIDGET_PRIMARYCOMMAND_MAX_HEIGHT		48#define LISTWIDGET_PRIMARYCOMMAND_DEFAULT_HEIGHT	36#define LISTWIDGET_SECONDARYCOMMAND_MIN_HEIGHT		14#define LISTWIDGET_SECONDARYCOMMAND_MAX_HEIGHT		36#define LISTWIDGET_SECONDARYCOMMAND_DEFAULT_HEIGHT	20#define LISTWIDGET_ACTIVITY_MIN_HEIGHT			16#define LISTWIDGET_ACTIVITY_MAX_HEIGHT			48#define LISTWIDGET_ACTIVITY_DEFAULT_HEIGHT		36#define LISTWIDGET_PROGRESS_MIN_HEIGHT			16#define LISTWIDGET_PROGRESS_FRAME_COUNT			9/*12*/typedef std::vector<ifc_device*> DeviceList;static ListWidgetCategory *ListWidget_CreateCategoryHelper(const char *name, int titleId, wchar_t *buffer, size_t bufferMax){	WASABI_API_LNGSTRINGW_BUF(titleId, buffer, bufferMax);	return ListWidget_CreateCategory(name,						buffer, 						Config_ReadBool("CollapsedCategories", name, FALSE));}static voidListWidget_CreateDefaultCategories(ListWidget *self){	ListWidgetCategory *category;	wchar_t buffer[512] = {0};	category = ListWidget_CreateCategoryHelper("attached", IDS_CATEGORY_ATTACHED, buffer, ARRAYSIZE(buffer));	if (NULL != category)	{		WASABI_API_LNGSTRINGW_BUF(IDS_CATEGORY_ATTACHED_EMPTY_TEXT, buffer, ARRAYSIZE(buffer));		ListWidget_SetCategoryEmptyText(category, buffer);		self->categories.push_back(category);	}	category = ListWidget_CreateCategoryHelper("discovered", IDS_CATEGORY_DISCOVERED, buffer, ARRAYSIZE(buffer));	if (NULL != category)		self->categories.push_back(category);}BOOLListWidget_GetViewOrigin(HWND hwnd, POINT *pt){	SCROLLINFO scrollInfo;	if (NULL == pt)		return FALSE;	scrollInfo.cbSize = sizeof(scrollInfo);	scrollInfo.fMask = SIF_POS;			if (FALSE == GetScrollInfo(hwnd, SB_HORZ, &scrollInfo))		return FALSE;	pt->x = -scrollInfo.nPos;	if (FALSE == GetScrollInfo(hwnd, SB_VERT, &scrollInfo))		return FALSE;	pt->y = -scrollInfo.nPos;	return TRUE;}static HBITMAPListWidget_CreateSpacebarBitmap(HBITMAP sourceBitmap, HWND hwnd, long width, long height){	HDC windowDC, sourceDC, resultDC;	HBITMAP resultBitmap;	BITMAP sourceInfo;	RECT resultRect, sourceRect;	if (NULL == sourceBitmap ||		sizeof(sourceInfo) != GetObject(sourceBitmap, sizeof(sourceInfo), &sourceInfo))	{		return FALSE;	}		windowDC = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);	if (NULL == windowDC)		return NULL;	sourceDC = CreateCompatibleDC(windowDC);	resultDC = CreateCompatibleDC(windowDC);	resultBitmap = CreateCompatibleBitmap(windowDC, width, height*2);	ReleaseDC(hwnd, windowDC);	if (NULL != sourceDC &&		NULL != resultDC &&		NULL != resultBitmap)	{		HBITMAP prevSourceBitmap, prevResultBitmap;		prevSourceBitmap = SelectBitmap(sourceDC, sourceBitmap);		prevResultBitmap = SelectBitmap(resultDC, resultBitmap);				SetRect(&resultRect, 0, 0, width, height);		SetRect(&sourceRect, 0, 0, sourceInfo.bmWidth, ABS(sourceInfo.bmHeight)/2);		Image_FillBorder(resultDC, &resultRect, sourceDC, &sourceRect, TRUE, 255);				OffsetRect(&resultRect, 0, height);		OffsetRect(&sourceRect, 0, RECTHEIGHT(sourceRect));		Image_FillBorder(resultDC, &resultRect, sourceDC, &sourceRect, TRUE, 255);		SelectBitmap(sourceDC, prevSourceBitmap);		SelectBitmap(resultDC, prevResultBitmap);	}		if (NULL != sourceDC)		DeleteDC(sourceDC);	if (NULL != resultDC)		DeleteDC(resultDC);	if (NULL != resultBitmap)	{		RECT imageRect;		SetRect(&imageRect, 0, 0, width, height);		Image_Premultiply(resultBitmap, &imageRect);	}	return resultBitmap;}HBITMAPListWidget_GetSpacebarBitmap(ListWidget *self, WidgetStyle *style, HWND hwnd, long width, long height){	if (NULL == self)		return NULL;	if (NULL != self->spacebarBitmap)	{		BITMAP bi;		if (sizeof(bi) != GetObject(self->spacebarBitmap, sizeof(bi), &bi) ||			bi.bmWidth != width || 			bi.bmHeight/2 != height)		{			DeleteObject(self->spacebarBitmap);			self->spacebarBitmap = NULL;		}	}		if (NULL == self->spacebarBitmap && 		NULL != style)	{		HBITMAP baseBitmap;		baseBitmap = Image_Load(MAKEINTRESOURCE(IDR_SPACEBAR_IMAGE), SRC_TYPE_PNG, 0, 0, 0); 									//WIDGETSTYLE_IMAGE_BACK_COLOR(style),  		//					WIDGETSTYLE_IMAGE_FRONT_COLOR(style),		//					WIDGETSTYLE_BACK_COLOR(style));				if (NULL != baseBitmap)		{			DIBSECTION bitmapData;									if (sizeof(bitmapData) == GetObjectW(baseBitmap, sizeof(bitmapData), &bitmapData))			{				BITMAP *bi;				long bitmapHeight;				void *pixels;				WORD backHue, backLuma, backSat, frontHue, frontLuma, frontSat;				bi = &bitmapData.dsBm;				bitmapHeight = ABS(bi->bmHeight);														pixels = ((BYTE*)bi->bmBits) + (bi->bmWidthBytes * (bitmapHeight - bitmapHeight/2));				ColorRGBToHLS(WIDGETSTYLE_IMAGE_BACK_COLOR(style), &backHue, &backLuma, &backSat);				ColorRGBToHLS(WIDGETSTYLE_IMAGE_FRONT_COLOR(style), &frontHue, &frontLuma, &frontSat);								if (backLuma > frontLuma)				{					COLORREF backColor;					frontLuma = 25;					backColor = ColorHLSToRGB(frontHue, frontLuma, frontSat);					Image_FilterEx(pixels, bi->bmWidth, bitmapHeight/2, bi->bmBitsPixel, 									0, 									backColor, 									WIDGETSTYLE_IMAGE_BACK_COLOR(style),									WIDGETSTYLE_BACK_COLOR(style));				}				else				{					Image_FilterEx(pixels, bi->bmWidth, bitmapHeight/2, bi->bmBitsPixel, 									0, 									WIDGETSTYLE_IMAGE_BACK_COLOR(style), 									WIDGETSTYLE_IMAGE_FRONT_COLOR(style), 									WIDGETSTYLE_BACK_COLOR(style));				}			}					Image_Premultiply(baseBitmap, NULL);			self->spacebarBitmap = ListWidget_CreateSpacebarBitmap(baseBitmap, hwnd, width, height);			DeleteObject(baseBitmap);		}	}	return self->spacebarBitmap;}static HBITMAPListWidget_CreateBorderBitmap(HBITMAP sourceBitmap, HWND hwnd, long width, long height){	HDC windowDC, sourceDC, resultDC;	HBITMAP resultBitmap;	BITMAP sourceInfo;	RECT resultRect, sourceRect;		if (NULL == sourceBitmap ||		sizeof(sourceInfo) != GetObject(sourceBitmap, sizeof(sourceInfo), &sourceInfo))	{		return FALSE;	}	SetRect(&resultRect, 0, 0, width, height);	SetRect(&sourceRect, 0, 0, sourceInfo.bmWidth, ABS(sourceInfo.bmHeight));			windowDC = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);	if (NULL == windowDC)		return NULL;	sourceDC = CreateCompatibleDC(windowDC);	resultDC = CreateCompatibleDC(windowDC);	resultBitmap = CreateCompatibleBitmap(windowDC, width, height);	ReleaseDC(hwnd, windowDC);	if (NULL != sourceDC &&		NULL != resultDC &&		NULL != resultBitmap)	{		HBITMAP prevSourceBitmap, prevResultBitmap;		prevSourceBitmap = SelectBitmap(sourceDC, sourceBitmap);		prevResultBitmap = SelectBitmap(resultDC, resultBitmap);			Image_FillBorder(resultDC, &resultRect, sourceDC, &sourceRect, TRUE, 255);				SelectBitmap(sourceDC, prevSourceBitmap);		SelectBitmap(resultDC, prevResultBitmap);	}		if (NULL != sourceDC)		DeleteDC(sourceDC);	if (NULL != resultDC)		DeleteDC(resultDC);		return resultBitmap;}static HBITMAPListWidget_GetBorderBitmap(HBITMAP bitmap, const wchar_t *path, WidgetStyle *style, 						   HWND hwnd, long width, long height, BOOL disableSkin,						   COLORREF colorBack, COLORREF colorFront){		if (NULL != bitmap)	{		BITMAP bi;		if (sizeof(bi) != GetObject(bitmap, sizeof(bi), &bi) ||			bi.bmWidth != width || 			bi.bmHeight != height)		{			DeleteObject(bitmap);			bitmap = NULL;		}	}	if (NULL == bitmap && 		NULL != style)	{		HBITMAP baseBitmap;		if (FALSE == disableSkin)		{			baseBitmap = Image_LoadSkinned(path, 								SRC_TYPE_PNG, 								IMAGE_FILTER_NORMAL,								0, 0, 								colorBack, colorFront, 								WIDGETSTYLE_BACK_COLOR(style));		}		else		{			baseBitmap = Image_Load(path, SRC_TYPE_PNG, 0, 0, 0);		}		if (NULL != baseBitmap)		{			Image_Premultiply(baseBitmap, NULL);			bitmap = ListWidget_CreateBorderBitmap(baseBitmap, hwnd, width, height);			DeleteObject(baseBitmap);		}	}	return bitmap;}HBITMAPListWidget_GetHoverBitmap(ListWidget *self, WidgetStyle *style, HWND hwnd, long width, long height){	if (NULL == self)		return NULL;		self->hoverBitmap = ListWidget_GetBorderBitmap(self->hoverBitmap, 								MAKEINTRESOURCE(IDR_ITEM_HOVER_IMAGE),								style, hwnd, width, height, FALSE,								WIDGETSTYLE_SELECT_BACK_COLOR(style),								WIDGETSTYLE_SELECT_FRONT_COLOR(style));	return self->hoverBitmap;}HBITMAPListWidget_GetSelectBitmap(ListWidget *self, WidgetStyle *style, HWND hwnd, long width, long height){	if (NULL == self)		return NULL;		self->selectBitmap = ListWidget_GetBorderBitmap(self->selectBitmap, 								MAKEINTRESOURCE(IDR_ITEM_SELECT_IMAGE),								style, hwnd, width, height, FALSE,								WIDGETSTYLE_SELECT_BACK_COLOR(style),								WIDGETSTYLE_SELECT_FRONT_COLOR(style));	return self->selectBitmap;}HBITMAPListWidget_GetInactiveSelectBitmap(ListWidget *self, WidgetStyle *style, HWND hwnd, long width, long height){	if (NULL == self)		return NULL;		self->inactiveSelectBitmap = ListWidget_GetBorderBitmap(self->inactiveSelectBitmap, 								MAKEINTRESOURCE(IDR_ITEM_SELECT_IMAGE),								style, hwnd, width, height, FALSE,								WIDGETSTYLE_INACTIVE_SELECT_BACK_COLOR(style),								WIDGETSTYLE_INACTIVE_SELECT_FRONT_COLOR(style));	return self->inactiveSelectBitmap;}HBITMAPListWidget_GetLargeBadgeBitmap(ListWidget *self, WidgetStyle *style, HWND hwnd, long width, long height){	if (NULL == self)		return NULL;		self->largeBadgeBitmap = ListWidget_GetBorderBitmap(self->largeBadgeBitmap, 								MAKEINTRESOURCE(IDR_COMMAND_BACKGROUND_IMAGE),								style, hwnd, width, height, TRUE,								WIDGETSTYLE_IMAGE_BACK_COLOR(style),								WIDGETSTYLE_IMAGE_FRONT_COLOR(style));	return self->largeBadgeBitmap;}HBITMAPListWidget_GetSmallBadgeBitmap(ListWidget *self, WidgetStyle *style, HWND hwnd, long width, long height){	if (NULL == self)		return NULL;		self->smallBadgeBitmap = ListWidget_GetBorderBitmap(self->smallBadgeBitmap, 								MAKEINTRESOURCE(IDR_COMMAND_SECONDARY_BACKGROUND_IMAGE),								style, hwnd, width, height, TRUE,								WIDGETSTYLE_IMAGE_BACK_COLOR(style),								WIDGETSTYLE_IMAGE_FRONT_COLOR(style));	return self->smallBadgeBitmap;}HBITMAPListWidget_GetArrowsBitmap(ListWidget *self, WidgetStyle *style, HWND hwnd){	if (NULL == self)		return NULL;	if (NULL == self->arrowsBitmap && 		NULL != style)	{		self->arrowsBitmap = Image_LoadSkinned(MAKEINTRESOURCE(IDR_CATEGORY_ARROWS_IMAGE),										SRC_TYPE_PNG, 										IMAGE_FILTER_NORMAL,										0, 0, 										WIDGETSTYLE_CATEGORY_BACK_COLOR(style),  										WIDGETSTYLE_CATEGORY_TEXT_COLOR(style),										WIDGETSTYLE_CATEGORY_BACK_COLOR(style));				if (NULL != self->arrowsBitmap)			Image_Premultiply(self->arrowsBitmap, NULL);	}	return self->arrowsBitmap;}HBITMAPListWidget_GetUnknownCommandLargeBitmap(ListWidget *self, WidgetStyle *style, long width, long height){	if (NULL == self)		return NULL;	if (NULL == self->unknownCommandLargeImage && 		NULL != style)	{		self->unknownCommandLargeImage = DeviceImageCache_GetImage(Plugin_GetImageCache(), 				MAKEINTRESOURCE(IDR_UNKNOWN_COMMAND_LARGE_IMAGE), 				width, height, 				NULL, NULL);	}	return DeviceImage_GetBitmap(self->unknownCommandLargeImage, DeviceImage_Normal);}HBITMAPListWidget_GetUnknownCommandSmallBitmap(ListWidget *self, WidgetStyle *style, long width, long height){	if (NULL == self)		return NULL;	if (NULL == self->unknownCommandSmallImage && 		NULL != style)	{		self->unknownCommandSmallImage = DeviceImageCache_GetImage(Plugin_GetImageCache(), 				MAKEINTRESOURCE(IDR_UNKNOWN_COMMAND_LARGE_IMAGE), 				width, height, 				NULL, NULL);	}	return DeviceImage_GetBitmap(self->unknownCommandSmallImage, DeviceImage_Normal);}HBITMAPListWidget_GetActivityProgressBitmap(ListWidget *self, WidgetStyle *style){	if (NULL == self)		return NULL;	if (NULL == self->activityProgressImage && 		NULL != style)	{		self->activityProgressImage = DeviceImageCache_GetImage(Plugin_GetImageCache(), 				MAKEINTRESOURCE(IDR_PROGRESS_SMALL_IMAGE), 				self->activityMetrics.progressWidth, self->activityMetrics.progressHeight * LISTWIDGET_PROGRESS_FRAME_COUNT, 				NULL, NULL);			}	return DeviceImage_GetBitmap(self->activityProgressImage, DeviceImage_Normal);}HBITMAPListWidget_GetActivityBadgeBitmap(ListWidget *self, WidgetStyle *style, HWND hwnd, long width, long height){		if (NULL == self)		return NULL;		self->activityBadgeBitmap = ListWidget_GetBorderBitmap(self->activityBadgeBitmap, 								MAKEINTRESOURCE(IDR_ACTION_BACKGROUND_IMAGE),								style, hwnd, width, height, TRUE,								WIDGETSTYLE_IMAGE_BACK_COLOR(style),								WIDGETSTYLE_IMAGE_FRONT_COLOR(style));	return self->activityBadgeBitmap;}static BOOLListWidget_UpdateCommandsLayout(ListWidget *self, HWND hwnd){	WidgetStyle *style;	ListWidgetItemMetric metrics;	RECT rect;	size_t index, indexMax;	long spacing;	if (NULL == self)		return FALSE;	style = WIDGET_GET_STYLE(hwnd);	if (NULL == style)		return FALSE;		if (0 == self->commandsCount)		return TRUE;			if (FALSE == ListWidget_GetItemMetrics(style, &metrics))		return FALSE;			indexMax = self->commandsCount;		if ((NULL == self->hoveredItem || NULL == self->hoveredItem->activity) &&		FALSE != ListWidget_GetCommandPrimary(self->commands[0]))	{		rect.bottom = self->imageSize.cy /*+ metrics.imageOffsetBottom*/;		rect.bottom += metrics.offsetTop + metrics.imageOffsetTop;		rect.top = rect.bottom - self->primaryCommandSize.cy;				rect.left = (self->itemWidth - self->primaryCommandSize.cx)/2;		rect.right = rect.left + self->primaryCommandSize.cx;				ListWidget_SetCommandRect(self->commands[0], &rect);		indexMax--;	}		rect.top = metrics.offsetTop + metrics.imageOffsetTop;	rect.bottom = rect.top + self->secondaryCommandSize.cy;	rect.right = self->itemWidth - metrics.offsetRight - metrics.imageOffsetRight;	rect.left = rect.right - self->secondaryCommandSize.cx;		spacing = self->secondaryCommandSize.cx/16 + 1;	for(index = 0; index < indexMax; index++)	{		ListWidget_SetCommandRect(self->commands[self->commandsCount - index - 1], &rect);		OffsetRect(&rect, -(self->secondaryCommandSize.cx + spacing), 0);	}	return TRUE;}static BOOLListWidget_UpdateActiveCommands(ListWidget *self, HWND hwnd){	ListWidgetCommand **clone;	size_t cloneSize, index;	BOOL invalidated;	POINT origin, pt;	RECT rect;			if (NULL == self)		return FALSE;	if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))	{		origin.x = 0;		origin.y = 0;	}	if (NULL == self->hoveredItem)	{				ListWidget_DestroyAllCommands(self->commands, self->commandsCount);		self->commandsCount = 0;		return TRUE;	}		origin.x += self->hoveredItem->rect.left;	origin.y += self->hoveredItem->rect.top;	invalidated = FALSE;		if (0 != self->commandsCount)	{					for(index = 0; index < self->commandsCount; index++)		{			if (FALSE != ListWidget_GetCommandRect(self->commands[index], &rect))			{				OffsetRect(&rect, origin.x, origin.y);				if (FALSE != InvalidateRect(hwnd, &rect, FALSE))					invalidated = TRUE;			}		}		clone = (ListWidgetCommand**)malloc(sizeof(ListWidgetCommand*) * self->commandsCount);		if (NULL != clone)		{			cloneSize = self->commandsCount;			CopyMemory(clone, self->commands, sizeof(ListWidgetCommand*) * cloneSize);		}		else		{			cloneSize = 0;			ListWidget_DestroyAllCommands(self->commands, self->commandsCount);		}	}	else	{		clone = NULL;		cloneSize = 0;	}	self->commandsCount = ListWidget_GetItemCommands(self->hoveredItem, 									self->commands, self->commandsMax);		if (0 != self->commandsCount)	{		ListWidget_UpdateCommandsLayout(self, hwnd);		ListWidgetItem_SetInteractive(self->hoveredItem);		for(index = 0; index < self->commandsCount; index++)		{			if (FALSE != ListWidget_GetCommandRect(self->commands[index], &rect))			{				OffsetRect(&rect, origin.x, origin.y);				if (FALSE != InvalidateRect(hwnd, &rect, FALSE))					invalidated = TRUE;			}		}	}	else		ListWidgetItem_UnsetInteractive(self->hoveredItem);		if (NULL != clone)	{		ListWidget_DestroyAllCommands(clone, cloneSize);		free(clone);	}	if (FALSE != GetCursorPos(&pt))	{		ListWidgetItem *tooltipItem;		ListWidgetItemPart tooltipItemPart;		RECT tooltipItemPartRect;		tooltipItem = ListWidget_TooltipGetCurrent(self->tooltip, &tooltipItemPart, &tooltipItemPartRect);		MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);		ListWidget_UpdateHoverEx(self, hwnd, &pt);		if (FALSE != ListWidget_TooltipGetChanged(self->tooltip, tooltipItem, 											tooltipItemPart, &tooltipItemPartRect))		{			ListWidget_TooltipRelayMouseMessage(self->tooltip, WM_MOUSEMOVE, 0, &pt);		}	}		if (FALSE != invalidated)		UpdateWindow(hwnd);	return TRUE;}static void CALLBACKListWidget_ShowCommandTimerCb(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD elpasedTime){	ListWidget *self;		KillTimer(hwnd, eventId);	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self)		return;	if (NULL != self->hoveredItem && 		FALSE == ListWidgetItem_IsInteractive(self->hoveredItem) &&		NULL == self->activeMenu)	{		ListWidget_UpdateActiveCommands(self, hwnd);	}}static void CALLBACKListWidget_ProgressTickCb(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD elpasedTime){	ListWidget *self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self)	{		KillTimer(hwnd, eventId);		return;	}	size_t index = self->activeItems.size();	if (index > 0)	{		POINT origin;		RECT rect;		ListWidgetItemMetric metrics, *metrics_ptr;		WidgetStyle *style;		if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))		{			origin.x = 0;			origin.y = 0;		}		style = WIDGET_GET_STYLE(hwnd);		if (NULL != style && FALSE != ListWidget_GetItemMetrics(style, &metrics))			metrics_ptr = &metrics;		else			metrics_ptr = NULL;		while(index--)		{			ListWidgetItem *item = self->activeItems[index];			item->activity->step++;			if (item->activity->step >= LISTWIDGET_PROGRESS_FRAME_COUNT)				item->activity->step = 1;						if (FALSE != ListWidget_GetItemActivityProgressRect(self, NULL, item, metrics_ptr, &rect))			{				OffsetRect(&rect, origin.x, origin.y);				InvalidateRect(hwnd, &rect, FALSE);			}		}	}	else	{		KillTimer(hwnd, eventId);		self->activityTimerEnabled = FALSE;	}}static void CALLBACKListWidget_BeginTitleEditTimerCb(HWND hwnd, UINT uMsg, UINT_PTR eventId, DWORD elpasedTime){	ListWidget *self;	self = WIDGET_GET_SELF(hwnd, ListWidget);	KillTimer(hwnd, eventId);	if (NULL != self && 		NULL != self->titleEditItem)	{		if (self->titleEditItem == self->selectedItem)		{			if (NULL != self->titleEditor)			{				DestroyWindow(self->titleEditor);				self->titleEditor = NULL;			}			self->titleEditor = ListWidget_BeginItemTitleEdit(self, hwnd, self->titleEditItem);		}				self->titleEditItem = NULL;	}}BOOLListWidget_UpdateHoverEx(ListWidget *self, HWND hwnd, const POINT *cursor){	ListWidgetItem *hoveredItem;	ListWidgetItemMetric metrics, *metrics_ptr;	WidgetStyle *style;	ListWidgetItemPart hoveredPart = ListWidgetItemPart_None;	RECT rect, hoveredPartRect;	POINT pt, origin;	if (NULL == cursor)		return FALSE;	metrics_ptr = NULL;	pt = *cursor;	if (NULL != self->pressedCategory ||		NULL != self->activeMenu || 		0 != (0x8000 & GetAsyncKeyState(VK_LBUTTON)) ||		0 != (0x8000 & GetAsyncKeyState(VK_RBUTTON)))	{		return FALSE;	}		if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))	{		origin.x = 0;		origin.y = 0;	}	if (FALSE != GetClientRect(hwnd, &rect) &&		FALSE != PtInRect(&rect, pt))	{				pt.x -= origin.x;		pt.y -= origin.y;		hoveredItem = ListWidget_GetItemFromPoint(self, pt);		if (NULL != hoveredItem)		{			if (NULL == metrics_ptr)			{				style = WIDGET_GET_STYLE(hwnd);							if (NULL != style && 					FALSE != ListWidget_GetItemMetrics(style, &metrics))				{					metrics_ptr = &metrics;				}			}			hoveredPart =	ListWidgetItemPart_Frame | 							ListWidgetItemPart_Command | 							ListWidgetItemPart_Spacebar | 							ListWidgetItemPart_Title;			hoveredPart = ListWidget_GetItemPartFromPoint(self, hoveredItem, metrics_ptr, pt, hoveredPart, &hoveredPartRect);		}	}	else		hoveredItem = NULL;		if (NULL == hoveredItem)		hoveredPart= ListWidgetItemPart_None;	ListWidget_TooltipUpdate(self->tooltip, hoveredItem, hoveredPart, &hoveredPartRect);		if (ListWidgetItemPart_None == ((ListWidgetItemPart_Frame | ListWidgetItemPart_Command | ListWidgetItemPart_Activity) & hoveredPart))		hoveredItem = NULL;		if (self->hoveredItem == hoveredItem)		return FALSE;		if (NULL == metrics_ptr)	{		style = WIDGET_GET_STYLE(hwnd);			if (NULL != style && 			FALSE != ListWidget_GetItemMetrics(style, &metrics))		{			metrics_ptr = &metrics;		}	}		if (NULL != self->hoveredItem)	{		ListWidgetItem_UnsetHovered(self->hoveredItem);		ListWidgetItem_UnsetInteractive(self->hoveredItem);				if (NULL == metrics_ptr || 			FALSE == ListWidget_GetItemFrameRect(self, self->hoveredItem, metrics_ptr, &rect))		{			CopyRect(&rect, &self->hoveredItem->rect);		}				OffsetRect(&rect, origin.x, origin.y);		InvalidateRect(hwnd, &rect, FALSE);	}		if (NULL != hoveredItem)	{		ListWidgetItem_SetHovered(hoveredItem);		if (NULL == metrics_ptr || 			FALSE == ListWidget_GetItemFrameRect(self, hoveredItem, metrics_ptr, &rect))		{			CopyRect(&rect, &hoveredItem->rect);		}		OffsetRect(&rect, origin.x, origin.y);		InvalidateRect(hwnd, &rect, FALSE);		SetTimer(hwnd, LISTWIDGETTIMER_SHOW_COMMANDS_ID, 					LISTWIDGETTIMER_SHOW_COMMANDS_DELAY, 					ListWidget_ShowCommandTimerCb);	}	else		KillTimer(hwnd, LISTWIDGETTIMER_SHOW_COMMANDS_ID);	self->hoveredItem = hoveredItem;			return TRUE;}BOOLListWidget_UpdateHover(ListWidget *self, HWND hwnd){	POINT pt;	if (FALSE == GetCursorPos(&pt))		return FALSE;		MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);	return ListWidget_UpdateHoverEx(self, hwnd, &pt);}BOOLListWidget_RemoveHover(ListWidget *self, HWND hwnd, BOOL invalidate){	if (NULL == self)		return FALSE;	if (NULL == self->hoveredItem)		return FALSE;	ListWidgetItem_UnsetHovered(self->hoveredItem);	ListWidgetItem_UnsetInteractive(self->hoveredItem);	KillTimer(hwnd, LISTWIDGETTIMER_SHOW_COMMANDS_ID);	if (FALSE != invalidate)	{		RECT rect;		POINT origin;		ListWidgetItemMetric metrics;		WidgetStyle *style;				style = WIDGET_GET_STYLE(hwnd);		if (NULL == style ||			FALSE == ListWidget_GetItemMetrics(style, &metrics) ||			FALSE == ListWidget_GetItemFrameRect(self, self->hoveredItem, &metrics, &rect))		{			CopyRect(&rect, &self->hoveredItem->rect);		}		if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))			OffsetRect(&rect, origin.x, origin.y);		InvalidateRect(hwnd, &rect, FALSE);	}	self->hoveredItem = NULL;	return TRUE;}voidListWidget_UpdateSelectionStatus(ListWidget *self, HWND hwnd, BOOL ensureVisible){	HWND statusWindow;	if (NULL == self)		return;	statusWindow = GetParent(hwnd);	if (NULL == statusWindow)		return;	statusWindow = MANAGERVIEW_GET_STATUS_BAR(statusWindow);	if (NULL == statusWindow)		return;			if (NULL != self->selectedItem)	{		wchar_t buffer[2048] = {0};		const wchar_t *statusString;		if (FALSE == ListWidget_FormatItemStatus(self, self->selectedItem, buffer, ARRAYSIZE(buffer)) ||			L'\0' == *buffer)		{			statusString = NULL;		}		else			statusString = buffer;				if (STATUS_ERROR == self->selectionStatus)		{			self->selectionStatus = STATUSBAR_ADD_STATUS(statusWindow, statusString);			if (STATUS_ERROR != self->selectionStatus)			{				if (FALSE == ListWidget_FormatItemSpaceStatus(self, self->selectedItem, buffer, ARRAYSIZE(buffer)) ||					L'\0' == *buffer)				{					statusString = NULL;				}				else					statusString = buffer;				STATUSBAR_SET_STATUS_RTEXT(statusWindow, self->selectionStatus, statusString); 			}		}		else		{			STATUSBAR_SET_STATUS_TEXT(statusWindow, self->selectionStatus, statusString);			if (FALSE == ListWidget_FormatItemSpaceStatus(self, self->selectedItem, buffer, ARRAYSIZE(buffer)) ||					L'\0' == *buffer)			{				statusString = NULL;			}			else				statusString = buffer;			STATUSBAR_SET_STATUS_RTEXT(statusWindow, self->selectionStatus, statusString); 			if (FALSE != ensureVisible)			{				STATUSBAR_MOVE_STATUS(statusWindow, self->selectionStatus, STATUS_MOVE_TOP);			}		}	}	else	{		if (STATUS_ERROR != self->selectionStatus)		{			STATUSBAR_REMOVE_STATUS(statusWindow, self->selectionStatus);			self->selectionStatus = STATUS_ERROR;		}	}}voidListWidget_UpdateSelectionSpaceStatus(ListWidget *self, HWND hwnd, BOOL ensureVisible){	HWND statusWindow;	if (NULL == self)		return;	statusWindow = GetParent(hwnd);	if (NULL == statusWindow)		return;	statusWindow = MANAGERVIEW_GET_STATUS_BAR(statusWindow);	if (NULL == statusWindow)		return;			if (NULL != self->selectedItem &&		STATUS_ERROR != self->selectionStatus)	{		wchar_t buffer[2048] = {0};		const wchar_t *statusString;		if (FALSE == ListWidget_FormatItemSpaceStatus(self, self->selectedItem, buffer, ARRAYSIZE(buffer)) ||				L'\0' == *buffer)		{			statusString = NULL;		}		else			statusString = buffer;		STATUSBAR_SET_STATUS_RTEXT(statusWindow, self->selectionStatus, statusString); 		if (FALSE != ensureVisible)			STATUSBAR_MOVE_STATUS(statusWindow, self->selectionStatus, STATUS_MOVE_TOP);	}}BOOLListWidget_SelectItem(ListWidget *self, HWND hwnd, ListWidgetItem *item, BOOL ensureVisible){	BOOL invalidated;		if (NULL == self)		return FALSE;	invalidated = FALSE;	if (self->selectedItem != item)	{		RECT rect;		POINT origin;		ListWidgetItemMetric metrics, *metrics_ptr;		WidgetStyle *style;		if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))		{			origin.x = 0;			origin.y = 0;		}		style = WIDGET_GET_STYLE(hwnd);		if (NULL != style && 			FALSE != ListWidget_GetItemMetrics(style, &metrics))		{			metrics_ptr = &metrics;		}		else			metrics_ptr = NULL;		if (NULL != self->selectedItem)		{			ListWidgetItem_UnsetSelected(self->selectedItem);			if (NULL == metrics_ptr ||				FALSE == ListWidget_GetItemFrameRect(self, self->selectedItem, metrics_ptr, &rect))			{				CopyRect(&rect, &self->selectedItem->rect);			}			OffsetRect(&rect, origin.x, origin.y);			if (FALSE != InvalidateRect(hwnd, &rect, FALSE))				invalidated = TRUE;		}				if (NULL != item)		{			ListWidgetItem_SetSelected(item);						if (NULL == metrics_ptr ||				FALSE == ListWidget_GetItemFrameRect(self, item, metrics_ptr, &rect))			{				CopyRect(&rect, &item->rect);			}			OffsetRect(&rect, origin.x, origin.y);			if (FALSE != InvalidateRect(hwnd, &rect, FALSE))				invalidated = TRUE;		}		self->selectedItem = item;	}	if (FALSE != ensureVisible)	{		if (FALSE != ListWidget_EnsureItemVisisble(self, hwnd, item, VISIBLE_NORMAL))			invalidated = TRUE;	}	if (FALSE != invalidated)		UpdateWindow(hwnd);	ListWidget_UpdateSelectionStatus(self, hwnd, TRUE);		return TRUE;}static void ListWidget_EnsureFocused(ListWidget *self, HWND hwnd, BOOL forceSelect){	HWND hDialog, hParent;	if (NULL == self || NULL == hwnd)		return;	if (GetFocus() == hwnd)		return;		hDialog = NULL;	hParent = hwnd;	while(NULL != (hParent = GetAncestor(hParent, GA_PARENT)))	{		if (32770 != GetClassLongPtr(hParent, GCW_ATOM) ||			0 == (WS_EX_CONTROLPARENT & GetWindowStyleEx(hParent)))		{			break;		}				hDialog = hParent;	}	self->flags |= ListWidgetFlag_NoFocusSelect;	if (NULL != hDialog)		SendMessage(hDialog, WM_NEXTDLGCTL, (WPARAM)hwnd, TRUE);	else 		SetFocus(hwnd);	self->flags &= ~ListWidgetFlag_NoFocusSelect;}static BOOLListWidget_EnsureTopVisible(ListWidget *self, HWND hwnd){	POINT pt;		if (NULL == self || NULL == hwnd)		return FALSE;		if (FALSE == ListWidget_GetViewOrigin(hwnd, &pt) || 		(0 == pt.x && 0 == pt.y))	{		return FALSE;	}	if (FALSE == WIDGET_SCROLL(hwnd, pt.x, pt.y, TRUE))		return FALSE;		ListWidget_UpdateHover(self, hwnd);		return TRUE;}static BOOLListWidget_EnsureBottomVisible(ListWidget *self, HWND hwnd){	SCROLLINFO scrollInfo;	POINT pt;	if (NULL == self || NULL == hwnd)		return FALSE;	scrollInfo.cbSize = sizeof(scrollInfo);	scrollInfo.fMask = SIF_POS | SIF_RANGE | SIF_PAGE;			if (FALSE != GetScrollInfo(hwnd, SB_HORZ, &scrollInfo))		pt.x = -scrollInfo.nPos;	else		pt.x = 0;	if (FALSE != GetScrollInfo(hwnd, SB_VERT, &scrollInfo) && 0 != scrollInfo.nPage)		pt.y = (scrollInfo.nMax + 1 - scrollInfo.nPage) - scrollInfo.nPos;	else		pt.y = 0;	if (0 == pt.x && 0 == pt.y)		return FALSE;		if (FALSE == WIDGET_SCROLL(hwnd, pt.x, pt.y, TRUE))		return FALSE;		ListWidget_UpdateHover(self, hwnd);		return TRUE;}BOOLListWidget_UpdateLayout(HWND hwnd, ListWidgetLayoutFlags layoutFlags){	BOOL result;	unsigned int flags;	ListWidget *self;	POINT anchorPoint;	ListWidgetItem *anchorItem;	SCROLLINFO scrollInfo;	HWND managerWindow, focusWindow;	POINT pt, menuAnchor, hoverAnchor;	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self)		return FALSE;	if (NULL == self->activeMenu ||		NULL == self->selectedItem ||		FALSE == ListWidget_GetViewItemPos(hwnd, self->selectedItem, &menuAnchor))	{		menuAnchor.x = 0x7FFFFFFF;		menuAnchor.y = 0x7FFFFFFF;	}	if (NULL != self->hoveredItem ||		FALSE == ListWidget_GetViewItemPos(hwnd, self->hoveredItem, &hoverAnchor))	{		hoverAnchor.x = 0x7FFFFFFF;		hoverAnchor.y = 0x7FFFFFFF;	}	scrollInfo.cbSize = sizeof(scrollInfo);	scrollInfo.fMask = SIF_POS;	anchorItem = NULL;	managerWindow = GetAncestor(hwnd, GA_PARENT);	if (NULL == managerWindow)		managerWindow = hwnd;	focusWindow = GetFocus();	if (0 != (ListWidgetLayout_KeepStable & layoutFlags) &&		(managerWindow == focusWindow || IsChild(managerWindow, focusWindow)))	{		if (NULL != self->selectedItem)		{			RECT clientRect;				GetClientRect(hwnd, &clientRect);			anchorPoint.x = (FALSE != GetScrollInfo(hwnd, SB_HORZ, &scrollInfo)) ?							-scrollInfo.nPos : 0;			anchorPoint.y = (FALSE != GetScrollInfo(hwnd, SB_VERT, &scrollInfo)) ?							-scrollInfo.nPos : 0;			OffsetRect(&clientRect, -anchorPoint.x, -anchorPoint.y);			if (clientRect.left <= self->selectedItem->rect.left &&				clientRect.top <= self->selectedItem->rect.top &&				clientRect.right >= self->selectedItem->rect.right &&				clientRect.bottom >= self->selectedItem->rect.bottom)			{				anchorItem = self->selectedItem;				anchorPoint.x += self->selectedItem->rect.left;				anchorPoint.y += self->selectedItem->rect.top;			}		}	}	flags = SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOSIZE | 			SWP_FRAMECHANGED | SWP_NOREDRAW;		result = SetWindowPos(hwnd, NULL, 0, 0, 0, 0, flags);	if (NULL != anchorItem)	{		long positionY;			positionY = anchorItem->rect.top;		if (FALSE != GetScrollInfo(hwnd, SB_VERT, &scrollInfo))			positionY -= scrollInfo.nPos;				if (positionY != anchorPoint.y)			WIDGET_SET_SCROLL_POS(hwnd, 0, positionY - anchorPoint.y, FALSE);	}	if (0x7FFFFFFF != menuAnchor.x &&		NULL != self->selectedItem &&		FALSE != ListWidget_GetViewItemPos(hwnd, self->selectedItem, &pt) &&		menuAnchor.x != pt.x && menuAnchor.y != pt.y)	{		if (NULL != self->activeMenu)			EndMenu();	}	if (0x7FFFFFFF != hoverAnchor.x &&		NULL != self->hoveredItem &&		FALSE != ListWidget_GetViewItemPos(hwnd, self->hoveredItem, &pt) &&		hoverAnchor.x != pt.x && hoverAnchor.y != pt.y)	{		ListWidget_UpdateHover(self, hwnd);	}	if (0 == (ListWidgetLayout_NoRedraw & layoutFlags))	{		flags = RDW_INVALIDATE | RDW_ALLCHILDREN | RDW_FRAME | RDW_ERASE;				if (0 != (ListWidgetLayout_UpdateNow & layoutFlags))			flags |= (RDW_ERASENOW | RDW_UPDATENOW);		RedrawWindow(hwnd, NULL, NULL, flags);	}	return result;}double ListWidget_GetZoomRatio(ListWidget *self){	if (NULL == self)		return 1.0;		if (self->imageSize.cy > LISTWIDGET_IMAGE_DEFAULT_HEIGHT)	{		return (1.0 + (double)(self->imageSize.cy - LISTWIDGET_IMAGE_DEFAULT_HEIGHT)/						(LISTWIDGET_IMAGE_MAX_HEIGHT - LISTWIDGET_IMAGE_DEFAULT_HEIGHT));	}		return (double)(self->imageSize.cy - LISTWIDGET_IMAGE_MIN_HEIGHT)/			(LISTWIDGET_IMAGE_DEFAULT_HEIGHT - LISTWIDGET_IMAGE_MIN_HEIGHT);	}longListWidget_GetZoomedValue(double zoomRatio, long normal, long min, long max){	if (zoomRatio < 1.0)		return min + (long)floor((double)(normal - min) * zoomRatio);	else if (zoomRatio > 1.0)		return normal + (long)ceil((double)(max - normal) * (zoomRatio - 1.0));	return normal;}static BOOL ListWidget_UpdateActivityLayout(ListWidget *self, HWND hwnd, double zoomRatio){	LOGFONTW lf;	HDC windowDC;	long elementHeight, titleMinWidth, workHeight;	ListWidgetItem *item;	ListWidgetActivityMetric *activityMetrics;	// always reset items activity size cache	size_t index = (self ? self->activeItems.size() : NULL);	while(index--)	{		item = self->activeItems[index];		if (NULL != item)			SetSizeEmpty(&item->activity->titleSize);	}	if (NULL == self)		return FALSE;	activityMetrics = &self->activityMetrics;	activityMetrics->offsetLeft = self->activityMetrics.height/16;	if (activityMetrics->offsetLeft < 1)		activityMetrics->offsetLeft = 1;	activityMetrics->offsetRight = activityMetrics->offsetLeft;	activityMetrics->offsetTop = self->activityMetrics.height/9;	if (activityMetrics->offsetTop < 3)		activityMetrics->offsetTop = 3;	activityMetrics->offsetBottom = activityMetrics->offsetTop;	activityMetrics->spacing = 4 + self->activityMetrics.height/16;	workHeight = activityMetrics->height - (activityMetrics->offsetTop + activityMetrics->offsetBottom);	activityMetrics->fontHeight = workHeight/2;	if (activityMetrics->fontHeight < 8)		activityMetrics->fontHeight = 8;	if (NULL == self->activityFont ||		sizeof(lf) != GetObject(self->activityFont, sizeof(lf), &lf) ||		lf.lfHeight != activityMetrics->fontHeight)	{		if (NULL != self->activityFont)			DeleteObject(self->activityFont);		lf.lfHeight = activityMetrics->fontHeight;		lf.lfWidth = 0;		lf.lfEscapement = 0;		lf.lfOrientation = 0;		lf.lfWeight = FW_NORMAL;		lf.lfItalic = FALSE;		lf.lfUnderline = FALSE;		lf.lfStrikeOut = FALSE;		lf.lfCharSet = DEFAULT_CHARSET;		lf.lfOutPrecision = OUT_TT_PRECIS;		lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;		lf.lfQuality = Graphics_GetSysFontQuality();		lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;		StringCchCopy(lf.lfFaceName, ARRAYSIZE(lf.lfFaceName), L"Arial"/*L"Times New Roman"*/);		self->activityFont = CreateFontIndirect(&lf); 	}	activityMetrics->titleHeight = workHeight;	if (activityMetrics->titleHeight < 0)		activityMetrics->titleHeight = 0;	activityMetrics->titleWidth = 0;	activityMetrics->percentWidth = 0;	activityMetrics->percentHeight = 0;	titleMinWidth = 0;	windowDC = GetWindowDC(hwnd);	if (NULL != windowDC)	{		SIZE textSize;		HFONT prevFont;		prevFont = SelectFont(windowDC, self->activityFont);		if (FALSE == GetTextExtentPoint32(windowDC, L"00%", 3, &textSize))			SetSizeEmpty(&textSize);		if (textSize.cy <= workHeight)		{			activityMetrics->fontHeight = textSize.cy;			activityMetrics->percentHeight = textSize.cy;			activityMetrics->percentWidth = textSize.cx;		}		titleMinWidth = Graphics_GetAveStrWidth(windowDC, 6);		activityMetrics->spacing = Graphics_GetAveStrWidth(windowDC, 1) - 2;	}		if (NULL != self->activityBadgeBitmap)	{		DeleteObject(self->activityBadgeBitmap);		self->activityBadgeBitmap = NULL;	}	elementHeight = (long)(18.0 * (double)workHeight/28.0);	if (activityMetrics->progressWidth != elementHeight ||		activityMetrics->progressHeight != elementHeight)	{		activityMetrics->progressWidth = elementHeight;		activityMetrics->progressHeight = elementHeight;		if (NULL != self->activityProgressImage)		{			DeviceImage_Release(self->activityProgressImage);			self->activityProgressImage = NULL;		}	}	for(;;)	{		activityMetrics->titleWidth = activityMetrics->width - 									(activityMetrics->offsetLeft + activityMetrics->offsetRight);		if(0 != activityMetrics->progressWidth)			activityMetrics->titleWidth -= (activityMetrics->progressWidth + activityMetrics->spacing);		if(0 != activityMetrics->percentWidth)			activityMetrics->titleWidth -= (activityMetrics->percentWidth + activityMetrics->spacing);		if (activityMetrics->titleWidth < titleMinWidth)		{			if (0 != activityMetrics->percentWidth)			{				activityMetrics->percentWidth = 0;				activityMetrics->percentHeight = 0;				continue;			}			if (0 != activityMetrics->progressWidth)			{				activityMetrics->progressWidth = 0;				activityMetrics->progressHeight = 0;				continue;			}			activityMetrics->titleWidth = 0;			activityMetrics->titleHeight = 0;		}		break;	}	return TRUE;}BOOLListWidget_SetImageSize(ListWidget *self, HWND hwnd, int imageWidth, int imageHeight, BOOL redraw){	size_t iCategory, iGroup, iItem;	ListWidgetCategory *category;	ListWidgetGroup	*group;	ListWidgetItem *item;	long elementWidth, elementHeight;	double zoomRatio;	if (NULL == self)		return FALSE;	SetSize(&self->imageSize, imageWidth, imageHeight);	zoomRatio = ListWidget_GetZoomRatio(self);	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 (NULL != item->image)				{					DeviceImage_Release(item->image);					item->image = NULL;				}				SetSize(&item->titleSize, -1, -1);			}		}	}	// connetion size	elementHeight = ListWidget_GetZoomedValue(zoomRatio, LISTWIDGET_CONNECTION_DEFAULT_HEIGHT, 						LISTWIDGET_CONNECTION_MIN_HEIGHT, LISTWIDGET_CONNECTION_MAX_HEIGHT);	elementWidth = elementHeight;	if (self->connectionSize.cx != elementWidth ||		self->connectionSize.cy != elementHeight)	{		SetSize(&self->connectionSize, elementWidth, elementHeight);		int index = (int)self->connections.size();		while (index--)		{			ListWidget_UpdateConnectionImageSize(self->connections[index], 				self->connectionSize.cx, self->connectionSize.cy);		}	}	// primary command	elementHeight = ListWidget_GetZoomedValue(zoomRatio, LISTWIDGET_PRIMARYCOMMAND_DEFAULT_HEIGHT, 						LISTWIDGET_PRIMARYCOMMAND_MIN_HEIGHT, LISTWIDGET_PRIMARYCOMMAND_MAX_HEIGHT);	elementWidth =  self->imageSize.cx;	if (self->primaryCommandSize.cx != elementWidth ||		self->primaryCommandSize.cy != elementHeight)	{		SetSize(&self->primaryCommandSize, elementWidth, elementHeight);	}	// secondary command	elementHeight = ListWidget_GetZoomedValue(zoomRatio, LISTWIDGET_SECONDARYCOMMAND_DEFAULT_HEIGHT, 						LISTWIDGET_SECONDARYCOMMAND_MIN_HEIGHT, LISTWIDGET_SECONDARYCOMMAND_MAX_HEIGHT);	elementWidth = elementHeight;	if (self->secondaryCommandSize.cx != elementWidth ||		self->secondaryCommandSize.cy != elementHeight)	{		SetSize(&self->secondaryCommandSize, elementWidth, elementHeight);	}	// activity	elementHeight = ListWidget_GetZoomedValue(zoomRatio, LISTWIDGET_ACTIVITY_DEFAULT_HEIGHT, 						LISTWIDGET_ACTIVITY_MIN_HEIGHT, LISTWIDGET_ACTIVITY_MAX_HEIGHT);	elementWidth = self->imageSize.cx;	if (self->activityMetrics.width != elementWidth ||		self->activityMetrics.height != elementHeight)	{		self->activityMetrics.width = elementWidth;		self->activityMetrics.height = elementHeight;	}		ListWidget_UpdateLayout(hwnd, ListWidgetLayout_NoRedraw);		if (NULL != self->hoveredItem && 		FALSE != ListWidgetItem_IsInteractive(self->hoveredItem))	{		ListWidget_UpdateActiveCommands(self, hwnd);	}	ListWidget_UpdateActivityLayout(self, hwnd, zoomRatio);	if (FALSE != redraw)		{		RedrawWindow(hwnd, NULL, NULL, 			RDW_INVALIDATE | RDW_ERASE | RDW_ERASENOW | RDW_UPDATENOW | RDW_ALLCHILDREN);	}		return TRUE;}BOOLListWidget_DisplayContextMenu(ListWidget *self, HWND hostWindow, POINT pt){	return FALSE;}BOOLListWidget_RegisterActiveItem(ListWidget *self, HWND hwnd, ListWidgetItem *item){	size_t index;	if (NULL == self || NULL == item)		return FALSE;	index = self->activeItems.size();	while(index--)	{		if (item == self->activeItems[index])			return FALSE;	}	self->activeItems.push_back(item);	if (1 == self->activeItems.size())	{		if (0 != SetTimer(hwnd, LISTWIDGETTIMER_PROGRESS_TICK_ID, 					LISTWIDGETTIMER_PROGRESS_TICK_DELAY, ListWidget_ProgressTickCb))		{			self->activityTimerEnabled = TRUE;		}	}	return TRUE;}BOOLListWidget_UnregisterActiveItem(ListWidget *self, HWND hwnd, ListWidgetItem *item){	size_t index;	if (NULL == self || NULL == item)		return FALSE;	index = self->activeItems.size();	while(index--)	{		if (item == self->activeItems[index])		{			self->activeItems.erase(self->activeItems.begin() + index);			if (0 == self->activeItems.size())			{				KillTimer(hwnd, LISTWIDGETTIMER_PROGRESS_TICK_ID);				self->activityTimerEnabled = FALSE;			}			return TRUE;		}	}	return FALSE;}static void ListWidget_CallItemAction(ListWidget *self, HWND hwnd, ListWidgetCategory *category, ListWidgetItem *item){	ifc_device *device;	if (NULL == self || NULL == item)		return;	if (NULL == category)	{		if (FALSE == ListWidget_GetItemOwner(self, item, &category) ||			NULL == category)		{			return;		}	}	if (NULL == WASABI_API_DEVICES ||		S_OK != WASABI_API_DEVICES->DeviceFind(item->name, &device))	{		return;	}	if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, category->name, -1, "discovered", -1))	{		if (FALSE == device->GetAttached())			device->Attach(NULL);	}	if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, category->name, -1, "attached", -1))	{		Navigation_SelectDevice(device->GetName());	}	device->Release();}static BOOLListWidget_AddDevicesToCategory(ListWidget *self, ListWidgetCategory *category, DeviceList *list){	ListWidgetGroup *group;	ListWidgetItem *item;	ifc_device *device;	size_t index, groupCount, categoryCount;	if (NULL == list || NULL == category)		return FALSE;	categoryCount = category->groups.size();	index = list->size();	if (0 == index)		return FALSE;	do	{		index--;		device = list->at(index);		const char *groupName = device->GetType();		group = ListWidget_FindGroupEx(category, groupName, categoryCount);		if (NULL == group)		{			group = ListWidget_CreateGroup(groupName);			if (NULL != group)				ListWidget_AddGroup(category, group);		}				if (NULL != group)		{			groupCount = group->items.size();			item = ListWidget_FindGroupItemEx(group, device->GetName(), groupCount);			if (NULL == item)			{				item = ListWidget_CreateItemFromDevice(self, device);				if (NULL != item)				{					ListWidget_AddItem(group, item);					if (NULL != item->activity)						self->activeItems.push_back(item);				}			}		}		else			groupCount = 0;		list->erase(list->begin() + index);		device->Release();		while(index--)		{			device = list->at(index);			if (CSTR_EQUAL == CompareStringA(CSTR_INVARIANT, 0, groupName, -1, device->GetType(), -1))			{				if (NULL != group)				{					item = ListWidget_FindGroupItemEx(group, device->GetName(), groupCount);					if (NULL == item)					{						item = ListWidget_CreateItemFromDevice(self, device);						if (NULL != item)						{							ListWidget_AddItem(group, item);							if (NULL != item->activity)							{								self->activeItems.push_back(item);							}						}					}				}				list->erase(list->begin() + index);				device->Release();			}		}		if (NULL != group)			ListWidget_SortGroup(group);		index = list->size();	} while(0 != index);	ListWidget_SortCategory(category);	return TRUE;}static voidListWidget_AddExistingDevices(ListWidget *self, HWND hwnd){	DeviceList discoveredList, attachedList;	ifc_device *device;	ListWidgetCategory *category;	size_t index, activeItemsCount;	BOOL devicesAdded;	if (NULL == self)		return;	activeItemsCount = self->activeItems.size();	if (NULL != WASABI_API_DEVICES)	{		ifc_deviceobjectenum *enumerator;		if (SUCCEEDED(WASABI_API_DEVICES->DeviceEnumerate(&enumerator)))		{			size_t reserveSize;			ifc_deviceobject *object;			if (SUCCEEDED(enumerator->GetCount(&reserveSize)))			{				discoveredList.reserve(reserveSize);				attachedList.reserve(reserveSize);			}			while(S_OK == enumerator->Next(&object, 1, NULL))			{				if (SUCCEEDED(object->QueryInterface(IFC_Device, (void**)&device)))				{					if (FALSE == device->GetHidden() &&						// excludes 'cloud' devices from appearing						lstrcmpiA(device->GetConnection(), "cloud"))					{						if (FALSE == device->GetAttached())							discoveredList.push_back(device);						else							attachedList.push_back(device);					}					else						device->Release();				}				object->Release();			}			enumerator->Release();		}	}	devicesAdded = FALSE;	if (0 != attachedList.size())	{		category = ListWidget_FindCategory(self, "attached");		if (NULL != category)		{			if (FALSE != ListWidget_AddDevicesToCategory(self, category, &attachedList))			{				ListWidget_ResetCategoryCounter(category);				devicesAdded = TRUE;			}		}		index = attachedList.size();		while(index--)			attachedList[index]->Release();	}	if (0 != discoveredList.size())	{		category = ListWidget_FindCategory(self, "discovered");		if (NULL != category)		{			if (FALSE != ListWidget_AddDevicesToCategory(self, category, &discoveredList))			{				ListWidget_ResetCategoryCounter(category);				devicesAdded = TRUE;			}		}		index = discoveredList.size();		while(index--)			discoveredList[index]->Release();	}	if (self->activeItems.size() > 0)	{		if (0 == activeItemsCount)		{			if (0 != SetTimer(hwnd, LISTWIDGETTIMER_PROGRESS_TICK_ID, 						LISTWIDGETTIMER_PROGRESS_TICK_DELAY, ListWidget_ProgressTickCb))			{				self->activityTimerEnabled = TRUE;			}		}	}	else	{		if (0 != activeItemsCount)		{			KillTimer(hwnd, LISTWIDGETTIMER_PROGRESS_TICK_ID);			self->activityTimerEnabled = FALSE;		}	}	if (FALSE != devicesAdded)	{		ListWidget_UpdateLayout(hwnd, ListWidgetLayout_Normal);	}}void ListWidget_UpdateTitleEditorColors(HWND editor, WidgetStyle *style){	if (NULL == editor || NULL == style)		return;	EMBEDDEDEDITOR_SET_TEXT_COLOR(editor, WIDGETSTYLE_TEXT_COLOR(style));	EMBEDDEDEDITOR_SET_BACK_COLOR(editor, WIDGETSTYLE_BACK_COLOR(style));	EMBEDDEDEDITOR_SET_BORDER_COLOR(editor, WIDGETSTYLE_TEXT_EDITOR_BORDER_COLOR(style));	InvalidateRect(editor, NULL, TRUE);}static BOOL ListWidget_DeviceAdd(HWND hwnd, ifc_device *device, DeviceImage *deviceImage){	ListWidget *self;	ListWidgetCategory *category;	ListWidgetGroup *group;	ListWidgetItem *item;	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self)		return FALSE;	if (NULL == self || 		NULL == device || 		FALSE != device->GetHidden() &&		// excludes 'cloud' devices from appearing		lstrcmpiA(device->GetConnection(), "cloud"))	{		return FALSE;	}	category = ListWidget_FindCategory(self, (FALSE != device->GetAttached()) ? "attached" : "discovered");	if (NULL == category)		return FALSE;	group = ListWidget_FindGroup(category, device->GetType());	if (NULL == group)	{		group = ListWidget_CreateGroup(device->GetType());		if (NULL == group)			return FALSE;		ListWidget_AddGroup(category, group);		ListWidget_SortCategory(category);	}	item = ListWidget_FindGroupItem(group, device->GetName());	if (NULL != item)		return FALSE;	item = ListWidget_CreateItemFromDevice(self, device);	if (NULL == item)		return NULL;	if (NULL == item->image && NULL != deviceImage)	{		item->image = deviceImage;		DeviceImage_AddRef(item->image);	}	ListWidget_AddItem(group, item);	ListWidget_SortGroup(group);	if (NULL != item->activity)		ListWidget_RegisterActiveItem(self, hwnd, item);	ListWidget_ResetCategoryCounter(category);	if (FALSE == category->collapsed)	{		ListWidget_UpdateLayout(hwnd, 					ListWidgetLayout_UpdateNow | ListWidgetLayout_KeepStable);	}	else	{		RECT rect;		POINT origin;		CopyRect(&rect, &category->rect);		if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))			OffsetRect(&rect, origin.x, origin.y);				InvalidateRect(hwnd, &rect, FALSE);	}	return TRUE;}static BOOL ListWidget_DeviceRemove(HWND hwnd, ifc_device *device){	ListWidget *self;	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	ListWidget_RemoveItem(self, hwnd, device->GetName());	ListWidget_UpdateHover(self, hwnd);	return TRUE;}static BOOLListWidget_DeviceAttach(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetCategory *category;	ListWidgetItem *item;	DeviceImage *image;	BOOL result;	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	image = NULL;	category = ListWidget_FindCategory(self, "discovered");	if (NULL != category)	{		ListWidgetGroup *group = ListWidget_FindGroup(category, device->GetType());		if (NULL != group)		{			item = ListWidget_FindGroupItem(group, device->GetName());			if (NULL != item)			{				image = item->image;				if (NULL != image)					DeviceImage_AddRef(image);				ListWidget_RemoveItem(self, hwnd, device->GetName());			}		}	}	result = ListWidget_DeviceAdd(hwnd, device, image);	if (NULL != image)		DeviceImage_Release(image);	return result;}static BOOLListWidget_DeviceDetach(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetCategory *category;	ListWidgetItem *item;	DeviceImage *image;	BOOL result;	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	image = NULL;	category = ListWidget_FindCategory(self, "attached");	if (NULL != category)	{		ListWidgetGroup *group = ListWidget_FindGroup(category, device->GetType());		if (NULL != group)		{			item = ListWidget_FindGroupItem(group, device->GetName());			if (NULL != item)			{				image = item->image;				if (NULL != image)					DeviceImage_AddRef(image);				ListWidget_RemoveItem(self, hwnd, device->GetName());			}		}	}	result = ListWidget_DeviceAdd(hwnd, device, image);		if (NULL != image)		DeviceImage_Release(image);	return result;}static BOOLListWidget_DeviceTitleChanged(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetItem *item;	ListWidgetCategory *category;	wchar_t buffer[1024] = {0};	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	item = ListWidget_FindItem(self, device->GetName(), &category, NULL);	if (NULL == item)		return FALSE;	if (FAILED(device->GetDisplayName(buffer, ARRAYSIZE(buffer))))		return FALSE;	ListWidget_SetItemTitle(item, buffer);	if (NULL == category ||		FALSE == category->collapsed)	{		ListWidget_UpdateLayout(hwnd, ListWidgetLayout_UpdateNow | ListWidgetLayout_KeepStable);		ListWidget_TooltipUpdateText(self, self->tooltip, item, Tooltip_DeviceTitleChanged);		if (STATUS_ERROR != self->selectionStatus &&			item == self->selectedItem)		{			ListWidget_UpdateSelectionStatus(self, hwnd, FALSE);		}	}	return TRUE;}static BOOLListWidget_DeviceSpaceChanged(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetItem *item;	ListWidgetCategory *category;		self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	item = ListWidget_FindItem(self, device->GetName(), &category, NULL);	if (NULL == item)		return FALSE;	if (FAILED(device->GetTotalSpace(&item->spaceTotal)))		return FALSE;	if (FAILED(device->GetUsedSpace(&item->spaceUsed)))		return FALSE;	if (NULL == category ||		FALSE == category->collapsed)	{		RECT rect;		POINT origin;		ListWidgetItemMetric metrics;		WidgetStyle *style;		CopyRect(&rect, &item->rect);		if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))			OffsetRect(&rect, origin.x, origin.y);		style = WIDGET_GET_STYLE(hwnd);		if (NULL != style && FALSE != ListWidget_GetItemMetrics(style, &metrics))		{			rect.top += metrics.offsetTop + 						metrics.imageOffsetTop + 						self->imageSize.cy + 						metrics.imageOffsetBottom + 						metrics.spacebarOffsetTop;			rect.left += metrics.offsetLeft;			rect.right -= metrics.offsetRight;			rect.bottom = rect.top + metrics.spacebarHeight;		}		InvalidateRect(hwnd, &rect, FALSE);		UpdateWindow(hwnd);		ListWidget_TooltipUpdateText(self, self->tooltip, item, Tooltip_DeviceSpaceChanged);		if (STATUS_ERROR != self->selectionStatus &&			item == self->selectedItem)		{			ListWidget_UpdateSelectionSpaceStatus(self, hwnd, FALSE);		}	}		return TRUE;}static BOOLListWidget_DeviceIconChanged(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetItem *item;	ListWidgetCategory *category;	DeviceImage *previousImage;	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	item = ListWidget_FindItem(self, device->GetName(), &category, NULL);	if (NULL == item)		return FALSE;	previousImage = item->image;	item->image = NULL;	if (NULL == category ||		FALSE == category->collapsed)	{		RECT rect;		POINT origin;		ListWidgetItemMetric metrics;		WidgetStyle *style;						style = WIDGET_GET_STYLE(hwnd);		if (NULL == style ||			FALSE == ListWidget_GetItemMetrics(style, &metrics) ||			FALSE == ListWidget_GetItemImageRect(self, item, &metrics, &rect))		{			CopyRect(&rect, &item->rect);		}		if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))			OffsetRect(&rect, origin.x, origin.y);		InvalidateRect(hwnd, &rect, FALSE);		UpdateWindow(hwnd);	}	if (NULL != previousImage)		DeviceImage_Release(previousImage);	return TRUE;}static BOOLListWidget_DeviceCommandChanged(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetItem *item;	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	item = ListWidget_FindItem(self, device->GetName(), NULL, NULL);	if (NULL == item)		return FALSE;	if (item == self->hoveredItem && 		NULL == self->activeMenu)	{		ListWidget_UpdateActiveCommands(self, hwnd);	}			return TRUE;}static BOOLListWidget_DeviceActivityStarted(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetItem *item;	ListWidgetCategory *category;	size_t index;	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	item = ListWidget_FindItem(self, device->GetName(), &category, NULL);	if (NULL == item)		return FALSE;	index = self->activeItems.size();	while(index--)	{		if (item == self->activeItems[index])			return FALSE;	}	if (FALSE != ListWidget_CreateItemActivity(item))	{		ifc_deviceactivity *activity;		ListWidget_RegisterActiveItem(self, hwnd, item);				if(S_OK == device->GetActivity(&activity) && 			NULL != activity)		{			ListWidget_UpdateItemActivity(item, activity);			activity->Release();		}	}				if (NULL == category ||		FALSE == category->collapsed)	{		ListWidget_InvalidateItemImage(self, hwnd, item);		if (STATUS_ERROR != self->selectionStatus &&			item == self->selectedItem)		{			ListWidget_UpdateSelectionStatus(self, hwnd, FALSE);		}	}	if (item == self->hoveredItem &&		NULL == self->activeMenu)	{		ListWidget_UpdateActiveCommands(self, hwnd);	}	return TRUE;}static BOOLListWidget_DeviceActivityFinished(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetItem *item;	ListWidgetCategory *category;	BOOL activityChanged;	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	item = ListWidget_FindItem(self, device->GetName(), &category, NULL);	if (NULL == item)		return FALSE;	activityChanged = FALSE;	if (FALSE != ListWidget_UnregisterActiveItem(self, hwnd, item))		activityChanged = TRUE;	if (FALSE != ListWidget_DeleteItemActivity(item))		activityChanged = TRUE;	if (FALSE != activityChanged)	{		if (NULL == category ||			FALSE == category->collapsed)		{			ListWidget_InvalidateItemImage(self, hwnd, item);		}		if (item == self->hoveredItem &&			NULL == self->activeMenu)		{			ListWidget_UpdateActiveCommands(self, hwnd);		}		if (STATUS_ERROR != self->selectionStatus &&			item == self->selectedItem)		{			ListWidget_UpdateSelectionStatus(self, hwnd, FALSE);		}	}	return TRUE;}static BOOLListWidget_DeviceActivityChanged(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetItem *item;	ListWidgetCategory *category;	ifc_deviceactivity *activity;	ListWidgetActivityChange changes;	self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	item = ListWidget_FindItem(self, device->GetName(), &category, NULL);	if (NULL == item)		return FALSE;	if (S_OK == device->GetActivity(&activity) && 		NULL != activity)	{		changes = ListWidget_UpdateItemActivity(item, activity);		activity->Release();	}	else		changes = ListWidgetActivityChanged_Nothing;	//if (FALSE != self->activityTimerEnabled)	//	changes &= ~ListWidgetActivityChanged_Percent;	if (ListWidgetActivityChanged_Nothing != changes &&		(NULL == category || FALSE == category->collapsed))	{		ListWidget_InvalidateItemActivity(self, hwnd, item, changes);		ListWidget_TooltipUpdateText(self, self->tooltip, item, Tooltip_DeviceActivityChanged);		if (0 != (ListWidgetActivityChanged_Title & changes) && 			STATUS_ERROR != self->selectionStatus &&			item == self->selectedItem)		{			ListWidget_UpdateSelectionStatus(self, hwnd, FALSE);		}	}		return TRUE;}static BOOLListWidget_DeviceModelChanged(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetItem *item;	ListWidgetCategory *category;		self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	item = ListWidget_FindItem(self, device->GetName(), &category, NULL);	if (NULL == item)		return FALSE;		if (NULL == category || 		FALSE == category->collapsed)	{				ListWidget_TooltipUpdateText(self, self->tooltip, item, Tooltip_DeviceModelChanged);		if (STATUS_ERROR != self->selectionStatus &&			item == self->selectedItem)		{			ListWidget_UpdateSelectionStatus(self, hwnd, FALSE);		}	}	return TRUE;}static BOOLListWidget_DeviceStatusChanged(HWND hwnd, ifc_device *device){	ListWidget *self;	ListWidgetItem *item;	ListWidgetCategory *category;		self = WIDGET_GET_SELF(hwnd, ListWidget);	if (NULL == self || NULL == device)		return FALSE;	item = ListWidget_FindItem(self, device->GetName(), &category, NULL);	if (NULL == item)		return FALSE;		if (NULL == category || 		FALSE == category->collapsed)	{				ListWidget_TooltipUpdateText(self, self->tooltip, item, Tooltip_DeviceStatusChanged);		if (STATUS_ERROR != self->selectionStatus &&			item == self->selectedItem)		{			ListWidget_UpdateSelectionStatus(self, hwnd, FALSE);		}	}	return TRUE;}static voidListWidget_DeviceCb(ifc_device *device, DeviceEvent eventId, void *user){	HWND hwnd;	hwnd = (HWND)user;		switch(eventId)	{		case Event_DeviceAdded:			ListWidget_DeviceAdd(hwnd, device, NULL);			break;		case Event_DeviceRemoved:			ListWidget_DeviceRemove(hwnd, device);			break;		case Event_DeviceHidden:			ListWidget_DeviceRemove(hwnd, device);			break;		case Event_DeviceShown:			ListWidget_DeviceAdd(hwnd, device, NULL);			break;		case Event_DeviceAttached:			ListWidget_DeviceAttach(hwnd, device);			break;		case Event_DeviceDetached:			ListWidget_DeviceDetach(hwnd, device);			break;		case Event_DeviceDisplayNameChanged:			ListWidget_DeviceTitleChanged(hwnd, device);			break;		case Event_DeviceTotalSpaceChanged:			ListWidget_DeviceSpaceChanged(hwnd, device);			break;		case Event_DeviceUsedSpaceChanged:			ListWidget_DeviceSpaceChanged(hwnd, device);			break;		case Event_DeviceIconChanged:			ListWidget_DeviceIconChanged(hwnd, device);			break;		case Event_DeviceActivityStarted:			ListWidget_DeviceActivityStarted(hwnd, device);			break;		case Event_DeviceActivityFinished:			ListWidget_DeviceActivityFinished(hwnd, device);			break;		case Event_DeviceActivityChanged:			ListWidget_DeviceActivityChanged(hwnd, device);			break;		case Event_DeviceCommandChanged:			ListWidget_DeviceCommandChanged(hwnd, device);			break;		case Event_DeviceModelChanged:			ListWidget_DeviceModelChanged(hwnd, device);			break;		case Event_DeviceStatusChanged:			ListWidget_DeviceStatusChanged(hwnd, device);			break;	}}static BOOLListWidget_RegisterDeviceHandler(ListWidget *self, HWND hwnd){	HWND eventRelay;	DeviceEventCallbacks callbacks;	if (NULL == self)		return FALSE;	if (0 != self->deviceHandler)		return FALSE;	eventRelay = Plugin_GetEventRelayWindow();	if (NULL == eventRelay)		return FALSE;		ZeroMemory(&callbacks, sizeof(callbacks));	callbacks.deviceCb = ListWidget_DeviceCb;	self->deviceHandler = EVENTRELAY_REGISTER_HANDLER(eventRelay, &callbacks, hwnd); 	return (0 != self->deviceHandler);}static BOOL ListWidget_InitCb(HWND hwnd, void **object, void *param){	ListWidget *self;	HWND sliderWindow;	int imageHeight, imageWidth;	self = new ListWidget();	if (NULL == self)		return FALSE;	self->flags = (ListWidgetFlags)0;	self->hoveredItem = NULL;	self->selectedItem = NULL;	self->titleEditItem = NULL;	self->pressedCategory = NULL;	self->itemWidth = 0;	self->spacebarBitmap = NULL;	self->hoverBitmap = NULL;	self->selectBitmap = NULL;	self->inactiveSelectBitmap = NULL;	self->largeBadgeBitmap = NULL;	self->smallBadgeBitmap = NULL;	self->arrowsBitmap = NULL;	self->itemsPerLine = 0;	self->deviceHandler = 0;	self->activeMenu = NULL;	self->previousMouse.x = -1;	self->previousMouse.y = -1;	self->commands = NULL;	self->commandsCount = 0;	self->commandsMax = 0;	self->unknownCommandLargeImage = NULL;	self->unknownCommandSmallImage = NULL;	ZeroMemory(&self->activityMetrics, sizeof(ListWidgetActivityMetric));	self->activityFont = NULL;	self->activityProgressImage = NULL;	self->activityBadgeBitmap = NULL;	self->activityTimerEnabled = FALSE;	SetSizeEmpty(&self->connectionSize);	SetSizeEmpty(&self->primaryCommandSize);	SetSizeEmpty(&self->secondaryCommandSize);	self->selectionStatus = STATUS_ERROR;	self->titleEditor = NULL;	BackBuffer_Initialize(&self->backBuffer, hwnd);	imageHeight = Config_ReadInt("View", "imageHeight", LISTWIDGET_IMAGE_DEFAULT_HEIGHT);	if (imageHeight < LISTWIDGET_IMAGE_MIN_HEIGHT)		imageHeight = LISTWIDGET_IMAGE_MIN_HEIGHT;	else if (imageHeight > LISTWIDGET_IMAGE_MAX_HEIGHT)		imageHeight = LISTWIDGET_IMAGE_MAX_HEIGHT;	imageWidth = (imageHeight * LISTWIDGET_IMAGE_DEFAULT_WIDTH)/LISTWIDGET_IMAGE_DEFAULT_HEIGHT;	ListWidget_SetImageSize(self, hwnd, imageWidth, imageHeight, FALSE);	ListWidget_CreateDefaultCategories(self);	*object = self;	sliderWindow = MANAGERVIEW_GET_ZOOM_SLIDER(GetParent(hwnd));	if (NULL != sliderWindow)	{		int pos;		SendMessage(sliderWindow, TBM_SETPAGESIZE, 0, 10);		SendMessage(sliderWindow, TBM_SETLINESIZE, 0, 10);		SendMessage(sliderWindow, TBM_SETRANGE, TRUE, MAKELPARAM(-100, 100));		SendMessage(sliderWindow, TBM_SETTIC, 0, 0);		if (imageHeight == LISTWIDGET_IMAGE_DEFAULT_HEIGHT)			pos = 0;		else if (imageHeight > LISTWIDGET_IMAGE_DEFAULT_HEIGHT)			pos = (100 * (imageHeight- LISTWIDGET_IMAGE_DEFAULT_HEIGHT))/(LISTWIDGET_IMAGE_MAX_HEIGHT - LISTWIDGET_IMAGE_DEFAULT_HEIGHT);		else 			pos = (100 * (imageHeight - LISTWIDGET_IMAGE_MIN_HEIGHT))/(LISTWIDGET_IMAGE_DEFAULT_HEIGHT - LISTWIDGET_IMAGE_MIN_HEIGHT) - 100;		SendMessage(sliderWindow, TBM_SETPOS, TRUE, pos);	}	self->tooltip = ListWidget_TooltipCreate(hwnd);	ListWidget_AddExistingDevices(self, hwnd);	ListWidget_RegisterDeviceHandler(self, hwnd);	return TRUE;}static void ListWidget_DestroyCb(ListWidget *self, HWND hwnd){	HWND sliderWindow;	size_t index;	if (NULL == self)		return;	Config_WriteInt("View", "imageHeight", self->imageSize.cy);	if (0 != self->deviceHandler)	{		HWND eventRelay;		eventRelay = Plugin_GetEventRelayWindow();		if (NULL != eventRelay)		{			EVENTRELAY_UNREGISTER_HANDLER(eventRelay, self->deviceHandler); 		}	}	index = self->activeItems.size();	if (0 != index)	{		KillTimer(hwnd, LISTWIDGETTIMER_PROGRESS_TICK_ID);		self->activityTimerEnabled = FALSE;		while(index--)			ListWidget_DeleteItemActivity(self->activeItems[index]);	}	index = self->categories.size();	if (0 != index)	{		while(index--)		{			ListWidgetCategory *category = self->categories[index];			Config_WriteBool("CollapsedCategories", category->name, category->collapsed);			ListWidget_DestroyCategory(category);		}		self->categories.clear();	}	ListWidget_RemoveAllConnections(self);	BackBuffer_Uninitialize(&self->backBuffer);	if (NULL != self->spacebarBitmap)		DeleteObject(self->spacebarBitmap);	if (NULL != self->hoverBitmap)		DeleteObject(self->hoverBitmap);	if (NULL != self->selectBitmap)		DeleteObject(self->selectBitmap);	if (NULL != self->inactiveSelectBitmap)		DeleteObject(self->inactiveSelectBitmap);	if (NULL != self->largeBadgeBitmap)		DeleteObject(self->largeBadgeBitmap);	if (NULL != self->smallBadgeBitmap)		DeleteObject(self->smallBadgeBitmap);	if (NULL != self->unknownCommandLargeImage)		DeviceImage_Release(self->unknownCommandLargeImage);	if (NULL != self->unknownCommandSmallImage)		DeviceImage_Release(self->unknownCommandSmallImage);	if (NULL != self->arrowsBitmap)		DeleteObject(self->arrowsBitmap);	if (NULL != self->activityProgressImage)		DeviceImage_Release(self->activityProgressImage);	if (NULL != self->activityBadgeBitmap)		DeleteObject(self->activityBadgeBitmap);	if (NULL != self->activityFont)		DeleteObject(self->activityFont);	ListWidget_TooltipDestroy(self->tooltip);	if (NULL != self->commands)	{		ListWidget_DestroyAllCommands(self->commands, self->commandsCount);		free(self->commands);	}	free(self);	sliderWindow = MANAGERVIEW_GET_ZOOM_SLIDER(GetParent(hwnd));	if (NULL != sliderWindow)	{		ShowWindow(sliderWindow, SW_HIDE);	}}static voidListWidget_LayoutCb(ListWidget *self, HWND hwnd, WidgetStyle *style, 					 const RECT *clientRect, SIZE *viewSize, BOOL redraw){	size_t iCategory, iGroup, iItem;	ListWidgetCategory *category;	ListWidgetGroup	*group;	ListWidgetItem *item;	ListWidgetCategoryMetric categoryMetrics;	size_t itemsInLine;	long viewWidth, itemHeight, lineHeight;	long itemTextWidth, itemTextHeightMax, textHeight, fontHeight;	long categoryHeight, categorySpacing, categorySpacingCollapsed;	SIZE itemSpacing, widgetSize, itemSize;	POINT widgetOffset, categoryOffset, itemOffset;	RECT elementRect;	HDC targetDC;	HFONT targetPrevFont;	TEXTMETRIC textMetrics;	if (NULL == style)		return;	viewWidth = RECTWIDTH(*clientRect);	if (FALSE == ListWidget_CalculateItemBaseSize(self, style, &itemSize, &itemTextWidth))		SetSizeEmpty(&itemSize);	self->itemWidth = itemSize.cx;	WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(widgetOffset.x, style, LISTWIDGET_OFFSET_LEFT_DLU, 1);	WIDGETSTYLE_DLU_TO_VERT_PX_MIN(widgetOffset.y, style, LISTWIDGET_OFFSET_TOP_DLU, 1);	WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(categoryOffset.x, style, LISTWIDGET_CATEGORY_OFFSET_LEFT_DLU, 1);	WIDGETSTYLE_DLU_TO_VERT_PX_MIN(categoryOffset.y, style, LISTWIDGET_CATEGORY_OFFSET_TOP_DLU, 1);	WIDGETSTYLE_DLU_TO_VERT_PX_MIN(categorySpacing, style, LISTWIDGET_CATEGORY_SPACING_DLU, 1);	WIDGETSTYLE_DLU_TO_VERT_PX_MIN(categorySpacingCollapsed, style, LISTWIDGET_CATEGORY_SPACING_COLLAPSED_DLU, 1);	WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(itemOffset.x, style, LISTWIDGET_ITEM_OFFSET_LEFT_DLU, 1);	WIDGETSTYLE_DLU_TO_VERT_PX_MIN(itemOffset.y, style, LISTWIDGET_ITEM_OFFSET_TOP_DLU, 1);	WIDGETSTYLE_DLU_TO_HORZ_PX_MIN(itemSpacing.cx, style, LISTWIDGET_ITEM_SPACING_HORZ_DLU, 1);	WIDGETSTYLE_DLU_TO_VERT_PX_MIN(itemSpacing.cy, style, LISTWIDGET_ITEM_SPACING_VERT_DLU, 1);	self->itemsPerLine = ((viewWidth - (widgetOffset.x + itemOffset.x))/* + itemSpacing.cx*/) / (itemSize.cx + itemSpacing.cx);	self->itemsPerLine = MAX(self->itemsPerLine, 1);	itemsInLine = 0;	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 (itemsInLine < group->items.size())					itemsInLine = group->items.size();			}		}	}	if (self->itemsPerLine < itemsInLine && self->itemsPerLine > 1)		itemSpacing.cx = (LONG)(((viewWidth - (widgetOffset.x + itemOffset.x)) - (itemSize.cx * self->itemsPerLine))/self->itemsPerLine);	if (itemsInLine < self->itemsPerLine)		self->itemsPerLine = itemsInLine;	widgetSize.cx = widgetOffset.x + itemOffset.x + itemSize.cx;	widgetSize.cy = widgetOffset.y;	targetDC = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);	if (NULL != targetDC)	{		targetPrevFont = SelectFont(targetDC, WIDGETSTYLE_CATEGORY_FONT(style));		categoryHeight = Graphics_GetFontHeight(targetDC);		SelectFont(targetDC, WIDGETSTYLE_TEXT_FONT(style));		fontHeight = Graphics_GetFontHeight(targetDC);		itemTextHeightMax = LISTWIDGET_ITEM_TITLE_MAX_LINES * fontHeight;	}	else	{		targetPrevFont = NULL;		itemTextHeightMax = 0;		categoryHeight = 0;		fontHeight = 0;	}	if (NULL == targetDC ||		FALSE == GetTextMetrics(targetDC, &textMetrics))	{		ZeroMemory(&textMetrics, sizeof(textMetrics));	}	if (FALSE != ListWidget_GetCategoryMetrics(style, &categoryMetrics))	{		if (categoryHeight < categoryMetrics.minHeight)			categoryHeight = categoryMetrics.minHeight;		categoryHeight += categoryMetrics.offsetTop + categoryMetrics.offsetBottom +						  categoryMetrics.lineHeight + categoryMetrics.lineOffsetTop;	}	for (iCategory = 0; iCategory < self->categories.size(); iCategory++)	{		category = self->categories[iCategory];		SetRect(&category->rect, 0, 0, viewWidth, categoryHeight);		long offsetX = clientRect->left + categoryOffset.x;		long offsetY = clientRect->top + widgetSize.cy;		if (0 == iCategory)			offsetY += categoryOffset.y;		else		{			if (FALSE == self->categories[iCategory - 1]->collapsed)				offsetY += categorySpacing;			else				offsetY += categorySpacingCollapsed;		}		OffsetRect(&category->rect, offsetX, offsetY);		widgetSize.cy = category->rect.bottom - clientRect->top;		size_t itemsInCategory = 0;		if (FALSE == category->collapsed)		{			for(iGroup = 0; iGroup < category->groups.size(); iGroup++)			{				group = category->groups[iGroup];				itemsInLine = 1;				lineHeight = 0;								if (0 != group->items.size())				{					if (0 == iGroup)						widgetSize.cy += itemOffset.y;					else						widgetSize.cy += itemSpacing.cy;					for(iItem = 0; iItem < group->items.size(); iItem++, itemsInLine++)					{						item = group->items[iItem];						if (itemsInLine > self->itemsPerLine)						{							widgetSize.cy += lineHeight + itemSpacing.cy;							lineHeight = 0;							itemsInLine = 1;						}						itemHeight = itemSize.cy;						itemsInCategory++;						if (-1 == item->titleSize.cy)						{							if (FALSE == IS_STRING_EMPTY(item->title))							{								SetRect(&elementRect, 0, 0, itemTextWidth - textMetrics.tmAveCharWidth/2, 0);								if (FALSE != DrawText(targetDC, item->title, -1, &elementRect, 														DT_NOPREFIX | DT_CALCRECT | DT_EDITCONTROL | DT_WORDBREAK))								{									SetSize(&item->titleSize, RECTWIDTH(elementRect), RECTHEIGHT(elementRect));									item->titleSize.cx += textMetrics.tmAveCharWidth/2;									if (item->titleSize.cx > itemTextWidth)										item->titleSize.cx = itemTextWidth;								}								else									SetSizeEmpty(&item->titleSize);							}							else							{								SetSize(&item->titleSize, 0, textMetrics.tmHeight);							}						}						textHeight = item->titleSize.cy;						if (textHeight > itemTextHeightMax)						{							textHeight = itemTextHeightMax;							ListWidgetItem_SetTextTruncated(item);						}						itemHeight += textHeight;																							SetRect(&item->rect, 0, 0, itemSize.cx, itemHeight);						offsetX = long(clientRect->left + itemOffset.x +								  (itemsInLine - 1)*(itemSize.cx + itemSpacing.cx));						offsetY = clientRect->top + widgetSize.cy;						OffsetRect(&item->rect, offsetX, offsetY);												if (lineHeight < itemHeight)							lineHeight = itemHeight;					}					if (0 != lineHeight)						widgetSize.cy += lineHeight;				}			}			if (0 == itemsInCategory && 				FALSE == IS_STRING_EMPTY(category->emptyText))			{				SetRect(&category->emptyTextRect, 0, 0, viewWidth - textMetrics.tmAveCharWidth/2, 0);				if (FALSE != DrawText(targetDC, category->emptyText, -1, &category->emptyTextRect, 										DT_NOPREFIX | DT_CALCRECT | DT_EDITCONTROL | DT_WORDBREAK))				{					category->emptyTextRect.right += textMetrics.tmAveCharWidth/2;					if (category->emptyTextRect.right > viewWidth)						category->emptyTextRect.right = viewWidth;					offsetX = clientRect->left + categoryOffset.x + 							 (viewWidth - category->emptyTextRect.right)/2;					offsetY = clientRect->top + widgetSize.cy + itemOffset.y + fontHeight/2;					OffsetRect(&category->emptyTextRect, offsetX, offsetY);					widgetSize.cy += RECTHEIGHT(category->emptyTextRect) + itemOffset.y + fontHeight;				}				else					SetRectEmpty(&category->emptyTextRect);			}		}		else		{			for(iGroup = 0; iGroup < category->groups.size(); iGroup++)			{				group = category->groups[iGroup];				for(iItem = 0; iItem < group->items.size(); iItem++, itemsInLine++)				{					item = group->items[iItem];					SetRectEmpty(&item->rect);					itemsInCategory++;				}			}		}	}	widgetSize.cy += WIDGETSTYLE_DLU_TO_VERT_PX(style, LISTWIDGET_OFFSET_BOTTOM_DLU);	viewSize->cx = widgetSize.cx;	viewSize->cy = widgetSize.cy;	size_t commandsMax = 1;	if (self->commandsMax != commandsMax)	{		if (NULL != self->commands)		{			ListWidget_DestroyAllCommands(self->commands, self->commandsCount);			free(self->commands);		}		self->commandsCount = 0;		self->commands = (ListWidgetCommand**)malloc(sizeof(ListWidgetCommand*) * commandsMax);		if (NULL != self->commands)			self->commandsMax = commandsMax;		else			self->commandsMax = 0;	}	if (NULL != targetDC)	{		SelectFont(targetDC, targetPrevFont);		ReleaseDC(hwnd, targetDC);	}}static BOOL ListWidget_PaintCb(ListWidget *self, HWND hwnd, WidgetStyle *style, HDC hdc, const RECT *paintRect, BOOL erase){	size_t iCategory, iGroup, iItem;	ListWidgetCategory *category;	ListWidgetGroup	*group;	ListWidgetItem *item;	HFONT prevFont;	FillRegion fillRegion;	ListWidgetPaint paint;	size_t itemsInCategory;	if (FALSE == ListWidgetPaint_Initialize(&paint, self, style, hwnd, hdc, paintRect, erase))		return FALSE;	SetTextColor(hdc, style->textColor);	SetBkColor(hdc, style->backColor);	SetBkMode(hdc, TRANSPARENT);	prevFont = SelectFont(hdc, style->textFont);	FillRegion_Init(&fillRegion, paintRect);	if (FALSE != erase)	{		for (iCategory = 0; iCategory < self->categories.size(); iCategory++)		{			category = self->categories[iCategory];						FillRegion_ExcludeRect(&fillRegion, &category->rect);			if (FALSE == category->collapsed)			{				itemsInCategory = 0;				for(iGroup = 0; iGroup < category->groups.size(); iGroup++)				{					group = category->groups[iGroup];					for(iItem = 0; iItem < group->items.size(); iItem++)					{						item = group->items[iItem];						itemsInCategory++;						FillRegion_ExcludeRect(&fillRegion, &item->rect);					}				}				if (0 == itemsInCategory &&					FALSE == IS_STRING_EMPTY(category->emptyText))				{					FillRegion_ExcludeRect(&fillRegion, &category->emptyTextRect);				}			}		}		FillRegion_BrushFill(&fillRegion, hdc, style->backBrush);		FillRegion_SetEmpty(&fillRegion);	}		for (iCategory = 0; iCategory < self->categories.size(); iCategory++)	{		category = self->categories[iCategory];				if (FALSE == ListWidgetPaint_DrawCategory(&paint, category))			FillRegion_AppendRect(&fillRegion, &category->rect);		if (FALSE == category->collapsed)		{			itemsInCategory = 0;			for(iGroup = 0; iGroup < category->groups.size(); iGroup++)			{				group = category->groups[iGroup];				for(iItem = 0; iItem < group->items.size(); iItem++)				{					item = group->items[iItem];					itemsInCategory++;					if (FALSE == ListWidgetPaint_DrawItem(&paint, item))						FillRegion_AppendRect(&fillRegion, &item->rect);				}			}			if (0 == itemsInCategory &&				FALSE == IS_STRING_EMPTY(category->emptyText))			{				if (FALSE == ListWidgetPaint_DrawEmptyCategoryText(&paint, category))					FillRegion_AppendRect(&fillRegion, &category->emptyTextRect);			}		}	}		FillRegion_BrushFill(&fillRegion, hdc, style->backBrush);	FillRegion_Uninit(&fillRegion);	SelectFont(hdc, prevFont);	ListWidgetPaint_Uninitialize(&paint);	return TRUE;}static voidListWidget_StyleColorChangedCb(ListWidget *self, HWND hwnd, WidgetStyle *style){	if (NULL == self)		return;	if (NULL != self->spacebarBitmap)	{		DeleteObject(self->spacebarBitmap);		self->spacebarBitmap = NULL;	}	if (NULL != self->hoverBitmap)	{		DeleteObject(self->hoverBitmap);		self->hoverBitmap = NULL;	}	if (NULL != self->selectBitmap)	{		DeleteObject(self->selectBitmap);		self->selectBitmap = NULL;	}	if (NULL != self->inactiveSelectBitmap)	{		DeleteObject(self->inactiveSelectBitmap);		self->inactiveSelectBitmap = NULL;	}	if (NULL != self->arrowsBitmap)	{		DeleteObject(self->arrowsBitmap);		self->arrowsBitmap = NULL;	}			ListWidget_ResetConnnectionsColors(self, style);		if (NULL != self->titleEditor)		ListWidget_UpdateTitleEditorColors(self->titleEditor, style);}static voidListWidget_StyleFontChangedCb(ListWidget *self, HWND hwnd, WidgetStyle *style){	size_t iCategory, iGroup, iItem;	ListWidgetCategory *category;	ListWidgetGroup	*group;	ListWidgetItem *item;	if (NULL == self)		return;	for (iCategory = 0; iCategory < self->categories.size(); iCategory++)	{		category = self->categories[iCategory];		category->countWidth = -1;		category->titleWidth = -1;		SetRect(&category->emptyTextRect, -1, -1, -1, -1);		for(iGroup = 0; iGroup < category->groups.size(); iGroup++)		{			group = category->groups[iGroup];			for(iItem = 0; iItem < group->items.size(); iItem++)			{				item = group->items[iItem];				SetSize(&item->titleSize, -1, -1);			}		}	}	ListWidget_TooltipFontChanged(self->tooltip);	if (NULL != self->titleEditor)		SendMessage(self->titleEditor, WM_SETFONT, (WPARAM)WIDGETSTYLE_TEXT_FONT(style), TRUE);	}static BOOL ListWidget_MouseMoveCb(ListWidget *self, HWND hwnd, unsigned int vKeys, const POINT *cursor){	if (self->previousMouse.x == cursor->x && 		self->previousMouse.y == cursor->y)	{		return TRUE;	}	self->previousMouse = *cursor;	if (FALSE != ListWidget_UpdateHoverEx(self, hwnd, cursor))		UpdateWindow(hwnd);	ListWidget_TooltipRelayMouseMessage(self->tooltip, WM_MOUSEMOVE, vKeys, cursor);	return TRUE;}static BOOL ListWidget_LeftButtonDownCb(ListWidget *self, HWND hwnd, unsigned int vKeys, const POINT *cursor){	ListWidgetItem *selectedItem;	ListWidgetCategory *pressedCategory;	ListWidgetItemPart pressedPart;	ListWidgetCommand *command, *pressedCommand;	WidgetStyle *style; 	RECT rect, pressedPartRect;	POINT pt, origin;	size_t index;	style = WIDGET_GET_STYLE(hwnd);	if (NULL == style)		return FALSE;		pt = *cursor;		if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))	{		origin.x = 0;		origin.y = 0;	}	selectedItem = NULL;	pressedCategory = NULL;	pressedPart = ListWidgetItemPart_None;	pressedCommand = NULL;	if (FALSE != GetClientRect(hwnd, &rect) &&		FALSE != PtInRect(&rect, pt))	{				pt.x -= origin.x;		pt.y -= origin.y;		pressedCategory = ListWidget_GetCategoryFromPoint(self, pt);				if (NULL == pressedCategory)		{			selectedItem = ListWidget_GetItemFromPoint(self, pt);			if (NULL != selectedItem)			{				ListWidgetItemMetric metrics;				if (FALSE != ListWidget_GetItemMetrics(style, &metrics))				{					pressedPart = ListWidgetItemPart_Command;					if (selectedItem == self->selectedItem)							pressedPart |= ListWidgetItemPart_Title;					pressedPart = ListWidget_GetItemPartFromPoint(self, selectedItem, &metrics, pt,																	pressedPart, &pressedPartRect);					if (ListWidgetItemPart_Title == pressedPart &&						self->titleEditItem != selectedItem &&						hwnd == GetFocus() &&						FALSE == ListWidgetItem_IsTextEdited(selectedItem))					{												self->titleEditItem = selectedItem;						SetTimer(hwnd, LISTWIDGETTIMER_EDIT_TITLE_ID, 									GetDoubleClickTime() + 1, 									ListWidget_BeginTitleEditTimerCb);														}				}			}				}	}	if (NULL != pressedCategory)	{		ListWidgetCategoryMetric metrics;		if (FALSE == ListWidget_GetCategoryMetrics(style, &metrics))			SetRectEmpty(&rect);		else		{			CopyRect(&rect, &pressedCategory->rect);			rect.left += metrics.offsetLeft;			rect.top += metrics.offsetTop;			rect.right = rect.left + metrics.iconWidth;			rect.bottom -= (metrics.offsetBottom + metrics.lineHeight + metrics.lineOffsetTop);		}		if (FALSE == PtInRect(&rect, pt))			pressedCategory = NULL;	}	self->pressedCategory = pressedCategory;			ListWidget_SelectItem(self, hwnd, selectedItem, FALSE);		ListWidget_EnsureFocused(self, hwnd, FALSE);	if (ListWidgetItemPart_Command == pressedPart &&		NULL != selectedItem)	{		OffsetRect(&pressedPartRect, -selectedItem->rect.left, -selectedItem->rect.top);	}	index = self->commandsCount;	while(index--)	{		command = self->commands[index];		if (NULL == pressedCommand &&			ListWidgetItemPart_Command == pressedPart &&			ListWidget_GetCommandRectEqual(command, &pressedPartRect))		{			pressedCommand = command;		}		if (FALSE != ListWidget_GetCommandPressed(command) || 			pressedCommand == command)		{			if (FALSE != ListWidget_SetCommandPressed(pressedCommand, (pressedCommand == command)) &&				FALSE != ListWidget_GetCommandRect(command, &rect) && 				NULL != selectedItem)			{				OffsetRect(&rect, selectedItem->rect.left + origin.x, selectedItem->rect.top + origin.y);				InvalidateRect(hwnd, &rect, FALSE);			}		}	}	if (NULL != pressedCommand)		self->flags |= ListWidgetFlag_LButtonDownOnCommand;	else		self->flags &= ~ListWidgetFlag_LButtonDownOnCommand;		if (GetCapture() != hwnd)		SetCapture(hwnd);	UpdateWindow(hwnd);		ListWidget_TooltipHide(self->tooltip);	return TRUE;}static BOOL ListWidget_LeftButtonUpCb(ListWidget *self, HWND hwnd, unsigned int vKeys, const POINT *cursor){		WidgetStyle *style; 	RECT rect;	POINT pt, origin;	ListWidgetCategory *pressedCategory;	ListWidgetCommand *pressedCommand;	size_t index;	BOOL updateWindow;	style = WIDGET_GET_STYLE(hwnd);	pt = *cursor;	if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))	{		origin.x = 0;		origin.y = 0;	}			pressedCategory = NULL;	pressedCommand = NULL;	updateWindow = FALSE;	if (FALSE != GetClientRect(hwnd, &rect) &&		FALSE != PtInRect(&rect, pt))	{				pt.x -= origin.x;		pt.y -= origin.y;		pressedCategory = ListWidget_GetCategoryFromPoint(self, pt);		if (NULL == pressedCategory)		{						if (NULL != self->selectedItem && 				FALSE != ListWidgetItem_IsInteractive(self->selectedItem))			{								index = self->commandsCount;				while(index--)				{					if (FALSE != ListWidget_GetCommandRect(self->commands[index], &rect))					{						OffsetRect(&rect, self->selectedItem->rect.left, self->selectedItem->rect.top);						if (PtInRect(&rect, pt))						{							pressedCommand = self->commands[index];							if (FALSE != ListWidget_GetCommandDisabled(pressedCommand) ||								FALSE == ListWidget_GetCommandPressed(pressedCommand))							{								pressedCommand = NULL;							}							break;						}					}				}			}		}	}		if (NULL != self->pressedCategory)	{		if (NULL != pressedCategory)		{					ListWidgetCategoryMetric metrics;			if (FALSE == ListWidget_GetCategoryMetrics(style, &metrics))				SetRectEmpty(&rect);			else			{				CopyRect(&rect, &pressedCategory->rect);				rect.left += metrics.offsetLeft;				rect.top += metrics.offsetTop;				rect.right = rect.left + metrics.iconWidth;				rect.bottom -= (metrics.offsetBottom + metrics.lineHeight + metrics.lineOffsetTop);			}			if (FALSE == PtInRect(&rect, pt))				pressedCategory = NULL;		}		if(self->pressedCategory == pressedCategory)		{			ListWidget_ToggleCategory(pressedCategory, hwnd);		}		self->pressedCategory = NULL;	}	if (NULL != self->selectedItem)	{		if (NULL != pressedCommand && NULL != self->selectedItem)		{			ListWidget_SendItemCommand(self->selectedItem->name, 										ListWidget_GetCommandName(pressedCommand), 										hwnd, 0, TRUE);		}		index = self->commandsCount;		while(index--)		{			if (FALSE != ListWidget_GetCommandPressed(self->commands[index]))			{				if (FALSE != ListWidget_SetCommandPressed(self->commands[index], FALSE) &&					FALSE != ListWidget_GetCommandRect(self->commands[index], &rect))				{					OffsetRect(&rect, self->selectedItem->rect.left + origin.x, self->selectedItem->rect.top + origin.y);					InvalidateRect(hwnd, &rect, FALSE);					updateWindow = TRUE;				}				break;			}		}		if (FALSE != ListWidget_EnsureItemVisisble(self, hwnd, self->selectedItem, VISIBLE_NORMAL))			updateWindow = TRUE;	}	if (FALSE != ListWidget_UpdateHoverEx(self, hwnd, cursor))		updateWindow = TRUE;			if (GetCapture() == hwnd)		ReleaseCapture();	if (FALSE != updateWindow)		UpdateWindow(hwnd);	ListWidget_TooltipRelayMouseMessage(self->tooltip, WM_LBUTTONUP, vKeys, cursor);	return TRUE;}static BOOL ListWidget_LeftButtonDblClkCb(ListWidget *self, HWND hwnd, unsigned int vKeys, const POINT *cursor){	RECT rect;	POINT pt = *cursor, origin;	ListWidgetCategory *category;	if (NULL != self->titleEditItem)	{		KillTimer(hwnd, LISTWIDGETTIMER_EDIT_TITLE_ID);		self->titleEditItem = NULL;	}	if (0 != (ListWidgetFlag_LButtonDownOnCommand & self->flags))		return FALSE;	if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))	{		origin.x = 0;		origin.y = 0;	}	if (FALSE != GetClientRect(hwnd, &rect) &&		FALSE != PtInRect(&rect, pt))	{		pt.x -= origin.x;		pt.y -= origin.y;		category = ListWidget_GetCategoryFromPoint(self, pt);		if (NULL != category)		{			ListWidget_ToggleCategory(category, hwnd);			self->pressedCategory = NULL;			return TRUE;		}		ListWidgetItem *item = ListWidget_GetItemFromPointEx(self, pt, &category, NULL);		if (NULL != item)		{			if (NULL != item && 				FALSE != ListWidgetItem_IsInteractive(item))			{				size_t index;				index = self->commandsCount;				while(index--)				{					if (FALSE != ListWidget_GetCommandRect(self->commands[index], &rect))					{						OffsetRect(&rect, item->rect.left, item->rect.top);						if (PtInRect(&rect, pt))						{							item = NULL;							break;						}					}				}			}			if (NULL != item)			{				ListWidget_CallItemAction(self, hwnd, category, item);				return TRUE;			}		}	}	return FALSE;}static BOOLListWidget_RightButtonDownCb(ListWidget *self, HWND hwnd, unsigned int vKeys, const POINT *cursor){	ListWidgetItem *selectedItem;	RECT rect;	POINT pt, origin;	pt = *cursor;		if (NULL != self->titleEditItem)	{		KillTimer(hwnd, LISTWIDGETTIMER_EDIT_TITLE_ID);		self->titleEditItem = NULL;	}	if (FALSE == ListWidget_GetViewOrigin(hwnd, &origin))	{		origin.x = 0;		origin.y = 0;	}	selectedItem = NULL;	if (FALSE != GetClientRect(hwnd, &rect) &&		FALSE != PtInRect(&rect, pt))	{		pt.x -= origin.x;		pt.y -= origin.y;		selectedItem = ListWidget_GetItemFromPoint(self, pt);	}	ListWidget_SelectItem(self, hwnd, selectedItem, TRUE);		ListWidget_EnsureFocused(self, hwnd, FALSE);	if (GetCapture() != hwnd)		SetCapture(hwnd);		UpdateWindow(hwnd);	ListWidget_TooltipRelayMouseMessage(self->tooltip, WM_RBUTTONDOWN, vKeys, cursor);		return FALSE; // allow defwindowproc to get this message}static BOOL ListWidget_RightButtonUpCb(ListWidget *self, HWND hwnd, unsigned int vKeys, const POINT *cursor){	RECT rect;	if (FALSE != ListWidget_UpdateHoverEx(self, hwnd, cursor))		UpdateWindow(hwnd);	if (GetCapture() == hwnd)		ReleaseCapture();	ListWidget_TooltipRelayMouseMessage(self->tooltip, WM_RBUTTONUP, vKeys, cursor);	if (FALSE != GetClientRect(hwnd, &rect) &&		FALSE != PtInRect(&rect, *cursor))	{		ListWidgetItem *item;		ListWidgetItemMetric metrics;		POINT pt;		if (FALSE == ListWidget_GetViewOrigin(hwnd, &pt))		{			pt.x = 0;			pt.y = 0;		}		pt.x = cursor->x - pt.x;		pt.y = cursor->y - pt.y;		item = ListWidget_GetItemFromPoint(self, pt);		if (NULL != item)		{			WidgetStyle *style = WIDGET_GET_STYLE(hwnd);			if (NULL != style && 				FALSE != ListWidget_GetItemMetrics(style, &metrics))			{				ListWidgetItemPart part;				part = ListWidgetItemPart_Command | ListWidgetItemPart_Activity;				part = ListWidget_GetItemPartFromPoint(self, item, &metrics, pt, part, NULL);				if (ListWidgetItemPart_None != part)					return TRUE;			}		}	}	return FALSE; // allow defwindowproc to get this message}static BOOLListWidget_KeyDownCb(ListWidget *self, HWND hwnd, unsigned int vKey, unsigned int flags){	ListWidgetItem *selectedItem;	ListWidgetVisibleFlags visibleFlags;	selectedItem = NULL;	visibleFlags = VISIBLE_NORMAL/*VISIBLE_PARTIAL_OK*/;	switch(vKey)	{		case VK_HOME:			ListWidget_EnsureTopVisible(self, hwnd);			visibleFlags |= VISIBLE_ALIGN_TOP | VISIBLE_ALIGN_ALWAYS;			selectedItem = ListWidget_GetFirstItem(self);			break;		case VK_END:			ListWidget_EnsureBottomVisible(self, hwnd);			visibleFlags |= VISIBLE_ALIGN_BOTTOM | VISIBLE_ALIGN_ALWAYS;			selectedItem = ListWidget_GetLastItem(self);			break;		case VK_LEFT:			selectedItem = (NULL != self->selectedItem) ?							ListWidget_GetPreviousItem(self, self->selectedItem) :							ListWidget_GetLastItem(self);			if (NULL == selectedItem)				ListWidget_EnsureTopVisible(self, hwnd);			break;		case VK_RIGHT:			selectedItem = (NULL != self->selectedItem) ?							ListWidget_GetNextItem(self, self->selectedItem) :							ListWidget_GetFirstItem(self);			if (NULL == selectedItem)				ListWidget_EnsureBottomVisible(self, hwnd);			break;		case VK_UP:			selectedItem = (NULL != self->selectedItem) ?							ListWidget_GetPreviousLineItem(self, self->selectedItem) :							ListWidget_GetLastItem(self);			if (NULL == selectedItem)				ListWidget_EnsureTopVisible(self, hwnd);			break;		case VK_DOWN:			selectedItem = (NULL != self->selectedItem) ?							ListWidget_GetNextLineItem(self, self->selectedItem) :							ListWidget_GetFirstItem(self);			if (NULL == selectedItem)				ListWidget_EnsureBottomVisible(self, hwnd);			break;		case VK_PRIOR:			visibleFlags |= VISIBLE_ALIGN_BOTTOM;			selectedItem = (NULL != self->selectedItem) ?							ListWidget_GetPreviousPageItem(self, hwnd, self->selectedItem) :							ListWidget_GetLastItem(self);			if (NULL == selectedItem)				ListWidget_EnsureTopVisible(self, hwnd);			break;		case VK_NEXT:			visibleFlags |= VISIBLE_ALIGN_TOP;			selectedItem = (NULL != self->selectedItem) ?							ListWidget_GetNextPageItem(self, hwnd, self->selectedItem) :							ListWidget_GetFirstItem(self);			if (NULL == selectedItem)				ListWidget_EnsureBottomVisible(self, hwnd);			break;		case VK_RETURN:			if (NULL != self->selectedItem)			{				ListWidget_CallItemAction(self, hwnd, NULL, self->selectedItem);				ListWidget_EnsureItemVisisble(self, hwnd, self->selectedItem, visibleFlags);			}			break;		case VK_F2:			if (NULL != self->selectedItem)			{				if (NULL != self->titleEditor)					DestroyWindow(self->titleEditor);								self->titleEditor = ListWidget_BeginItemTitleEdit(self, hwnd, self->selectedItem);			}			break;				default:			return FALSE;	}	if (NULL != selectedItem)	{		ListWidget_SelectItem(self, hwnd, selectedItem, FALSE);		ListWidget_EnsureItemVisisble(self, hwnd, self->selectedItem, visibleFlags);	}	return TRUE;}static BOOLListWidget_KeyUpCb(ListWidget *self, HWND hwnd, unsigned int vKey, unsigned int flags){	return FALSE;}static BOOLListWidget_CharacterCb(ListWidget *self, HWND hwnd, unsigned int vKey, unsigned int flags){	return FALSE;}static INTListWidget_InputRequestCb(ListWidget *self, HWND hwnd, unsigned int vKey, MSG *message){	INT result;	if (NULL == message)		return DLGC_WANTALLKEYS;		ListWidget_TooltipHide(self->tooltip);	result = DLGC_WANTCHARS;	switch(vKey)	{		case VK_LEFT:		case VK_RIGHT:		case VK_UP:		case VK_DOWN:		case VK_PRIOR:		case VK_NEXT:		case VK_END:		case VK_HOME:		case VK_RETURN:			result |= DLGC_WANTALLKEYS;			break;	}	return result;}static voidListWidget_FocusChangedCb(ListWidget *self, HWND hwnd, HWND focusWindow, BOOL focusReceived){	if (NULL == self)		return;	if (NULL == self->selectedItem)	{		if (FALSE != focusReceived && 0 == (ListWidgetFlag_NoFocusSelect & self->flags))		{			BOOL disableSelect;			disableSelect = FALSE;			if (NULL != focusWindow)			{				HWND ancestorWindow;				ancestorWindow = hwnd;				while(NULL != ancestorWindow)				{					ancestorWindow = GetAncestor(ancestorWindow, GA_PARENT);					if (focusWindow == ancestorWindow)					{						wchar_t buffer[64] = {0};						if (0 != GetClassName(focusWindow, buffer, ARRAYSIZE(buffer)) &&							CSTR_EQUAL == CompareString(CSTR_INVARIANT, NORM_IGNORECASE, buffer, -1, L"Winamp Gen", -1))						{							disableSelect = TRUE;						}						break;					}				}			}			if (FALSE == disableSelect)			{				ListWidgetItem *item;				item = ListWidget_GetFirstItem(self);				if (NULL != item)					ListWidget_SelectItem(self, hwnd, item, FALSE);			}		}	}	else	{		POINT origin;		RECT rect;		CopyRect(&rect, &self->selectedItem->rect);		if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))			OffsetRect(&rect, origin.x, origin.y);		InvalidateRect(hwnd, &rect, FALSE);		UpdateWindow(hwnd);	}}static BOOLListWidget_ContextMenuCb(ListWidget *self, HWND hwnd, HWND targetWindow, const POINT *cursor){	POINT pt;	ListWidgetItem *item;	if (NULL == self)		return FALSE;	if (NULL == cursor || 		(-1 == cursor->x && -1 == cursor->y))	{		if (hwnd != targetWindow)			return FALSE;		item = self->selectedItem;		if (NULL != item)		{			POINT origin;			pt.x = RECTWIDTH(item->rect);			pt.x = item->rect.left + pt.x/2 + pt.x%2;			pt.y = RECTHEIGHT(item->rect);			pt.y = item->rect.top + pt.y/2 + pt.y%2;			if (FALSE != ListWidget_GetViewOrigin(hwnd, &origin))			{				pt.x += origin.x;				pt.y += origin.y;			}		}		else		{			RECT rect;			GetClientRect(hwnd, &rect);			pt.x = rect.left + 2;			pt.y = rect.top + 2;		}		MapWindowPoints(hwnd, HWND_DESKTOP, &pt, 1);	}	else	{		POINT test;		pt = *cursor;				if (FALSE == ListWidget_GetViewOrigin(hwnd, &test))		{			test = pt;		}		else		{			test.x = pt.x - test.x;			test.y = pt.y - test.y;		}		MapWindowPoints(HWND_DESKTOP, hwnd, &test, 1);		item = ListWidget_GetItemFromPoint(self, test);	}	if (NULL == item)		ListWidget_DisplayContextMenu(self, hwnd, pt);	else		ListWidget_DisplayItemContextMenu(self, hwnd, item, pt);		return TRUE;};static void ListWidget_ZoomChangingCb(ListWidget *self, HWND hwnd, NMTRBTHUMBPOSCHANGING *zoomInfo){	double pos, height, width;	int cx, cy;			if (NULL == self)		return;	pos = (double)(int)zoomInfo->dwPos;	if (0 == pos)	{		height = LISTWIDGET_IMAGE_DEFAULT_HEIGHT;	}	else if (pos < 0)	{		height = ((LISTWIDGET_IMAGE_DEFAULT_HEIGHT - LISTWIDGET_IMAGE_MIN_HEIGHT) * (100.0 + pos))/100.0;		height += LISTWIDGET_IMAGE_MIN_HEIGHT;		height = floor(height);	}	else	{		height = ((LISTWIDGET_IMAGE_MAX_HEIGHT - LISTWIDGET_IMAGE_DEFAULT_HEIGHT) * pos)/100.0;		height += LISTWIDGET_IMAGE_DEFAULT_HEIGHT;		height = ceil(height);	}	width = (height * LISTWIDGET_IMAGE_DEFAULT_WIDTH)/ LISTWIDGET_IMAGE_DEFAULT_HEIGHT;	cx = (int)(width + 0.5);	cy = (int)(height + 0.5);	if (self->imageSize.cx == cx &&		self->imageSize.cy == cy)	{		return;	}	ListWidget_SetImageSize(self, hwnd, cx, cy, TRUE);	//	aTRACE_FMT("zoom changing: pos = %d, width = %d, height = %d\r\n", zoomInfo->dwPos, cx, cy);}static voidListWidget_ScrollCb(ListWidget *self, HWND hwnd, int *dx, int *dy){		if (NULL != self->titleEditor)	{		DestroyWindow(self->titleEditor);		self->titleEditor = NULL;	}	if (FALSE != ListWidget_UpdateHover(self, hwnd))		UpdateWindow(hwnd);			ListWidget_TooltipHide(self->tooltip);}static BOOLListWidget_NotifyCb(ListWidget *self, HWND hwnd, NMHDR *pnmh, LRESULT *result){	if (FALSE != ListWidget_TooltipProcessNotification(self, self->tooltip, pnmh, result))		return TRUE;	return FALSE;}HWND ListWidget_CreateWindow(HWND parentWindow, int x, int y, int width, int height, BOOL border, unsigned int controlId){	const static WidgetInterface widgetInterface =	{		(WidgetInitCallback)ListWidget_InitCb,		(WidgetDestroyCallback)ListWidget_DestroyCb,		(WidgetLayoutCallback)ListWidget_LayoutCb,		(WidgetPaintCallback)ListWidget_PaintCb,		(WidgetStyleCallback)ListWidget_StyleColorChangedCb,		(WidgetStyleCallback)ListWidget_StyleFontChangedCb,		(WidgetMouseCallback)ListWidget_MouseMoveCb,		(WidgetMouseCallback)ListWidget_LeftButtonDownCb,		(WidgetMouseCallback)ListWidget_LeftButtonUpCb,		(WidgetMouseCallback)ListWidget_LeftButtonDblClkCb,		(WidgetMouseCallback)ListWidget_RightButtonDownCb,		(WidgetMouseCallback)ListWidget_RightButtonUpCb,		(WidgetKeyCallback)ListWidget_KeyDownCb,		(WidgetKeyCallback)ListWidget_KeyUpCb,		(WidgetKeyCallback)ListWidget_CharacterCb,		(WidgetInputCallback)ListWidget_InputRequestCb,		(WidgetFocusCallback)ListWidget_FocusChangedCb,		(WidgetMenuCallback)ListWidget_ContextMenuCb,		(WidgetZoomCallback)ListWidget_ZoomChangingCb,		(WidgetScrollCallback)NULL, /*scrollBefore*/		(WidgetScrollCallback)ListWidget_ScrollCb,		(WidgetNotifyCallback)ListWidget_NotifyCb,	};	return Widget_CreateWindow(WIDGET_TYPE_LIST,								&widgetInterface, 								NULL,								(FALSE != border) ? WS_EX_CLIENTEDGE : 0, 								WS_TABSTOP, 								x, y, width, height, 								parentWindow, 								controlId, 0L);}
 |