atlframe.h 101 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577
  1. // Windows Template Library - WTL version 10.0
  2. // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
  3. //
  4. // This file is a part of the Windows Template Library.
  5. // The use and distribution terms for this software are covered by the
  6. // Microsoft Public License (http://opensource.org/licenses/MS-PL)
  7. // which can be found in the file MS-PL.txt at the root folder.
  8. #ifndef __ATLFRAME_H__
  9. #define __ATLFRAME_H__
  10. #pragma once
  11. #ifndef __ATLAPP_H__
  12. #error atlframe.h requires atlapp.h to be included first
  13. #endif
  14. #ifndef __ATLWIN_H__
  15. #error atlframe.h requires atlwin.h to be included first
  16. #endif
  17. ///////////////////////////////////////////////////////////////////////////////
  18. // Classes in this file:
  19. //
  20. // CFrameWindowImpl<T, TBase, TWinTraits>
  21. // CMDIWindow
  22. // CMDIFrameWindowImpl<T, TBase, TWinTraits>
  23. // CMDIChildWindowImpl<T, TBase, TWinTraits>
  24. // COwnerDraw<T>
  25. // CUpdateUIBase
  26. // CUpdateUI<T>
  27. // CDynamicUpdateUI<T>
  28. // CAutoUpdateUI<T>
  29. // CDialogResize<T>
  30. // CDynamicDialogLayout<T>
  31. // CDoubleBufferImpl<T>
  32. // CDoubleBufferWindowImpl<T, TBase, TWinTraits>
  33. //
  34. // Global functions:
  35. // AtlCreateSimpleToolBar()
  36. namespace WTL
  37. {
  38. ///////////////////////////////////////////////////////////////////////////////
  39. // CFrameWndClassInfo - Manages frame window Windows class information
  40. class CFrameWndClassInfo
  41. {
  42. public:
  43. enum { cchAutoName = 5 + sizeof(void*) * 2 }; // sizeof(void*) * 2 is the number of digits %p outputs
  44. WNDCLASSEX m_wc;
  45. LPCTSTR m_lpszOrigName;
  46. WNDPROC pWndProc;
  47. LPCTSTR m_lpszCursorID;
  48. BOOL m_bSystemCursor;
  49. ATOM m_atom;
  50. TCHAR m_szAutoName[cchAutoName];
  51. UINT m_uCommonResourceID;
  52. ATOM Register(WNDPROC* pProc)
  53. {
  54. if (m_atom == 0)
  55. {
  56. CWindowCreateCriticalSectionLock lock;
  57. if(FAILED(lock.Lock()))
  58. {
  59. ATLTRACE2(atlTraceUI, 0, _T("ERROR : Unable to lock critical section in CFrameWndClassInfo::Register.\n"));
  60. ATLASSERT(FALSE);
  61. return 0;
  62. }
  63. if(m_atom == 0)
  64. {
  65. HINSTANCE hInst = ModuleHelper::GetModuleInstance();
  66. if (m_lpszOrigName != NULL)
  67. {
  68. ATLASSERT(pProc != NULL);
  69. LPCTSTR lpsz = m_wc.lpszClassName;
  70. WNDPROC proc = m_wc.lpfnWndProc;
  71. WNDCLASSEX wc = { sizeof(WNDCLASSEX) };
  72. // try process local class first
  73. if(!::GetClassInfoEx(ModuleHelper::GetModuleInstance(), m_lpszOrigName, &wc))
  74. {
  75. // try global class
  76. if(!::GetClassInfoEx(NULL, m_lpszOrigName, &wc))
  77. {
  78. lock.Unlock();
  79. return 0;
  80. }
  81. }
  82. m_wc = wc;
  83. pWndProc = m_wc.lpfnWndProc;
  84. m_wc.lpszClassName = lpsz;
  85. m_wc.lpfnWndProc = proc;
  86. }
  87. else
  88. {
  89. m_wc.hCursor = ::LoadCursor(m_bSystemCursor ? NULL : hInst, m_lpszCursorID);
  90. }
  91. m_wc.hInstance = hInst;
  92. m_wc.style &= ~CS_GLOBALCLASS; // we don't register global classes
  93. if (m_wc.lpszClassName == NULL)
  94. {
  95. _stprintf_s(m_szAutoName, cchAutoName, _T("ATL:%p"), &m_wc);
  96. m_wc.lpszClassName = m_szAutoName;
  97. }
  98. WNDCLASSEX wcTemp = m_wc;
  99. m_atom = (ATOM)::GetClassInfoEx(m_wc.hInstance, m_wc.lpszClassName, &wcTemp);
  100. if (m_atom == 0)
  101. {
  102. if(m_uCommonResourceID != 0) // use it if not zero
  103. {
  104. m_wc.hIcon = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(),
  105. MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON,
  106. ::GetSystemMetrics(SM_CXICON), ::GetSystemMetrics(SM_CYICON), LR_DEFAULTCOLOR);
  107. m_wc.hIconSm = (HICON)::LoadImage(ModuleHelper::GetResourceInstance(),
  108. MAKEINTRESOURCE(m_uCommonResourceID), IMAGE_ICON,
  109. ::GetSystemMetrics(SM_CXSMICON), ::GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
  110. }
  111. m_atom = ::RegisterClassEx(&m_wc);
  112. }
  113. }
  114. lock.Unlock();
  115. }
  116. if (m_lpszOrigName != NULL)
  117. {
  118. ATLASSERT(pProc != NULL);
  119. ATLASSERT(pWndProc != NULL);
  120. *pProc = pWndProc;
  121. }
  122. return m_atom;
  123. }
  124. };
  125. ///////////////////////////////////////////////////////////////////////////////
  126. // Macros for declaring frame window WNDCLASS
  127. #define DECLARE_FRAME_WND_CLASS(WndClassName, uCommonResourceID) \
  128. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  129. { \
  130. static WTL::CFrameWndClassInfo wc = \
  131. { \
  132. { sizeof(WNDCLASSEX), 0, StartWindowProc, \
  133. 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
  134. NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  135. }; \
  136. return wc; \
  137. }
  138. #define DECLARE_FRAME_WND_CLASS_EX(WndClassName, uCommonResourceID, style, bkgnd) \
  139. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  140. { \
  141. static WTL::CFrameWndClassInfo wc = \
  142. { \
  143. { sizeof(WNDCLASSEX), style, StartWindowProc, \
  144. 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \
  145. NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  146. }; \
  147. return wc; \
  148. }
  149. #define DECLARE_FRAME_WND_SUPERCLASS(WndClassName, OrigWndClassName, uCommonResourceID) \
  150. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  151. { \
  152. static WTL::CFrameWndClassInfo wc = \
  153. { \
  154. { sizeof(WNDCLASSEX), 0, StartWindowProc, \
  155. 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \
  156. OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \
  157. }; \
  158. return wc; \
  159. }
  160. // These are for templated classes
  161. #define DECLARE_FRAME_WND_CLASS2(WndClassName, EnclosingClass, uCommonResourceID) \
  162. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  163. { \
  164. static WTL::CFrameWndClassInfo wc = \
  165. { \
  166. { sizeof(WNDCLASSEX), 0, EnclosingClass::StartWindowProc, \
  167. 0, 0, NULL, NULL, NULL, (HBRUSH)(COLOR_WINDOW + 1), NULL, WndClassName, NULL }, \
  168. NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  169. }; \
  170. return wc; \
  171. }
  172. #define DECLARE_FRAME_WND_CLASS_EX2(WndClassName, EnclosingClass, uCommonResourceID, style, bkgnd) \
  173. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  174. { \
  175. static WTL::CFrameWndClassInfo wc = \
  176. { \
  177. { sizeof(WNDCLASSEX), style, EnclosingClass::StartWindowProc, \
  178. 0, 0, NULL, NULL, NULL, (HBRUSH)(bkgnd + 1), NULL, WndClassName, NULL }, \
  179. NULL, NULL, IDC_ARROW, TRUE, 0, _T(""), uCommonResourceID \
  180. }; \
  181. return wc; \
  182. }
  183. #define DECLARE_FRAME_WND_SUPERCLASS2(WndClassName, EnclosingClass, OrigWndClassName, uCommonResourceID) \
  184. static WTL::CFrameWndClassInfo& GetWndClassInfo() \
  185. { \
  186. static WTL::CFrameWndClassInfo wc = \
  187. { \
  188. { sizeof(WNDCLASSEX), 0, EnclosingClass::StartWindowProc, \
  189. 0, 0, NULL, NULL, NULL, NULL, NULL, WndClassName, NULL }, \
  190. OrigWndClassName, NULL, NULL, TRUE, 0, _T(""), uCommonResourceID \
  191. }; \
  192. return wc; \
  193. }
  194. ///////////////////////////////////////////////////////////////////////////////
  195. // CFrameWindowImpl
  196. // Client window command chaining macro (only for frame windows)
  197. #define CHAIN_CLIENT_COMMANDS() \
  198. if((uMsg == WM_COMMAND) && (this->m_hWndClient != NULL)) \
  199. ::SendMessage(this->m_hWndClient, uMsg, wParam, lParam);
  200. // standard toolbar styles
  201. #define ATL_SIMPLE_TOOLBAR_STYLE \
  202. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | TBSTYLE_TOOLTIPS)
  203. // toolbar in a rebar pane
  204. #define ATL_SIMPLE_TOOLBAR_PANE_STYLE \
  205. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT)
  206. // standard rebar styles
  207. #define ATL_SIMPLE_REBAR_STYLE \
  208. (WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE)
  209. // rebar without borders
  210. #define ATL_SIMPLE_REBAR_NOBORDER_STYLE \
  211. (WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | RBS_VARHEIGHT | RBS_BANDBORDERS | RBS_AUTOSIZE | CCS_NODIVIDER)
  212. // command bar support
  213. #if !defined(__ATLCTRLW_H__)
  214. #define CBRM_GETCMDBAR (WM_USER + 301) // returns command bar HWND
  215. #define CBRM_GETMENU (WM_USER + 302) // returns loaded or attached menu
  216. #define CBRM_TRACKPOPUPMENU (WM_USER + 303) // displays a popup menu
  217. struct _AtlFrameWnd_CmdBarPopupMenu
  218. {
  219. int cbSize;
  220. HMENU hMenu;
  221. UINT uFlags;
  222. int x;
  223. int y;
  224. LPTPMPARAMS lptpm;
  225. };
  226. #define CBRPOPUPMENU _AtlFrameWnd_CmdBarPopupMenu
  227. #endif // !defined(__ATLCTRLW_H__)
  228. template <class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>
  229. class ATL_NO_VTABLE CFrameWindowImplBase : public ATL::CWindowImplBaseT< TBase, TWinTraits >
  230. {
  231. public:
  232. typedef CFrameWindowImplBase<TBase, TWinTraits > _thisClass;
  233. DECLARE_FRAME_WND_CLASS2(NULL, _thisClass, 0)
  234. struct _ChevronMenuInfo
  235. {
  236. HMENU hMenu;
  237. LPNMREBARCHEVRON lpnm;
  238. bool bCmdBar;
  239. };
  240. // Data members
  241. HWND m_hWndToolBar;
  242. HWND m_hWndStatusBar;
  243. HWND m_hWndClient;
  244. HACCEL m_hAccel;
  245. // Constructor
  246. CFrameWindowImplBase() :
  247. m_hWndToolBar(NULL),
  248. m_hWndStatusBar(NULL),
  249. m_hWndClient(NULL),
  250. m_hAccel(NULL)
  251. { }
  252. // Methods
  253. HWND Create(HWND hWndParent, ATL::_U_RECT rect, LPCTSTR szWindowName, DWORD dwStyle, DWORD dwExStyle, ATL::_U_MENUorID MenuOrID, ATOM atom, LPVOID lpCreateParam)
  254. {
  255. ATLASSERT(this->m_hWnd == NULL);
  256. // Allocate the thunk structure here, where we can fail gracefully.
  257. BOOL bRet = this->m_thunk.Init(NULL, NULL);
  258. if(bRet == FALSE)
  259. {
  260. ::SetLastError(ERROR_OUTOFMEMORY);
  261. return NULL;
  262. }
  263. if(atom == 0)
  264. return NULL;
  265. ModuleHelper::AddCreateWndData(&this->m_thunk.cd, this);
  266. if((MenuOrID.m_hMenu == NULL) && (dwStyle & WS_CHILD))
  267. MenuOrID.m_hMenu = (HMENU)(UINT_PTR)this;
  268. if(rect.m_lpRect == NULL)
  269. rect.m_lpRect = &TBase::rcDefault;
  270. HWND hWnd = ::CreateWindowEx(dwExStyle, MAKEINTATOM(atom), szWindowName,
  271. dwStyle, rect.m_lpRect->left, rect.m_lpRect->top, rect.m_lpRect->right - rect.m_lpRect->left,
  272. rect.m_lpRect->bottom - rect.m_lpRect->top, hWndParent, MenuOrID.m_hMenu,
  273. ModuleHelper::GetModuleInstance(), lpCreateParam);
  274. ATLASSERT((hWnd == NULL) || (this->m_hWnd == hWnd));
  275. return hWnd;
  276. }
  277. static HWND CreateSimpleToolBarCtrl(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE,
  278. DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  279. {
  280. HINSTANCE hInst = ModuleHelper::GetResourceInstance();
  281. HRSRC hRsrc = ::FindResource(hInst, MAKEINTRESOURCE(nResourceID), RT_TOOLBAR);
  282. if (hRsrc == NULL)
  283. return NULL;
  284. HGLOBAL hGlobal = ::LoadResource(hInst, hRsrc);
  285. if (hGlobal == NULL)
  286. return NULL;
  287. _AtlToolBarData* pData = (_AtlToolBarData*)::LockResource(hGlobal);
  288. if (pData == NULL)
  289. return NULL;
  290. ATLASSERT(pData->wVersion == 1);
  291. WORD* pItems = pData->items();
  292. int nItems = pData->wItemCount + (bInitialSeparator ? 1 : 0);
  293. ATL::CTempBuffer<TBBUTTON, _WTL_STACK_ALLOC_THRESHOLD> buff;
  294. TBBUTTON* pTBBtn = buff.Allocate(nItems);
  295. ATLASSERT(pTBBtn != NULL);
  296. if(pTBBtn == NULL)
  297. return NULL;
  298. const int cxSeparator = 8;
  299. // set initial separator (half width)
  300. if(bInitialSeparator)
  301. {
  302. pTBBtn[0].iBitmap = cxSeparator / 2;
  303. pTBBtn[0].idCommand = 0;
  304. pTBBtn[0].fsState = 0;
  305. pTBBtn[0].fsStyle = BTNS_SEP;
  306. pTBBtn[0].dwData = 0;
  307. pTBBtn[0].iString = 0;
  308. }
  309. int nBmp = 0;
  310. for(int i = 0, j = bInitialSeparator ? 1 : 0; i < pData->wItemCount; i++, j++)
  311. {
  312. if(pItems[i] != 0)
  313. {
  314. pTBBtn[j].iBitmap = nBmp++;
  315. pTBBtn[j].idCommand = pItems[i];
  316. pTBBtn[j].fsState = TBSTATE_ENABLED;
  317. pTBBtn[j].fsStyle = BTNS_BUTTON;
  318. pTBBtn[j].dwData = 0;
  319. pTBBtn[j].iString = 0;
  320. }
  321. else
  322. {
  323. pTBBtn[j].iBitmap = cxSeparator;
  324. pTBBtn[j].idCommand = 0;
  325. pTBBtn[j].fsState = 0;
  326. pTBBtn[j].fsStyle = BTNS_SEP;
  327. pTBBtn[j].dwData = 0;
  328. pTBBtn[j].iString = 0;
  329. }
  330. }
  331. HWND hWnd = ::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL);
  332. if(hWnd == NULL)
  333. {
  334. ATLASSERT(FALSE);
  335. return NULL;
  336. }
  337. ::SendMessage(hWnd, TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON), 0L);
  338. // check if font is taller than our bitmaps
  339. CFontHandle font = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L);
  340. if(font.IsNull())
  341. font = (HFONT)::GetStockObject(SYSTEM_FONT);
  342. LOGFONT lf = {};
  343. font.GetLogFont(lf);
  344. WORD cyFontHeight = (WORD)abs(lf.lfHeight);
  345. WORD bitsPerPixel = AtlGetBitmapResourceBitsPerPixel(nResourceID);
  346. if(bitsPerPixel > 4)
  347. {
  348. COLORREF crMask = CLR_DEFAULT;
  349. if(bitsPerPixel == 32)
  350. {
  351. // 32-bit color bitmap with alpha channel (valid for Windows XP and later)
  352. crMask = CLR_NONE;
  353. }
  354. HIMAGELIST hImageList = ImageList_LoadImage(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nResourceID), pData->wWidth, 1, crMask, IMAGE_BITMAP, LR_CREATEDIBSECTION | LR_DEFAULTSIZE);
  355. ATLASSERT(hImageList != NULL);
  356. ::SendMessage(hWnd, TB_SETIMAGELIST, 0, (LPARAM)hImageList);
  357. }
  358. else
  359. {
  360. TBADDBITMAP tbab = {};
  361. tbab.hInst = hInst;
  362. tbab.nID = nResourceID;
  363. ::SendMessage(hWnd, TB_ADDBITMAP, nBmp, (LPARAM)&tbab);
  364. }
  365. ::SendMessage(hWnd, TB_ADDBUTTONS, nItems, (LPARAM)pTBBtn);
  366. ::SendMessage(hWnd, TB_SETBITMAPSIZE, 0, MAKELONG(pData->wWidth, __max(pData->wHeight, cyFontHeight)));
  367. const int cxyButtonMargin = 7;
  368. ::SendMessage(hWnd, TB_SETBUTTONSIZE, 0, MAKELONG(pData->wWidth + cxyButtonMargin, __max(pData->wHeight, cyFontHeight) + cxyButtonMargin));
  369. return hWnd;
  370. }
  371. static HWND CreateSimpleReBarCtrl(HWND hWndParent, DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  372. {
  373. // Ensure style combinations for proper rebar painting
  374. if(dwStyle & CCS_NODIVIDER && (dwStyle & WS_BORDER))
  375. dwStyle &= ~WS_BORDER;
  376. else if(!(dwStyle & WS_BORDER) && !(dwStyle & CCS_NODIVIDER))
  377. dwStyle |= CCS_NODIVIDER;
  378. // Create rebar window
  379. HWND hWndReBar = ::CreateWindowEx(0, REBARCLASSNAME, NULL, dwStyle, 0, 0, 100, 100, hWndParent, (HMENU)LongToHandle(nID), ModuleHelper::GetModuleInstance(), NULL);
  380. if(hWndReBar == NULL)
  381. {
  382. ATLTRACE2(atlTraceUI, 0, _T("Failed to create rebar.\n"));
  383. return NULL;
  384. }
  385. // Initialize and send the REBARINFO structure
  386. REBARINFO rbi = { sizeof(REBARINFO), 0 };
  387. if(::SendMessage(hWndReBar, RB_SETBARINFO, 0, (LPARAM)&rbi) == 0)
  388. {
  389. ATLTRACE2(atlTraceUI, 0, _T("Failed to initialize rebar.\n"));
  390. ::DestroyWindow(hWndReBar);
  391. return NULL;
  392. }
  393. return hWndReBar;
  394. }
  395. BOOL CreateSimpleReBar(DWORD dwStyle = ATL_SIMPLE_REBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  396. {
  397. ATLASSERT(!::IsWindow(m_hWndToolBar));
  398. m_hWndToolBar = CreateSimpleReBarCtrl(this->m_hWnd, dwStyle, nID);
  399. return (m_hWndToolBar != NULL);
  400. }
  401. static BOOL AddSimpleReBarBandCtrl(HWND hWndReBar, HWND hWndBand, int nID = 0, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)
  402. {
  403. ATLASSERT(::IsWindow(hWndReBar)); // must be already created
  404. #ifdef _DEBUG
  405. // block - check if this is really a rebar
  406. {
  407. TCHAR lpszClassName[sizeof(REBARCLASSNAME)] = {};
  408. ::GetClassName(hWndReBar, lpszClassName, sizeof(REBARCLASSNAME));
  409. ATLASSERT(lstrcmp(lpszClassName, REBARCLASSNAME) == 0);
  410. }
  411. #endif // _DEBUG
  412. ATLASSERT(::IsWindow(hWndBand)); // must be already created
  413. // Get number of buttons on the toolbar
  414. int nBtnCount = (int)::SendMessage(hWndBand, TB_BUTTONCOUNT, 0, 0L);
  415. // Set band info structure
  416. REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() };
  417. rbBand.fMask = RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_STYLE | RBBIM_ID | RBBIM_SIZE | RBBIM_IDEALSIZE;
  418. if(lpstrTitle != NULL)
  419. rbBand.fMask |= RBBIM_TEXT;
  420. rbBand.fStyle = RBBS_CHILDEDGE;
  421. if(nBtnCount > 0) // add chevron style for toolbar with buttons
  422. rbBand.fStyle |= RBBS_USECHEVRON;
  423. if(bNewRow)
  424. rbBand.fStyle |= RBBS_BREAK;
  425. rbBand.lpText = (LPTSTR)lpstrTitle;
  426. rbBand.hwndChild = hWndBand;
  427. if(nID == 0) // calc band ID
  428. nID = ATL_IDW_BAND_FIRST + (int)::SendMessage(hWndReBar, RB_GETBANDCOUNT, 0, 0L);
  429. rbBand.wID = nID;
  430. // Calculate the size of the band
  431. BOOL bRet = FALSE;
  432. RECT rcTmp = {};
  433. if(nBtnCount > 0)
  434. {
  435. bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, nBtnCount - 1, (LPARAM)&rcTmp);
  436. ATLASSERT(bRet);
  437. rbBand.cx = (cxWidth != 0) ? cxWidth : rcTmp.right;
  438. rbBand.cyMinChild = rcTmp.bottom - rcTmp.top;
  439. if(bFullWidthAlways)
  440. {
  441. rbBand.cxMinChild = rbBand.cx;
  442. }
  443. else if(lpstrTitle == NULL)
  444. {
  445. bRet = (BOOL)::SendMessage(hWndBand, TB_GETITEMRECT, 0, (LPARAM)&rcTmp);
  446. ATLASSERT(bRet);
  447. rbBand.cxMinChild = rcTmp.right;
  448. }
  449. else
  450. {
  451. rbBand.cxMinChild = 0;
  452. }
  453. }
  454. else // no buttons, either not a toolbar or really has no buttons
  455. {
  456. bRet = ::GetWindowRect(hWndBand, &rcTmp);
  457. ATLASSERT(bRet);
  458. rbBand.cx = (cxWidth != 0) ? cxWidth : (rcTmp.right - rcTmp.left);
  459. rbBand.cxMinChild = bFullWidthAlways ? rbBand.cx : 0;
  460. rbBand.cyMinChild = rcTmp.bottom - rcTmp.top;
  461. }
  462. rbBand.cxIdeal = rbBand.cx;
  463. // Add the band
  464. LRESULT lRes = ::SendMessage(hWndReBar, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
  465. if(lRes == 0)
  466. {
  467. ATLTRACE2(atlTraceUI, 0, _T("Failed to add a band to the rebar.\n"));
  468. return FALSE;
  469. }
  470. DWORD dwExStyle = (DWORD)::SendMessage(hWndBand, TB_GETEXTENDEDSTYLE, 0, 0L);
  471. ::SendMessage(hWndBand, TB_SETEXTENDEDSTYLE, 0, dwExStyle | TBSTYLE_EX_HIDECLIPPEDBUTTONS);
  472. return TRUE;
  473. }
  474. BOOL AddSimpleReBarBand(HWND hWndBand, LPCTSTR lpstrTitle = NULL, BOOL bNewRow = FALSE, int cxWidth = 0, BOOL bFullWidthAlways = FALSE)
  475. {
  476. ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar
  477. ATLASSERT(::IsWindow(hWndBand)); // must be created
  478. return AddSimpleReBarBandCtrl(m_hWndToolBar, hWndBand, 0, lpstrTitle, bNewRow, cxWidth, bFullWidthAlways);
  479. }
  480. void SizeSimpleReBarBands()
  481. {
  482. ATLASSERT(::IsWindow(m_hWndToolBar)); // must be an existing rebar
  483. int nCount = (int)::SendMessage(m_hWndToolBar, RB_GETBANDCOUNT, 0, 0L);
  484. for(int i = 0; i < nCount; i++)
  485. {
  486. REBARBANDINFO rbBand = { RunTimeHelper::SizeOf_REBARBANDINFO() };
  487. rbBand.fMask = RBBIM_SIZE;
  488. BOOL bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_GETBANDINFO, i, (LPARAM)&rbBand);
  489. ATLASSERT(bRet);
  490. RECT rect = {};
  491. ::SendMessage(m_hWndToolBar, RB_GETBANDBORDERS, i, (LPARAM)&rect);
  492. rbBand.cx += rect.left + rect.right;
  493. bRet = (BOOL)::SendMessage(m_hWndToolBar, RB_SETBANDINFO, i, (LPARAM)&rbBand);
  494. ATLASSERT(bRet);
  495. }
  496. }
  497. BOOL CreateSimpleStatusBar(LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
  498. {
  499. ATLASSERT(!::IsWindow(m_hWndStatusBar));
  500. m_hWndStatusBar = ::CreateStatusWindow(dwStyle, lpstrText, this->m_hWnd, nID);
  501. return (m_hWndStatusBar != NULL);
  502. }
  503. BOOL CreateSimpleStatusBar(UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
  504. {
  505. const int cchMax = 128; // max text length is 127 for status bars (+1 for null)
  506. TCHAR szText[cchMax] = {};
  507. ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax);
  508. return CreateSimpleStatusBar(szText, dwStyle, nID);
  509. }
  510. void UpdateLayout(BOOL bResizeBars = TRUE)
  511. {
  512. RECT rect = {};
  513. this->GetClientRect(&rect);
  514. // position bars and offset their dimensions
  515. UpdateBarsPosition(rect, bResizeBars);
  516. // resize client window
  517. if(m_hWndClient != NULL)
  518. ::SetWindowPos(m_hWndClient, NULL, rect.left, rect.top,
  519. rect.right - rect.left, rect.bottom - rect.top,
  520. SWP_NOZORDER | SWP_NOACTIVATE);
  521. }
  522. void UpdateBarsPosition(RECT& rect, BOOL bResizeBars = TRUE)
  523. {
  524. // resize toolbar
  525. if((m_hWndToolBar != NULL) && ((DWORD)::GetWindowLong(m_hWndToolBar, GWL_STYLE) & WS_VISIBLE))
  526. {
  527. if(bResizeBars != FALSE)
  528. {
  529. ::SendMessage(m_hWndToolBar, WM_SIZE, 0, 0);
  530. ::InvalidateRect(m_hWndToolBar, NULL, TRUE);
  531. }
  532. RECT rectTB = {};
  533. ::GetWindowRect(m_hWndToolBar, &rectTB);
  534. rect.top += rectTB.bottom - rectTB.top;
  535. }
  536. // resize status bar
  537. if((m_hWndStatusBar != NULL) && ((DWORD)::GetWindowLong(m_hWndStatusBar, GWL_STYLE) & WS_VISIBLE))
  538. {
  539. if(bResizeBars != FALSE)
  540. ::SendMessage(m_hWndStatusBar, WM_SIZE, 0, 0);
  541. RECT rectSB = {};
  542. ::GetWindowRect(m_hWndStatusBar, &rectSB);
  543. rect.bottom -= rectSB.bottom - rectSB.top;
  544. }
  545. }
  546. BOOL PreTranslateMessage(MSG* pMsg)
  547. {
  548. if((m_hAccel != NULL) && ::TranslateAccelerator(this->m_hWnd, m_hAccel, pMsg))
  549. return TRUE;
  550. return FALSE;
  551. }
  552. BEGIN_MSG_MAP(CFrameWindowImplBase)
  553. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  554. MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
  555. MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  556. MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
  557. NOTIFY_CODE_HANDLER(TTN_GETDISPINFOA, OnToolTipTextA)
  558. NOTIFY_CODE_HANDLER(TTN_GETDISPINFOW, OnToolTipTextW)
  559. END_MSG_MAP()
  560. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  561. {
  562. if(m_hWndClient != NULL) // view will paint itself instead
  563. return 1;
  564. bHandled = FALSE;
  565. return 0;
  566. }
  567. LRESULT OnMenuSelect(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
  568. {
  569. bHandled = FALSE;
  570. if(m_hWndStatusBar == NULL)
  571. return 1;
  572. WORD wFlags = HIWORD(wParam);
  573. if((wFlags == 0xFFFF) && (lParam == NULL)) // menu closing
  574. {
  575. ::SendMessage(m_hWndStatusBar, SB_SIMPLE, FALSE, 0L);
  576. }
  577. else
  578. {
  579. const int cchBuff = 256;
  580. TCHAR szBuff[cchBuff] = {};
  581. if(!(wFlags & MF_POPUP))
  582. {
  583. WORD wID = LOWORD(wParam);
  584. // check for special cases
  585. if((wID >= 0xF000) && (wID < 0xF1F0)) // system menu IDs
  586. wID = (WORD)(((wID - 0xF000) >> 4) + ATL_IDS_SCFIRST);
  587. else if((wID >= ID_FILE_MRU_FIRST) && (wID <= ID_FILE_MRU_LAST)) // MRU items
  588. wID = ATL_IDS_MRU_FILE;
  589. else if((wID >= ATL_IDM_FIRST_MDICHILD) && (wID <= ATL_IDM_LAST_MDICHILD)) // MDI child windows
  590. wID = ATL_IDS_MDICHILD;
  591. int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), wID, szBuff, cchBuff);
  592. for(int i = 0; i < nRet; i++)
  593. {
  594. if(szBuff[i] == _T('\n'))
  595. {
  596. szBuff[i] = 0;
  597. break;
  598. }
  599. }
  600. }
  601. ::SendMessage(m_hWndStatusBar, SB_SIMPLE, TRUE, 0L);
  602. ::SendMessage(m_hWndStatusBar, SB_SETTEXT, (255 | SBT_NOBORDERS), (LPARAM)szBuff);
  603. }
  604. return 1;
  605. }
  606. LRESULT OnSetFocus(UINT, WPARAM, LPARAM, BOOL& bHandled)
  607. {
  608. if(m_hWndClient != NULL)
  609. ::SetFocus(m_hWndClient);
  610. bHandled = FALSE;
  611. return 1;
  612. }
  613. LRESULT OnDestroy(UINT, WPARAM, LPARAM, BOOL& bHandled)
  614. {
  615. if((this->GetStyle() & (WS_CHILD | WS_POPUP)) == 0)
  616. ::PostQuitMessage(1);
  617. bHandled = FALSE;
  618. return 1;
  619. }
  620. LRESULT OnToolTipTextA(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)
  621. {
  622. LPNMTTDISPINFOA pDispInfo = (LPNMTTDISPINFOA)pnmh;
  623. if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))
  624. {
  625. const int cchBuff = 256;
  626. char szBuff[cchBuff] = {};
  627. int nRet = ::LoadStringA(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff);
  628. for(int i = 0; i < nRet; i++)
  629. {
  630. if(szBuff[i] == '\n')
  631. {
  632. ATL::Checked::strncpy_s(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE);
  633. break;
  634. }
  635. }
  636. if(nRet > 0) // string was loaded, save it
  637. pDispInfo->uFlags |= TTF_DI_SETITEM;
  638. }
  639. return 0;
  640. }
  641. LRESULT OnToolTipTextW(int idCtrl, LPNMHDR pnmh, BOOL& /*bHandled*/)
  642. {
  643. LPNMTTDISPINFOW pDispInfo = (LPNMTTDISPINFOW)pnmh;
  644. if((idCtrl != 0) && !(pDispInfo->uFlags & TTF_IDISHWND))
  645. {
  646. const int cchBuff = 256;
  647. wchar_t szBuff[cchBuff] = {};
  648. int nRet = ::LoadStringW(ModuleHelper::GetResourceInstance(), idCtrl, szBuff, cchBuff);
  649. for(int i = 0; i < nRet; i++)
  650. {
  651. if(szBuff[i] == L'\n')
  652. {
  653. ATL::Checked::wcsncpy_s(pDispInfo->szText, _countof(pDispInfo->szText), &szBuff[i + 1], _TRUNCATE);
  654. break;
  655. }
  656. }
  657. if(nRet > 0) // string was loaded, save it
  658. pDispInfo->uFlags |= TTF_DI_SETITEM;
  659. }
  660. return 0;
  661. }
  662. // Implementation - chevron menu support
  663. bool PrepareChevronMenu(_ChevronMenuInfo& cmi)
  664. {
  665. // get rebar and toolbar
  666. REBARBANDINFO rbbi = { RunTimeHelper::SizeOf_REBARBANDINFO() };
  667. rbbi.fMask = RBBIM_CHILD;
  668. BOOL bRet = (BOOL)::SendMessage(cmi.lpnm->hdr.hwndFrom, RB_GETBANDINFO, cmi.lpnm->uBand, (LPARAM)&rbbi);
  669. ATLASSERT(bRet);
  670. // assume the band is a toolbar
  671. ATL::CWindow wnd = rbbi.hwndChild;
  672. int nCount = (int)wnd.SendMessage(TB_BUTTONCOUNT);
  673. if(nCount <= 0) // probably not a toolbar
  674. return false;
  675. // check if it's a command bar
  676. CMenuHandle menuCmdBar = (HMENU)wnd.SendMessage(CBRM_GETMENU);
  677. cmi.bCmdBar = (menuCmdBar.m_hMenu != NULL);
  678. // build a menu from hidden items
  679. CMenuHandle menu;
  680. bRet = menu.CreatePopupMenu();
  681. ATLASSERT(bRet);
  682. RECT rcClient = {};
  683. bRet = wnd.GetClientRect(&rcClient);
  684. ATLASSERT(bRet);
  685. for(int i = 0; i < nCount; i++)
  686. {
  687. TBBUTTON tbb = {};
  688. bRet = (BOOL)wnd.SendMessage(TB_GETBUTTON, i, (LPARAM)&tbb);
  689. ATLASSERT(bRet);
  690. // skip hidden buttons
  691. if((tbb.fsState & TBSTATE_HIDDEN) != 0)
  692. continue;
  693. RECT rcButton = {};
  694. bRet = (BOOL)wnd.SendMessage(TB_GETITEMRECT, i, (LPARAM)&rcButton);
  695. ATLASSERT(bRet);
  696. bool bEnabled = ((tbb.fsState & TBSTATE_ENABLED) != 0);
  697. if((rcButton.right > rcClient.right) || (rcButton.bottom > rcClient.bottom))
  698. {
  699. if(tbb.fsStyle & BTNS_SEP)
  700. {
  701. if(menu.GetMenuItemCount() > 0)
  702. menu.AppendMenu(MF_SEPARATOR);
  703. }
  704. else if(cmi.bCmdBar)
  705. {
  706. const int cchBuff = 200;
  707. TCHAR szBuff[cchBuff] = {};
  708. CMenuItemInfo mii;
  709. mii.fMask = MIIM_TYPE | MIIM_SUBMENU;
  710. mii.dwTypeData = szBuff;
  711. mii.cch = cchBuff;
  712. bRet = menuCmdBar.GetMenuItemInfo(i, TRUE, &mii);
  713. ATLASSERT(bRet);
  714. // Note: CmdBar currently supports only drop-down items
  715. ATLASSERT(::IsMenu(mii.hSubMenu));
  716. bRet = menu.AppendMenu(MF_STRING | MF_POPUP | (bEnabled ? MF_ENABLED : MF_GRAYED), (UINT_PTR)mii.hSubMenu, mii.dwTypeData);
  717. ATLASSERT(bRet);
  718. }
  719. else
  720. {
  721. // get button's text
  722. const int cchBuff = 200;
  723. TCHAR szBuff[cchBuff] = {};
  724. LPCTSTR lpstrText = szBuff;
  725. TBBUTTONINFO tbbi = {};
  726. tbbi.cbSize = sizeof(TBBUTTONINFO);
  727. tbbi.dwMask = TBIF_TEXT;
  728. tbbi.pszText = szBuff;
  729. tbbi.cchText = cchBuff;
  730. if((wnd.SendMessage(TB_GETBUTTONINFO, tbb.idCommand, (LPARAM)&tbbi) == -1) || (szBuff[0] == 0))
  731. {
  732. // no text for this button, try a resource string
  733. lpstrText = _T("");
  734. int nRet = ::LoadString(ModuleHelper::GetResourceInstance(), tbb.idCommand, szBuff, cchBuff);
  735. for(int n = 0; n < nRet; n++)
  736. {
  737. if(szBuff[n] == _T('\n'))
  738. {
  739. lpstrText = &szBuff[n + 1];
  740. break;
  741. }
  742. }
  743. }
  744. bRet = menu.AppendMenu(MF_STRING | (bEnabled ? MF_ENABLED : MF_GRAYED), tbb.idCommand, lpstrText);
  745. ATLASSERT(bRet);
  746. }
  747. }
  748. }
  749. if(menu.GetMenuItemCount() == 0) // no hidden buttons after all
  750. {
  751. menu.DestroyMenu();
  752. ::MessageBeep((UINT)-1);
  753. return false;
  754. }
  755. cmi.hMenu = menu;
  756. return true;
  757. }
  758. void DisplayChevronMenu(_ChevronMenuInfo& cmi)
  759. {
  760. // convert chevron rect to screen coordinates
  761. ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
  762. POINT pt = { cmi.lpnm->rc.left, cmi.lpnm->rc.bottom };
  763. wndFrom.MapWindowPoints(NULL, &pt, 1);
  764. RECT rc = cmi.lpnm->rc;
  765. wndFrom.MapWindowPoints(NULL, &rc);
  766. // set up flags and rect
  767. UINT uMenuFlags = TPM_LEFTBUTTON | TPM_VERTICAL | TPM_LEFTALIGN | TPM_TOPALIGN | TPM_VERPOSANIMATION;
  768. TPMPARAMS TPMParams = {};
  769. TPMParams.cbSize = sizeof(TPMPARAMS);
  770. TPMParams.rcExclude = rc;
  771. // check if this window has a command bar
  772. HWND hWndCmdBar = (HWND)::SendMessage(this->m_hWnd, CBRM_GETCMDBAR, 0, 0L);
  773. if(::IsWindow(hWndCmdBar))
  774. {
  775. CBRPOPUPMENU CBRPopupMenu = { sizeof(CBRPOPUPMENU), cmi.hMenu, uMenuFlags, pt.x, pt.y, &TPMParams };
  776. ::SendMessage(hWndCmdBar, CBRM_TRACKPOPUPMENU, 0, (LPARAM)&CBRPopupMenu);
  777. }
  778. else
  779. {
  780. CMenuHandle menu = cmi.hMenu;
  781. menu.TrackPopupMenuEx(uMenuFlags, pt.x, pt.y, this->m_hWnd, &TPMParams);
  782. }
  783. }
  784. void CleanupChevronMenu(_ChevronMenuInfo& cmi)
  785. {
  786. CMenuHandle menu = cmi.hMenu;
  787. // if menu is from a command bar, detach submenus so they are not destroyed
  788. if(cmi.bCmdBar)
  789. {
  790. for(int i = menu.GetMenuItemCount() - 1; i >=0; i--)
  791. menu.RemoveMenu(i, MF_BYPOSITION);
  792. }
  793. // destroy menu
  794. menu.DestroyMenu();
  795. // convert chevron rect to screen coordinates
  796. ATL::CWindow wndFrom = cmi.lpnm->hdr.hwndFrom;
  797. RECT rc = cmi.lpnm->rc;
  798. wndFrom.MapWindowPoints(NULL, &rc);
  799. // eat next message if click is on the same button
  800. MSG msg = {};
  801. if(::PeekMessage(&msg, this->m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE) && ::PtInRect(&rc, msg.pt))
  802. ::PeekMessage(&msg, this->m_hWnd, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_REMOVE);
  803. }
  804. };
  805. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CFrameWinTraits>
  806. class ATL_NO_VTABLE CFrameWindowImpl : public CFrameWindowImplBase< TBase, TWinTraits >
  807. {
  808. public:
  809. HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
  810. DWORD dwStyle = 0, DWORD dwExStyle = 0,
  811. HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
  812. {
  813. ATOM atom = T::GetWndClassInfo().Register(&this->m_pfnSuperWindowProc);
  814. dwStyle = T::GetWndStyle(dwStyle);
  815. dwExStyle = T::GetWndExStyle(dwExStyle);
  816. if(rect.m_lpRect == NULL)
  817. rect.m_lpRect = &TBase::rcDefault;
  818. return CFrameWindowImplBase< TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);
  819. }
  820. HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
  821. {
  822. const int cchName = 256;
  823. TCHAR szWindowName[cchName] = {};
  824. ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
  825. HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  826. T* pT = static_cast<T*>(this);
  827. HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
  828. if(hWnd != NULL)
  829. this->m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  830. return hWnd;
  831. }
  832. BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  833. {
  834. if(nResourceID == 0)
  835. nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
  836. ATLASSERT(!::IsWindow(this->m_hWndToolBar));
  837. this->m_hWndToolBar = T::CreateSimpleToolBarCtrl(this->m_hWnd, nResourceID, TRUE, dwStyle, nID);
  838. return (this->m_hWndToolBar != NULL);
  839. }
  840. // message map and handlers
  841. typedef CFrameWindowImplBase< TBase, TWinTraits > _baseClass;
  842. BEGIN_MSG_MAP(CFrameWindowImpl)
  843. MESSAGE_HANDLER(WM_SIZE, OnSize)
  844. #ifndef _ATL_NO_REBAR_SUPPORT
  845. NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
  846. NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
  847. #endif // !_ATL_NO_REBAR_SUPPORT
  848. CHAIN_MSG_MAP(_baseClass)
  849. END_MSG_MAP()
  850. LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  851. {
  852. if(wParam != SIZE_MINIMIZED)
  853. {
  854. T* pT = static_cast<T*>(this);
  855. pT->UpdateLayout();
  856. }
  857. bHandled = FALSE;
  858. return 1;
  859. }
  860. #ifndef _ATL_NO_REBAR_SUPPORT
  861. LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
  862. {
  863. T* pT = static_cast<T*>(this);
  864. pT->UpdateLayout(FALSE);
  865. return 0;
  866. }
  867. LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
  868. {
  869. T* pT = static_cast<T*>(this);
  870. typename CFrameWindowImplBase< TBase, TWinTraits >::_ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
  871. if(!pT->PrepareChevronMenu(cmi))
  872. {
  873. bHandled = FALSE;
  874. return 1;
  875. }
  876. // display a popup menu with hidden items
  877. pT->DisplayChevronMenu(cmi);
  878. // cleanup
  879. pT->CleanupChevronMenu(cmi);
  880. return 0;
  881. }
  882. #endif // !_ATL_NO_REBAR_SUPPORT
  883. };
  884. ///////////////////////////////////////////////////////////////////////////////
  885. // AtlCreateSimpleToolBar - helper for creating simple toolbars
  886. inline HWND AtlCreateSimpleToolBar(HWND hWndParent, UINT nResourceID, BOOL bInitialSeparator = FALSE,
  887. DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  888. {
  889. return CFrameWindowImplBase<>::CreateSimpleToolBarCtrl(hWndParent, nResourceID, bInitialSeparator, dwStyle, nID);
  890. }
  891. ///////////////////////////////////////////////////////////////////////////////
  892. // CMDIWindow
  893. #ifndef _WTL_MDIWINDOWMENU_TEXT
  894. #define _WTL_MDIWINDOWMENU_TEXT _T("&Window")
  895. #endif
  896. class CMDIWindow : public ATL::CWindow
  897. {
  898. public:
  899. // Data members
  900. HWND m_hWndMDIClient;
  901. HMENU m_hMenu;
  902. // Constructors
  903. CMDIWindow(HWND hWnd = NULL) : ATL::CWindow(hWnd), m_hWndMDIClient(NULL), m_hMenu(NULL)
  904. { }
  905. CMDIWindow& operator =(HWND hWnd)
  906. {
  907. m_hWnd = hWnd;
  908. return *this;
  909. }
  910. // Operations
  911. HWND MDIGetActive(BOOL* lpbMaximized = NULL)
  912. {
  913. ATLASSERT(::IsWindow(m_hWndMDIClient));
  914. return (HWND)::SendMessage(m_hWndMDIClient, WM_MDIGETACTIVE, 0, (LPARAM)lpbMaximized);
  915. }
  916. void MDIActivate(HWND hWndChildToActivate)
  917. {
  918. ATLASSERT(::IsWindow(m_hWndMDIClient));
  919. ATLASSERT(::IsWindow(hWndChildToActivate));
  920. ::SendMessage(m_hWndMDIClient, WM_MDIACTIVATE, (WPARAM)hWndChildToActivate, 0);
  921. }
  922. void MDINext(HWND hWndChild, BOOL bPrevious = FALSE)
  923. {
  924. ATLASSERT(::IsWindow(m_hWndMDIClient));
  925. ATLASSERT((hWndChild == NULL) || ::IsWindow(hWndChild));
  926. ::SendMessage(m_hWndMDIClient, WM_MDINEXT, (WPARAM)hWndChild, (LPARAM)bPrevious);
  927. }
  928. void MDIMaximize(HWND hWndChildToMaximize)
  929. {
  930. ATLASSERT(::IsWindow(m_hWndMDIClient));
  931. ATLASSERT(::IsWindow(hWndChildToMaximize));
  932. ::SendMessage(m_hWndMDIClient, WM_MDIMAXIMIZE, (WPARAM)hWndChildToMaximize, 0);
  933. }
  934. void MDIRestore(HWND hWndChildToRestore)
  935. {
  936. ATLASSERT(::IsWindow(m_hWndMDIClient));
  937. ATLASSERT(::IsWindow(hWndChildToRestore));
  938. ::SendMessage(m_hWndMDIClient, WM_MDIRESTORE, (WPARAM)hWndChildToRestore, 0);
  939. }
  940. void MDIDestroy(HWND hWndChildToDestroy)
  941. {
  942. ATLASSERT(::IsWindow(m_hWndMDIClient));
  943. ATLASSERT(::IsWindow(hWndChildToDestroy));
  944. ::SendMessage(m_hWndMDIClient, WM_MDIDESTROY, (WPARAM)hWndChildToDestroy, 0);
  945. }
  946. BOOL MDICascade(UINT uFlags = 0)
  947. {
  948. ATLASSERT(::IsWindow(m_hWndMDIClient));
  949. return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDICASCADE, (WPARAM)uFlags, 0);
  950. }
  951. BOOL MDITile(UINT uFlags = MDITILE_HORIZONTAL)
  952. {
  953. ATLASSERT(::IsWindow(m_hWndMDIClient));
  954. return (BOOL)::SendMessage(m_hWndMDIClient, WM_MDITILE, (WPARAM)uFlags, 0);
  955. }
  956. void MDIIconArrange()
  957. {
  958. ATLASSERT(::IsWindow(m_hWndMDIClient));
  959. ::SendMessage(m_hWndMDIClient, WM_MDIICONARRANGE, 0, 0);
  960. }
  961. HMENU MDISetMenu(HMENU hMenuFrame, HMENU hMenuWindow)
  962. {
  963. ATLASSERT(::IsWindow(m_hWndMDIClient));
  964. return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDISETMENU, (WPARAM)hMenuFrame, (LPARAM)hMenuWindow);
  965. }
  966. HMENU MDIRefreshMenu()
  967. {
  968. ATLASSERT(::IsWindow(m_hWndMDIClient));
  969. return (HMENU)::SendMessage(m_hWndMDIClient, WM_MDIREFRESHMENU, 0, 0);
  970. }
  971. // Additional operations
  972. static HMENU GetStandardWindowMenu(HMENU hMenu)
  973. {
  974. int nCount = ::GetMenuItemCount(hMenu);
  975. if(nCount == -1)
  976. return NULL;
  977. int nLen = ::GetMenuString(hMenu, nCount - 2, NULL, 0, MF_BYPOSITION);
  978. if(nLen == 0)
  979. return NULL;
  980. ATL::CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
  981. LPTSTR lpszText = buff.Allocate(nLen + 1);
  982. if(lpszText == NULL)
  983. return NULL;
  984. if(::GetMenuString(hMenu, nCount - 2, lpszText, nLen + 1, MF_BYPOSITION) != nLen)
  985. return NULL;
  986. if(lstrcmp(lpszText, _WTL_MDIWINDOWMENU_TEXT) != 0)
  987. return NULL;
  988. return ::GetSubMenu(hMenu, nCount - 2);
  989. }
  990. void SetMDIFrameMenu()
  991. {
  992. HMENU hWindowMenu = GetStandardWindowMenu(m_hMenu);
  993. MDISetMenu(m_hMenu, hWindowMenu);
  994. MDIRefreshMenu();
  995. ::DrawMenuBar(GetMDIFrame());
  996. }
  997. HWND GetMDIFrame() const
  998. {
  999. return ::GetParent(m_hWndMDIClient);
  1000. }
  1001. };
  1002. ///////////////////////////////////////////////////////////////////////////////
  1003. // CMDIFrameWindowImpl
  1004. // MDI child command chaining macro (only for MDI frame windows)
  1005. #define CHAIN_MDI_CHILD_COMMANDS() \
  1006. if(uMsg == WM_COMMAND) \
  1007. { \
  1008. HWND hWndChild = this->MDIGetActive(); \
  1009. if(hWndChild != NULL) \
  1010. ::SendMessage(hWndChild, uMsg, wParam, lParam); \
  1011. }
  1012. template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CFrameWinTraits>
  1013. class ATL_NO_VTABLE CMDIFrameWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >
  1014. {
  1015. public:
  1016. HWND Create(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
  1017. DWORD dwStyle = 0, DWORD dwExStyle = 0,
  1018. HMENU hMenu = NULL, LPVOID lpCreateParam = NULL)
  1019. {
  1020. this->m_hMenu = hMenu;
  1021. ATOM atom = T::GetWndClassInfo().Register(&this->m_pfnSuperWindowProc);
  1022. dwStyle = T::GetWndStyle(dwStyle);
  1023. dwExStyle = T::GetWndExStyle(dwExStyle);
  1024. if(rect.m_lpRect == NULL)
  1025. rect.m_lpRect = &TBase::rcDefault;
  1026. return CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, hMenu, atom, lpCreateParam);
  1027. }
  1028. HWND CreateEx(HWND hWndParent = NULL, ATL::_U_RECT rect = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
  1029. {
  1030. const int cchName = 256;
  1031. TCHAR szWindowName[cchName] = {};
  1032. ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
  1033. HMENU hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  1034. T* pT = static_cast<T*>(this);
  1035. HWND hWnd = pT->Create(hWndParent, rect, szWindowName, dwStyle, dwExStyle, hMenu, lpCreateParam);
  1036. if(hWnd != NULL)
  1037. this->m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  1038. return hWnd;
  1039. }
  1040. BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  1041. {
  1042. ATLASSERT(!::IsWindow(this->m_hWndToolBar));
  1043. if(nResourceID == 0)
  1044. nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
  1045. this->m_hWndToolBar = T::CreateSimpleToolBarCtrl(this->m_hWnd, nResourceID, TRUE, dwStyle, nID);
  1046. return (this->m_hWndToolBar != NULL);
  1047. }
  1048. virtual WNDPROC GetWindowProc()
  1049. {
  1050. return MDIFrameWindowProc;
  1051. }
  1052. static LRESULT CALLBACK MDIFrameWindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1053. {
  1054. CMDIFrameWindowImpl< T, TBase, TWinTraits >* pThis = (CMDIFrameWindowImpl< T, TBase, TWinTraits >*)hWnd;
  1055. // set a ptr to this message and save the old value
  1056. ATL::_ATL_MSG msg(pThis->m_hWnd, uMsg, wParam, lParam);
  1057. const ATL::_ATL_MSG* pOldMsg = pThis->m_pCurrentMsg;
  1058. pThis->m_pCurrentMsg = &msg;
  1059. // pass to the message map to process
  1060. LRESULT lRes = 0;
  1061. BOOL bRet = pThis->ProcessWindowMessage(pThis->m_hWnd, uMsg, wParam, lParam, lRes, 0);
  1062. // restore saved value for the current message
  1063. ATLASSERT(pThis->m_pCurrentMsg == &msg);
  1064. pThis->m_pCurrentMsg = pOldMsg;
  1065. // do the default processing if message was not handled
  1066. if(!bRet)
  1067. {
  1068. if(uMsg != WM_NCDESTROY)
  1069. {
  1070. lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
  1071. }
  1072. else
  1073. {
  1074. // unsubclass, if needed
  1075. LONG_PTR pfnWndProc = ::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC);
  1076. lRes = pThis->DefWindowProc(uMsg, wParam, lParam);
  1077. if((pThis->m_pfnSuperWindowProc != ::DefWindowProc) && (::GetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC) == pfnWndProc))
  1078. ::SetWindowLongPtr(pThis->m_hWnd, GWLP_WNDPROC, (LONG_PTR)pThis->m_pfnSuperWindowProc);
  1079. // mark window as destryed
  1080. pThis->m_dwState |= ATL::CWindowImplRoot< TBase >::WINSTATE_DESTROYED;
  1081. }
  1082. }
  1083. if((pThis->m_dwState & ATL::CWindowImplRoot< TBase >::WINSTATE_DESTROYED) && (pThis->m_pCurrentMsg == NULL))
  1084. {
  1085. // clear out window handle
  1086. HWND hWndThis = pThis->m_hWnd;
  1087. pThis->m_hWnd = NULL;
  1088. pThis->m_dwState &= ~ATL::CWindowImplRoot< TBase >::WINSTATE_DESTROYED;
  1089. // clean up after window is destroyed
  1090. pThis->OnFinalMessage(hWndThis);
  1091. }
  1092. return lRes;
  1093. }
  1094. // Overriden to call DefWindowProc which uses DefFrameProc
  1095. LRESULT DefWindowProc()
  1096. {
  1097. const ATL::_ATL_MSG* pMsg = this->m_pCurrentMsg;
  1098. LRESULT lRes = 0;
  1099. if (pMsg != NULL)
  1100. lRes = DefWindowProc(pMsg->message, pMsg->wParam, pMsg->lParam);
  1101. return lRes;
  1102. }
  1103. LRESULT DefWindowProc(UINT uMsg, WPARAM wParam, LPARAM lParam)
  1104. {
  1105. return ::DefFrameProc(this->m_hWnd, this->m_hWndMDIClient, uMsg, wParam, lParam);
  1106. }
  1107. BOOL PreTranslateMessage(MSG* pMsg)
  1108. {
  1109. if(CFrameWindowImplBase<TBase, TWinTraits>::PreTranslateMessage(pMsg))
  1110. return TRUE;
  1111. return ::TranslateMDISysAccel(this->m_hWndMDIClient, pMsg);
  1112. }
  1113. HWND CreateMDIClient(HMENU hWindowMenu = NULL, UINT nID = ATL_IDW_CLIENT, UINT nFirstChildID = ATL_IDM_FIRST_MDICHILD)
  1114. {
  1115. DWORD dwStyle = WS_VISIBLE | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | MDIS_ALLCHILDSTYLES;
  1116. DWORD dwExStyle = WS_EX_CLIENTEDGE;
  1117. CLIENTCREATESTRUCT ccs = {};
  1118. ccs.hWindowMenu = hWindowMenu;
  1119. ccs.idFirstChild = nFirstChildID;
  1120. if((this->GetStyle() & (WS_HSCROLL | WS_VSCROLL)) != 0)
  1121. {
  1122. // parent MDI frame's scroll styles move to the MDICLIENT
  1123. dwStyle |= (this->GetStyle() & (WS_HSCROLL | WS_VSCROLL));
  1124. // fast way to turn off the scrollbar bits (without a resize)
  1125. this->ModifyStyle(WS_HSCROLL | WS_VSCROLL, 0, SWP_NOREDRAW | SWP_FRAMECHANGED);
  1126. }
  1127. // Create MDICLIENT window
  1128. this->m_hWndClient = ::CreateWindowEx(dwExStyle, _T("MDIClient"), NULL,
  1129. dwStyle, 0, 0, 1, 1, this->m_hWnd, (HMENU)LongToHandle(nID),
  1130. ModuleHelper::GetModuleInstance(), (LPVOID)&ccs);
  1131. if (this->m_hWndClient == NULL)
  1132. {
  1133. ATLTRACE2(atlTraceUI, 0, _T("MDI Frame failed to create MDICLIENT.\n"));
  1134. return NULL;
  1135. }
  1136. // Move it to the top of z-order
  1137. ::BringWindowToTop(this->m_hWndClient);
  1138. // set as MDI client window
  1139. this->m_hWndMDIClient = this->m_hWndClient;
  1140. // update to proper size
  1141. T* pT = static_cast<T*>(this);
  1142. pT->UpdateLayout();
  1143. return this->m_hWndClient;
  1144. }
  1145. typedef CFrameWindowImplBase<TBase, TWinTraits > _baseClass;
  1146. BEGIN_MSG_MAP(CMDIFrameWindowImpl)
  1147. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1148. MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
  1149. MESSAGE_HANDLER(WM_MDISETMENU, OnMDISetMenu)
  1150. #ifndef _ATL_NO_REBAR_SUPPORT
  1151. NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
  1152. NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
  1153. #endif // !_ATL_NO_REBAR_SUPPORT
  1154. CHAIN_MSG_MAP(_baseClass)
  1155. END_MSG_MAP()
  1156. LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1157. {
  1158. if(wParam != SIZE_MINIMIZED)
  1159. {
  1160. T* pT = static_cast<T*>(this);
  1161. pT->UpdateLayout();
  1162. }
  1163. // message must be handled, otherwise DefFrameProc would resize the client again
  1164. return 0;
  1165. }
  1166. LRESULT OnSetFocus(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1167. {
  1168. // don't allow CFrameWindowImplBase to handle this one
  1169. return DefWindowProc(uMsg, wParam, lParam);
  1170. }
  1171. LRESULT OnMDISetMenu(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  1172. {
  1173. this->SetMDIFrameMenu();
  1174. return 0;
  1175. }
  1176. #ifndef _ATL_NO_REBAR_SUPPORT
  1177. LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
  1178. {
  1179. T* pT = static_cast<T*>(this);
  1180. pT->UpdateLayout(FALSE);
  1181. return 0;
  1182. }
  1183. LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
  1184. {
  1185. T* pT = static_cast<T*>(this);
  1186. typename CFrameWindowImplBase<TBase, TWinTraits >::_ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
  1187. if(!pT->PrepareChevronMenu(cmi))
  1188. {
  1189. bHandled = FALSE;
  1190. return 1;
  1191. }
  1192. // display a popup menu with hidden items
  1193. pT->DisplayChevronMenu(cmi);
  1194. // cleanup
  1195. pT->CleanupChevronMenu(cmi);
  1196. return 0;
  1197. }
  1198. #endif // !_ATL_NO_REBAR_SUPPORT
  1199. };
  1200. ///////////////////////////////////////////////////////////////////////////////
  1201. // CMDIChildWindowImpl
  1202. template <class T, class TBase = CMDIWindow, class TWinTraits = ATL::CMDIChildWinTraits>
  1203. class ATL_NO_VTABLE CMDIChildWindowImpl : public CFrameWindowImplBase<TBase, TWinTraits >
  1204. {
  1205. public:
  1206. HWND Create(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR szWindowName = NULL,
  1207. DWORD dwStyle = 0, DWORD dwExStyle = 0,
  1208. UINT nMenuID = 0, LPVOID lpCreateParam = NULL)
  1209. {
  1210. ATOM atom = T::GetWndClassInfo().Register(&this->m_pfnSuperWindowProc);
  1211. if(nMenuID != 0)
  1212. this->m_hMenu = ::LoadMenu(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(nMenuID));
  1213. dwStyle = T::GetWndStyle(dwStyle);
  1214. dwExStyle = T::GetWndExStyle(dwExStyle);
  1215. dwExStyle |= WS_EX_MDICHILD; // force this one
  1216. this->m_pfnSuperWindowProc = ::DefMDIChildProc;
  1217. this->m_hWndMDIClient = hWndParent;
  1218. ATLASSERT(::IsWindow(this->m_hWndMDIClient));
  1219. if(rect.m_lpRect == NULL)
  1220. rect.m_lpRect = &TBase::rcDefault;
  1221. // If the currently active MDI child is maximized, we want to create this one maximized too
  1222. ATL::CWindow wndParent = hWndParent;
  1223. BOOL bMaximized = FALSE;
  1224. wndParent.SendMessage(WM_MDIGETACTIVE, 0, (LPARAM)&bMaximized);
  1225. if(bMaximized)
  1226. wndParent.SetRedraw(FALSE);
  1227. HWND hWnd = CFrameWindowImplBase<TBase, TWinTraits >::Create(hWndParent, rect.m_lpRect, szWindowName, dwStyle, dwExStyle, (UINT)0U, atom, lpCreateParam);
  1228. if(bMaximized)
  1229. {
  1230. // Maximize and redraw everything
  1231. if(hWnd != NULL)
  1232. this->MDIMaximize(hWnd);
  1233. wndParent.SetRedraw(TRUE);
  1234. wndParent.RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_ALLCHILDREN);
  1235. ::SetFocus(this->GetMDIFrame()); // focus will be set back to this window
  1236. }
  1237. else if((hWnd != NULL) && ::IsWindowVisible(this->m_hWnd) && !::IsChild(hWnd, ::GetFocus()))
  1238. {
  1239. ::SetFocus(hWnd);
  1240. }
  1241. return hWnd;
  1242. }
  1243. HWND CreateEx(HWND hWndParent, ATL::_U_RECT rect = NULL, LPCTSTR lpcstrWindowName = NULL, DWORD dwStyle = 0, DWORD dwExStyle = 0, LPVOID lpCreateParam = NULL)
  1244. {
  1245. const int cchName = 256;
  1246. TCHAR szWindowName[cchName] = {};
  1247. if(lpcstrWindowName == NULL)
  1248. {
  1249. ::LoadString(ModuleHelper::GetResourceInstance(), T::GetWndClassInfo().m_uCommonResourceID, szWindowName, cchName);
  1250. lpcstrWindowName = szWindowName;
  1251. }
  1252. T* pT = static_cast<T*>(this);
  1253. HWND hWnd = pT->Create(hWndParent, rect, lpcstrWindowName, dwStyle, dwExStyle, T::GetWndClassInfo().m_uCommonResourceID, lpCreateParam);
  1254. if(hWnd != NULL)
  1255. this->m_hAccel = ::LoadAccelerators(ModuleHelper::GetResourceInstance(), MAKEINTRESOURCE(T::GetWndClassInfo().m_uCommonResourceID));
  1256. return hWnd;
  1257. }
  1258. BOOL CreateSimpleToolBar(UINT nResourceID = 0, DWORD dwStyle = ATL_SIMPLE_TOOLBAR_STYLE, UINT nID = ATL_IDW_TOOLBAR)
  1259. {
  1260. ATLASSERT(!::IsWindow(this->m_hWndToolBar));
  1261. if(nResourceID == 0)
  1262. nResourceID = T::GetWndClassInfo().m_uCommonResourceID;
  1263. this->m_hWndToolBar = T::CreateSimpleToolBarCtrl(this->m_hWnd, nResourceID, TRUE, dwStyle, nID);
  1264. return (this->m_hWndToolBar != NULL);
  1265. }
  1266. BOOL UpdateClientEdge(LPRECT lpRect = NULL)
  1267. {
  1268. // only adjust for active MDI child window
  1269. HWND hWndChild = this->MDIGetActive();
  1270. if((hWndChild != NULL) && (hWndChild != this->m_hWnd))
  1271. return FALSE;
  1272. // need to adjust the client edge style as max/restore happens
  1273. DWORD dwStyle = ::GetWindowLong(this->m_hWndMDIClient, GWL_EXSTYLE);
  1274. DWORD dwNewStyle = dwStyle;
  1275. if((hWndChild != NULL) && ((this->GetExStyle() & WS_EX_CLIENTEDGE) == 0) && ((this->GetStyle() & WS_MAXIMIZE) != 0))
  1276. dwNewStyle &= ~(WS_EX_CLIENTEDGE);
  1277. else
  1278. dwNewStyle |= WS_EX_CLIENTEDGE;
  1279. if(dwStyle != dwNewStyle)
  1280. {
  1281. // SetWindowPos will not move invalid bits
  1282. ::RedrawWindow(this->m_hWndMDIClient, NULL, NULL,
  1283. RDW_INVALIDATE | RDW_ALLCHILDREN);
  1284. // remove/add WS_EX_CLIENTEDGE to MDI client area
  1285. ::SetWindowLong(this->m_hWndMDIClient, GWL_EXSTYLE, dwNewStyle);
  1286. ::SetWindowPos(this->m_hWndMDIClient, NULL, 0, 0, 0, 0,
  1287. SWP_FRAMECHANGED | SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE |
  1288. SWP_NOZORDER | SWP_NOCOPYBITS);
  1289. // return new client area
  1290. if (lpRect != NULL)
  1291. ::GetClientRect(this->m_hWndMDIClient, lpRect);
  1292. return TRUE;
  1293. }
  1294. return FALSE;
  1295. }
  1296. typedef CFrameWindowImplBase<TBase, TWinTraits > _baseClass;
  1297. BEGIN_MSG_MAP(CMDIChildWindowImpl)
  1298. MESSAGE_HANDLER(WM_SIZE, OnSize)
  1299. MESSAGE_HANDLER(WM_WINDOWPOSCHANGED, OnWindowPosChanged)
  1300. MESSAGE_HANDLER(WM_MOUSEACTIVATE, OnMouseActivate)
  1301. MESSAGE_HANDLER(WM_MENUSELECT, OnMenuSelect)
  1302. MESSAGE_HANDLER(WM_MDIACTIVATE, OnMDIActivate)
  1303. MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
  1304. #ifndef _ATL_NO_REBAR_SUPPORT
  1305. NOTIFY_CODE_HANDLER(RBN_AUTOSIZE, OnReBarAutoSize)
  1306. NOTIFY_CODE_HANDLER(RBN_CHEVRONPUSHED, OnChevronPushed)
  1307. #endif // !_ATL_NO_REBAR_SUPPORT
  1308. CHAIN_MSG_MAP(_baseClass)
  1309. END_MSG_MAP()
  1310. LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1311. {
  1312. this->DefWindowProc(uMsg, wParam, lParam); // needed for MDI children
  1313. if(wParam != SIZE_MINIMIZED)
  1314. {
  1315. T* pT = static_cast<T*>(this);
  1316. pT->UpdateLayout();
  1317. }
  1318. return 0;
  1319. }
  1320. LRESULT OnWindowPosChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1321. {
  1322. // update MDI client edge and adjust MDI child rect
  1323. LPWINDOWPOS lpWndPos = (LPWINDOWPOS)lParam;
  1324. if(!(lpWndPos->flags & SWP_NOSIZE))
  1325. {
  1326. RECT rectClient = {};
  1327. if(UpdateClientEdge(&rectClient) && ((this->GetStyle() & WS_MAXIMIZE) != 0))
  1328. {
  1329. ::AdjustWindowRectEx(&rectClient, this->GetStyle(), FALSE, this->GetExStyle());
  1330. lpWndPos->x = rectClient.left;
  1331. lpWndPos->y = rectClient.top;
  1332. lpWndPos->cx = rectClient.right - rectClient.left;
  1333. lpWndPos->cy = rectClient.bottom - rectClient.top;
  1334. }
  1335. }
  1336. bHandled = FALSE;
  1337. return 1;
  1338. }
  1339. LRESULT OnMouseActivate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1340. {
  1341. LRESULT lRes = this->DefWindowProc(uMsg, wParam, lParam);
  1342. // Activate this MDI window if needed
  1343. if((lRes == MA_ACTIVATE) || (lRes == MA_ACTIVATEANDEAT))
  1344. {
  1345. if(this->MDIGetActive() != this->m_hWnd)
  1346. this->MDIActivate(this->m_hWnd);
  1347. }
  1348. return lRes;
  1349. }
  1350. LRESULT OnMenuSelect(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  1351. {
  1352. return ::SendMessage(this->GetMDIFrame(), uMsg, wParam, lParam);
  1353. }
  1354. LRESULT OnMDIActivate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1355. {
  1356. if(((HWND)lParam == this->m_hWnd) && (this->m_hMenu != NULL))
  1357. this->SetMDIFrameMenu();
  1358. else if((HWND)lParam == NULL)
  1359. ::SendMessage(this->GetMDIFrame(), WM_MDISETMENU, 0, 0);
  1360. bHandled = FALSE;
  1361. return 1;
  1362. }
  1363. LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
  1364. {
  1365. if(this->m_hMenu != NULL)
  1366. {
  1367. ::DestroyMenu(this->m_hMenu);
  1368. this->m_hMenu = NULL;
  1369. }
  1370. UpdateClientEdge();
  1371. bHandled = FALSE;
  1372. return 1;
  1373. }
  1374. #ifndef _ATL_NO_REBAR_SUPPORT
  1375. LRESULT OnReBarAutoSize(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
  1376. {
  1377. T* pT = static_cast<T*>(this);
  1378. pT->UpdateLayout(FALSE);
  1379. return 0;
  1380. }
  1381. LRESULT OnChevronPushed(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
  1382. {
  1383. T* pT = static_cast<T*>(this);
  1384. typename CFrameWindowImplBase<TBase, TWinTraits >::_ChevronMenuInfo cmi = { NULL, (LPNMREBARCHEVRON)pnmh, false };
  1385. if(!pT->PrepareChevronMenu(cmi))
  1386. {
  1387. bHandled = FALSE;
  1388. return 1;
  1389. }
  1390. // display a popup menu with hidden items
  1391. pT->DisplayChevronMenu(cmi);
  1392. // cleanup
  1393. pT->CleanupChevronMenu(cmi);
  1394. return 0;
  1395. }
  1396. #endif // !_ATL_NO_REBAR_SUPPORT
  1397. };
  1398. ///////////////////////////////////////////////////////////////////////////////
  1399. // COwnerDraw - MI class for owner-draw support
  1400. template <class T>
  1401. class COwnerDraw
  1402. {
  1403. public:
  1404. // Message map and handlers
  1405. BEGIN_MSG_MAP(COwnerDraw< T >)
  1406. MESSAGE_HANDLER(WM_DRAWITEM, OnDrawItem)
  1407. MESSAGE_HANDLER(WM_MEASUREITEM, OnMeasureItem)
  1408. MESSAGE_HANDLER(WM_COMPAREITEM, OnCompareItem)
  1409. MESSAGE_HANDLER(WM_DELETEITEM, OnDeleteItem)
  1410. ALT_MSG_MAP(1)
  1411. MESSAGE_HANDLER(OCM_DRAWITEM, OnDrawItem)
  1412. MESSAGE_HANDLER(OCM_MEASUREITEM, OnMeasureItem)
  1413. MESSAGE_HANDLER(OCM_COMPAREITEM, OnCompareItem)
  1414. MESSAGE_HANDLER(OCM_DELETEITEM, OnDeleteItem)
  1415. END_MSG_MAP()
  1416. LRESULT OnDrawItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1417. {
  1418. T* pT = static_cast<T*>(this);
  1419. pT->SetMsgHandled(TRUE);
  1420. pT->DrawItem((LPDRAWITEMSTRUCT)lParam);
  1421. bHandled = pT->IsMsgHandled();
  1422. return (LRESULT)TRUE;
  1423. }
  1424. LRESULT OnMeasureItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1425. {
  1426. T* pT = static_cast<T*>(this);
  1427. pT->SetMsgHandled(TRUE);
  1428. pT->MeasureItem((LPMEASUREITEMSTRUCT)lParam);
  1429. bHandled = pT->IsMsgHandled();
  1430. return (LRESULT)TRUE;
  1431. }
  1432. LRESULT OnCompareItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1433. {
  1434. T* pT = static_cast<T*>(this);
  1435. pT->SetMsgHandled(TRUE);
  1436. bHandled = pT->IsMsgHandled();
  1437. return (LRESULT)pT->CompareItem((LPCOMPAREITEMSTRUCT)lParam);
  1438. }
  1439. LRESULT OnDeleteItem(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
  1440. {
  1441. T* pT = static_cast<T*>(this);
  1442. pT->SetMsgHandled(TRUE);
  1443. pT->DeleteItem((LPDELETEITEMSTRUCT)lParam);
  1444. bHandled = pT->IsMsgHandled();
  1445. return (LRESULT)TRUE;
  1446. }
  1447. // Overrideables
  1448. void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/)
  1449. {
  1450. // must be implemented
  1451. ATLASSERT(FALSE);
  1452. }
  1453. void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)
  1454. {
  1455. if(lpMeasureItemStruct->CtlType != ODT_MENU)
  1456. {
  1457. // return default height for a system font
  1458. T* pT = static_cast<T*>(this);
  1459. HWND hWnd = pT->GetDlgItem(lpMeasureItemStruct->CtlID);
  1460. CClientDC dc(hWnd);
  1461. TEXTMETRIC tm = {};
  1462. dc.GetTextMetrics(&tm);
  1463. lpMeasureItemStruct->itemHeight = tm.tmHeight;
  1464. }
  1465. else
  1466. lpMeasureItemStruct->itemHeight = ::GetSystemMetrics(SM_CYMENU);
  1467. }
  1468. int CompareItem(LPCOMPAREITEMSTRUCT /*lpCompareItemStruct*/)
  1469. {
  1470. // all items are equal
  1471. return 0;
  1472. }
  1473. void DeleteItem(LPDELETEITEMSTRUCT /*lpDeleteItemStruct*/)
  1474. {
  1475. // default - nothing
  1476. }
  1477. };
  1478. ///////////////////////////////////////////////////////////////////////////////
  1479. // Update UI macros
  1480. // these build the Update UI map inside a class definition
  1481. #define BEGIN_UPDATE_UI_MAP(thisClass) \
  1482. static const CUpdateUIBase::_AtlUpdateUIMap* GetUpdateUIMap() \
  1483. { \
  1484. static const CUpdateUIBase::_AtlUpdateUIMap theMap[] = \
  1485. {
  1486. #define UPDATE_ELEMENT(nID, wType) \
  1487. { nID, wType },
  1488. #define END_UPDATE_UI_MAP() \
  1489. { (WORD)-1, 0 } \
  1490. }; \
  1491. return theMap; \
  1492. }
  1493. ///////////////////////////////////////////////////////////////////////////////
  1494. // CUpdateUI - manages UI elements updating
  1495. class CUpdateUIBase
  1496. {
  1497. public:
  1498. // constants
  1499. enum
  1500. {
  1501. // UI element type
  1502. UPDUI_MENUPOPUP = 0x0001,
  1503. UPDUI_MENUBAR = 0x0002,
  1504. UPDUI_CHILDWINDOW = 0x0004,
  1505. UPDUI_TOOLBAR = 0x0008,
  1506. UPDUI_STATUSBAR = 0x0010,
  1507. // state
  1508. UPDUI_ENABLED = 0x0000,
  1509. UPDUI_DISABLED = 0x0100,
  1510. UPDUI_CHECKED = 0x0200,
  1511. UPDUI_CHECKED2 = 0x0400,
  1512. UPDUI_RADIO = 0x0800,
  1513. UPDUI_DEFAULT = 0x1000,
  1514. UPDUI_TEXT = 0x2000,
  1515. // internal state
  1516. UPDUI_CLEARDEFAULT = 0x4000,
  1517. };
  1518. // element data
  1519. struct _AtlUpdateUIElement
  1520. {
  1521. HWND m_hWnd;
  1522. WORD m_wType;
  1523. bool operator ==(const _AtlUpdateUIElement& e) const
  1524. { return ((m_hWnd == e.m_hWnd) && (m_wType == e.m_wType)); }
  1525. };
  1526. // map data
  1527. struct _AtlUpdateUIMap
  1528. {
  1529. WORD m_nID;
  1530. WORD m_wType;
  1531. bool operator ==(const _AtlUpdateUIMap& e) const
  1532. { return ((m_nID == e.m_nID) && (m_wType == e.m_wType)); }
  1533. };
  1534. // instance data
  1535. #pragma warning(push)
  1536. #pragma warning(disable: 4201) // nameless unions are part of C++
  1537. struct _AtlUpdateUIData
  1538. {
  1539. WORD m_wState;
  1540. union
  1541. {
  1542. void* m_lpData;
  1543. LPTSTR m_lpstrText;
  1544. struct
  1545. {
  1546. WORD m_nIDFirst;
  1547. WORD m_nIDLast;
  1548. };
  1549. };
  1550. bool operator ==(const _AtlUpdateUIData& e) const
  1551. { return ((m_wState == e.m_wState) && (m_lpData == e.m_lpData)); }
  1552. };
  1553. #pragma warning(pop)
  1554. ATL::CSimpleArray<_AtlUpdateUIElement> m_UIElements; // elements data
  1555. const _AtlUpdateUIMap* m_pUIMap; // static UI data
  1556. _AtlUpdateUIData* m_pUIData; // instance UI data
  1557. WORD m_wDirtyType; // global dirty flag
  1558. bool m_bBlockAccelerators;
  1559. // Constructor, destructor
  1560. CUpdateUIBase() : m_pUIMap(NULL), m_pUIData(NULL), m_wDirtyType(0), m_bBlockAccelerators(false)
  1561. { }
  1562. ~CUpdateUIBase()
  1563. {
  1564. if((m_pUIMap != NULL) && (m_pUIData != NULL))
  1565. {
  1566. const _AtlUpdateUIMap* pUIMap = m_pUIMap;
  1567. _AtlUpdateUIData* pUIData = m_pUIData;
  1568. while(pUIMap->m_nID != (WORD)-1)
  1569. {
  1570. if(pUIData->m_wState & UPDUI_TEXT)
  1571. delete [] pUIData->m_lpstrText;
  1572. pUIMap++;
  1573. pUIData++;
  1574. }
  1575. delete [] m_pUIData;
  1576. }
  1577. }
  1578. // Check for disabled commands
  1579. bool UIGetBlockAccelerators() const
  1580. {
  1581. return m_bBlockAccelerators;
  1582. }
  1583. bool UISetBlockAccelerators(bool bBlock)
  1584. {
  1585. bool bOld = m_bBlockAccelerators;
  1586. m_bBlockAccelerators = bBlock;
  1587. return bOld;
  1588. }
  1589. // Add elements
  1590. BOOL UIAddMenuBar(HWND hWnd) // menu bar (main menu)
  1591. {
  1592. if(hWnd == NULL)
  1593. return FALSE;
  1594. _AtlUpdateUIElement e;
  1595. e.m_hWnd = hWnd;
  1596. e.m_wType = UPDUI_MENUBAR;
  1597. return m_UIElements.Add(e);
  1598. }
  1599. BOOL UIAddToolBar(HWND hWnd) // toolbar
  1600. {
  1601. if(hWnd == NULL)
  1602. return FALSE;
  1603. _AtlUpdateUIElement e;
  1604. e.m_hWnd = hWnd;
  1605. e.m_wType = UPDUI_TOOLBAR;
  1606. return m_UIElements.Add(e);
  1607. }
  1608. BOOL UIAddStatusBar(HWND hWnd) // status bar
  1609. {
  1610. if(hWnd == NULL)
  1611. return FALSE;
  1612. _AtlUpdateUIElement e;
  1613. e.m_hWnd = hWnd;
  1614. e.m_wType = UPDUI_STATUSBAR;
  1615. return m_UIElements.Add(e);
  1616. }
  1617. BOOL UIAddChildWindowContainer(HWND hWnd) // child window
  1618. {
  1619. if(hWnd == NULL)
  1620. return FALSE;
  1621. _AtlUpdateUIElement e;
  1622. e.m_hWnd = hWnd;
  1623. e.m_wType = UPDUI_CHILDWINDOW;
  1624. return m_UIElements.Add(e);
  1625. }
  1626. // Message map for popup menu updates and accelerator blocking
  1627. BEGIN_MSG_MAP(CUpdateUIBase)
  1628. MESSAGE_HANDLER(WM_INITMENUPOPUP, OnInitMenuPopup)
  1629. MESSAGE_HANDLER(WM_COMMAND, OnCommand)
  1630. END_MSG_MAP()
  1631. LRESULT OnInitMenuPopup(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  1632. {
  1633. bHandled = FALSE;
  1634. HMENU hMenu = (HMENU)wParam;
  1635. if(hMenu == NULL)
  1636. return 1;
  1637. _AtlUpdateUIData* pUIData = m_pUIData;
  1638. if(pUIData == NULL)
  1639. return 1;
  1640. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1641. while(pMap->m_nID != (WORD)-1)
  1642. {
  1643. if(pMap->m_wType & UPDUI_MENUPOPUP)
  1644. {
  1645. UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);
  1646. if((pUIData->m_wState & UPDUI_RADIO) != 0)
  1647. ::CheckMenuRadioItem(hMenu, pUIData->m_nIDFirst, pUIData->m_nIDLast, pMap->m_nID, MF_BYCOMMAND);
  1648. }
  1649. pMap++;
  1650. pUIData++;
  1651. }
  1652. return 0;
  1653. }
  1654. LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
  1655. {
  1656. bHandled = FALSE;
  1657. if(m_bBlockAccelerators && (HIWORD(wParam) == 1)) // accelerators only
  1658. {
  1659. int nID = LOWORD(wParam);
  1660. if((UIGetState(nID) & UPDUI_DISABLED) == UPDUI_DISABLED)
  1661. {
  1662. ATLTRACE2(atlTraceUI, 0, _T("CUpdateUIBase::OnCommand - blocked disabled command 0x%4.4X\n"), nID);
  1663. bHandled = TRUE; // eat the command, UI item is disabled
  1664. }
  1665. }
  1666. return 0;
  1667. }
  1668. // methods for setting UI element state
  1669. BOOL UIEnable(int nID, BOOL bEnable, BOOL bForceUpdate = FALSE)
  1670. {
  1671. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1672. _AtlUpdateUIData* pUIData = m_pUIData;
  1673. if(pUIData == NULL)
  1674. return FALSE;
  1675. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1676. {
  1677. if(nID == (int)pMap->m_nID)
  1678. {
  1679. if(bEnable)
  1680. {
  1681. if(pUIData->m_wState & UPDUI_DISABLED)
  1682. {
  1683. pUIData->m_wState |= pMap->m_wType;
  1684. pUIData->m_wState &= ~UPDUI_DISABLED;
  1685. }
  1686. }
  1687. else
  1688. {
  1689. if(!(pUIData->m_wState & UPDUI_DISABLED))
  1690. {
  1691. pUIData->m_wState |= pMap->m_wType;
  1692. pUIData->m_wState |= UPDUI_DISABLED;
  1693. }
  1694. }
  1695. if(bForceUpdate)
  1696. pUIData->m_wState |= pMap->m_wType;
  1697. if(pUIData->m_wState & pMap->m_wType)
  1698. m_wDirtyType |= pMap->m_wType;
  1699. break; // found
  1700. }
  1701. }
  1702. return TRUE;
  1703. }
  1704. BOOL UISetCheck(int nID, int nCheck, BOOL bForceUpdate = FALSE)
  1705. {
  1706. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1707. _AtlUpdateUIData* pUIData = m_pUIData;
  1708. if(pUIData == NULL)
  1709. return FALSE;
  1710. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1711. {
  1712. if(nID == (int)pMap->m_nID)
  1713. {
  1714. switch(nCheck)
  1715. {
  1716. case 0:
  1717. if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_CHECKED2))
  1718. {
  1719. pUIData->m_wState |= pMap->m_wType;
  1720. pUIData->m_wState &= ~(UPDUI_CHECKED | UPDUI_CHECKED2);
  1721. }
  1722. break;
  1723. case 1:
  1724. if(!(pUIData->m_wState & UPDUI_CHECKED))
  1725. {
  1726. pUIData->m_wState |= pMap->m_wType;
  1727. pUIData->m_wState &= ~UPDUI_CHECKED2;
  1728. pUIData->m_wState |= UPDUI_CHECKED;
  1729. }
  1730. break;
  1731. case 2:
  1732. if(!(pUIData->m_wState & UPDUI_CHECKED2))
  1733. {
  1734. pUIData->m_wState |= pMap->m_wType;
  1735. pUIData->m_wState &= ~UPDUI_CHECKED;
  1736. pUIData->m_wState |= UPDUI_CHECKED2;
  1737. }
  1738. break;
  1739. }
  1740. if(bForceUpdate)
  1741. pUIData->m_wState |= pMap->m_wType;
  1742. if(pUIData->m_wState & pMap->m_wType)
  1743. m_wDirtyType |= pMap->m_wType;
  1744. break; // found
  1745. }
  1746. }
  1747. return TRUE;
  1748. }
  1749. // variant that supports bool (checked/not-checked, no intermediate state)
  1750. BOOL UISetCheck(int nID, bool bCheck, BOOL bForceUpdate = FALSE)
  1751. {
  1752. return UISetCheck(nID, bCheck ? 1 : 0, bForceUpdate);
  1753. }
  1754. BOOL UISetRadio(int nID, BOOL bRadio, BOOL bForceUpdate = FALSE)
  1755. {
  1756. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1757. _AtlUpdateUIData* pUIData = m_pUIData;
  1758. if(pUIData == NULL)
  1759. return FALSE;
  1760. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1761. {
  1762. if(nID == (int)pMap->m_nID)
  1763. {
  1764. if(bRadio)
  1765. {
  1766. if(!(pUIData->m_wState & UPDUI_RADIO))
  1767. {
  1768. pUIData->m_wState |= pMap->m_wType;
  1769. pUIData->m_wState |= UPDUI_RADIO;
  1770. }
  1771. }
  1772. else
  1773. {
  1774. if(pUIData->m_wState & UPDUI_RADIO)
  1775. {
  1776. pUIData->m_wState |= pMap->m_wType;
  1777. pUIData->m_wState &= ~UPDUI_RADIO;
  1778. }
  1779. }
  1780. if(bForceUpdate)
  1781. pUIData->m_wState |= pMap->m_wType;
  1782. if(pUIData->m_wState & pMap->m_wType)
  1783. m_wDirtyType |= pMap->m_wType;
  1784. break; // found
  1785. }
  1786. }
  1787. return TRUE;
  1788. }
  1789. // for menu items
  1790. BOOL UISetRadioMenuItem(int nID, int nIDFirst, int nIDLast, BOOL bForceUpdate = FALSE)
  1791. {
  1792. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1793. _AtlUpdateUIData* pUIData = m_pUIData;
  1794. if(pUIData == NULL)
  1795. return FALSE;
  1796. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1797. {
  1798. if(nID == (int)pMap->m_nID)
  1799. {
  1800. pUIData->m_wState |= pMap->m_wType;
  1801. pUIData->m_wState |= UPDUI_RADIO;
  1802. pUIData->m_nIDFirst = (WORD)nIDFirst;
  1803. pUIData->m_nIDLast = (WORD)nIDLast;
  1804. if(bForceUpdate)
  1805. pUIData->m_wState |= pMap->m_wType;
  1806. if(pUIData->m_wState & pMap->m_wType)
  1807. m_wDirtyType |= pMap->m_wType;
  1808. }
  1809. else if((pMap->m_nID >= nIDFirst) && (pMap->m_nID <= nIDLast))
  1810. {
  1811. if(pUIData->m_wState & UPDUI_RADIO)
  1812. {
  1813. pUIData->m_wState &= ~pMap->m_wType;
  1814. pUIData->m_wState &= ~UPDUI_RADIO;
  1815. pUIData->m_nIDFirst = 0;
  1816. pUIData->m_nIDLast = 0;
  1817. }
  1818. }
  1819. if(pMap->m_nID == nIDLast)
  1820. break;
  1821. }
  1822. return TRUE;
  1823. }
  1824. BOOL UISetText(int nID, LPCTSTR lpstrText, BOOL bForceUpdate = FALSE)
  1825. {
  1826. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1827. _AtlUpdateUIData* pUIData = m_pUIData;
  1828. if(pUIData == NULL)
  1829. return FALSE;
  1830. if(lpstrText == NULL)
  1831. lpstrText = _T("");
  1832. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1833. {
  1834. if(nID == (int)pMap->m_nID)
  1835. {
  1836. if((pUIData->m_lpstrText == NULL) || (lstrcmp(pUIData->m_lpstrText, lpstrText) != 0))
  1837. {
  1838. delete [] pUIData->m_lpstrText;
  1839. pUIData->m_lpstrText = NULL;
  1840. int nStrLen = lstrlen(lpstrText);
  1841. ATLTRY(pUIData->m_lpstrText = new TCHAR[nStrLen + 1]);
  1842. if(pUIData->m_lpstrText == NULL)
  1843. {
  1844. ATLTRACE2(atlTraceUI, 0, _T("UISetText - memory allocation failed\n"));
  1845. break;
  1846. }
  1847. ATL::Checked::tcscpy_s(pUIData->m_lpstrText, nStrLen + 1, lpstrText);
  1848. pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);
  1849. }
  1850. if(bForceUpdate)
  1851. pUIData->m_wState |= (UPDUI_TEXT | pMap->m_wType);
  1852. if(pUIData->m_wState & pMap->m_wType)
  1853. m_wDirtyType |= pMap->m_wType;
  1854. break; // found
  1855. }
  1856. }
  1857. return TRUE;
  1858. }
  1859. BOOL UISetDefault(int nID, BOOL bDefault, BOOL bForceUpdate = FALSE)
  1860. {
  1861. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1862. _AtlUpdateUIData* pUIData = m_pUIData;
  1863. if(pUIData == NULL)
  1864. return FALSE;
  1865. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1866. {
  1867. if(nID == (int)pMap->m_nID)
  1868. {
  1869. if(bDefault)
  1870. {
  1871. if((pUIData->m_wState & UPDUI_DEFAULT) == 0)
  1872. {
  1873. pUIData->m_wState |= pMap->m_wType;
  1874. pUIData->m_wState |= UPDUI_DEFAULT;
  1875. }
  1876. }
  1877. else
  1878. {
  1879. if((pUIData->m_wState & UPDUI_DEFAULT) != 0)
  1880. {
  1881. pUIData->m_wState |= pMap->m_wType;
  1882. pUIData->m_wState &= ~UPDUI_DEFAULT;
  1883. pUIData->m_wState |= UPDUI_CLEARDEFAULT;
  1884. }
  1885. }
  1886. if(bForceUpdate)
  1887. pUIData->m_wState |= pMap->m_wType;
  1888. if(pUIData->m_wState & pMap->m_wType)
  1889. m_wDirtyType |= pMap->m_wType;
  1890. break; // found
  1891. }
  1892. }
  1893. return TRUE;
  1894. }
  1895. // methods for complete state set/get
  1896. BOOL UISetState(int nID, DWORD dwState)
  1897. {
  1898. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1899. _AtlUpdateUIData* pUIData = m_pUIData;
  1900. if(pUIData == NULL)
  1901. return FALSE;
  1902. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1903. {
  1904. if(nID == (int)pMap->m_nID)
  1905. {
  1906. pUIData->m_wState = (WORD)(dwState | pMap->m_wType);
  1907. m_wDirtyType |= pMap->m_wType;
  1908. break; // found
  1909. }
  1910. }
  1911. return TRUE;
  1912. }
  1913. DWORD UIGetState(int nID)
  1914. {
  1915. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1916. _AtlUpdateUIData* pUIData = m_pUIData;
  1917. if(pUIData == NULL)
  1918. return 0;
  1919. for( ; pMap->m_nID != (WORD)-1; pMap++, pUIData++)
  1920. {
  1921. if(nID == (int)pMap->m_nID)
  1922. return pUIData->m_wState;
  1923. }
  1924. return 0;
  1925. }
  1926. // methods for updating UI
  1927. BOOL UIUpdateMenuBar(BOOL bForceUpdate = FALSE, BOOL bMainMenu = FALSE)
  1928. {
  1929. if(!(m_wDirtyType & UPDUI_MENUBAR) && !bForceUpdate)
  1930. return TRUE;
  1931. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1932. _AtlUpdateUIData* pUIData = m_pUIData;
  1933. if(pUIData == NULL)
  1934. return FALSE;
  1935. while(pMap->m_nID != (WORD)-1)
  1936. {
  1937. for(int i = 0; i < m_UIElements.GetSize(); i++)
  1938. {
  1939. if(m_UIElements[i].m_wType == UPDUI_MENUBAR)
  1940. {
  1941. HMENU hMenu = ::GetMenu(m_UIElements[i].m_hWnd);
  1942. if((hMenu != NULL) && (pUIData->m_wState & UPDUI_MENUBAR) && (pMap->m_wType & UPDUI_MENUBAR))
  1943. UIUpdateMenuBarElement(pMap->m_nID, pUIData, hMenu);
  1944. }
  1945. if(bMainMenu)
  1946. ::DrawMenuBar(m_UIElements[i].m_hWnd);
  1947. }
  1948. pMap++;
  1949. pUIData->m_wState &= ~UPDUI_MENUBAR;
  1950. if(pUIData->m_wState & UPDUI_TEXT)
  1951. {
  1952. delete [] pUIData->m_lpstrText;
  1953. pUIData->m_lpstrText = NULL;
  1954. pUIData->m_wState &= ~UPDUI_TEXT;
  1955. }
  1956. pUIData++;
  1957. }
  1958. m_wDirtyType &= ~UPDUI_MENUBAR;
  1959. return TRUE;
  1960. }
  1961. BOOL UIUpdateToolBar(BOOL bForceUpdate = FALSE)
  1962. {
  1963. if(!(m_wDirtyType & UPDUI_TOOLBAR) && !bForceUpdate)
  1964. return TRUE;
  1965. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1966. _AtlUpdateUIData* pUIData = m_pUIData;
  1967. if(pUIData == NULL)
  1968. return FALSE;
  1969. while(pMap->m_nID != (WORD)-1)
  1970. {
  1971. for(int i = 0; i < m_UIElements.GetSize(); i++)
  1972. {
  1973. if(m_UIElements[i].m_wType == UPDUI_TOOLBAR)
  1974. {
  1975. if((pUIData->m_wState & UPDUI_TOOLBAR) && (pMap->m_wType & UPDUI_TOOLBAR))
  1976. UIUpdateToolBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
  1977. }
  1978. }
  1979. pMap++;
  1980. pUIData->m_wState &= ~UPDUI_TOOLBAR;
  1981. pUIData++;
  1982. }
  1983. m_wDirtyType &= ~UPDUI_TOOLBAR;
  1984. return TRUE;
  1985. }
  1986. BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE)
  1987. {
  1988. if(!(m_wDirtyType & UPDUI_STATUSBAR) && !bForceUpdate)
  1989. return TRUE;
  1990. const _AtlUpdateUIMap* pMap = m_pUIMap;
  1991. _AtlUpdateUIData* pUIData = m_pUIData;
  1992. if(pUIData == NULL)
  1993. return FALSE;
  1994. while(pMap->m_nID != (WORD)-1)
  1995. {
  1996. for(int i = 0; i < m_UIElements.GetSize(); i++)
  1997. {
  1998. if(m_UIElements[i].m_wType == UPDUI_STATUSBAR)
  1999. {
  2000. if((pUIData->m_wState & UPDUI_STATUSBAR) && (pMap->m_wType & UPDUI_STATUSBAR))
  2001. UIUpdateStatusBarElement(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
  2002. }
  2003. }
  2004. pMap++;
  2005. pUIData->m_wState &= ~UPDUI_STATUSBAR;
  2006. if(pUIData->m_wState & UPDUI_TEXT)
  2007. {
  2008. delete [] pUIData->m_lpstrText;
  2009. pUIData->m_lpstrText = NULL;
  2010. pUIData->m_wState &= ~UPDUI_TEXT;
  2011. }
  2012. pUIData++;
  2013. }
  2014. m_wDirtyType &= ~UPDUI_STATUSBAR;
  2015. return TRUE;
  2016. }
  2017. BOOL UIUpdateChildWindows(BOOL bForceUpdate = FALSE)
  2018. {
  2019. if(!(m_wDirtyType & UPDUI_CHILDWINDOW) && !bForceUpdate)
  2020. return TRUE;
  2021. const _AtlUpdateUIMap* pMap = m_pUIMap;
  2022. _AtlUpdateUIData* pUIData = m_pUIData;
  2023. if(pUIData == NULL)
  2024. return FALSE;
  2025. while(pMap->m_nID != (WORD)-1)
  2026. {
  2027. for(int i = 0; i < m_UIElements.GetSize(); i++)
  2028. {
  2029. if(m_UIElements[i].m_wType == UPDUI_CHILDWINDOW)
  2030. {
  2031. if((pUIData->m_wState & UPDUI_CHILDWINDOW) && (pMap->m_wType & UPDUI_CHILDWINDOW))
  2032. UIUpdateChildWindow(pMap->m_nID, pUIData, m_UIElements[i].m_hWnd);
  2033. }
  2034. }
  2035. pMap++;
  2036. pUIData->m_wState &= ~UPDUI_CHILDWINDOW;
  2037. if(pUIData->m_wState & UPDUI_TEXT)
  2038. {
  2039. delete [] pUIData->m_lpstrText;
  2040. pUIData->m_lpstrText = NULL;
  2041. pUIData->m_wState &= ~UPDUI_TEXT;
  2042. }
  2043. pUIData++;
  2044. }
  2045. m_wDirtyType &= ~UPDUI_CHILDWINDOW;
  2046. return TRUE;
  2047. }
  2048. // internal element specific methods
  2049. static void UIUpdateMenuBarElement(int nID, _AtlUpdateUIData* pUIData, HMENU hMenu)
  2050. {
  2051. if((pUIData->m_wState & UPDUI_CLEARDEFAULT) != 0)
  2052. {
  2053. ::SetMenuDefaultItem(hMenu, (UINT)-1, 0);
  2054. pUIData->m_wState &= ~UPDUI_CLEARDEFAULT;
  2055. }
  2056. CMenuItemInfo mii;
  2057. mii.fMask = MIIM_STATE;
  2058. mii.wID = nID;
  2059. if((pUIData->m_wState & UPDUI_DISABLED) != 0)
  2060. mii.fState |= MFS_DISABLED | MFS_GRAYED;
  2061. else
  2062. mii.fState |= MFS_ENABLED;
  2063. if((pUIData->m_wState & UPDUI_CHECKED) != 0)
  2064. mii.fState |= MFS_CHECKED;
  2065. else
  2066. mii.fState |= MFS_UNCHECKED;
  2067. if((pUIData->m_wState & UPDUI_DEFAULT) != 0)
  2068. mii.fState |= MFS_DEFAULT;
  2069. if((pUIData->m_wState & UPDUI_TEXT) != 0)
  2070. {
  2071. CMenuItemInfo miiNow;
  2072. miiNow.fMask = MIIM_TYPE;
  2073. miiNow.wID = nID;
  2074. if(::GetMenuItemInfo(hMenu, nID, FALSE, &miiNow))
  2075. {
  2076. mii.fMask |= MIIM_TYPE;
  2077. // MFT_BITMAP and MFT_SEPARATOR don't go together with MFT_STRING
  2078. mii.fType |= (miiNow.fType & ~(MFT_BITMAP | MFT_SEPARATOR)) | MFT_STRING;
  2079. mii.dwTypeData = pUIData->m_lpstrText;
  2080. }
  2081. }
  2082. ::SetMenuItemInfo(hMenu, nID, FALSE, &mii);
  2083. }
  2084. static void UIUpdateToolBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndToolBar)
  2085. {
  2086. // Note: only handles enabled/disabled, checked state, and radio (press)
  2087. ::SendMessage(hWndToolBar, TB_ENABLEBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);
  2088. ::SendMessage(hWndToolBar, TB_CHECKBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED) ? TRUE : FALSE);
  2089. ::SendMessage(hWndToolBar, TB_INDETERMINATE, nID, (LPARAM)(pUIData->m_wState & UPDUI_CHECKED2) ? TRUE : FALSE);
  2090. ::SendMessage(hWndToolBar, TB_PRESSBUTTON, nID, (LPARAM)(pUIData->m_wState & UPDUI_RADIO) ? TRUE : FALSE);
  2091. }
  2092. static void UIUpdateStatusBarElement(int nID, _AtlUpdateUIData* pUIData, HWND hWndStatusBar)
  2093. {
  2094. // Note: only handles text
  2095. if(pUIData->m_wState & UPDUI_TEXT)
  2096. ::SendMessage(hWndStatusBar, SB_SETTEXT, nID, (LPARAM)pUIData->m_lpstrText);
  2097. }
  2098. static void UIUpdateChildWindow(int nID, _AtlUpdateUIData* pUIData, HWND hWnd)
  2099. {
  2100. HWND hChild = ::GetDlgItem(hWnd, nID);
  2101. ::EnableWindow(hChild, (pUIData->m_wState & UPDUI_DISABLED) ? FALSE : TRUE);
  2102. // for check and radio, assume that window is a button
  2103. int nCheck = BST_UNCHECKED;
  2104. if((pUIData->m_wState & UPDUI_CHECKED) || (pUIData->m_wState & UPDUI_RADIO))
  2105. nCheck = BST_CHECKED;
  2106. else if(pUIData->m_wState & UPDUI_CHECKED2)
  2107. nCheck = BST_INDETERMINATE;
  2108. ::SendMessage(hChild, BM_SETCHECK, nCheck, 0L);
  2109. if(pUIData->m_wState & UPDUI_DEFAULT)
  2110. {
  2111. DWORD dwRet = (DWORD)::SendMessage(hWnd, DM_GETDEFID, 0, 0L);
  2112. if(HIWORD(dwRet) == DC_HASDEFID)
  2113. {
  2114. HWND hOldDef = ::GetDlgItem(hWnd, (int)(short)LOWORD(dwRet));
  2115. // remove BS_DEFPUSHBUTTON
  2116. ::SendMessage(hOldDef, BM_SETSTYLE, BS_PUSHBUTTON, MAKELPARAM(TRUE, 0));
  2117. }
  2118. ::SendMessage(hWnd, DM_SETDEFID, nID, 0L);
  2119. }
  2120. if(pUIData->m_wState & UPDUI_TEXT)
  2121. ::SetWindowText(hChild, pUIData->m_lpstrText);
  2122. }
  2123. };
  2124. template <class T>
  2125. class CUpdateUI : public CUpdateUIBase
  2126. {
  2127. public:
  2128. CUpdateUI()
  2129. {
  2130. T* pT = static_cast<T*>(this);
  2131. (void)pT; // avoid level 4 warning
  2132. const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();
  2133. m_pUIMap = pMap;
  2134. ATLASSERT(m_pUIMap != NULL);
  2135. int nCount = 1;
  2136. for( ; pMap->m_nID != (WORD)-1; nCount++)
  2137. pMap++;
  2138. // check for duplicates (debug only)
  2139. #ifdef _DEBUG
  2140. for(int i = 0; i < nCount; i++)
  2141. {
  2142. for(int j = 0; j < nCount; j++)
  2143. {
  2144. // shouldn't have duplicates in the update UI map
  2145. if(i != j)
  2146. ATLASSERT(m_pUIMap[j].m_nID != m_pUIMap[i].m_nID);
  2147. }
  2148. }
  2149. #endif // _DEBUG
  2150. ATLTRY(m_pUIData = new _AtlUpdateUIData[nCount]);
  2151. ATLASSERT(m_pUIData != NULL);
  2152. if(m_pUIData != NULL)
  2153. memset(m_pUIData, 0, sizeof(_AtlUpdateUIData) * nCount);
  2154. }
  2155. };
  2156. ///////////////////////////////////////////////////////////////////////////////
  2157. // CDynamicUpdateUI - allows update elements to dynamically added and removed
  2158. // in addition to a static update UI map
  2159. template <class T>
  2160. class CDynamicUpdateUI : public CUpdateUIBase
  2161. {
  2162. public:
  2163. // Data members
  2164. ATL::CSimpleArray<_AtlUpdateUIMap> m_arrUIMap; // copy of the static UI data
  2165. ATL::CSimpleArray<_AtlUpdateUIData> m_arrUIData; // instance UI data
  2166. // Constructor/destructor
  2167. CDynamicUpdateUI()
  2168. {
  2169. T* pT = static_cast<T*>(this);
  2170. (void)pT; // avoid level 4 warning
  2171. const _AtlUpdateUIMap* pMap = pT->GetUpdateUIMap();
  2172. ATLASSERT(pMap != NULL);
  2173. for(;;)
  2174. {
  2175. BOOL bRet = m_arrUIMap.Add(*(_AtlUpdateUIMap*)pMap);
  2176. ATLASSERT(bRet);
  2177. if(bRet != FALSE)
  2178. {
  2179. _AtlUpdateUIData data = { 0, NULL };
  2180. bRet = m_arrUIData.Add(data);
  2181. ATLASSERT(bRet);
  2182. }
  2183. if(pMap->m_nID == (WORD)-1)
  2184. break;
  2185. pMap++;
  2186. }
  2187. ATLASSERT(m_arrUIMap.GetSize() == m_arrUIData.GetSize());
  2188. #ifdef _DEBUG
  2189. // check for duplicates (debug only)
  2190. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  2191. {
  2192. for(int j = 0; j < m_arrUIMap.GetSize(); j++)
  2193. {
  2194. // shouldn't have duplicates in the update UI map
  2195. if(i != j)
  2196. ATLASSERT(m_arrUIMap[j].m_nID != m_arrUIMap[i].m_nID);
  2197. }
  2198. }
  2199. #endif // _DEBUG
  2200. // Set internal data pointers to point to the new data arrays
  2201. m_pUIMap = m_arrUIMap.m_aT;
  2202. m_pUIData = m_arrUIData.m_aT;
  2203. }
  2204. ~CDynamicUpdateUI()
  2205. {
  2206. for(int i = 0; i < m_arrUIData.GetSize(); i++)
  2207. {
  2208. if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0)
  2209. delete [] m_arrUIData[i].m_lpstrText;
  2210. }
  2211. // Reset internal data pointers (memory will be released by CSimpleArray d-tor)
  2212. m_pUIMap = NULL;
  2213. m_pUIData = NULL;
  2214. }
  2215. // Methods for dynamically adding and removing update elements
  2216. bool UIAddUpdateElement(WORD nID, WORD wType)
  2217. {
  2218. // check for duplicates
  2219. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  2220. {
  2221. // shouldn't have duplicates in the update UI map
  2222. ATLASSERT(m_arrUIMap[i].m_nID != nID);
  2223. if(m_arrUIMap[i].m_nID == nID)
  2224. return false;
  2225. }
  2226. bool bRetVal = false;
  2227. // Add new end element
  2228. _AtlUpdateUIMap uumEnd = { (WORD)-1, 0 };
  2229. BOOL bRet = m_arrUIMap.Add(uumEnd);
  2230. ATLASSERT(bRet);
  2231. if(bRet != FALSE)
  2232. {
  2233. _AtlUpdateUIData uud = { 0, NULL };
  2234. bRet = m_arrUIData.Add(uud);
  2235. ATLASSERT(bRet);
  2236. // Set new data to the previous end element
  2237. if(bRet != FALSE)
  2238. {
  2239. int nSize = m_arrUIMap.GetSize();
  2240. _AtlUpdateUIMap uum = { nID, wType };
  2241. m_arrUIMap.SetAtIndex(nSize - 2, uum);
  2242. m_arrUIData.SetAtIndex(nSize - 2, uud);
  2243. // Set internal data pointers again, just in case that memory moved
  2244. m_pUIMap = m_arrUIMap.m_aT;
  2245. m_pUIData = m_arrUIData.m_aT;
  2246. bRetVal = true;
  2247. }
  2248. }
  2249. return bRetVal;
  2250. }
  2251. bool UIRemoveUpdateElement(WORD nID)
  2252. {
  2253. bool bRetVal = false;
  2254. for(int i = 0; i < m_arrUIMap.GetSize(); i++)
  2255. {
  2256. if(m_arrUIMap[i].m_nID == nID)
  2257. {
  2258. if((m_arrUIData[i].m_wState & UPDUI_TEXT) != 0)
  2259. delete [] m_arrUIData[i].m_lpstrText;
  2260. BOOL bRet = m_arrUIMap.RemoveAt(i);
  2261. ATLASSERT(bRet);
  2262. bRet = m_arrUIData.RemoveAt(i);
  2263. ATLASSERT(bRet);
  2264. bRetVal = true;
  2265. break;
  2266. }
  2267. }
  2268. return bRetVal;
  2269. }
  2270. };
  2271. ///////////////////////////////////////////////////////////////////////////////
  2272. // CAutoUpdateUI : Automatic mapping of UI elements
  2273. template <class T>
  2274. class CAutoUpdateUI : public CDynamicUpdateUI<T>
  2275. {
  2276. public:
  2277. LPCTSTR UIGetText(int nID)
  2278. {
  2279. for(int i = 0; i < this->m_arrUIMap.GetSize(); i++)
  2280. {
  2281. if(this->m_arrUIMap[i].m_nID == nID)
  2282. return this->m_arrUIData[i].m_lpstrText;
  2283. }
  2284. return NULL;
  2285. }
  2286. // Element
  2287. template <WORD t_wType>
  2288. bool UIAddElement(UINT nID)
  2289. {
  2290. // check for existing UI map element
  2291. for(int i = 0; i < this->m_arrUIMap.GetSize(); i++)
  2292. {
  2293. if(this->m_arrUIMap[i].m_nID == nID)
  2294. {
  2295. // set requested type
  2296. this->m_arrUIMap[i].m_wType |= t_wType;
  2297. return true;
  2298. }
  2299. }
  2300. // Add element to UI map with requested type
  2301. return this->UIAddUpdateElement((WORD)nID, t_wType);
  2302. }
  2303. template <WORD t_wType>
  2304. bool UIRemoveElement(UINT nID)
  2305. {
  2306. for(int i = 0; i < this->m_arrUIMap.GetSize(); i++)
  2307. {
  2308. if(this->m_arrUIMap[i].m_nID == nID) // matching UI map element
  2309. {
  2310. WORD wType = this->m_arrUIMap[i].m_wType & ~t_wType;
  2311. if (wType != 0) // has other types
  2312. {
  2313. this->m_arrUIMap[i].m_wType = wType; // keep other types
  2314. return true;
  2315. }
  2316. else
  2317. {
  2318. return this->UIRemoveUpdateElement((WORD)nID);
  2319. }
  2320. }
  2321. }
  2322. return false;
  2323. }
  2324. // Menu
  2325. bool UIAddMenu(HMENU hMenu, bool bSetText = false)
  2326. {
  2327. ATLASSERT(::IsMenu(hMenu));
  2328. MENUITEMINFO mii = {sizeof(MENUITEMINFO), MIIM_TYPE | MIIM_ID | MIIM_SUBMENU};
  2329. // Complete the UI map
  2330. for (INT uItem = 0; CMenuHandle(hMenu).GetMenuItemInfo(uItem, TRUE, &mii); uItem++)
  2331. {
  2332. if(mii.hSubMenu)
  2333. {
  2334. // Add submenu to UI map
  2335. UIAddMenu(mii.hSubMenu, bSetText);
  2336. }
  2337. else if (mii.wID != 0)
  2338. {
  2339. // Add element to UI map
  2340. UIAddElement<CDynamicUpdateUI<T>::UPDUI_MENUPOPUP>(mii.wID);
  2341. if (bSetText)
  2342. {
  2343. TCHAR sText[64] = {};
  2344. if (GetMenuString(hMenu, uItem, sText, 64, MF_BYPOSITION))
  2345. this->UISetText(mii.wID, sText);
  2346. }
  2347. }
  2348. }
  2349. return true;
  2350. }
  2351. bool UIAddMenu(UINT uID, bool bSetText = false)
  2352. {
  2353. CMenu menu;
  2354. ATLVERIFY(menu.LoadMenu(uID));
  2355. return UIAddMenu(menu, bSetText);
  2356. }
  2357. // ToolBar
  2358. bool UIAddToolBar(HWND hWndToolBar)
  2359. {
  2360. ATLASSERT(::IsWindow(hWndToolBar));
  2361. TBBUTTONINFO tbbi = { sizeof(TBBUTTONINFO), TBIF_COMMAND | TBIF_STYLE | TBIF_BYINDEX };
  2362. // Add toolbar buttons
  2363. for (int uItem = 0; ::SendMessage(hWndToolBar, TB_GETBUTTONINFO, uItem, (LPARAM)&tbbi) != -1; uItem++)
  2364. {
  2365. if (tbbi.fsStyle ^ BTNS_SEP)
  2366. UIAddElement<CDynamicUpdateUI<T>::UPDUI_TOOLBAR>(tbbi.idCommand);
  2367. }
  2368. // Add embedded controls if any
  2369. if (::GetWindow(hWndToolBar, GW_CHILD))
  2370. UIAddChildWindowContainer(hWndToolBar);
  2371. return (CUpdateUIBase::UIAddToolBar(hWndToolBar) != FALSE);
  2372. }
  2373. // Container
  2374. bool UIAddChildWindowContainer(HWND hWnd)
  2375. {
  2376. ATLASSERT(::IsWindow(hWnd));
  2377. // Add children controls if any
  2378. for (ATL::CWindow wCtl = ::GetWindow(hWnd, GW_CHILD); wCtl.IsWindow(); wCtl = wCtl.GetWindow(GW_HWNDNEXT))
  2379. {
  2380. int id = wCtl.GetDlgCtrlID();
  2381. if(id != 0)
  2382. UIAddElement<CDynamicUpdateUI<T>::UPDUI_CHILDWINDOW>(id);
  2383. }
  2384. return (CUpdateUIBase::UIAddChildWindowContainer(hWnd) != FALSE);
  2385. }
  2386. // StatusBar
  2387. BOOL UIUpdateStatusBar(BOOL bForceUpdate = FALSE)
  2388. {
  2389. if(!(this->m_wDirtyType & CDynamicUpdateUI<T>::UPDUI_STATUSBAR) && !bForceUpdate)
  2390. return TRUE;
  2391. for(int i = 0; i < this->m_arrUIMap.GetSize(); i++)
  2392. {
  2393. for(int e = 0; e < this->m_UIElements.GetSize(); e++)
  2394. {
  2395. if((this->m_UIElements[e].m_wType == CDynamicUpdateUI<T>::UPDUI_STATUSBAR) &&
  2396. (this->m_arrUIMap[i].m_wType & CDynamicUpdateUI<T>::UPDUI_STATUSBAR) &&
  2397. (this->m_arrUIData[i].m_wState & CDynamicUpdateUI<T>::UPDUI_STATUSBAR))
  2398. {
  2399. this->UIUpdateStatusBarElement(this->m_arrUIMap[i].m_nID, &this->m_arrUIData[i], this->m_UIElements[e].m_hWnd);
  2400. this->m_arrUIData[i].m_wState &= ~CDynamicUpdateUI<T>::UPDUI_STATUSBAR;
  2401. if(this->m_arrUIData[i].m_wState & CDynamicUpdateUI<T>::UPDUI_TEXT)
  2402. this->m_arrUIData[i].m_wState &= ~CDynamicUpdateUI<T>::UPDUI_TEXT;
  2403. }
  2404. }
  2405. }
  2406. this->m_wDirtyType &= ~CDynamicUpdateUI<T>::UPDUI_STATUSBAR;
  2407. return TRUE;
  2408. }
  2409. bool UIAddStatusBar(HWND hWndStatusBar, INT nPanes = 1)
  2410. {
  2411. ATLASSERT(::IsWindow(hWndStatusBar));
  2412. // Add StatusBar panes
  2413. for (int iPane = 0; iPane < nPanes; iPane++)
  2414. UIAddElement<CDynamicUpdateUI<T>::UPDUI_STATUSBAR>(ID_DEFAULT_PANE + iPane);
  2415. return (CUpdateUIBase::UIAddStatusBar(hWndStatusBar) != FALSE);
  2416. }
  2417. // UI Map used if derived class has none
  2418. BEGIN_UPDATE_UI_MAP(CAutoUpdateUI)
  2419. END_UPDATE_UI_MAP()
  2420. };
  2421. ///////////////////////////////////////////////////////////////////////////////
  2422. // CDialogResize - provides support for resizing dialog controls
  2423. // (works for any window that has child controls)
  2424. // Put CDialogResize in the list of base classes for a dialog (or even plain window),
  2425. // then implement DLGRESIZE map by specifying controls and groups of control
  2426. // and using DLSZ_* values to specify how are they supposed to be resized.
  2427. //
  2428. // Notes:
  2429. // - Resizeable border (WS_THICKFRAME style) should be set in the dialog template
  2430. // for top level dialogs (popup or overlapped), so that users can resize the dialog.
  2431. // - Some flags cannot be combined; for instance DLSZ_CENTER_X overrides DLSZ_SIZE_X,
  2432. // DLSZ_SIZE_X overrides DLSZ_MOVE_X. X and Y flags can be combined.
  2433. // - Order of controls is important - group controls are resized and moved based
  2434. // on the position of the previous control in a group.
  2435. // dialog resize map macros
  2436. struct _AtlDlgResizeMap
  2437. {
  2438. int m_nCtlID;
  2439. DWORD m_dwResizeFlags;
  2440. };
  2441. #define BEGIN_DLGRESIZE_MAP(thisClass) \
  2442. static const WTL::_AtlDlgResizeMap* GetDlgResizeMap() \
  2443. { \
  2444. static const WTL::_AtlDlgResizeMap theMap[] = \
  2445. {
  2446. #define END_DLGRESIZE_MAP() \
  2447. { -1, 0 }, \
  2448. }; \
  2449. return theMap; \
  2450. }
  2451. #define DLGRESIZE_CONTROL(id, flags) \
  2452. { id, flags },
  2453. #define BEGIN_DLGRESIZE_GROUP() \
  2454. { -1, _DLSZ_BEGIN_GROUP },
  2455. #define END_DLGRESIZE_GROUP() \
  2456. { -1, _DLSZ_END_GROUP },
  2457. template <class T>
  2458. class CDialogResize
  2459. {
  2460. public:
  2461. // Data declarations and members
  2462. enum
  2463. {
  2464. DLSZ_SIZE_X = 0x00000001,
  2465. DLSZ_SIZE_Y = 0x00000002,
  2466. DLSZ_MOVE_X = 0x00000004,
  2467. DLSZ_MOVE_Y = 0x00000008,
  2468. DLSZ_REPAINT = 0x00000010,
  2469. DLSZ_CENTER_X = 0x00000020,
  2470. DLSZ_CENTER_Y = 0x00000040,
  2471. // internal use only
  2472. _DLSZ_BEGIN_GROUP = 0x00001000,
  2473. _DLSZ_END_GROUP = 0x00002000,
  2474. _DLSZ_GRIPPER = 0x00004000
  2475. };
  2476. struct _AtlDlgResizeData
  2477. {
  2478. int m_nCtlID;
  2479. DWORD m_dwResizeFlags;
  2480. RECT m_rect;
  2481. int GetGroupCount() const
  2482. {
  2483. return (int)LOBYTE(HIWORD(m_dwResizeFlags));
  2484. }
  2485. void SetGroupCount(int nCount)
  2486. {
  2487. ATLASSERT((nCount > 0) && (nCount < 256));
  2488. DWORD dwCount = (DWORD)MAKELONG(0, MAKEWORD(nCount, 0));
  2489. m_dwResizeFlags &= 0xFF00FFFF;
  2490. m_dwResizeFlags |= dwCount;
  2491. }
  2492. bool operator ==(const _AtlDlgResizeData& r) const
  2493. { return ((m_nCtlID == r.m_nCtlID) && (m_dwResizeFlags == r.m_dwResizeFlags)); }
  2494. };
  2495. ATL::CSimpleArray<_AtlDlgResizeData> m_arrData;
  2496. SIZE m_sizeDialog;
  2497. POINT m_ptMinTrackSize;
  2498. bool m_bGripper;
  2499. // Constructor
  2500. CDialogResize() : m_bGripper(false)
  2501. {
  2502. m_sizeDialog.cx = 0;
  2503. m_sizeDialog.cy = 0;
  2504. m_ptMinTrackSize.x = -1;
  2505. m_ptMinTrackSize.y = -1;
  2506. }
  2507. // Operations
  2508. void DlgResize_Init(bool bAddGripper = true, bool bUseMinTrackSize = true, DWORD dwForceStyle = WS_CLIPCHILDREN)
  2509. {
  2510. T* pT = static_cast<T*>(this);
  2511. ATLASSERT(::IsWindow(pT->m_hWnd));
  2512. DWORD dwStyle = pT->GetStyle();
  2513. #ifdef _DEBUG
  2514. // Debug only: Check if top level dialogs have a resizeable border.
  2515. if(((dwStyle & WS_CHILD) == 0) && ((dwStyle & WS_THICKFRAME) == 0))
  2516. ATLTRACE2(atlTraceUI, 0, _T("DlgResize_Init - warning: top level dialog without the WS_THICKFRAME style - user cannot resize it\n"));
  2517. #endif // _DEBUG
  2518. // Force specified styles (default WS_CLIPCHILDREN reduces flicker)
  2519. if((dwStyle & dwForceStyle) != dwForceStyle)
  2520. pT->ModifyStyle(0, dwForceStyle);
  2521. // Adding this style removes an empty icon that dialogs with WS_THICKFRAME have.
  2522. // Setting icon to NULL is required when XP themes are active.
  2523. // Note: This will not prevent adding an icon for the dialog using SetIcon()
  2524. if((dwStyle & WS_CHILD) == 0)
  2525. {
  2526. pT->ModifyStyleEx(0, WS_EX_DLGMODALFRAME);
  2527. if(pT->GetIcon(FALSE) == NULL)
  2528. pT->SetIcon(NULL, FALSE);
  2529. }
  2530. // Cleanup in case of multiple initialization
  2531. // block: first check for the gripper control, destroy it if needed
  2532. {
  2533. ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
  2534. if(wndGripper.IsWindow() && (m_arrData.GetSize() > 0) && (m_arrData[0].m_dwResizeFlags & _DLSZ_GRIPPER) != 0)
  2535. wndGripper.DestroyWindow();
  2536. }
  2537. // clear out everything else
  2538. m_arrData.RemoveAll();
  2539. m_sizeDialog.cx = 0;
  2540. m_sizeDialog.cy = 0;
  2541. m_ptMinTrackSize.x = -1;
  2542. m_ptMinTrackSize.y = -1;
  2543. // Get initial dialog client size
  2544. RECT rectDlg = {};
  2545. pT->GetClientRect(&rectDlg);
  2546. m_sizeDialog.cx = rectDlg.right;
  2547. m_sizeDialog.cy = rectDlg.bottom;
  2548. // Create gripper if requested
  2549. m_bGripper = false;
  2550. if(bAddGripper)
  2551. {
  2552. // shouldn't exist already
  2553. ATLASSERT(!pT->GetDlgItem(ATL_IDW_STATUS_BAR).IsWindow());
  2554. if(!pT->GetDlgItem(ATL_IDW_STATUS_BAR).IsWindow())
  2555. {
  2556. ATL::CWindow wndGripper;
  2557. wndGripper.Create(_T("SCROLLBAR"), pT->m_hWnd, rectDlg, NULL, WS_CHILD | WS_VISIBLE | WS_GROUP | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, ATL_IDW_STATUS_BAR);
  2558. ATLASSERT(wndGripper.IsWindow());
  2559. if(wndGripper.IsWindow())
  2560. {
  2561. m_bGripper = true;
  2562. RECT rectCtl = {};
  2563. wndGripper.GetWindowRect(&rectCtl);
  2564. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
  2565. _AtlDlgResizeData data = { ATL_IDW_STATUS_BAR, DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | _DLSZ_GRIPPER, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
  2566. m_arrData.Add(data);
  2567. }
  2568. }
  2569. }
  2570. // Get min track position if requested
  2571. if(bUseMinTrackSize)
  2572. {
  2573. if((dwStyle & WS_CHILD) != 0)
  2574. {
  2575. RECT rect = {};
  2576. pT->GetClientRect(&rect);
  2577. m_ptMinTrackSize.x = rect.right - rect.left;
  2578. m_ptMinTrackSize.y = rect.bottom - rect.top;
  2579. }
  2580. else
  2581. {
  2582. RECT rect = {};
  2583. pT->GetWindowRect(&rect);
  2584. m_ptMinTrackSize.x = rect.right - rect.left;
  2585. m_ptMinTrackSize.y = rect.bottom - rect.top;
  2586. }
  2587. }
  2588. // Walk the map and initialize data
  2589. const _AtlDlgResizeMap* pMap = pT->GetDlgResizeMap();
  2590. ATLASSERT(pMap != NULL);
  2591. int nGroupStart = -1;
  2592. for(int nCount = 1; !((pMap->m_nCtlID == -1) && (pMap->m_dwResizeFlags == 0)); nCount++, pMap++)
  2593. {
  2594. if(pMap->m_nCtlID == -1)
  2595. {
  2596. switch(pMap->m_dwResizeFlags)
  2597. {
  2598. case _DLSZ_BEGIN_GROUP:
  2599. ATLASSERT(nGroupStart == -1);
  2600. nGroupStart = m_arrData.GetSize();
  2601. break;
  2602. case _DLSZ_END_GROUP:
  2603. {
  2604. ATLASSERT(nGroupStart != -1);
  2605. int nGroupCount = m_arrData.GetSize() - nGroupStart;
  2606. m_arrData[nGroupStart].SetGroupCount(nGroupCount);
  2607. nGroupStart = -1;
  2608. }
  2609. break;
  2610. default:
  2611. ATLASSERT(FALSE && _T("Invalid DLGRESIZE Map Entry"));
  2612. break;
  2613. }
  2614. }
  2615. else
  2616. {
  2617. // this ID conflicts with the default gripper one
  2618. ATLASSERT(m_bGripper ? (pMap->m_nCtlID != ATL_IDW_STATUS_BAR) : TRUE);
  2619. ATL::CWindow ctl = pT->GetDlgItem(pMap->m_nCtlID);
  2620. ATLASSERT(ctl.IsWindow());
  2621. RECT rectCtl = {};
  2622. ctl.GetWindowRect(&rectCtl);
  2623. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
  2624. DWORD dwGroupFlag = ((nGroupStart != -1) && (m_arrData.GetSize() == nGroupStart)) ? _DLSZ_BEGIN_GROUP : 0;
  2625. _AtlDlgResizeData data = { pMap->m_nCtlID, pMap->m_dwResizeFlags | dwGroupFlag, { rectCtl.left, rectCtl.top, rectCtl.right, rectCtl.bottom } };
  2626. m_arrData.Add(data);
  2627. }
  2628. }
  2629. ATLASSERT((nGroupStart == -1) && _T("No End Group Entry in the DLGRESIZE Map"));
  2630. }
  2631. void DlgResize_UpdateLayout(int cxWidth, int cyHeight)
  2632. {
  2633. T* pT = static_cast<T*>(this);
  2634. ATLASSERT(::IsWindow(pT->m_hWnd));
  2635. // Restrict minimum size if requested
  2636. if(((pT->GetStyle() & WS_CHILD) != 0) && (m_ptMinTrackSize.x != -1) && (m_ptMinTrackSize.y != -1))
  2637. {
  2638. if(cxWidth < m_ptMinTrackSize.x)
  2639. cxWidth = m_ptMinTrackSize.x;
  2640. if(cyHeight < m_ptMinTrackSize.y)
  2641. cyHeight = m_ptMinTrackSize.y;
  2642. }
  2643. BOOL bVisible = pT->IsWindowVisible();
  2644. if(bVisible)
  2645. pT->SetRedraw(FALSE);
  2646. for(int i = 0; i < m_arrData.GetSize(); i++)
  2647. {
  2648. if((m_arrData[i].m_dwResizeFlags & _DLSZ_BEGIN_GROUP) != 0) // start of a group
  2649. {
  2650. int nGroupCount = m_arrData[i].GetGroupCount();
  2651. ATLASSERT((nGroupCount > 0) && ((i + nGroupCount - 1) < m_arrData.GetSize()));
  2652. RECT rectGroup = m_arrData[i].m_rect;
  2653. int j = 1;
  2654. for(j = 1; j < nGroupCount; j++)
  2655. {
  2656. rectGroup.left = __min(rectGroup.left, m_arrData[i + j].m_rect.left);
  2657. rectGroup.top = __min(rectGroup.top, m_arrData[i + j].m_rect.top);
  2658. rectGroup.right = __max(rectGroup.right, m_arrData[i + j].m_rect.right);
  2659. rectGroup.bottom = __max(rectGroup.bottom, m_arrData[i + j].m_rect.bottom);
  2660. }
  2661. for(j = 0; j < nGroupCount; j++)
  2662. {
  2663. _AtlDlgResizeData* pDataPrev = NULL;
  2664. if(j > 0)
  2665. pDataPrev = &(m_arrData[i + j - 1]);
  2666. pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i + j], true, pDataPrev);
  2667. }
  2668. i += nGroupCount - 1; // increment to skip all group controls
  2669. }
  2670. else // one control entry
  2671. {
  2672. RECT rectGroup = {};
  2673. pT->DlgResize_PositionControl(cxWidth, cyHeight, rectGroup, m_arrData[i], false);
  2674. }
  2675. }
  2676. if(bVisible)
  2677. pT->SetRedraw(TRUE);
  2678. pT->RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
  2679. }
  2680. // Message map and handlers
  2681. BEGIN_MSG_MAP(CDialogResize)
  2682. MESSAGE_HANDLER(WM_SIZE, OnSize)
  2683. MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)
  2684. END_MSG_MAP()
  2685. LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
  2686. {
  2687. T* pT = static_cast<T*>(this);
  2688. if(m_bGripper)
  2689. {
  2690. ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
  2691. if(wParam == SIZE_MAXIMIZED)
  2692. wndGripper.ShowWindow(SW_HIDE);
  2693. else if(wParam == SIZE_RESTORED)
  2694. wndGripper.ShowWindow(SW_SHOW);
  2695. }
  2696. if(wParam != SIZE_MINIMIZED)
  2697. {
  2698. ATLASSERT(::IsWindow(pT->m_hWnd));
  2699. pT->DlgResize_UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
  2700. }
  2701. return 0;
  2702. }
  2703. LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  2704. {
  2705. if((m_ptMinTrackSize.x != -1) && (m_ptMinTrackSize.y != -1))
  2706. {
  2707. LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
  2708. lpMMI->ptMinTrackSize = m_ptMinTrackSize;
  2709. }
  2710. return 0;
  2711. }
  2712. // Implementation
  2713. bool DlgResize_PositionControl(int cxWidth, int cyHeight, RECT& rectGroup, _AtlDlgResizeData& data, bool bGroup,
  2714. _AtlDlgResizeData* pDataPrev = NULL)
  2715. {
  2716. T* pT = static_cast<T*>(this);
  2717. ATLASSERT(::IsWindow(pT->m_hWnd));
  2718. ATL::CWindow ctl;
  2719. RECT rectCtl = {};
  2720. ctl = pT->GetDlgItem(data.m_nCtlID);
  2721. if(!ctl.GetWindowRect(&rectCtl))
  2722. return false;
  2723. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rectCtl, 2);
  2724. if(bGroup)
  2725. {
  2726. if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0)
  2727. {
  2728. int cxRight = rectGroup.right + cxWidth - m_sizeDialog.cx;
  2729. int cxCtl = data.m_rect.right - data.m_rect.left;
  2730. rectCtl.left = rectGroup.left + (cxRight - rectGroup.left - cxCtl) / 2;
  2731. rectCtl.right = rectCtl.left + cxCtl;
  2732. }
  2733. else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
  2734. {
  2735. rectCtl.left = rectGroup.left + ::MulDiv(data.m_rect.left - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
  2736. if((data.m_dwResizeFlags & DLSZ_SIZE_X) != 0)
  2737. {
  2738. rectCtl.right = rectGroup.left + ::MulDiv(data.m_rect.right - rectGroup.left, rectGroup.right - rectGroup.left + (cxWidth - m_sizeDialog.cx), rectGroup.right - rectGroup.left);
  2739. if(pDataPrev != NULL)
  2740. {
  2741. ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID);
  2742. RECT rcPrev = {};
  2743. ctlPrev.GetWindowRect(&rcPrev);
  2744. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2);
  2745. int dxAdjust = (rectCtl.left - rcPrev.right) - (data.m_rect.left - pDataPrev->m_rect.right);
  2746. rcPrev.right += dxAdjust;
  2747. ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
  2748. }
  2749. }
  2750. else
  2751. {
  2752. rectCtl.right = rectCtl.left + (data.m_rect.right - data.m_rect.left);
  2753. }
  2754. }
  2755. if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0)
  2756. {
  2757. int cyBottom = rectGroup.bottom + cyHeight - m_sizeDialog.cy;
  2758. int cyCtl = data.m_rect.bottom - data.m_rect.top;
  2759. rectCtl.top = rectGroup.top + (cyBottom - rectGroup.top - cyCtl) / 2;
  2760. rectCtl.bottom = rectCtl.top + cyCtl;
  2761. }
  2762. else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
  2763. {
  2764. rectCtl.top = rectGroup.top + ::MulDiv(data.m_rect.top - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
  2765. if((data.m_dwResizeFlags & DLSZ_SIZE_Y) != 0)
  2766. {
  2767. rectCtl.bottom = rectGroup.top + ::MulDiv(data.m_rect.bottom - rectGroup.top, rectGroup.bottom - rectGroup.top + (cyHeight - m_sizeDialog.cy), rectGroup.bottom - rectGroup.top);
  2768. if(pDataPrev != NULL)
  2769. {
  2770. ATL::CWindow ctlPrev = pT->GetDlgItem(pDataPrev->m_nCtlID);
  2771. RECT rcPrev = {};
  2772. ctlPrev.GetWindowRect(&rcPrev);
  2773. ::MapWindowPoints(NULL, pT->m_hWnd, (LPPOINT)&rcPrev, 2);
  2774. int dxAdjust = (rectCtl.top - rcPrev.bottom) - (data.m_rect.top - pDataPrev->m_rect.bottom);
  2775. rcPrev.bottom += dxAdjust;
  2776. ctlPrev.SetWindowPos(NULL, &rcPrev, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE);
  2777. }
  2778. }
  2779. else
  2780. {
  2781. rectCtl.bottom = rectCtl.top + (data.m_rect.bottom - data.m_rect.top);
  2782. }
  2783. }
  2784. }
  2785. else // no group
  2786. {
  2787. if((data.m_dwResizeFlags & DLSZ_CENTER_X) != 0)
  2788. {
  2789. int cxCtl = data.m_rect.right - data.m_rect.left;
  2790. rectCtl.left = (cxWidth - cxCtl) / 2;
  2791. rectCtl.right = rectCtl.left + cxCtl;
  2792. }
  2793. else if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_MOVE_X)) != 0)
  2794. {
  2795. rectCtl.right = data.m_rect.right + (cxWidth - m_sizeDialog.cx);
  2796. if((data.m_dwResizeFlags & DLSZ_MOVE_X) != 0)
  2797. rectCtl.left = rectCtl.right - (data.m_rect.right - data.m_rect.left);
  2798. }
  2799. if((data.m_dwResizeFlags & DLSZ_CENTER_Y) != 0)
  2800. {
  2801. int cyCtl = data.m_rect.bottom - data.m_rect.top;
  2802. rectCtl.top = (cyHeight - cyCtl) / 2;
  2803. rectCtl.bottom = rectCtl.top + cyCtl;
  2804. }
  2805. else if((data.m_dwResizeFlags & (DLSZ_SIZE_Y | DLSZ_MOVE_Y)) != 0)
  2806. {
  2807. rectCtl.bottom = data.m_rect.bottom + (cyHeight - m_sizeDialog.cy);
  2808. if((data.m_dwResizeFlags & DLSZ_MOVE_Y) != 0)
  2809. rectCtl.top = rectCtl.bottom - (data.m_rect.bottom - data.m_rect.top);
  2810. }
  2811. }
  2812. if((data.m_dwResizeFlags & DLSZ_REPAINT) != 0)
  2813. ctl.Invalidate();
  2814. if((data.m_dwResizeFlags & (DLSZ_SIZE_X | DLSZ_SIZE_Y | DLSZ_MOVE_X | DLSZ_MOVE_Y | DLSZ_REPAINT | DLSZ_CENTER_X | DLSZ_CENTER_Y)) != 0)
  2815. ctl.SetWindowPos(NULL, &rectCtl, SWP_NOZORDER | SWP_NOACTIVATE);
  2816. return true;
  2817. }
  2818. };
  2819. ///////////////////////////////////////////////////////////////////////////////
  2820. // CDynamicDialogLayout - support for dialog dynamic layout resource info
  2821. // (AFX_DIALOG_LAYOUT) in VS2015 and higher
  2822. #if (_MSC_VER >= 1900)
  2823. template<class T>
  2824. class CDynamicDialogLayout
  2825. {
  2826. public:
  2827. // Data declarations
  2828. struct _AtlDynamicLayoutData
  2829. {
  2830. HWND m_hWnd;
  2831. char m_nMoveRatioX;
  2832. char m_nMoveRatioY;
  2833. char m_nSizeRatioX;
  2834. char m_nSizeRatioY;
  2835. RECT m_rcInit;
  2836. };
  2837. // Data members
  2838. ATL::CSimpleArray<_AtlDynamicLayoutData> m_arrLayoutData;
  2839. SIZE m_szParentInit;
  2840. POINT m_ptMinTrackSize;
  2841. bool m_bGripper;
  2842. // Constructor
  2843. CDynamicDialogLayout() : m_bGripper(false)
  2844. {
  2845. m_szParentInit.cx = 0;
  2846. m_szParentInit.cy = 0;
  2847. m_ptMinTrackSize.x = -1;
  2848. m_ptMinTrackSize.y = -1;
  2849. }
  2850. // Methods
  2851. void InitDynamicLayout(bool bAddGripper = true, bool bMinTrackSize = true)
  2852. {
  2853. T* pT = static_cast<T*>(this);
  2854. ATLASSERT(::IsWindow(pT->m_hWnd));
  2855. // Cleanup in case of multiple initialization
  2856. // block: first check for the gripper control, destroy it if needed
  2857. {
  2858. ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
  2859. if(wndGripper.IsWindow() != FALSE)
  2860. wndGripper.DestroyWindow();
  2861. }
  2862. // clear out everything else
  2863. m_arrLayoutData.RemoveAll();
  2864. m_ptMinTrackSize.x = -1;
  2865. m_ptMinTrackSize.y = -1;
  2866. m_szParentInit.cx = 0;
  2867. m_szParentInit.cy = 0;
  2868. m_bGripper = false;
  2869. CResource rcLayout;
  2870. if(rcLayout.Load(_T("AFX_DIALOG_LAYOUT"), pT->IDD))
  2871. {
  2872. int nCount = rcLayout.GetSize() / sizeof(WORD);
  2873. if(nCount > 1)
  2874. {
  2875. RECT rcParent = {};
  2876. pT->GetWindowRect(&rcParent);
  2877. m_szParentInit.cx = rcParent.right - rcParent.left;
  2878. m_szParentInit.cy = rcParent.bottom - rcParent.top;
  2879. WORD* pnData = (WORD*)rcLayout.Lock();
  2880. WORD wVersion = *pnData; // AFX_DIALOG_LAYOUT version
  2881. ATLASSERT(wVersion == 0);
  2882. if(wVersion == 0)
  2883. {
  2884. pnData++; // skip version
  2885. ATL::CWindow wndChild = pT->GetWindow(GW_CHILD);
  2886. for(int i = 0; (i < nCount) && (wndChild.m_hWnd != NULL); i += 4)
  2887. {
  2888. char nMoveRatioX = _GetDataPct(pnData[i]);
  2889. char nMoveRatioY = _GetDataPct(pnData[i + 1]);
  2890. char nSizeRatioX = _GetDataPct(pnData[i + 2]);
  2891. char nSizeRatioY = _GetDataPct(pnData[i + 3]);
  2892. bool bValid = ((nMoveRatioX != -1) && (nMoveRatioY != -1) && (nSizeRatioX != -1) && (nSizeRatioY != -1));
  2893. bool bAction = ((nMoveRatioX != 0) || (nMoveRatioY != 0) || (nSizeRatioX != 0) || (nSizeRatioY != 0));
  2894. if(bValid && bAction)
  2895. {
  2896. _AtlDynamicLayoutData LayoutData = { wndChild.m_hWnd, nMoveRatioX, nMoveRatioY, nSizeRatioX, nSizeRatioY };
  2897. wndChild.GetWindowRect(&LayoutData.m_rcInit);
  2898. pT->ScreenToClient(&LayoutData.m_rcInit);
  2899. m_arrLayoutData.Add(LayoutData);
  2900. }
  2901. wndChild = wndChild.GetWindow(GW_HWNDNEXT);
  2902. }
  2903. }
  2904. rcLayout.Release();
  2905. }
  2906. }
  2907. if(bAddGripper)
  2908. {
  2909. RECT rcDialog = {};
  2910. pT->GetClientRect(&rcDialog);
  2911. ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
  2912. if(wndGripper.m_hWnd != NULL)
  2913. wndGripper.DestroyWindow();
  2914. wndGripper.Create(_T("SCROLLBAR"), pT->m_hWnd, rcDialog, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | SBS_SIZEBOX | SBS_SIZEGRIP | SBS_SIZEBOXBOTTOMRIGHTALIGN, 0, ATL_IDW_STATUS_BAR);
  2915. ATLASSERT(wndGripper.m_hWnd != NULL);
  2916. if(wndGripper.m_hWnd != NULL)
  2917. {
  2918. m_bGripper = true;
  2919. _AtlDynamicLayoutData LayoutData = { wndGripper.m_hWnd, 100, 100, 0, 0 };
  2920. wndGripper.GetWindowRect(&LayoutData.m_rcInit);
  2921. pT->ScreenToClient(&LayoutData.m_rcInit);
  2922. m_arrLayoutData.Add(LayoutData);
  2923. }
  2924. }
  2925. if(bMinTrackSize)
  2926. {
  2927. RECT rcMinTrack = {};
  2928. if((pT->GetStyle() & WS_CHILD) != 0)
  2929. pT->GetClientRect(&rcMinTrack);
  2930. else
  2931. pT->GetWindowRect(&rcMinTrack);
  2932. m_ptMinTrackSize.x = rcMinTrack.right - rcMinTrack.left;
  2933. m_ptMinTrackSize.y = rcMinTrack.bottom - rcMinTrack.top;
  2934. }
  2935. }
  2936. void UpdateDynamicLayout()
  2937. {
  2938. T* pT = static_cast<T*>(this);
  2939. ATLASSERT(::IsWindow(pT->m_hWnd));
  2940. int nCount = m_arrLayoutData.GetSize();
  2941. if(nCount == 0)
  2942. return;
  2943. RECT rcParent = {};
  2944. pT->GetWindowRect(&rcParent);
  2945. int nDeltaWidth = rcParent.right - rcParent.left - m_szParentInit.cx;
  2946. int nDeltaHeight = rcParent.bottom - rcParent.top - m_szParentInit.cy;
  2947. HDWP hDwp = ::BeginDeferWindowPos(nCount);
  2948. for(int i = 0; i < nCount; i++)
  2949. {
  2950. _AtlDynamicLayoutData& LayoutData = m_arrLayoutData[i];
  2951. ATLASSERT(::IsWindow(LayoutData.m_hWnd) != FALSE);
  2952. int nID = ::GetDlgCtrlID(LayoutData.m_hWnd);
  2953. UINT nFlags = (SWP_NOMOVE | SWP_NOSIZE);
  2954. RECT rcItem = LayoutData.m_rcInit;
  2955. if(((nID == ATL_IDW_STATUS_BAR) || (nDeltaWidth >= 0)) && (LayoutData.m_nMoveRatioX != 0))
  2956. {
  2957. rcItem.left += ::MulDiv(nDeltaWidth, LayoutData.m_nMoveRatioX, 100);
  2958. rcItem.right += ::MulDiv(nDeltaWidth, LayoutData.m_nMoveRatioX, 100);
  2959. nFlags &= ~SWP_NOMOVE;
  2960. }
  2961. if(((nID == ATL_IDW_STATUS_BAR) || (nDeltaHeight >= 0)) && (LayoutData.m_nMoveRatioY != 0))
  2962. {
  2963. rcItem.top += ::MulDiv(nDeltaHeight, LayoutData.m_nMoveRatioY, 100);
  2964. rcItem.bottom += ::MulDiv(nDeltaHeight, LayoutData.m_nMoveRatioY, 100);
  2965. nFlags &= ~SWP_NOMOVE;
  2966. }
  2967. if((nDeltaWidth >= 0) && (LayoutData.m_nSizeRatioX != 0))
  2968. {
  2969. rcItem.right += ::MulDiv(nDeltaWidth, LayoutData.m_nSizeRatioX, 100);
  2970. nFlags &= ~SWP_NOSIZE;
  2971. }
  2972. if((nDeltaHeight >= 0) && (LayoutData.m_nSizeRatioY != 0))
  2973. {
  2974. rcItem.bottom += ::MulDiv(nDeltaHeight, LayoutData.m_nSizeRatioY, 100);
  2975. nFlags &= ~SWP_NOSIZE;
  2976. }
  2977. if(nFlags != (SWP_NOMOVE | SWP_NOSIZE))
  2978. ::DeferWindowPos(hDwp, LayoutData.m_hWnd, NULL, rcItem.left, rcItem.top, rcItem.right - rcItem.left, rcItem.bottom - rcItem.top, nFlags | SWP_NOZORDER | SWP_NOREPOSITION | SWP_NOACTIVATE | SWP_NOCOPYBITS);
  2979. }
  2980. ::EndDeferWindowPos(hDwp);
  2981. }
  2982. // Message map and handlers
  2983. BEGIN_MSG_MAP(CDynamicDialogLayout)
  2984. MESSAGE_HANDLER(WM_SIZE, OnSize)
  2985. MESSAGE_HANDLER(WM_GETMINMAXINFO, OnGetMinMaxInfo)
  2986. END_MSG_MAP()
  2987. LRESULT OnSize(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  2988. {
  2989. T* pT = static_cast<T*>(this);
  2990. if(m_bGripper)
  2991. {
  2992. ATL::CWindow wndGripper = pT->GetDlgItem(ATL_IDW_STATUS_BAR);
  2993. if(wndGripper.m_hWnd != NULL)
  2994. {
  2995. if(wParam == SIZE_MAXIMIZED)
  2996. wndGripper.ShowWindow(SW_HIDE);
  2997. else if(wParam == SIZE_RESTORED)
  2998. wndGripper.ShowWindow(SW_SHOW);
  2999. }
  3000. }
  3001. if(wParam != SIZE_MINIMIZED)
  3002. pT->UpdateDynamicLayout();
  3003. return 0;
  3004. }
  3005. LRESULT OnGetMinMaxInfo(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
  3006. {
  3007. if((m_ptMinTrackSize.x != -1) && (m_ptMinTrackSize.y != -1))
  3008. {
  3009. LPMINMAXINFO lpMMI = (LPMINMAXINFO)lParam;
  3010. lpMMI->ptMinTrackSize = m_ptMinTrackSize;
  3011. }
  3012. return 0;
  3013. }
  3014. // Implementation
  3015. char _GetDataPct(WORD wResData)
  3016. {
  3017. ATLASSERT((wResData >= 0) && (wResData <= 100));
  3018. char nPct = (char)LOBYTE(wResData);
  3019. if((nPct < 0) || (nPct > 100))
  3020. nPct = -1;
  3021. return nPct;
  3022. }
  3023. };
  3024. #endif // (_MSC_VER >= 1900)
  3025. ///////////////////////////////////////////////////////////////////////////////
  3026. // CDoubleBufferImpl - Provides double-buffer painting support to any window
  3027. template <class T>
  3028. class CDoubleBufferImpl
  3029. {
  3030. public:
  3031. // Overrideables
  3032. void DoPaint(CDCHandle /*dc*/)
  3033. {
  3034. // must be implemented in a derived class
  3035. ATLASSERT(FALSE);
  3036. }
  3037. // Message map and handlers
  3038. BEGIN_MSG_MAP(CDoubleBufferImpl)
  3039. MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
  3040. MESSAGE_HANDLER(WM_PAINT, OnPaint)
  3041. MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
  3042. END_MSG_MAP()
  3043. LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  3044. {
  3045. return 1; // no background painting needed
  3046. }
  3047. LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  3048. {
  3049. T* pT = static_cast<T*>(this);
  3050. ATLASSERT(::IsWindow(pT->m_hWnd));
  3051. if(wParam != NULL)
  3052. {
  3053. RECT rect = {};
  3054. pT->GetClientRect(&rect);
  3055. CMemoryDC dcMem((HDC)wParam, rect);
  3056. pT->DoPaint(dcMem.m_hDC);
  3057. }
  3058. else
  3059. {
  3060. CPaintDC dc(pT->m_hWnd);
  3061. CMemoryDC dcMem(dc.m_hDC, dc.m_ps.rcPaint);
  3062. pT->DoPaint(dcMem.m_hDC);
  3063. }
  3064. return 0;
  3065. }
  3066. };
  3067. ///////////////////////////////////////////////////////////////////////////////
  3068. // CDoubleBufferWindowImpl - Implements a double-buffer painting window
  3069. template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
  3070. class ATL_NO_VTABLE CDoubleBufferWindowImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CDoubleBufferImpl< T >
  3071. {
  3072. public:
  3073. BEGIN_MSG_MAP(CDoubleBufferWindowImpl)
  3074. CHAIN_MSG_MAP(CDoubleBufferImpl< T >)
  3075. END_MSG_MAP()
  3076. };
  3077. // command bar support
  3078. #if !defined(__ATLCTRLW_H__)
  3079. #undef CBRM_GETMENU
  3080. #undef CBRM_TRACKPOPUPMENU
  3081. #undef CBRM_GETCMDBAR
  3082. #undef CBRPOPUPMENU
  3083. #endif // !defined(__ATLCTRLW_H__)
  3084. } // namespace WTL
  3085. #endif // __ATLFRAME_H__