loginTab.cpp 83 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192
  1. #include "./loginTab.h"
  2. #include "./common.h"
  3. #include "./imageLoader.h"
  4. #include "./loginGui.h"
  5. #include "./graphics.h"
  6. #include "../api.h"
  7. #include "../resource.h"
  8. #include "../../nu/windowsTheme.h"
  9. #include <vssym32.h>
  10. #include <vsstyle.h>
  11. #include <malloc.h>
  12. #include <math.h>
  13. #include <shlwapi.h>
  14. #include <commctrl.h>
  15. #include <strsafe.h>
  16. #define MAX_TEXT_AVECHAR_WIDTH 12
  17. #define MAX_HELP_AVECHAR_WIDTH 28
  18. #define IMAGE_MARGIN_CY 4
  19. #define IMAGE_MARGIN_CX 4
  20. #define NLTDS_FOCUSED 0x00000001
  21. #define NLTDS_DISABLED 0x00000002
  22. #define NLTDS_LOCKED 0x00000004
  23. typedef struct __LOGINTABITEM
  24. {
  25. LPWSTR text;
  26. UINT iImage;
  27. UINT iImageActive;
  28. UINT iImageDisabled;
  29. LPARAM param;
  30. LONG textWidth;
  31. } LOGINTABITEM;
  32. typedef struct __ITEMSTATECOLORTABLE
  33. {
  34. COLORREF backTop;
  35. COLORREF backBottom;
  36. COLORREF backAlpha;
  37. COLORREF text;
  38. INT frameType;
  39. } ITEMSTATECOLORTABLE;
  40. typedef struct __ITEMCOLORTABLE
  41. {
  42. ITEMSTATECOLORTABLE normal;
  43. ITEMSTATECOLORTABLE normalPressed;
  44. ITEMSTATECOLORTABLE normalHigh;
  45. ITEMSTATECOLORTABLE normalDisabled;
  46. ITEMSTATECOLORTABLE selected;
  47. ITEMSTATECOLORTABLE selectedPressed;
  48. ITEMSTATECOLORTABLE selectedHigh;
  49. ITEMSTATECOLORTABLE selectedDisabled;
  50. } ITEMCOLORTABLE;
  51. typedef struct __COLORTABLE
  52. {
  53. COLORREF backTop;
  54. COLORREF backBottom;
  55. COLORREF backLine;
  56. COLORREF focus;
  57. COLORREF focusDash;
  58. ITEMCOLORTABLE item;
  59. } COLORTABLE;
  60. typedef struct __LOGINTAB
  61. {
  62. LOGINTABITEM **items;
  63. INT itemsCount;
  64. INT *order;
  65. INT iSelected;
  66. INT iHighlighted;
  67. INT iPressed;
  68. INT iFocused;
  69. HIMAGELIST imageList;
  70. UINT drawStyle;
  71. COLORTABLE colors;
  72. HFONT fontText;
  73. LONG textHeight;
  74. LONG spacing;
  75. RECT margins;
  76. LONG textWidthMax;
  77. HBITMAP chevronImage;
  78. INT chevronWidth;
  79. HMENU chevronMenu;
  80. LONG chevronLeft;
  81. LONG visibleRight;
  82. INT lastVisible;
  83. HBITMAP frameBitmap;
  84. INT frameHeight;
  85. INT frameWidth;
  86. HBITMAP itemBitmap;
  87. HWND hTooltip;
  88. BSTR helpText;
  89. } LOGINTAB;
  90. typedef struct __CALCITEMWIDTH
  91. {
  92. HDC hdc;
  93. HFONT font;
  94. HWND hwnd;
  95. INT textWidthMax;
  96. INT imageWidth;
  97. INT imageHeight;
  98. INT itemHeight;
  99. INT frameWidth;
  100. INT dialogPt;
  101. HDC ownedDC;
  102. HFONT ownedFont;
  103. } CALCITEMWIDTH;
  104. #define FRAMETYPE_NONE 0
  105. #define FRAMETYPE_SELECTED 1
  106. #define FRAMETYPE_ACTIVE 2
  107. #define FRAMETYPE_DISABLED 0
  108. typedef struct __PAINTITEMPARAM
  109. {
  110. HWND hwndTab;
  111. HDC hdc;
  112. const RECT *prcPaint;
  113. const RECT *prcClient;
  114. HRGN clipRgn;
  115. HRGN eraseRgn;
  116. HDC hdcSrc;
  117. HDC hdcItem;
  118. } PAINTITEMPARAM;
  119. typedef struct __GETITEMRECTPARAM
  120. {
  121. INT index;
  122. RECT *rect;
  123. } GETITEMRECTPARAM;
  124. typedef struct __HITTESTITEMPARAM
  125. {
  126. POINT pt;
  127. RECT *rect;
  128. } HITTESTITEMPARAM;
  129. typedef struct __UPDATELAYOUTPARAM
  130. {
  131. INT itemCount;
  132. RECT visibleBox;
  133. BOOL chevronVisible;
  134. LONG chevronLeft;
  135. } UPDATELAYOUTPARAM;
  136. typedef struct __CHEVRONMENUPAINTPARAM
  137. {
  138. INT itemWidth;
  139. INT itemHeight;
  140. HDC hdcSrc;
  141. HDC hdcItem;
  142. RECT ownerRect;
  143. HWND hwndMenu;
  144. } CHEVRONMENUPAINTPARAM;
  145. #define GetTab(__hwnd) ((LOGINTAB*)(LONG_PTR)(LONGX86)GetWindowLongPtr((__hwnd), 0))
  146. static LRESULT WINAPI LoginTab_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  147. typedef INT (CALLBACK *ITEMRECTCALLBAC)(LOGINTAB* /*tab*/, LOGINTABITEM* /*item*/, INT /*iItem*/, const RECT* /*prcItem*/, ULONG_PTR /*param*/);
  148. BOOL LoginTab_RegisterClass(HINSTANCE hInstance)
  149. {
  150. WNDCLASSW wc;
  151. if (FALSE != GetClassInfo(hInstance, NWC_LOGINTAB, &wc))
  152. return TRUE;
  153. ZeroMemory(&wc, sizeof(wc));
  154. wc.lpszClassName = NWC_LOGINTAB;
  155. wc.lpfnWndProc = LoginTab_WindowProc;
  156. wc.style = CS_PARENTDC;
  157. wc.cbWndExtra = sizeof(LOGINTAB*);
  158. wc.hInstance = hInstance;
  159. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  160. return ( 0 != RegisterClassW(&wc));
  161. }
  162. HWND LoginTab_CreateWindow(UINT styleEx, LPCWSTR pszTitle, UINT style, INT x, INT y, INT cx, INT cy, HWND hParent, INT_PTR controlId)
  163. {
  164. if (FALSE == LoginTab_RegisterClass(WASABI_API_ORIG_HINST))
  165. return FALSE;
  166. HWND hwnd = CreateWindowEx(styleEx, NWC_LOGINTAB, pszTitle, WS_CHILD | style,
  167. x, y, cx, cy, hParent, (HMENU)controlId, WASABI_API_ORIG_HINST, NULL);
  168. return hwnd;
  169. }
  170. static BOOL LoginTab_IsLocked(HWND hwnd)
  171. {
  172. UINT windowStyle = GetWindowStyle(hwnd);
  173. return (0 != (NLTS_LOCKED & windowStyle));
  174. }
  175. static BOOL LoginTab_InitCalcItemWidth(HWND hwnd, HDC hdc, CALCITEMWIDTH *pciw)
  176. {
  177. LOGINTAB *tab = GetTab(hwnd);
  178. if (NULL == tab || NULL == pciw) return FALSE;
  179. pciw->hdc = hdc;
  180. pciw->font = tab->fontText;
  181. pciw->hwnd = hwnd;
  182. pciw->textWidthMax = tab->textWidthMax;
  183. if (NULL == tab->imageList || FALSE == ImageList_GetIconSize(tab->imageList, &pciw->imageWidth, &pciw->imageHeight))
  184. {
  185. pciw->imageWidth = 0;
  186. pciw->imageHeight = 0;
  187. }
  188. else
  189. {
  190. pciw->imageWidth += 2 * IMAGE_MARGIN_CX;
  191. pciw->imageHeight += 2 * IMAGE_MARGIN_CY;
  192. }
  193. RECT rect;
  194. GetClientRect(hwnd, &rect);
  195. pciw->itemHeight = tab->frameHeight * 2 + tab->textHeight + pciw->imageHeight;
  196. pciw->frameWidth = tab->frameWidth;
  197. pciw->dialogPt = tab->spacing;
  198. pciw->ownedDC = NULL;
  199. pciw->ownedFont = NULL;
  200. return TRUE;
  201. }
  202. static BOOL LoginTab_DestroyCalcItemWidth(CALCITEMWIDTH *pciw)
  203. {
  204. if (NULL == pciw) return FALSE;
  205. if (NULL != pciw->ownedDC)
  206. {
  207. SelectObject(pciw->ownedDC, pciw->ownedFont);
  208. ReleaseDC(pciw->hwnd, pciw->ownedDC);
  209. }
  210. return TRUE;
  211. }
  212. static INT LoginTab_CalculateItemWidth(CALCITEMWIDTH *pciw, LOGINTABITEM *item)
  213. {
  214. if (NULL == pciw || NULL == item) return 0;
  215. if (-1 == item->textWidth)
  216. {
  217. if (NULL != item->text && L'\0' != *(item->text))
  218. {
  219. if (NULL == pciw->hdc)
  220. {
  221. pciw->ownedDC = GetDCEx(pciw->hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
  222. if (NULL == pciw->ownedDC) return 0;
  223. pciw->ownedFont = (HFONT)SelectObject(pciw->ownedDC, pciw->font);
  224. pciw->hdc = pciw->ownedDC;
  225. }
  226. SIZE textSize;
  227. if (FALSE == GetTextExtentPoint(pciw->hdc, item->text, lstrlen(item->text), &textSize))
  228. return 0;
  229. item->textWidth = textSize.cx;
  230. }
  231. else
  232. item->textWidth = 0;
  233. }
  234. INT width = (item->textWidth > pciw->imageWidth) ? item->textWidth : pciw->imageWidth;
  235. if (width > pciw->textWidthMax) width = pciw->textWidthMax;
  236. width += 2*pciw->frameWidth; // borders
  237. if (width < pciw->itemHeight)
  238. {
  239. INT k = (pciw->itemHeight - width)/(2*pciw->dialogPt);
  240. if (k > 2) k = 2;
  241. width += 2*k*pciw->dialogPt;
  242. }
  243. return width;
  244. }
  245. static INT LoginTab_EnumerateItemRects(HWND hwnd, HDC hdc, ITEMRECTCALLBAC callback, ULONG_PTR param)
  246. {
  247. LOGINTAB *tab = GetTab(hwnd);
  248. if (NULL == tab || NULL == callback) return -1;
  249. RECT clientRect, tabRect;
  250. LONG chevronLeft, limitRight;
  251. GetClientRect(hwnd, &clientRect);
  252. chevronLeft = clientRect.right - tab->chevronWidth;
  253. clientRect.left += tab->margins.left;
  254. clientRect.top += tab->margins.top;
  255. clientRect.right -= tab->margins.right;
  256. clientRect.bottom -= tab->margins.bottom;
  257. limitRight = (chevronLeft < clientRect.right) ? chevronLeft : clientRect.right;
  258. CALCITEMWIDTH calcWidth;
  259. if (FALSE == LoginTab_InitCalcItemWidth(hwnd, hdc, &calcWidth))
  260. return -1;
  261. SetRect(&tabRect, clientRect.left, clientRect.top, clientRect.left, clientRect.bottom);
  262. INT result, index, lastItem;
  263. lastItem = tab->itemsCount - 1;
  264. result = -1;
  265. BOOL ignoreVisibleUpdate = FALSE;
  266. for (index = 0; index < tab->itemsCount; index++)
  267. {
  268. tabRect.left = tabRect.right;
  269. if (tabRect.left != clientRect.left)
  270. tabRect.left += tab->spacing;
  271. if (tabRect.left > limitRight)
  272. {
  273. tabRect.right = clientRect.right + 1;
  274. break;
  275. }
  276. INT iItem = tab->order[index];
  277. LOGINTABITEM *item = tab->items[iItem];
  278. INT width = LoginTab_CalculateItemWidth(&calcWidth, item);
  279. if (0 == width) break;
  280. tabRect.right = tabRect.left + width;
  281. if ((index == lastItem && tabRect.right > clientRect.right) ||
  282. (index < lastItem && tabRect.right > limitRight))
  283. {
  284. break;
  285. }
  286. result = callback(tab, item, iItem, &tabRect, param);
  287. if (-1 != result)
  288. {
  289. ignoreVisibleUpdate = TRUE;
  290. break;
  291. }
  292. }
  293. if (FALSE == ignoreVisibleUpdate)
  294. {
  295. if ((index == lastItem && tabRect.right > clientRect.right) ||
  296. (index < lastItem && tabRect.right > limitRight))
  297. {
  298. tab->lastVisible = (index - 1);
  299. SetRect(&tabRect, chevronLeft, clientRect.top,
  300. clientRect.right + tab->margins.right, clientRect.bottom);
  301. result = callback(tab, NULL, tab->itemsCount, &tabRect, param);
  302. }
  303. else
  304. tab->lastVisible = lastItem;
  305. }
  306. LoginTab_DestroyCalcItemWidth(&calcWidth);
  307. return result;
  308. }
  309. static void LoginTab_NotifySelectionChanged(HWND hwnd)
  310. {
  311. HWND hParent = GetAncestor(hwnd, GA_PARENT);
  312. if (NULL == hParent) return;
  313. NMHDR nmhdr;
  314. nmhdr.code = NLTN_SELCHANGE;
  315. nmhdr.hwndFrom = hwnd;
  316. nmhdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
  317. SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmhdr.idFrom, (LPARAM)&nmhdr);
  318. }
  319. static HBITMAP LoginTab_GetItemBitmap(LOGINTAB *tab, HDC hdc, INT cx, INT cy)
  320. {
  321. if (cx < 1) cx = 1;
  322. if (cy < 1) cy = 1;
  323. BITMAP bm;
  324. if (NULL == tab->itemBitmap ||
  325. sizeof(BITMAP) != GetObject(tab->itemBitmap, sizeof(BITMAP), &bm) ||
  326. bm.bmWidth <= cx || abs(bm.bmHeight) < cy)
  327. {
  328. if (NULL != tab->itemBitmap)
  329. DeleteObject(tab->itemBitmap);
  330. cx++; // need +1px to compose selection fill
  331. tab->itemBitmap = CreateCompatibleBitmap(hdc, cx, cy);
  332. }
  333. return tab->itemBitmap;
  334. }
  335. static HBITMAP LoginTab_LoadChevronImage(HWND hwnd, INT *imageWidth, INT *imageHeight)
  336. {
  337. INT width, height;
  338. HBITMAP hbmpDst, hbmpSrc;
  339. hbmpSrc = ImageLoader_LoadBitmap(WASABI_API_ORIG_HINST,
  340. MAKEINTRESOURCE(IDR_ARROW_IMAGE), FALSE, &width, &height);
  341. if (NULL == hbmpSrc)
  342. return NULL;
  343. if (height < 0) height = -height;
  344. INT frameHeight = height/2;
  345. INT frameWidth = width;
  346. BITMAPINFOHEADER bhi;
  347. ZeroMemory(&bhi, sizeof(bhi));
  348. bhi.biSize = sizeof(bhi);
  349. bhi.biCompression = BI_RGB;
  350. bhi.biBitCount = 32;
  351. bhi.biPlanes = 1;
  352. bhi.biWidth = frameWidth;
  353. bhi.biHeight = 4 * frameHeight;
  354. UINT *pixelData;
  355. hbmpDst = CreateDIBSection(NULL, (LPBITMAPINFO)&bhi, DIB_RGB_COLORS, (void**)&pixelData, NULL, 0);
  356. if (NULL == hbmpDst)
  357. {
  358. DeleteObject(hbmpSrc);
  359. return NULL;
  360. }
  361. BOOL resultOk = FALSE;
  362. HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
  363. if (NULL != hdc)
  364. {
  365. HDC hdcSrc = CreateCompatibleDC(hdc);
  366. HDC hdcDst = CreateCompatibleDC(hdc);
  367. if (NULL != hdcSrc && NULL != hdcDst)
  368. {
  369. HBITMAP hbmpSrcOrig = (HBITMAP)SelectObject(hdcSrc, hbmpSrc);
  370. HBITMAP hbmpDstOrig = (HBITMAP)SelectObject(hdcDst, hbmpDst);
  371. RECT imageRect;
  372. SetRect(&imageRect, 0, 0, frameWidth, frameHeight);
  373. BOOL blitFailed = FALSE;
  374. // normal
  375. if (FALSE == blitFailed &&
  376. FALSE != BitBlt(hdcDst, 0, 0*frameHeight, frameWidth, frameHeight, hdcSrc, 0, 0, SRCCOPY))
  377. {
  378. Image_AdjustSaturationAlpha(hbmpDst, &imageRect, -150, -100);
  379. }
  380. else blitFailed = TRUE;
  381. // active
  382. if (FALSE == blitFailed &&
  383. FALSE == BitBlt(hdcDst, 0, 1*frameHeight, frameWidth, frameHeight, hdcSrc, 0, 0, SRCCOPY))
  384. {
  385. blitFailed = TRUE;
  386. }
  387. // disabled
  388. if (FALSE == blitFailed &&
  389. FALSE != BitBlt(hdcDst, 0, 2*frameHeight, frameWidth, frameHeight, hdcSrc, 0, 0, SRCCOPY))
  390. {
  391. OffsetRect(&imageRect, 0, 2*frameHeight);
  392. Image_AdjustSaturationAlpha(hbmpDst, &imageRect, -(150 + 600), -(100 + 600));
  393. }
  394. else blitFailed = TRUE;
  395. // pressed
  396. if (FALSE == blitFailed &&
  397. FALSE == BitBlt(hdcDst, 0, 3*frameHeight, frameWidth, frameHeight, hdcSrc, 0, frameHeight, SRCCOPY))
  398. {
  399. blitFailed = TRUE;
  400. }
  401. if (FALSE == blitFailed)
  402. {
  403. SetRect(&imageRect, 0, 0, bhi.biWidth, -bhi.biHeight);
  404. Image_Premultiply(hbmpDst, &imageRect);
  405. resultOk = TRUE;
  406. }
  407. SelectObject(hdcSrc, hbmpSrcOrig);
  408. SelectObject(hdcDst, hbmpDstOrig);
  409. }
  410. if (NULL != hdcSrc) DeleteDC(hdcSrc);
  411. if (NULL != hdcDst) DeleteDC(hdcDst);
  412. ReleaseDC(hwnd, hdc);
  413. }
  414. DeleteObject(hbmpSrc);
  415. if (FALSE == resultOk)
  416. {
  417. DeleteObject(hbmpDst);
  418. hbmpDst = NULL;
  419. }
  420. else
  421. {
  422. if (NULL != imageWidth) *imageWidth = width;
  423. if (NULL != imageHeight) *imageHeight = height;
  424. }
  425. return hbmpDst;
  426. }
  427. static BOOL LoginTab_GradientFillVertRect(HDC hdc, const RECT *prcFill, COLORREF rgbTop, COLORREF rgbBottom)
  428. {
  429. TRIVERTEX szVertex[2];
  430. szVertex[0].x = prcFill->left;
  431. szVertex[0].y = prcFill->top;
  432. szVertex[0].Red = GetRValue(rgbTop) << 8;
  433. szVertex[0].Green = GetGValue(rgbTop) << 8;
  434. szVertex[0].Blue = GetBValue(rgbTop) << 8;
  435. szVertex[0].Alpha = 0x0000;
  436. szVertex[1].x = prcFill->right;
  437. szVertex[1].y = prcFill->bottom;
  438. szVertex[1].Red = GetRValue(rgbBottom) << 8;
  439. szVertex[1].Green = GetGValue(rgbBottom) << 8;
  440. szVertex[1].Blue = GetBValue(rgbBottom) << 8;
  441. szVertex[1].Alpha = 0x0000;
  442. GRADIENT_RECT szMesh[1];
  443. szMesh[0].UpperLeft = 0;
  444. szMesh[0].LowerRight = 1;
  445. return GdiGradientFill(hdc, szVertex, ARRAYSIZE(szVertex), szMesh, 1, GRADIENT_FILL_RECT_V);
  446. }
  447. static void LoginTab_EraseBkGround(HDC hdc, LOGINTAB *tab, LONG clientHeight, const RECT *prcPaint)
  448. {
  449. RECT rect;
  450. LONG middleY = clientHeight/2;
  451. COLORREF rgbOrig = SetBkColor(hdc, tab->colors.backTop);
  452. CopyRect(&rect, prcPaint);
  453. rect.bottom = middleY;
  454. if (rect.top < rect.bottom)
  455. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  456. SetRect(&rect, prcPaint->left, middleY, prcPaint->right, clientHeight - 1);
  457. if (FALSE == LoginTab_GradientFillVertRect(hdc, &rect, tab->colors.backTop, tab->colors.backBottom))
  458. {
  459. SetBkColor(hdc, tab->colors.backBottom);
  460. if (prcPaint->bottom < rect.bottom)
  461. rect.bottom = prcPaint->bottom;
  462. if (rect.top < rect.bottom)
  463. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  464. }
  465. if (prcPaint->bottom == clientHeight)
  466. {
  467. SetBkColor(hdc, tab->colors.backLine);
  468. SetRect(&rect, prcPaint->left, clientHeight - 1, prcPaint->right, clientHeight);
  469. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  470. }
  471. SetBkColor(hdc, rgbOrig);
  472. }
  473. static BOOL LoginTab_PaintItemFrame(HDC hdc, LOGINTAB *tab, INT frameType, const RECT *prcItem, const RECT *prcPaint, HDC hdcSrc)
  474. {
  475. if (NULL == tab->frameBitmap)
  476. return FALSE;
  477. INT offsetY;
  478. switch(frameType)
  479. {
  480. case FRAMETYPE_SELECTED: offsetY = 0; break;
  481. case FRAMETYPE_ACTIVE: offsetY = 1 * (tab->frameHeight * 2 + 1); break;
  482. case FRAMETYPE_DISABLED: offsetY = 2 * (tab->frameHeight * 2 + 1); break;
  483. default: return FALSE;
  484. }
  485. SelectObject(hdcSrc, tab->frameBitmap);
  486. BLENDFUNCTION bf;
  487. bf.BlendOp = AC_SRC_OVER;
  488. bf.BlendFlags = 0;
  489. bf.SourceConstantAlpha = 255;
  490. bf.AlphaFormat = AC_SRC_ALPHA;
  491. INT lineLength;
  492. // left-top
  493. GdiAlphaBlend(hdc, prcItem->left, prcItem->top, tab->frameWidth, tab->frameHeight,
  494. hdcSrc, 0, offsetY + 0, tab->frameWidth, tab->frameHeight, bf);
  495. // right-top
  496. GdiAlphaBlend(hdc, prcItem->right - tab->frameWidth, prcItem->top, tab->frameWidth, tab->frameHeight,
  497. hdcSrc, tab->frameWidth + 1, offsetY + 0, tab->frameWidth, tab->frameHeight, bf);
  498. // right-bottom
  499. GdiAlphaBlend(hdc, prcItem->right - tab->frameWidth, prcItem->bottom - tab->frameHeight, tab->frameWidth, tab->frameHeight,
  500. hdcSrc, tab->frameWidth + 1, offsetY + tab->frameHeight + 1, tab->frameWidth, tab->frameHeight, bf);
  501. // left-bottom
  502. GdiAlphaBlend(hdc, prcItem->left, prcItem->bottom - tab->frameHeight, tab->frameWidth, tab->frameHeight,
  503. hdcSrc, 0, offsetY + tab->frameHeight + 1, tab->frameWidth, tab->frameHeight, bf);
  504. lineLength = (prcItem->right - prcItem->left) - tab->frameWidth * 2;
  505. // top
  506. GdiAlphaBlend(hdc, prcItem->left + tab->frameWidth, prcItem->top, lineLength, tab->frameHeight,
  507. hdcSrc, tab->frameWidth, offsetY + 0, 1, tab->frameHeight, bf);
  508. // bottom
  509. GdiAlphaBlend(hdc, prcItem->left + tab->frameWidth, prcItem->bottom - tab->frameHeight, lineLength, tab->frameHeight,
  510. hdcSrc, tab->frameWidth, offsetY + tab->frameHeight + 1, 1, tab->frameHeight, bf);
  511. lineLength = (prcItem->bottom - prcItem->top) - tab->frameHeight * 2;
  512. // left
  513. GdiAlphaBlend(hdc, prcItem->left, prcItem->top + tab->frameHeight, tab->frameWidth, lineLength,
  514. hdcSrc, 0, offsetY + tab->frameHeight, tab->frameWidth, 1, bf);
  515. // right
  516. GdiAlphaBlend(hdc, prcItem->right - tab->frameWidth, prcItem->top + tab->frameHeight, tab->frameWidth, lineLength,
  517. hdcSrc, tab->frameWidth + 1, offsetY + tab->frameHeight, tab->frameWidth, 1, bf);
  518. return TRUE;
  519. }
  520. static BOOL LoginTab_FillItem(HDC hdc, const RECT *prcItem, const RECT *prcPaint, INT alpha, COLORREF rgbTop, COLORREF rgbBottom, INT tempX)
  521. {
  522. RECT rect;
  523. SetRect(&rect, tempX, prcItem->top, tempX + 1, prcItem->bottom);
  524. if (rgbTop == rgbBottom || FALSE == LoginTab_GradientFillVertRect(hdc, &rect, rgbTop, rgbBottom))
  525. {
  526. COLORREF rgbOrig = SetBkColor(hdc, rgbBottom);
  527. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  528. if (rgbOrig != rgbBottom) SetBkColor(hdc, rgbOrig);
  529. }
  530. INT height = prcPaint->bottom - prcPaint->top;
  531. BLENDFUNCTION bf;
  532. bf.BlendOp = AC_SRC_OVER;
  533. bf.BlendFlags = 0;
  534. bf.SourceConstantAlpha = alpha;
  535. bf.AlphaFormat = 0x00;
  536. BOOL result = GdiAlphaBlend(hdc, prcPaint->left, prcPaint->top, 1, height,
  537. hdc, tempX, prcPaint->top, 1, height, bf);
  538. if (FALSE != result)
  539. {
  540. INT stretchModeOrig = SetStretchBltMode(hdc, COLORONCOLOR);
  541. result = StretchBlt(hdc, prcPaint->left + 1, prcPaint->top, prcPaint->right - prcPaint->left - 1, height,
  542. hdc, prcPaint->left, prcPaint->top, 1, height, SRCCOPY);
  543. if (COLORONCOLOR != stretchModeOrig)
  544. SetStretchBltMode(hdc, stretchModeOrig);
  545. }
  546. return result;
  547. }
  548. static void LoginTab_DrawRect(HDC hdc, const RECT *prc)
  549. {
  550. RECT rect;
  551. SetRect(&rect, prc->left +1, prc->top, prc->right -1, prc->top + 1);
  552. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  553. SetRect(&rect, prc->left + 1, prc->bottom-1, prc->right -1, prc->bottom);
  554. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  555. SetRect(&rect, prc->left, prc->top + 1, prc->left + 1, prc->bottom - 1);
  556. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  557. SetRect(&rect, prc->right - 1, prc->top + 1, prc->right, prc->bottom - 1);
  558. ExtTextOut(hdc, 0, 0, ETO_OPAQUE, &rect, NULL, 0, NULL);
  559. }
  560. static BOOL LoginTab_PaintChevron(HDC hdc, LOGINTAB *tab, const RECT *prcItem, const RECT *prcPaint, HDC hdcSrc)
  561. {
  562. ITEMSTATECOLORTABLE *color;
  563. INT iItem = tab->itemsCount;
  564. if (0 != ((NLTDS_LOCKED | NLTDS_DISABLED) & tab->drawStyle))
  565. color = &tab->colors.item.normalDisabled;
  566. else
  567. {
  568. if (iItem == tab->iPressed)
  569. color = &tab->colors.item.normalPressed;
  570. else if (iItem == tab->iHighlighted)
  571. color = &tab->colors.item.normalHigh;
  572. else
  573. color = &tab->colors.item.normal;
  574. }
  575. RECT rect, itemRect;
  576. CopyRect(&itemRect, prcItem);
  577. if (iItem == tab->iFocused && 0 != (NLTDS_FOCUSED & tab->drawStyle))
  578. {
  579. CopyRect(&rect, prcItem);
  580. InflateRect(&rect, -(tab->frameWidth - 2), -(tab->frameWidth - 2));
  581. COLORREF rgbBkOrig = SetBkColor(hdc, tab->colors.focus);
  582. COLORREF rgbTextOrig = SetTextColor(hdc, tab->colors.focusDash);
  583. DrawFocusRect(hdc, &rect);
  584. //LoginTab_DrawRect(hdc, &rect);
  585. if (rgbBkOrig != tab->colors.focus) SetBkColor(hdc, rgbBkOrig);
  586. if (rgbTextOrig != tab->colors.focusDash) SetTextColor(hdc, rgbTextOrig);
  587. }
  588. INT frameType = color->frameType;
  589. if (iItem == tab->iFocused && 0 != (NLTDS_FOCUSED & tab->drawStyle))
  590. frameType = FRAMETYPE_ACTIVE;
  591. if (FRAMETYPE_NONE != frameType &&
  592. FALSE != LoginTab_PaintItemFrame(hdc, tab, frameType, prcItem, prcPaint, hdcSrc))
  593. {
  594. InflateRect(&itemRect, -(tab->frameWidth -1), -(tab->frameHeight -1));
  595. }
  596. if (0 != color->backAlpha && FALSE != IntersectRect(&rect, &itemRect, prcPaint))
  597. {
  598. LoginTab_FillItem(hdc, &itemRect, &rect, color->backAlpha, color->backTop, color->backBottom, prcPaint->right);
  599. }
  600. if (NULL != tab->chevronImage)
  601. {
  602. BITMAP bm;
  603. if (sizeof(bm) == GetObject(tab->chevronImage, sizeof(bm), &bm))
  604. {
  605. if (bm.bmHeight < 0) bm.bmHeight = -bm.bmHeight;
  606. bm.bmHeight = bm.bmHeight/4;
  607. INT cx = bm.bmWidth;
  608. INT cy = bm.bmHeight;
  609. INT offsetY;
  610. if (0 != ((NLTDS_LOCKED | NLTDS_DISABLED) & tab->drawStyle))
  611. offsetY = 2*bm.bmHeight;
  612. else if (iItem == tab->iPressed)
  613. offsetY = 3*bm.bmHeight;
  614. else if (iItem == tab->iHighlighted || iItem == tab->iSelected)
  615. offsetY = 1*bm.bmHeight;
  616. else
  617. offsetY = 0;
  618. INT x = prcItem->left + ((prcItem->right - prcItem->left) - cx)/2;
  619. if (x < prcItem->left) x = prcItem->left;
  620. INT y = prcItem->top + ((prcItem->bottom - prcItem->top) - cy)/2;
  621. if (y < prcItem->top) y = prcItem->top;
  622. if ((x + cx) > prcItem->right) cx = prcItem->right - x;
  623. if ((y + cy) > prcItem->bottom) cy = prcItem->bottom - y;
  624. if (iItem == tab->iPressed) y++;
  625. SelectObject(hdcSrc, tab->chevronImage);
  626. BLENDFUNCTION bf;
  627. bf.BlendOp = AC_SRC_OVER;
  628. bf.BlendFlags = 0;
  629. bf.SourceConstantAlpha = 255;
  630. bf.AlphaFormat = AC_SRC_ALPHA;
  631. GdiAlphaBlend(hdc, x, y, cx, cy, hdcSrc, 0, offsetY, bm.bmWidth, bm.bmHeight, bf);
  632. }
  633. }
  634. return TRUE;
  635. }
  636. static void LoginTab_ResolveImageIndex(HWND hwnd, HIMAGELIST imageList, LOGINTABITEM *item, INT iItem, UINT requestMask)
  637. {
  638. HWND hParent = GetAncestor(hwnd, GA_PARENT);
  639. if (NULL == hParent) return;
  640. NMLOGINTABIMAGE request;
  641. request.hdr.code = NLTN_GETITEMIMAGE;
  642. request.hdr.hwndFrom = hwnd;
  643. request.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
  644. request.iItem = iItem;
  645. request.param = item->param;
  646. request.imageList = imageList;
  647. request.maskRequest = requestMask;
  648. request.maskUpdate = 0;
  649. request.iImage = item->iImage;
  650. request.iImageActive = item->iImageActive;
  651. request.iImageDisabled = item->iImageDisabled;
  652. SNDMSG(hParent, WM_NOTIFY, (WPARAM)request.hdr.idFrom, (LPARAM)&request);
  653. if (0 != request.maskUpdate)
  654. {
  655. if (0 != (NLTIF_IMAGE & request.maskUpdate))
  656. item->iImage = request.iImage;
  657. if (0 != (NLTIF_IMAGE_ACTIVE & request.maskUpdate))
  658. item->iImageActive = request.iImageActive;
  659. if (0 != (NLTIF_IMAGE_DISABLED & request.maskUpdate))
  660. item->iImageDisabled = request.iImageDisabled;
  661. }
  662. }
  663. static UINT LoginTab_GetImageIndex(HWND hwnd, HIMAGELIST imageList, LOGINTABITEM *item, INT iItem, UINT imageType)
  664. {
  665. if (NULL == item) return NLTM_IMAGE_NONE;
  666. switch(imageType & NLTIF_IMAGE_MASK)
  667. {
  668. case NLTIF_IMAGE_ACTIVE:
  669. if (NLTM_IMAGE_CALLBACK == item->iImageActive)
  670. {
  671. LoginTab_ResolveImageIndex(hwnd, imageList, item, iItem, NLTIF_IMAGE_ACTIVE);
  672. if (NLTM_IMAGE_CALLBACK == item->iImageActive)
  673. break;
  674. }
  675. if (NLTM_IMAGE_NONE != item->iImageActive)
  676. return item->iImageActive;
  677. break;
  678. case NLTIF_IMAGE_DISABLED:
  679. if (NLTM_IMAGE_CALLBACK == item->iImageDisabled)
  680. {
  681. LoginTab_ResolveImageIndex(hwnd, imageList, item, iItem, NLTIF_IMAGE_DISABLED);
  682. if (NLTM_IMAGE_CALLBACK == item->iImageDisabled)
  683. break;
  684. }
  685. if (NLTM_IMAGE_NONE != item->iImageDisabled)
  686. return item->iImageDisabled;
  687. break;
  688. }
  689. if (NLTM_IMAGE_CALLBACK == item->iImage)
  690. LoginTab_ResolveImageIndex(hwnd, imageList, item, iItem, NLTIF_IMAGE);
  691. return item->iImage;
  692. }
  693. static BOOL LoginTab_PaintItem(HWND hwndTab, HDC hdc, LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, const RECT *prcPaint, HDC hdcSrc)
  694. {
  695. ITEMSTATECOLORTABLE *color;
  696. UINT imageType;
  697. if (iItem == tab->iSelected)
  698. {
  699. if (0 != (NLTDS_DISABLED & tab->drawStyle))
  700. {
  701. color = &tab->colors.item.selectedDisabled;
  702. imageType = NLTIF_IMAGE_DISABLED;
  703. }
  704. else
  705. {
  706. if (0 != (NLTDS_LOCKED & tab->drawStyle))
  707. {
  708. color = &tab->colors.item.selected;
  709. }
  710. else
  711. {
  712. if (iItem == tab->iPressed)
  713. color = &tab->colors.item.selectedPressed;
  714. else if (iItem == tab->iHighlighted)
  715. color = &tab->colors.item.selectedHigh;
  716. else
  717. color = &tab->colors.item.selected;
  718. }
  719. imageType = NLTIF_IMAGE_ACTIVE;
  720. }
  721. }
  722. else
  723. {
  724. if (0 != ((NLTDS_DISABLED | NLTDS_LOCKED) & tab->drawStyle))
  725. {
  726. color = &tab->colors.item.normalDisabled;
  727. imageType = NLTIF_IMAGE_DISABLED;
  728. }
  729. else if (iItem == tab->iPressed)
  730. {
  731. color = &tab->colors.item.normalPressed;
  732. imageType = NLTIF_IMAGE_ACTIVE;
  733. }
  734. else if (iItem == tab->iHighlighted)
  735. {
  736. color = &tab->colors.item.normalHigh;
  737. imageType = NLTIF_IMAGE_ACTIVE;
  738. }
  739. else
  740. {
  741. color = &tab->colors.item.normal;
  742. imageType = NLTIF_IMAGE;
  743. }
  744. }
  745. RECT rect, itemRect;
  746. CopyRect(&itemRect, prcItem);
  747. if (FRAMETYPE_NONE != color->frameType &&
  748. FALSE != LoginTab_PaintItemFrame(hdc, tab, color->frameType, prcItem, prcPaint, hdcSrc))
  749. {
  750. InflateRect(&itemRect, -(tab->frameWidth -1), -(tab->frameHeight -1));
  751. }
  752. if (0 != color->backAlpha && FALSE != IntersectRect(&rect, &itemRect, prcPaint))
  753. {
  754. LoginTab_FillItem(hdc, &itemRect, &rect, color->backAlpha, color->backTop, color->backBottom, prcPaint->right);
  755. }
  756. if (iItem == tab->iFocused && 0 != (NLTDS_FOCUSED & tab->drawStyle))
  757. {
  758. CopyRect(&rect, prcItem);
  759. InflateRect(&rect, -(tab->frameWidth - 2), -(tab->frameWidth - 2));
  760. COLORREF rgbBkOrig = SetBkColor(hdc, tab->colors.focus);
  761. COLORREF rgbTextOrig = SetTextColor(hdc, tab->colors.focusDash);
  762. DrawFocusRect(hdc, &rect);
  763. //LoginTab_DrawRect(hdc, &rect);
  764. if (rgbBkOrig != tab->colors.focus) SetBkColor(hdc, rgbBkOrig);
  765. if (rgbTextOrig != tab->colors.focusDash) SetTextColor(hdc, rgbTextOrig);
  766. }
  767. if (NULL != tab->imageList)
  768. {
  769. UINT iImage = LoginTab_GetImageIndex(hwndTab, tab->imageList, item, iItem, imageType);
  770. if (NLTM_IMAGE_NONE != iImage)
  771. {
  772. IMAGELISTDRAWPARAMS dp;
  773. dp.cbSize = 56/*sizeof(IMAGELISTDRAWPARAMS) - sizeof(DWORD) * 3*/;
  774. dp.himl = tab->imageList;
  775. dp.i = iImage;
  776. dp.hdcDst = hdc;
  777. ImageList_GetIconSize(tab->imageList, &dp.cx, &dp.cy);
  778. dp.x = prcItem->left + ((prcItem->right - prcItem->left) - dp.cx)/2;
  779. if (dp.x < (prcItem->left + tab->frameWidth)) dp.x = prcItem->left + tab->frameWidth;
  780. if ((dp.x + dp.cx) > (prcItem->right - tab->frameWidth))
  781. {
  782. dp.cx = prcItem->right - tab->frameWidth - dp.x;
  783. if (dp.cx < 0) dp.cx = 0;
  784. }
  785. dp.y = prcItem->top + tab->frameHeight + IMAGE_MARGIN_CY;
  786. if ((dp.y + dp.cy) > (prcItem->bottom - tab->frameHeight))
  787. {
  788. dp.cy = prcItem->bottom - tab->frameHeight- dp.y;
  789. if (dp.cy < 0) dp.cy = 0;
  790. }
  791. dp.xBitmap = 0;
  792. dp.yBitmap = 0;
  793. dp.rgbBk = CLR_NONE;
  794. dp.rgbFg = CLR_NONE;
  795. dp.fStyle = ILD_NORMAL;
  796. dp.dwRop = SRCCOPY;
  797. dp.fState = ILS_NORMAL /*| ILS_SATURATE*/ /*| ILS_ALPHA*/;
  798. dp.Frame = 255;
  799. dp.crEffect = 0;
  800. if (dp.cx > 0 && dp.cy > 0)
  801. ImageList_DrawIndirect(&dp);
  802. }
  803. }
  804. if (NULL != item->text && L'\0' != *item->text)
  805. {
  806. LONG left = prcItem->left + ((prcItem->right - prcItem->left) - item->textWidth) / 2;
  807. if (left < (prcItem->left + tab->frameWidth)) left = prcItem->left + tab->frameWidth;
  808. LONG top = prcItem->bottom - tab->textHeight - tab->frameHeight + 1;
  809. SetRect(&rect, left, top, left + item->textWidth, top + tab->textHeight);
  810. if (rect.right > (prcItem->right - tab->frameWidth)) rect.right = prcItem->right - tab->frameWidth;
  811. if (rect.bottom > prcPaint->bottom) rect.bottom = prcPaint->bottom;
  812. if (rect.top < prcPaint->top) rect.top = prcPaint->top;
  813. if (rect.right > prcPaint->right) rect.right = prcPaint->right;
  814. if (rect.left < prcPaint->left) rect.left = prcPaint->left;
  815. if (rect.left < rect.right && rect.top < rect.bottom)
  816. {
  817. SetTextColor(hdc, color->text);
  818. INT cchText = lstrlen(item->text);
  819. ExtTextOut(hdc, left, top, ETO_CLIPPED, &rect, item->text, cchText, NULL);
  820. }
  821. }
  822. return TRUE;
  823. }
  824. static INT CALLBACK LoginTab_PaintItemCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param)
  825. {
  826. PAINTITEMPARAM *pip = (PAINTITEMPARAM*)param;
  827. if (NULL == pip) return -2;
  828. RECT paintRect;
  829. if (FALSE != IntersectRect(&paintRect, pip->prcPaint, prcItem))
  830. {
  831. SetRectRgn(pip->clipRgn, paintRect.left, paintRect.top, paintRect.right, paintRect.bottom);
  832. CombineRgn(pip->eraseRgn, pip->eraseRgn, pip->clipRgn, RGN_DIFF);
  833. HBITMAP hbmp = LoginTab_GetItemBitmap(tab, pip->hdc,
  834. prcItem->right - prcItem->left,
  835. prcItem->bottom - prcItem->top);
  836. if (NULL != hbmp)
  837. {
  838. SelectObject(pip->hdcItem, hbmp);
  839. SetViewportOrgEx(pip->hdcItem, -paintRect.left, -paintRect.top, NULL);
  840. }
  841. LoginTab_EraseBkGround(pip->hdcItem, tab, pip->prcClient->bottom - pip->prcClient->top, &paintRect);
  842. if (iItem == tab->itemsCount)
  843. LoginTab_PaintChevron(pip->hdcItem, tab, prcItem, &paintRect, pip->hdcSrc);
  844. else
  845. LoginTab_PaintItem(pip->hwndTab, pip->hdcItem, tab, item, iItem, prcItem, &paintRect, pip->hdcSrc);
  846. BitBlt(pip->hdc, paintRect.left, paintRect.top, paintRect.right - paintRect.left, paintRect.bottom - paintRect.top,
  847. pip->hdcItem, paintRect.left, paintRect.top, SRCCOPY);
  848. }
  849. return -1;
  850. }
  851. static UINT LoginTab_GetDrawStyles(HWND hwnd)
  852. {
  853. UINT windowStyle = GetWindowStyle(hwnd);
  854. UINT drawStyle = 0;
  855. if (0 != (WS_DISABLED & windowStyle))
  856. drawStyle |= NLTDS_DISABLED;
  857. else if (hwnd == GetFocus())
  858. {
  859. UINT uiState = (UINT)SendMessage(hwnd, WM_QUERYUISTATE, 0, 0L);
  860. if (0 == (UISF_HIDEFOCUS & uiState))
  861. drawStyle |= NLTDS_FOCUSED;
  862. }
  863. if (0 != (NLTS_LOCKED & windowStyle))
  864. drawStyle |= NLTDS_LOCKED;
  865. return drawStyle;
  866. }
  867. static void LoginTab_Paint(HWND hwnd, HDC hdc, const RECT *prcPaint, BOOL fErase)
  868. {
  869. LOGINTAB *tab = GetTab(hwnd);
  870. if (NULL == tab) return;
  871. RECT clientRect;
  872. GetClientRect(hwnd, &clientRect);
  873. tab->drawStyle = LoginTab_GetDrawStyles(hwnd);
  874. HBITMAP bitmapSrcOrig, bitmapItemOrig;
  875. HFONT fontItemOrig;
  876. PAINTITEMPARAM param;
  877. param.hwndTab = hwnd;
  878. param.hdc = hdc;
  879. param.prcPaint = prcPaint;
  880. param.prcClient = &clientRect;
  881. param.clipRgn = CreateRectRgn(0,0,0,0);
  882. param.eraseRgn = CreateRectRgnIndirect(&clientRect);
  883. param.hdcSrc = CreateCompatibleDC(hdc);
  884. param.hdcItem = CreateCompatibleDC(hdc);
  885. if (NULL != param.hdcSrc)
  886. bitmapSrcOrig = (HBITMAP)GetCurrentObject(param.hdcSrc, OBJ_BITMAP);
  887. if (NULL != param.hdcItem)
  888. {
  889. bitmapItemOrig = (HBITMAP)GetCurrentObject(param.hdcItem, OBJ_BITMAP);
  890. SetBkMode(param.hdcItem, TRANSPARENT);
  891. fontItemOrig = (HFONT)SelectObject(param.hdcItem, tab->fontText);
  892. }
  893. LoginTab_EnumerateItemRects(hwnd, param.hdcItem, LoginTab_PaintItemCallback, (ULONG_PTR)&param);
  894. if (FALSE != fErase)
  895. {
  896. SelectClipRgn(hdc, param.eraseRgn);
  897. LoginTab_EraseBkGround(hdc, tab, clientRect.bottom - clientRect.top, prcPaint);
  898. //if (SUCCEEDED(UxTheme_LoadLibrary()) && FALSE != UxIsAppThemed())
  899. //{
  900. // // CONTROLPANEL, CPANEL_NAVIGATIONPANE, 0
  901. // //
  902. // UXTHEME hTheme = UxOpenThemeData(hwnd, L"MENU");
  903. // if (NULL != hTheme)
  904. // {
  905. // clientRect.right++;
  906. // UxDrawThemeBackground(hTheme, hdc, MENU_BARBACKGROUND, MB_ACTIVE, &clientRect, prcPaint);
  907. // UxCloseThemeData(hTheme);
  908. // }
  909. //}
  910. }
  911. if (NULL != param.hdcSrc)
  912. {
  913. SelectObject(param.hdcSrc, bitmapSrcOrig);
  914. DeleteDC(param.hdcSrc);
  915. }
  916. if (NULL != param.hdcItem)
  917. {
  918. SelectObject(param.hdcItem, bitmapItemOrig);
  919. SelectObject(param.hdcItem, fontItemOrig);
  920. DeleteDC(param.hdcItem);
  921. }
  922. DeleteObject(param.clipRgn);
  923. DeleteObject(param.eraseRgn);
  924. }
  925. static INT CALLBACK LoginTab_GetItemRectCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param)
  926. {
  927. GETITEMRECTPARAM *gip = (GETITEMRECTPARAM*)param;
  928. if (NULL == gip) return -2;
  929. if (iItem == gip->index)
  930. {
  931. CopyRect(gip->rect, prcItem);
  932. return iItem;
  933. }
  934. return -1;
  935. }
  936. static BOOL LoginTab_GetItemRect(HWND hwnd, INT iItem, RECT *itemRect)
  937. {
  938. LOGINTAB *tab = GetTab(hwnd);
  939. if (NULL == tab || NULL == itemRect || iItem < 0 || iItem > tab->itemsCount)
  940. return FALSE;
  941. GETITEMRECTPARAM param;
  942. param.index = iItem;
  943. param.rect = itemRect;
  944. INT result = LoginTab_EnumerateItemRects(hwnd, NULL, LoginTab_GetItemRectCallback, (ULONG_PTR)&param);
  945. return (result == iItem);
  946. }
  947. static INT CALLBACK LoginTab_HitTestCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param)
  948. {
  949. HITTESTITEMPARAM *htp = (HITTESTITEMPARAM*)param;
  950. if (NULL == htp) return -2;
  951. if (FALSE != PtInRect(prcItem, htp->pt))
  952. {
  953. if (NULL != htp->rect)
  954. CopyRect(htp->rect, prcItem);
  955. return iItem;
  956. }
  957. return -1;
  958. }
  959. static INT LoginTab_HitTest(HWND hwnd, INT x, INT y, RECT *itemRect)
  960. {
  961. LOGINTAB *tab = GetTab(hwnd);
  962. if (NULL == tab) return -1;
  963. HITTESTITEMPARAM param;
  964. param.pt.x = x;
  965. param.pt.y = y;
  966. param.rect = itemRect;
  967. return LoginTab_EnumerateItemRects(hwnd, NULL, LoginTab_HitTestCallback, (ULONG_PTR)&param);
  968. }
  969. static INT CALLBACK LoginTab_UpdateLayoutCallback(LOGINTAB *tab, LOGINTABITEM *item, INT iItem, const RECT *prcItem, ULONG_PTR param)
  970. {
  971. UPDATELAYOUTPARAM *ulp = (UPDATELAYOUTPARAM*)param;
  972. if (NULL == ulp) return -2;
  973. if (iItem != tab->itemsCount)
  974. {
  975. if (0 == ulp->itemCount)
  976. CopyRect(&ulp->visibleBox, prcItem);
  977. else
  978. ulp->visibleBox.right = prcItem->right;
  979. ulp->itemCount++;
  980. }
  981. else
  982. {
  983. ulp->chevronLeft = prcItem->left;
  984. if (ulp->visibleBox.right > ulp->chevronLeft)
  985. ulp->visibleBox.right = ulp->chevronLeft;
  986. ulp->chevronVisible = TRUE;
  987. }
  988. return -1;
  989. }
  990. static void LoginTab_UpdateLayout(HWND hwnd, BOOL fRedraw)
  991. {
  992. LOGINTAB *tab = GetTab(hwnd);
  993. if (NULL == tab) return;
  994. RECT clientRect, rect;
  995. GetClientRect(hwnd, &clientRect);
  996. UPDATELAYOUTPARAM param;
  997. ZeroMemory(&param, sizeof(param));
  998. param.chevronLeft = clientRect.right;
  999. INT *orderCopy = NULL;
  1000. if (tab->itemsCount > 0)
  1001. {
  1002. orderCopy = (INT*)calloc(tab->itemsCount, sizeof(INT));
  1003. if (NULL == orderCopy) return;
  1004. CopyMemory(orderCopy, tab->order, tab->itemsCount * sizeof(INT));
  1005. }
  1006. // for (INT i = 0; i < tab->itemsCount; i++)
  1007. // tab->order[i] = i; // reset order
  1008. LoginTab_EnumerateItemRects(hwnd, NULL, LoginTab_UpdateLayoutCallback, (ULONG_PTR)&param);
  1009. INT selectPos = -1;
  1010. if (-1 != tab->iSelected)
  1011. {
  1012. for (INT i = 0; i < tab->itemsCount; i++)
  1013. {
  1014. if (tab->order[i] == tab->iSelected)
  1015. {
  1016. selectPos = i;
  1017. break;
  1018. }
  1019. }
  1020. }
  1021. if (tab->lastVisible < selectPos && tab->lastVisible >= 0 && selectPos >= 0)
  1022. {
  1023. CALCITEMWIDTH calcWidth;
  1024. if (FALSE != LoginTab_InitCalcItemWidth(hwnd, NULL, &calcWidth))
  1025. {
  1026. INT selectWidth = LoginTab_CalculateItemWidth(&calcWidth, tab->items[tab->iSelected]);
  1027. INT limit = param.chevronLeft - selectWidth;
  1028. INT right = param.visibleBox.right + tab->spacing;
  1029. INT pos = tab->lastVisible + 1;
  1030. while(right > limit && pos-- > 0)
  1031. {
  1032. right -= LoginTab_CalculateItemWidth(&calcWidth, tab->items[tab->order[pos]]);
  1033. if (pos > 0)
  1034. right -= tab->spacing;
  1035. }
  1036. if (pos < selectPos)
  1037. MoveMemory(tab->order + (pos + 1), tab->order + pos, (selectPos - pos) * sizeof(INT));
  1038. tab->order[pos] = tab->iSelected;
  1039. tab->lastVisible = pos;
  1040. right += selectWidth;
  1041. //if (param.visibleBox.right > right)
  1042. param.visibleBox.right = right;
  1043. LoginTab_DestroyCalcItemWidth(&calcWidth);
  1044. }
  1045. }
  1046. INT invalidLeft = clientRect.right;
  1047. if(NULL != orderCopy)
  1048. {
  1049. for (INT i = 0; i < tab->itemsCount; i++)
  1050. {
  1051. if (tab->order[i] != orderCopy[i])
  1052. {
  1053. if (FALSE != LoginTab_GetItemRect(hwnd, tab->order[i], &rect))
  1054. invalidLeft = rect.left;
  1055. break;
  1056. }
  1057. }
  1058. free(orderCopy);
  1059. }
  1060. if (tab->chevronLeft != param.chevronLeft)
  1061. {
  1062. SetRect(&rect, param.chevronLeft, clientRect.top, clientRect.right, clientRect.bottom);
  1063. if (rect.left > tab->chevronLeft)
  1064. rect.left = tab->chevronLeft;
  1065. InvalidateRect(hwnd, &rect, FALSE);
  1066. tab->chevronLeft = param.chevronLeft;
  1067. }
  1068. if (tab->visibleRight != param.visibleBox.right || invalidLeft != clientRect.right)
  1069. {
  1070. CopyRect(&rect, &param.visibleBox);
  1071. rect.left = min(param.visibleBox.right, tab->visibleRight);
  1072. if (invalidLeft < rect.left) rect.left = invalidLeft;
  1073. rect.right = max(param.visibleBox.right, tab->visibleRight);
  1074. InvalidateRect(hwnd, &rect, FALSE);
  1075. tab->visibleRight = param.visibleBox.right;
  1076. }
  1077. }
  1078. static void LoginTab_SetItemFocus(HWND hwnd, INT iFocus)
  1079. {
  1080. LOGINTAB *tab = GetTab(hwnd);
  1081. if (NULL == tab) return;
  1082. INT focusPos = -1;
  1083. if (iFocus >= tab->itemsCount)
  1084. focusPos = iFocus;
  1085. else if (-1 != iFocus)
  1086. {
  1087. for (INT i = 0; i < tab->itemsCount; i++)
  1088. {
  1089. if (tab->order[i] == iFocus)
  1090. {
  1091. focusPos = i;
  1092. break;
  1093. }
  1094. }
  1095. }
  1096. if (focusPos > tab->lastVisible)
  1097. {
  1098. if (tab->lastVisible != (tab->itemsCount -1))
  1099. {
  1100. iFocus = tab->itemsCount;
  1101. }
  1102. else
  1103. {
  1104. iFocus = tab->order[tab->lastVisible];
  1105. }
  1106. }
  1107. if (iFocus < 0)
  1108. iFocus = (tab->itemsCount > 0) ? 0 : -1;
  1109. if (iFocus != tab->iFocused)
  1110. {
  1111. INT iFocused = tab->iFocused;
  1112. INT iSelected = tab->iSelected;
  1113. tab->iFocused = iFocus;
  1114. if (iFocus < tab->itemsCount)
  1115. tab->iSelected = iFocus;
  1116. RECT rect;
  1117. if (-1 != tab->iFocused && FALSE != LoginTab_GetItemRect(hwnd, tab->iFocused, &rect))
  1118. InvalidateRect(hwnd, &rect, FALSE);
  1119. if (-1 != iFocused && iFocused != tab->iFocused &&
  1120. FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect))
  1121. {
  1122. InvalidateRect(hwnd, &rect, FALSE);
  1123. }
  1124. if (-1 != iSelected && iSelected != tab->iSelected && iSelected != iFocused &&
  1125. FALSE != LoginTab_GetItemRect(hwnd, iSelected, &rect))
  1126. {
  1127. InvalidateRect(hwnd, &rect, FALSE);
  1128. }
  1129. if (iSelected != tab->iSelected)
  1130. {
  1131. LoginTab_NotifySelectionChanged(hwnd);
  1132. }
  1133. }
  1134. }
  1135. static BOOL LoginTab_ShowHiddenTabs(HWND hwnd, const RECT *ownerRect)
  1136. {
  1137. LOGINTAB *tab = GetTab(hwnd);
  1138. if (NULL == tab) return FALSE;
  1139. HMENU hMenu = CreatePopupMenu();
  1140. if (NULL == hMenu) return FALSE;
  1141. MENUINFO mi;
  1142. mi.cbSize = sizeof(mi);
  1143. mi.fMask = MIM_STYLE | MIIM_FTYPE;
  1144. mi.dwStyle = /*MNS_MODELESS | */ MNS_NOCHECK;
  1145. SetMenuInfo(hMenu, &mi);
  1146. UINT insertedCount = 0;
  1147. MENUITEMINFO mii;
  1148. mii.cbSize = sizeof(mii);
  1149. mii.fMask = MIIM_STRING | MIIM_ID | MIIM_STATE | MIIM_FTYPE | MIIM_DATA;
  1150. mii.fState = MFS_UNHILITE | MFS_ENABLED;
  1151. CHEVRONMENUPAINTPARAM menuPaint;
  1152. ZeroMemory(&menuPaint, sizeof(menuPaint));
  1153. CALCITEMWIDTH calcItem;
  1154. LoginTab_InitCalcItemWidth(hwnd, NULL, &calcItem);
  1155. menuPaint.itemHeight = calcItem.itemHeight;
  1156. if (NULL != ownerRect)
  1157. CopyRect(&menuPaint.ownerRect, ownerRect);
  1158. INT width = tab->itemsCount - tab->lastVisible - 1;
  1159. if (width < 2) width = 1;
  1160. else if (width < 9) width = 2;
  1161. else width = (INT)sqrt((float)(width));
  1162. for(INT offset = 0; offset < width; offset++)
  1163. {
  1164. mii.fType = MFT_OWNERDRAW | MFT_MENUBREAK;
  1165. for(INT i = tab->lastVisible + 1 + offset; i < tab->itemsCount; i += width)
  1166. {
  1167. LOGINTABITEM *item = tab->items[tab->order[i]];
  1168. INT itemWidth = LoginTab_CalculateItemWidth(&calcItem, item);
  1169. if (menuPaint.itemWidth < itemWidth) menuPaint.itemWidth = itemWidth;
  1170. mii.wID = tab->order[i] + 1;
  1171. mii.dwTypeData = item->text;
  1172. mii.dwItemData = (ULONG_PTR)item;
  1173. if (FALSE != InsertMenuItem(hMenu, insertedCount, TRUE, &mii))
  1174. insertedCount++;
  1175. mii.fType = MFT_OWNERDRAW;
  1176. }
  1177. }
  1178. LoginTab_DestroyCalcItemWidth(&calcItem);
  1179. if (NULL != hMenu && insertedCount > 0)
  1180. {
  1181. RECT windowRect;
  1182. GetWindowRect(hwnd, &windowRect);
  1183. POINT menuOrig;
  1184. menuOrig.x = windowRect.right;
  1185. menuOrig.y = windowRect.bottom - 1;
  1186. UINT menuStyle = TPM_RIGHTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION | TPM_NONOTIFY | TPM_RETURNCMD;
  1187. TRACKMOUSEEVENT tm;
  1188. tm.cbSize = sizeof(tm);
  1189. tm.dwFlags = TME_CANCEL | TME_LEAVE;
  1190. tm.hwndTrack = hwnd;
  1191. TrackMouseEvent(&tm);
  1192. tab->chevronMenu = hMenu;
  1193. HBITMAP bitmapSrcOrig, bitmapItemOrig;
  1194. HFONT fontItemOrig;
  1195. HBRUSH hbrBack = NULL;
  1196. HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
  1197. if (NULL != hdc)
  1198. {
  1199. menuPaint.hdcSrc = CreateCompatibleDC(hdc);
  1200. menuPaint.hdcItem = CreateCompatibleDC(hdc);
  1201. if (NULL != menuPaint.hdcSrc)
  1202. {
  1203. bitmapSrcOrig = (HBITMAP)GetCurrentObject(menuPaint.hdcSrc, OBJ_BITMAP);
  1204. INT menuHeight = (insertedCount /width + insertedCount%width) * menuPaint.itemHeight + 2 * 4;
  1205. HBITMAP hbmpPattern = CreateCompatibleBitmap(hdc, 1, menuHeight);
  1206. if (NULL != hbmpPattern)
  1207. {
  1208. HBITMAP bmpOrig = (HBITMAP)SelectObject(menuPaint.hdcSrc, hbmpPattern);
  1209. RECT rect;
  1210. SetRect(&rect, 0, 0, 1, menuHeight);
  1211. LoginTab_EraseBkGround(menuPaint.hdcSrc, tab, menuHeight, &rect);
  1212. SelectObject(menuPaint.hdcSrc, bmpOrig);
  1213. hbrBack = CreatePatternBrush(hbmpPattern);
  1214. DeleteObject(hbmpPattern);
  1215. }
  1216. }
  1217. if (NULL != menuPaint.hdcItem)
  1218. {
  1219. bitmapItemOrig = (HBITMAP)GetCurrentObject(menuPaint.hdcItem, OBJ_BITMAP);
  1220. SetBkMode(menuPaint.hdcItem, TRANSPARENT);
  1221. fontItemOrig = (HFONT)SelectObject(menuPaint.hdcItem, tab->fontText);
  1222. }
  1223. ReleaseDC(hwnd, hdc);
  1224. }
  1225. MENUINFO mi;
  1226. mi.cbSize = sizeof(mi);
  1227. mi.fMask = MIM_MENUDATA | MIM_BACKGROUND;
  1228. mi.dwMenuData = (ULONG_PTR)&menuPaint;
  1229. mi.hbrBack = hbrBack;
  1230. SetMenuInfo(hMenu, &mi);
  1231. TPMPARAMS tpm;
  1232. tpm.cbSize =sizeof(tpm);
  1233. GetWindowRect(hwnd, &tpm.rcExclude);
  1234. tpm.rcExclude.bottom -= 2;
  1235. tpm.rcExclude.left = -20000;
  1236. tpm.rcExclude.right = 20000;
  1237. INT commandId = TrackPopupMenuEx(hMenu, menuStyle, menuOrig.x, menuOrig.y, hwnd, &tpm);
  1238. commandId--;
  1239. if ( hbrBack != NULL )
  1240. DeleteObject( hbrBack );
  1241. if (NULL != menuPaint.hdcSrc)
  1242. {
  1243. SelectObject(menuPaint.hdcSrc, bitmapSrcOrig);
  1244. DeleteDC(menuPaint.hdcSrc);
  1245. }
  1246. if (NULL != menuPaint.hdcItem)
  1247. {
  1248. SelectObject(menuPaint.hdcItem, bitmapItemOrig);
  1249. SelectObject(menuPaint.hdcItem, fontItemOrig);
  1250. DeleteDC(menuPaint.hdcItem);
  1251. }
  1252. tab->chevronMenu = NULL;
  1253. if (commandId >= 0 && commandId < tab->itemsCount && tab->iSelected != commandId)
  1254. {
  1255. LoginTab_SetCurSel(hwnd, commandId);
  1256. LoginTab_NotifySelectionChanged(hwnd);
  1257. }
  1258. }
  1259. if (NULL != hMenu)
  1260. DestroyMenu(hMenu);
  1261. return TRUE;
  1262. }
  1263. static void LoginTab_TrackMouseLeave(HWND hwnd)
  1264. {
  1265. TRACKMOUSEEVENT tm;
  1266. tm.cbSize = sizeof(TRACKMOUSEEVENT);
  1267. tm.dwFlags = TME_QUERY;
  1268. tm.hwndTrack = hwnd;
  1269. if (TrackMouseEvent(&tm) && 0 == (TME_LEAVE & tm.dwFlags))
  1270. {
  1271. tm.cbSize = sizeof(TRACKMOUSEEVENT);
  1272. tm.dwFlags = TME_LEAVE;
  1273. tm.hwndTrack = hwnd;
  1274. TrackMouseEvent(&tm);
  1275. }
  1276. }
  1277. static void LoginTab_UpdateColors(HWND hwnd)
  1278. {
  1279. LOGINTAB *tab = GetTab(hwnd);
  1280. if (NULL == tab) return;
  1281. tab->colors.backTop = GetSysColor(COLOR_WINDOW);
  1282. WORD h, l, s, lBottom, lLine;
  1283. INT k;
  1284. ColorRGBToHLS(tab->colors.backTop, &h, &l, &s);
  1285. k = MulDiv(240, 50, 1000);
  1286. lBottom = l + ((l > 0) ? -k : k);
  1287. if (lBottom > 240) lBottom = 240;
  1288. k = MulDiv(240, 75, 1000);
  1289. lLine = l + ((l > 0) ? -k : k);
  1290. if (lLine > 240) lLine = 240;
  1291. tab->colors.backBottom = ColorHLSToRGB(h, lBottom, s);
  1292. tab->colors.backLine = ColorHLSToRGB(h, lLine, s);
  1293. tab->colors.focus = RGB(255, 255, 255);
  1294. tab->colors.focusDash = RGB(0, 0, 0);
  1295. COLORREF rgbTextActive = GetSysColor(COLOR_WINDOWTEXT);
  1296. COLORREF rgbText = Color_Blend(rgbTextActive, tab->colors.backBottom, 210);
  1297. tab->colors.item.normal.backAlpha = 0;
  1298. tab->colors.item.normal.backTop = 0;
  1299. tab->colors.item.normal.backBottom = 0;
  1300. tab->colors.item.normal.frameType = FRAMETYPE_NONE;
  1301. tab->colors.item.normal.text = rgbText;
  1302. tab->colors.item.normalHigh.backAlpha = tab->colors.item.normal.backAlpha;
  1303. tab->colors.item.normalHigh.backTop = tab->colors.item.normal.backTop;
  1304. tab->colors.item.normalHigh.backBottom = tab->colors.item.normal.backBottom;
  1305. tab->colors.item.normalHigh.frameType = tab->colors.item.normal.frameType;
  1306. tab->colors.item.normalHigh.text = rgbTextActive;
  1307. tab->colors.item.normalPressed.backAlpha = tab->colors.item.normal.backAlpha;
  1308. tab->colors.item.normalPressed.backTop = tab->colors.item.normal.backTop;
  1309. tab->colors.item.normalPressed.backBottom = tab->colors.item.normal.backBottom;
  1310. tab->colors.item.normalPressed.frameType = tab->colors.item.normal.frameType;
  1311. tab->colors.item.normalPressed.text = rgbTextActive;
  1312. tab->colors.item.normalDisabled.backAlpha = tab->colors.item.normal.backAlpha;
  1313. tab->colors.item.normalDisabled.backTop = tab->colors.item.normal.backTop;
  1314. tab->colors.item.normalDisabled.backBottom = tab->colors.item.normal.backBottom;
  1315. tab->colors.item.normalDisabled.frameType = tab->colors.item.normal.frameType;
  1316. tab->colors.item.normalDisabled.text = Color_Blend(GetSysColor(COLOR_GRAYTEXT), tab->colors.backBottom, 160);
  1317. tab->colors.item.selected.backAlpha = 100;
  1318. tab->colors.item.selected.backTop = Color_Blend(GetSysColor(COLOR_HIGHLIGHT), GetSysColor(COLOR_WINDOW), 100);
  1319. tab->colors.item.selected.backBottom = Color_Blend(GetSysColor(COLOR_HIGHLIGHT), GetSysColor(COLOR_WINDOW), 140);
  1320. tab->colors.item.selected.frameType = FRAMETYPE_SELECTED;
  1321. tab->colors.item.selected.text = rgbTextActive;
  1322. tab->colors.item.selectedHigh.backAlpha = tab->colors.item.selected.backAlpha;
  1323. tab->colors.item.selectedHigh.backTop = tab->colors.item.selected.backTop;
  1324. tab->colors.item.selectedHigh.backBottom = tab->colors.item.selected.backBottom;
  1325. tab->colors.item.selectedHigh.frameType = tab->colors.item.selected.frameType;
  1326. tab->colors.item.selectedHigh.text = tab->colors.item.selected.text;
  1327. tab->colors.item.selectedPressed.backAlpha = tab->colors.item.selected.backAlpha;
  1328. tab->colors.item.selectedPressed.backTop = tab->colors.item.selected.backTop;
  1329. tab->colors.item.selectedPressed.backBottom = tab->colors.item.selected.backBottom;
  1330. tab->colors.item.selectedPressed.frameType = tab->colors.item.selected.frameType;
  1331. tab->colors.item.selectedPressed.text = tab->colors.item.selected.text;
  1332. tab->colors.item.selectedDisabled.backAlpha = tab->colors.item.selected.backAlpha;
  1333. tab->colors.item.selectedDisabled.backTop = Color_Blend(GetSysColor(COLOR_3DLIGHT), GetSysColor(COLOR_WINDOW), 100);
  1334. tab->colors.item.selectedDisabled.backBottom = Color_Blend(GetSysColor(COLOR_3DLIGHT), GetSysColor(COLOR_WINDOW), 140);
  1335. tab->colors.item.selectedDisabled.frameType = FRAMETYPE_DISABLED;
  1336. tab->colors.item.selectedDisabled.text = tab->colors.item.normalDisabled.text;
  1337. if (NULL != tab->frameBitmap)
  1338. DeleteObject(tab->frameBitmap);
  1339. BITMAPINFOHEADER frameHeader;
  1340. BYTE *framePixels;
  1341. tab->frameBitmap = ImageLoader_LoadBitmapEx(WASABI_API_ORIG_HINST,
  1342. MAKEINTRESOURCE(IDR_SELECTIONFRAME_IMAGE), FALSE, &frameHeader, (void**)&framePixels);
  1343. if (NULL == tab->frameBitmap)
  1344. {
  1345. tab->frameWidth = 0;
  1346. tab->frameHeight = 0;
  1347. }
  1348. else
  1349. {
  1350. if (frameHeader.biHeight < 0)
  1351. frameHeader.biHeight = -frameHeader.biHeight;
  1352. tab->frameWidth = (frameHeader.biWidth - 1)/2;
  1353. tab->frameHeight = (frameHeader.biHeight/2 - 1)/2;
  1354. COLORREF rgbTop = Color_Blend(GetSysColor(COLOR_HIGHLIGHT), GetSysColor(COLOR_WINDOW), 200);
  1355. COLORREF rgbBottom = GetSysColor(COLOR_WINDOW);
  1356. Image_ColorizeEx(framePixels, frameHeader.biWidth, frameHeader.biHeight, 0, 0,
  1357. frameHeader.biWidth, frameHeader.biHeight, frameHeader.biBitCount, TRUE, rgbBottom, rgbTop);
  1358. }
  1359. if (NULL != tab->chevronImage)
  1360. {
  1361. DeleteObject(tab->chevronImage);
  1362. tab->chevronImage = NULL;
  1363. }
  1364. tab->chevronImage = LoginTab_LoadChevronImage(hwnd, &tab->chevronWidth, NULL);
  1365. if (NULL == tab->chevronImage)
  1366. {
  1367. tab->chevronWidth = 0;
  1368. }
  1369. else
  1370. {
  1371. INT k = tab->frameWidth - 2;
  1372. if (k < 0) k = 0;
  1373. tab->chevronWidth += 2 * k;
  1374. }
  1375. }
  1376. static void LoginTab_UpdateFonts(HWND hwnd)
  1377. {
  1378. LOGINTAB *tab = GetTab(hwnd);
  1379. if (NULL == tab) return;
  1380. tab->fontText = NULL;
  1381. LoginGuiObject *loginGui;
  1382. if (SUCCEEDED(LoginGuiObject::QueryInstance(&loginGui)))
  1383. {
  1384. tab->fontText = loginGui->GetTextFont();
  1385. loginGui->Release();
  1386. }
  1387. HDC hdc = GetDCEx(hwnd, NULL, DCX_CACHE | DCX_NORESETATTRS);
  1388. if (NULL != hdc)
  1389. {
  1390. HFONT fontOrig = (HFONT)SelectObject(hdc, tab->fontText);
  1391. TEXTMETRIC tm;
  1392. if (FALSE != GetTextMetrics(hdc, &tm))
  1393. {
  1394. tab->textHeight = tm.tmHeight;
  1395. LONG baseunitY = tm.tmHeight;
  1396. LONG baseunitX = LoginBox_GetAveCharWidth(hdc);
  1397. tab->textWidthMax = baseunitX * MAX_TEXT_AVECHAR_WIDTH + tm.tmOverhang;
  1398. tab->margins.left = MulDiv(1, baseunitX, 4);
  1399. tab->margins.right = MulDiv(1, baseunitX, 4);
  1400. tab->margins.top = MulDiv(1, baseunitY, 8);
  1401. tab->margins.bottom = MulDiv(1, baseunitY, 8);
  1402. tab->spacing = MulDiv(1, baseunitX, 4);
  1403. for (INT i = 0; i < tab->itemsCount; i++)
  1404. tab->items[i]->textWidth = -1;
  1405. }
  1406. SelectObject(hdc, fontOrig);
  1407. ReleaseDC(hwnd, hdc);
  1408. }
  1409. }
  1410. static void LoginTab_UpdateMouseInfo(HWND hwnd)
  1411. {
  1412. POINT pt;
  1413. RECT rect;
  1414. GetCursorPos(&pt);
  1415. MapWindowPoints(HWND_DESKTOP, hwnd, &pt, 1);
  1416. GetClientRect(hwnd, &rect);
  1417. if (FALSE == PtInRect(&rect, pt))
  1418. {
  1419. SendMessage(hwnd, WM_MOUSELEAVE, 0, 0L);
  1420. }
  1421. else
  1422. {
  1423. UINT vKey = 0;
  1424. if (0 != (0x8000 & GetAsyncKeyState(VK_CONTROL)))
  1425. vKey |= MK_CONTROL;
  1426. if (0 != (0x8000 & GetAsyncKeyState(VK_LBUTTON)))
  1427. vKey |= MK_LBUTTON;
  1428. if (0 != (0x8000 & GetAsyncKeyState(VK_RBUTTON)))
  1429. vKey |= MK_RBUTTON;
  1430. if (0 != (0x8000 & GetAsyncKeyState(VK_SHIFT)))
  1431. vKey |= MK_SHIFT;
  1432. if (0 != (0x8000 & GetAsyncKeyState(VK_XBUTTON1)))
  1433. vKey |= MK_XBUTTON1;
  1434. if (0 != (0x8000 & GetAsyncKeyState(VK_XBUTTON2)))
  1435. vKey |= MK_XBUTTON2;
  1436. SendMessage(hwnd, WM_MOUSEMOVE, vKey, MAKELPARAM(pt.x, pt.y));
  1437. }
  1438. }
  1439. static HWND LoginTab_CreateTooltip(HWND hwnd)
  1440. {
  1441. HWND hTooltip = CreateWindowExW(WS_EX_TOOLWINDOW | WS_EX_NOPARENTNOTIFY | WS_EX_TRANSPARENT | WS_EX_LAYERED,
  1442. TOOLTIPS_CLASS, NULL, WS_CLIPSIBLINGS | WS_POPUP | TTS_NOPREFIX /*| TTS_ALWAYSTIP*/,
  1443. 0, 0, 0, 0, hwnd, NULL, NULL, NULL);
  1444. if (NULL == hTooltip)
  1445. return NULL;
  1446. SendMessage(hTooltip, CCM_SETVERSION, 6, 0L);
  1447. SetWindowPos(hTooltip, HWND_TOP, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER);
  1448. SendMessage(hTooltip, TTM_SETDELAYTIME, TTDT_INITIAL, MAKELPARAM(1000, 0));
  1449. TOOLINFO ti;
  1450. ZeroMemory(&ti, sizeof(ti));
  1451. ti.cbSize = sizeof(TOOLINFO);
  1452. ti.hwnd = hwnd;
  1453. ti.lpszText = LPSTR_TEXTCALLBACK;
  1454. SendMessage(hTooltip, TTM_ADDTOOL, 0, (LPARAM)&ti);
  1455. INT helpWidthMax = 260;
  1456. NONCLIENTMETRICS ncm;
  1457. ncm.cbSize = sizeof(ncm);
  1458. OSVERSIONINFO vi;
  1459. vi.dwOSVersionInfoSize = sizeof(vi);
  1460. if (FALSE == GetVersionEx(&vi))
  1461. ZeroMemory(&vi, sizeof(vi));
  1462. if (vi.dwMajorVersion < 6)
  1463. ncm.cbSize -= sizeof(ncm.iPaddedBorderWidth);
  1464. RECT marginRect;
  1465. SetRect(&marginRect, 3, 1, 3, 1);
  1466. if (SystemParametersInfo(SPI_GETNONCLIENTMETRICS, ncm.cbSize, &ncm, 0))
  1467. {
  1468. HFONT font = CreateFontIndirect(&ncm.lfStatusFont);
  1469. if (NULL != font)
  1470. {
  1471. HDC hdc = GetDCEx(hTooltip, NULL, DCX_CACHE);
  1472. if (NULL != hdc)
  1473. {
  1474. HFONT fontOrig = (HFONT)SelectObject(hdc, font);
  1475. TEXTMETRIC tm;
  1476. if (FALSE != GetTextMetrics(hdc, &tm))
  1477. {
  1478. INT baseunitX = LoginBox_GetAveCharWidth(hdc);
  1479. if (NULL != baseunitX)
  1480. {
  1481. helpWidthMax = baseunitX * MAX_HELP_AVECHAR_WIDTH + tm.tmOverhang;
  1482. marginRect.left = MulDiv(2, baseunitX, 4);
  1483. marginRect.right = marginRect.left;
  1484. marginRect.top = MulDiv(1, tm.tmHeight, 8);
  1485. marginRect.bottom = MulDiv(1, tm.tmHeight, 8);
  1486. }
  1487. }
  1488. SelectObject(hdc, fontOrig);
  1489. ReleaseDC(hTooltip, hdc);
  1490. }
  1491. DeleteObject(font);
  1492. }
  1493. }
  1494. SendMessage(hTooltip, TTM_SETMAXTIPWIDTH, 0, helpWidthMax);
  1495. SendMessage(hTooltip, TTM_SETMARGIN, 0, (LPARAM)&marginRect);
  1496. return hTooltip;
  1497. }
  1498. static void LoginTab_RelayTooltipMouseMsg(HWND hwnd, UINT uMsg, UINT vKey, POINTS pts)
  1499. {
  1500. LOGINTAB *tab = GetTab(hwnd);
  1501. if (NULL == tab || NULL == tab->hTooltip || -1 == tab->iHighlighted)
  1502. return;
  1503. MSG msg;
  1504. msg.hwnd = hwnd;
  1505. msg.message = uMsg;
  1506. msg.wParam = (WPARAM)vKey;
  1507. msg.lParam = MAKELPARAM(pts.x, pts.y);
  1508. SendMessage(tab->hTooltip, TTM_RELAYEVENT, 0, (LPARAM)&msg);
  1509. }
  1510. static void LoginTab_UpdateTooltip(HWND hwnd)
  1511. {
  1512. LOGINTAB *tab = GetTab(hwnd);
  1513. if (NULL == tab) return;
  1514. TOOLINFO ti;
  1515. ZeroMemory(&ti, sizeof(ti));
  1516. ti.cbSize = sizeof(ti);
  1517. ti.hwnd = hwnd;
  1518. ti.uId = 0;
  1519. if (FALSE == SendMessage(tab->hTooltip, TTM_GETTOOLINFO, 0, (LPARAM)&ti))
  1520. return;
  1521. INT iItem = tab->iHighlighted;
  1522. RECT rect;
  1523. if (-1 == iItem || FALSE == LoginTab_GetItemRect(hwnd, iItem, &rect))
  1524. {
  1525. SendMessage(tab->hTooltip, TTM_ACTIVATE, FALSE, 0L);
  1526. SysFreeString(tab->helpText);
  1527. tab->helpText = NULL;
  1528. return;
  1529. }
  1530. if (ti.lParam != (LPARAM)iItem || FALSE == EqualRect(&ti.rect, &rect))
  1531. {
  1532. SendMessage(tab->hTooltip, TTM_ACTIVATE, FALSE, 0L);
  1533. CopyRect(&ti.rect, &rect);
  1534. if (ti.lParam != iItem)
  1535. {
  1536. LPCWSTR pszTitle = NULL;
  1537. if (iItem >= 0 && iItem < tab->itemsCount)
  1538. pszTitle = tab->items[iItem]->text;
  1539. SendMessage(tab->hTooltip, TTM_SETTITLE, (WPARAM)TTI_NONE, (LPARAM)pszTitle);
  1540. ti.lParam = (LPARAM)iItem;
  1541. ti.lpszText = LPSTR_TEXTCALLBACK;
  1542. SysFreeString(tab->helpText);
  1543. tab->helpText = NULL;
  1544. }
  1545. SendMessage(tab->hTooltip, TTM_SETTOOLINFO, 0, (LPARAM)&ti);
  1546. }
  1547. SendMessage(tab->hTooltip, TTM_ACTIVATE, TRUE, 0L);
  1548. }
  1549. static void LoginTab_FreeItem(LOGINTABITEM *item)
  1550. {
  1551. if (NULL == item) return;
  1552. LoginBox_FreeString(item->text);
  1553. free(item);
  1554. }
  1555. static BOOL LoginTab_SetItemInternal(LOGINTABITEM *dst, const NLTITEM *src)
  1556. {
  1557. if (NULL == dst || NULL == src)
  1558. return FALSE;
  1559. BOOL succeeded = TRUE;
  1560. if (0 != (NLTIF_TEXT & src->mask))
  1561. {
  1562. dst->textWidth = -1;
  1563. LoginBox_FreeString(dst->text);
  1564. if (NULL != src->pszText)
  1565. {
  1566. dst->text = LoginBox_CopyString(src->pszText);
  1567. if (NULL == dst->text) succeeded = FALSE;
  1568. }
  1569. else
  1570. {
  1571. dst->text = NULL;
  1572. }
  1573. }
  1574. if (0 != (NLTIF_PARAM & src->mask))
  1575. dst->param = src->param;
  1576. if (0 != (NLTIF_IMAGE & src->mask))
  1577. dst->iImage = src->iImage;
  1578. if (0 != (NLTIF_IMAGE_ACTIVE & src->mask))
  1579. dst->iImageActive = src->iImageActive;
  1580. if (0 != (NLTIF_IMAGE_DISABLED & src->mask))
  1581. dst->iImageDisabled = src->iImageDisabled;
  1582. return succeeded;
  1583. }
  1584. static LOGINTABITEM *LoginTab_CreateItem(const NLTITEM *pItem)
  1585. {
  1586. LOGINTABITEM *item = (LOGINTABITEM*)calloc(1, sizeof(LOGINTABITEM));
  1587. if (NULL == item) return NULL;
  1588. item->textWidth = -1;
  1589. item->iImage = NLTM_IMAGE_NONE;
  1590. item->iImageActive = NLTM_IMAGE_NONE;
  1591. item->iImageDisabled = NLTM_IMAGE_NONE;
  1592. if (NULL != pItem && FALSE == LoginTab_SetItemInternal(item, pItem))
  1593. {
  1594. LoginTab_FreeItem(item);
  1595. item = NULL;
  1596. }
  1597. return item;
  1598. }
  1599. static INT LoginTab_DeleteAllItemsReal(HWND hwnd, LOGINTABITEM **itemsList, INT itemsCount)
  1600. {
  1601. if (NULL == itemsList || itemsCount < 1)
  1602. return 0;
  1603. NMLOGINTAB nmp;
  1604. nmp.hdr.hwndFrom = hwnd;
  1605. nmp.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
  1606. HWND hParent = GetAncestor(hwnd, GA_PARENT);
  1607. BOOL fNotifyItem = FALSE;
  1608. if (NULL != hParent)
  1609. {
  1610. nmp.hdr.code = NLTN_DELETEALLITEMS;
  1611. nmp.iItem = -1;
  1612. fNotifyItem = (FALSE == (BOOL)SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmp.hdr.idFrom, (LPARAM)&nmp));
  1613. if (FALSE != fNotifyItem)
  1614. nmp.hdr.code = NLTN_DELETEITEM;
  1615. }
  1616. INT deleted = 0;
  1617. for(; itemsCount > 0; itemsCount--)
  1618. {
  1619. nmp.iItem = itemsCount - 1;
  1620. if (FALSE != fNotifyItem)
  1621. SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmp.hdr.idFrom, (LPARAM)&nmp);
  1622. LoginTab_FreeItem(itemsList[nmp.iItem]);
  1623. deleted++;
  1624. }
  1625. return deleted;
  1626. }
  1627. static LRESULT LoginTab_OnCreate(HWND hwnd, CREATESTRUCT* pcs)
  1628. {
  1629. LOGINTAB *tab = (LOGINTAB*)calloc(1, sizeof(LOGINTAB));
  1630. if (NULL != tab)
  1631. {
  1632. SetLastError(ERROR_SUCCESS);
  1633. if (!SetWindowLongPtr(hwnd, 0, (LONGX86)(LONG_PTR)tab) && ERROR_SUCCESS != GetLastError())
  1634. {
  1635. free(tab);
  1636. tab = NULL;
  1637. }
  1638. }
  1639. if (NULL == tab)
  1640. return -1;
  1641. tab->iPressed = -1;
  1642. tab->iSelected = -1;
  1643. tab->iHighlighted = -1;
  1644. tab->hTooltip = LoginTab_CreateTooltip(hwnd);
  1645. LoginTab_UpdateColors(hwnd);
  1646. LoginTab_UpdateFonts(hwnd);
  1647. return 0;
  1648. }
  1649. static void LoginTab_OnDestroy(HWND hwnd)
  1650. {
  1651. LOGINTAB *tab = GetTab(hwnd);
  1652. SetWindowLongPtr(hwnd, 0, 0L);
  1653. if (NULL == tab) return;
  1654. if (NULL != tab->items)
  1655. {
  1656. tab->itemsCount -= LoginTab_DeleteAllItemsReal(hwnd, tab->items, tab->itemsCount);
  1657. free(tab->items);
  1658. }
  1659. if (NULL != tab->order)
  1660. free(tab->order);
  1661. if (NULL != tab->frameBitmap)
  1662. DeleteObject(tab->frameBitmap);
  1663. if (NULL != tab->itemBitmap)
  1664. DeleteObject(tab->itemBitmap);
  1665. if (NULL != tab->chevronImage)
  1666. DeleteObject(tab->chevronImage);
  1667. if (NULL != tab->hTooltip)
  1668. DestroyWindow(tab->hTooltip);
  1669. SysFreeString(tab->helpText);
  1670. free(tab);
  1671. }
  1672. static void LoginTab_OnWindowPosChanged(HWND hwnd, WINDOWPOS *pwp)
  1673. {
  1674. if (SWP_NOSIZE == ((SWP_NOSIZE | SWP_FRAMECHANGED) & pwp->flags))
  1675. return;
  1676. LoginTab_UpdateLayout(hwnd, 0 == (SWP_NOREDRAW & pwp->flags));
  1677. }
  1678. static void LoginTab_OnPaint(HWND hwnd)
  1679. {
  1680. PAINTSTRUCT ps;
  1681. if (BeginPaint(hwnd, &ps))
  1682. {
  1683. if (ps.rcPaint.left != ps.rcPaint.right)
  1684. LoginTab_Paint(hwnd, ps.hdc, &ps.rcPaint, ps.fErase);
  1685. EndPaint(hwnd, &ps);
  1686. }
  1687. }
  1688. static void LoginTab_OnPrintClient(HWND hwnd, HDC hdc, UINT options)
  1689. {
  1690. RECT clientRect;
  1691. if (GetClientRect(hwnd, &clientRect))
  1692. LoginTab_Paint(hwnd, hdc, &clientRect, 0 != (PRF_ERASEBKGND & options));
  1693. }
  1694. static void LoginTab_OnMouseMove(HWND hwnd, UINT vKey, POINTS pts)
  1695. {
  1696. LOGINTAB *tab = GetTab(hwnd);
  1697. if (NULL == tab) return;
  1698. if (FALSE != LoginTab_IsLocked(hwnd))
  1699. return;
  1700. RECT rect;
  1701. INT iHighlighted = tab->iHighlighted;
  1702. tab->iHighlighted = (-1 == tab->iPressed) ?
  1703. LoginTab_HitTest(hwnd, pts.x, pts.y, &rect) : -1;
  1704. if (iHighlighted != tab->iHighlighted)
  1705. LoginTab_UpdateTooltip(hwnd);
  1706. LoginTab_RelayTooltipMouseMsg(hwnd, WM_MOUSEMOVE, vKey, pts);
  1707. if (iHighlighted != tab->iHighlighted)
  1708. {
  1709. InvalidateRect(hwnd, &rect, FALSE);
  1710. if (-1 != iHighlighted && FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect))
  1711. InvalidateRect(hwnd, &rect, FALSE);
  1712. }
  1713. if (-1 != tab->iHighlighted)
  1714. LoginTab_TrackMouseLeave(hwnd);
  1715. }
  1716. static void LoginTab_OnMouseLeave(HWND hwnd)
  1717. {
  1718. LOGINTAB *tab = GetTab(hwnd);
  1719. if (NULL == tab) return;
  1720. INT iPressed = tab->iPressed;
  1721. INT iHighlighted = tab->iHighlighted;
  1722. tab->iPressed = -1;
  1723. tab->iHighlighted = -1;
  1724. RECT rect;
  1725. if (-1 != iHighlighted && FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect))
  1726. InvalidateRect(hwnd, &rect, FALSE);
  1727. if (-1 != iPressed && iPressed != iHighlighted && FALSE != LoginTab_GetItemRect(hwnd, iPressed, &rect))
  1728. InvalidateRect(hwnd, &rect, FALSE);
  1729. }
  1730. static void LoginTab_OnLButtonDown(HWND hwnd, UINT vKey, POINTS pts)
  1731. {
  1732. LOGINTAB *tab = GetTab(hwnd);
  1733. if (NULL == tab) return;
  1734. if (FALSE != LoginTab_IsLocked(hwnd))
  1735. return;
  1736. LoginTab_RelayTooltipMouseMsg(hwnd, WM_LBUTTONDOWN, vKey, pts);
  1737. RECT rect, rect2;
  1738. INT iPressed, iHighlighted;
  1739. INT iItem = LoginTab_HitTest(hwnd, pts.x, pts.y, &rect);
  1740. iPressed = tab->iPressed;
  1741. iHighlighted = tab->iHighlighted;
  1742. tab->iPressed = iItem;
  1743. tab->iHighlighted = -1;
  1744. if (iPressed != iItem && -1 != iPressed &&
  1745. FALSE != LoginTab_GetItemRect(hwnd, iPressed, &rect2))
  1746. {
  1747. InvalidateRect(hwnd, &rect2, FALSE);
  1748. }
  1749. if (iHighlighted != iItem && -1 != iHighlighted && iHighlighted != iPressed &&
  1750. FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect2))
  1751. {
  1752. InvalidateRect(hwnd, &rect2, FALSE);
  1753. }
  1754. if (-1 != iItem && iPressed != iItem)
  1755. {
  1756. if (iItem == tab->itemsCount && tab->iFocused != iItem)
  1757. {
  1758. INT iFocused = tab->iFocused;
  1759. tab->iFocused = iItem;
  1760. if (-1 != iFocused && FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect2))
  1761. InvalidateRect(hwnd, &rect2, FALSE);
  1762. }
  1763. InvalidateRect(hwnd, &rect, FALSE);
  1764. if (iItem == tab->itemsCount)
  1765. {
  1766. LoginTab_ShowHiddenTabs(hwnd, &rect);
  1767. if (0 == (0x8000 & GetAsyncKeyState((FALSE == GetSystemMetrics(SM_SWAPBUTTON)) ? VK_LBUTTON : VK_RBUTTON)))
  1768. tab->iPressed = -1;
  1769. tab->iFocused = tab->itemsCount;
  1770. InvalidateRect(hwnd, &rect, FALSE);
  1771. LoginTab_UpdateMouseInfo(hwnd);
  1772. }
  1773. else if (hwnd != GetCapture())
  1774. SetCapture(hwnd);
  1775. }
  1776. }
  1777. static void LoginTab_OnLButtonUp(HWND hwnd, UINT vKey, POINTS pts)
  1778. {
  1779. LOGINTAB *tab = GetTab(hwnd);
  1780. if (NULL == tab) return;
  1781. if (FALSE != LoginTab_IsLocked(hwnd))
  1782. return;
  1783. LoginTab_RelayTooltipMouseMsg(hwnd, WM_LBUTTONUP, vKey, pts);
  1784. RECT rect, rect2;
  1785. INT iPressed = tab->iPressed;
  1786. INT iHighlighted = tab->iHighlighted;
  1787. INT iSelected = tab->iSelected;
  1788. INT iFocused = tab->iFocused;
  1789. INT iItem = LoginTab_HitTest(hwnd, pts.x, pts.y, &rect);
  1790. tab->iPressed = -1;
  1791. tab->iHighlighted = iItem;
  1792. if (iItem == iPressed && -1 != iItem)
  1793. {
  1794. if (iItem < tab->itemsCount)
  1795. tab->iSelected = iItem;
  1796. tab->iFocused = iItem;
  1797. }
  1798. if (-1 != iHighlighted && iHighlighted != tab->iHighlighted &&
  1799. iHighlighted != iPressed && iHighlighted != iFocused && iHighlighted != iSelected &&
  1800. FALSE != LoginTab_GetItemRect(hwnd, iHighlighted, &rect2))
  1801. {
  1802. InvalidateRect(hwnd, &rect2, FALSE);
  1803. }
  1804. if (-1 != iPressed && iPressed != tab->iPressed &&
  1805. (iPressed != iFocused || tab->iFocused == iFocused) &&
  1806. (iPressed != iSelected || tab->iSelected == iSelected) &&
  1807. FALSE != LoginTab_GetItemRect(hwnd, iPressed, &rect2))
  1808. {
  1809. InvalidateRect(hwnd, &rect2, FALSE);
  1810. }
  1811. if (-1 != iSelected && iSelected != tab->iSelected &&
  1812. iSelected != iFocused &&
  1813. FALSE != LoginTab_GetItemRect(hwnd, iSelected, &rect2))
  1814. {
  1815. InvalidateRect(hwnd, &rect2, FALSE);
  1816. }
  1817. if (-1 != iFocused && iFocused != tab->iFocused &&
  1818. FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect2))
  1819. {
  1820. InvalidateRect(hwnd, &rect2, FALSE);
  1821. }
  1822. if (-1 != iItem)
  1823. InvalidateRect(hwnd, &rect, FALSE);
  1824. if (hwnd == GetCapture())
  1825. ReleaseCapture();
  1826. if (-1 != tab->iSelected && tab->iSelected != iSelected)
  1827. LoginTab_NotifySelectionChanged(hwnd);
  1828. }
  1829. static void LoginTab_OnRButtonDown(HWND hwnd, UINT vKey, POINTS pts)
  1830. {
  1831. LOGINTAB *tab = GetTab(hwnd);
  1832. if (NULL == tab) return;
  1833. if (FALSE != LoginTab_IsLocked(hwnd))
  1834. return;
  1835. LoginTab_RelayTooltipMouseMsg(hwnd, WM_RBUTTONDOWN, vKey, pts);
  1836. HWND hParent = GetAncestor(hwnd, GA_PARENT);
  1837. if (NULL != hParent)
  1838. {
  1839. NMLOGINTABCLICK ntc;
  1840. ntc.hdr.code = NM_RCLICK;
  1841. ntc.hdr.hwndFrom = hwnd;
  1842. ntc.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
  1843. ntc.pt.x = pts.x;
  1844. ntc.pt.y = pts.y;
  1845. SNDMSG(hParent, WM_NOTIFY, (WPARAM)ntc.hdr.idFrom, (LPARAM)&ntc);
  1846. }
  1847. }
  1848. static void LoginTab_OnRButtonUp(HWND hwnd, UINT vKey, POINTS pts)
  1849. {
  1850. if (FALSE != LoginTab_IsLocked(hwnd))
  1851. return;
  1852. LoginTab_RelayTooltipMouseMsg(hwnd, WM_RBUTTONUP, vKey, pts);
  1853. }
  1854. static void LoginTab_OnMButtonDown(HWND hwnd, UINT vKey, POINTS pts)
  1855. {
  1856. if (FALSE != LoginTab_IsLocked(hwnd))
  1857. return;
  1858. LoginTab_RelayTooltipMouseMsg(hwnd, WM_MBUTTONDOWN, vKey, pts);
  1859. }
  1860. static void LoginTab_OnMButtonUp(HWND hwnd, UINT vKey, POINTS pts)
  1861. {
  1862. if (FALSE != LoginTab_IsLocked(hwnd))
  1863. return;
  1864. LoginTab_RelayTooltipMouseMsg(hwnd, WM_MBUTTONUP, vKey, pts);
  1865. }
  1866. static void LoginTab_OnCaptureChanged(HWND hwnd, HWND hCapture)
  1867. {
  1868. if (hwnd != hCapture)
  1869. LoginTab_TrackMouseLeave(hwnd);
  1870. }
  1871. static void LoginTab_OnSetFocus(HWND hwnd, HWND hFocus)
  1872. {
  1873. LOGINTAB *tab = GetTab(hwnd);
  1874. if (NULL == tab) return;
  1875. INT iFocus = tab->iSelected;
  1876. tab->iFocused = -1;
  1877. LoginTab_SetItemFocus(hwnd, iFocus);
  1878. }
  1879. static void LoginTab_OnKillFocus(HWND hwnd, HWND hFocus)
  1880. {
  1881. LOGINTAB *tab = GetTab(hwnd);
  1882. if (NULL == tab) return;
  1883. RECT rect;
  1884. if (-1 != tab->iFocused && FALSE != LoginTab_GetItemRect(hwnd, tab->iFocused, &rect))
  1885. {
  1886. InvalidateRect(hwnd, &rect, FALSE);
  1887. }
  1888. }
  1889. static void LoginTab_OnEnable(HWND hwnd, BOOL fEnabled)
  1890. {
  1891. InvalidateRect(hwnd, NULL, FALSE);
  1892. }
  1893. static void LoginTab_OnKeyDown(HWND hwnd, INT vKey, UINT flags)
  1894. {
  1895. LOGINTAB *tab = GetTab(hwnd);
  1896. if (NULL == tab) return;
  1897. if (FALSE != LoginTab_IsLocked(hwnd))
  1898. return;
  1899. INT focusPos = -1;
  1900. if (tab->iFocused >= tab->itemsCount)
  1901. {
  1902. focusPos = tab->iFocused;
  1903. }
  1904. else if (-1 != tab->iFocused)
  1905. {
  1906. for (INT i = 0; i < tab->itemsCount; i++)
  1907. {
  1908. if (tab->order[i] == tab->iFocused)
  1909. {
  1910. focusPos = i;
  1911. break;
  1912. }
  1913. }
  1914. }
  1915. switch(vKey)
  1916. {
  1917. case VK_LEFT: focusPos = (focusPos > tab->lastVisible) ? tab->lastVisible : (focusPos - 1); break;
  1918. case VK_RIGHT: focusPos++; break;
  1919. case VK_PRIOR:
  1920. case VK_HOME: focusPos = 0; break;
  1921. case VK_END: focusPos = tab->itemsCount -1; break;
  1922. case VK_NEXT: focusPos = tab->lastVisible; break;
  1923. case VK_SPACE:
  1924. case VK_RETURN:
  1925. if (tab->iFocused == tab->itemsCount)
  1926. {
  1927. tab->iPressed = tab->iFocused;
  1928. RECT rect;
  1929. if (FALSE == LoginTab_GetItemRect(hwnd, tab->iPressed, &rect))
  1930. SetRectEmpty(&rect);
  1931. LoginTab_ShowHiddenTabs(hwnd, &rect);
  1932. tab->iFocused = tab->itemsCount;
  1933. tab->iPressed = -1;
  1934. InvalidateRect(hwnd, &rect, FALSE);
  1935. LoginTab_UpdateMouseInfo(hwnd);
  1936. return;
  1937. }
  1938. break;
  1939. }
  1940. INT iFocus;
  1941. if (focusPos >= tab->itemsCount)
  1942. iFocus = tab->itemsCount;
  1943. else if (focusPos < 0)
  1944. iFocus = 0;
  1945. else
  1946. iFocus = tab->order[focusPos];
  1947. LoginTab_SetItemFocus(hwnd, iFocus);
  1948. }
  1949. static LRESULT LoginTab_OnGetDlgCode(HWND hwnd, INT vKey, MSG *pMsg)
  1950. {
  1951. switch(vKey)
  1952. {
  1953. case VK_TAB: return 0;
  1954. }
  1955. return DLGC_WANTALLKEYS;
  1956. }
  1957. static LRESULT LoginTab_OnMenuChar(HWND hwnd, INT vkCode, INT menuType, HMENU hMenu)
  1958. {
  1959. switch(vkCode)
  1960. {
  1961. case VK_SPACE:
  1962. case VK_RETURN:
  1963. for (INT i = GetMenuItemCount(hMenu) - 1; i >= 0; i--)
  1964. {
  1965. UINT r = GetMenuState(hMenu, i, MF_BYPOSITION);
  1966. if (-1 != r && 0 != (MF_HILITE & LOWORD(r)))
  1967. return MAKELRESULT(i, MNC_EXECUTE);
  1968. }
  1969. return MAKELRESULT(0, MNC_SELECT);
  1970. }
  1971. return MAKELRESULT(0, MNC_IGNORE);
  1972. }
  1973. static void LoginTab_OnMenuSelect(HWND hwnd, INT iItem, UINT flags, HMENU hMenu)
  1974. {
  1975. MENUINFO mi;
  1976. mi.cbSize = sizeof(mi);
  1977. mi.fMask = MIM_MENUDATA | MIM_BACKGROUND;
  1978. if (FALSE != GetMenuInfo(hMenu, &mi) && NULL != mi.dwMenuData)
  1979. {
  1980. CHEVRONMENUPAINTPARAM *pmp= (CHEVRONMENUPAINTPARAM*)mi.dwMenuData;
  1981. if (NULL != pmp->hwndMenu)
  1982. {
  1983. UINT stateOrig = (UINT)SendMessage(pmp->hwndMenu, WM_QUERYUISTATE, 0, 0L);
  1984. SendMessage(pmp->hwndMenu, WM_CHANGEUISTATE,
  1985. MAKEWPARAM(UISF_HIDEACCEL | UISF_HIDEFOCUS, UIS_INITIALIZE), 0L);
  1986. UINT stateCurrent = (UINT)SendMessage(pmp->hwndMenu, WM_QUERYUISTATE, 0, 0L);
  1987. if ((UISF_HIDEFOCUS & stateOrig) != (UISF_HIDEFOCUS & stateCurrent))
  1988. {
  1989. INT menuCount = GetMenuItemCount(hMenu);
  1990. while(menuCount--)
  1991. {
  1992. if (iItem == GetMenuItemID(hMenu, menuCount))
  1993. {
  1994. RECT rect;
  1995. if (FALSE != GetMenuItemRect(NULL, hMenu, menuCount, &rect))
  1996. {
  1997. MapWindowPoints(HWND_DESKTOP, pmp->hwndMenu, (POINT*)&rect, 2);
  1998. InvalidateRect(pmp->hwndMenu, &rect, FALSE);
  1999. }
  2000. break;
  2001. }
  2002. }
  2003. }
  2004. }
  2005. }
  2006. }
  2007. static void LoginTab_GetTootipDispInfo(HWND hwnd, NMTTDISPINFO *pdisp)
  2008. {
  2009. LOGINTAB *tab = GetTab(hwnd);
  2010. if (NULL == tab) return;
  2011. if(NULL == tab->helpText)
  2012. {
  2013. INT iItem = (INT)pdisp->lParam;
  2014. if (iItem >= 0 && iItem < tab->itemsCount)
  2015. {
  2016. HWND hParent = GetAncestor(hwnd, GA_PARENT);
  2017. if (NULL != hParent)
  2018. {
  2019. NMLOGINTABHELP help;
  2020. help.hdr.code = NLTN_GETITEMHELP;
  2021. help.hdr.hwndFrom = hwnd;
  2022. help.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
  2023. help.iItem = iItem;
  2024. help.param = tab->items[iItem]->param;
  2025. help.bstrHelp = NULL;
  2026. SNDMSG(hParent, WM_NOTIFY, (WPARAM)help.hdr.idFrom, (LPARAM)&help);
  2027. tab->helpText = help.bstrHelp;
  2028. }
  2029. }
  2030. else if (iItem == tab->itemsCount)
  2031. {
  2032. WCHAR szBuffer[256] = {0};
  2033. WASABI_API_LNGSTRINGW_BUF(IDS_LOGINTAB_MOREPROVIDERS, szBuffer, ARRAYSIZE(szBuffer));
  2034. tab->helpText = SysAllocString(szBuffer);
  2035. }
  2036. if (NULL == tab->helpText)
  2037. tab->helpText = SysAllocString(L" ");
  2038. }
  2039. if (NULL != tab->helpText && L'\0' != tab->helpText)
  2040. {
  2041. pdisp->lpszText = (LPWSTR)tab->helpText;
  2042. pdisp->uFlags = TTF_DI_SETITEM;
  2043. }
  2044. }
  2045. static BOOL LoginTab_OnShow(HWND hwnd, HWND hTooltip)
  2046. {
  2047. TOOLINFO ti;
  2048. ZeroMemory(&ti, sizeof(ti));
  2049. ti.cbSize = sizeof(ti);
  2050. ti.hwnd = hwnd;
  2051. ti.uId = 0;
  2052. if (FALSE == SendMessage(hTooltip, TTM_GETTOOLINFO, 0, (LPARAM)&ti))
  2053. return FALSE;
  2054. MapWindowPoints(hwnd, HWND_DESKTOP, (POINT*)&ti.rect, 2);
  2055. RECT windowRect, tooltipRect;
  2056. GetWindowRect(hwnd, &windowRect);
  2057. GetWindowRect(hTooltip, &tooltipRect);
  2058. ti.rect.right = ti.rect.left + (tooltipRect.right - tooltipRect.left);
  2059. ti.rect.top = windowRect.bottom;
  2060. ti.rect.bottom = ti.rect.top + (tooltipRect.bottom - tooltipRect.top);
  2061. HMONITOR hMonitor = MonitorFromRect(&ti.rect, MONITOR_DEFAULTTONEAREST);
  2062. if (NULL != hMonitor)
  2063. {
  2064. MONITORINFO mi;
  2065. mi.cbSize = sizeof(mi);
  2066. if (FALSE != GetMonitorInfo(hMonitor, &mi))
  2067. {
  2068. INT offsetX = 0;
  2069. INT offsetY = 0;
  2070. if (ti.rect.right > mi.rcWork.right)
  2071. offsetX += (mi.rcWork.right - ti.rect.right);
  2072. if (ti.rect.bottom > mi.rcWork.bottom)
  2073. {
  2074. offsetY += (mi.rcWork.bottom - ti.rect.bottom);
  2075. if ((ti.rect.top + offsetY) < windowRect.bottom && (ti.rect.bottom + offsetY) > windowRect.top)
  2076. offsetY = (windowRect.top - (ti.rect.bottom - ti.rect.top)) - ti.rect.top;
  2077. }
  2078. if ((ti.rect.left + offsetX) < mi.rcWork.left)
  2079. offsetX += (mi.rcWork.left - (ti.rect.left + offsetX));
  2080. if ((ti.rect.top + offsetY) < mi.rcWork.top)
  2081. offsetY += (mi.rcWork.top - (ti.rect.top + offsetY));
  2082. OffsetRect(&ti.rect, offsetX, offsetY);
  2083. }
  2084. }
  2085. return SetWindowPos(hTooltip, NULL, ti.rect.left, ti.rect.top, 0, 0,
  2086. SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOREDRAW);
  2087. }
  2088. static LRESULT LoginTab_OnTooltipNotify(HWND hwnd, NMHDR *pnmh)
  2089. {
  2090. switch(pnmh->code)
  2091. {
  2092. case TTN_GETDISPINFO:
  2093. LoginTab_GetTootipDispInfo(hwnd, (NMTTDISPINFO*)pnmh);
  2094. break;
  2095. case TTN_SHOW:
  2096. return LoginTab_OnShow(hwnd, pnmh->hwndFrom);
  2097. }
  2098. return 0;
  2099. }
  2100. static LRESULT LoginTab_OnNotify(HWND hwnd, INT controlId, NMHDR *pnmh)
  2101. {
  2102. LOGINTAB *tab = GetTab(hwnd);
  2103. if (NULL == tab) return 0;
  2104. if (tab->hTooltip == pnmh->hwndFrom && NULL != tab->hTooltip)
  2105. return LoginTab_OnTooltipNotify(hwnd, pnmh);
  2106. return 0;
  2107. }
  2108. static INT LoginTab_OnGetIdealHeight(HWND hwnd)
  2109. {
  2110. LOGINTAB *tab = GetTab(hwnd);
  2111. if (NULL == tab) return 0;
  2112. INT height = 0;
  2113. INT iconCX, iconCY;
  2114. if (NULL != tab->imageList && FALSE != ImageList_GetIconSize(tab->imageList, &iconCX, &iconCY))
  2115. {
  2116. height += (iconCY + 2 * IMAGE_MARGIN_CY);
  2117. }
  2118. height += tab->textHeight;
  2119. height += tab->margins.top + tab->margins.bottom;
  2120. height += 2 * tab->frameHeight;
  2121. return height;
  2122. }
  2123. static INT LoginTab_OnGetIdealWidth(HWND hwnd, INT itemsCount)
  2124. {
  2125. LOGINTAB *tab = GetTab(hwnd);
  2126. if (NULL == tab) return 0;
  2127. INT width = 0;
  2128. if (itemsCount < 0) itemsCount = 0;
  2129. if (itemsCount > tab->itemsCount) itemsCount = tab->itemsCount;
  2130. if (itemsCount == 0)
  2131. {
  2132. width = tab->margins.left + tab->margins.right;
  2133. return width;
  2134. }
  2135. itemsCount--;
  2136. if (itemsCount <= tab->lastVisible)
  2137. {
  2138. RECT rect;
  2139. if (FALSE != LoginTab_GetItemRect(hwnd, itemsCount, &rect))
  2140. width = rect.right;
  2141. }
  2142. else
  2143. {
  2144. RECT rect;
  2145. GetWindowRect(hwnd, &rect);
  2146. LONG origWidth = rect.right - rect.left;
  2147. LONG origHeight = rect.bottom - rect.top;
  2148. SetWindowPos(hwnd, NULL, 0, 0, 40000, origHeight,
  2149. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING);
  2150. if (FALSE != LoginTab_GetItemRect(hwnd, itemsCount, &rect))
  2151. width = rect.right;
  2152. SetWindowPos(hwnd, NULL, 0, 0, origWidth, origHeight,
  2153. SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOMOVE | SWP_NOREDRAW | SWP_NOSENDCHANGING);
  2154. }
  2155. if (0 != width)
  2156. {
  2157. width += (itemsCount < (tab->itemsCount - 1) && tab->chevronWidth > tab->margins.right) ?
  2158. tab->chevronWidth : tab->margins.right;
  2159. }
  2160. return width;
  2161. }
  2162. static INT LoginTab_OnInsertItem(HWND hwnd, INT iItem, NLTITEM *pItem)
  2163. {
  2164. LOGINTAB *tab = GetTab(hwnd);
  2165. if (NULL == tab || NULL == pItem) return -1;
  2166. if (iItem < 0) iItem = 0;
  2167. INT itemsMax = (0 != tab->items) ? (INT)(_msize(tab->items)/sizeof(LOGINTABITEM*)) : 0;
  2168. if (tab->itemsCount >= itemsMax)
  2169. {
  2170. INT k = tab->itemsCount + 1 - itemsMax;
  2171. if (k < 8) k = 8;
  2172. itemsMax += k;
  2173. void *data = realloc(tab->items, itemsMax * sizeof(LOGINTABITEM*));
  2174. if (NULL == data) return -1;
  2175. tab->items = (LOGINTABITEM**)data;
  2176. data = realloc(tab->order, itemsMax * sizeof(INT));
  2177. if (NULL == data) return -1;
  2178. tab->order = (INT*)data;
  2179. }
  2180. LOGINTABITEM *item = LoginTab_CreateItem(pItem);
  2181. if (NULL == item) return -1;
  2182. if (iItem >= tab->itemsCount)
  2183. {
  2184. iItem = tab->itemsCount;
  2185. tab->items[iItem] = item;
  2186. tab->order[iItem] = iItem;
  2187. }
  2188. else
  2189. {
  2190. MoveMemory((tab->items + iItem + 1), (tab->items + iItem), sizeof(LOGINTABITEM*) * (tab->itemsCount - iItem));
  2191. tab->items[iItem] = item;
  2192. MoveMemory((tab->order + iItem + 1), (tab->order + iItem), sizeof(INT) * (tab->itemsCount - iItem));
  2193. tab->order[iItem] = iItem;
  2194. for (INT i = 0; i <= tab->itemsCount; i++)
  2195. {
  2196. if (iItem != i && tab->order[i] >= iItem)
  2197. ++(tab->order[i]);
  2198. }
  2199. }
  2200. tab->itemsCount++;
  2201. return iItem;
  2202. }
  2203. static BOOL LoginTab_OnSetItem(HWND hwnd, INT iItem, NLTITEM *pItem)
  2204. {
  2205. LOGINTAB *tab = GetTab(hwnd);
  2206. if (NULL == tab || NULL == pItem) return FALSE;
  2207. if (iItem < 0 || iItem >= tab->itemsCount) return FALSE;
  2208. BOOL result = LoginTab_SetItemInternal(tab->items[iItem], pItem);
  2209. RECT rect;
  2210. GetClientRect(hwnd, &rect);
  2211. LONG clientRight = rect.right;
  2212. if (FALSE != LoginTab_GetItemRect(hwnd, iItem, &rect))
  2213. {
  2214. rect.right = clientRight;
  2215. InvalidateRect(hwnd, &rect, FALSE);
  2216. }
  2217. else if (NULL != tab->chevronMenu)
  2218. {
  2219. INT menuCount = GetMenuItemCount(tab->chevronMenu);
  2220. while(menuCount--)
  2221. {
  2222. if (iItem == (GetMenuItemID(tab->chevronMenu, menuCount) - 1))
  2223. {
  2224. if (FALSE != GetMenuItemRect(NULL, tab->chevronMenu, menuCount, &rect))
  2225. {
  2226. POINT ptTest;
  2227. ptTest.x = rect.left + (rect.right - rect.left)/2;
  2228. ptTest.y = rect.top + (rect.bottom - rect.top)/2;
  2229. HWND hwndMenu = WindowFromPoint(ptTest);
  2230. if (NULL != hwndMenu)
  2231. {
  2232. MapWindowPoints(HWND_DESKTOP, hwndMenu, (POINT*)&rect, 2);
  2233. InvalidateRect(hwndMenu, &rect, FALSE);
  2234. }
  2235. }
  2236. break;
  2237. }
  2238. }
  2239. }
  2240. return result;
  2241. }
  2242. static BOOL LoginTab_OnGetItem(HWND hwnd, INT iItem, NLTITEM *pItem)
  2243. {
  2244. LOGINTAB *tab = GetTab(hwnd);
  2245. if (NULL == tab || NULL == pItem) return FALSE;
  2246. if (iItem < 0 || iItem >= tab->itemsCount) return FALSE;
  2247. LOGINTABITEM *item = tab->items[iItem];
  2248. BOOL succeeded = TRUE;
  2249. if (0 != (NLTIF_TEXT & pItem->mask))
  2250. {
  2251. if (NULL == pItem->pszText ||
  2252. FAILED(StringCchCopyEx(pItem->pszText, pItem->cchTextMax, item->text, NULL, NULL, STRSAFE_IGNORE_NULLS)))
  2253. {
  2254. succeeded = FALSE;
  2255. }
  2256. }
  2257. if (0 != (NLTIF_PARAM & pItem->mask))
  2258. pItem->param = item->param;
  2259. if (0 != (NLTIF_IMAGE & pItem->mask))
  2260. pItem->iImage = item->iImage;
  2261. if (0 != (NLTIF_IMAGE_ACTIVE & pItem->mask))
  2262. pItem->iImageActive = item->iImageActive;
  2263. if (0 != (NLTIF_IMAGE_DISABLED & pItem->mask))
  2264. pItem->iImageDisabled = item->iImageDisabled;
  2265. return succeeded;
  2266. }
  2267. static BOOL LoginTab_OnDeleteItem(HWND hwnd, INT iItem)
  2268. {
  2269. LOGINTAB *tab = GetTab(hwnd);
  2270. if (NULL == tab) return FALSE;
  2271. if (iItem < 0 || iItem >= tab->itemsCount)
  2272. return FALSE;
  2273. HWND hParent = GetAncestor(hwnd, GA_PARENT);
  2274. if (NULL != hParent)
  2275. {
  2276. NMLOGINTAB nmp;
  2277. nmp.hdr.code = NLTN_DELETEITEM;
  2278. nmp.hdr.hwndFrom = hwnd;
  2279. nmp.hdr.idFrom = GetWindowLongPtr(hwnd, GWLP_ID);
  2280. nmp.iItem = iItem;
  2281. SNDMSG(hParent, WM_NOTIFY, (WPARAM)nmp.hdr.idFrom, (LPARAM)&nmp);
  2282. }
  2283. LOGINTABITEM *item = tab->items[iItem];
  2284. INT shiftLen = tab->itemsCount - iItem - 1;
  2285. if (shiftLen > 0)
  2286. {
  2287. MoveMemory((tab->items + iItem), (tab->items + (iItem + 1)), sizeof(LOGINTABITEM*)*shiftLen);
  2288. INT iOrder = tab->itemsCount - 1;
  2289. while(iOrder--)
  2290. {
  2291. if (iItem == tab->order[iOrder])
  2292. {
  2293. MoveMemory((tab->order + iOrder), (tab->order + (iOrder + 1)),
  2294. sizeof(INT)*(tab->itemsCount - iOrder - 1));
  2295. break;
  2296. }
  2297. }
  2298. }
  2299. LoginTab_FreeItem(item);
  2300. tab->itemsCount--;
  2301. return TRUE;
  2302. }
  2303. static BOOL LoginTab_OnDeleteAllItems(HWND hwnd)
  2304. {
  2305. LOGINTAB *tab = GetTab(hwnd);
  2306. if (NULL == tab) return FALSE;
  2307. tab->itemsCount -= LoginTab_DeleteAllItemsReal(hwnd, tab->items, tab->itemsCount);
  2308. return TRUE;
  2309. }
  2310. static INT LoginTab_OnGetItemCount(HWND hwnd)
  2311. {
  2312. LOGINTAB *tab = GetTab(hwnd);
  2313. return (NULL != tab) ? tab->itemsCount : -1;
  2314. }
  2315. static INT LoginTab_OnGetCurSel(HWND hwnd)
  2316. {
  2317. LOGINTAB *tab = GetTab(hwnd);
  2318. return (NULL != tab) ? tab->iSelected : -1;
  2319. }
  2320. static INT LoginTab_OnSetCurSel(HWND hwnd, INT iItem)
  2321. {
  2322. LOGINTAB *tab = GetTab(hwnd);
  2323. if (NULL == tab) return -1;
  2324. if (iItem < 0 || iItem >= tab->itemsCount)
  2325. return -1;
  2326. if (iItem == tab->iSelected)
  2327. return tab->iSelected;
  2328. INT iSelected = tab->iSelected;
  2329. INT iFocused = tab->iFocused;
  2330. tab->iSelected = iItem;
  2331. if (tab->iFocused != tab->itemsCount)
  2332. tab->iFocused = iItem;
  2333. RECT rect;
  2334. if (-1 != iSelected &&
  2335. FALSE != LoginTab_GetItemRect(hwnd, iSelected, &rect))
  2336. {
  2337. InvalidateRect(hwnd, &rect, FALSE);
  2338. }
  2339. if (iFocused != tab->iFocused && -1 != iFocused && iFocused != iSelected &&
  2340. FALSE != LoginTab_GetItemRect(hwnd, iFocused, &rect))
  2341. {
  2342. InvalidateRect(hwnd, &rect, FALSE);
  2343. }
  2344. if (-1 != tab->iSelected &&
  2345. FALSE != LoginTab_GetItemRect(hwnd, tab->iSelected, &rect))
  2346. {
  2347. InvalidateRect(hwnd, &rect, FALSE);
  2348. }
  2349. for(INT i = (tab->lastVisible + 1); i < tab->itemsCount; i++)
  2350. {
  2351. if (tab->order[i] == tab->iSelected)
  2352. {
  2353. LoginTab_UpdateLayout(hwnd, TRUE);
  2354. break;
  2355. }
  2356. }
  2357. return iSelected;
  2358. }
  2359. static HIMAGELIST LoginTab_OnSetImageList(HWND hwnd, HIMAGELIST himl)
  2360. {
  2361. LOGINTAB *tab = GetTab(hwnd);
  2362. if (NULL == tab) return NULL;
  2363. HIMAGELIST old = tab->imageList;
  2364. tab->imageList = himl;
  2365. LoginTab_UpdateLayout(hwnd, TRUE);
  2366. return old;
  2367. }
  2368. static HIMAGELIST LoginTab_OnGetImageList(HWND hwnd)
  2369. {
  2370. LOGINTAB *tab = GetTab(hwnd);
  2371. return (NULL != tab) ? tab->imageList : NULL;
  2372. }
  2373. static BOOL LoginTab_OnResetOrder(HWND hwnd)
  2374. {
  2375. LOGINTAB *tab = GetTab(hwnd);
  2376. if (NULL == tab) return FALSE;
  2377. for (INT i = 0; i < tab->itemsCount; i++)
  2378. tab->order[i] = i;
  2379. LoginTab_UpdateLayout(hwnd, FALSE);
  2380. InvalidateRect(hwnd, NULL, FALSE);
  2381. return TRUE;
  2382. }
  2383. static void LoginTab_OnLockSelection(HWND hwnd, BOOL fLock)
  2384. {
  2385. UINT windowStyle = GetWindowStyle(hwnd);
  2386. if ((FALSE != fLock) != (0 != (NLTS_LOCKED & windowStyle)))
  2387. {
  2388. if (FALSE != fLock)
  2389. windowStyle |= NLTS_LOCKED;
  2390. else
  2391. windowStyle &= ~NLTS_LOCKED;
  2392. SetWindowLongPtr(hwnd, GWL_STYLE, windowStyle);
  2393. InvalidateRect(hwnd, NULL, FALSE);
  2394. }
  2395. }
  2396. static BOOL LoginTab_OnMeasureChevronItem(HWND hwnd, MEASUREITEMSTRUCT* pmis)
  2397. {
  2398. LOGINTAB *tab = GetTab(hwnd);
  2399. if (NULL == tab) return FALSE;
  2400. MENUINFO mi;
  2401. mi.cbSize = sizeof(mi);
  2402. mi.fMask = MIM_MENUDATA;
  2403. if (FALSE != GetMenuInfo(tab->chevronMenu, &mi) && NULL != mi.dwMenuData)
  2404. {
  2405. CHEVRONMENUPAINTPARAM *pmp= (CHEVRONMENUPAINTPARAM*)mi.dwMenuData;
  2406. pmis->itemWidth = pmp->itemWidth;
  2407. pmis->itemHeight = pmp->itemHeight;
  2408. return TRUE;
  2409. }
  2410. return FALSE;
  2411. }
  2412. static BOOL LoginTab_OnDrawChevronItem(HWND hwnd, DRAWITEMSTRUCT* pdis)
  2413. {
  2414. LOGINTAB *tab = GetTab(hwnd);
  2415. if (NULL == tab) return FALSE;
  2416. MENUINFO mi;
  2417. mi.cbSize = sizeof(mi);
  2418. mi.fMask = MIM_MENUDATA | MIM_BACKGROUND;
  2419. if (FALSE == GetMenuInfo(tab->chevronMenu, &mi) || NULL == mi.dwMenuData)
  2420. return FALSE;
  2421. CHEVRONMENUPAINTPARAM *pmp= (CHEVRONMENUPAINTPARAM*)mi.dwMenuData;
  2422. if (NULL == pmp->hwndMenu)
  2423. {
  2424. pmp->hwndMenu = WindowFromDC(pdis->hDC);
  2425. if (NULL != pmp->hwndMenu)
  2426. {
  2427. SendMessage(pmp->hwndMenu, WM_CHANGEUISTATE,
  2428. MAKEWPARAM(UISF_HIDEACCEL | UISF_HIDEFOCUS, UIS_INITIALIZE), 0L);
  2429. }
  2430. }
  2431. tab->drawStyle = LoginTab_GetDrawStyles(hwnd);
  2432. if (NULL != pmp->hwndMenu)
  2433. {
  2434. UINT uiState = (UINT)SendMessage(pmp->hwndMenu, WM_QUERYUISTATE, 0, 0L);
  2435. if (0 == (UISF_HIDEFOCUS & uiState))
  2436. tab->drawStyle |= NLTDS_FOCUSED;
  2437. else
  2438. tab->drawStyle &= ~NLTDS_FOCUSED;
  2439. }
  2440. HBITMAP hbmp = LoginTab_GetItemBitmap(tab, pdis->hDC,
  2441. pdis->rcItem.right - pdis->rcItem.left,
  2442. pdis->rcItem.bottom - pdis->rcItem.top);
  2443. HBITMAP hbmpOrig = NULL;
  2444. POINT viewportOrig;
  2445. if (NULL != hbmp)
  2446. {
  2447. hbmpOrig = (HBITMAP)SelectObject(pmp->hdcItem, hbmp);
  2448. SetViewportOrgEx(pmp->hdcItem, -pdis->rcItem.left, -pdis->rcItem.top, &viewportOrig);
  2449. }
  2450. if (NULL == mi.hbrBack)
  2451. mi.hbrBack = GetSysColorBrush(COLOR_MENU);
  2452. INT itemWidth = pdis->rcItem.right - pdis->rcItem.left;
  2453. INT itemHeight = pdis->rcItem.bottom - pdis->rcItem.top;
  2454. POINT brushOrgEx;
  2455. SetBrushOrgEx(pmp->hdcItem, 0, -pdis->rcItem.top, &brushOrgEx);
  2456. FillRect(pmp->hdcItem, &pdis->rcItem, mi.hbrBack);
  2457. SetBrushOrgEx(pmp->hdcItem, brushOrgEx.x, brushOrgEx.y, NULL);
  2458. LOGINTABITEM *item = (LOGINTABITEM*)pdis->itemData;
  2459. INT iItem = pdis->itemID - 1;
  2460. INT iHighlighted = tab->iHighlighted;
  2461. if (0 != (ODS_SELECTED & pdis->itemState))
  2462. {
  2463. tab->iHighlighted = iItem;
  2464. if (tab->iFocused != iItem && -1 != tab->iFocused)
  2465. {
  2466. RECT rect;
  2467. if (FALSE != LoginTab_GetItemRect(hwnd, tab->iFocused, &rect))
  2468. InvalidateRect(hwnd, &rect, FALSE);
  2469. }
  2470. tab->iFocused = iItem;
  2471. }
  2472. else
  2473. tab->iFocused = -1;
  2474. LoginTab_PaintItem(hwnd, pmp->hdcItem, tab, item, iItem, &pdis->rcItem, &pdis->rcItem, pmp->hdcSrc);
  2475. tab->iHighlighted = iHighlighted;
  2476. BitBlt(pdis->hDC, pdis->rcItem.left, pdis->rcItem.top, itemWidth, itemHeight,
  2477. pmp->hdcItem, pdis->rcItem.left, pdis->rcItem.top, SRCCOPY);
  2478. if (NULL != hbmp)
  2479. {
  2480. SelectObject(pmp->hdcItem, hbmpOrig);
  2481. SetViewportOrgEx(pmp->hdcItem, viewportOrig.x, viewportOrig.y, NULL);
  2482. }
  2483. return TRUE;
  2484. }
  2485. static BOOL LoginTab_OnMeasureItem(HWND hwnd, MEASUREITEMSTRUCT* pmis)
  2486. {
  2487. LOGINTAB *tab = GetTab(hwnd);
  2488. if (NULL == tab) return FALSE;
  2489. switch(pmis->CtlType)
  2490. {
  2491. case ODT_MENU:
  2492. if (NULL != tab->chevronMenu)
  2493. return LoginTab_OnMeasureChevronItem(hwnd, pmis);
  2494. break;
  2495. }
  2496. return FALSE;
  2497. }
  2498. static BOOL LoginTab_OnDrawItem(HWND hwnd, DRAWITEMSTRUCT* pdis)
  2499. {
  2500. LOGINTAB *tab = GetTab(hwnd);
  2501. if (NULL == tab) return FALSE;
  2502. switch(pdis->CtlType)
  2503. {
  2504. case ODT_MENU:
  2505. if (NULL != tab->chevronMenu)
  2506. return LoginTab_OnDrawChevronItem(hwnd, pdis);
  2507. break;
  2508. }
  2509. return FALSE;
  2510. }
  2511. void LoginTab_OnThemeChanged(HWND hwnd)
  2512. {
  2513. LoginTab_UpdateColors(hwnd);
  2514. OutputDebugStringA("Theme changed received\r\n");
  2515. }
  2516. void LoginTab_OnSysColorChanged(HWND hwnd)
  2517. {
  2518. LoginTab_UpdateColors(hwnd);
  2519. OutputDebugStringA("Color changed received\r\n");
  2520. }
  2521. static LRESULT WINAPI LoginTab_WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2522. {
  2523. switch(uMsg)
  2524. {
  2525. case WM_CREATE: return LoginTab_OnCreate(hwnd, (CREATESTRUCT*)lParam);
  2526. case WM_DESTROY: LoginTab_OnDestroy(hwnd); return 0;
  2527. case WM_ERASEBKGND: return 0;
  2528. case WM_PAINT: LoginTab_OnPaint(hwnd); return 0;
  2529. case WM_PRINTCLIENT: LoginTab_OnPrintClient(hwnd, (HDC)wParam, (UINT)lParam); return 0;
  2530. case WM_WINDOWPOSCHANGED: LoginTab_OnWindowPosChanged(hwnd, (WINDOWPOS*)lParam); return 0;
  2531. case WM_SIZE: return 0;
  2532. case WM_MOUSEMOVE: LoginTab_OnMouseMove(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  2533. case WM_LBUTTONDOWN: LoginTab_OnLButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  2534. case WM_LBUTTONUP: LoginTab_OnLButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  2535. case WM_RBUTTONDOWN: LoginTab_OnRButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  2536. case WM_RBUTTONUP: LoginTab_OnRButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  2537. case WM_MBUTTONDOWN: LoginTab_OnMButtonDown(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  2538. case WM_MBUTTONUP: LoginTab_OnMButtonUp(hwnd, (UINT)wParam, MAKEPOINTS(lParam)); return 0;
  2539. case WM_MOUSELEAVE: LoginTab_OnMouseLeave(hwnd); return 0;
  2540. case WM_CAPTURECHANGED: LoginTab_OnCaptureChanged(hwnd, (HWND)lParam); return 0;
  2541. case WM_SETFOCUS: LoginTab_OnSetFocus(hwnd, (HWND)wParam); return 0;
  2542. case WM_KILLFOCUS: LoginTab_OnKillFocus(hwnd, (HWND)wParam); return 0;
  2543. case WM_ENABLE: LoginTab_OnEnable(hwnd, (BOOL)wParam); return 0;
  2544. case WM_KEYDOWN: LoginTab_OnKeyDown(hwnd, (INT)wParam, (UINT)lParam); return 0;
  2545. case WM_GETDLGCODE: return LoginTab_OnGetDlgCode(hwnd, (INT)wParam, (MSG*)lParam);
  2546. case WM_MENUCHAR: return LoginTab_OnMenuChar(hwnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam);
  2547. case WM_MENUSELECT: LoginTab_OnMenuSelect(hwnd, LOWORD(wParam), HIWORD(wParam), (HMENU)lParam); return 0;
  2548. case WM_MEASUREITEM: return LoginTab_OnMeasureItem(hwnd, (MEASUREITEMSTRUCT*)lParam);
  2549. case WM_DRAWITEM: return LoginTab_OnDrawItem(hwnd, (DRAWITEMSTRUCT*)lParam);
  2550. case WM_NOTIFY: return LoginTab_OnNotify(hwnd, (INT)wParam, (NMHDR*)lParam);
  2551. case WM_THEMECHANGED: LoginTab_OnThemeChanged(hwnd); return TRUE;
  2552. case WM_SYSCOLORCHANGE: LoginTab_OnSysColorChanged(hwnd); return TRUE;
  2553. case NLTM_GETIDEALHEIGHT: return LoginTab_OnGetIdealHeight(hwnd);
  2554. case NLTM_INSERTITEM: return LoginTab_OnInsertItem(hwnd, (INT)wParam, (NLTITEM*)lParam);
  2555. case NLTM_SETITEM: return LoginTab_OnSetItem(hwnd, (INT)wParam, (NLTITEM*)lParam);
  2556. case NLTM_GETITEM: return LoginTab_OnGetItem(hwnd, (INT)wParam, (NLTITEM*)lParam);
  2557. case NLTM_DELETEITEM: return LoginTab_OnDeleteItem(hwnd, (INT)wParam);
  2558. case NLTM_DELETEALLITEMS: return LoginTab_OnDeleteAllItems(hwnd);
  2559. case NLTM_GETITEMCOUNT: return LoginTab_OnGetItemCount(hwnd);
  2560. case NLTM_GETCURSEL: return LoginTab_OnGetCurSel(hwnd);
  2561. case NLTM_SETCURSEL: return LoginTab_OnSetCurSel(hwnd, (INT)wParam);
  2562. case NLTM_SETIMAGELIST: return (LRESULT)LoginTab_OnSetImageList(hwnd, (HIMAGELIST)lParam);
  2563. case NLTM_GETIMAGELIST: return (LRESULT)LoginTab_OnGetImageList(hwnd);
  2564. case NLTM_RESETORDER: LoginTab_OnResetOrder(hwnd); return 0;
  2565. case NLTM_LOCKSELECTION: LoginTab_OnLockSelection(hwnd, (BOOL)wParam); return 0;
  2566. case NLTM_GETIDEALWIDTH: return LoginTab_OnGetIdealWidth(hwnd, (INT)wParam);
  2567. }
  2568. return DefWindowProc(hwnd, uMsg, wParam, lParam);
  2569. }