UIList.cpp 95 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040
  1. #include "StdAfx.h"
  2. namespace DuiLib {
  3. /////////////////////////////////////////////////////////////////////////////////////
  4. //
  5. class CListBodyUI : public CVerticalLayoutUI
  6. {
  7. public:
  8. CListBodyUI(CListUI* pOwner);
  9. void SetScrollPos(SIZE szPos);
  10. void SetPos(RECT rc, bool bNeedInvalidate = true);
  11. void DoEvent(TEventUI& event);
  12. bool DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl);
  13. bool SortItems(PULVCompareFunc pfnCompare, UINT_PTR dwData, int& iCurSel);
  14. protected:
  15. static int __cdecl ItemComareFunc(void *pvlocale, const void *item1, const void *item2);
  16. int __cdecl ItemComareFunc(const void *item1, const void *item2);
  17. protected:
  18. CListUI* m_pOwner;
  19. PULVCompareFunc m_pCompareFunc;
  20. UINT_PTR m_compareData;
  21. };
  22. /////////////////////////////////////////////////////////////////////////////////////
  23. //
  24. //
  25. CListUI::CListUI() : m_pCallback(NULL), m_bScrollSelect(false), m_iCurSel(-1), m_iExpandedItem(-1)
  26. {
  27. m_pList = new CListBodyUI(this);
  28. m_pHeader = new CListHeaderUI;
  29. Add(m_pHeader);
  30. CVerticalLayoutUI::Add(m_pList);
  31. m_ListInfo.nColumns = 0;
  32. m_ListInfo.uFixedHeight = 0;
  33. m_ListInfo.nFont = -1;
  34. m_ListInfo.uTextStyle = DT_VCENTER | DT_SINGLELINE; // m_uTextStyle(DT_VCENTER | DT_END_ELLIPSIS)
  35. m_ListInfo.dwTextColor = 0xFF000000;
  36. m_ListInfo.dwBkColor = 0;
  37. m_ListInfo.bAlternateBk = false;
  38. m_ListInfo.dwSelectedTextColor = 0xFF000000;
  39. m_ListInfo.dwSelectedBkColor = 0xFFC1E3FF;
  40. m_ListInfo.dwHotTextColor = 0xFF000000;
  41. m_ListInfo.dwHotBkColor = 0xFFE9F5FF;
  42. m_ListInfo.dwDisabledTextColor = 0xFFCCCCCC;
  43. m_ListInfo.dwDisabledBkColor = 0xFFFFFFFF;
  44. m_ListInfo.iHLineSize = 0;
  45. m_ListInfo.dwHLineColor = 0xFF3C3C3C;
  46. m_ListInfo.iVLineSize = 0;
  47. m_ListInfo.dwVLineColor = 0xFF3C3C3C;
  48. m_ListInfo.bShowHtml = false;
  49. m_ListInfo.bMultiExpandable = false;
  50. ::ZeroMemory(&m_ListInfo.rcTextPadding, sizeof(m_ListInfo.rcTextPadding));
  51. ::ZeroMemory(&m_ListInfo.rcColumn, sizeof(m_ListInfo.rcColumn));
  52. }
  53. LPCTSTR CListUI::GetClass() const
  54. {
  55. return DUI_CTR_LIST;
  56. }
  57. UINT CListUI::GetControlFlags() const
  58. {
  59. return UIFLAG_TABSTOP;
  60. }
  61. LPVOID CListUI::GetInterface(LPCTSTR pstrName)
  62. {
  63. if( _tcscmp(pstrName, DUI_CTR_LIST) == 0 ) return static_cast<CListUI*>(this);
  64. if( _tcscmp(pstrName, DUI_CTR_ILIST) == 0 ) return static_cast<IListUI*>(this);
  65. if( _tcscmp(pstrName, DUI_CTR_ILISTOWNER) == 0 ) return static_cast<IListOwnerUI*>(this);
  66. return CVerticalLayoutUI::GetInterface(pstrName);
  67. }
  68. CControlUI* CListUI::GetItemAt(int iIndex) const
  69. {
  70. return m_pList->GetItemAt(iIndex);
  71. }
  72. int CListUI::GetItemIndex(CControlUI* pControl) const
  73. {
  74. if( pControl->GetInterface(DUI_CTR_LISTHEADER) != NULL ) return CVerticalLayoutUI::GetItemIndex(pControl);
  75. // We also need to recognize header sub-items
  76. if( _tcsstr(pControl->GetClass(), DUI_CTR_LISTHEADERITEM) != NULL ) return m_pHeader->GetItemIndex(pControl);
  77. return m_pList->GetItemIndex(pControl);
  78. }
  79. bool CListUI::SetItemIndex(CControlUI* pControl, int iIndex)
  80. {
  81. if( pControl->GetInterface(DUI_CTR_LISTHEADER) != NULL ) return CVerticalLayoutUI::SetItemIndex(pControl, iIndex);
  82. // We also need to recognize header sub-items
  83. if( _tcsstr(pControl->GetClass(), DUI_CTR_LISTHEADERITEM) != NULL ) return m_pHeader->SetItemIndex(pControl, iIndex);
  84. int iOrginIndex = m_pList->GetItemIndex(pControl);
  85. if( iOrginIndex == -1 ) return false;
  86. if( iOrginIndex == iIndex ) return true;
  87. IListItemUI* pSelectedListItem = NULL;
  88. if( m_iCurSel >= 0 ) pSelectedListItem =
  89. static_cast<IListItemUI*>(GetItemAt(m_iCurSel)->GetInterface(DUI_CTR_ILISTITEM));
  90. if( !m_pList->SetItemIndex(pControl, iIndex) ) return false;
  91. int iMinIndex = min(iOrginIndex, iIndex);
  92. int iMaxIndex = max(iOrginIndex, iIndex);
  93. for(int i = iMinIndex; i < iMaxIndex + 1; ++i) {
  94. CControlUI* p = m_pList->GetItemAt(i);
  95. IListItemUI* pListItem = static_cast<IListItemUI*>(p->GetInterface(DUI_CTR_ILISTITEM));
  96. if( pListItem != NULL ) {
  97. pListItem->SetIndex(i);
  98. }
  99. }
  100. if( m_iCurSel >= 0 && pSelectedListItem != NULL ) m_iCurSel = pSelectedListItem->GetIndex();
  101. return true;
  102. }
  103. bool CListUI::SetMultiItemIndex(CControlUI* pStartControl, int iCount, int iNewStartIndex)
  104. {
  105. if (pStartControl == NULL || iCount < 0 || iNewStartIndex < 0) return false;
  106. if( pStartControl->GetInterface(DUI_CTR_LISTHEADER) != NULL ) return CVerticalLayoutUI::SetMultiItemIndex(pStartControl, iCount, iNewStartIndex);
  107. // We also need to recognize header sub-items
  108. if( _tcsstr(pStartControl->GetClass(), DUI_CTR_LISTHEADERITEM) != NULL ) return m_pHeader->SetMultiItemIndex(pStartControl, iCount, iNewStartIndex);
  109. int iStartIndex = GetItemIndex(pStartControl);
  110. if (iStartIndex == iNewStartIndex) return true;
  111. if (iStartIndex + iCount > GetCount()) return false;
  112. if (iNewStartIndex + iCount > GetCount()) return false;
  113. IListItemUI* pSelectedListItem = NULL;
  114. if( m_iCurSel >= 0 ) pSelectedListItem =
  115. static_cast<IListItemUI*>(GetItemAt(m_iCurSel)->GetInterface(DUI_CTR_ILISTITEM));
  116. if( !m_pList->SetMultiItemIndex(pStartControl, iCount, iNewStartIndex) ) return false;
  117. int iMinIndex = min(iStartIndex, iNewStartIndex);
  118. int iMaxIndex = max(iStartIndex + iCount, iNewStartIndex + iCount);
  119. for(int i = iMinIndex; i < iMaxIndex + 1; ++i) {
  120. CControlUI* p = m_pList->GetItemAt(i);
  121. IListItemUI* pListItem = static_cast<IListItemUI*>(p->GetInterface(DUI_CTR_ILISTITEM));
  122. if( pListItem != NULL ) {
  123. pListItem->SetIndex(i);
  124. }
  125. }
  126. if( m_iCurSel >= 0 && pSelectedListItem != NULL ) m_iCurSel = pSelectedListItem->GetIndex();
  127. return true;
  128. }
  129. int CListUI::GetCount() const
  130. {
  131. return m_pList->GetCount();
  132. }
  133. bool CListUI::Add(CControlUI* pControl)
  134. {
  135. // Override the Add() method so we can add items specifically to
  136. // the intended widgets. Headers are assumed to be
  137. // answer the correct interface so we can add multiple list headers.
  138. if( pControl->GetInterface(DUI_CTR_LISTHEADER) != NULL ) {
  139. if( m_pHeader != pControl && m_pHeader->GetCount() == 0 ) {
  140. CVerticalLayoutUI::Remove(m_pHeader);
  141. m_pHeader = static_cast<CListHeaderUI*>(pControl);
  142. }
  143. m_ListInfo.nColumns = MIN(m_pHeader->GetCount(), UILIST_MAX_COLUMNS);
  144. return CVerticalLayoutUI::AddAt(pControl, 0);
  145. }
  146. // We also need to recognize header sub-items
  147. if( _tcsstr(pControl->GetClass(), DUI_CTR_LISTHEADERITEM) != NULL ) {
  148. bool ret = m_pHeader->Add(pControl);
  149. m_ListInfo.nColumns = MIN(m_pHeader->GetCount(), UILIST_MAX_COLUMNS);
  150. return ret;
  151. }
  152. // The list items should know about us
  153. IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(DUI_CTR_ILISTITEM));
  154. if( pListItem != NULL ) {
  155. pListItem->SetOwner(this);
  156. pListItem->SetIndex(GetCount());
  157. }
  158. return m_pList->Add(pControl);
  159. }
  160. bool CListUI::AddAt(CControlUI* pControl, int iIndex)
  161. {
  162. // Override the AddAt() method so we can add items specifically to
  163. // the intended widgets. Headers and are assumed to be
  164. // answer the correct interface so we can add multiple list headers.
  165. if( pControl->GetInterface(DUI_CTR_LISTHEADER) != NULL ) {
  166. if( m_pHeader != pControl && m_pHeader->GetCount() == 0 ) {
  167. CVerticalLayoutUI::Remove(m_pHeader);
  168. m_pHeader = static_cast<CListHeaderUI*>(pControl);
  169. }
  170. m_ListInfo.nColumns = MIN(m_pHeader->GetCount(), UILIST_MAX_COLUMNS);
  171. return CVerticalLayoutUI::AddAt(pControl, 0);
  172. }
  173. // We also need to recognize header sub-items
  174. if( _tcsstr(pControl->GetClass(), DUI_CTR_LISTHEADERITEM) != NULL ) {
  175. bool ret = m_pHeader->AddAt(pControl, iIndex);
  176. m_ListInfo.nColumns = MIN(m_pHeader->GetCount(), UILIST_MAX_COLUMNS);
  177. return ret;
  178. }
  179. if (!m_pList->AddAt(pControl, iIndex)) return false;
  180. // The list items should know about us
  181. IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(DUI_CTR_ILISTITEM));
  182. if( pListItem != NULL ) {
  183. pListItem->SetOwner(this);
  184. pListItem->SetIndex(iIndex);
  185. }
  186. for(int i = iIndex + 1; i < m_pList->GetCount(); ++i) {
  187. CControlUI* p = m_pList->GetItemAt(i);
  188. pListItem = static_cast<IListItemUI*>(p->GetInterface(DUI_CTR_ILISTITEM));
  189. if( pListItem != NULL ) {
  190. pListItem->SetIndex(i);
  191. }
  192. }
  193. if( m_iCurSel >= iIndex ) m_iCurSel += 1;
  194. return true;
  195. }
  196. bool CListUI::Remove(CControlUI* pControl, bool bDoNotDestroy)
  197. {
  198. if( pControl->GetInterface(DUI_CTR_LISTHEADER) != NULL ) return CVerticalLayoutUI::Remove(pControl, bDoNotDestroy);
  199. // We also need to recognize header sub-items
  200. if( _tcsstr(pControl->GetClass(), DUI_CTR_LISTHEADERITEM) != NULL ) return m_pHeader->Remove(pControl, bDoNotDestroy);
  201. int iIndex = m_pList->GetItemIndex(pControl);
  202. if (iIndex == -1) return false;
  203. if (!m_pList->RemoveAt(iIndex, bDoNotDestroy)) return false;
  204. for(int i = iIndex; i < m_pList->GetCount(); ++i) {
  205. CControlUI* p = m_pList->GetItemAt(i);
  206. IListItemUI* pListItem = static_cast<IListItemUI*>(p->GetInterface(DUI_CTR_ILISTITEM));
  207. if( pListItem != NULL ) {
  208. pListItem->SetIndex(i);
  209. }
  210. }
  211. if( iIndex == m_iCurSel && m_iCurSel >= 0 ) {
  212. int iSel = m_iCurSel;
  213. m_iCurSel = -1;
  214. SelectItem(FindSelectable(iSel, false));
  215. }
  216. else if( iIndex < m_iCurSel ) m_iCurSel -= 1;
  217. return true;
  218. }
  219. bool CListUI::RemoveAt(int iIndex, bool bDoNotDestroy)
  220. {
  221. if (!m_pList->RemoveAt(iIndex, bDoNotDestroy)) return false;
  222. for(int i = iIndex; i < m_pList->GetCount(); ++i) {
  223. CControlUI* p = m_pList->GetItemAt(i);
  224. IListItemUI* pListItem = static_cast<IListItemUI*>(p->GetInterface(DUI_CTR_ILISTITEM));
  225. if( pListItem != NULL ) pListItem->SetIndex(i);
  226. }
  227. if( iIndex == m_iCurSel && m_iCurSel >= 0 ) {
  228. int iSel = m_iCurSel;
  229. m_iCurSel = -1;
  230. SelectItem(FindSelectable(iSel, false));
  231. }
  232. else if( iIndex < m_iCurSel ) m_iCurSel -= 1;
  233. return true;
  234. }
  235. void CListUI::RemoveAll()
  236. {
  237. m_iCurSel = -1;
  238. m_iExpandedItem = -1;
  239. m_pList->RemoveAll();
  240. }
  241. void CListUI::SetPos(RECT rc, bool bNeedInvalidate)
  242. {
  243. if( m_pHeader != NULL ) { // 设置header各子元素x坐标,因为有些listitem的setpos需要用到(临时修复)
  244. int iLeft = rc.left + m_rcInset.left;
  245. int iRight = rc.right - m_rcInset.right;
  246. m_ListInfo.nColumns = MIN(m_pHeader->GetCount(), UILIST_MAX_COLUMNS);
  247. if( !m_pHeader->IsVisible() ) {
  248. for( int it = m_pHeader->GetCount() - 1; it >= 0; it-- ) {
  249. static_cast<CControlUI*>(m_pHeader->GetItemAt(it))->SetInternVisible(true);
  250. }
  251. }
  252. m_pHeader->SetPos(CDuiRect(iLeft, 0, iRight, 0), false);
  253. int iOffset = m_pList->GetScrollPos().cx;
  254. for( int i = 0; i < m_ListInfo.nColumns; i++ ) {
  255. CControlUI* pControl = static_cast<CControlUI*>(m_pHeader->GetItemAt(i));
  256. if( !pControl->IsVisible() ) continue;
  257. if( pControl->IsFloat() ) continue;
  258. RECT rcPos = pControl->GetPos();
  259. if( iOffset > 0 ) {
  260. rcPos.left -= iOffset;
  261. rcPos.right -= iOffset;
  262. pControl->SetPos(rcPos, false);
  263. }
  264. m_ListInfo.rcColumn[i] = pControl->GetPos();
  265. }
  266. if( !m_pHeader->IsVisible() ) {
  267. for( int it = m_pHeader->GetCount() - 1; it >= 0; it-- ) {
  268. static_cast<CControlUI*>(m_pHeader->GetItemAt(it))->SetInternVisible(false);
  269. }
  270. m_pHeader->SetInternVisible(false);
  271. }
  272. }
  273. CVerticalLayoutUI::SetPos(rc, bNeedInvalidate);
  274. if( m_pHeader == NULL ) return;
  275. rc = m_rcItem;
  276. rc.left += m_rcInset.left;
  277. rc.top += m_rcInset.top;
  278. rc.right -= m_rcInset.right;
  279. rc.bottom -= m_rcInset.bottom;
  280. if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {
  281. rc.top -= m_pVerticalScrollBar->GetScrollPos();
  282. rc.bottom -= m_pVerticalScrollBar->GetScrollPos();
  283. rc.bottom += m_pVerticalScrollBar->GetScrollRange();
  284. rc.right -= m_pVerticalScrollBar->GetFixedWidth();
  285. }
  286. if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) {
  287. rc.left -= m_pHorizontalScrollBar->GetScrollPos();
  288. rc.right -= m_pHorizontalScrollBar->GetScrollPos();
  289. rc.right += m_pHorizontalScrollBar->GetScrollRange();
  290. rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
  291. }
  292. m_ListInfo.nColumns = MIN(m_pHeader->GetCount(), UILIST_MAX_COLUMNS);
  293. if( !m_pHeader->IsVisible() ) {
  294. for( int it = m_pHeader->GetCount() - 1; it >= 0; it-- ) {
  295. static_cast<CControlUI*>(m_pHeader->GetItemAt(it))->SetInternVisible(true);
  296. }
  297. m_pHeader->SetPos(CDuiRect(rc.left, 0, rc.right, 0), false);
  298. }
  299. int iOffset = m_pList->GetScrollPos().cx;
  300. for( int i = 0; i < m_ListInfo.nColumns; i++ ) {
  301. CControlUI* pControl = static_cast<CControlUI*>(m_pHeader->GetItemAt(i));
  302. if( !pControl->IsVisible() ) continue;
  303. if( pControl->IsFloat() ) continue;
  304. RECT rcPos = pControl->GetPos();
  305. if( iOffset > 0 ) {
  306. rcPos.left -= iOffset;
  307. rcPos.right -= iOffset;
  308. pControl->SetPos(rcPos, false);
  309. }
  310. m_ListInfo.rcColumn[i] = pControl->GetPos();
  311. }
  312. if( !m_pHeader->IsVisible() ) {
  313. for( int it = m_pHeader->GetCount() - 1; it >= 0; it-- ) {
  314. static_cast<CControlUI*>(m_pHeader->GetItemAt(it))->SetInternVisible(false);
  315. }
  316. m_pHeader->SetInternVisible(false);
  317. }
  318. }
  319. void CListUI::Move(SIZE szOffset, bool bNeedInvalidate)
  320. {
  321. CVerticalLayoutUI::Move(szOffset, bNeedInvalidate);
  322. if( !m_pHeader->IsVisible() ) m_pHeader->Move(szOffset, false);
  323. }
  324. void CListUI::DoEvent(TEventUI& event)
  325. {
  326. if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {
  327. if( m_pParent != NULL ) m_pParent->DoEvent(event);
  328. else CVerticalLayoutUI::DoEvent(event);
  329. return;
  330. }
  331. if( event.Type == UIEVENT_SETFOCUS )
  332. {
  333. m_bFocused = true;
  334. return;
  335. }
  336. if( event.Type == UIEVENT_KILLFOCUS )
  337. {
  338. m_bFocused = false;
  339. return;
  340. }
  341. if( event.Type == UIEVENT_KEYDOWN )
  342. {
  343. if (IsKeyboardEnabled() && IsEnabled()) {
  344. switch( event.chKey ) {
  345. case VK_UP:
  346. SelectItem(FindSelectable(m_iCurSel - 1, false), true);
  347. case VK_DOWN:
  348. SelectItem(FindSelectable(m_iCurSel + 1, true), true);
  349. case VK_PRIOR:
  350. PageUp();
  351. case VK_NEXT:
  352. PageDown();
  353. case VK_HOME:
  354. SelectItem(FindSelectable(0, false), true);
  355. case VK_END:
  356. SelectItem(FindSelectable(GetCount() - 1, true), true);
  357. case VK_RETURN:
  358. if( m_iCurSel != -1 ) GetItemAt(m_iCurSel)->Activate();
  359. }
  360. return;
  361. }
  362. }
  363. if( event.Type == UIEVENT_SCROLLWHEEL )
  364. {
  365. if (IsEnabled()) {
  366. switch( LOWORD(event.wParam) ) {
  367. case SB_LINEUP:
  368. if( m_bScrollSelect ) SelectItem(FindSelectable(m_iCurSel - 1, false), true);
  369. else LineUp();
  370. return;
  371. case SB_LINEDOWN:
  372. if( m_bScrollSelect ) SelectItem(FindSelectable(m_iCurSel + 1, true), true);
  373. else LineDown();
  374. return;
  375. }
  376. }
  377. }
  378. CVerticalLayoutUI::DoEvent(event);
  379. }
  380. CListHeaderUI* CListUI::GetHeader() const
  381. {
  382. return m_pHeader;
  383. }
  384. CContainerUI* CListUI::GetList() const
  385. {
  386. return m_pList;
  387. }
  388. bool CListUI::GetScrollSelect()
  389. {
  390. return m_bScrollSelect;
  391. }
  392. void CListUI::SetScrollSelect(bool bScrollSelect)
  393. {
  394. m_bScrollSelect = bScrollSelect;
  395. }
  396. int CListUI::GetCurSel() const
  397. {
  398. return m_iCurSel;
  399. }
  400. bool CListUI::SelectItem(int iIndex, bool bTakeFocus, bool bTriggerEvent)
  401. {
  402. if( iIndex == m_iCurSel ) return true;
  403. int iOldSel = m_iCurSel;
  404. // We should first unselect the currently selected item
  405. if( m_iCurSel >= 0 ) {
  406. CControlUI* pControl = GetItemAt(m_iCurSel);
  407. if( pControl != NULL) {
  408. IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(DUI_CTR_ILISTITEM));
  409. if( pListItem != NULL ) pListItem->Select(false, bTriggerEvent);
  410. }
  411. m_iCurSel = -1;
  412. }
  413. if( iIndex < 0 ) return false;
  414. CControlUI* pControl = GetItemAt(iIndex);
  415. if( pControl == NULL ) return false;
  416. if( !pControl->IsVisible() ) return false;
  417. if( !pControl->IsEnabled() ) return false;
  418. IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(DUI_CTR_ILISTITEM));
  419. if( pListItem == NULL ) return false;
  420. m_iCurSel = iIndex;
  421. if( !pListItem->Select(true, bTriggerEvent) ) {
  422. m_iCurSel = -1;
  423. return false;
  424. }
  425. EnsureVisible(m_iCurSel);
  426. if( bTakeFocus ) pControl->SetFocus();
  427. if( m_pManager != NULL && bTriggerEvent ) {
  428. m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMSELECT, m_iCurSel, iOldSel);
  429. }
  430. return true;
  431. }
  432. TListInfoUI* CListUI::GetListInfo()
  433. {
  434. return &m_ListInfo;
  435. }
  436. int CListUI::GetChildPadding() const
  437. {
  438. return m_pList->GetChildPadding();
  439. }
  440. void CListUI::SetChildPadding(int iPadding)
  441. {
  442. m_pList->SetChildPadding(iPadding);
  443. }
  444. UINT CListUI::GetItemFixedHeight()
  445. {
  446. return m_ListInfo.uFixedHeight;
  447. }
  448. void CListUI::SetItemFixedHeight(UINT nHeight)
  449. {
  450. m_ListInfo.uFixedHeight = nHeight;
  451. NeedUpdate();
  452. }
  453. int CListUI::GetItemFont(int index)
  454. {
  455. return m_ListInfo.nFont;
  456. }
  457. void CListUI::SetItemFont(int index)
  458. {
  459. m_ListInfo.nFont = index;
  460. NeedUpdate();
  461. }
  462. UINT CListUI::GetItemTextStyle()
  463. {
  464. return m_ListInfo.uTextStyle;
  465. }
  466. void CListUI::SetItemTextStyle(UINT uStyle)
  467. {
  468. m_ListInfo.uTextStyle = uStyle;
  469. NeedUpdate();
  470. }
  471. void CListUI::SetItemTextPadding(RECT rc)
  472. {
  473. m_ListInfo.rcTextPadding = rc;
  474. NeedUpdate();
  475. }
  476. RECT CListUI::GetItemTextPadding() const
  477. {
  478. return m_ListInfo.rcTextPadding;
  479. }
  480. void CListUI::SetItemTextColor(DWORD dwTextColor)
  481. {
  482. m_ListInfo.dwTextColor = dwTextColor;
  483. Invalidate();
  484. }
  485. void CListUI::SetItemBkColor(DWORD dwBkColor)
  486. {
  487. m_ListInfo.dwBkColor = dwBkColor;
  488. Invalidate();
  489. }
  490. void CListUI::SetItemBkImage(LPCTSTR pStrImage)
  491. {
  492. if( m_ListInfo.diBk.sDrawString == pStrImage && m_ListInfo.diBk.pImageInfo != NULL ) return;
  493. m_ListInfo.diBk.Clear();
  494. m_ListInfo.diBk.sDrawString = pStrImage;
  495. Invalidate();
  496. }
  497. bool CListUI::IsAlternateBk() const
  498. {
  499. return m_ListInfo.bAlternateBk;
  500. }
  501. void CListUI::SetAlternateBk(bool bAlternateBk)
  502. {
  503. m_ListInfo.bAlternateBk = bAlternateBk;
  504. Invalidate();
  505. }
  506. DWORD CListUI::GetItemTextColor() const
  507. {
  508. return m_ListInfo.dwTextColor;
  509. }
  510. DWORD CListUI::GetItemBkColor() const
  511. {
  512. return m_ListInfo.dwBkColor;
  513. }
  514. LPCTSTR CListUI::GetItemBkImage() const
  515. {
  516. return m_ListInfo.diBk.sDrawString;
  517. }
  518. void CListUI::SetSelectedItemTextColor(DWORD dwTextColor)
  519. {
  520. m_ListInfo.dwSelectedTextColor = dwTextColor;
  521. Invalidate();
  522. }
  523. void CListUI::SetSelectedItemBkColor(DWORD dwBkColor)
  524. {
  525. m_ListInfo.dwSelectedBkColor = dwBkColor;
  526. Invalidate();
  527. }
  528. void CListUI::SetSelectedItemImage(LPCTSTR pStrImage)
  529. {
  530. if( m_ListInfo.diSelected.sDrawString == pStrImage && m_ListInfo.diSelected.pImageInfo != NULL ) return;
  531. m_ListInfo.diSelected.Clear();
  532. m_ListInfo.diSelected.sDrawString = pStrImage;
  533. Invalidate();
  534. }
  535. DWORD CListUI::GetSelectedItemTextColor() const
  536. {
  537. return m_ListInfo.dwSelectedTextColor;
  538. }
  539. DWORD CListUI::GetSelectedItemBkColor() const
  540. {
  541. return m_ListInfo.dwSelectedBkColor;
  542. }
  543. LPCTSTR CListUI::GetSelectedItemImage() const
  544. {
  545. return m_ListInfo.diSelected.sDrawString;
  546. }
  547. void CListUI::SetHotItemTextColor(DWORD dwTextColor)
  548. {
  549. m_ListInfo.dwHotTextColor = dwTextColor;
  550. Invalidate();
  551. }
  552. void CListUI::SetHotItemBkColor(DWORD dwBkColor)
  553. {
  554. m_ListInfo.dwHotBkColor = dwBkColor;
  555. Invalidate();
  556. }
  557. void CListUI::SetHotItemImage(LPCTSTR pStrImage)
  558. {
  559. if( m_ListInfo.diHot.sDrawString == pStrImage && m_ListInfo.diHot.pImageInfo != NULL ) return;
  560. m_ListInfo.diHot.Clear();
  561. m_ListInfo.diHot.sDrawString = pStrImage;
  562. Invalidate();
  563. }
  564. DWORD CListUI::GetHotItemTextColor() const
  565. {
  566. return m_ListInfo.dwHotTextColor;
  567. }
  568. DWORD CListUI::GetHotItemBkColor() const
  569. {
  570. return m_ListInfo.dwHotBkColor;
  571. }
  572. LPCTSTR CListUI::GetHotItemImage() const
  573. {
  574. return m_ListInfo.diHot.sDrawString;
  575. }
  576. void CListUI::SetDisabledItemTextColor(DWORD dwTextColor)
  577. {
  578. m_ListInfo.dwDisabledTextColor = dwTextColor;
  579. Invalidate();
  580. }
  581. void CListUI::SetDisabledItemBkColor(DWORD dwBkColor)
  582. {
  583. m_ListInfo.dwDisabledBkColor = dwBkColor;
  584. Invalidate();
  585. }
  586. void CListUI::SetDisabledItemImage(LPCTSTR pStrImage)
  587. {
  588. if( m_ListInfo.diDisabled.sDrawString == pStrImage && m_ListInfo.diDisabled.pImageInfo != NULL ) return;
  589. m_ListInfo.diDisabled.Clear();
  590. m_ListInfo.diDisabled.sDrawString = pStrImage;
  591. Invalidate();
  592. }
  593. DWORD CListUI::GetDisabledItemTextColor() const
  594. {
  595. return m_ListInfo.dwDisabledTextColor;
  596. }
  597. DWORD CListUI::GetDisabledItemBkColor() const
  598. {
  599. return m_ListInfo.dwDisabledBkColor;
  600. }
  601. LPCTSTR CListUI::GetDisabledItemImage() const
  602. {
  603. return m_ListInfo.diDisabled.sDrawString;
  604. }
  605. int CListUI::GetItemHLineSize() const
  606. {
  607. return m_ListInfo.iHLineSize;
  608. }
  609. void CListUI::SetItemHLineSize(int iSize)
  610. {
  611. m_ListInfo.iHLineSize = iSize;
  612. Invalidate();
  613. }
  614. DWORD CListUI::GetItemHLineColor() const
  615. {
  616. return m_ListInfo.dwHLineColor;
  617. }
  618. void CListUI::SetItemHLineColor(DWORD dwLineColor)
  619. {
  620. m_ListInfo.dwHLineColor = dwLineColor;
  621. Invalidate();
  622. }
  623. int CListUI::GetItemVLineSize() const
  624. {
  625. return m_ListInfo.iVLineSize;
  626. }
  627. void CListUI::SetItemVLineSize(int iSize)
  628. {
  629. m_ListInfo.iVLineSize = iSize;
  630. Invalidate();
  631. }
  632. DWORD CListUI::GetItemVLineColor() const
  633. {
  634. return m_ListInfo.dwVLineColor;
  635. }
  636. void CListUI::SetItemVLineColor(DWORD dwLineColor)
  637. {
  638. m_ListInfo.dwVLineColor = dwLineColor;
  639. Invalidate();
  640. }
  641. bool CListUI::IsItemShowHtml()
  642. {
  643. return m_ListInfo.bShowHtml;
  644. }
  645. void CListUI::SetItemShowHtml(bool bShowHtml)
  646. {
  647. if( m_ListInfo.bShowHtml == bShowHtml ) return;
  648. m_ListInfo.bShowHtml = bShowHtml;
  649. NeedUpdate();
  650. }
  651. void CListUI::SetMultiExpanding(bool bMultiExpandable)
  652. {
  653. m_ListInfo.bMultiExpandable = bMultiExpandable;
  654. }
  655. bool CListUI::ExpandItem(int iIndex, bool bExpand /*= true*/)
  656. {
  657. if( m_iExpandedItem >= 0 && !m_ListInfo.bMultiExpandable) {
  658. CControlUI* pControl = GetItemAt(m_iExpandedItem);
  659. if( pControl != NULL ) {
  660. IListItemUI* pItem = static_cast<IListItemUI*>(pControl->GetInterface(DUI_CTR_ILISTITEM));
  661. if( pItem != NULL ) pItem->Expand(false);
  662. }
  663. m_iExpandedItem = -1;
  664. }
  665. if( bExpand ) {
  666. CControlUI* pControl = GetItemAt(iIndex);
  667. if( pControl == NULL ) return false;
  668. if( !pControl->IsVisible() ) return false;
  669. IListItemUI* pItem = static_cast<IListItemUI*>(pControl->GetInterface(DUI_CTR_ILISTITEM));
  670. if( pItem == NULL ) return false;
  671. m_iExpandedItem = iIndex;
  672. if( !pItem->Expand(true) ) {
  673. m_iExpandedItem = -1;
  674. return false;
  675. }
  676. }
  677. NeedUpdate();
  678. return true;
  679. }
  680. int CListUI::GetExpandedItem() const
  681. {
  682. return m_iExpandedItem;
  683. }
  684. void CListUI::EnsureVisible(int iIndex)
  685. {
  686. if( m_iCurSel < 0 ) return;
  687. RECT rcItem = m_pList->GetItemAt(iIndex)->GetPos();
  688. RECT rcList = m_pList->GetPos();
  689. RECT rcListInset = m_pList->GetInset();
  690. rcList.left += rcListInset.left;
  691. rcList.top += rcListInset.top;
  692. rcList.right -= rcListInset.right;
  693. rcList.bottom -= rcListInset.bottom;
  694. CScrollBarUI* pHorizontalScrollBar = m_pList->GetHorizontalScrollBar();
  695. if( pHorizontalScrollBar && pHorizontalScrollBar->IsVisible() ) rcList.bottom -= pHorizontalScrollBar->GetFixedHeight();
  696. int iPos = m_pList->GetScrollPos().cy;
  697. if( rcItem.top >= rcList.top && rcItem.bottom < rcList.bottom ) return;
  698. int dx = 0;
  699. if( rcItem.top < rcList.top ) dx = rcItem.top - rcList.top;
  700. if( rcItem.bottom > rcList.bottom ) dx = rcItem.bottom - rcList.bottom;
  701. Scroll(0, dx);
  702. }
  703. void CListUI::Scroll(int dx, int dy)
  704. {
  705. if( dx == 0 && dy == 0 ) return;
  706. SIZE sz = m_pList->GetScrollPos();
  707. m_pList->SetScrollPos(CDuiSize(sz.cx + dx, sz.cy + dy));
  708. }
  709. void CListUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
  710. {
  711. if( _tcscmp(pstrName, _T("header")) == 0 ) GetHeader()->SetVisible(_tcscmp(pstrValue, _T("hidden")) != 0);
  712. else if( _tcscmp(pstrName, _T("headerbkimage")) == 0 ) GetHeader()->SetBkImage(pstrValue);
  713. else if( _tcscmp(pstrName, _T("scrollselect")) == 0 ) SetScrollSelect(_tcscmp(pstrValue, _T("true")) == 0);
  714. else if( _tcscmp(pstrName, _T("multiexpanding")) == 0 ) SetMultiExpanding(_tcscmp(pstrValue, _T("true")) == 0);
  715. else if( _tcscmp(pstrName, _T("itemheight")) == 0 ) m_ListInfo.uFixedHeight = _ttoi(pstrValue);
  716. else if( _tcscmp(pstrName, _T("itemfont")) == 0 ) m_ListInfo.nFont = _ttoi(pstrValue);
  717. else if( _tcscmp(pstrName, _T("itemalign")) == 0 ) {
  718. if( _tcsstr(pstrValue, _T("left")) != NULL ) {
  719. m_ListInfo.uTextStyle &= ~(DT_CENTER | DT_RIGHT);
  720. m_ListInfo.uTextStyle |= DT_LEFT;
  721. }
  722. if( _tcsstr(pstrValue, _T("center")) != NULL ) {
  723. m_ListInfo.uTextStyle &= ~(DT_LEFT | DT_RIGHT);
  724. m_ListInfo.uTextStyle |= DT_CENTER;
  725. }
  726. if( _tcsstr(pstrValue, _T("right")) != NULL ) {
  727. m_ListInfo.uTextStyle &= ~(DT_LEFT | DT_CENTER);
  728. m_ListInfo.uTextStyle |= DT_RIGHT;
  729. }
  730. }
  731. else if (_tcscmp(pstrName, _T("itemvalign")) == 0)
  732. {
  733. if (_tcsstr(pstrValue, _T("top")) != NULL) {
  734. m_ListInfo.uTextStyle &= ~(DT_BOTTOM | DT_VCENTER);
  735. m_ListInfo.uTextStyle |= DT_TOP;
  736. }
  737. if (_tcsstr(pstrValue, _T("vcenter")) != NULL) {
  738. m_ListInfo.uTextStyle &= ~(DT_TOP | DT_BOTTOM);
  739. m_ListInfo.uTextStyle |= DT_VCENTER;
  740. }
  741. if (_tcsstr(pstrValue, _T("bottom")) != NULL) {
  742. m_ListInfo.uTextStyle &= ~(DT_TOP | DT_VCENTER);
  743. m_ListInfo.uTextStyle |= DT_BOTTOM;
  744. }
  745. }
  746. else if( _tcscmp(pstrName, _T("itemendellipsis")) == 0 ) {
  747. if( _tcscmp(pstrValue, _T("true")) == 0 ) m_ListInfo.uTextStyle |= DT_END_ELLIPSIS;
  748. else m_ListInfo.uTextStyle &= ~DT_END_ELLIPSIS;
  749. }
  750. else if( _tcscmp(pstrName, _T("itemmultiline")) == 0 ) {
  751. if (_tcscmp(pstrValue, _T("true")) == 0) {
  752. m_ListInfo.uTextStyle &= ~DT_SINGLELINE;
  753. m_ListInfo.uTextStyle |= DT_WORDBREAK;
  754. }
  755. else m_ListInfo.uTextStyle |= DT_SINGLELINE;
  756. }
  757. else if( _tcscmp(pstrName, _T("itemtextpadding")) == 0 ) {
  758. RECT rcTextPadding = { 0 };
  759. LPTSTR pstr = NULL;
  760. rcTextPadding.left = _tcstol(pstrValue, &pstr, 10); ASSERT(pstr);
  761. rcTextPadding.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
  762. rcTextPadding.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
  763. rcTextPadding.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
  764. SetItemTextPadding(rcTextPadding);
  765. }
  766. else if( _tcscmp(pstrName, _T("itemtextcolor")) == 0 ) {
  767. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  768. LPTSTR pstr = NULL;
  769. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  770. SetItemTextColor(clrColor);
  771. }
  772. else if( _tcscmp(pstrName, _T("itembkcolor")) == 0 ) {
  773. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  774. LPTSTR pstr = NULL;
  775. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  776. SetItemBkColor(clrColor);
  777. }
  778. else if( _tcscmp(pstrName, _T("itembkimage")) == 0 ) SetItemBkImage(pstrValue);
  779. else if( _tcscmp(pstrName, _T("itemaltbk")) == 0 ) SetAlternateBk(_tcscmp(pstrValue, _T("true")) == 0);
  780. else if( _tcscmp(pstrName, _T("itemselectedtextcolor")) == 0 ) {
  781. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  782. LPTSTR pstr = NULL;
  783. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  784. SetSelectedItemTextColor(clrColor);
  785. }
  786. else if( _tcscmp(pstrName, _T("itemselectedbkcolor")) == 0 ) {
  787. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  788. LPTSTR pstr = NULL;
  789. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  790. SetSelectedItemBkColor(clrColor);
  791. }
  792. else if( _tcscmp(pstrName, _T("itemselectedimage")) == 0 ) SetSelectedItemImage(pstrValue);
  793. else if( _tcscmp(pstrName, _T("itemhottextcolor")) == 0 ) {
  794. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  795. LPTSTR pstr = NULL;
  796. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  797. SetHotItemTextColor(clrColor);
  798. }
  799. else if( _tcscmp(pstrName, _T("itemhotbkcolor")) == 0 ) {
  800. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  801. LPTSTR pstr = NULL;
  802. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  803. SetHotItemBkColor(clrColor);
  804. }
  805. else if( _tcscmp(pstrName, _T("itemhotimage")) == 0 ) SetHotItemImage(pstrValue);
  806. else if( _tcscmp(pstrName, _T("itemdisabledtextcolor")) == 0 ) {
  807. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  808. LPTSTR pstr = NULL;
  809. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  810. SetDisabledItemTextColor(clrColor);
  811. }
  812. else if( _tcscmp(pstrName, _T("itemdisabledbkcolor")) == 0 ) {
  813. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  814. LPTSTR pstr = NULL;
  815. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  816. SetDisabledItemBkColor(clrColor);
  817. }
  818. else if( _tcscmp(pstrName, _T("itemdisabledimage")) == 0 ) SetDisabledItemImage(pstrValue);
  819. else if( _tcscmp(pstrName, _T("itemvlinesize")) == 0 ) {
  820. SetItemVLineSize(_ttoi(pstrValue));
  821. }
  822. else if( _tcscmp(pstrName, _T("itemvlinecolor")) == 0 ) {
  823. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  824. LPTSTR pstr = NULL;
  825. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  826. SetItemVLineColor(clrColor);
  827. }
  828. else if( _tcscmp(pstrName, _T("itemhlinesize")) == 0 ) {
  829. SetItemHLineSize(_ttoi(pstrValue));
  830. }
  831. else if( _tcscmp(pstrName, _T("itemhlinecolor")) == 0 ) {
  832. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  833. LPTSTR pstr = NULL;
  834. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  835. SetItemHLineColor(clrColor);
  836. }
  837. else if( _tcscmp(pstrName, _T("itemshowhtml")) == 0 ) SetItemShowHtml(_tcscmp(pstrValue, _T("true")) == 0);
  838. else CVerticalLayoutUI::SetAttribute(pstrName, pstrValue);
  839. }
  840. IListCallbackUI* CListUI::GetTextCallback() const
  841. {
  842. return m_pCallback;
  843. }
  844. void CListUI::SetTextCallback(IListCallbackUI* pCallback)
  845. {
  846. m_pCallback = pCallback;
  847. }
  848. SIZE CListUI::GetScrollPos() const
  849. {
  850. return m_pList->GetScrollPos();
  851. }
  852. SIZE CListUI::GetScrollRange() const
  853. {
  854. return m_pList->GetScrollRange();
  855. }
  856. void CListUI::SetScrollPos(SIZE szPos)
  857. {
  858. m_pList->SetScrollPos(szPos);
  859. }
  860. void CListUI::LineUp()
  861. {
  862. m_pList->LineUp();
  863. }
  864. void CListUI::LineDown()
  865. {
  866. m_pList->LineDown();
  867. }
  868. void CListUI::PageUp()
  869. {
  870. m_pList->PageUp();
  871. }
  872. void CListUI::PageDown()
  873. {
  874. m_pList->PageDown();
  875. }
  876. void CListUI::HomeUp()
  877. {
  878. m_pList->HomeUp();
  879. }
  880. void CListUI::EndDown()
  881. {
  882. m_pList->EndDown();
  883. }
  884. void CListUI::LineLeft()
  885. {
  886. m_pList->LineLeft();
  887. }
  888. void CListUI::LineRight()
  889. {
  890. m_pList->LineRight();
  891. }
  892. void CListUI::PageLeft()
  893. {
  894. m_pList->PageLeft();
  895. }
  896. void CListUI::PageRight()
  897. {
  898. m_pList->PageRight();
  899. }
  900. void CListUI::HomeLeft()
  901. {
  902. m_pList->HomeLeft();
  903. }
  904. void CListUI::EndRight()
  905. {
  906. m_pList->EndRight();
  907. }
  908. void CListUI::EnableScrollBar(bool bEnableVertical, bool bEnableHorizontal)
  909. {
  910. m_pList->EnableScrollBar(bEnableVertical, bEnableHorizontal);
  911. }
  912. CScrollBarUI* CListUI::GetVerticalScrollBar() const
  913. {
  914. return m_pList->GetVerticalScrollBar();
  915. }
  916. CScrollBarUI* CListUI::GetHorizontalScrollBar() const
  917. {
  918. return m_pList->GetHorizontalScrollBar();
  919. }
  920. bool CListUI::SortItems(PULVCompareFunc pfnCompare, UINT_PTR dwData)
  921. {
  922. if (!m_pList) return false;
  923. int iCurSel = m_iCurSel;
  924. bool bResult = m_pList->SortItems(pfnCompare, dwData, iCurSel);
  925. if (bResult) {
  926. m_iCurSel = iCurSel;
  927. EnsureVisible(m_iCurSel);
  928. NeedUpdate();
  929. }
  930. return bResult;
  931. }
  932. /////////////////////////////////////////////////////////////////////////////////////
  933. //
  934. //
  935. CListBodyUI::CListBodyUI(CListUI* pOwner) : m_pOwner(pOwner)
  936. {
  937. ASSERT(m_pOwner);
  938. }
  939. bool CListBodyUI::SortItems(PULVCompareFunc pfnCompare, UINT_PTR dwData, int& iCurSel)
  940. {
  941. if (!pfnCompare) return false;
  942. m_pCompareFunc = pfnCompare;
  943. m_compareData = dwData;
  944. CControlUI *pCurSelControl = GetItemAt(iCurSel);
  945. CControlUI **pData = (CControlUI **)m_items.GetData();
  946. qsort_s(m_items.GetData(), m_items.GetSize(), sizeof(CControlUI*), CListBodyUI::ItemComareFunc, this);
  947. if (pCurSelControl) iCurSel = GetItemIndex(pCurSelControl);
  948. IListItemUI *pItem = NULL;
  949. for (int i = 0; i < m_items.GetSize(); ++i)
  950. {
  951. pItem = (IListItemUI*)(static_cast<CControlUI*>(m_items[i])->GetInterface(TEXT("ListItem")));
  952. if (pItem)
  953. {
  954. pItem->SetIndex(i);
  955. }
  956. }
  957. return true;
  958. }
  959. int __cdecl CListBodyUI::ItemComareFunc(void *pvlocale, const void *item1, const void *item2)
  960. {
  961. CListBodyUI *pThis = (CListBodyUI*)pvlocale;
  962. if (!pThis || !item1 || !item2)
  963. return 0;
  964. return pThis->ItemComareFunc(item1, item2);
  965. }
  966. int __cdecl CListBodyUI::ItemComareFunc(const void *item1, const void *item2)
  967. {
  968. CControlUI *pControl1 = *(CControlUI**)item1;
  969. CControlUI *pControl2 = *(CControlUI**)item2;
  970. return m_pCompareFunc((UINT_PTR)pControl1, (UINT_PTR)pControl2, m_compareData);
  971. }
  972. void CListBodyUI::SetScrollPos(SIZE szPos)
  973. {
  974. int cx = 0;
  975. int cy = 0;
  976. if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {
  977. int iLastScrollPos = m_pVerticalScrollBar->GetScrollPos();
  978. m_pVerticalScrollBar->SetScrollPos(szPos.cy);
  979. cy = m_pVerticalScrollBar->GetScrollPos() - iLastScrollPos;
  980. }
  981. if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) {
  982. int iLastScrollPos = m_pHorizontalScrollBar->GetScrollPos();
  983. m_pHorizontalScrollBar->SetScrollPos(szPos.cx);
  984. cx = m_pHorizontalScrollBar->GetScrollPos() - iLastScrollPos;
  985. }
  986. if( cx == 0 && cy == 0 ) return;
  987. for( int it2 = 0; it2 < m_items.GetSize(); it2++ ) {
  988. CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
  989. if( !pControl->IsVisible() ) continue;
  990. if( pControl->IsFloat() ) continue;
  991. pControl->Move(CDuiSize(-cx, -cy), false);
  992. }
  993. Invalidate();
  994. if( cx != 0 && m_pOwner ) {
  995. CListHeaderUI* pHeader = m_pOwner->GetHeader();
  996. if( pHeader == NULL ) return;
  997. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  998. pInfo->nColumns = MIN(pHeader->GetCount(), UILIST_MAX_COLUMNS);
  999. for( int i = 0; i < pInfo->nColumns; i++ ) {
  1000. CControlUI* pControl = static_cast<CControlUI*>(pHeader->GetItemAt(i));
  1001. if( !pControl->IsVisible() ) continue;
  1002. if( pControl->IsFloat() ) continue;
  1003. pControl->Move(CDuiSize(-cx, -cy), false);
  1004. pInfo->rcColumn[i] = pControl->GetPos();
  1005. }
  1006. pHeader->Invalidate();
  1007. }
  1008. }
  1009. void CListBodyUI::SetPos(RECT rc, bool bNeedInvalidate)
  1010. {
  1011. CControlUI::SetPos(rc, bNeedInvalidate);
  1012. rc = m_rcItem;
  1013. // Adjust for inset
  1014. rc.left += m_rcInset.left;
  1015. rc.top += m_rcInset.top;
  1016. rc.right -= m_rcInset.right;
  1017. rc.bottom -= m_rcInset.bottom;
  1018. if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) rc.right -= m_pVerticalScrollBar->GetFixedWidth();
  1019. if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
  1020. // Determine the minimum size
  1021. SIZE szAvailable = { rc.right - rc.left, rc.bottom - rc.top };
  1022. if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() )
  1023. szAvailable.cx += m_pHorizontalScrollBar->GetScrollRange();
  1024. int iChildPadding = m_iChildPadding;
  1025. TListInfoUI* pInfo = NULL;
  1026. if( m_pOwner ) {
  1027. pInfo = m_pOwner->GetListInfo();
  1028. if( pInfo != NULL ) {
  1029. iChildPadding += pInfo->iHLineSize;
  1030. if (pInfo->nColumns > 0) {
  1031. szAvailable.cx = pInfo->rcColumn[pInfo->nColumns - 1].right - pInfo->rcColumn[0].left;
  1032. }
  1033. }
  1034. }
  1035. int cxNeeded = 0;
  1036. int cyFixed = 0;
  1037. int nEstimateNum = 0;
  1038. SIZE szControlAvailable;
  1039. int iControlMaxWidth = 0;
  1040. int iControlMaxHeight = 0;
  1041. for( int it1 = 0; it1 < m_items.GetSize(); it1++ ) {
  1042. CControlUI* pControl = static_cast<CControlUI*>(m_items[it1]);
  1043. if( !pControl->IsVisible() ) continue;
  1044. if( pControl->IsFloat() ) continue;
  1045. szControlAvailable = szAvailable;
  1046. RECT rcPadding = pControl->GetPadding();
  1047. szControlAvailable.cx -= rcPadding.left + rcPadding.right;
  1048. iControlMaxWidth = pControl->GetFixedWidth();
  1049. iControlMaxHeight = pControl->GetFixedHeight();
  1050. if (iControlMaxWidth <= 0) iControlMaxWidth = pControl->GetMaxWidth();
  1051. if (iControlMaxHeight <= 0) iControlMaxHeight = pControl->GetMaxHeight();
  1052. if (szControlAvailable.cx > iControlMaxWidth) szControlAvailable.cx = iControlMaxWidth;
  1053. if (szControlAvailable.cy > iControlMaxHeight) szControlAvailable.cy = iControlMaxHeight;
  1054. SIZE sz = pControl->EstimateSize(szAvailable);
  1055. if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
  1056. if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();
  1057. cyFixed += sz.cy + pControl->GetPadding().top + pControl->GetPadding().bottom;
  1058. sz.cx = MAX(sz.cx, 0);
  1059. if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth();
  1060. if( sz.cx > pControl->GetMaxWidth() ) sz.cx = pControl->GetMaxWidth();
  1061. cxNeeded = MAX(cxNeeded, sz.cx);
  1062. nEstimateNum++;
  1063. }
  1064. cyFixed += (nEstimateNum - 1) * iChildPadding;
  1065. if( m_pOwner ) {
  1066. CListHeaderUI* pHeader = m_pOwner->GetHeader();
  1067. if( pHeader != NULL && pHeader->GetCount() > 0 ) {
  1068. cxNeeded = MAX(0, pHeader->EstimateSize(CDuiSize(rc.right - rc.left, rc.bottom - rc.top)).cx);
  1069. }
  1070. }
  1071. // Place elements
  1072. int cyNeeded = 0;
  1073. // Position the elements
  1074. SIZE szRemaining = szAvailable;
  1075. int iPosY = rc.top;
  1076. if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) {
  1077. iPosY -= m_pVerticalScrollBar->GetScrollPos();
  1078. }
  1079. int iPosX = rc.left;
  1080. if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) {
  1081. iPosX -= m_pHorizontalScrollBar->GetScrollPos();
  1082. }
  1083. int iAdjustable = 0;
  1084. for( int it2 = 0; it2 < m_items.GetSize(); it2++ ) {
  1085. CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
  1086. if( !pControl->IsVisible() ) continue;
  1087. if( pControl->IsFloat() ) {
  1088. SetFloatPos(it2);
  1089. continue;
  1090. }
  1091. RECT rcPadding = pControl->GetPadding();
  1092. szRemaining.cy -= rcPadding.top;
  1093. szControlAvailable = szRemaining;
  1094. szControlAvailable.cx -= rcPadding.left + rcPadding.right;
  1095. iControlMaxWidth = pControl->GetFixedWidth();
  1096. iControlMaxHeight = pControl->GetFixedHeight();
  1097. if (iControlMaxWidth <= 0) iControlMaxWidth = pControl->GetMaxWidth();
  1098. if (iControlMaxHeight <= 0) iControlMaxHeight = pControl->GetMaxHeight();
  1099. if (szControlAvailable.cx > iControlMaxWidth) szControlAvailable.cx = iControlMaxWidth;
  1100. if (szControlAvailable.cy > iControlMaxHeight) szControlAvailable.cy = iControlMaxHeight;
  1101. SIZE sz = pControl->EstimateSize(szControlAvailable);
  1102. if( sz.cy < pControl->GetMinHeight() ) sz.cy = pControl->GetMinHeight();
  1103. if( sz.cy > pControl->GetMaxHeight() ) sz.cy = pControl->GetMaxHeight();
  1104. sz.cx = pControl->GetMaxWidth();
  1105. if( sz.cx == 0 ) sz.cx = szAvailable.cx - rcPadding.left - rcPadding.right;
  1106. if( sz.cx < 0 ) sz.cx = 0;
  1107. if( sz.cx > szControlAvailable.cx ) sz.cx = szControlAvailable.cx;
  1108. if( sz.cx < pControl->GetMinWidth() ) sz.cx = pControl->GetMinWidth();
  1109. RECT rcCtrl = { iPosX + rcPadding.left, iPosY + rcPadding.top, iPosX + rcPadding.left + sz.cx, iPosY + sz.cy + rcPadding.top + rcPadding.bottom };
  1110. pControl->SetPos(rcCtrl, false);
  1111. iPosY += sz.cy + iChildPadding + rcPadding.top + rcPadding.bottom;
  1112. cyNeeded += sz.cy + rcPadding.top + rcPadding.bottom;
  1113. szRemaining.cy -= sz.cy + iChildPadding + rcPadding.bottom;
  1114. }
  1115. cyNeeded += (nEstimateNum - 1) * iChildPadding;
  1116. // Process the scrollbar
  1117. ProcessScrollBar(rc, cxNeeded, cyNeeded);
  1118. }
  1119. void CListBodyUI::DoEvent(TEventUI& event)
  1120. {
  1121. if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {
  1122. if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
  1123. else CControlUI::DoEvent(event);
  1124. return;
  1125. }
  1126. if( m_pOwner != NULL ) {
  1127. if (event.Type == UIEVENT_SCROLLWHEEL) {
  1128. if (m_pHorizontalScrollBar != NULL && m_pHorizontalScrollBar->IsVisible() && m_pHorizontalScrollBar->IsEnabled()) {
  1129. RECT rcHorizontalScrollBar = m_pHorizontalScrollBar->GetPos();
  1130. if( ::PtInRect(&rcHorizontalScrollBar, event.ptMouse) )
  1131. {
  1132. switch( LOWORD(event.wParam) ) {
  1133. case SB_LINEUP:
  1134. m_pOwner->LineLeft();
  1135. return;
  1136. case SB_LINEDOWN:
  1137. m_pOwner->LineRight();
  1138. return;
  1139. }
  1140. }
  1141. }
  1142. }
  1143. m_pOwner->DoEvent(event); }
  1144. else {
  1145. CControlUI::DoEvent(event);
  1146. }
  1147. }
  1148. bool CListBodyUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
  1149. {
  1150. RECT rcTemp = { 0 };
  1151. if( !::IntersectRect(&rcTemp, &rcPaint, &m_rcItem) ) return true;
  1152. TListInfoUI* pListInfo = NULL;
  1153. if( m_pOwner ) pListInfo = m_pOwner->GetListInfo();
  1154. CRenderClip clip;
  1155. CRenderClip::GenerateClip(hDC, rcTemp, clip);
  1156. CControlUI::DoPaint(hDC, rcPaint, pStopControl);
  1157. if( m_items.GetSize() > 0 ) {
  1158. RECT rc = m_rcItem;
  1159. rc.left += m_rcInset.left;
  1160. rc.top += m_rcInset.top;
  1161. rc.right -= m_rcInset.right;
  1162. rc.bottom -= m_rcInset.bottom;
  1163. if( m_pVerticalScrollBar && m_pVerticalScrollBar->IsVisible() ) rc.right -= m_pVerticalScrollBar->GetFixedWidth();
  1164. if( m_pHorizontalScrollBar && m_pHorizontalScrollBar->IsVisible() ) rc.bottom -= m_pHorizontalScrollBar->GetFixedHeight();
  1165. if( !::IntersectRect(&rcTemp, &rcPaint, &rc) ) {
  1166. for( int it = 0; it < m_items.GetSize(); it++ ) {
  1167. CControlUI* pControl = static_cast<CControlUI*>(m_items[it]);
  1168. if( pControl == pStopControl ) return false;
  1169. if( !pControl->IsVisible() ) continue;
  1170. if( !::IntersectRect(&rcTemp, &rcPaint, &pControl->GetPos()) ) continue;
  1171. if( pControl->IsFloat() ) {
  1172. if( !::IntersectRect(&rcTemp, &m_rcItem, &pControl->GetPos()) ) continue;
  1173. if( !pControl->Paint(hDC, rcPaint, pStopControl) ) return false;
  1174. }
  1175. }
  1176. }
  1177. else {
  1178. int iDrawIndex = 0;
  1179. CRenderClip childClip;
  1180. CRenderClip::GenerateClip(hDC, rcTemp, childClip);
  1181. for( int it = 0; it < m_items.GetSize(); it++ ) {
  1182. CControlUI* pControl = static_cast<CControlUI*>(m_items[it]);
  1183. if( pControl == pStopControl ) return false;
  1184. if( !pControl->IsVisible() ) continue;
  1185. if( !pControl->IsFloat() ) {
  1186. IListItemUI* pListItem = static_cast<IListItemUI*>(pControl->GetInterface(DUI_CTR_ILISTITEM));
  1187. if( pListItem != NULL ) {
  1188. pListItem->SetDrawIndex(iDrawIndex);
  1189. iDrawIndex += 1;
  1190. }
  1191. if (pListInfo && pListInfo->iHLineSize > 0) {
  1192. // 因为没有为最后一个预留分割条长度,如果list铺满,最后一条不会显示
  1193. RECT rcPadding = pControl->GetPadding();
  1194. const RECT& rcPos = pControl->GetPos();
  1195. RECT rcBottomLine = { rcPos.left, rcPos.bottom + rcPadding.bottom, rcPos.right, rcPos.bottom + rcPadding.bottom + pListInfo->iHLineSize };
  1196. if( ::IntersectRect(&rcTemp, &rcPaint, &rcBottomLine) ) {
  1197. rcBottomLine.top += pListInfo->iHLineSize / 2;
  1198. rcBottomLine.bottom = rcBottomLine.top;
  1199. CRenderEngine::DrawLine(hDC, rcBottomLine, pListInfo->iHLineSize, GetAdjustColor(pListInfo->dwHLineColor));
  1200. }
  1201. }
  1202. }
  1203. if( !::IntersectRect(&rcTemp, &rcPaint, &pControl->GetPos()) ) continue;
  1204. if( pControl->IsFloat() ) {
  1205. if( !::IntersectRect(&rcTemp, &m_rcItem, &pControl->GetPos()) ) continue;
  1206. CRenderClip::UseOldClipBegin(hDC, childClip);
  1207. if( !pControl->Paint(hDC, rcPaint, pStopControl) ) return false;
  1208. CRenderClip::UseOldClipEnd(hDC, childClip);
  1209. }
  1210. else {
  1211. if( !::IntersectRect(&rcTemp, &rc, &pControl->GetPos()) ) continue;
  1212. if( !pControl->Paint(hDC, rcPaint, pStopControl) ) return false;
  1213. }
  1214. }
  1215. }
  1216. }
  1217. if( m_pVerticalScrollBar != NULL ) {
  1218. if( m_pVerticalScrollBar == pStopControl ) return false;
  1219. if (m_pVerticalScrollBar->IsVisible()) {
  1220. if( ::IntersectRect(&rcTemp, &rcPaint, &m_pVerticalScrollBar->GetPos()) ) {
  1221. if( !m_pVerticalScrollBar->Paint(hDC, rcPaint, pStopControl) ) return false;
  1222. }
  1223. }
  1224. }
  1225. if( m_pHorizontalScrollBar != NULL ) {
  1226. if( m_pHorizontalScrollBar == pStopControl ) return false;
  1227. if (m_pHorizontalScrollBar->IsVisible()) {
  1228. if( ::IntersectRect(&rcTemp, &rcPaint, &m_pHorizontalScrollBar->GetPos()) ) {
  1229. if( !m_pHorizontalScrollBar->Paint(hDC, rcPaint, pStopControl) ) return false;
  1230. }
  1231. }
  1232. }
  1233. return true;
  1234. }
  1235. /////////////////////////////////////////////////////////////////////////////////////
  1236. //
  1237. //
  1238. CListHeaderUI::CListHeaderUI()
  1239. {
  1240. }
  1241. LPCTSTR CListHeaderUI::GetClass() const
  1242. {
  1243. return DUI_CTR_LISTHEADER;
  1244. }
  1245. LPVOID CListHeaderUI::GetInterface(LPCTSTR pstrName)
  1246. {
  1247. if( _tcscmp(pstrName, DUI_CTR_LISTHEADER) == 0 ) return this;
  1248. return CHorizontalLayoutUI::GetInterface(pstrName);
  1249. }
  1250. SIZE CListHeaderUI::EstimateSize(SIZE szAvailable)
  1251. {
  1252. SIZE cXY = {0, m_cxyFixed.cy};
  1253. if( cXY.cy == 0 && m_pManager != NULL ) {
  1254. for( int it = 0; it < m_items.GetSize(); it++ ) {
  1255. cXY.cy = MAX(cXY.cy,static_cast<CControlUI*>(m_items[it])->EstimateSize(szAvailable).cy);
  1256. }
  1257. int nMin = m_pManager->GetDefaultFontInfo()->tm.tmHeight + 8;
  1258. cXY.cy = MAX(cXY.cy,nMin);
  1259. }
  1260. for( int it = 0; it < m_items.GetSize(); it++ ) {
  1261. cXY.cx += static_cast<CControlUI*>(m_items[it])->EstimateSize(szAvailable).cx;
  1262. }
  1263. return cXY;
  1264. }
  1265. /////////////////////////////////////////////////////////////////////////////////////
  1266. //
  1267. //
  1268. CListHeaderItemUI::CListHeaderItemUI() : m_bDragable(true), m_uButtonState(0), m_iSepWidth(4),
  1269. m_uTextStyle(DT_CENTER | DT_VCENTER | DT_SINGLELINE), m_dwTextColor(0), m_dwSepColor(0),
  1270. m_iFont(-1), m_bShowHtml(false)
  1271. {
  1272. SetTextPadding(CDuiRect(2, 0, 2, 0));
  1273. ptLastMouse.x = ptLastMouse.y = 0;
  1274. SetMinWidth(16);
  1275. }
  1276. LPCTSTR CListHeaderItemUI::GetClass() const
  1277. {
  1278. return DUI_CTR_LISTHEADERITEM;
  1279. }
  1280. LPVOID CListHeaderItemUI::GetInterface(LPCTSTR pstrName)
  1281. {
  1282. if( _tcscmp(pstrName, DUI_CTR_LISTHEADERITEM) == 0 ) return this;
  1283. return CControlUI::GetInterface(pstrName);
  1284. }
  1285. UINT CListHeaderItemUI::GetControlFlags() const
  1286. {
  1287. if( IsEnabled() && m_iSepWidth != 0 ) return UIFLAG_SETCURSOR;
  1288. else return 0;
  1289. }
  1290. void CListHeaderItemUI::SetEnabled(bool bEnable)
  1291. {
  1292. CControlUI::SetEnabled(bEnable);
  1293. if( !IsEnabled() ) {
  1294. m_uButtonState = 0;
  1295. }
  1296. }
  1297. bool CListHeaderItemUI::IsDragable() const
  1298. {
  1299. return m_bDragable;
  1300. }
  1301. void CListHeaderItemUI::SetDragable(bool bDragable)
  1302. {
  1303. m_bDragable = bDragable;
  1304. if ( !m_bDragable ) m_uButtonState &= ~UISTATE_CAPTURED;
  1305. }
  1306. DWORD CListHeaderItemUI::GetSepWidth() const
  1307. {
  1308. return m_iSepWidth;
  1309. }
  1310. void CListHeaderItemUI::SetSepWidth(int iWidth)
  1311. {
  1312. m_iSepWidth = iWidth;
  1313. }
  1314. DWORD CListHeaderItemUI::GetTextStyle() const
  1315. {
  1316. return m_uTextStyle;
  1317. }
  1318. void CListHeaderItemUI::SetTextStyle(UINT uStyle)
  1319. {
  1320. m_uTextStyle = uStyle;
  1321. Invalidate();
  1322. }
  1323. DWORD CListHeaderItemUI::GetTextColor() const
  1324. {
  1325. return m_dwTextColor;
  1326. }
  1327. void CListHeaderItemUI::SetTextColor(DWORD dwTextColor)
  1328. {
  1329. m_dwTextColor = dwTextColor;
  1330. Invalidate();
  1331. }
  1332. DWORD CListHeaderItemUI::GetSepColor() const
  1333. {
  1334. return m_dwSepColor;
  1335. }
  1336. void CListHeaderItemUI::SetSepColor(DWORD dwSepColor)
  1337. {
  1338. m_dwSepColor = dwSepColor;
  1339. Invalidate();
  1340. }
  1341. RECT CListHeaderItemUI::GetTextPadding() const
  1342. {
  1343. return m_rcTextPadding;
  1344. }
  1345. void CListHeaderItemUI::SetTextPadding(RECT rc)
  1346. {
  1347. m_rcTextPadding = rc;
  1348. Invalidate();
  1349. }
  1350. void CListHeaderItemUI::SetFont(int index)
  1351. {
  1352. m_iFont = index;
  1353. }
  1354. bool CListHeaderItemUI::IsShowHtml()
  1355. {
  1356. return m_bShowHtml;
  1357. }
  1358. void CListHeaderItemUI::SetShowHtml(bool bShowHtml)
  1359. {
  1360. if( m_bShowHtml == bShowHtml ) return;
  1361. m_bShowHtml = bShowHtml;
  1362. Invalidate();
  1363. }
  1364. LPCTSTR CListHeaderItemUI::GetNormalImage() const
  1365. {
  1366. return m_diNormal.sDrawString;
  1367. }
  1368. void CListHeaderItemUI::SetNormalImage(LPCTSTR pStrImage)
  1369. {
  1370. if( m_diNormal.sDrawString == pStrImage && m_diNormal.pImageInfo != NULL ) return;
  1371. m_diNormal.Clear();
  1372. m_diNormal.sDrawString = pStrImage;
  1373. Invalidate();
  1374. }
  1375. LPCTSTR CListHeaderItemUI::GetHotImage() const
  1376. {
  1377. return m_diHot.sDrawString;
  1378. }
  1379. void CListHeaderItemUI::SetHotImage(LPCTSTR pStrImage)
  1380. {
  1381. if( m_diHot.sDrawString == pStrImage && m_diHot.pImageInfo != NULL ) return;
  1382. m_diHot.Clear();
  1383. m_diHot.sDrawString = pStrImage;
  1384. Invalidate();
  1385. }
  1386. LPCTSTR CListHeaderItemUI::GetPushedImage() const
  1387. {
  1388. return m_diPushed.sDrawString;
  1389. }
  1390. void CListHeaderItemUI::SetPushedImage(LPCTSTR pStrImage)
  1391. {
  1392. if( m_diPushed.sDrawString == pStrImage && m_diPushed.pImageInfo != NULL ) return;
  1393. m_diPushed.Clear();
  1394. m_diPushed.sDrawString = pStrImage;
  1395. Invalidate();
  1396. }
  1397. LPCTSTR CListHeaderItemUI::GetFocusedImage() const
  1398. {
  1399. return m_diFocused.sDrawString;
  1400. }
  1401. void CListHeaderItemUI::SetFocusedImage(LPCTSTR pStrImage)
  1402. {
  1403. if( m_diFocused.sDrawString == pStrImage && m_diFocused.pImageInfo != NULL ) return;
  1404. m_diFocused.Clear();
  1405. m_diFocused.sDrawString = pStrImage;
  1406. Invalidate();
  1407. }
  1408. LPCTSTR CListHeaderItemUI::GetSepImage() const
  1409. {
  1410. return m_diSep.sDrawString;
  1411. }
  1412. void CListHeaderItemUI::SetSepImage(LPCTSTR pStrImage)
  1413. {
  1414. if( m_diSep.sDrawString == pStrImage && m_diSep.pImageInfo != NULL ) return;
  1415. m_diSep.Clear();
  1416. m_diSep.sDrawString = pStrImage;
  1417. Invalidate();
  1418. }
  1419. void CListHeaderItemUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
  1420. {
  1421. if( _tcscmp(pstrName, _T("dragable")) == 0 ) SetDragable(_tcscmp(pstrValue, _T("true")) == 0);
  1422. else if( _tcscmp(pstrName, _T("align")) == 0 ) {
  1423. if( _tcsstr(pstrValue, _T("left")) != NULL ) {
  1424. m_uTextStyle &= ~(DT_CENTER | DT_RIGHT);
  1425. m_uTextStyle |= DT_LEFT;
  1426. }
  1427. if( _tcsstr(pstrValue, _T("center")) != NULL ) {
  1428. m_uTextStyle &= ~(DT_LEFT | DT_RIGHT);
  1429. m_uTextStyle |= DT_CENTER;
  1430. }
  1431. if( _tcsstr(pstrValue, _T("right")) != NULL ) {
  1432. m_uTextStyle &= ~(DT_LEFT | DT_CENTER);
  1433. m_uTextStyle |= DT_RIGHT;
  1434. }
  1435. }
  1436. else if (_tcscmp(pstrName, _T("valign")) == 0)
  1437. {
  1438. if (_tcsstr(pstrValue, _T("top")) != NULL) {
  1439. m_uTextStyle &= ~(DT_BOTTOM | DT_VCENTER);
  1440. m_uTextStyle |= DT_TOP;
  1441. }
  1442. if (_tcsstr(pstrValue, _T("vcenter")) != NULL) {
  1443. m_uTextStyle &= ~(DT_TOP | DT_BOTTOM);
  1444. m_uTextStyle |= DT_VCENTER;
  1445. }
  1446. if (_tcsstr(pstrValue, _T("bottom")) != NULL) {
  1447. m_uTextStyle &= ~(DT_TOP | DT_VCENTER);
  1448. m_uTextStyle |= DT_BOTTOM;
  1449. }
  1450. }
  1451. else if( _tcscmp(pstrName, _T("endellipsis")) == 0 ) {
  1452. if( _tcscmp(pstrValue, _T("true")) == 0 ) m_uTextStyle |= DT_END_ELLIPSIS;
  1453. else m_uTextStyle &= ~DT_END_ELLIPSIS;
  1454. }
  1455. else if( _tcscmp(pstrName, _T("multiline")) == 0 ) {
  1456. if (_tcscmp(pstrValue, _T("true")) == 0) {
  1457. m_uTextStyle &= ~DT_SINGLELINE;
  1458. m_uTextStyle |= DT_WORDBREAK;
  1459. }
  1460. else m_uTextStyle |= DT_SINGLELINE;
  1461. }
  1462. else if( _tcscmp(pstrName, _T("font")) == 0 ) SetFont(_ttoi(pstrValue));
  1463. else if( _tcscmp(pstrName, _T("textcolor")) == 0 ) {
  1464. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  1465. LPTSTR pstr = NULL;
  1466. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  1467. SetTextColor(clrColor);
  1468. }
  1469. else if( _tcscmp(pstrName, _T("textpadding")) == 0 ) {
  1470. RECT rcTextPadding = { 0 };
  1471. LPTSTR pstr = NULL;
  1472. rcTextPadding.left = _tcstol(pstrValue, &pstr, 10); ASSERT(pstr);
  1473. rcTextPadding.top = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
  1474. rcTextPadding.right = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
  1475. rcTextPadding.bottom = _tcstol(pstr + 1, &pstr, 10); ASSERT(pstr);
  1476. SetTextPadding(rcTextPadding);
  1477. }
  1478. else if( _tcscmp(pstrName, _T("showhtml")) == 0 ) SetShowHtml(_tcscmp(pstrValue, _T("true")) == 0);
  1479. else if( _tcscmp(pstrName, _T("normalimage")) == 0 ) SetNormalImage(pstrValue);
  1480. else if( _tcscmp(pstrName, _T("hotimage")) == 0 ) SetHotImage(pstrValue);
  1481. else if( _tcscmp(pstrName, _T("pushedimage")) == 0 ) SetPushedImage(pstrValue);
  1482. else if( _tcscmp(pstrName, _T("focusedimage")) == 0 ) SetFocusedImage(pstrValue);
  1483. else if( _tcscmp(pstrName, _T("sepwidth")) == 0 ) SetSepWidth(_ttoi(pstrValue));
  1484. else if( _tcscmp(pstrName, _T("sepcolor")) == 0 ) {
  1485. if( *pstrValue == _T('#')) pstrValue = ::CharNext(pstrValue);
  1486. LPTSTR pstr = NULL;
  1487. DWORD clrColor = _tcstoul(pstrValue, &pstr, 16);
  1488. SetSepColor(clrColor);
  1489. }
  1490. else if( _tcscmp(pstrName, _T("sepimage")) == 0 ) SetSepImage(pstrValue);
  1491. else CControlUI::SetAttribute(pstrName, pstrValue);
  1492. }
  1493. void CListHeaderItemUI::DoEvent(TEventUI& event)
  1494. {
  1495. if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {
  1496. if( m_pParent != NULL ) m_pParent->DoEvent(event);
  1497. else CControlUI::DoEvent(event);
  1498. return;
  1499. }
  1500. if( event.Type == UIEVENT_SETFOCUS )
  1501. {
  1502. Invalidate();
  1503. }
  1504. if( event.Type == UIEVENT_KILLFOCUS )
  1505. {
  1506. Invalidate();
  1507. }
  1508. if( event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_DBLCLICK )
  1509. {
  1510. if( !IsEnabled() ) return;
  1511. RECT rcSeparator = GetThumbRect();
  1512. if( ::PtInRect(&rcSeparator, event.ptMouse) ) {
  1513. if( m_bDragable ) {
  1514. m_uButtonState |= UISTATE_CAPTURED;
  1515. ptLastMouse = event.ptMouse;
  1516. }
  1517. }
  1518. else {
  1519. m_uButtonState |= UISTATE_PUSHED;
  1520. m_pManager->SendNotify(this, DUI_MSGTYPE_HEADERCLICK);
  1521. Invalidate();
  1522. }
  1523. return;
  1524. }
  1525. if( event.Type == UIEVENT_BUTTONUP )
  1526. {
  1527. if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
  1528. m_uButtonState &= ~UISTATE_CAPTURED;
  1529. if( GetParent() )
  1530. GetParent()->NeedParentUpdate();
  1531. }
  1532. else if( (m_uButtonState & UISTATE_PUSHED) != 0 ) {
  1533. m_uButtonState &= ~UISTATE_PUSHED;
  1534. Invalidate();
  1535. }
  1536. return;
  1537. }
  1538. if( event.Type == UIEVENT_MOUSEMOVE )
  1539. {
  1540. if( (m_uButtonState & UISTATE_CAPTURED) != 0 ) {
  1541. RECT rc = m_rcItem;
  1542. if( m_iSepWidth >= 0 ) {
  1543. rc.right -= ptLastMouse.x - event.ptMouse.x;
  1544. }
  1545. else {
  1546. rc.left -= ptLastMouse.x - event.ptMouse.x;
  1547. }
  1548. if( rc.right - rc.left > GetMinWidth() ) {
  1549. m_cxyFixed.cx = rc.right - rc.left;
  1550. ptLastMouse = event.ptMouse;
  1551. if( GetParent() )
  1552. GetParent()->NeedParentUpdate();
  1553. }
  1554. }
  1555. return;
  1556. }
  1557. if( event.Type == UIEVENT_SETCURSOR )
  1558. {
  1559. RECT rcSeparator = GetThumbRect();
  1560. if( IsEnabled() && m_bDragable && ::PtInRect(&rcSeparator, event.ptMouse) ) {
  1561. ::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_SIZEWE)));
  1562. return;
  1563. }
  1564. }
  1565. if( event.Type == UIEVENT_MOUSEENTER )
  1566. {
  1567. if( ::PtInRect(&m_rcItem, event.ptMouse ) ) {
  1568. if( IsEnabled() ) {
  1569. if( (m_uButtonState & UISTATE_HOT) == 0 ) {
  1570. m_uButtonState |= UISTATE_HOT;
  1571. Invalidate();
  1572. }
  1573. }
  1574. }
  1575. }
  1576. if( event.Type == UIEVENT_MOUSELEAVE )
  1577. {
  1578. if( !::PtInRect(&m_rcItem, event.ptMouse ) ) {
  1579. if( IsEnabled() ) {
  1580. if( (m_uButtonState & UISTATE_HOT) != 0 ) {
  1581. m_uButtonState &= ~UISTATE_HOT;
  1582. Invalidate();
  1583. }
  1584. }
  1585. if (m_pManager) m_pManager->RemoveMouseLeaveNeeded(this);
  1586. }
  1587. else {
  1588. if (m_pManager) m_pManager->AddMouseLeaveNeeded(this);
  1589. return;
  1590. }
  1591. }
  1592. CControlUI::DoEvent(event);
  1593. }
  1594. SIZE CListHeaderItemUI::EstimateSize(SIZE szAvailable)
  1595. {
  1596. if( m_cxyFixed.cy == 0 ) return CDuiSize(m_cxyFixed.cx, m_pManager->GetDefaultFontInfo()->tm.tmHeight + 8);
  1597. return CControlUI::EstimateSize(szAvailable);
  1598. }
  1599. RECT CListHeaderItemUI::GetThumbRect() const
  1600. {
  1601. if( m_iSepWidth >= 0 ) return CDuiRect(m_rcItem.right - m_iSepWidth, m_rcItem.top, m_rcItem.right, m_rcItem.bottom);
  1602. else return CDuiRect(m_rcItem.left, m_rcItem.top, m_rcItem.left - m_iSepWidth, m_rcItem.bottom);
  1603. }
  1604. void CListHeaderItemUI::PaintStatusImage(HDC hDC)
  1605. {
  1606. if( IsFocused() ) m_uButtonState |= UISTATE_FOCUSED;
  1607. else m_uButtonState &= ~ UISTATE_FOCUSED;
  1608. if( (m_uButtonState & UISTATE_PUSHED) != 0 ) {
  1609. if( !DrawImage(hDC, m_diPushed) ) DrawImage(hDC, m_diNormal);
  1610. }
  1611. else if( (m_uButtonState & UISTATE_HOT) != 0 ) {
  1612. if( !DrawImage(hDC, m_diHot) ) DrawImage(hDC, m_diNormal);
  1613. }
  1614. else if( (m_uButtonState & UISTATE_FOCUSED) != 0 ) {
  1615. if( !DrawImage(hDC, m_diFocused) ) DrawImage(hDC, m_diNormal);
  1616. }
  1617. else {
  1618. DrawImage(hDC, m_diNormal);
  1619. }
  1620. if (m_iSepWidth > 0) {
  1621. RECT rcThumb = GetThumbRect();
  1622. m_diSep.rcDestOffset.left = rcThumb.left - m_rcItem.left;
  1623. m_diSep.rcDestOffset.top = rcThumb.top - m_rcItem.top;
  1624. m_diSep.rcDestOffset.right = rcThumb.right - m_rcItem.left;
  1625. m_diSep.rcDestOffset.bottom = rcThumb.bottom - m_rcItem.top;
  1626. if( !DrawImage(hDC, m_diSep) ) {
  1627. if (m_dwSepColor != 0) {
  1628. RECT rcSepLine = { rcThumb.left + m_iSepWidth/2, rcThumb.top, rcThumb.left + m_iSepWidth/2, rcThumb.bottom};
  1629. CRenderEngine::DrawLine(hDC, rcSepLine, m_iSepWidth, GetAdjustColor(m_dwSepColor));
  1630. }
  1631. }
  1632. }
  1633. }
  1634. void CListHeaderItemUI::PaintText(HDC hDC)
  1635. {
  1636. if( m_dwTextColor == 0 ) m_dwTextColor = m_pManager->GetDefaultFontColor();
  1637. RECT rcText = m_rcItem;
  1638. rcText.left += m_rcTextPadding.left;
  1639. rcText.top += m_rcTextPadding.top;
  1640. rcText.right -= m_rcTextPadding.right;
  1641. rcText.bottom -= m_rcTextPadding.bottom;
  1642. if( m_sText.IsEmpty() ) return;
  1643. int nLinks = 0;
  1644. if( m_bShowHtml )
  1645. CRenderEngine::DrawHtmlText(hDC, m_pManager, rcText, m_sText, m_dwTextColor, \
  1646. NULL, NULL, nLinks, m_iFont, m_uTextStyle);
  1647. else
  1648. CRenderEngine::DrawText(hDC, m_pManager, rcText, m_sText, m_dwTextColor, \
  1649. m_iFont, m_uTextStyle);
  1650. }
  1651. /////////////////////////////////////////////////////////////////////////////////////
  1652. //
  1653. //
  1654. CListElementUI::CListElementUI() :
  1655. m_iIndex(-1),
  1656. m_iDrawIndex(0),
  1657. m_pOwner(NULL),
  1658. m_bSelected(false),
  1659. m_uButtonState(0)
  1660. {
  1661. }
  1662. LPCTSTR CListElementUI::GetClass() const
  1663. {
  1664. return DUI_CTR_LISTELEMENT;
  1665. }
  1666. UINT CListElementUI::GetControlFlags() const
  1667. {
  1668. return UIFLAG_WANTRETURN;
  1669. }
  1670. LPVOID CListElementUI::GetInterface(LPCTSTR pstrName)
  1671. {
  1672. if( _tcscmp(pstrName, DUI_CTR_ILISTITEM) == 0 ) return static_cast<IListItemUI*>(this);
  1673. if( _tcscmp(pstrName, DUI_CTR_LISTELEMENT) == 0 ) return static_cast<CListElementUI*>(this);
  1674. return CControlUI::GetInterface(pstrName);
  1675. }
  1676. IListOwnerUI* CListElementUI::GetOwner()
  1677. {
  1678. return m_pOwner;
  1679. }
  1680. void CListElementUI::SetOwner(CControlUI* pOwner)
  1681. {
  1682. if (pOwner != NULL) m_pOwner = static_cast<IListOwnerUI*>(pOwner->GetInterface(DUI_CTR_ILISTOWNER));
  1683. }
  1684. void CListElementUI::SetVisible(bool bVisible)
  1685. {
  1686. CControlUI::SetVisible(bVisible);
  1687. if( !IsVisible() && m_bSelected)
  1688. {
  1689. m_bSelected = false;
  1690. if( m_pOwner != NULL ) m_pOwner->SelectItem(-1);
  1691. }
  1692. }
  1693. void CListElementUI::SetEnabled(bool bEnable)
  1694. {
  1695. CControlUI::SetEnabled(bEnable);
  1696. if( !IsEnabled() ) {
  1697. m_uButtonState = 0;
  1698. }
  1699. }
  1700. int CListElementUI::GetIndex() const
  1701. {
  1702. return m_iIndex;
  1703. }
  1704. void CListElementUI::SetIndex(int iIndex)
  1705. {
  1706. m_iIndex = iIndex;
  1707. }
  1708. int CListElementUI::GetDrawIndex() const
  1709. {
  1710. return m_iDrawIndex;
  1711. }
  1712. void CListElementUI::SetDrawIndex(int iIndex)
  1713. {
  1714. m_iDrawIndex = iIndex;
  1715. }
  1716. void CListElementUI::Invalidate()
  1717. {
  1718. if( !IsVisible() ) return;
  1719. if( GetParent() ) {
  1720. CContainerUI* pParentContainer = static_cast<CContainerUI*>(GetParent()->GetInterface(DUI_CTR_CONTAINER));
  1721. if( pParentContainer ) {
  1722. RECT rc = pParentContainer->GetPos();
  1723. RECT rcInset = pParentContainer->GetInset();
  1724. rc.left += rcInset.left;
  1725. rc.top += rcInset.top;
  1726. rc.right -= rcInset.right;
  1727. rc.bottom -= rcInset.bottom;
  1728. CScrollBarUI* pVerticalScrollBar = pParentContainer->GetVerticalScrollBar();
  1729. if( pVerticalScrollBar && pVerticalScrollBar->IsVisible() ) rc.right -= pVerticalScrollBar->GetFixedWidth();
  1730. CScrollBarUI* pHorizontalScrollBar = pParentContainer->GetHorizontalScrollBar();
  1731. if( pHorizontalScrollBar && pHorizontalScrollBar->IsVisible() ) rc.bottom -= pHorizontalScrollBar->GetFixedHeight();
  1732. RECT invalidateRc = m_rcItem;
  1733. if( !::IntersectRect(&invalidateRc, &m_rcItem, &rc) )
  1734. {
  1735. return;
  1736. }
  1737. CControlUI* pParent = GetParent();
  1738. RECT rcTemp;
  1739. RECT rcParent;
  1740. while( pParent = pParent->GetParent() )
  1741. {
  1742. rcTemp = invalidateRc;
  1743. rcParent = pParent->GetPos();
  1744. if( !::IntersectRect(&invalidateRc, &rcTemp, &rcParent) )
  1745. {
  1746. return;
  1747. }
  1748. }
  1749. if( m_pManager != NULL ) m_pManager->Invalidate(invalidateRc);
  1750. }
  1751. else {
  1752. CControlUI::Invalidate();
  1753. }
  1754. }
  1755. else {
  1756. CControlUI::Invalidate();
  1757. }
  1758. }
  1759. bool CListElementUI::Activate()
  1760. {
  1761. if( !CControlUI::Activate() ) return false;
  1762. if( m_pManager != NULL ) m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMACTIVATE);
  1763. return true;
  1764. }
  1765. bool CListElementUI::IsSelected() const
  1766. {
  1767. return m_bSelected;
  1768. }
  1769. bool CListElementUI::Select(bool bSelect, bool bTriggerEvent)
  1770. {
  1771. if( !IsEnabled() ) return false;
  1772. if( bSelect == m_bSelected ) return true;
  1773. m_bSelected = bSelect;
  1774. if( bSelect && m_pOwner != NULL ) m_pOwner->SelectItem(m_iIndex, bTriggerEvent);
  1775. Invalidate();
  1776. return true;
  1777. }
  1778. bool CListElementUI::IsExpanded() const
  1779. {
  1780. return false;
  1781. }
  1782. bool CListElementUI::Expand(bool /*bExpand = true*/)
  1783. {
  1784. return false;
  1785. }
  1786. void CListElementUI::DoEvent(TEventUI& event)
  1787. {
  1788. if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {
  1789. if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
  1790. else CControlUI::DoEvent(event);
  1791. return;
  1792. }
  1793. if( event.Type == UIEVENT_DBLCLICK )
  1794. {
  1795. if( IsEnabled() ) {
  1796. Activate();
  1797. Invalidate();
  1798. }
  1799. return;
  1800. }
  1801. if( event.Type == UIEVENT_KEYDOWN )
  1802. {
  1803. if (IsKeyboardEnabled() && IsEnabled()) {
  1804. if( event.chKey == VK_RETURN ) {
  1805. Activate();
  1806. Invalidate();
  1807. return;
  1808. }
  1809. }
  1810. }
  1811. // An important twist: The list-item will send the event not to its immediate
  1812. // parent but to the "attached" list. A list may actually embed several components
  1813. // in its path to the item, but key-presses etc. needs to go to the actual list.
  1814. if( m_pOwner != NULL ) m_pOwner->DoEvent(event); else CControlUI::DoEvent(event);
  1815. }
  1816. void CListElementUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
  1817. {
  1818. if( _tcscmp(pstrName, _T("selected")) == 0 ) Select();
  1819. else CControlUI::SetAttribute(pstrName, pstrValue);
  1820. }
  1821. void CListElementUI::DrawItemBk(HDC hDC, const RECT& rcItem)
  1822. {
  1823. ASSERT(m_pOwner);
  1824. if( m_pOwner == NULL ) return;
  1825. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  1826. if( pInfo == NULL ) return;
  1827. DWORD iBackColor = 0;
  1828. if( !pInfo->bAlternateBk || m_iDrawIndex % 2 == 0 ) iBackColor = pInfo->dwBkColor;
  1829. if( (m_uButtonState & UISTATE_HOT) != 0 ) {
  1830. iBackColor = pInfo->dwHotBkColor;
  1831. }
  1832. if( IsSelected() ) {
  1833. iBackColor = pInfo->dwSelectedBkColor;
  1834. }
  1835. if( !IsEnabled() ) {
  1836. iBackColor = pInfo->dwDisabledBkColor;
  1837. }
  1838. if ( iBackColor != 0 ) {
  1839. CRenderEngine::DrawColor(hDC, rcItem, GetAdjustColor(iBackColor));
  1840. }
  1841. if( !IsEnabled() ) {
  1842. if( DrawImage(hDC, pInfo->diDisabled) ) return;
  1843. }
  1844. if( IsSelected() ) {
  1845. if( DrawImage(hDC, pInfo->diSelected) ) return;
  1846. }
  1847. if( (m_uButtonState & UISTATE_HOT) != 0 ) {
  1848. if( DrawImage(hDC, pInfo->diHot) ) return;
  1849. }
  1850. if( !DrawImage(hDC, m_diBk) ) {
  1851. if( !pInfo->bAlternateBk || m_iDrawIndex % 2 == 0 ) {
  1852. if( DrawImage(hDC, pInfo->diBk) ) return;
  1853. }
  1854. }
  1855. }
  1856. /////////////////////////////////////////////////////////////////////////////////////
  1857. //
  1858. //
  1859. CListLabelElementUI::CListLabelElementUI() : m_bNeedEstimateSize(true), m_uFixedHeightLast(0),
  1860. m_nFontLast(-1), m_uTextStyleLast(0)
  1861. {
  1862. m_szAvailableLast.cx = m_szAvailableLast.cy = 0;
  1863. m_cxyFixedLast.cx = m_cxyFixedLast.cy = 0;
  1864. ::ZeroMemory(&m_rcTextPaddingLast, sizeof(m_rcTextPaddingLast));
  1865. }
  1866. LPCTSTR CListLabelElementUI::GetClass() const
  1867. {
  1868. return DUI_CTR_LISTLABELELEMENT;
  1869. }
  1870. LPVOID CListLabelElementUI::GetInterface(LPCTSTR pstrName)
  1871. {
  1872. if( _tcscmp(pstrName, DUI_CTR_LISTLABELELEMENT) == 0 ) return static_cast<CListLabelElementUI*>(this);
  1873. return CListElementUI::GetInterface(pstrName);
  1874. }
  1875. void CListLabelElementUI::SetOwner(CControlUI* pOwner)
  1876. {
  1877. m_bNeedEstimateSize = true;
  1878. CListElementUI::SetOwner(pOwner);
  1879. }
  1880. void CListLabelElementUI::SetFixedWidth(int cx)
  1881. {
  1882. m_bNeedEstimateSize = true;
  1883. CControlUI::SetFixedWidth(cx);
  1884. }
  1885. void CListLabelElementUI::SetFixedHeight(int cy)
  1886. {
  1887. m_bNeedEstimateSize = true;
  1888. CControlUI::SetFixedHeight(cy);
  1889. }
  1890. void CListLabelElementUI::SetText(LPCTSTR pstrText)
  1891. {
  1892. m_bNeedEstimateSize = true;
  1893. CControlUI::SetText(pstrText);
  1894. }
  1895. void CListLabelElementUI::DoEvent(TEventUI& event)
  1896. {
  1897. if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {
  1898. if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
  1899. else CListElementUI::DoEvent(event);
  1900. return;
  1901. }
  1902. if( event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_RBUTTONDOWN )
  1903. {
  1904. if( IsEnabled() ) {
  1905. m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMCLICK);
  1906. Select();
  1907. Invalidate();
  1908. }
  1909. return;
  1910. }
  1911. if( event.Type == UIEVENT_MOUSEMOVE )
  1912. {
  1913. return;
  1914. }
  1915. if( event.Type == UIEVENT_BUTTONUP )
  1916. {
  1917. return;
  1918. }
  1919. if( event.Type == UIEVENT_MOUSEENTER )
  1920. {
  1921. if( ::PtInRect(&m_rcItem, event.ptMouse ) ) {
  1922. if( IsEnabled() ) {
  1923. if( (m_uButtonState & UISTATE_HOT) == 0 ) {
  1924. m_uButtonState |= UISTATE_HOT;
  1925. Invalidate();
  1926. }
  1927. }
  1928. }
  1929. }
  1930. if( event.Type == UIEVENT_MOUSELEAVE )
  1931. {
  1932. if( !::PtInRect(&m_rcItem, event.ptMouse ) ) {
  1933. if( IsEnabled() ) {
  1934. if( (m_uButtonState & UISTATE_HOT) != 0 ) {
  1935. m_uButtonState &= ~UISTATE_HOT;
  1936. Invalidate();
  1937. }
  1938. }
  1939. if (m_pManager) m_pManager->RemoveMouseLeaveNeeded(this);
  1940. }
  1941. else {
  1942. if (m_pManager) m_pManager->AddMouseLeaveNeeded(this);
  1943. return;
  1944. }
  1945. }
  1946. CListElementUI::DoEvent(event);
  1947. }
  1948. SIZE CListLabelElementUI::EstimateSize(SIZE szAvailable)
  1949. {
  1950. if( m_pOwner == NULL ) return CDuiSize(0, 0);
  1951. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  1952. if (pInfo == NULL) return CDuiSize(0, 0);
  1953. if (m_cxyFixed.cx > 0) {
  1954. if (m_cxyFixed.cy > 0) return m_cxyFixed;
  1955. else if (pInfo->uFixedHeight > 0) return CDuiSize(m_cxyFixed.cx, pInfo->uFixedHeight);
  1956. }
  1957. if ((pInfo->uTextStyle & DT_SINGLELINE) == 0 &&
  1958. (szAvailable.cx != m_szAvailableLast.cx || szAvailable.cy != m_szAvailableLast.cy)) {
  1959. m_bNeedEstimateSize = true;
  1960. }
  1961. if (m_uFixedHeightLast != pInfo->uFixedHeight || m_nFontLast != pInfo->nFont ||
  1962. m_uTextStyleLast != pInfo->uTextStyle ||
  1963. m_rcTextPaddingLast.left != pInfo->rcTextPadding.left || m_rcTextPaddingLast.right != pInfo->rcTextPadding.right ||
  1964. m_rcTextPaddingLast.top != pInfo->rcTextPadding.top || m_rcTextPaddingLast.bottom != pInfo->rcTextPadding.bottom) {
  1965. m_bNeedEstimateSize = true;
  1966. }
  1967. if (m_bNeedEstimateSize) {
  1968. m_bNeedEstimateSize = false;
  1969. m_szAvailableLast = szAvailable;
  1970. m_uFixedHeightLast = pInfo->uFixedHeight;
  1971. m_nFontLast = pInfo->nFont;
  1972. m_uTextStyleLast = pInfo->uTextStyle;
  1973. m_rcTextPaddingLast = pInfo->rcTextPadding;
  1974. m_cxyFixedLast = m_cxyFixed;
  1975. if (m_cxyFixedLast.cy == 0) {
  1976. m_cxyFixedLast.cy = pInfo->uFixedHeight;
  1977. }
  1978. if ((pInfo->uTextStyle & DT_SINGLELINE) != 0) {
  1979. if( m_cxyFixedLast.cy == 0 ) {
  1980. m_cxyFixedLast.cy = m_pManager->GetFontInfo(pInfo->nFont)->tm.tmHeight + 8;
  1981. m_cxyFixedLast.cy += pInfo->rcTextPadding.top + pInfo->rcTextPadding.bottom;
  1982. }
  1983. if (m_cxyFixedLast.cx == 0) {
  1984. RECT rcText = { 0, 0, 9999, m_cxyFixedLast.cy };
  1985. if( pInfo->bShowHtml ) {
  1986. int nLinks = 0;
  1987. CRenderEngine::DrawHtmlText(m_pManager->GetPaintDC(), m_pManager, rcText, m_sText, 0, NULL, NULL, nLinks, pInfo->nFont, DT_CALCRECT | pInfo->uTextStyle & ~DT_RIGHT & ~DT_CENTER);
  1988. }
  1989. else {
  1990. CRenderEngine::DrawText(m_pManager->GetPaintDC(), m_pManager, rcText, m_sText, 0, pInfo->nFont, DT_CALCRECT | pInfo->uTextStyle & ~DT_RIGHT & ~DT_CENTER);
  1991. }
  1992. m_cxyFixedLast.cx = rcText.right - rcText.left + pInfo->rcTextPadding.left + pInfo->rcTextPadding.right;
  1993. }
  1994. }
  1995. else {
  1996. if( m_cxyFixedLast.cx == 0 ) {
  1997. m_cxyFixedLast.cx = szAvailable.cx;
  1998. }
  1999. RECT rcText = { 0, 0, m_cxyFixedLast.cx, 9999 };
  2000. rcText.left += pInfo->rcTextPadding.left;
  2001. rcText.right -= pInfo->rcTextPadding.right;
  2002. if( pInfo->bShowHtml ) {
  2003. int nLinks = 0;
  2004. CRenderEngine::DrawHtmlText(m_pManager->GetPaintDC(), m_pManager, rcText, m_sText, 0, NULL, NULL, nLinks, pInfo->nFont, DT_CALCRECT | pInfo->uTextStyle & ~DT_RIGHT & ~DT_CENTER);
  2005. }
  2006. else {
  2007. CRenderEngine::DrawText(m_pManager->GetPaintDC(), m_pManager, rcText, m_sText, 0, pInfo->nFont, DT_CALCRECT | pInfo->uTextStyle & ~DT_RIGHT & ~DT_CENTER);
  2008. }
  2009. m_cxyFixedLast.cy = rcText.bottom - rcText.top + pInfo->rcTextPadding.top + pInfo->rcTextPadding.bottom;
  2010. }
  2011. }
  2012. return m_cxyFixedLast;
  2013. }
  2014. bool CListLabelElementUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
  2015. {
  2016. DrawItemBk(hDC, m_rcItem);
  2017. DrawItemText(hDC, m_rcItem);
  2018. return true;
  2019. }
  2020. void CListLabelElementUI::DrawItemText(HDC hDC, const RECT& rcItem)
  2021. {
  2022. if( m_sText.IsEmpty() ) return;
  2023. if( m_pOwner == NULL ) return;
  2024. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  2025. if( pInfo == NULL ) return;
  2026. DWORD iTextColor = pInfo->dwTextColor;
  2027. if( (m_uButtonState & UISTATE_HOT) != 0 ) {
  2028. iTextColor = pInfo->dwHotTextColor;
  2029. }
  2030. if( IsSelected() ) {
  2031. iTextColor = pInfo->dwSelectedTextColor;
  2032. }
  2033. if( !IsEnabled() ) {
  2034. iTextColor = pInfo->dwDisabledTextColor;
  2035. }
  2036. int nLinks = 0;
  2037. RECT rcText = rcItem;
  2038. rcText.left += pInfo->rcTextPadding.left;
  2039. rcText.right -= pInfo->rcTextPadding.right;
  2040. rcText.top += pInfo->rcTextPadding.top;
  2041. rcText.bottom -= pInfo->rcTextPadding.bottom;
  2042. if( pInfo->bShowHtml )
  2043. CRenderEngine::DrawHtmlText(hDC, m_pManager, rcText, m_sText, iTextColor, \
  2044. NULL, NULL, nLinks, pInfo->nFont, pInfo->uTextStyle);
  2045. else
  2046. CRenderEngine::DrawText(hDC, m_pManager, rcText, m_sText, iTextColor, \
  2047. pInfo->nFont, pInfo->uTextStyle);
  2048. }
  2049. /////////////////////////////////////////////////////////////////////////////////////
  2050. //
  2051. //
  2052. CListTextElementUI::CListTextElementUI() : m_nLinks(0), m_nHoverLink(-1), m_pOwner(NULL)
  2053. {
  2054. ::ZeroMemory(&m_rcLinks, sizeof(m_rcLinks));
  2055. }
  2056. CListTextElementUI::~CListTextElementUI()
  2057. {
  2058. CDuiString* pText;
  2059. for( int it = 0; it < m_aTexts.GetSize(); it++ ) {
  2060. pText = static_cast<CDuiString*>(m_aTexts[it]);
  2061. if( pText ) delete pText;
  2062. }
  2063. m_aTexts.Empty();
  2064. }
  2065. LPCTSTR CListTextElementUI::GetClass() const
  2066. {
  2067. return DUI_CTR_LISTTEXTELEMENT;
  2068. }
  2069. LPVOID CListTextElementUI::GetInterface(LPCTSTR pstrName)
  2070. {
  2071. if( _tcscmp(pstrName, DUI_CTR_LISTTEXTELEMENT) == 0 ) return static_cast<CListTextElementUI*>(this);
  2072. return CListLabelElementUI::GetInterface(pstrName);
  2073. }
  2074. UINT CListTextElementUI::GetControlFlags() const
  2075. {
  2076. return UIFLAG_WANTRETURN | ( (IsEnabled() && m_nLinks > 0) ? UIFLAG_SETCURSOR : 0);
  2077. }
  2078. LPCTSTR CListTextElementUI::GetText(int iIndex) const
  2079. {
  2080. CDuiString* pText = static_cast<CDuiString*>(m_aTexts.GetAt(iIndex));
  2081. if( pText ) return pText->GetData();
  2082. return NULL;
  2083. }
  2084. void CListTextElementUI::SetText(int iIndex, LPCTSTR pstrText)
  2085. {
  2086. if( m_pOwner == NULL ) return;
  2087. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  2088. if( iIndex < 0 || iIndex >= pInfo->nColumns ) return;
  2089. m_bNeedEstimateSize = true;
  2090. while( m_aTexts.GetSize() < pInfo->nColumns ) { m_aTexts.Add(NULL); }
  2091. CDuiString* pText = static_cast<CDuiString*>(m_aTexts[iIndex]);
  2092. if( (pText == NULL && pstrText == NULL) || (pText && *pText == pstrText) ) return;
  2093. if ( pText ) //by cddjr 2011/10/20
  2094. pText->Assign(pstrText);
  2095. else
  2096. m_aTexts.SetAt(iIndex, new CDuiString(pstrText));
  2097. Invalidate();
  2098. }
  2099. void CListTextElementUI::SetOwner(CControlUI* pOwner)
  2100. {
  2101. if (pOwner != NULL) {
  2102. m_bNeedEstimateSize = true;
  2103. CListElementUI::SetOwner(pOwner);
  2104. m_pOwner = static_cast<IListUI*>(pOwner->GetInterface(DUI_CTR_ILIST));
  2105. }
  2106. }
  2107. CDuiString* CListTextElementUI::GetLinkContent(int iIndex)
  2108. {
  2109. if( iIndex >= 0 && iIndex < m_nLinks ) return &m_sLinks[iIndex];
  2110. return NULL;
  2111. }
  2112. void CListTextElementUI::DoEvent(TEventUI& event)
  2113. {
  2114. if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {
  2115. if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
  2116. else CListLabelElementUI::DoEvent(event);
  2117. return;
  2118. }
  2119. // When you hover over a link
  2120. if( event.Type == UIEVENT_SETCURSOR ) {
  2121. for( int i = 0; i < m_nLinks; i++ ) {
  2122. if( ::PtInRect(&m_rcLinks[i], event.ptMouse) ) {
  2123. ::SetCursor(::LoadCursor(NULL, MAKEINTRESOURCE(IDC_HAND)));
  2124. return;
  2125. }
  2126. }
  2127. }
  2128. if( event.Type == UIEVENT_BUTTONUP && IsEnabled() ) {
  2129. for( int i = 0; i < m_nLinks; i++ ) {
  2130. if( ::PtInRect(&m_rcLinks[i], event.ptMouse) ) {
  2131. m_pManager->SendNotify(this, DUI_MSGTYPE_LINK, i);
  2132. return;
  2133. }
  2134. }
  2135. }
  2136. if( m_nLinks > 0 && event.Type == UIEVENT_MOUSEMOVE ) {
  2137. int nHoverLink = -1;
  2138. for( int i = 0; i < m_nLinks; i++ ) {
  2139. if( ::PtInRect(&m_rcLinks[i], event.ptMouse) ) {
  2140. nHoverLink = i;
  2141. break;
  2142. }
  2143. }
  2144. if(m_nHoverLink != nHoverLink) {
  2145. Invalidate();
  2146. m_nHoverLink = nHoverLink;
  2147. }
  2148. }
  2149. if( m_nLinks > 0 && event.Type == UIEVENT_MOUSELEAVE ) {
  2150. if(m_nHoverLink != -1) {
  2151. if( !::PtInRect(&m_rcLinks[m_nHoverLink], event.ptMouse) ) {
  2152. m_nHoverLink = -1;
  2153. Invalidate();
  2154. if (m_pManager) m_pManager->RemoveMouseLeaveNeeded(this);
  2155. }
  2156. else {
  2157. if (m_pManager) m_pManager->AddMouseLeaveNeeded(this);
  2158. return;
  2159. }
  2160. }
  2161. }
  2162. CListLabelElementUI::DoEvent(event);
  2163. }
  2164. SIZE CListTextElementUI::EstimateSize(SIZE szAvailable)
  2165. {
  2166. if( m_pOwner == NULL ) return CDuiSize(0, 0);
  2167. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  2168. if (pInfo == NULL) return CDuiSize(0, 0);
  2169. SIZE cxyFixed = m_cxyFixed;
  2170. if (cxyFixed.cx == 0 && pInfo->nColumns > 0) {
  2171. cxyFixed.cx = pInfo->rcColumn[pInfo->nColumns - 1].right - pInfo->rcColumn[0].left;
  2172. if (m_cxyFixedLast.cx != cxyFixed.cx) m_bNeedEstimateSize = true;
  2173. }
  2174. if (cxyFixed.cx > 0) {
  2175. if (cxyFixed.cy > 0) return cxyFixed;
  2176. else if (pInfo->uFixedHeight > 0) return CDuiSize(cxyFixed.cx, pInfo->uFixedHeight);
  2177. }
  2178. if ((pInfo->uTextStyle & DT_SINGLELINE) == 0 &&
  2179. (szAvailable.cx != m_szAvailableLast.cx || szAvailable.cy != m_szAvailableLast.cy)) {
  2180. m_bNeedEstimateSize = true;
  2181. }
  2182. if (m_uFixedHeightLast != pInfo->uFixedHeight || m_nFontLast != pInfo->nFont ||
  2183. m_uTextStyleLast != pInfo->uTextStyle ||
  2184. m_rcTextPaddingLast.left != pInfo->rcTextPadding.left || m_rcTextPaddingLast.right != pInfo->rcTextPadding.right ||
  2185. m_rcTextPaddingLast.top != pInfo->rcTextPadding.top || m_rcTextPaddingLast.bottom != pInfo->rcTextPadding.bottom) {
  2186. m_bNeedEstimateSize = true;
  2187. }
  2188. CDuiString strText;
  2189. IListCallbackUI* pCallback = m_pOwner->GetTextCallback();
  2190. if( pCallback ) strText = pCallback->GetItemText(this, m_iIndex, 0);
  2191. else if (m_aTexts.GetSize() > 0) strText.Assign(GetText(0));
  2192. else strText = m_sText;
  2193. if (m_sTextLast != strText) m_bNeedEstimateSize = true;
  2194. if (m_bNeedEstimateSize) {
  2195. m_bNeedEstimateSize = false;
  2196. m_szAvailableLast = szAvailable;
  2197. m_uFixedHeightLast = pInfo->uFixedHeight;
  2198. m_nFontLast = pInfo->nFont;
  2199. m_uTextStyleLast = pInfo->uTextStyle;
  2200. m_rcTextPaddingLast = pInfo->rcTextPadding;
  2201. m_sTextLast = strText;
  2202. m_cxyFixedLast = m_cxyFixed;
  2203. if (m_cxyFixedLast.cx == 0 && pInfo->nColumns > 0) {
  2204. m_cxyFixedLast.cx = pInfo->rcColumn[pInfo->nColumns - 1].right - pInfo->rcColumn[0].left;
  2205. }
  2206. if (m_cxyFixedLast.cy == 0) {
  2207. m_cxyFixedLast.cy = pInfo->uFixedHeight;
  2208. }
  2209. if ((pInfo->uTextStyle & DT_SINGLELINE) != 0) {
  2210. if( m_cxyFixedLast.cy == 0 ) {
  2211. m_cxyFixedLast.cy = m_pManager->GetFontInfo(pInfo->nFont)->tm.tmHeight + 8;
  2212. m_cxyFixedLast.cy += pInfo->rcTextPadding.top + pInfo->rcTextPadding.bottom;
  2213. }
  2214. if (m_cxyFixedLast.cx == 0) {
  2215. RECT rcText = { 0, 0, 9999, m_cxyFixedLast.cy };
  2216. if( pInfo->bShowHtml ) {
  2217. int nLinks = 0;
  2218. CRenderEngine::DrawHtmlText(m_pManager->GetPaintDC(), m_pManager, rcText, strText, 0, NULL, NULL, nLinks, pInfo->nFont, DT_CALCRECT | pInfo->uTextStyle & ~DT_RIGHT & ~DT_CENTER);
  2219. }
  2220. else {
  2221. CRenderEngine::DrawText(m_pManager->GetPaintDC(), m_pManager, rcText, strText, 0, pInfo->nFont, DT_CALCRECT | pInfo->uTextStyle & ~DT_RIGHT & ~DT_CENTER);
  2222. }
  2223. m_cxyFixedLast.cx = rcText.right - rcText.left + pInfo->rcTextPadding.left + pInfo->rcTextPadding.right;
  2224. }
  2225. }
  2226. else {
  2227. if( m_cxyFixedLast.cx == 0 ) {
  2228. m_cxyFixedLast.cx = szAvailable.cx;
  2229. }
  2230. RECT rcText = { 0, 0, m_cxyFixedLast.cx, 9999 };
  2231. rcText.left += pInfo->rcTextPadding.left;
  2232. rcText.right -= pInfo->rcTextPadding.right;
  2233. if( pInfo->bShowHtml ) {
  2234. int nLinks = 0;
  2235. CRenderEngine::DrawHtmlText(m_pManager->GetPaintDC(), m_pManager, rcText, strText, 0, NULL, NULL, nLinks, pInfo->nFont, DT_CALCRECT | pInfo->uTextStyle & ~DT_RIGHT & ~DT_CENTER);
  2236. }
  2237. else {
  2238. CRenderEngine::DrawText(m_pManager->GetPaintDC(), m_pManager, rcText, strText, 0, pInfo->nFont, DT_CALCRECT | pInfo->uTextStyle & ~DT_RIGHT & ~DT_CENTER);
  2239. }
  2240. m_cxyFixedLast.cy = rcText.bottom - rcText.top + pInfo->rcTextPadding.top + pInfo->rcTextPadding.bottom;
  2241. }
  2242. }
  2243. return m_cxyFixedLast;
  2244. }
  2245. void CListTextElementUI::DrawItemText(HDC hDC, const RECT& rcItem)
  2246. {
  2247. if( m_pOwner == NULL ) return;
  2248. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  2249. if (pInfo == NULL) return;
  2250. DWORD iTextColor = pInfo->dwTextColor;
  2251. if( (m_uButtonState & UISTATE_HOT) != 0 ) {
  2252. iTextColor = pInfo->dwHotTextColor;
  2253. }
  2254. if( IsSelected() ) {
  2255. iTextColor = pInfo->dwSelectedTextColor;
  2256. }
  2257. if( !IsEnabled() ) {
  2258. iTextColor = pInfo->dwDisabledTextColor;
  2259. }
  2260. IListCallbackUI* pCallback = m_pOwner->GetTextCallback();
  2261. m_nLinks = 0;
  2262. int nLinks = lengthof(m_rcLinks);
  2263. if (pInfo->nColumns > 0) {
  2264. for( int i = 0; i < pInfo->nColumns; i++ )
  2265. {
  2266. RECT rcItem = { pInfo->rcColumn[i].left, m_rcItem.top, pInfo->rcColumn[i].right, m_rcItem.bottom };
  2267. if (pInfo->iVLineSize > 0 && i < pInfo->nColumns - 1) {
  2268. RECT rcLine = { rcItem.right - pInfo->iVLineSize / 2, rcItem.top, rcItem.right - pInfo->iVLineSize / 2, rcItem.bottom};
  2269. CRenderEngine::DrawLine(hDC, rcLine, pInfo->iVLineSize, GetAdjustColor(pInfo->dwVLineColor));
  2270. rcItem.right -= pInfo->iVLineSize;
  2271. }
  2272. rcItem.left += pInfo->rcTextPadding.left;
  2273. rcItem.right -= pInfo->rcTextPadding.right;
  2274. rcItem.top += pInfo->rcTextPadding.top;
  2275. rcItem.bottom -= pInfo->rcTextPadding.bottom;
  2276. CDuiString strText;//不使用LPCTSTR,否则限制太多 by cddjr 2011/10/20
  2277. if( pCallback ) strText = pCallback->GetItemText(this, m_iIndex, i);
  2278. else strText.Assign(GetText(i));
  2279. if( pInfo->bShowHtml )
  2280. CRenderEngine::DrawHtmlText(hDC, m_pManager, rcItem, strText.GetData(), iTextColor, \
  2281. &m_rcLinks[m_nLinks], &m_sLinks[m_nLinks], nLinks, pInfo->nFont, pInfo->uTextStyle);
  2282. else
  2283. CRenderEngine::DrawText(hDC, m_pManager, rcItem, strText.GetData(), iTextColor, \
  2284. pInfo->nFont, pInfo->uTextStyle);
  2285. m_nLinks += nLinks;
  2286. nLinks = lengthof(m_rcLinks) - m_nLinks;
  2287. }
  2288. }
  2289. else {
  2290. RECT rcItem = m_rcItem;
  2291. rcItem.left += pInfo->rcTextPadding.left;
  2292. rcItem.right -= pInfo->rcTextPadding.right;
  2293. rcItem.top += pInfo->rcTextPadding.top;
  2294. rcItem.bottom -= pInfo->rcTextPadding.bottom;
  2295. CDuiString strText;
  2296. if( pCallback ) strText = pCallback->GetItemText(this, m_iIndex, 0);
  2297. else if (m_aTexts.GetSize() > 0) strText.Assign(GetText(0));
  2298. else strText = m_sText;
  2299. if( pInfo->bShowHtml )
  2300. CRenderEngine::DrawHtmlText(hDC, m_pManager, rcItem, strText.GetData(), iTextColor, \
  2301. &m_rcLinks[m_nLinks], &m_sLinks[m_nLinks], nLinks, pInfo->nFont, pInfo->uTextStyle);
  2302. else
  2303. CRenderEngine::DrawText(hDC, m_pManager, rcItem, strText.GetData(), iTextColor, \
  2304. pInfo->nFont, pInfo->uTextStyle);
  2305. m_nLinks += nLinks;
  2306. nLinks = lengthof(m_rcLinks) - m_nLinks;
  2307. }
  2308. for( int i = m_nLinks; i < lengthof(m_rcLinks); i++ ) {
  2309. ::ZeroMemory(m_rcLinks + i, sizeof(RECT));
  2310. ((CDuiString*)(m_sLinks + i))->Empty();
  2311. }
  2312. }
  2313. /////////////////////////////////////////////////////////////////////////////////////
  2314. //
  2315. //
  2316. CListContainerElementUI::CListContainerElementUI() :
  2317. m_iIndex(-1),
  2318. m_iDrawIndex(0),
  2319. m_pOwner(NULL),
  2320. m_bSelected(false),
  2321. m_bExpandable(false),
  2322. m_bExpand(false),
  2323. m_uButtonState(0)
  2324. {
  2325. }
  2326. LPCTSTR CListContainerElementUI::GetClass() const
  2327. {
  2328. return DUI_CTR_LISTCONTAINERELEMENT;
  2329. }
  2330. UINT CListContainerElementUI::GetControlFlags() const
  2331. {
  2332. return UIFLAG_WANTRETURN;
  2333. }
  2334. LPVOID CListContainerElementUI::GetInterface(LPCTSTR pstrName)
  2335. {
  2336. if( _tcscmp(pstrName, DUI_CTR_ILISTITEM) == 0 ) return static_cast<IListItemUI*>(this);
  2337. if( _tcscmp(pstrName, DUI_CTR_LISTCONTAINERELEMENT) == 0 ) return static_cast<CListContainerElementUI*>(this);
  2338. return CContainerUI::GetInterface(pstrName);
  2339. }
  2340. IListOwnerUI* CListContainerElementUI::GetOwner()
  2341. {
  2342. return m_pOwner;
  2343. }
  2344. void CListContainerElementUI::SetOwner(CControlUI* pOwner)
  2345. {
  2346. if (pOwner != NULL) m_pOwner = static_cast<IListOwnerUI*>(pOwner->GetInterface(DUI_CTR_ILISTOWNER));
  2347. }
  2348. void CListContainerElementUI::SetVisible(bool bVisible)
  2349. {
  2350. CContainerUI::SetVisible(bVisible);
  2351. if( !IsVisible() && m_bSelected)
  2352. {
  2353. m_bSelected = false;
  2354. if( m_pOwner != NULL ) m_pOwner->SelectItem(-1);
  2355. }
  2356. }
  2357. void CListContainerElementUI::SetEnabled(bool bEnable)
  2358. {
  2359. CControlUI::SetEnabled(bEnable);
  2360. if( !IsEnabled() ) {
  2361. m_uButtonState = 0;
  2362. }
  2363. }
  2364. int CListContainerElementUI::GetIndex() const
  2365. {
  2366. return m_iIndex;
  2367. }
  2368. void CListContainerElementUI::SetIndex(int iIndex)
  2369. {
  2370. m_iIndex = iIndex;
  2371. }
  2372. int CListContainerElementUI::GetDrawIndex() const
  2373. {
  2374. return m_iDrawIndex;
  2375. }
  2376. void CListContainerElementUI::SetDrawIndex(int iIndex)
  2377. {
  2378. m_iDrawIndex = iIndex;
  2379. }
  2380. void CListContainerElementUI::Invalidate()
  2381. {
  2382. if( !IsVisible() ) return;
  2383. if( GetParent() ) {
  2384. CContainerUI* pParentContainer = static_cast<CContainerUI*>(GetParent()->GetInterface(DUI_CTR_CONTAINER));
  2385. if( pParentContainer ) {
  2386. RECT rc = pParentContainer->GetPos();
  2387. RECT rcInset = pParentContainer->GetInset();
  2388. rc.left += rcInset.left;
  2389. rc.top += rcInset.top;
  2390. rc.right -= rcInset.right;
  2391. rc.bottom -= rcInset.bottom;
  2392. CScrollBarUI* pVerticalScrollBar = pParentContainer->GetVerticalScrollBar();
  2393. if( pVerticalScrollBar && pVerticalScrollBar->IsVisible() ) rc.right -= pVerticalScrollBar->GetFixedWidth();
  2394. CScrollBarUI* pHorizontalScrollBar = pParentContainer->GetHorizontalScrollBar();
  2395. if( pHorizontalScrollBar && pHorizontalScrollBar->IsVisible() ) rc.bottom -= pHorizontalScrollBar->GetFixedHeight();
  2396. RECT invalidateRc = m_rcItem;
  2397. if( !::IntersectRect(&invalidateRc, &m_rcItem, &rc) )
  2398. {
  2399. return;
  2400. }
  2401. CControlUI* pParent = GetParent();
  2402. RECT rcTemp;
  2403. RECT rcParent;
  2404. while( pParent = pParent->GetParent() )
  2405. {
  2406. rcTemp = invalidateRc;
  2407. rcParent = pParent->GetPos();
  2408. if( !::IntersectRect(&invalidateRc, &rcTemp, &rcParent) )
  2409. {
  2410. return;
  2411. }
  2412. }
  2413. if( m_pManager != NULL ) m_pManager->Invalidate(invalidateRc);
  2414. }
  2415. else {
  2416. CContainerUI::Invalidate();
  2417. }
  2418. }
  2419. else {
  2420. CContainerUI::Invalidate();
  2421. }
  2422. }
  2423. bool CListContainerElementUI::Activate()
  2424. {
  2425. if( !CContainerUI::Activate() ) return false;
  2426. if( m_pManager != NULL ) m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMACTIVATE);
  2427. return true;
  2428. }
  2429. bool CListContainerElementUI::IsSelected() const
  2430. {
  2431. return m_bSelected;
  2432. }
  2433. bool CListContainerElementUI::Select(bool bSelect, bool bTriggerEvent)
  2434. {
  2435. if( !IsEnabled() ) return false;
  2436. if( bSelect == m_bSelected ) return true;
  2437. m_bSelected = bSelect;
  2438. if( bSelect && m_pOwner != NULL ) m_pOwner->SelectItem(m_iIndex, bTriggerEvent);
  2439. Invalidate();
  2440. return true;
  2441. }
  2442. bool CListContainerElementUI::IsExpandable() const
  2443. {
  2444. return m_bExpandable;
  2445. }
  2446. void CListContainerElementUI::SetExpandable(bool bExpandable)
  2447. {
  2448. m_bExpandable = bExpandable;
  2449. }
  2450. bool CListContainerElementUI::IsExpanded() const
  2451. {
  2452. return m_bExpand;
  2453. }
  2454. bool CListContainerElementUI::Expand(bool bExpand)
  2455. {
  2456. ASSERT(m_pOwner);
  2457. if( m_pOwner == NULL ) return false;
  2458. if( bExpand == m_bExpand ) return true;
  2459. m_bExpand = bExpand;
  2460. if( m_bExpandable ) {
  2461. if( !m_pOwner->ExpandItem(m_iIndex, bExpand) ) return false;
  2462. if( m_pManager != NULL ) {
  2463. if( bExpand ) m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMEXPAND, false);
  2464. else m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMCOLLAPSE, false);
  2465. }
  2466. }
  2467. return true;
  2468. }
  2469. void CListContainerElementUI::DoEvent(TEventUI& event)
  2470. {
  2471. if( !IsMouseEnabled() && event.Type > UIEVENT__MOUSEBEGIN && event.Type < UIEVENT__MOUSEEND ) {
  2472. if( m_pOwner != NULL ) m_pOwner->DoEvent(event);
  2473. else CContainerUI::DoEvent(event);
  2474. return;
  2475. }
  2476. if( event.Type == UIEVENT_DBLCLICK )
  2477. {
  2478. if( IsEnabled() ) {
  2479. Activate();
  2480. Invalidate();
  2481. }
  2482. return;
  2483. }
  2484. if( event.Type == UIEVENT_KEYDOWN )
  2485. {
  2486. if (IsKeyboardEnabled() && IsEnabled()) {
  2487. if( event.chKey == VK_RETURN ) {
  2488. Activate();
  2489. Invalidate();
  2490. return;
  2491. }
  2492. }
  2493. }
  2494. if( event.Type == UIEVENT_BUTTONDOWN || event.Type == UIEVENT_RBUTTONDOWN )
  2495. {
  2496. if( IsEnabled() ) {
  2497. m_pManager->SendNotify(this, DUI_MSGTYPE_ITEMCLICK);
  2498. Select();
  2499. Invalidate();
  2500. }
  2501. return;
  2502. }
  2503. if( event.Type == UIEVENT_BUTTONUP )
  2504. {
  2505. return;
  2506. }
  2507. if( event.Type == UIEVENT_MOUSEMOVE )
  2508. {
  2509. return;
  2510. }
  2511. if( event.Type == UIEVENT_MOUSEENTER )
  2512. {
  2513. if( ::PtInRect(&m_rcItem, event.ptMouse ) ) {
  2514. if( IsEnabled() ) {
  2515. if( (m_uButtonState & UISTATE_HOT) == 0 ) {
  2516. m_uButtonState |= UISTATE_HOT;
  2517. Invalidate();
  2518. }
  2519. }
  2520. }
  2521. }
  2522. if( event.Type == UIEVENT_MOUSELEAVE )
  2523. {
  2524. if( !::PtInRect(&m_rcItem, event.ptMouse ) ) {
  2525. if( IsEnabled() ) {
  2526. if( (m_uButtonState & UISTATE_HOT) != 0 ) {
  2527. m_uButtonState &= ~UISTATE_HOT;
  2528. Invalidate();
  2529. }
  2530. }
  2531. if (m_pManager) m_pManager->RemoveMouseLeaveNeeded(this);
  2532. }
  2533. else {
  2534. if (m_pManager) m_pManager->AddMouseLeaveNeeded(this);
  2535. return;
  2536. }
  2537. }
  2538. // An important twist: The list-item will send the event not to its immediate
  2539. // parent but to the "attached" list. A list may actually embed several components
  2540. // in its path to the item, but key-presses etc. needs to go to the actual list.
  2541. if( m_pOwner != NULL ) m_pOwner->DoEvent(event); else CControlUI::DoEvent(event);
  2542. }
  2543. void CListContainerElementUI::SetAttribute(LPCTSTR pstrName, LPCTSTR pstrValue)
  2544. {
  2545. if( _tcscmp(pstrName, _T("selected")) == 0 ) Select();
  2546. else if( _tcscmp(pstrName, _T("expandable")) == 0 ) SetExpandable(_tcscmp(pstrValue, _T("true")) == 0);
  2547. else CContainerUI::SetAttribute(pstrName, pstrValue);
  2548. }
  2549. bool CListContainerElementUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
  2550. {
  2551. DrawItemBk(hDC, m_rcItem);
  2552. return CContainerUI::DoPaint(hDC, rcPaint, pStopControl);
  2553. }
  2554. void CListContainerElementUI::DrawItemText(HDC hDC, const RECT& rcItem)
  2555. {
  2556. return;
  2557. }
  2558. void CListContainerElementUI::DrawItemBk(HDC hDC, const RECT& rcItem)
  2559. {
  2560. ASSERT(m_pOwner);
  2561. if( m_pOwner == NULL ) return;
  2562. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  2563. if( pInfo == NULL ) return;
  2564. DWORD iBackColor = 0;
  2565. if( !pInfo->bAlternateBk || m_iDrawIndex % 2 == 0 ) iBackColor = pInfo->dwBkColor;
  2566. if( (m_uButtonState & UISTATE_HOT) != 0 ) {
  2567. iBackColor = pInfo->dwHotBkColor;
  2568. }
  2569. if( IsSelected() ) {
  2570. iBackColor = pInfo->dwSelectedBkColor;
  2571. }
  2572. if( !IsEnabled() ) {
  2573. iBackColor = pInfo->dwDisabledBkColor;
  2574. }
  2575. if ( iBackColor != 0 ) {
  2576. CRenderEngine::DrawColor(hDC, m_rcItem, GetAdjustColor(iBackColor));
  2577. }
  2578. if( !IsEnabled() ) {
  2579. if( DrawImage(hDC, pInfo->diDisabled) ) return;
  2580. }
  2581. if( IsSelected() ) {
  2582. if( DrawImage(hDC, pInfo->diSelected) ) return;
  2583. }
  2584. if( (m_uButtonState & UISTATE_HOT) != 0 ) {
  2585. if( DrawImage(hDC, pInfo->diHot) ) return;
  2586. }
  2587. if( !DrawImage(hDC, m_diBk) ) {
  2588. if( !pInfo->bAlternateBk || m_iDrawIndex % 2 == 0 ) {
  2589. if( DrawImage(hDC, pInfo->diBk) ) return;
  2590. }
  2591. }
  2592. }
  2593. SIZE CListContainerElementUI::EstimateSize(SIZE szAvailable)
  2594. {
  2595. TListInfoUI* pInfo = NULL;
  2596. if( m_pOwner ) pInfo = m_pOwner->GetListInfo();
  2597. SIZE cXY = m_cxyFixed;
  2598. if( cXY.cy == 0 ) {
  2599. cXY.cy = pInfo->uFixedHeight;
  2600. }
  2601. return cXY;
  2602. }
  2603. /////////////////////////////////////////////////////////////////////////////////////
  2604. //
  2605. //
  2606. CListHBoxElementUI::CListHBoxElementUI()
  2607. {
  2608. }
  2609. LPCTSTR CListHBoxElementUI::GetClass() const
  2610. {
  2611. return DUI_CTR_LISTHBOXELEMENT;
  2612. }
  2613. LPVOID CListHBoxElementUI::GetInterface(LPCTSTR pstrName)
  2614. {
  2615. if( _tcscmp(pstrName, DUI_CTR_LISTHBOXELEMENT) == 0 ) return static_cast<CListHBoxElementUI*>(this);
  2616. return CListContainerElementUI::GetInterface(pstrName);
  2617. }
  2618. void CListHBoxElementUI::SetPos(RECT rc, bool bNeedInvalidate)
  2619. {
  2620. if( m_pOwner == NULL ) return CListContainerElementUI::SetPos(rc, bNeedInvalidate);
  2621. CControlUI::SetPos(rc, bNeedInvalidate);
  2622. rc = m_rcItem;
  2623. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  2624. if (pInfo == NULL) return;
  2625. if (pInfo->nColumns > 0) {
  2626. int iColumnIndex = 0;
  2627. for( int it2 = 0; it2 < m_items.GetSize(); it2++ ) {
  2628. CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
  2629. if( !pControl->IsVisible() ) continue;
  2630. if( pControl->IsFloat() ) {
  2631. SetFloatPos(it2);
  2632. continue;
  2633. }
  2634. if( iColumnIndex >= pInfo->nColumns ) continue;
  2635. RECT rcPadding = pControl->GetPadding();
  2636. RECT rcItem = { pInfo->rcColumn[iColumnIndex].left + rcPadding.left, m_rcItem.top + rcPadding.top,
  2637. pInfo->rcColumn[iColumnIndex].right - rcPadding.right, m_rcItem.bottom - rcPadding.bottom };
  2638. if (pInfo->iVLineSize > 0 && iColumnIndex < pInfo->nColumns - 1) {
  2639. rcItem.right -= pInfo->iVLineSize;
  2640. }
  2641. pControl->SetPos(rcItem, false);
  2642. iColumnIndex += 1;
  2643. }
  2644. }
  2645. else {
  2646. for( int it2 = 0; it2 < m_items.GetSize(); it2++ ) {
  2647. CControlUI* pControl = static_cast<CControlUI*>(m_items[it2]);
  2648. if( !pControl->IsVisible() ) continue;
  2649. if( pControl->IsFloat() ) {
  2650. SetFloatPos(it2);
  2651. continue;
  2652. }
  2653. RECT rcPadding = pControl->GetPadding();
  2654. RECT rcItem = { m_rcItem.left + rcPadding.left, m_rcItem.top + rcPadding.top,
  2655. m_rcItem.right - rcPadding.right, m_rcItem.bottom - rcPadding.bottom };
  2656. pControl->SetPos(rcItem, false);
  2657. }
  2658. }
  2659. }
  2660. bool CListHBoxElementUI::DoPaint(HDC hDC, const RECT& rcPaint, CControlUI* pStopControl)
  2661. {
  2662. ASSERT(m_pOwner);
  2663. if( m_pOwner == NULL ) return true;
  2664. TListInfoUI* pInfo = m_pOwner->GetListInfo();
  2665. if( pInfo == NULL ) return true;
  2666. DrawItemBk(hDC, m_rcItem);
  2667. for( int i = 0; i < pInfo->nColumns; i++ ) {
  2668. RECT rcItem = { pInfo->rcColumn[i].left, m_rcItem.top, pInfo->rcColumn[i].right, m_rcItem.bottom };
  2669. if (pInfo->iVLineSize > 0 && i < pInfo->nColumns - 1) {
  2670. RECT rcLine = { rcItem.right - pInfo->iVLineSize / 2, rcItem.top, rcItem.right - pInfo->iVLineSize / 2, rcItem.bottom};
  2671. CRenderEngine::DrawLine(hDC, rcLine, pInfo->iVLineSize, GetAdjustColor(pInfo->dwVLineColor));
  2672. }
  2673. }
  2674. return CContainerUI::DoPaint(hDC, rcPaint, pStopControl);
  2675. }
  2676. } // namespace DuiLib