12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258 |
- // Windows Template Library - WTL version 10.0
- // Copyright (C) Microsoft Corporation, WTL Team. All rights reserved.
- //
- // This file is a part of the Windows Template Library.
- // The use and distribution terms for this software are covered by the
- // Microsoft Public License (http://opensource.org/licenses/MS-PL)
- // which can be found in the file MS-PL.txt at the root folder.
- #ifndef __ATLCTRLX_H__
- #define __ATLCTRLX_H__
- #pragma once
- #ifndef __ATLAPP_H__
- #error atlctrlx.h requires atlapp.h to be included first
- #endif
- #ifndef __ATLCTRLS_H__
- #error atlctrlx.h requires atlctrls.h to be included first
- #endif
- ///////////////////////////////////////////////////////////////////////////////
- // Classes in this file:
- //
- // CBitmapButtonImpl<T, TBase, TWinTraits>
- // CBitmapButton
- // CCheckListViewCtrlImpl<T, TBase, TWinTraits>
- // CCheckListViewCtrl
- // CHyperLinkImpl<T, TBase, TWinTraits>
- // CHyperLink
- // CWaitCursor
- // CCustomWaitCursor
- // CMultiPaneStatusBarCtrlImpl<T, TBase>
- // CMultiPaneStatusBarCtrl
- // CPaneContainerImpl<T, TBase, TWinTraits>
- // CPaneContainer
- // CSortListViewImpl<T>
- // CSortListViewCtrlImpl<T, TBase, TWinTraits>
- // CSortListViewCtrl
- // CTabViewImpl<T, TBase, TWinTraits>
- // CTabView
- namespace WTL
- {
- ///////////////////////////////////////////////////////////////////////////////
- // CBitmapButton - bitmap button implementation
- // bitmap button extended styles
- #define BMPBTN_HOVER 0x00000001
- #define BMPBTN_AUTO3D_SINGLE 0x00000002
- #define BMPBTN_AUTO3D_DOUBLE 0x00000004
- #define BMPBTN_AUTOSIZE 0x00000008
- #define BMPBTN_SHAREIMAGELISTS 0x00000010
- #define BMPBTN_AUTOFIRE 0x00000020
- #define BMPBTN_CHECK 0x00000040
- #define BMPBTN_AUTOCHECK 0x00000080
- // Note: BMPBTN_CHECK/BMPBTN_AUTOCHECK disables BN_DOUBLECLICKED,
- // BMPBTN_AUTOFIRE doesn't work with BMPBTN_CHECK/BMPBTN_AUTOCHECK
- template <class T, class TBase = CButton, class TWinTraits = ATL::CControlWinTraits>
- class ATL_NO_VTABLE CBitmapButtonImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >
- {
- public:
- DECLARE_WND_SUPERCLASS2(NULL, T, TBase::GetWndClassName())
- enum
- {
- _nImageNormal = 0,
- _nImagePushed,
- _nImageFocusOrHover,
- _nImageDisabled,
- _nImageCount = 4,
- };
- enum
- {
- ID_TIMER_FIRST = 1000,
- ID_TIMER_REPEAT = 1001
- };
- // Bitmap button specific extended styles
- DWORD m_dwExtendedStyle;
- CImageList m_ImageList;
- int m_nImage[_nImageCount];
- CToolTipCtrl m_tip;
- LPTSTR m_lpstrToolTipText;
- // Internal states
- unsigned m_fMouseOver:1;
- unsigned m_fFocus:1;
- unsigned m_fPressed:1;
- unsigned m_fChecked:1;
- // Constructor/Destructor
- CBitmapButtonImpl(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) :
- m_dwExtendedStyle(dwExtendedStyle), m_ImageList(hImageList),
- m_lpstrToolTipText(NULL),
- m_fMouseOver(0), m_fFocus(0), m_fPressed(0), m_fChecked(0)
- {
- m_nImage[_nImageNormal] = -1;
- m_nImage[_nImagePushed] = -1;
- m_nImage[_nImageFocusOrHover] = -1;
- m_nImage[_nImageDisabled] = -1;
- #ifdef _DEBUG
- if(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && IsCheckMode())
- ATLTRACE2(atlTraceUI, 0, _T("CBitmapButtonImpl - Check mode and BMPBTN_AUTOFIRE cannot be used together, BMPBTN_AUTOFIRE will be ignored.\n"));
- #endif // _DEBUG
- }
- ~CBitmapButtonImpl()
- {
- if((m_dwExtendedStyle & BMPBTN_SHAREIMAGELISTS) == 0)
- m_ImageList.Destroy();
- delete [] m_lpstrToolTipText;
- }
- // overridden to provide proper initialization
- BOOL SubclassWindow(HWND hWnd)
- {
- BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
- if(bRet != FALSE)
- {
- T* pT = static_cast<T*>(this);
- pT->Init();
- }
- return bRet;
- }
- // Attributes
- DWORD GetBitmapButtonExtendedStyle() const
- {
- return m_dwExtendedStyle;
- }
- DWORD SetBitmapButtonExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
- {
- DWORD dwPrevStyle = m_dwExtendedStyle;
- if(dwMask == 0)
- m_dwExtendedStyle = dwExtendedStyle;
- else
- m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
- #ifdef _DEBUG
- if(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && IsCheckMode())
- ATLTRACE2(atlTraceUI, 0, _T("CBitmapButtonImpl - Check mode and BMPBTN_AUTOFIRE cannot be used together, BMPBTN_AUTOFIRE will be ignored.\n"));
- #endif // _DEBUG
- return dwPrevStyle;
- }
- HIMAGELIST GetImageList() const
- {
- return m_ImageList;
- }
- HIMAGELIST SetImageList(HIMAGELIST hImageList)
- {
- HIMAGELIST hImageListPrev = m_ImageList;
- m_ImageList = hImageList;
- if(((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0) && ::IsWindow(this->m_hWnd))
- SizeToImage();
- return hImageListPrev;
- }
- int GetToolTipTextLength() const
- {
- return (m_lpstrToolTipText == NULL) ? -1 : lstrlen(m_lpstrToolTipText);
- }
- bool GetToolTipText(LPTSTR lpstrText, int nLength) const
- {
- ATLASSERT(lpstrText != NULL);
- if(m_lpstrToolTipText == NULL)
- return false;
- errno_t nRet = ATL::Checked::tcsncpy_s(lpstrText, nLength, m_lpstrToolTipText, _TRUNCATE);
- return ((nRet == 0) || (nRet == STRUNCATE));
- }
- bool SetToolTipText(LPCTSTR lpstrText)
- {
- if(m_lpstrToolTipText != NULL)
- {
- delete [] m_lpstrToolTipText;
- m_lpstrToolTipText = NULL;
- }
- if(lpstrText == NULL)
- {
- if(m_tip.IsWindow())
- m_tip.Activate(FALSE);
- return true;
- }
- int cchLen = lstrlen(lpstrText) + 1;
- ATLTRY(m_lpstrToolTipText = new TCHAR[cchLen]);
- if(m_lpstrToolTipText == NULL)
- return false;
- ATL::Checked::tcscpy_s(m_lpstrToolTipText, cchLen, lpstrText);
- if(m_tip.IsWindow())
- {
- m_tip.Activate(TRUE);
- m_tip.AddTool(this->m_hWnd, m_lpstrToolTipText);
- }
- return true;
- }
- bool GetCheck() const
- {
- return (m_fChecked == 1);
- }
- void SetCheck(bool bCheck, bool bUpdate = true)
- {
- m_fChecked = bCheck ? 1 : 0;
- if(bUpdate)
- {
- this->Invalidate();
- this->UpdateWindow();
- }
- }
- // Operations
- void SetImages(int nNormal, int nPushed = -1, int nFocusOrHover = -1, int nDisabled = -1)
- {
- if(nNormal != -1)
- m_nImage[_nImageNormal] = nNormal;
- if(nPushed != -1)
- m_nImage[_nImagePushed] = nPushed;
- if(nFocusOrHover != -1)
- m_nImage[_nImageFocusOrHover] = nFocusOrHover;
- if(nDisabled != -1)
- m_nImage[_nImageDisabled] = nDisabled;
- }
- BOOL SizeToImage()
- {
- ATLASSERT(::IsWindow(this->m_hWnd) && (m_ImageList.m_hImageList != NULL));
- int cx = 0;
- int cy = 0;
- if(!m_ImageList.GetIconSize(cx, cy))
- return FALSE;
- return this->ResizeClient(cx, cy);
- }
- // Overrideables
- void DoPaint(CDCHandle dc)
- {
- ATLASSERT(m_ImageList.m_hImageList != NULL); // image list must be set
- ATLASSERT(m_nImage[0] != -1); // main bitmap must be set
- // set bitmap according to the current button state
- bool bHover = IsHoverMode();
- bool bPressed = (m_fPressed == 1) || (IsCheckMode() && (m_fChecked == 1));
- int nImage = -1;
- if(!this->IsWindowEnabled())
- nImage = m_nImage[_nImageDisabled];
- else if(bPressed)
- nImage = m_nImage[_nImagePushed];
- else if((!bHover && (m_fFocus == 1)) || (bHover && (m_fMouseOver == 1)))
- nImage = m_nImage[_nImageFocusOrHover];
- // if none is set, use default one
- if(nImage == -1)
- nImage = m_nImage[_nImageNormal];
- // draw the button image
- bool bAuto3D = (m_dwExtendedStyle & (BMPBTN_AUTO3D_SINGLE | BMPBTN_AUTO3D_DOUBLE)) != 0;
- int xyPos = (bPressed && bAuto3D && (m_nImage[_nImagePushed] == -1)) ? 1 : 0;
- m_ImageList.Draw(dc, nImage, xyPos, xyPos, ILD_NORMAL);
- // draw 3D border if required
- if(bAuto3D)
- {
- RECT rect = {};
- this->GetClientRect(&rect);
- if(bPressed)
- dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_SUNKENOUTER : EDGE_SUNKEN, BF_RECT);
- else if(!bHover || (m_fMouseOver == 1))
- dc.DrawEdge(&rect, ((m_dwExtendedStyle & BMPBTN_AUTO3D_SINGLE) != 0) ? BDR_RAISEDINNER : EDGE_RAISED, BF_RECT);
- if(!bHover && (m_fFocus == 1))
- {
- ::InflateRect(&rect, -2 * ::GetSystemMetrics(SM_CXEDGE), -2 * ::GetSystemMetrics(SM_CYEDGE));
- dc.DrawFocusRect(&rect);
- }
- }
- }
- // Message map and handlers
- BEGIN_MSG_MAP(CBitmapButtonImpl)
- MESSAGE_HANDLER(WM_CREATE, OnCreate)
- MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
- MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
- MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
- MESSAGE_HANDLER(WM_PAINT, OnPaint)
- MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
- MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
- MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
- MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
- MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDblClk)
- MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
- MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
- MESSAGE_HANDLER(WM_ENABLE, OnEnable)
- MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
- MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
- MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
- MESSAGE_HANDLER(WM_KEYUP, OnKeyUp)
- MESSAGE_HANDLER(WM_TIMER, OnTimer)
- MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState)
- END_MSG_MAP()
- LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
- {
- T* pT = static_cast<T*>(this);
- pT->Init();
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if(m_tip.IsWindow())
- {
- m_tip.DestroyWindow();
- m_tip.m_hWnd = NULL;
- }
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- MSG msg = { this->m_hWnd, uMsg, wParam, lParam };
- if(m_tip.IsWindow())
- m_tip.RelayEvent(&msg);
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- return 1; // no background needed
- }
- LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- if(wParam != NULL)
- {
- pT->DoPaint((HDC)wParam);
- }
- else
- {
- CPaintDC dc(this->m_hWnd);
- pT->DoPaint(dc.m_hDC);
- }
- return 0;
- }
- LRESULT OnFocus(UINT uMsg, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
- {
- m_fFocus = (uMsg == WM_SETFOCUS) ? 1 : 0;
- this->Invalidate();
- this->UpdateWindow();
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
- {
- LRESULT lRet = 0;
- if(IsHoverMode())
- this->SetCapture();
- else
- lRet = this->DefWindowProc(uMsg, wParam, lParam);
- if(::GetCapture() == this->m_hWnd)
- {
- m_fPressed = 1;
- this->Invalidate();
- this->UpdateWindow();
- }
- if(((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0) && !IsCheckMode())
- {
- int nElapse = 250;
- int nDelay = 0;
- if(::SystemParametersInfo(SPI_GETKEYBOARDDELAY, 0, &nDelay, 0))
- nElapse += nDelay * 250; // all milli-seconds
- this->SetTimer(ID_TIMER_FIRST, nElapse);
- }
- return lRet;
- }
- LRESULT OnLButtonDblClk(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
- {
- LRESULT lRet = 0;
- if(!IsHoverMode() && !IsCheckMode())
- lRet = this->DefWindowProc(uMsg, wParam, lParam);
- if(::GetCapture() != this->m_hWnd)
- this->SetCapture();
- if(m_fPressed == 0)
- {
- m_fPressed = 1;
- this->Invalidate();
- this->UpdateWindow();
- }
- return lRet;
- }
- LRESULT OnLButtonUp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
- {
- if(((m_dwExtendedStyle & BMPBTN_AUTOCHECK) != 0) && (m_fPressed == 1))
- SetCheck(!GetCheck(), false);
- LRESULT lRet = 0;
- if(!IsHoverMode() && !IsCheckMode())
- lRet = this->DefWindowProc(uMsg, wParam, lParam);
- if(::GetCapture() == this->m_hWnd)
- {
- if((IsHoverMode() || IsCheckMode()) && (m_fPressed == 1))
- this->GetParent().SendMessage(WM_COMMAND, MAKEWPARAM(this->GetDlgCtrlID(), BN_CLICKED), (LPARAM)this->m_hWnd);
- ::ReleaseCapture();
- }
- return lRet;
- }
- LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if(m_fPressed == 1)
- {
- m_fPressed = 0;
- this->Invalidate();
- this->UpdateWindow();
- }
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
- {
- this->Invalidate();
- this->UpdateWindow();
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
- {
- if(::GetCapture() == this->m_hWnd)
- {
- POINT ptCursor = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- this->ClientToScreen(&ptCursor);
- RECT rect = {};
- this->GetWindowRect(&rect);
- unsigned int uPressed = ::PtInRect(&rect, ptCursor) ? 1 : 0;
- if(m_fPressed != uPressed)
- {
- m_fPressed = uPressed;
- this->Invalidate();
- this->UpdateWindow();
- }
- }
- else if(IsHoverMode() && m_fMouseOver == 0)
- {
- m_fMouseOver = 1;
- this->Invalidate();
- this->UpdateWindow();
- StartTrackMouseLeave();
- }
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- if(m_fMouseOver == 1)
- {
- m_fMouseOver = 0;
- this->Invalidate();
- this->UpdateWindow();
- }
- return 0;
- }
- LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if((wParam == VK_SPACE) && IsHoverMode())
- return 0; // ignore if in hover mode
- if((wParam == VK_SPACE) && (m_fPressed == 0))
- {
- m_fPressed = 1;
- this->Invalidate();
- this->UpdateWindow();
- }
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnKeyUp(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if((wParam == VK_SPACE) && IsHoverMode())
- return 0; // ignore if in hover mode
- if((wParam == VK_SPACE) && (m_fPressed == 1))
- {
- m_fPressed = 0;
- if((m_dwExtendedStyle & BMPBTN_AUTOCHECK) != 0)
- SetCheck(!GetCheck(), false);
- this->Invalidate();
- this->UpdateWindow();
- }
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- ATLASSERT((m_dwExtendedStyle & BMPBTN_AUTOFIRE) != 0);
- switch(wParam) // timer ID
- {
- case ID_TIMER_FIRST:
- this->KillTimer(ID_TIMER_FIRST);
- if(m_fPressed == 1)
- {
- this->GetParent().SendMessage(WM_COMMAND, MAKEWPARAM(this->GetDlgCtrlID(), BN_CLICKED), (LPARAM)this->m_hWnd);
- int nElapse = 250;
- int nRepeat = 40;
- if(::SystemParametersInfo(SPI_GETKEYBOARDSPEED, 0, &nRepeat, 0))
- nElapse = 10000 / (10 * nRepeat + 25); // milli-seconds, approximated
- this->SetTimer(ID_TIMER_REPEAT, nElapse);
- }
- break;
- case ID_TIMER_REPEAT:
- if(m_fPressed == 1)
- this->GetParent().SendMessage(WM_COMMAND, MAKEWPARAM(this->GetDlgCtrlID(), BN_CLICKED), (LPARAM)this->m_hWnd);
- else if(::GetCapture() != this->m_hWnd)
- this->KillTimer(ID_TIMER_REPEAT);
- break;
- default: // not our timer
- break;
- }
- return 0;
- }
- LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- // If the control is subclassed or superclassed, this message can cause
- // repainting without WM_PAINT. We don't use this state, so just do nothing.
- return 0;
- }
- // Implementation
- void Init()
- {
- // We need this style to prevent Windows from painting the button
- this->ModifyStyle(0, BS_OWNERDRAW);
- // create a tool tip
- m_tip.Create(this->m_hWnd);
- ATLASSERT(m_tip.IsWindow());
- if(m_tip.IsWindow() && (m_lpstrToolTipText != NULL))
- {
- m_tip.Activate(TRUE);
- m_tip.AddTool(this->m_hWnd, m_lpstrToolTipText);
- }
- if((m_ImageList.m_hImageList != NULL) && ((m_dwExtendedStyle & BMPBTN_AUTOSIZE) != 0))
- SizeToImage();
- }
- BOOL StartTrackMouseLeave()
- {
- TRACKMOUSEEVENT tme = {};
- tme.cbSize = sizeof(tme);
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = this->m_hWnd;
- return ::TrackMouseEvent(&tme);
- }
- bool IsHoverMode() const
- {
- return ((m_dwExtendedStyle & BMPBTN_HOVER) != 0);
- }
- bool IsCheckMode() const
- {
- return ((m_dwExtendedStyle & (BMPBTN_CHECK | BMPBTN_AUTOCHECK)) != 0);
- }
- };
- class CBitmapButton : public CBitmapButtonImpl<CBitmapButton>
- {
- public:
- DECLARE_WND_SUPERCLASS(_T("WTL_BitmapButton"), GetWndClassName())
- CBitmapButton(DWORD dwExtendedStyle = BMPBTN_AUTOSIZE, HIMAGELIST hImageList = NULL) :
- CBitmapButtonImpl<CBitmapButton>(dwExtendedStyle, hImageList)
- { }
- };
- ///////////////////////////////////////////////////////////////////////////////
- // CCheckListCtrlView - list view control with check boxes
- template <DWORD t_dwStyle, DWORD t_dwExStyle, DWORD t_dwExListViewStyle>
- class CCheckListViewCtrlImplTraits
- {
- public:
- static DWORD GetWndStyle(DWORD dwStyle)
- {
- return (dwStyle == 0) ? t_dwStyle : dwStyle;
- }
- static DWORD GetWndExStyle(DWORD dwExStyle)
- {
- return (dwExStyle == 0) ? t_dwExStyle : dwExStyle;
- }
- static DWORD GetExtendedLVStyle()
- {
- return t_dwExListViewStyle;
- }
- };
- typedef CCheckListViewCtrlImplTraits<WS_CHILD | WS_VISIBLE | LVS_REPORT | LVS_SHOWSELALWAYS, WS_EX_CLIENTEDGE, LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT> CCheckListViewCtrlTraits;
- template <class T, class TBase = CListViewCtrl, class TWinTraits = CCheckListViewCtrlTraits>
- class ATL_NO_VTABLE CCheckListViewCtrlImpl : public ATL::CWindowImpl<T, TBase, TWinTraits >
- {
- public:
- DECLARE_WND_SUPERCLASS2(NULL, T, TBase::GetWndClassName())
- // Attributes
- static DWORD GetExtendedLVStyle()
- {
- return TWinTraits::GetExtendedLVStyle();
- }
- // Operations
- BOOL SubclassWindow(HWND hWnd)
- {
- BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
- if(bRet != FALSE)
- {
- T* pT = static_cast<T*>(this);
- pT->Init();
- }
- return bRet;
- }
- void CheckSelectedItems(int nCurrItem)
- {
- // first check if this item is selected
- LVITEM lvi = {};
- lvi.iItem = nCurrItem;
- lvi.iSubItem = 0;
- lvi.mask = LVIF_STATE;
- lvi.stateMask = LVIS_SELECTED;
- this->GetItem(&lvi);
- // if item is not selected, don't do anything
- if(!(lvi.state & LVIS_SELECTED))
- return;
- // new check state will be reverse of the current state,
- BOOL bCheck = !this->GetCheckState(nCurrItem);
- int nItem = -1;
- int nOldItem = -1;
- while((nItem = this->GetNextItem(nOldItem, LVNI_SELECTED)) != -1)
- {
- if(nItem != nCurrItem)
- this->SetCheckState(nItem, bCheck);
- nOldItem = nItem;
- }
- }
- // Implementation
- void Init()
- {
- T* pT = static_cast<T*>(this);
- (void)pT; // avoid level 4 warning
- ATLASSERT((pT->GetExtendedLVStyle() & LVS_EX_CHECKBOXES) != 0);
- this->SetExtendedListViewStyle(pT->GetExtendedLVStyle());
- }
- // Message map and handlers
- BEGIN_MSG_MAP(CCheckListViewCtrlImpl)
- MESSAGE_HANDLER(WM_CREATE, OnCreate)
- MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
- MESSAGE_HANDLER(WM_LBUTTONDBLCLK, OnLButtonDown)
- MESSAGE_HANDLER(WM_KEYDOWN, OnKeyDown)
- END_MSG_MAP()
- LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
- {
- // first let list view control initialize everything
- LRESULT lRet = this->DefWindowProc(uMsg, wParam, lParam);
- if(lRet == 0)
- {
- T* pT = static_cast<T*>(this);
- pT->Init();
- }
- return lRet;
- }
- LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
- {
- POINT ptMsg = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- LVHITTESTINFO lvh = {};
- lvh.pt = ptMsg;
- if((this->HitTest(&lvh) != -1) && (lvh.flags == LVHT_ONITEMSTATEICON) && (::GetKeyState(VK_CONTROL) >= 0))
- {
- T* pT = static_cast<T*>(this);
- pT->CheckSelectedItems(lvh.iItem);
- }
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnKeyDown(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if(wParam == VK_SPACE)
- {
- int nCurrItem = this->GetNextItem(-1, LVNI_FOCUSED);
- if((nCurrItem != -1) && (::GetKeyState(VK_CONTROL) >= 0))
- {
- T* pT = static_cast<T*>(this);
- pT->CheckSelectedItems(nCurrItem);
- }
- }
- bHandled = FALSE;
- return 1;
- }
- };
- class CCheckListViewCtrl : public CCheckListViewCtrlImpl<CCheckListViewCtrl>
- {
- public:
- DECLARE_WND_SUPERCLASS(_T("WTL_CheckListView"), GetWndClassName())
- };
- ///////////////////////////////////////////////////////////////////////////////
- // CHyperLink - hyper link control implementation
- #define HLINK_UNDERLINED 0x00000000
- #define HLINK_NOTUNDERLINED 0x00000001
- #define HLINK_UNDERLINEHOVER 0x00000002
- #define HLINK_COMMANDBUTTON 0x00000004
- #define HLINK_NOTIFYBUTTON 0x0000000C
- #define HLINK_USETAGS 0x00000010
- #define HLINK_USETAGSBOLD 0x00000030
- #define HLINK_NOTOOLTIP 0x00000040
- #define HLINK_AUTOCREATELINKFONT 0x00000080
- #define HLINK_SINGLELINE 0x00000100
- // Notes:
- // - HLINK_USETAGS and HLINK_USETAGSBOLD are always left-aligned
- // - When HLINK_USETAGSBOLD is used, the underlined styles will be ignored
- template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
- class ATL_NO_VTABLE CHyperLinkImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >
- {
- public:
- LPTSTR m_lpstrLabel;
- LPTSTR m_lpstrHyperLink;
- HCURSOR m_hCursor;
- HFONT m_hFontLink;
- HFONT m_hFontNormal;
- RECT m_rcLink;
- CToolTipCtrl m_tip;
- COLORREF m_clrLink;
- COLORREF m_clrVisited;
- DWORD m_dwExtendedStyle; // Hyper Link specific extended styles
- bool m_bPaintLabel:1;
- bool m_bVisited:1;
- bool m_bHover:1;
- bool m_bInternalLinkFont:1;
- bool m_bInternalNormalFont:1;
- // Constructor/Destructor
- CHyperLinkImpl(DWORD dwExtendedStyle = HLINK_UNDERLINED) :
- m_lpstrLabel(NULL), m_lpstrHyperLink(NULL),
- m_hCursor(NULL), m_hFontLink(NULL), m_hFontNormal(NULL),
- m_clrLink(RGB(0, 0, 255)), m_clrVisited(RGB(128, 0, 128)),
- m_dwExtendedStyle(dwExtendedStyle),
- m_bPaintLabel(true), m_bVisited(false),
- m_bHover(false), m_bInternalLinkFont(false), m_bInternalNormalFont(false)
- {
- ::SetRectEmpty(&m_rcLink);
- }
- ~CHyperLinkImpl()
- {
- delete [] m_lpstrLabel;
- delete [] m_lpstrHyperLink;
- }
- // Attributes
- DWORD GetHyperLinkExtendedStyle() const
- {
- return m_dwExtendedStyle;
- }
- DWORD SetHyperLinkExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
- {
- DWORD dwPrevStyle = m_dwExtendedStyle;
- if(dwMask == 0)
- m_dwExtendedStyle = dwExtendedStyle;
- else
- m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
- return dwPrevStyle;
- }
- bool GetLabel(LPTSTR lpstrBuffer, int nLength) const
- {
- if(m_lpstrLabel == NULL)
- return false;
- ATLASSERT(lpstrBuffer != NULL);
- if(nLength <= lstrlen(m_lpstrLabel))
- return false;
- ATL::Checked::tcscpy_s(lpstrBuffer, nLength, m_lpstrLabel);
- return true;
- }
- bool SetLabel(LPCTSTR lpstrLabel)
- {
- delete [] m_lpstrLabel;
- m_lpstrLabel = NULL;
- int cchLen = lstrlen(lpstrLabel) + 1;
- ATLTRY(m_lpstrLabel = new TCHAR[cchLen]);
- if(m_lpstrLabel == NULL)
- return false;
- ATL::Checked::tcscpy_s(m_lpstrLabel, cchLen, lpstrLabel);
- T* pT = static_cast<T*>(this);
- pT->CalcLabelRect();
- if(this->m_hWnd != NULL)
- this->SetWindowText(lpstrLabel); // Set this for accessibility
- return true;
- }
- bool GetHyperLink(LPTSTR lpstrBuffer, int nLength) const
- {
- if(m_lpstrHyperLink == NULL)
- return false;
- ATLASSERT(lpstrBuffer != NULL);
- if(nLength <= lstrlen(m_lpstrHyperLink))
- return false;
- ATL::Checked::tcscpy_s(lpstrBuffer, nLength, m_lpstrHyperLink);
- return true;
- }
- bool SetHyperLink(LPCTSTR lpstrLink)
- {
- delete [] m_lpstrHyperLink;
- m_lpstrHyperLink = NULL;
- int cchLen = lstrlen(lpstrLink) + 1;
- ATLTRY(m_lpstrHyperLink = new TCHAR[cchLen]);
- if(m_lpstrHyperLink == NULL)
- return false;
- ATL::Checked::tcscpy_s(m_lpstrHyperLink, cchLen, lpstrLink);
- if(m_lpstrLabel == NULL)
- {
- T* pT = static_cast<T*>(this);
- pT->CalcLabelRect();
- }
- if(m_tip.IsWindow())
- {
- m_tip.Activate(TRUE);
- m_tip.AddTool(this->m_hWnd, m_lpstrHyperLink, &m_rcLink, 1);
- }
- return true;
- }
- HFONT GetLinkFont() const
- {
- return m_hFontLink;
- }
- void SetLinkFont(HFONT hFont)
- {
- if(m_bInternalLinkFont)
- {
- ::DeleteObject(m_hFontLink);
- m_bInternalLinkFont = false;
- }
- m_hFontLink = hFont;
- T* pT = static_cast<T*>(this);
- pT->CalcLabelRect();
- }
- int GetIdealHeight() const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- if((m_lpstrLabel == NULL) && (m_lpstrHyperLink == NULL))
- return -1;
- if(!m_bPaintLabel)
- return -1;
- UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
- CClientDC dc(this->m_hWnd);
- RECT rect = {};
- this->GetClientRect(&rect);
- HFONT hFontOld = dc.SelectFont(m_hFontNormal);
- RECT rcText = rect;
- dc.DrawText(_T("NS"), -1, &rcText, DT_LEFT | uFormat | DT_CALCRECT);
- dc.SelectFont(m_hFontLink);
- RECT rcLink = rect;
- dc.DrawText(_T("NS"), -1, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);
- dc.SelectFont(hFontOld);
- return __max(rcText.bottom - rcText.top, rcLink.bottom - rcLink.top);
- }
- bool GetIdealSize(SIZE& size) const
- {
- int cx = 0, cy = 0;
- bool bRet = GetIdealSize(cx, cy);
- if(bRet)
- {
- size.cx = cx;
- size.cy = cy;
- }
- return bRet;
- }
- bool GetIdealSize(int& cx, int& cy) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- if((m_lpstrLabel == NULL) && (m_lpstrHyperLink == NULL))
- return false;
- if(!m_bPaintLabel)
- return false;
- CClientDC dc(this->m_hWnd);
- RECT rcClient = {};
- this->GetClientRect(&rcClient);
- RECT rcAll = rcClient;
- if(IsUsingTags())
- {
- // find tags and label parts
- LPTSTR lpstrLeft = NULL;
- int cchLeft = 0;
- LPTSTR lpstrLink = NULL;
- int cchLink = 0;
- LPTSTR lpstrRight = NULL;
- int cchRight = 0;
- const T* pT = static_cast<const T*>(this);
- pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);
- // get label part rects
- UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
- HFONT hFontOld = dc.SelectFont(m_hFontNormal);
- RECT rcLeft = rcClient;
- dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT);
- dc.SelectFont(m_hFontLink);
- RECT rcLink = { rcLeft.right, rcLeft.top, rcClient.right, rcClient.bottom };
- dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);
- dc.SelectFont(m_hFontNormal);
- RECT rcRight = { rcLink.right, rcLink.top, rcClient.right, rcClient.bottom };
- dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat | DT_CALCRECT);
- dc.SelectFont(hFontOld);
- int cyMax = __max(rcLeft.bottom, __max(rcLink.bottom, rcRight.bottom));
- ::SetRect(&rcAll, rcLeft.left, rcLeft.top, rcRight.right, cyMax);
- }
- else
- {
- HFONT hOldFont = NULL;
- if(m_hFontLink != NULL)
- hOldFont = dc.SelectFont(m_hFontLink);
- LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
- DWORD dwStyle = this->GetStyle();
- UINT uFormat = DT_LEFT;
- if (dwStyle & SS_CENTER)
- uFormat = DT_CENTER;
- else if (dwStyle & SS_RIGHT)
- uFormat = DT_RIGHT;
- uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
- dc.DrawText(lpstrText, -1, &rcAll, uFormat | DT_CALCRECT);
- if(m_hFontLink != NULL)
- dc.SelectFont(hOldFont);
- if (dwStyle & SS_CENTER)
- {
- int dx = (rcClient.right - rcAll.right) / 2;
- ::OffsetRect(&rcAll, dx, 0);
- }
- else if (dwStyle & SS_RIGHT)
- {
- int dx = rcClient.right - rcAll.right;
- ::OffsetRect(&rcAll, dx, 0);
- }
- }
- cx = rcAll.right - rcAll.left;
- cy = rcAll.bottom - rcAll.top;
- return true;
- }
- // for command buttons only
- bool GetToolTipText(LPTSTR lpstrBuffer, int nLength) const
- {
- ATLASSERT(IsCommandButton());
- return GetHyperLink(lpstrBuffer, nLength);
- }
- bool SetToolTipText(LPCTSTR lpstrToolTipText)
- {
- ATLASSERT(IsCommandButton());
- return SetHyperLink(lpstrToolTipText);
- }
- // Operations
- BOOL SubclassWindow(HWND hWnd)
- {
- ATLASSERT(this->m_hWnd == NULL);
- ATLASSERT(::IsWindow(hWnd));
- if(m_hFontNormal == NULL)
- m_hFontNormal = (HFONT)::SendMessage(hWnd, WM_GETFONT, 0, 0L);
- BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
- if(bRet != FALSE)
- {
- T* pT = static_cast<T*>(this);
- pT->Init();
- }
- return bRet;
- }
- bool Navigate()
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- bool bRet = true;
- if(IsNotifyButton())
- {
- NMHDR nmhdr = { this->m_hWnd, (UINT_PTR)this->GetDlgCtrlID(), NM_CLICK };
- this->GetParent().SendMessage(WM_NOTIFY, this->GetDlgCtrlID(), (LPARAM)&nmhdr);
- }
- else if(IsCommandButton())
- {
- this->GetParent().SendMessage(WM_COMMAND, MAKEWPARAM(this->GetDlgCtrlID(), BN_CLICKED), (LPARAM)this->m_hWnd);
- }
- else
- {
- ATLASSERT(m_lpstrHyperLink != NULL);
- DWORD_PTR dwRet = (DWORD_PTR)::ShellExecute(0, _T("open"), m_lpstrHyperLink, 0, 0, SW_SHOWNORMAL);
- bRet = (dwRet > 32);
- ATLASSERT(bRet);
- if(bRet)
- {
- m_bVisited = true;
- this->Invalidate();
- }
- }
- return bRet;
- }
- void CreateLinkFontFromNormal()
- {
- if(m_bInternalLinkFont)
- {
- ::DeleteObject(m_hFontLink);
- m_bInternalLinkFont = false;
- }
- CFontHandle font = (m_hFontNormal != NULL) ? m_hFontNormal : (HFONT)::GetStockObject(SYSTEM_FONT);
- LOGFONT lf = {};
- font.GetLogFont(&lf);
- if(IsUsingTagsBold())
- lf.lfWeight = FW_BOLD;
- else if(!IsNotUnderlined())
- lf.lfUnderline = TRUE;
- m_hFontLink = ::CreateFontIndirect(&lf);
- m_bInternalLinkFont = true;
- ATLASSERT(m_hFontLink != NULL);
- }
- // Message map and handlers
- BEGIN_MSG_MAP(CHyperLinkImpl)
- MESSAGE_HANDLER(WM_CREATE, OnCreate)
- MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
- MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
- MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
- MESSAGE_HANDLER(WM_PAINT, OnPaint)
- MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
- MESSAGE_HANDLER(WM_SETFOCUS, OnFocus)
- MESSAGE_HANDLER(WM_KILLFOCUS, OnFocus)
- MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
- MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
- MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
- MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
- MESSAGE_HANDLER(WM_CHAR, OnChar)
- MESSAGE_HANDLER(WM_GETDLGCODE, OnGetDlgCode)
- MESSAGE_HANDLER(WM_SETCURSOR, OnSetCursor)
- MESSAGE_HANDLER(WM_ENABLE, OnEnable)
- MESSAGE_HANDLER(WM_GETFONT, OnGetFont)
- MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
- MESSAGE_HANDLER(WM_UPDATEUISTATE, OnUpdateUiState)
- MESSAGE_HANDLER(WM_SIZE, OnSize)
- END_MSG_MAP()
- LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- pT->Init();
- return 0;
- }
- LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if(m_tip.IsWindow())
- {
- m_tip.DestroyWindow();
- m_tip.m_hWnd = NULL;
- }
- if(m_bInternalLinkFont)
- {
- ::DeleteObject(m_hFontLink);
- m_hFontLink = NULL;
- m_bInternalLinkFont = false;
- }
- if(m_bInternalNormalFont)
- {
- ::DeleteObject(m_hFontNormal);
- m_hFontNormal = NULL;
- m_bInternalNormalFont = false;
- }
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- MSG msg = { this->m_hWnd, uMsg, wParam, lParam };
- if(m_tip.IsWindow() && IsUsingToolTip())
- m_tip.RelayEvent(&msg);
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- return 1; // no background painting needed (we do it all during WM_PAINT)
- }
- LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if(!m_bPaintLabel)
- {
- bHandled = FALSE;
- return 1;
- }
- T* pT = static_cast<T*>(this);
- if(wParam != NULL)
- {
- pT->DoEraseBackground((HDC)wParam);
- pT->DoPaint((HDC)wParam);
- }
- else
- {
- CPaintDC dc(this->m_hWnd);
- pT->DoEraseBackground(dc.m_hDC);
- pT->DoPaint(dc.m_hDC);
- }
- return 0;
- }
- LRESULT OnFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if(m_bPaintLabel)
- this->Invalidate();
- else
- bHandled = FALSE;
- return 0;
- }
- LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
- {
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- if(((m_lpstrHyperLink != NULL) || IsCommandButton()) && ::PtInRect(&m_rcLink, pt))
- {
- ::SetCursor(m_hCursor);
- if(IsUnderlineHover())
- {
- if(!m_bHover)
- {
- m_bHover = true;
- this->InvalidateRect(&m_rcLink);
- this->UpdateWindow();
- StartTrackMouseLeave();
- }
- }
- }
- else
- {
- if(IsUnderlineHover())
- {
- if(m_bHover)
- {
- m_bHover = false;
- this->InvalidateRect(&m_rcLink);
- this->UpdateWindow();
- }
- }
- bHandled = FALSE;
- }
- return 0;
- }
- LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- if(IsUnderlineHover() && m_bHover)
- {
- m_bHover = false;
- this->InvalidateRect(&m_rcLink);
- this->UpdateWindow();
- }
- return 0;
- }
- LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
- {
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- if(::PtInRect(&m_rcLink, pt))
- {
- this->SetFocus();
- this->SetCapture();
- }
- return 0;
- }
- LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
- {
- if(GetCapture() == this->m_hWnd)
- {
- ReleaseCapture();
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- if(::PtInRect(&m_rcLink, pt))
- {
- T* pT = static_cast<T*>(this);
- pT->Navigate();
- }
- }
- return 0;
- }
- LRESULT OnChar(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- if((wParam == VK_RETURN) || (wParam == VK_SPACE))
- {
- T* pT = static_cast<T*>(this);
- pT->Navigate();
- }
- return 0;
- }
- LRESULT OnGetDlgCode(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- return DLGC_WANTCHARS;
- }
- LRESULT OnSetCursor(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
- {
- POINT pt = {};
- GetCursorPos(&pt);
- this->ScreenToClient(&pt);
- if(((m_lpstrHyperLink != NULL) || IsCommandButton()) && ::PtInRect(&m_rcLink, pt))
- {
- return TRUE;
- }
- bHandled = FALSE;
- return FALSE;
- }
- LRESULT OnEnable(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- this->Invalidate();
- this->UpdateWindow();
- return 0;
- }
- LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- return (LRESULT)m_hFontNormal;
- }
- LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
- {
- if(m_bInternalNormalFont)
- {
- ::DeleteObject(m_hFontNormal);
- m_bInternalNormalFont = false;
- }
- bool bCreateLinkFont = m_bInternalLinkFont;
- m_hFontNormal = (HFONT)wParam;
- if(bCreateLinkFont || IsAutoCreateLinkFont())
- CreateLinkFontFromNormal();
- T* pT = static_cast<T*>(this);
- pT->CalcLabelRect();
- if((BOOL)lParam)
- {
- this->Invalidate();
- this->UpdateWindow();
- }
- return 0;
- }
- LRESULT OnUpdateUiState(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- // If the control is subclassed or superclassed, this message can cause
- // repainting without WM_PAINT. We don't use this state, so just do nothing.
- return 0;
- }
- LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- pT->CalcLabelRect();
- pT->Invalidate();
- return 0;
- }
- // Implementation
- void Init()
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- // Check if we should paint a label
- const int cchBuff = 8;
- TCHAR szBuffer[cchBuff] = {};
- if(::GetClassName(this->m_hWnd, szBuffer, cchBuff))
- {
- if(lstrcmpi(szBuffer, _T("static")) == 0)
- {
- this->ModifyStyle(0, SS_NOTIFY); // we need this
- DWORD dwStyle = this->GetStyle() & 0x000000FF;
- if((dwStyle == SS_ICON) || (dwStyle == SS_BLACKRECT) || (dwStyle == SS_GRAYRECT) ||
- (dwStyle == SS_WHITERECT) || (dwStyle == SS_BLACKFRAME) || (dwStyle == SS_GRAYFRAME) ||
- (dwStyle == SS_WHITEFRAME) || (dwStyle == SS_OWNERDRAW) ||
- (dwStyle == SS_BITMAP) || (dwStyle == SS_ENHMETAFILE))
- m_bPaintLabel = false;
- }
- }
- // create or load a cursor
- m_hCursor = ::LoadCursor(NULL, IDC_HAND);
- ATLASSERT(m_hCursor != NULL);
- // set fonts
- if(m_bPaintLabel)
- {
- if(m_hFontNormal == NULL)
- {
- m_hFontNormal = AtlCreateControlFont();
- m_bInternalNormalFont = true;
- }
- if(m_hFontLink == NULL)
- CreateLinkFontFromNormal();
- }
- // create a tool tip
- m_tip.Create(this->m_hWnd);
- ATLASSERT(m_tip.IsWindow());
- // set label (defaults to window text)
- if(m_lpstrLabel == NULL)
- {
- int nLen = this->GetWindowTextLength();
- if(nLen > 0)
- {
- ATLTRY(m_lpstrLabel = new TCHAR[nLen + 1]);
- if(m_lpstrLabel != NULL)
- ATLVERIFY(this->GetWindowText(m_lpstrLabel, nLen + 1) > 0);
- }
- }
- T* pT = static_cast<T*>(this);
- pT->CalcLabelRect();
- // set hyperlink (defaults to label), or just activate tool tip if already set
- if((m_lpstrHyperLink == NULL) && !IsCommandButton())
- {
- if(m_lpstrLabel != NULL)
- SetHyperLink(m_lpstrLabel);
- }
- else
- {
- m_tip.Activate(TRUE);
- m_tip.AddTool(this->m_hWnd, m_lpstrHyperLink, &m_rcLink, 1);
- }
- // set link colors
- if(m_bPaintLabel)
- {
- ATL::CRegKey rk;
- LONG lRet = rk.Open(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Internet Explorer\\Settings"));
- if(lRet == ERROR_SUCCESS)
- {
- const int cchValue = 12;
- TCHAR szValue[cchValue] = {};
- ULONG ulCount = cchValue;
- lRet = rk.QueryStringValue(_T("Anchor Color"), szValue, &ulCount);
- if(lRet == ERROR_SUCCESS)
- {
- COLORREF clr = pT->_ParseColorString(szValue);
- ATLASSERT(clr != CLR_INVALID);
- if(clr != CLR_INVALID)
- m_clrLink = clr;
- }
- ulCount = cchValue;
- lRet = rk.QueryStringValue(_T("Anchor Color Visited"), szValue, &ulCount);
- if(lRet == ERROR_SUCCESS)
- {
- COLORREF clr = pT->_ParseColorString(szValue);
- ATLASSERT(clr != CLR_INVALID);
- if(clr != CLR_INVALID)
- m_clrVisited = clr;
- }
- }
- }
- }
- static COLORREF _ParseColorString(LPTSTR lpstr)
- {
- int c[3] = { -1, -1, -1 };
- LPTSTR p = NULL;
- for(int i = 0; i < 2; i++)
- {
- for(p = lpstr; *p != _T('\0'); p = ::CharNext(p))
- {
- if(*p == _T(','))
- {
- *p = _T('\0');
- c[i] = _ttoi(lpstr);
- lpstr = &p[1];
- break;
- }
- }
- if(c[i] == -1)
- return CLR_INVALID;
- }
- if(*lpstr == _T('\0'))
- return CLR_INVALID;
- c[2] = _ttoi(lpstr);
- return RGB(c[0], c[1], c[2]);
- }
- bool CalcLabelRect()
- {
- if(!::IsWindow(this->m_hWnd))
- return false;
- if((m_lpstrLabel == NULL) && (m_lpstrHyperLink == NULL))
- return false;
- CClientDC dc(this->m_hWnd);
- RECT rcClient = {};
- this->GetClientRect(&rcClient);
- m_rcLink = rcClient;
- if(!m_bPaintLabel)
- return true;
- if(IsUsingTags())
- {
- // find tags and label parts
- LPTSTR lpstrLeft = NULL;
- int cchLeft = 0;
- LPTSTR lpstrLink = NULL;
- int cchLink = 0;
- LPTSTR lpstrRight = NULL;
- int cchRight = 0;
- T* pT = static_cast<T*>(this);
- pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);
- ATLASSERT(lpstrLink != NULL);
- ATLASSERT(cchLink > 0);
- // get label part rects
- HFONT hFontOld = dc.SelectFont(m_hFontNormal);
- UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
- RECT rcLeft = rcClient;
- if(lpstrLeft != NULL)
- dc.DrawText(lpstrLeft, cchLeft, &rcLeft, DT_LEFT | uFormat | DT_CALCRECT);
- dc.SelectFont(m_hFontLink);
- RECT rcLink = rcClient;
- if(lpstrLeft != NULL)
- rcLink.left = rcLeft.right;
- dc.DrawText(lpstrLink, cchLink, &rcLink, DT_LEFT | uFormat | DT_CALCRECT);
- dc.SelectFont(hFontOld);
- m_rcLink = rcLink;
- }
- else
- {
- HFONT hOldFont = NULL;
- if(m_hFontLink != NULL)
- hOldFont = dc.SelectFont(m_hFontLink);
- LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
- DWORD dwStyle = this->GetStyle();
- UINT uFormat = DT_LEFT;
- if (dwStyle & SS_CENTER)
- uFormat = DT_CENTER;
- else if (dwStyle & SS_RIGHT)
- uFormat = DT_RIGHT;
- uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
- dc.DrawText(lpstrText, -1, &m_rcLink, uFormat | DT_CALCRECT);
- if(m_hFontLink != NULL)
- dc.SelectFont(hOldFont);
- if (dwStyle & SS_CENTER)
- {
- int dx = (rcClient.right - m_rcLink.right) / 2;
- ::OffsetRect(&m_rcLink, dx, 0);
- }
- else if (dwStyle & SS_RIGHT)
- {
- int dx = rcClient.right - m_rcLink.right;
- ::OffsetRect(&m_rcLink, dx, 0);
- }
- }
- return true;
- }
- void CalcLabelParts(LPTSTR& lpstrLeft, int& cchLeft, LPTSTR& lpstrLink, int& cchLink, LPTSTR& lpstrRight, int& cchRight) const
- {
- lpstrLeft = NULL;
- cchLeft = 0;
- lpstrLink = NULL;
- cchLink = 0;
- lpstrRight = NULL;
- cchRight = 0;
- LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
- int cchText = lstrlen(lpstrText);
- bool bOutsideLink = true;
- for(int i = 0; i < cchText; i++)
- {
- if(lpstrText[i] != _T('<'))
- continue;
- if(bOutsideLink)
- {
- if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 3, _T("<A>"), 3) == CSTR_EQUAL)
- {
- if(i > 0)
- {
- lpstrLeft = lpstrText;
- cchLeft = i;
- }
- lpstrLink = &lpstrText[i + 3];
- bOutsideLink = false;
- }
- }
- else
- {
- if(::CompareString(LOCALE_USER_DEFAULT, NORM_IGNORECASE, &lpstrText[i], 4, _T("</A>"), 4) == CSTR_EQUAL)
- {
- cchLink = i - 3 - cchLeft;
- if(lpstrText[i + 4] != 0)
- {
- lpstrRight = &lpstrText[i + 4];
- cchRight = cchText - (i + 4);
- break;
- }
- }
- }
- }
- }
- void DoEraseBackground(CDCHandle dc)
- {
- HBRUSH hBrush = (HBRUSH)this->GetParent().SendMessage(WM_CTLCOLORSTATIC, (WPARAM)dc.m_hDC, (LPARAM)this->m_hWnd);
- if(hBrush != NULL)
- {
- RECT rect = {};
- this->GetClientRect(&rect);
- dc.FillRect(&rect, hBrush);
- }
- }
- void DoPaint(CDCHandle dc)
- {
- if(IsUsingTags())
- {
- // find tags and label parts
- LPTSTR lpstrLeft = NULL;
- int cchLeft = 0;
- LPTSTR lpstrLink = NULL;
- int cchLink = 0;
- LPTSTR lpstrRight = NULL;
- int cchRight = 0;
- T* pT = static_cast<T*>(this);
- pT->CalcLabelParts(lpstrLeft, cchLeft, lpstrLink, cchLink, lpstrRight, cchRight);
- // get label part rects
- RECT rcClient = {};
- this->GetClientRect(&rcClient);
- dc.SetBkMode(TRANSPARENT);
- HFONT hFontOld = dc.SelectFont(m_hFontNormal);
- UINT uFormat = IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
- if(lpstrLeft != NULL)
- dc.DrawText(lpstrLeft, cchLeft, &rcClient, DT_LEFT | uFormat);
- COLORREF clrOld = dc.SetTextColor(this->IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT)));
- if((m_hFontLink != NULL) && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover)))
- dc.SelectFont(m_hFontLink);
- else
- dc.SelectFont(m_hFontNormal);
- dc.DrawText(lpstrLink, cchLink, &m_rcLink, DT_LEFT | uFormat);
- dc.SetTextColor(clrOld);
- dc.SelectFont(m_hFontNormal);
- if(lpstrRight != NULL)
- {
- RECT rcRight = { m_rcLink.right, m_rcLink.top, rcClient.right, rcClient.bottom };
- dc.DrawText(lpstrRight, cchRight, &rcRight, DT_LEFT | uFormat);
- }
- if(GetFocus() == this->m_hWnd)
- dc.DrawFocusRect(&m_rcLink);
- dc.SelectFont(hFontOld);
- }
- else
- {
- dc.SetBkMode(TRANSPARENT);
- COLORREF clrOld = dc.SetTextColor(this->IsWindowEnabled() ? (m_bVisited ? m_clrVisited : m_clrLink) : (::GetSysColor(COLOR_GRAYTEXT)));
- HFONT hFontOld = NULL;
- if((m_hFontLink != NULL) && (!IsUnderlineHover() || (IsUnderlineHover() && m_bHover)))
- hFontOld = dc.SelectFont(m_hFontLink);
- else
- hFontOld = dc.SelectFont(m_hFontNormal);
- LPTSTR lpstrText = (m_lpstrLabel != NULL) ? m_lpstrLabel : m_lpstrHyperLink;
- DWORD dwStyle = this->GetStyle();
- UINT uFormat = DT_LEFT;
- if (dwStyle & SS_CENTER)
- uFormat = DT_CENTER;
- else if (dwStyle & SS_RIGHT)
- uFormat = DT_RIGHT;
- uFormat |= IsSingleLine() ? DT_SINGLELINE : DT_WORDBREAK;
- dc.DrawText(lpstrText, -1, &m_rcLink, uFormat);
- if(GetFocus() == this->m_hWnd)
- dc.DrawFocusRect(&m_rcLink);
- dc.SetTextColor(clrOld);
- dc.SelectFont(hFontOld);
- }
- }
- BOOL StartTrackMouseLeave()
- {
- TRACKMOUSEEVENT tme = {};
- tme.cbSize = sizeof(tme);
- tme.dwFlags = TME_LEAVE;
- tme.hwndTrack = this->m_hWnd;
- return ::TrackMouseEvent(&tme);
- }
- // Implementation helpers
- bool IsUnderlined() const
- {
- return ((m_dwExtendedStyle & (HLINK_NOTUNDERLINED | HLINK_UNDERLINEHOVER)) == 0);
- }
- bool IsNotUnderlined() const
- {
- return ((m_dwExtendedStyle & HLINK_NOTUNDERLINED) != 0);
- }
- bool IsUnderlineHover() const
- {
- return ((m_dwExtendedStyle & HLINK_UNDERLINEHOVER) != 0);
- }
- bool IsCommandButton() const
- {
- return ((m_dwExtendedStyle & HLINK_COMMANDBUTTON) != 0);
- }
- bool IsNotifyButton() const
- {
- return ((m_dwExtendedStyle & HLINK_NOTIFYBUTTON) == HLINK_NOTIFYBUTTON);
- }
- bool IsUsingTags() const
- {
- return ((m_dwExtendedStyle & HLINK_USETAGS) != 0);
- }
- bool IsUsingTagsBold() const
- {
- return ((m_dwExtendedStyle & HLINK_USETAGSBOLD) == HLINK_USETAGSBOLD);
- }
- bool IsUsingToolTip() const
- {
- return ((m_dwExtendedStyle & HLINK_NOTOOLTIP) == 0);
- }
- bool IsAutoCreateLinkFont() const
- {
- return ((m_dwExtendedStyle & HLINK_AUTOCREATELINKFONT) == HLINK_AUTOCREATELINKFONT);
- }
- bool IsSingleLine() const
- {
- return ((m_dwExtendedStyle & HLINK_SINGLELINE) == HLINK_SINGLELINE);
- }
- };
- class CHyperLink : public CHyperLinkImpl<CHyperLink>
- {
- public:
- DECLARE_WND_CLASS(_T("WTL_HyperLink"))
- };
- ///////////////////////////////////////////////////////////////////////////////
- // CWaitCursor - displays a wait cursor
- class CWaitCursor
- {
- public:
- // Data
- HCURSOR m_hWaitCursor;
- HCURSOR m_hOldCursor;
- bool m_bInUse;
- // Constructor/destructor
- CWaitCursor(bool bSet = true, LPCTSTR lpstrCursor = IDC_WAIT, bool bSys = true) : m_hOldCursor(NULL), m_bInUse(false)
- {
- HINSTANCE hInstance = bSys ? NULL : ModuleHelper::GetResourceInstance();
- m_hWaitCursor = ::LoadCursor(hInstance, lpstrCursor);
- ATLASSERT(m_hWaitCursor != NULL);
- if(bSet)
- Set();
- }
- ~CWaitCursor()
- {
- Restore();
- }
- // Methods
- bool Set()
- {
- if(m_bInUse)
- return false;
- m_hOldCursor = ::SetCursor(m_hWaitCursor);
- m_bInUse = true;
- return true;
- }
- bool Restore()
- {
- if(!m_bInUse)
- return false;
- ::SetCursor(m_hOldCursor);
- m_bInUse = false;
- return true;
- }
- };
- ///////////////////////////////////////////////////////////////////////////////
- // CCustomWaitCursor - for custom and animated cursors
- class CCustomWaitCursor : public CWaitCursor
- {
- public:
- // Constructor/destructor
- CCustomWaitCursor(ATL::_U_STRINGorID cursor, bool bSet = true, HINSTANCE hInstance = NULL) :
- CWaitCursor(false, IDC_WAIT, true)
- {
- if(hInstance == NULL)
- hInstance = ModuleHelper::GetResourceInstance();
- m_hWaitCursor = (HCURSOR)::LoadImage(hInstance, cursor.m_lpstr, IMAGE_CURSOR, 0, 0, LR_DEFAULTSIZE);
- if(bSet)
- Set();
- }
- ~CCustomWaitCursor()
- {
- Restore();
- ::DestroyCursor(m_hWaitCursor);
- }
- };
- ///////////////////////////////////////////////////////////////////////////////
- // CMultiPaneStatusBarCtrl - Status Bar with multiple panes
- template <class T, class TBase = CStatusBarCtrl>
- class ATL_NO_VTABLE CMultiPaneStatusBarCtrlImpl : public ATL::CWindowImpl< T, TBase >
- {
- public:
- DECLARE_WND_SUPERCLASS2(NULL, T, TBase::GetWndClassName())
- // Data
- enum { m_cxPaneMargin = 3 };
- int m_nPanes;
- int* m_pPane;
- // Constructor/destructor
- CMultiPaneStatusBarCtrlImpl() : m_nPanes(0), m_pPane(NULL)
- { }
- ~CMultiPaneStatusBarCtrlImpl()
- {
- delete [] m_pPane;
- }
- // Methods
- HWND Create(HWND hWndParent, LPCTSTR lpstrText, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
- {
- return ATL::CWindowImpl< T, TBase >::Create(hWndParent, this->rcDefault, lpstrText, dwStyle, 0, nID);
- }
- HWND Create(HWND hWndParent, UINT nTextID = ATL_IDS_IDLEMESSAGE, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | SBARS_SIZEGRIP, UINT nID = ATL_IDW_STATUS_BAR)
- {
- const int cchMax = 128; // max text length is 127 for status bars (+1 for null)
- TCHAR szText[cchMax] = {};
- ::LoadString(ModuleHelper::GetResourceInstance(), nTextID, szText, cchMax);
- return Create(hWndParent, szText, dwStyle, nID);
- }
- BOOL SetPanes(int* pPanes, int nPanes, bool bSetText = true)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(nPanes > 0);
- m_nPanes = nPanes;
- delete [] m_pPane;
- m_pPane = NULL;
- ATLTRY(m_pPane = new int[nPanes]);
- ATLASSERT(m_pPane != NULL);
- if(m_pPane == NULL)
- return FALSE;
- ATL::CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;
- int* pPanesPos = buff.Allocate(nPanes);
- ATLASSERT(pPanesPos != NULL);
- if(pPanesPos == NULL)
- return FALSE;
- ATL::Checked::memcpy_s(m_pPane, nPanes * sizeof(int), pPanes, nPanes * sizeof(int));
- // get status bar DC and set font
- CClientDC dc(this->m_hWnd);
- HFONT hOldFont = dc.SelectFont(this->GetFont());
- // get status bar borders
- int arrBorders[3] = {};
- this->GetBorders(arrBorders);
- const int cchBuff = 128;
- TCHAR szBuff[cchBuff] = {};
- int cxLeft = arrBorders[0];
- // calculate right edge of each part
- for(int i = 0; i < nPanes; i++)
- {
- if(pPanes[i] == ID_DEFAULT_PANE)
- {
- // make very large, will be resized later
- pPanesPos[i] = INT_MAX / 2;
- }
- else
- {
- ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff);
- SIZE size = {};
- dc.GetTextExtent(szBuff, lstrlen(szBuff), &size);
- T* pT = static_cast<T*>(this);
- (void)pT; // avoid level 4 warning
- pPanesPos[i] = cxLeft + size.cx + arrBorders[2] + 2 * pT->m_cxPaneMargin;
- }
- cxLeft = pPanesPos[i];
- }
- BOOL bRet = this->SetParts(nPanes, pPanesPos);
- if(bRet && bSetText)
- {
- for(int i = 0; i < nPanes; i++)
- {
- if(pPanes[i] != ID_DEFAULT_PANE)
- {
- ::LoadString(ModuleHelper::GetResourceInstance(), pPanes[i], szBuff, cchBuff);
- SetPaneText(m_pPane[i], szBuff);
- }
- }
- }
- dc.SelectFont(hOldFont);
- return bRet;
- }
- bool GetPaneTextLength(int nPaneID, int* pcchLength = NULL, int* pnType = NULL) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- int nIndex = GetPaneIndexFromID(nPaneID);
- if(nIndex == -1)
- return false;
- int nLength = this->GetTextLength(nIndex, pnType);
- if(pcchLength != NULL)
- *pcchLength = nLength;
- return true;
- }
- BOOL GetPaneText(int nPaneID, LPTSTR lpstrText, int* pcchLength = NULL, int* pnType = NULL) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- int nIndex = GetPaneIndexFromID(nPaneID);
- if(nIndex == -1)
- return FALSE;
- int nLength = this->GetText(nIndex, lpstrText, pnType);
- if(pcchLength != NULL)
- *pcchLength = nLength;
- return TRUE;
- }
- #ifdef __ATLSTR_H__
- BOOL GetPaneText(int nPaneID, ATL::CString& strText, int* pcchLength = NULL, int* pnType = NULL) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- int nIndex = GetPaneIndexFromID(nPaneID);
- if(nIndex == -1)
- return FALSE;
- int nLength = this->GetText(nIndex, strText, pnType);
- if(pcchLength != NULL)
- *pcchLength = nLength;
- return TRUE;
- }
- #endif // __ATLSTR_H__
- BOOL SetPaneText(int nPaneID, LPCTSTR lpstrText, int nType = 0)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- int nIndex = GetPaneIndexFromID(nPaneID);
- if(nIndex == -1)
- return FALSE;
- return this->SetText(nIndex, lpstrText, nType);
- }
- BOOL GetPaneRect(int nPaneID, LPRECT lpRect) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- int nIndex = GetPaneIndexFromID(nPaneID);
- if(nIndex == -1)
- return FALSE;
- return this->GetRect(nIndex, lpRect);
- }
- BOOL SetPaneWidth(int nPaneID, int cxWidth)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(nPaneID != ID_DEFAULT_PANE); // Can't resize this one
- int nIndex = GetPaneIndexFromID(nPaneID);
- if(nIndex == -1)
- return FALSE;
- // get pane positions
- ATL::CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;
- int* pPanesPos = buff.Allocate(m_nPanes);
- if(pPanesPos == NULL)
- return FALSE;
- this->GetParts(m_nPanes, pPanesPos);
- // calculate offset
- int cxPaneWidth = pPanesPos[nIndex] - ((nIndex == 0) ? 0 : pPanesPos[nIndex - 1]);
- int cxOff = cxWidth - cxPaneWidth;
- // find variable width pane
- int nDef = m_nPanes;
- for(int i = 0; i < m_nPanes; i++)
- {
- if(m_pPane[i] == ID_DEFAULT_PANE)
- {
- nDef = i;
- break;
- }
- }
- // resize
- if(nIndex < nDef) // before default pane
- {
- for(int i = nIndex; i < nDef; i++)
- pPanesPos[i] += cxOff;
-
- }
- else // after default one
- {
- for(int i = nDef; i < nIndex; i++)
- pPanesPos[i] -= cxOff;
- }
- // set pane postions
- return this->SetParts(m_nPanes, pPanesPos);
- }
- BOOL GetPaneTipText(int nPaneID, LPTSTR lpstrText, int nSize) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- int nIndex = GetPaneIndexFromID(nPaneID);
- if(nIndex == -1)
- return FALSE;
- this->GetTipText(nIndex, lpstrText, nSize);
- return TRUE;
- }
- BOOL SetPaneTipText(int nPaneID, LPCTSTR lpstrText)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- int nIndex = GetPaneIndexFromID(nPaneID);
- if(nIndex == -1)
- return FALSE;
- this->SetTipText(nIndex, lpstrText);
- return TRUE;
- }
- BOOL GetPaneIcon(int nPaneID, HICON& hIcon) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- int nIndex = GetPaneIndexFromID(nPaneID);
- if(nIndex == -1)
- return FALSE;
- hIcon = this->GetIcon(nIndex);
- return TRUE;
- }
- BOOL SetPaneIcon(int nPaneID, HICON hIcon)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- int nIndex = GetPaneIndexFromID(nPaneID);
- if(nIndex == -1)
- return FALSE;
- return this->SetIcon(nIndex, hIcon);
- }
- // Message map and handlers
- BEGIN_MSG_MAP(CMultiPaneStatusBarCtrlImpl< T >)
- MESSAGE_HANDLER(WM_SIZE, OnSize)
- END_MSG_MAP()
- LRESULT OnSize(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
- {
- LRESULT lRet = this->DefWindowProc(uMsg, wParam, lParam);
- if((wParam != SIZE_MINIMIZED) && (m_nPanes > 0))
- {
- T* pT = static_cast<T*>(this);
- pT->UpdatePanesLayout();
- }
- return lRet;
- }
- // Implementation
- BOOL UpdatePanesLayout()
- {
- // get pane positions
- ATL::CTempBuffer<int, _WTL_STACK_ALLOC_THRESHOLD> buff;
- int* pPanesPos = buff.Allocate(m_nPanes);
- ATLASSERT(pPanesPos != NULL);
- if(pPanesPos == NULL)
- return FALSE;
- int nRet = this->GetParts(m_nPanes, pPanesPos);
- ATLASSERT(nRet == m_nPanes);
- if(nRet != m_nPanes)
- return FALSE;
- // calculate offset
- RECT rcClient = {};
- this->GetClientRect(&rcClient);
- int cxOff = rcClient.right - pPanesPos[m_nPanes - 1];
- // Move panes left if size grip box is present
- if((this->GetStyle() & SBARS_SIZEGRIP) != 0)
- cxOff -= ::GetSystemMetrics(SM_CXVSCROLL) + ::GetSystemMetrics(SM_CXEDGE);
- // find variable width pane
- int i;
- for(i = 0; i < m_nPanes; i++)
- {
- if(m_pPane[i] == ID_DEFAULT_PANE)
- break;
- }
- // resize all panes from the variable one to the right
- if((i < m_nPanes) && (pPanesPos[i] + cxOff) > ((i == 0) ? 0 : pPanesPos[i - 1]))
- {
- for(; i < m_nPanes; i++)
- pPanesPos[i] += cxOff;
- }
- // set pane postions
- return this->SetParts(m_nPanes, pPanesPos);
- }
- int GetPaneIndexFromID(int nPaneID) const
- {
- for(int i = 0; i < m_nPanes; i++)
- {
- if(m_pPane[i] == nPaneID)
- return i;
- }
- return -1; // not found
- }
- };
- class CMultiPaneStatusBarCtrl : public CMultiPaneStatusBarCtrlImpl<CMultiPaneStatusBarCtrl>
- {
- public:
- DECLARE_WND_SUPERCLASS(_T("WTL_MultiPaneStatusBar"), GetWndClassName())
- };
- ///////////////////////////////////////////////////////////////////////////////
- // CPaneContainer - provides header with title and close button for panes
- // pane container extended styles
- #define PANECNT_NOCLOSEBUTTON 0x00000001
- #define PANECNT_VERTICAL 0x00000002
- #define PANECNT_FLATBORDER 0x00000004
- #define PANECNT_NOBORDER 0x00000008
- #define PANECNT_DIVIDER 0x00000010
- #define PANECNT_GRADIENT 0x00000020
- template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
- class ATL_NO_VTABLE CPaneContainerImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >, public CCustomDraw< T >
- {
- public:
- DECLARE_WND_CLASS_EX2(NULL, T, 0, -1)
- // Constants
- enum
- {
- m_cxyBorder = 2,
- m_cxyTextOffset = 4,
- m_cxyBtnOffset = 1,
- m_cchTitle = 80,
- m_cxImageTB = 13,
- m_cyImageTB = 11,
- m_cxyBtnAddTB = 7,
- m_cxToolBar = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + m_cxyBtnOffset,
- m_xBtnImageLeft = 6,
- m_yBtnImageTop = 5,
- m_xBtnImageRight = 12,
- m_yBtnImageBottom = 11,
- m_nCloseBtnID = ID_PANE_CLOSE
- };
- // Data members
- CToolBarCtrl m_tb;
- ATL::CWindow m_wndClient;
- int m_cxyHeader;
- TCHAR m_szTitle[m_cchTitle];
- DWORD m_dwExtendedStyle; // Pane container specific extended styles
- HFONT m_hFont;
- bool m_bInternalFont;
- // Constructor
- CPaneContainerImpl() : m_cxyHeader(0), m_dwExtendedStyle(0), m_hFont(NULL), m_bInternalFont(false)
- {
- m_szTitle[0] = 0;
- }
- // Attributes
- DWORD GetPaneContainerExtendedStyle() const
- {
- return m_dwExtendedStyle;
- }
- DWORD SetPaneContainerExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
- {
- DWORD dwPrevStyle = m_dwExtendedStyle;
- if(dwMask == 0)
- m_dwExtendedStyle = dwExtendedStyle;
- else
- m_dwExtendedStyle = (m_dwExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
- if(this->m_hWnd != NULL)
- {
- T* pT = static_cast<T*>(this);
- bool bUpdate = false;
- if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) != 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)) // add close button
- {
- pT->CreateCloseButton();
- bUpdate = true;
- }
- else if(((dwPrevStyle & PANECNT_NOCLOSEBUTTON) == 0) && ((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) != 0)) // remove close button
- {
- pT->DestroyCloseButton();
- bUpdate = true;
- }
- if((dwPrevStyle & PANECNT_VERTICAL) != (m_dwExtendedStyle & PANECNT_VERTICAL)) // change orientation
- {
- pT->CalcSize();
- bUpdate = true;
- }
- if((dwPrevStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER)) !=
- (m_dwExtendedStyle & (PANECNT_FLATBORDER | PANECNT_NOBORDER))) // change border
- {
- bUpdate = true;
- }
- if((dwPrevStyle & PANECNT_GRADIENT) != (m_dwExtendedStyle & PANECNT_GRADIENT)) // change background
- {
- bUpdate = true;
- }
- if(bUpdate)
- pT->UpdateLayout();
- }
- return dwPrevStyle;
- }
- HWND GetClient() const
- {
- return m_wndClient;
- }
- HWND SetClient(HWND hWndClient)
- {
- HWND hWndOldClient = m_wndClient;
- m_wndClient = hWndClient;
- if(this->m_hWnd != NULL)
- {
- T* pT = static_cast<T*>(this);
- pT->UpdateLayout();
- }
- return hWndOldClient;
- }
- BOOL GetTitle(LPTSTR lpstrTitle, int cchLength) const
- {
- ATLASSERT(lpstrTitle != NULL);
- errno_t nRet = ATL::Checked::tcsncpy_s(lpstrTitle, cchLength, m_szTitle, _TRUNCATE);
- return ((nRet == 0) || (nRet == STRUNCATE));
- }
- BOOL SetTitle(LPCTSTR lpstrTitle)
- {
- ATLASSERT(lpstrTitle != NULL);
- errno_t nRet = ATL::Checked::tcsncpy_s(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE);
- bool bRet = ((nRet == 0) || (nRet == STRUNCATE));
- if(bRet && (this->m_hWnd != NULL))
- {
- T* pT = static_cast<T*>(this);
- pT->UpdateLayout();
- }
- return bRet;
- }
- int GetTitleLength() const
- {
- return lstrlen(m_szTitle);
- }
- // Methods
- HWND Create(HWND hWndParent, LPCTSTR lpstrTitle = NULL, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
- DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
- {
- if(lpstrTitle != NULL)
- ATL::Checked::tcsncpy_s(m_szTitle, m_cchTitle, lpstrTitle, _TRUNCATE);
- return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, this->rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
- }
- HWND Create(HWND hWndParent, UINT uTitleID, DWORD dwStyle = WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
- DWORD dwExStyle = 0, UINT nID = 0, LPVOID lpCreateParam = NULL)
- {
- if(uTitleID != 0U)
- ::LoadString(ModuleHelper::GetResourceInstance(), uTitleID, m_szTitle, m_cchTitle);
- return ATL::CWindowImpl< T, TBase, TWinTraits >::Create(hWndParent, this->rcDefault, NULL, dwStyle, dwExStyle, nID, lpCreateParam);
- }
- BOOL SubclassWindow(HWND hWnd)
- {
- BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
- if(bRet != FALSE)
- {
- T* pT = static_cast<T*>(this);
- pT->Init();
- RECT rect = {};
- this->GetClientRect(&rect);
- pT->UpdateLayout(rect.right, rect.bottom);
- }
- return bRet;
- }
- BOOL EnableCloseButton(BOOL bEnable)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- T* pT = static_cast<T*>(this);
- (void)pT; // avoid level 4 warning
- return (m_tb.m_hWnd != NULL) ? m_tb.EnableButton(pT->m_nCloseBtnID, bEnable) : FALSE;
- }
- void UpdateLayout()
- {
- RECT rcClient = {};
- this->GetClientRect(&rcClient);
- T* pT = static_cast<T*>(this);
- pT->UpdateLayout(rcClient.right, rcClient.bottom);
- }
- // Message map and handlers
- BEGIN_MSG_MAP(CPaneContainerImpl)
- MESSAGE_HANDLER(WM_CREATE, OnCreate)
- MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
- MESSAGE_HANDLER(WM_SIZE, OnSize)
- MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
- MESSAGE_HANDLER(WM_GETFONT, OnGetFont)
- MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
- MESSAGE_HANDLER(WM_ERASEBKGND, OnEraseBackground)
- MESSAGE_HANDLER(WM_PAINT, OnPaint)
- MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
- MESSAGE_HANDLER(WM_NOTIFY, OnNotify)
- MESSAGE_HANDLER(WM_COMMAND, OnCommand)
- FORWARD_NOTIFICATIONS()
- END_MSG_MAP()
- LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- pT->Init();
- return 0;
- }
- LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- if(m_bInternalFont)
- {
- ::DeleteObject(m_hFont);
- m_hFont = NULL;
- m_bInternalFont = false;
- }
- return 0;
- }
- LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- pT->UpdateLayout(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
- return 0;
- }
- LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- if(m_wndClient.m_hWnd != NULL)
- m_wndClient.SetFocus();
- return 0;
- }
- LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- return (LRESULT)m_hFont;
- }
- LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
- {
- if(m_bInternalFont)
- {
- ::DeleteObject(m_hFont);
- m_bInternalFont = false;
- }
- m_hFont = (HFONT)wParam;
- T* pT = static_cast<T*>(this);
- pT->CalcSize();
- if((BOOL)lParam != FALSE)
- pT->UpdateLayout();
- return 0;
- }
- LRESULT OnEraseBackground(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- pT->DrawPaneTitleBackground((HDC)wParam);
- return 1;
- }
- LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- if(wParam != NULL)
- {
- pT->DrawPaneTitle((HDC)wParam);
- if(m_wndClient.m_hWnd == NULL) // no client window
- pT->DrawPane((HDC)wParam);
- }
- else
- {
- CPaintDC dc(this->m_hWnd);
- pT->DrawPaneTitle(dc.m_hDC);
- if(m_wndClient.m_hWnd == NULL) // no client window
- pT->DrawPane(dc.m_hDC);
- }
- return 0;
- }
- LRESULT OnNotify(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
- {
- if(m_tb.m_hWnd == NULL)
- {
- bHandled = FALSE;
- return 1;
- }
- T* pT = static_cast<T*>(this);
- (void)pT; // avoid level 4 warning
- LPNMHDR lpnmh = (LPNMHDR)lParam;
- LRESULT lRet = 0;
- // pass toolbar custom draw notifications to the base class
- if((lpnmh->code == NM_CUSTOMDRAW) && (lpnmh->hwndFrom == m_tb.m_hWnd))
- lRet = CCustomDraw< T >::OnCustomDraw(0, lpnmh, bHandled);
- // tooltip notifications come with the tooltip window handle and button ID,
- // pass them to the parent if we don't handle them
- else if((lpnmh->code == TTN_GETDISPINFO) && (lpnmh->idFrom == pT->m_nCloseBtnID))
- bHandled = pT->GetToolTipText(lpnmh);
- // only let notifications not from the toolbar go to the parent
- else if((lpnmh->hwndFrom != m_tb.m_hWnd) && (lpnmh->idFrom != pT->m_nCloseBtnID))
- bHandled = FALSE;
- return lRet;
- }
- LRESULT OnCommand(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- // if command comes from the close button, substitute HWND of the pane container instead
- if((m_tb.m_hWnd != NULL) && ((HWND)lParam == m_tb.m_hWnd))
- return this->GetParent().SendMessage(WM_COMMAND, wParam, (LPARAM)this->m_hWnd);
- bHandled = FALSE;
- return 1;
- }
- // Custom draw overrides
- DWORD OnPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
- {
- return CDRF_NOTIFYITEMDRAW; // we need per-item notifications
- }
- DWORD OnItemPrePaint(int /*idCtrl*/, LPNMCUSTOMDRAW /*lpNMCustomDraw*/)
- {
- return CDRF_NOTIFYPOSTPAINT;
- }
- DWORD OnItemPostPaint(int /*idCtrl*/, LPNMCUSTOMDRAW lpNMCustomDraw)
- {
- CDCHandle dc = lpNMCustomDraw->hdc;
- RECT& rc = lpNMCustomDraw->rc;
- RECT rcImage = { m_xBtnImageLeft, m_yBtnImageTop, m_xBtnImageRight + 1, m_yBtnImageBottom + 1 };
- ::OffsetRect(&rcImage, rc.left, rc.top);
- T* pT = static_cast<T*>(this);
- if((lpNMCustomDraw->uItemState & CDIS_DISABLED) != 0)
- {
- RECT rcShadow = rcImage;
- ::OffsetRect(&rcShadow, 1, 1);
- CPen pen1;
- pen1.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DHILIGHT));
- pT->DrawButtonImage(dc, rcShadow, pen1);
- CPen pen2;
- pen2.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_3DSHADOW));
- pT->DrawButtonImage(dc, rcImage, pen2);
- }
- else
- {
- if((lpNMCustomDraw->uItemState & CDIS_SELECTED) != 0)
- ::OffsetRect(&rcImage, 1, 1);
- CPen pen;
- pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT));
- pT->DrawButtonImage(dc, rcImage, pen);
- }
- return CDRF_DODEFAULT; // continue with the default item painting
- }
- // Implementation - overrideable methods
- void Init()
- {
- if(m_hFont == NULL)
- {
- // The same as AtlCreateControlFont() for horizontal pane
- LOGFONT lf = {};
- ATLVERIFY(::SystemParametersInfo(SPI_GETICONTITLELOGFONT, sizeof(LOGFONT), &lf, 0) != FALSE);
- if(IsVertical())
- lf.lfEscapement = 900; // 90 degrees
- m_hFont = ::CreateFontIndirect(&lf);
- m_bInternalFont = true;
- }
- T* pT = static_cast<T*>(this);
- pT->CalcSize();
- if((m_dwExtendedStyle & PANECNT_NOCLOSEBUTTON) == 0)
- pT->CreateCloseButton();
- }
- void UpdateLayout(int cxWidth, int cyHeight)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- RECT rect = {};
- if(IsVertical())
- {
- ::SetRect(&rect, 0, 0, m_cxyHeader, cyHeight);
- if(m_tb.m_hWnd != NULL)
- m_tb.SetWindowPos(NULL, m_cxyBorder, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
- if(m_wndClient.m_hWnd != NULL)
- m_wndClient.SetWindowPos(NULL, m_cxyHeader, 0, cxWidth - m_cxyHeader, cyHeight, SWP_NOZORDER);
- else
- rect.right = cxWidth;
- }
- else
- {
- ::SetRect(&rect, 0, 0, cxWidth, m_cxyHeader);
- if(m_tb.m_hWnd != NULL)
- m_tb.SetWindowPos(NULL, rect.right - m_cxToolBar, m_cxyBorder + m_cxyBtnOffset, 0, 0, SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE);
- if(m_wndClient.m_hWnd != NULL)
- m_wndClient.SetWindowPos(NULL, 0, m_cxyHeader, cxWidth, cyHeight - m_cxyHeader, SWP_NOZORDER);
- else
- rect.bottom = cyHeight;
- }
- this->InvalidateRect(&rect);
- }
- void CreateCloseButton()
- {
- ATLASSERT(m_tb.m_hWnd == NULL);
- // create toolbar for the "x" button
- m_tb.Create(this->m_hWnd, this->rcDefault, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NORESIZE | CCS_NOPARENTALIGN | CCS_NOMOVEY | TBSTYLE_TOOLTIPS | TBSTYLE_FLAT, 0);
- ATLASSERT(m_tb.IsWindow());
- if(m_tb.m_hWnd != NULL)
- {
- T* pT = static_cast<T*>(this);
- (void)pT; // avoid level 4 warning
- m_tb.SetButtonStructSize();
- TBBUTTON tbbtn = {};
- tbbtn.idCommand = pT->m_nCloseBtnID;
- tbbtn.fsState = TBSTATE_ENABLED;
- tbbtn.fsStyle = BTNS_BUTTON;
- m_tb.AddButtons(1, &tbbtn);
- m_tb.SetBitmapSize(m_cxImageTB, m_cyImageTB);
- m_tb.SetButtonSize(m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB);
- if(IsVertical())
- m_tb.SetWindowPos(NULL, m_cxyBorder + m_cxyBtnOffset, m_cxyBorder + m_cxyBtnOffset, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB + 1, SWP_NOZORDER | SWP_NOACTIVATE);
- else
- m_tb.SetWindowPos(NULL, 0, 0, m_cxImageTB + m_cxyBtnAddTB, m_cyImageTB + m_cxyBtnAddTB + 1, SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
- }
- }
- void DestroyCloseButton()
- {
- if(m_tb.m_hWnd != NULL)
- m_tb.DestroyWindow();
- }
- void CalcSize()
- {
- T* pT = static_cast<T*>(this);
- CFontHandle font = pT->GetTitleFont();
- if(font.IsNull())
- font = (HFONT)::GetStockObject(SYSTEM_FONT);
- LOGFONT lf = {};
- font.GetLogFont(lf);
- if(IsVertical())
- {
- m_cxyHeader = m_cxImageTB + m_cxyBtnAddTB + m_cxyBorder + 1;
- }
- else
- {
- int cyFont = abs(lf.lfHeight) + m_cxyBorder + 2 * m_cxyTextOffset;
- int cyBtn = m_cyImageTB + m_cxyBtnAddTB + m_cxyBorder + 2 * m_cxyBtnOffset + 1;
- m_cxyHeader = __max(cyFont, cyBtn);
- }
- }
- HFONT GetTitleFont() const
- {
- return m_hFont;
- }
- BOOL GetToolTipText(LPNMHDR /*lpnmh*/)
- {
- return FALSE;
- }
- void DrawPaneTitle(CDCHandle dc)
- {
- RECT rect = {};
- this->GetClientRect(&rect);
- UINT uBorder = BF_LEFT | BF_TOP | BF_ADJUST;
- if(IsVertical())
- {
- rect.right = rect.left + m_cxyHeader;
- uBorder |= BF_BOTTOM;
- }
- else
- {
- rect.bottom = rect.top + m_cxyHeader;
- uBorder |= BF_RIGHT;
- }
- if((m_dwExtendedStyle & PANECNT_NOBORDER) == 0)
- {
- if((m_dwExtendedStyle & PANECNT_FLATBORDER) != 0)
- uBorder |= BF_FLAT;
- dc.DrawEdge(&rect, EDGE_ETCHED, uBorder);
- }
- if((m_dwExtendedStyle & PANECNT_DIVIDER) != 0)
- {
- uBorder = BF_FLAT | BF_ADJUST | (IsVertical() ? BF_RIGHT : BF_BOTTOM);
- dc.DrawEdge(&rect, BDR_SUNKENOUTER, uBorder);
- }
- // draw title text
- dc.SetTextColor(::GetSysColor(COLOR_WINDOWTEXT));
- dc.SetBkMode(TRANSPARENT);
- T* pT = static_cast<T*>(this);
- HFONT hFontOld = dc.SelectFont(pT->GetTitleFont());
- if(IsVertical())
- {
- rect.top += m_cxyTextOffset;
- rect.bottom -= m_cxyTextOffset;
- if(m_tb.m_hWnd != NULL)
- rect.top += m_cxToolBar;;
- RECT rcCalc = { rect.left, rect.bottom, rect.right, rect.top };
- int cxFont = dc.DrawText(m_szTitle, -1, &rcCalc, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS | DT_CALCRECT);
- RECT rcText = {};
- rcText.left = (rect.right - rect.left - cxFont) / 2;
- rcText.right = rcText.left + (rect.bottom - rect.top);
- rcText.top = rect.bottom;
- rcText.bottom = rect.top;
- dc.DrawText(m_szTitle, -1, &rcText, DT_TOP | DT_SINGLELINE | DT_END_ELLIPSIS);
- }
- else
- {
- rect.left += m_cxyTextOffset;
- rect.right -= m_cxyTextOffset;
- if(m_tb.m_hWnd != NULL)
- rect.right -= m_cxToolBar;;
- dc.DrawText(m_szTitle, -1, &rect, DT_LEFT | DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS);
- }
- dc.SelectFont(hFontOld);
- }
- void DrawPaneTitleBackground(CDCHandle dc)
- {
- RECT rect = {};
- this->GetClientRect(&rect);
- if(IsVertical())
- rect.right = m_cxyHeader;
- else
- rect.bottom = m_cxyHeader;
- if((m_dwExtendedStyle & PANECNT_GRADIENT) != 0)
- dc.GradientFillRect(rect, ::GetSysColor(COLOR_WINDOW), ::GetSysColor(COLOR_3DFACE), IsVertical());
- else
- dc.FillRect(&rect, COLOR_3DFACE);
- }
- // called only if pane is empty
- void DrawPane(CDCHandle dc)
- {
- RECT rect = {};
- this->GetClientRect(&rect);
- if(IsVertical())
- rect.left += m_cxyHeader;
- else
- rect.top += m_cxyHeader;
- if((this->GetExStyle() & WS_EX_CLIENTEDGE) == 0)
- dc.DrawEdge(&rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
- dc.FillRect(&rect, COLOR_APPWORKSPACE);
- }
- // drawing helper - draws "x" button image
- void DrawButtonImage(CDCHandle dc, RECT& rcImage, HPEN hPen)
- {
- HPEN hPenOld = dc.SelectPen(hPen);
- dc.MoveTo(rcImage.left, rcImage.top);
- dc.LineTo(rcImage.right, rcImage.bottom);
- dc.MoveTo(rcImage.left + 1, rcImage.top);
- dc.LineTo(rcImage.right + 1, rcImage.bottom);
- dc.MoveTo(rcImage.left, rcImage.bottom - 1);
- dc.LineTo(rcImage.right, rcImage.top - 1);
- dc.MoveTo(rcImage.left + 1, rcImage.bottom - 1);
- dc.LineTo(rcImage.right + 1, rcImage.top - 1);
- dc.SelectPen(hPenOld);
- }
- bool IsVertical() const
- {
- return ((m_dwExtendedStyle & PANECNT_VERTICAL) != 0);
- }
- };
- class CPaneContainer : public CPaneContainerImpl<CPaneContainer>
- {
- public:
- DECLARE_WND_CLASS_EX(_T("WTL_PaneContainer"), 0, -1)
- };
- ///////////////////////////////////////////////////////////////////////////////
- // CSortListViewCtrl - implements sorting for a listview control
- // sort listview extended styles
- #define SORTLV_USESHELLBITMAPS 0x00000001
- // Notification sent to parent when sort column is changed by user clicking header.
- #define SLVN_SORTCHANGED LVN_LAST
- // A LPNMSORTLISTVIEW is sent with the SLVN_SORTCHANGED notification
- typedef struct tagNMSORTLISTVIEW
- {
- NMHDR hdr;
- int iNewSortColumn;
- int iOldSortColumn;
- } NMSORTLISTVIEW, *LPNMSORTLISTVIEW;
- // Column sort types. Can be set on a per-column basis with the SetColumnSortType method.
- enum
- {
- LVCOLSORT_NONE,
- LVCOLSORT_TEXT, // default
- LVCOLSORT_TEXTNOCASE,
- LVCOLSORT_LONG,
- LVCOLSORT_DOUBLE,
- LVCOLSORT_DECIMAL,
- LVCOLSORT_DATETIME,
- LVCOLSORT_DATE,
- LVCOLSORT_TIME,
- LVCOLSORT_CUSTOM,
- LVCOLSORT_LAST = LVCOLSORT_CUSTOM
- };
- template <class T>
- class CSortListViewImpl
- {
- public:
- enum
- {
- m_cchCmpTextMax = 32, // overrideable
- m_cxSortImage = 16,
- m_cySortImage = 15,
- m_cxSortArrow = 11,
- m_cySortArrow = 6,
- m_iSortUp = 0, // index of sort bitmaps
- m_iSortDown = 1,
- m_nShellSortUpID = 133
- };
- // passed to LVCompare functions as lParam1 and lParam2
- struct LVCompareParam
- {
- int iItem;
- DWORD_PTR dwItemData;
- union
- {
- long lValue;
- double dblValue;
- DECIMAL decValue;
- LPCTSTR pszValue;
- };
- };
-
- // passed to LVCompare functions as the lParamSort parameter
- struct LVSortInfo
- {
- T* pT;
- int iSortCol;
- bool bDescending;
- };
- bool m_bSortDescending;
- bool m_bCommCtrl6;
- int m_iSortColumn;
- CBitmap m_bmSort[2];
- int m_fmtOldSortCol;
- HBITMAP m_hbmOldSortCol;
- DWORD m_dwSortLVExtendedStyle;
- ATL::CSimpleArray<WORD> m_arrColSortType;
- bool m_bUseWaitCursor;
-
- CSortListViewImpl() :
- m_bSortDescending(false),
- m_bCommCtrl6(false),
- m_iSortColumn(-1),
- m_fmtOldSortCol(0),
- m_hbmOldSortCol(NULL),
- m_dwSortLVExtendedStyle(SORTLV_USESHELLBITMAPS),
- m_bUseWaitCursor(true)
- {
- DWORD dwMajor = 0;
- DWORD dwMinor = 0;
- HRESULT hRet = ATL::AtlGetCommCtrlVersion(&dwMajor, &dwMinor);
- m_bCommCtrl6 = SUCCEEDED(hRet) && (dwMajor >= 6);
- }
-
- // Attributes
- void SetSortColumn(int iCol)
- {
- T* pT = static_cast<T*>(this);
- ATLASSERT(::IsWindow(pT->m_hWnd));
- CHeaderCtrl header = pT->GetHeader();
- ATLASSERT(header.m_hWnd != NULL);
- ATLASSERT((iCol >= -1) && (iCol < m_arrColSortType.GetSize()));
- int iOldSortCol = m_iSortColumn;
- m_iSortColumn = iCol;
- if(m_bCommCtrl6)
- {
- const int nMask = HDF_SORTUP | HDF_SORTDOWN;
- HDITEM hditem = { HDI_FORMAT };
- if((iOldSortCol != iCol) && (iOldSortCol >= 0) && header.GetItem(iOldSortCol, &hditem))
- {
- hditem.fmt &= ~nMask;
- header.SetItem(iOldSortCol, &hditem);
- }
- if((iCol >= 0) && header.GetItem(iCol, &hditem))
- {
- hditem.fmt &= ~nMask;
- hditem.fmt |= m_bSortDescending ? HDF_SORTDOWN : HDF_SORTUP;
- header.SetItem(iCol, &hditem);
- }
- return;
- }
- if(m_bmSort[m_iSortUp].IsNull())
- pT->CreateSortBitmaps();
- // restore previous sort column's bitmap, if any, and format
- HDITEM hditem = { HDI_BITMAP | HDI_FORMAT };
- if((iOldSortCol != iCol) && (iOldSortCol >= 0))
- {
- hditem.hbm = m_hbmOldSortCol;
- hditem.fmt = m_fmtOldSortCol;
- header.SetItem(iOldSortCol, &hditem);
- }
- // save new sort column's bitmap and format, and add our sort bitmap
- if((iCol >= 0) && header.GetItem(iCol, &hditem))
- {
- if(iOldSortCol != iCol)
- {
- m_fmtOldSortCol = hditem.fmt;
- m_hbmOldSortCol = hditem.hbm;
- }
- hditem.fmt &= ~HDF_IMAGE;
- hditem.fmt |= HDF_BITMAP | HDF_BITMAP_ON_RIGHT;
- int i = m_bSortDescending ? m_iSortDown : m_iSortUp;
- hditem.hbm = m_bmSort[i];
- header.SetItem(iCol, &hditem);
- }
- }
- int GetSortColumn() const
- {
- return m_iSortColumn;
- }
- void SetColumnSortType(int iCol, WORD wType)
- {
- ATLASSERT((iCol >= 0) && (iCol < m_arrColSortType.GetSize()));
- ATLASSERT((wType >= LVCOLSORT_NONE) && (wType <= LVCOLSORT_LAST));
- m_arrColSortType[iCol] = wType;
- }
- WORD GetColumnSortType(int iCol) const
- {
- ATLASSERT((iCol >= 0) && (iCol < m_arrColSortType.GetSize()));
- return m_arrColSortType[iCol];
- }
- int GetColumnCount() const
- {
- const T* pT = static_cast<const T*>(this);
- ATLASSERT(::IsWindow(pT->m_hWnd));
- CHeaderCtrl header = pT->GetHeader();
- return header.m_hWnd != NULL ? header.GetItemCount() : 0;
- }
- bool IsSortDescending() const
- {
- return m_bSortDescending;
- }
- DWORD GetSortListViewExtendedStyle() const
- {
- return m_dwSortLVExtendedStyle;
- }
- DWORD SetSortListViewExtendedStyle(DWORD dwExtendedStyle, DWORD dwMask = 0)
- {
- DWORD dwPrevStyle = m_dwSortLVExtendedStyle;
- if(dwMask == 0)
- m_dwSortLVExtendedStyle = dwExtendedStyle;
- else
- m_dwSortLVExtendedStyle = (m_dwSortLVExtendedStyle & ~dwMask) | (dwExtendedStyle & dwMask);
- return dwPrevStyle;
- }
- // Operations
- bool DoSortItems(int iCol, bool bDescending = false)
- {
- T* pT = static_cast<T*>(this);
- ATLASSERT(::IsWindow(pT->m_hWnd));
- ATLASSERT((iCol >= 0) && (iCol < m_arrColSortType.GetSize()));
- WORD wType = m_arrColSortType[iCol];
- if(wType == LVCOLSORT_NONE)
- return false;
- int nCount = pT->GetItemCount();
- if(nCount < 2)
- {
- m_bSortDescending = bDescending;
- SetSortColumn(iCol);
- return true;
- }
- CWaitCursor waitCursor(false);
- if(m_bUseWaitCursor)
- waitCursor.Set();
- LVCompareParam* pParam = NULL;
- ATLTRY(pParam = new LVCompareParam[nCount]);
- PFNLVCOMPARE pFunc = NULL;
- TCHAR pszTemp[pT->m_cchCmpTextMax] = {};
- bool bStrValue = false;
- switch(wType)
- {
- case LVCOLSORT_TEXT:
- pFunc = (PFNLVCOMPARE)pT->LVCompareText;
- case LVCOLSORT_TEXTNOCASE:
- if(pFunc == NULL)
- pFunc = (PFNLVCOMPARE)pT->LVCompareTextNoCase;
- case LVCOLSORT_CUSTOM:
- {
- if(pFunc == NULL)
- pFunc = (PFNLVCOMPARE)pT->LVCompareCustom;
- for(int i = 0; i < nCount; i++)
- {
- pParam[i].iItem = i;
- pParam[i].dwItemData = pT->GetItemData(i);
- pParam[i].pszValue = new TCHAR[pT->m_cchCmpTextMax];
- pT->GetItemText(i, iCol, (LPTSTR)pParam[i].pszValue, pT->m_cchCmpTextMax);
- pT->SetItemData(i, (DWORD_PTR)&pParam[i]);
- }
- bStrValue = true;
- }
- break;
- case LVCOLSORT_LONG:
- {
- pFunc = (PFNLVCOMPARE)pT->LVCompareLong;
- for(int i = 0; i < nCount; i++)
- {
- pParam[i].iItem = i;
- pParam[i].dwItemData = pT->GetItemData(i);
- pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);
- pParam[i].lValue = pT->StrToLong(pszTemp);
- pT->SetItemData(i, (DWORD_PTR)&pParam[i]);
- }
- }
- break;
- case LVCOLSORT_DOUBLE:
- {
- pFunc = (PFNLVCOMPARE)pT->LVCompareDouble;
- for(int i = 0; i < nCount; i++)
- {
- pParam[i].iItem = i;
- pParam[i].dwItemData = pT->GetItemData(i);
- pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);
- pParam[i].dblValue = pT->StrToDouble(pszTemp);
- pT->SetItemData(i, (DWORD_PTR)&pParam[i]);
- }
- }
- break;
- case LVCOLSORT_DECIMAL:
- {
- pFunc = (PFNLVCOMPARE)pT->LVCompareDecimal;
- for(int i = 0; i < nCount; i++)
- {
- pParam[i].iItem = i;
- pParam[i].dwItemData = pT->GetItemData(i);
- pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);
- pT->StrToDecimal(pszTemp, &pParam[i].decValue);
- pT->SetItemData(i, (DWORD_PTR)&pParam[i]);
- }
- }
- break;
- case LVCOLSORT_DATETIME:
- case LVCOLSORT_DATE:
- case LVCOLSORT_TIME:
- {
- pFunc = (PFNLVCOMPARE)pT->LVCompareDouble;
- DWORD dwFlags = LOCALE_NOUSEROVERRIDE;
- if(wType == LVCOLSORT_DATE)
- dwFlags |= VAR_DATEVALUEONLY;
- else if(wType == LVCOLSORT_TIME)
- dwFlags |= VAR_TIMEVALUEONLY;
- for(int i = 0; i < nCount; i++)
- {
- pParam[i].iItem = i;
- pParam[i].dwItemData = pT->GetItemData(i);
- pT->GetItemText(i, iCol, pszTemp, pT->m_cchCmpTextMax);
- pParam[i].dblValue = pT->DateStrToDouble(pszTemp, dwFlags);
- pT->SetItemData(i, (DWORD_PTR)&pParam[i]);
- }
- }
- break;
- default:
- ATLTRACE2(atlTraceUI, 0, _T("Unknown value for sort type in CSortListViewImpl::DoSortItems()\n"));
- break;
- } // switch(wType)
- ATLASSERT(pFunc != NULL);
- LVSortInfo lvsi = { pT, iCol, bDescending };
- bool bRet = ((BOOL)pT->DefWindowProc(LVM_SORTITEMS, (WPARAM)&lvsi, (LPARAM)pFunc) != FALSE);
- for(int i = 0; i < nCount; i++)
- {
- DWORD_PTR dwItemData = pT->GetItemData(i);
- LVCompareParam* p = (LVCompareParam*)dwItemData;
- ATLASSERT(p != NULL);
- if(bStrValue)
- delete [] (TCHAR*)p->pszValue;
- pT->SetItemData(i, p->dwItemData);
- }
- delete [] pParam;
- if(bRet)
- {
- m_bSortDescending = bDescending;
- SetSortColumn(iCol);
- }
- if(m_bUseWaitCursor)
- waitCursor.Restore();
- return bRet;
- }
- void CreateSortBitmaps()
- {
- if((m_dwSortLVExtendedStyle & SORTLV_USESHELLBITMAPS) != 0)
- {
- bool bFree = false;
- LPCTSTR pszModule = _T("shell32.dll");
- HINSTANCE hShell = ::GetModuleHandle(pszModule);
- if (hShell == NULL)
- {
- hShell = ::LoadLibrary(pszModule);
- bFree = true;
- }
-
- if (hShell != NULL)
- {
- bool bSuccess = true;
- for(int i = m_iSortUp; i <= m_iSortDown; i++)
- {
- if(!m_bmSort[i].IsNull())
- m_bmSort[i].DeleteObject();
- m_bmSort[i] = (HBITMAP)::LoadImage(hShell, MAKEINTRESOURCE(m_nShellSortUpID + i),
- IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS);
- if(m_bmSort[i].IsNull())
- {
- bSuccess = false;
- break;
- }
- }
- if(bFree)
- ::FreeLibrary(hShell);
- if(bSuccess)
- return;
- }
- }
- T* pT = static_cast<T*>(this);
- for(int i = m_iSortUp; i <= m_iSortDown; i++)
- {
- if(!m_bmSort[i].IsNull())
- m_bmSort[i].DeleteObject();
- CDC dcMem;
- CClientDC dc(::GetDesktopWindow());
- dcMem.CreateCompatibleDC(dc.m_hDC);
- m_bmSort[i].CreateCompatibleBitmap(dc.m_hDC, m_cxSortImage, m_cySortImage);
- HBITMAP hbmOld = dcMem.SelectBitmap(m_bmSort[i]);
- RECT rc = { 0, 0, m_cxSortImage, m_cySortImage };
- pT->DrawSortBitmap(dcMem.m_hDC, i, &rc);
- dcMem.SelectBitmap(hbmOld);
- dcMem.DeleteDC();
- }
- }
- void NotifyParentSortChanged(int iNewSortCol, int iOldSortCol)
- {
- T* pT = static_cast<T*>(this);
- int nID = pT->GetDlgCtrlID();
- NMSORTLISTVIEW nm = { { pT->m_hWnd, (UINT_PTR)nID, SLVN_SORTCHANGED }, iNewSortCol, iOldSortCol };
- ::SendMessage(pT->GetParent(), WM_NOTIFY, (WPARAM)nID, (LPARAM)&nm);
- }
- // Overrideables
- int CompareItemsCustom(LVCompareParam* /*pItem1*/, LVCompareParam* /*pItem2*/, int /*iSortCol*/)
- {
- // pItem1 and pItem2 contain valid iItem, dwItemData, and pszValue members.
- // If item1 > item2 return 1, if item1 < item2 return -1, else return 0.
- return 0;
- }
- void DrawSortBitmap(CDCHandle dc, int iBitmap, LPRECT prc)
- {
- dc.FillRect(prc, ::GetSysColorBrush(COLOR_BTNFACE));
- HBRUSH hbrOld = dc.SelectBrush(::GetSysColorBrush(COLOR_BTNSHADOW));
- CPen pen;
- pen.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNSHADOW));
- HPEN hpenOld = dc.SelectPen(pen);
- POINT ptOrg = { (m_cxSortImage - m_cxSortArrow) / 2, (m_cySortImage - m_cySortArrow) / 2 };
- if(iBitmap == m_iSortUp)
- {
- POINT pts[3] =
- {
- { ptOrg.x + m_cxSortArrow / 2, ptOrg.y },
- { ptOrg.x, ptOrg.y + m_cySortArrow - 1 },
- { ptOrg.x + m_cxSortArrow - 1, ptOrg.y + m_cySortArrow - 1 }
- };
- dc.Polygon(pts, 3);
- }
- else
- {
- POINT pts[3] =
- {
- { ptOrg.x, ptOrg.y },
- { ptOrg.x + m_cxSortArrow / 2, ptOrg.y + m_cySortArrow - 1 },
- { ptOrg.x + m_cxSortArrow - 1, ptOrg.y }
- };
- dc.Polygon(pts, 3);
- }
- dc.SelectBrush(hbrOld);
- dc.SelectPen(hpenOld);
- }
- double DateStrToDouble(LPCTSTR lpstr, DWORD dwFlags)
- {
- ATLASSERT(lpstr != NULL);
- if((lpstr == NULL) || (lpstr[0] == _T('\0')))
- return 0;
- USES_CONVERSION;
- HRESULT hRet = E_FAIL;
- DATE dRet = 0;
- if (FAILED(hRet = ::VarDateFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, dwFlags, &dRet)))
- {
- ATLTRACE2(atlTraceUI, 0, _T("VarDateFromStr failed with result of 0x%8.8X\n"), hRet);
- dRet = 0;
- }
- return dRet;
- }
- long StrToLong(LPCTSTR lpstr)
- {
- ATLASSERT(lpstr != NULL);
- if((lpstr == NULL) || (lpstr[0] == _T('\0')))
- return 0;
-
- USES_CONVERSION;
- HRESULT hRet = E_FAIL;
- long lRet = 0;
- if (FAILED(hRet = ::VarI4FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &lRet)))
- {
- ATLTRACE2(atlTraceUI, 0, _T("VarI4FromStr failed with result of 0x%8.8X\n"), hRet);
- lRet = 0;
- }
- return lRet;
- }
- double StrToDouble(LPCTSTR lpstr)
- {
- ATLASSERT(lpstr != NULL);
- if((lpstr == NULL) || (lpstr[0] == _T('\0')))
- return 0;
- USES_CONVERSION;
- HRESULT hRet = E_FAIL;
- double dblRet = 0;
- if (FAILED(hRet = ::VarR8FromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, &dblRet)))
- {
- ATLTRACE2(atlTraceUI, 0, _T("VarR8FromStr failed with result of 0x%8.8X\n"), hRet);
- dblRet = 0;
- }
- return dblRet;
- }
- bool StrToDecimal(LPCTSTR lpstr, DECIMAL* pDecimal)
- {
- ATLASSERT(lpstr != NULL);
- ATLASSERT(pDecimal != NULL);
- if((lpstr == NULL) || (pDecimal == NULL))
- return false;
- USES_CONVERSION;
- HRESULT hRet = E_FAIL;
- if (FAILED(hRet = ::VarDecFromStr((LPOLESTR)T2COLE(lpstr), LANG_USER_DEFAULT, LOCALE_NOUSEROVERRIDE, pDecimal)))
- {
- ATLTRACE2(atlTraceUI, 0, _T("VarDecFromStr failed with result of 0x%8.8X\n"), hRet);
- pDecimal->Lo64 = 0;
- pDecimal->Hi32 = 0;
- pDecimal->signscale = 0;
- return false;
- }
- return true;
- }
- // Overrideable PFNLVCOMPARE functions
- static int CALLBACK LVCompareText(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
- {
- ATLASSERT((lParam1 != NULL) && (lParam2 != NULL) && (lParamSort != NULL));
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
-
- int nRet = lstrcmp(pParam1->pszValue, pParam2->pszValue);
- return pInfo->bDescending ? -nRet : nRet;
- }
- static int CALLBACK LVCompareTextNoCase(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
- {
- ATLASSERT((lParam1 != NULL) && (lParam2 != NULL) && (lParamSort != NULL));
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
-
- int nRet = lstrcmpi(pParam1->pszValue, pParam2->pszValue);
- return pInfo->bDescending ? -nRet : nRet;
- }
- static int CALLBACK LVCompareLong(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
- {
- ATLASSERT((lParam1 != NULL) && (lParam2 != NULL) && (lParamSort != NULL));
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
-
- int nRet = 0;
- if(pParam1->lValue > pParam2->lValue)
- nRet = 1;
- else if(pParam1->lValue < pParam2->lValue)
- nRet = -1;
- return pInfo->bDescending ? -nRet : nRet;
- }
- static int CALLBACK LVCompareDouble(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
- {
- ATLASSERT((lParam1 != NULL) && (lParam2 != NULL) && (lParamSort != NULL));
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
-
- int nRet = 0;
- if(pParam1->dblValue > pParam2->dblValue)
- nRet = 1;
- else if(pParam1->dblValue < pParam2->dblValue)
- nRet = -1;
- return pInfo->bDescending ? -nRet : nRet;
- }
- static int CALLBACK LVCompareCustom(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
- {
- ATLASSERT((lParam1 != NULL) && (lParam2 != NULL) && (lParamSort != NULL));
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
-
- int nRet = pInfo->pT->CompareItemsCustom(pParam1, pParam2, pInfo->iSortCol);
- return pInfo->bDescending ? -nRet : nRet;
- }
- static int CALLBACK LVCompareDecimal(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
- {
- ATLASSERT((lParam1 != NULL) && (lParam2 != NULL) && (lParamSort != NULL));
- LVCompareParam* pParam1 = (LVCompareParam*)lParam1;
- LVCompareParam* pParam2 = (LVCompareParam*)lParam2;
- LVSortInfo* pInfo = (LVSortInfo*)lParamSort;
-
- int nRet = (int)::VarDecCmp(&pParam1->decValue, &pParam2->decValue);
- nRet--;
- return pInfo->bDescending ? -nRet : nRet;
- }
- BEGIN_MSG_MAP(CSortListViewImpl)
- MESSAGE_HANDLER(LVM_INSERTCOLUMN, OnInsertColumn)
- MESSAGE_HANDLER(LVM_DELETECOLUMN, OnDeleteColumn)
- NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, OnHeaderItemClick)
- NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, OnHeaderItemClick)
- MESSAGE_HANDLER(WM_SETTINGCHANGE, OnSettingChange)
- END_MSG_MAP()
- LRESULT OnInsertColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
- if(lRet == -1)
- return -1;
- WORD wType = 0;
- m_arrColSortType.Add(wType);
- int nCount = m_arrColSortType.GetSize();
- ATLASSERT(nCount == GetColumnCount());
- for(int i = nCount - 1; i > lRet; i--)
- m_arrColSortType[i] = m_arrColSortType[i - 1];
- m_arrColSortType[(int)lRet] = LVCOLSORT_TEXT;
- if(lRet <= m_iSortColumn)
- m_iSortColumn++;
- return lRet;
- }
- LRESULT OnDeleteColumn(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- LRESULT lRet = pT->DefWindowProc(uMsg, wParam, lParam);
- if(lRet == 0)
- return 0;
- int iCol = (int)wParam;
- if(m_iSortColumn == iCol)
- m_iSortColumn = -1;
- else if(m_iSortColumn > iCol)
- m_iSortColumn--;
- m_arrColSortType.RemoveAt(iCol);
- return lRet;
- }
- LRESULT OnHeaderItemClick(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
- {
- LPNMHEADER p = (LPNMHEADER)pnmh;
- if(p->iButton == 0)
- {
- int iOld = m_iSortColumn;
- bool bDescending = (m_iSortColumn == p->iItem) ? !m_bSortDescending : false;
- if(DoSortItems(p->iItem, bDescending))
- NotifyParentSortChanged(p->iItem, iOld);
- }
- bHandled = FALSE;
- return 0;
- }
- LRESULT OnSettingChange(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if(wParam == SPI_SETNONCLIENTMETRICS)
- GetSystemSettings();
- bHandled = FALSE;
- return 0;
- }
- void GetSystemSettings()
- {
- if(!m_bCommCtrl6 && !m_bmSort[m_iSortUp].IsNull())
- {
- T* pT = static_cast<T*>(this);
- pT->CreateSortBitmaps();
- if(m_iSortColumn != -1)
- SetSortColumn(m_iSortColumn);
- }
- }
- };
- typedef ATL::CWinTraits<WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | LVS_REPORT | LVS_SHOWSELALWAYS , WS_EX_CLIENTEDGE> CSortListViewCtrlTraits;
- template <class T, class TBase = CListViewCtrl, class TWinTraits = CSortListViewCtrlTraits>
- class ATL_NO_VTABLE CSortListViewCtrlImpl: public ATL::CWindowImpl<T, TBase, TWinTraits>, public CSortListViewImpl<T>
- {
- public:
- DECLARE_WND_SUPERCLASS2(NULL, T, TBase::GetWndClassName())
- bool SortItems(int iCol, bool bDescending = false)
- {
- return this->DoSortItems(iCol, bDescending);
- }
-
- BEGIN_MSG_MAP(CSortListViewCtrlImpl)
- MESSAGE_HANDLER(LVM_INSERTCOLUMN, CSortListViewImpl<T>::OnInsertColumn)
- MESSAGE_HANDLER(LVM_DELETECOLUMN, CSortListViewImpl<T>::OnDeleteColumn)
- NOTIFY_CODE_HANDLER(HDN_ITEMCLICKA, CSortListViewImpl<T>::OnHeaderItemClick)
- NOTIFY_CODE_HANDLER(HDN_ITEMCLICKW, CSortListViewImpl<T>::OnHeaderItemClick)
- MESSAGE_HANDLER(WM_SETTINGCHANGE, CSortListViewImpl<T>::OnSettingChange)
- END_MSG_MAP()
- };
- class CSortListViewCtrl : public CSortListViewCtrlImpl<CSortListViewCtrl>
- {
- public:
- DECLARE_WND_SUPERCLASS(_T("WTL_SortListViewCtrl"), GetWndClassName())
- };
- ///////////////////////////////////////////////////////////////////////////////
- // CTabView - implements tab view window
- // TabView Notifications
- #define TBVN_PAGEACTIVATED (0U-741)
- #define TBVN_CONTEXTMENU (0U-742)
- #define TBVN_TABCLOSEBTN (0U-743) // return 0 to close page, 1 to keep open
- // internal
- #define TBVN_CLOSEBTNMOUSELEAVE (0U-744)
- // Notification data for TBVN_CONTEXTMENU
- struct TBVCONTEXTMENUINFO
- {
- NMHDR hdr;
- POINT pt;
- };
- typedef TBVCONTEXTMENUINFO* LPTBVCONTEXTMENUINFO;
- // Helper class for tab item hover close button
- class CTabViewCloseBtn : public ATL::CWindowImpl<CTabViewCloseBtn>
- {
- public:
- DECLARE_WND_CLASS_EX(_T("WTL_TabView_CloseBtn"), 0, -1)
- enum { _xyBtnImageLeftTop = 3, _xyBtnImageRightBottom = 9 };
- bool m_bHover;
- bool m_bPressed;
- CToolTipCtrl m_tip;
- CTabViewCloseBtn() : m_bHover(false), m_bPressed(false)
- { }
- // Message map and handlers
- BEGIN_MSG_MAP(CTabViewCloseBtn)
- MESSAGE_RANGE_HANDLER(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
- MESSAGE_HANDLER(WM_LBUTTONDOWN, OnLButtonDown)
- MESSAGE_HANDLER(WM_MOUSEMOVE, OnMouseMove)
- MESSAGE_HANDLER(WM_MOUSELEAVE, OnMouseLeave)
- MESSAGE_HANDLER(WM_LBUTTONUP, OnLButtonUp)
- MESSAGE_HANDLER(WM_CAPTURECHANGED, OnCaptureChanged)
- MESSAGE_HANDLER(WM_PAINT, OnPaint)
- MESSAGE_HANDLER(WM_PRINTCLIENT, OnPaint)
- FORWARD_NOTIFICATIONS()
- END_MSG_MAP()
- LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- MSG msg = { m_hWnd, uMsg, wParam, lParam };
- if(m_tip.IsWindow() != FALSE)
- m_tip.RelayEvent(&msg);
- bHandled = FALSE;
- return 1;
- }
- LRESULT OnLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- SetCapture();
- m_bHover = false;
- m_bPressed = true;
- Invalidate(FALSE);
- UpdateWindow();
- return 0;
- }
- LRESULT OnMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& /*bHandled*/)
- {
- if(::GetCapture() == m_hWnd)
- {
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- ClientToScreen(&pt);
- RECT rect = {};
- GetWindowRect(&rect);
- bool bPressed = (::PtInRect(&rect, pt) != FALSE);
- if(m_bPressed != bPressed)
- {
- m_bPressed = bPressed;
- Invalidate(FALSE);
- UpdateWindow();
- }
- }
- else
- {
- if(!m_bHover)
- {
- m_bHover = true;
- Invalidate(FALSE);
- UpdateWindow();
- }
- TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, m_hWnd };
- ::TrackMouseEvent(&tme);
- }
- return 0;
- }
- LRESULT OnMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- if(m_bHover)
- {
- m_bHover = false;
- Invalidate(FALSE);
- UpdateWindow();
- }
- NMHDR nmhdr = { m_hWnd, (UINT_PTR)GetDlgCtrlID(), TBVN_CLOSEBTNMOUSELEAVE };
- GetParent().SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&nmhdr);
- return 0;
- }
- LRESULT OnLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- if(::GetCapture() == m_hWnd)
- {
- bool bAction = m_bPressed;
- ReleaseCapture();
- if(bAction)
- GetParent().SendMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED), (LPARAM)m_hWnd);
- }
- return 0;
- }
- LRESULT OnCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- if(m_bPressed)
- {
- m_bPressed = false;
- Invalidate(FALSE);
- UpdateWindow();
- }
- return 0;
- }
- LRESULT OnPaint(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- if(wParam != NULL)
- {
- DoPaint((HDC)wParam);
- }
- else
- {
- CPaintDC dc(this->m_hWnd);
- DoPaint(dc.m_hDC);
- }
- return 0;
- }
- // painting helper
- void DoPaint(CDCHandle dc)
- {
- RECT rect = {};
- GetClientRect(&rect);
- RECT rcImage = { _xyBtnImageLeftTop, _xyBtnImageLeftTop, _xyBtnImageRightBottom + 1, _xyBtnImageRightBottom + 1 };
- ::OffsetRect(&rcImage, rect.left, rect.top);
- if(m_bPressed)
- ::OffsetRect(&rcImage, 1, 0);
- // draw button frame and background
- CPen penFrame;
- penFrame.CreatePen(PS_SOLID, 0, ::GetSysColor((m_bHover || m_bPressed) ? COLOR_BTNTEXT : COLOR_BTNSHADOW));
- HPEN hPenOld = dc.SelectPen(penFrame);
- CBrush brush;
- brush.CreateSysColorBrush(m_bPressed ? COLOR_BTNSHADOW : COLOR_WINDOW);
- HBRUSH hBrushOld = dc.SelectBrush(brush);
- dc.Rectangle(&rect);
- // draw button "X"
- CPen penX;
- penX.CreatePen(PS_SOLID, 0, ::GetSysColor(COLOR_BTNTEXT));
- dc.SelectPen(penX);
- dc.MoveTo(rcImage.left, rcImage.top);
- dc.LineTo(rcImage.right, rcImage.bottom);
- dc.MoveTo(rcImage.left + 1, rcImage.top);
- dc.LineTo(rcImage.right + 1, rcImage.bottom);
- dc.MoveTo(rcImage.left, rcImage.bottom - 1);
- dc.LineTo(rcImage.right, rcImage.top - 1);
- dc.MoveTo(rcImage.left + 1, rcImage.bottom - 1);
- dc.LineTo(rcImage.right + 1, rcImage.top - 1);
- dc.SelectPen(hPenOld);
- dc.SelectBrush(hBrushOld);
- }
- };
- template <class T, class TBase = ATL::CWindow, class TWinTraits = ATL::CControlWinTraits>
- class ATL_NO_VTABLE CTabViewImpl : public ATL::CWindowImpl< T, TBase, TWinTraits >
- {
- public:
- DECLARE_WND_CLASS_EX2(NULL, T, 0, COLOR_APPWORKSPACE)
- // Declarations and enums
- struct TABVIEWPAGE
- {
- HWND hWnd;
- LPTSTR lpstrTitle;
- LPVOID pData;
- };
- struct TCITEMEXTRA
- {
- TCITEMHEADER tciheader;
- TABVIEWPAGE tvpage;
- operator LPTCITEM() { return (LPTCITEM)this; }
- };
- enum
- {
- m_nTabID = 1313,
- m_cxMoveMark = 6,
- m_cyMoveMark = 3,
- m_nMenuItemsMax = (ID_WINDOW_TABLAST - ID_WINDOW_TABFIRST + 1)
- };
- enum { _nAutoScrollTimerID = 4321 };
- enum AutoScroll
- {
- _AUTOSCROLL_NONE = 0,
- _AUTOSCROLL_LEFT = -1,
- _AUTOSCROLL_RIGHT = 1
- };
- enum CloseBtn
- {
- _cxCloseBtn = 14,
- _cyCloseBtn = 13,
- _cxCloseBtnMargin = 4,
- _cxCloseBtnMarginSel = 1,
- _nCloseBtnID = ID_PANE_CLOSE
- };
- // Data members
- ATL::CContainedWindowT<CTabCtrl> m_tab;
- int m_cyTabHeight;
- int m_nActivePage;
- int m_nInsertItem;
- POINT m_ptStartDrag;
- CMenuHandle m_menu;
- int m_cchTabTextLength;
- int m_nMenuItemsCount;
- ATL::CWindow m_wndTitleBar;
- LPTSTR m_lpstrTitleBarBase;
- int m_cchTitleBarLength;
- CImageList m_ilDrag;
- AutoScroll m_AutoScroll;
- CUpDownCtrl m_ud;
- CTabViewCloseBtn m_btnClose;
- int m_nCloseItem;
- bool m_bDestroyPageOnRemove:1;
- bool m_bDestroyImageList:1;
- bool m_bActivePageMenuItem:1;
- bool m_bActiveAsDefaultMenuItem:1;
- bool m_bEmptyMenuItem:1;
- bool m_bWindowsMenuItem:1;
- bool m_bNoTabDrag:1;
- bool m_bNoTabDragAutoScroll:1;
- bool m_bTabCloseButton:1;
- // internal
- bool m_bTabCapture:1;
- bool m_bTabDrag:1;
- bool m_bInternalFont:1;
- // Constructor/destructor
- CTabViewImpl() :
- m_tab(this, 1),
- m_cyTabHeight(0),
- m_nActivePage(-1),
- m_nInsertItem(-1),
- m_cchTabTextLength(30),
- m_nMenuItemsCount(10),
- m_lpstrTitleBarBase(NULL),
- m_cchTitleBarLength(100),
- m_AutoScroll(_AUTOSCROLL_NONE),
- m_nCloseItem(-1),
- m_bDestroyPageOnRemove(true),
- m_bDestroyImageList(true),
- m_bActivePageMenuItem(true),
- m_bActiveAsDefaultMenuItem(false),
- m_bEmptyMenuItem(false),
- m_bWindowsMenuItem(false),
- m_bNoTabDrag(false),
- m_bNoTabDragAutoScroll(false),
- m_bTabCloseButton(true),
- m_bTabCapture(false),
- m_bTabDrag(false),
- m_bInternalFont(false)
- {
- m_ptStartDrag.x = 0;
- m_ptStartDrag.y = 0;
- }
- ~CTabViewImpl()
- {
- delete [] m_lpstrTitleBarBase;
- }
- // Message filter function - to be called from PreTranslateMessage of the main window
- BOOL PreTranslateMessage(MSG* pMsg)
- {
- if(this->IsWindow() == FALSE)
- return FALSE;
- BOOL bRet = FALSE;
- // Check for TabView built-in accelerators (Ctrl+Tab/Ctrl+Shift+Tab - next/previous page)
- int nCount = GetPageCount();
- if(nCount > 0)
- {
- bool bControl = (::GetKeyState(VK_CONTROL) < 0);
- if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_TAB) && bControl)
- {
- if(nCount > 1)
- {
- int nPage = m_nActivePage;
- bool bShift = (::GetKeyState(VK_SHIFT) < 0);
- if(bShift)
- nPage = (nPage > 0) ? (nPage - 1) : (nCount - 1);
- else
- nPage = ((nPage >= 0) && (nPage < (nCount - 1))) ? (nPage + 1) : 0;
- SetActivePage(nPage);
- T* pT = static_cast<T*>(this);
- pT->OnPageActivated(m_nActivePage);
- }
- bRet = TRUE;
- }
- }
- // If we are doing drag-drop, check for Escape key that cancels it
- if(bRet == FALSE)
- {
- if(m_bTabCapture && (pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_ESCAPE))
- {
- ::ReleaseCapture();
- bRet = TRUE;
- }
- }
- // Pass the message to the active page
- if(bRet == FALSE)
- {
- if(m_nActivePage != -1)
- bRet = (BOOL)::SendMessage(GetPageHWND(m_nActivePage), WM_FORWARDMSG, 0, (LPARAM)pMsg);
- }
- return bRet;
- }
- // Attributes
- int GetPageCount() const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- return m_tab.GetItemCount();
- }
- int GetActivePage() const
- {
- return m_nActivePage;
- }
- void SetActivePage(int nPage)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(IsValidPageIndex(nPage));
- T* pT = static_cast<T*>(this);
- this->SetRedraw(FALSE);
- if(m_nActivePage != -1)
- ::ShowWindow(GetPageHWND(m_nActivePage), SW_HIDE);
- m_nActivePage = nPage;
- m_tab.SetCurSel(m_nActivePage);
- ::ShowWindow(GetPageHWND(m_nActivePage), SW_SHOW);
- pT->UpdateLayout();
- this->SetRedraw(TRUE);
- this->RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
- HWND hWndFocus = ::GetFocus();
- ATL::CWindow wndTop = this->GetTopLevelWindow();
- if((hWndFocus == wndTop.m_hWnd) || ((wndTop.IsChild(hWndFocus) != FALSE) && (hWndFocus != m_tab.m_hWnd)))
- ::SetFocus(GetPageHWND(m_nActivePage));
- pT->UpdateTitleBar();
- pT->UpdateMenu();
- }
- HIMAGELIST GetImageList() const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- return m_tab.GetImageList();
- }
- HIMAGELIST SetImageList(HIMAGELIST hImageList)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- return m_tab.SetImageList(hImageList);
- }
- void SetWindowMenu(HMENU hMenu)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- m_menu = hMenu;
- T* pT = static_cast<T*>(this);
- pT->UpdateMenu();
- }
- void SetTitleBarWindow(HWND hWnd)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- delete [] m_lpstrTitleBarBase;
- m_lpstrTitleBarBase = NULL;
- m_wndTitleBar = hWnd;
- if(hWnd == NULL)
- return;
- int cchLen = m_wndTitleBar.GetWindowTextLength() + 1;
- ATLTRY(m_lpstrTitleBarBase = new TCHAR[cchLen]);
- if(m_lpstrTitleBarBase != NULL)
- {
- m_wndTitleBar.GetWindowText(m_lpstrTitleBarBase, cchLen);
- T* pT = static_cast<T*>(this);
- pT->UpdateTitleBar();
- }
- }
- // Page attributes
- HWND GetPageHWND(int nPage) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(IsValidPageIndex(nPage));
- TCITEMEXTRA tcix = {};
- tcix.tciheader.mask = TCIF_PARAM;
- m_tab.GetItem(nPage, tcix);
- return tcix.tvpage.hWnd;
- }
- LPCTSTR GetPageTitle(int nPage) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(IsValidPageIndex(nPage));
- TCITEMEXTRA tcix = {};
- tcix.tciheader.mask = TCIF_PARAM;
- if(m_tab.GetItem(nPage, tcix) == FALSE)
- return NULL;
- return tcix.tvpage.lpstrTitle;
- }
- bool SetPageTitle(int nPage, LPCTSTR lpstrTitle)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(IsValidPageIndex(nPage));
- T* pT = static_cast<T*>(this);
- int cchBuff = lstrlen(lpstrTitle) + 1;
- LPTSTR lpstrBuff = NULL;
- ATLTRY(lpstrBuff = new TCHAR[cchBuff]);
- if(lpstrBuff == NULL)
- return false;
- ATL::Checked::tcscpy_s(lpstrBuff, cchBuff, lpstrTitle);
- TCITEMEXTRA tcix = {};
- tcix.tciheader.mask = TCIF_PARAM;
- if(m_tab.GetItem(nPage, tcix) == FALSE)
- return false;
- ATL::CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
- LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);
- if(lpstrTabText == NULL)
- return false;
- delete [] tcix.tvpage.lpstrTitle;
- pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1);
- tcix.tciheader.mask = TCIF_TEXT | TCIF_PARAM;
- tcix.tciheader.pszText = lpstrTabText;
- tcix.tvpage.lpstrTitle = lpstrBuff;
- if(m_tab.SetItem(nPage, tcix) == FALSE)
- return false;
- pT->UpdateTitleBar();
- pT->UpdateMenu();
- return true;
- }
- LPVOID GetPageData(int nPage) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(IsValidPageIndex(nPage));
- TCITEMEXTRA tcix = {};
- tcix.tciheader.mask = TCIF_PARAM;
- m_tab.GetItem(nPage, tcix);
- return tcix.tvpage.pData;
- }
- LPVOID SetPageData(int nPage, LPVOID pData)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(IsValidPageIndex(nPage));
- TCITEMEXTRA tcix = {};
- tcix.tciheader.mask = TCIF_PARAM;
- m_tab.GetItem(nPage, tcix);
- LPVOID pDataOld = tcix.tvpage.pData;
- tcix.tvpage.pData = pData;
- m_tab.SetItem(nPage, tcix);
- return pDataOld;
- }
- int GetPageImage(int nPage) const
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(IsValidPageIndex(nPage));
- TCITEMEXTRA tcix = {};
- tcix.tciheader.mask = TCIF_IMAGE;
- m_tab.GetItem(nPage, tcix);
- return tcix.tciheader.iImage;
- }
- int SetPageImage(int nPage, int nImage)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(IsValidPageIndex(nPage));
- TCITEMEXTRA tcix = {};
- tcix.tciheader.mask = TCIF_IMAGE;
- m_tab.GetItem(nPage, tcix);
- int nImageOld = tcix.tciheader.iImage;
- tcix.tciheader.iImage = nImage;
- m_tab.SetItem(nPage, tcix);
- return nImageOld;
- }
- // Operations
- bool AddPage(HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL)
- {
- return InsertPage(GetPageCount(), hWndView, lpstrTitle, nImage, pData);
- }
- bool InsertPage(int nPage, HWND hWndView, LPCTSTR lpstrTitle, int nImage = -1, LPVOID pData = NULL)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT((nPage == GetPageCount()) || IsValidPageIndex(nPage));
- T* pT = static_cast<T*>(this);
- int cchBuff = lstrlen(lpstrTitle) + 1;
- LPTSTR lpstrBuff = NULL;
- ATLTRY(lpstrBuff = new TCHAR[cchBuff]);
- if(lpstrBuff == NULL)
- return false;
- ATL::Checked::tcscpy_s(lpstrBuff, cchBuff, lpstrTitle);
- ATL::CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
- LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);
- if(lpstrTabText == NULL)
- return false;
- pT->ShortenTitle(lpstrTitle, lpstrTabText, m_cchTabTextLength + 1);
- this->SetRedraw(FALSE);
- TCITEMEXTRA tcix = {};
- tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
- tcix.tciheader.pszText = lpstrTabText;
- tcix.tciheader.iImage = nImage;
- tcix.tvpage.hWnd = hWndView;
- tcix.tvpage.lpstrTitle = lpstrBuff;
- tcix.tvpage.pData = pData;
- int nItem = m_tab.InsertItem(nPage, tcix);
- if(nItem == -1)
- {
- delete [] lpstrBuff;
- this->SetRedraw(TRUE);
- return false;
- }
- // adjust active page index, if inserted before it
- if(nPage <= m_nActivePage)
- m_nActivePage++;
- SetActivePage(nItem);
- pT->OnPageActivated(m_nActivePage);
- if(GetPageCount() == 1)
- pT->ShowTabControl(true);
- pT->UpdateLayout();
- this->SetRedraw(TRUE);
- this->RedrawWindow(NULL, NULL, RDW_FRAME | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
- return true;
- }
- void RemovePage(int nPage)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- ATLASSERT(IsValidPageIndex(nPage));
- T* pT = static_cast<T*>(this);
- this->SetRedraw(FALSE);
- if(GetPageCount() == 1)
- pT->ShowTabControl(false);
- if(m_bDestroyPageOnRemove)
- ::DestroyWindow(GetPageHWND(nPage));
- else
- ::ShowWindow(GetPageHWND(nPage), SW_HIDE);
- LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(nPage);
- delete [] lpstrTitle;
- ATLVERIFY(m_tab.DeleteItem(nPage) != FALSE);
- if(m_nActivePage == nPage)
- {
- m_nActivePage = -1;
- if(nPage > 0)
- {
- SetActivePage(nPage - 1);
- }
- else if(GetPageCount() > 0)
- {
- SetActivePage(nPage);
- }
- else
- {
- this->SetRedraw(TRUE);
- this->Invalidate();
- this->UpdateWindow();
- pT->UpdateTitleBar();
- pT->UpdateMenu();
- }
- }
- else
- {
- nPage = (nPage < m_nActivePage) ? (m_nActivePage - 1) : m_nActivePage;
- m_nActivePage = -1;
- SetActivePage(nPage);
- }
- pT->OnPageActivated(m_nActivePage);
- }
- void RemoveAllPages()
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- if(GetPageCount() == 0)
- return;
- T* pT = static_cast<T*>(this);
- this->SetRedraw(FALSE);
- pT->ShowTabControl(false);
- for(int i = 0; i < GetPageCount(); i++)
- {
- if(m_bDestroyPageOnRemove)
- ::DestroyWindow(GetPageHWND(i));
- else
- ::ShowWindow(GetPageHWND(i), SW_HIDE);
- LPTSTR lpstrTitle = (LPTSTR)GetPageTitle(i);
- delete [] lpstrTitle;
- }
- m_tab.DeleteAllItems();
- m_nActivePage = -1;
- pT->OnPageActivated(m_nActivePage);
- this->SetRedraw(TRUE);
- this->Invalidate();
- this->UpdateWindow();
- pT->UpdateTitleBar();
- pT->UpdateMenu();
- }
- int PageIndexFromHwnd(HWND hWnd) const
- {
- int nIndex = -1;
- for(int i = 0; i < GetPageCount(); i++)
- {
- if(GetPageHWND(i) == hWnd)
- {
- nIndex = i;
- break;
- }
- }
- return nIndex;
- }
- void BuildWindowMenu(HMENU hMenu, int nMenuItemsCount = 10, bool bEmptyMenuItem = true, bool bWindowsMenuItem = true, bool bActivePageMenuItem = true, bool bActiveAsDefaultMenuItem = false)
- {
- ATLASSERT(::IsWindow(this->m_hWnd));
- CMenuHandle menu = hMenu;
- T* pT = static_cast<T*>(this);
- (void)pT; // avoid level 4 warning
- int nFirstPos = 0;
- // Find first menu item in our range
- for(nFirstPos = 0; nFirstPos < menu.GetMenuItemCount(); nFirstPos++)
- {
- UINT nID = menu.GetMenuItemID(nFirstPos);
- if(((nID >= ID_WINDOW_TABFIRST) && (nID <= ID_WINDOW_TABLAST)) || (nID == ID_WINDOW_SHOWTABLIST))
- break;
- }
- // Remove all menu items for tab pages
- BOOL bRet = TRUE;
- while(bRet != FALSE)
- bRet = menu.DeleteMenu(nFirstPos, MF_BYPOSITION);
- // Add separator if it's not already there
- int nPageCount = GetPageCount();
- if((bWindowsMenuItem || (nPageCount > 0)) && (nFirstPos > 0))
- {
- CMenuItemInfo mii;
- mii.fMask = MIIM_TYPE;
- menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii);
- if((mii.fType & MFT_SEPARATOR) == 0)
- {
- menu.AppendMenu(MF_SEPARATOR);
- nFirstPos++;
- }
- }
- // Add menu items for all pages
- if(nPageCount > 0)
- {
- // Append menu items for all pages
- const int cchPrefix = 3; // 2 digits + space
- nMenuItemsCount = __min(__min(nPageCount, nMenuItemsCount), (int)m_nMenuItemsMax);
- ATLASSERT(nMenuItemsCount < 100); // 2 digits only
- if(nMenuItemsCount >= 100)
- nMenuItemsCount = 99;
- for(int i = 0; i < nMenuItemsCount; i++)
- {
- LPCTSTR lpstrTitle = GetPageTitle(i);
- int nLen = lstrlen(lpstrTitle);
- ATL::CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
- LPTSTR lpstrText = buff.Allocate(cchPrefix + nLen + 1);
- ATLASSERT(lpstrText != NULL);
- if(lpstrText != NULL)
- {
- LPCTSTR lpstrFormat = (i < 9) ? _T("&%i %s") : _T("%i %s");
- _stprintf_s(lpstrText, cchPrefix + nLen + 1, lpstrFormat, i + 1, lpstrTitle);
- menu.AppendMenu(MF_STRING, ID_WINDOW_TABFIRST + i, lpstrText);
- }
- }
- // Mark active page
- if(bActivePageMenuItem && (m_nActivePage != -1))
- {
- if(bActiveAsDefaultMenuItem)
- {
- menu.SetMenuDefaultItem((UINT)-1, TRUE);
- menu.SetMenuDefaultItem(nFirstPos + m_nActivePage, TRUE);
- }
- else
- {
- menu.CheckMenuRadioItem(nFirstPos, nFirstPos + nMenuItemsCount, nFirstPos + m_nActivePage, MF_BYPOSITION);
- }
- }
- }
- else
- {
- if(bEmptyMenuItem)
- {
- menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_TABFIRST, pT->GetEmptyListText());
- menu.EnableMenuItem(ID_WINDOW_TABFIRST, MF_GRAYED);
- }
- // Remove separator if nothing else is there
- if(!bEmptyMenuItem && !bWindowsMenuItem && (nFirstPos > 0))
- {
- CMenuItemInfo mii;
- mii.fMask = MIIM_TYPE;
- menu.GetMenuItemInfo(nFirstPos - 1, TRUE, &mii);
- if((mii.fType & MFT_SEPARATOR) != 0)
- menu.DeleteMenu(nFirstPos - 1, MF_BYPOSITION);
- }
- }
- // Add "Windows..." menu item
- if(bWindowsMenuItem)
- menu.AppendMenu(MF_BYPOSITION | MF_STRING, ID_WINDOW_SHOWTABLIST, pT->GetWindowsMenuItemText());
- }
- BOOL SubclassWindow(HWND hWnd)
- {
- BOOL bRet = ATL::CWindowImpl< T, TBase, TWinTraits >::SubclassWindow(hWnd);
- if(bRet != FALSE)
- {
- T* pT = static_cast<T*>(this);
- pT->CreateTabControl();
- pT->UpdateLayout();
- }
- return bRet;
- }
- // Message map and handlers
- BEGIN_MSG_MAP(CTabViewImpl)
- MESSAGE_HANDLER(WM_CREATE, OnCreate)
- MESSAGE_HANDLER(WM_DESTROY, OnDestroy)
- MESSAGE_HANDLER(WM_SIZE, OnSize)
- MESSAGE_HANDLER(WM_SETFOCUS, OnSetFocus)
- MESSAGE_HANDLER(WM_GETFONT, OnGetFont)
- MESSAGE_HANDLER(WM_SETFONT, OnSetFont)
- MESSAGE_HANDLER(WM_TIMER, OnTimer)
- MESSAGE_HANDLER(WM_CONTEXTMENU, OnTabContextMenu)
- NOTIFY_HANDLER(m_nTabID, TCN_SELCHANGE, OnTabChanged)
- NOTIFY_ID_HANDLER(m_nTabID, OnTabNotification)
- NOTIFY_CODE_HANDLER(TTN_GETDISPINFO, OnTabGetDispInfo)
- FORWARD_NOTIFICATIONS()
- ALT_MSG_MAP(1) // tab control
- MESSAGE_HANDLER(WM_LBUTTONDOWN, OnTabLButtonDown)
- MESSAGE_HANDLER(WM_LBUTTONUP, OnTabLButtonUp)
- MESSAGE_HANDLER(WM_CAPTURECHANGED, OnTabCaptureChanged)
- MESSAGE_HANDLER(WM_MOUSEMOVE, OnTabMouseMove)
- MESSAGE_HANDLER(WM_MOUSELEAVE, OnTabMouseLeave)
- NOTIFY_HANDLER(T::_nCloseBtnID, TBVN_CLOSEBTNMOUSELEAVE, OnTabCloseBtnMouseLeave)
- COMMAND_HANDLER(T::_nCloseBtnID, BN_CLICKED, OnTabCloseBtnClicked)
- END_MSG_MAP()
- LRESULT OnCreate(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- pT->CreateTabControl();
- return 0;
- }
- LRESULT OnDestroy(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- RemoveAllPages();
- if(m_bDestroyImageList)
- {
- CImageList il = m_tab.SetImageList(NULL);
- if(il.m_hImageList != NULL)
- il.Destroy();
- }
- if(m_bInternalFont)
- {
- HFONT hFont = m_tab.GetFont();
- m_tab.SetFont(NULL, FALSE);
- ::DeleteObject(hFont);
- m_bInternalFont = false;
- }
- m_ud.m_hWnd = NULL;
- return 0;
- }
- LRESULT OnSize(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- pT->UpdateLayout();
- return 0;
- }
- LRESULT OnSetFocus(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- if(m_nActivePage != -1)
- ::SetFocus(GetPageHWND(m_nActivePage));
- return 0;
- }
- LRESULT OnGetFont(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
- {
- return m_tab.SendMessage(WM_GETFONT);
- }
- LRESULT OnSetFont(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& /*bHandled*/)
- {
- if(m_bInternalFont)
- {
- HFONT hFont = m_tab.GetFont();
- m_tab.SetFont(NULL, FALSE);
- ::DeleteObject(hFont);
- m_bInternalFont = false;
- }
- m_tab.SendMessage(WM_SETFONT, wParam, lParam);
- T* pT = static_cast<T*>(this);
- m_cyTabHeight = pT->CalcTabHeight();
- if((BOOL)lParam != FALSE)
- pT->UpdateLayout();
- return 0;
- }
- LRESULT OnTimer(UINT /*uMsg*/, WPARAM wParam, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if(wParam == _nAutoScrollTimerID)
- {
- T* pT = static_cast<T*>(this);
- pT->DoAutoScroll();
- }
- else
- {
- bHandled = FALSE;
- }
- return 0;
- }
- LRESULT OnTabContextMenu(UINT /*uMsg*/, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
- {
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- int nPage = m_nActivePage;
- bool bAction = false;
- if((HWND)wParam == m_tab.m_hWnd)
- {
- if((pt.x == -1) && (pt.y == -1)) // keyboard
- {
- RECT rect = {};
- m_tab.GetItemRect(m_nActivePage, &rect);
- pt.x = rect.left;
- pt.y = rect.bottom;
- m_tab.ClientToScreen(&pt);
- bAction = true;
- }
- else if(::WindowFromPoint(pt) == m_tab.m_hWnd)
- {
- TCHITTESTINFO hti = {};
- hti.pt = pt;
- this->ScreenToClient(&hti.pt);
- nPage = m_tab.HitTest(&hti);
- bAction = true;
- }
- }
- if(bAction)
- {
- T* pT = static_cast<T*>(this);
- pT->OnContextMenu(nPage, pt);
- }
- else
- {
- bHandled = FALSE;
- }
- return 0;
- }
- LRESULT OnTabChanged(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
- {
- if(m_bTabCloseButton && (m_btnClose.m_hWnd != NULL))
- {
- T* pT = static_cast<T*>(this);
- RECT rcClose = {};
- pT->CalcCloseButtonRect(m_nCloseItem, rcClose);
- m_btnClose.SetWindowPos(NULL, &rcClose, SWP_NOZORDER | SWP_NOACTIVATE);
- }
- SetActivePage(m_tab.GetCurSel());
- T* pT = static_cast<T*>(this);
- pT->OnPageActivated(m_nActivePage);
- return 0;
- }
- LRESULT OnTabNotification(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
- {
- // nothing to do - this just blocks all tab control
- // notifications from being propagated further
- return 0;
- }
- LRESULT OnTabGetDispInfo(int /*idCtrl*/, LPNMHDR pnmh, BOOL& bHandled)
- {
- LPNMTTDISPINFO pTTDI = (LPNMTTDISPINFO)pnmh;
- if(pTTDI->hdr.hwndFrom == m_tab.GetTooltips())
- {
- T* pT = static_cast<T*>(this);
- pT->UpdateTooltipText(pTTDI);
- }
- else
- {
- bHandled = FALSE;
- }
- return 0;
- }
- // Tab control message handlers
- LRESULT OnTabLButtonDown(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
- {
- if(!m_bNoTabDrag && (m_tab.GetItemCount() > 1))
- {
- m_bTabCapture = true;
- m_tab.SetCapture();
- m_ptStartDrag.x = GET_X_LPARAM(lParam);
- m_ptStartDrag.y = GET_Y_LPARAM(lParam);
- }
- bHandled = FALSE;
- return 0;
- }
- LRESULT OnTabLButtonUp(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
- {
- if(m_bTabCapture)
- {
- if(m_bTabDrag)
- {
- T* pT = static_cast<T*>(this);
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- int nItem = pT->DragHitTest(pt);
- if(nItem != -1)
- MovePage(m_nActivePage, nItem);
- }
- ::ReleaseCapture();
- }
- bHandled = FALSE;
- return 0;
- }
- LRESULT OnTabCaptureChanged(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
- {
- if(m_bTabCapture)
- {
- m_bTabCapture = false;
- if(m_bTabDrag)
- {
- m_bTabDrag = false;
- T* pT = static_cast<T*>(this);
- if(!m_bNoTabDragAutoScroll)
- pT->StartStopAutoScroll(-1);
- pT->DrawMoveMark(-1);
- m_ilDrag.DragLeave(GetDesktopWindow());
- m_ilDrag.EndDrag();
- m_ilDrag.Destroy();
- m_ilDrag.m_hImageList = NULL;
- }
- }
- bHandled = FALSE;
- return 0;
- }
- LRESULT OnTabMouseMove(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM lParam, BOOL& bHandled)
- {
- bHandled = FALSE;
- if(m_bTabCapture)
- {
- POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
- if(!m_bTabDrag)
- {
- if((abs(m_ptStartDrag.x - GET_X_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CXDRAG)) ||
- (abs(m_ptStartDrag.y - GET_Y_LPARAM(lParam)) >= ::GetSystemMetrics(SM_CYDRAG)))
- {
- T* pT = static_cast<T*>(this);
- pT->GenerateDragImage(m_nActivePage);
- int cxCursor = ::GetSystemMetrics(SM_CXCURSOR);
- int cyCursor = ::GetSystemMetrics(SM_CYCURSOR);
- m_ilDrag.BeginDrag(0, -(cxCursor / 2), -(cyCursor / 2));
- POINT ptEnter = m_ptStartDrag;
- m_tab.ClientToScreen(&ptEnter);
- m_ilDrag.DragEnter(GetDesktopWindow(), ptEnter);
- m_bTabDrag = true;
- }
- }
- if(m_bTabDrag)
- {
- T* pT = static_cast<T*>(this);
- int nItem = pT->DragHitTest(pt);
- pT->SetMoveCursor(nItem != -1);
- if(m_nInsertItem != nItem)
- pT->DrawMoveMark(nItem);
- if(!m_bNoTabDragAutoScroll)
- pT->StartStopAutoScroll(pt.x);
- m_ilDrag.DragShowNolock((nItem != -1) ? TRUE : FALSE);
- m_tab.ClientToScreen(&pt);
- m_ilDrag.DragMove(pt);
- bHandled = TRUE;
- }
- }
- else if(m_bTabCloseButton)
- {
- TCHITTESTINFO thti = {};
- thti.pt.x = GET_X_LPARAM(lParam);
- thti.pt.y = GET_Y_LPARAM(lParam);
- int nItem = m_tab.HitTest(&thti);
- if(nItem >= 0)
- {
- ATLTRACE(_T("+++++ item = %i\n"), nItem);
- T* pT = static_cast<T*>(this);
- if(m_btnClose.m_hWnd == NULL)
- {
- pT->CreateCloseButton(nItem);
- m_nCloseItem = nItem;
- }
- else if(m_nCloseItem != nItem)
- {
- RECT rcClose = {};
- pT->CalcCloseButtonRect(nItem, rcClose);
- m_btnClose.SetWindowPos(NULL, &rcClose, SWP_NOZORDER | SWP_NOACTIVATE);
- m_nCloseItem = nItem;
- }
- TRACKMOUSEEVENT tme = { sizeof(TRACKMOUSEEVENT), TME_LEAVE, m_tab.m_hWnd };
- ::TrackMouseEvent(&tme);
- }
- }
- return 0;
- }
- LRESULT OnTabMouseLeave(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& bHandled)
- {
- bHandled = FALSE;
- if(m_btnClose.m_hWnd != NULL)
- {
- POINT pt = {};
- ::GetCursorPos(&pt);
- RECT rect = {};
- m_btnClose.GetWindowRect(&rect);
- if(::PtInRect(&rect, pt) == FALSE)
- {
- m_nCloseItem = -1;
- T* pT = static_cast<T*>(this);
- pT->DestroyCloseButton();
- }
- else
- {
- bHandled = TRUE;
- }
- }
- return 0;
- }
- LRESULT OnTabCloseBtnMouseLeave(int /*idCtrl*/, LPNMHDR /*pnmh*/, BOOL& /*bHandled*/)
- {
- TCHITTESTINFO thti = {};
- ::GetCursorPos(&thti.pt);
- m_tab.ScreenToClient(&thti.pt);
- int nItem = m_tab.HitTest(&thti);
- if(nItem == -1)
- m_tab.SendMessage(WM_MOUSELEAVE);
- return 0;
- }
- LRESULT OnTabCloseBtnClicked(WORD /*wNotifyCode*/, WORD /*wID*/, HWND /*hWndCtl*/, BOOL& /*bHandled*/)
- {
- T* pT = static_cast<T*>(this);
- pT->OnTabCloseBtn(m_nCloseItem);
- return 0;
- }
- // Implementation helpers
- bool IsValidPageIndex(int nPage) const
- {
- return ((nPage >= 0) && (nPage < GetPageCount()));
- }
- bool MovePage(int nMovePage, int nInsertBeforePage)
- {
- ATLASSERT(IsValidPageIndex(nMovePage));
- ATLASSERT(IsValidPageIndex(nInsertBeforePage));
- if(!IsValidPageIndex(nMovePage) || !IsValidPageIndex(nInsertBeforePage))
- return false;
- if(nMovePage == nInsertBeforePage)
- return true; // nothing to do
- ATL::CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
- LPTSTR lpstrTabText = buff.Allocate(m_cchTabTextLength + 1);
- if(lpstrTabText == NULL)
- return false;
- TCITEMEXTRA tcix = {};
- tcix.tciheader.mask = TCIF_TEXT | TCIF_IMAGE | TCIF_PARAM;
- tcix.tciheader.pszText = lpstrTabText;
- tcix.tciheader.cchTextMax = m_cchTabTextLength + 1;
- BOOL bRet = m_tab.GetItem(nMovePage, tcix);
- ATLASSERT(bRet != FALSE);
- if(bRet == FALSE)
- return false;
- int nInsertItem = (nInsertBeforePage > nMovePage) ? nInsertBeforePage + 1 : nInsertBeforePage;
- int nNewItem = m_tab.InsertItem(nInsertItem, tcix);
- ATLASSERT(nNewItem == nInsertItem);
- if(nNewItem != nInsertItem)
- {
- ATLVERIFY(m_tab.DeleteItem(nNewItem));
- return false;
- }
- if(nMovePage > nInsertBeforePage)
- ATLVERIFY(m_tab.DeleteItem(nMovePage + 1) != FALSE);
- else if(nMovePage < nInsertBeforePage)
- ATLVERIFY(m_tab.DeleteItem(nMovePage) != FALSE);
- SetActivePage(nInsertBeforePage);
- T* pT = static_cast<T*>(this);
- pT->OnPageActivated(m_nActivePage);
- return true;
- }
- // Implementation overrideables
- bool CreateTabControl()
- {
- m_tab.Create(this->m_hWnd, this->rcDefault, NULL, WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | TCS_TOOLTIPS, 0, m_nTabID);
- ATLASSERT(m_tab.m_hWnd != NULL);
- if(m_tab.m_hWnd == NULL)
- return false;
- m_tab.SetFont(AtlCreateControlFont());
- m_bInternalFont = true;
- m_tab.SetItemExtra(sizeof(TABVIEWPAGE));
- T* pT = static_cast<T*>(this);
- m_cyTabHeight = pT->CalcTabHeight();
- return true;
- }
- int CalcTabHeight()
- {
- int nCount = m_tab.GetItemCount();
- TCHAR szText[] = _T("NS");
- TCITEMEXTRA tcix = {};
- tcix.tciheader.mask = TCIF_TEXT;
- tcix.tciheader.pszText = szText;
- int nIndex = m_tab.InsertItem(nCount, tcix);
- RECT rect = { 0, 0, 1000, 1000 };
- m_tab.AdjustRect(FALSE, &rect);
- RECT rcWnd = { 0, 0, 1000, rect.top };
- ::AdjustWindowRectEx(&rcWnd, m_tab.GetStyle(), FALSE, m_tab.GetExStyle());
- int nHeight = rcWnd.bottom - rcWnd.top;
- m_tab.DeleteItem(nIndex);
- return nHeight;
- }
- void ShowTabControl(bool bShow)
- {
- m_tab.ShowWindow(bShow ? SW_SHOWNOACTIVATE : SW_HIDE);
- T* pT = static_cast<T*>(this);
- pT->UpdateLayout();
- }
- void UpdateLayout()
- {
- RECT rect = {};
- this->GetClientRect(&rect);
- int cyOffset = 0;
- if(m_tab.IsWindow() && ((m_tab.GetStyle() & WS_VISIBLE) != 0))
- {
- m_tab.SetWindowPos(NULL, 0, 0, rect.right - rect.left, m_cyTabHeight, SWP_NOZORDER);
- cyOffset = m_cyTabHeight;
- }
- if(m_nActivePage != -1)
- ::SetWindowPos(GetPageHWND(m_nActivePage), NULL, 0, cyOffset, rect.right - rect.left, rect.bottom - rect.top - cyOffset, SWP_NOZORDER);
- }
- void UpdateMenu()
- {
- if(m_menu.m_hMenu != NULL)
- BuildWindowMenu(m_menu, m_nMenuItemsCount, m_bEmptyMenuItem, m_bWindowsMenuItem, m_bActivePageMenuItem, m_bActiveAsDefaultMenuItem);
- }
- void UpdateTitleBar()
- {
- if(!m_wndTitleBar.IsWindow() || (m_lpstrTitleBarBase == NULL))
- return; // nothing to do
- if(m_nActivePage != -1)
- {
- T* pT = static_cast<T*>(this);
- LPCTSTR lpstrTitle = pT->GetPageTitle(m_nActivePage);
- LPCTSTR lpstrDivider = pT->GetTitleDividerText();
- int cchBuffer = m_cchTitleBarLength + lstrlen(lpstrDivider) + lstrlen(m_lpstrTitleBarBase) + 1;
- ATL::CTempBuffer<TCHAR, _WTL_STACK_ALLOC_THRESHOLD> buff;
- LPTSTR lpstrPageTitle = buff.Allocate(cchBuffer);
- ATLASSERT(lpstrPageTitle != NULL);
- if(lpstrPageTitle != NULL)
- {
- pT->ShortenTitle(lpstrTitle, lpstrPageTitle, m_cchTitleBarLength + 1);
- ATL::Checked::tcscat_s(lpstrPageTitle, cchBuffer, lpstrDivider);
- ATL::Checked::tcscat_s(lpstrPageTitle, cchBuffer, m_lpstrTitleBarBase);
- }
- else
- {
- lpstrPageTitle = m_lpstrTitleBarBase;
- }
- m_wndTitleBar.SetWindowText(lpstrPageTitle);
- }
- else
- {
- m_wndTitleBar.SetWindowText(m_lpstrTitleBarBase);
- }
- }
- void DrawMoveMark(int nItem)
- {
- T* pT = static_cast<T*>(this);
- if(m_nInsertItem != -1)
- {
- RECT rect = {};
- pT->GetMoveMarkRect(rect);
- m_tab.InvalidateRect(&rect);
- }
- m_nInsertItem = nItem;
- if(m_nInsertItem != -1)
- {
- CClientDC dc(m_tab.m_hWnd);
- RECT rect = {};
- pT->GetMoveMarkRect(rect);
- CPen pen;
- pen.CreatePen(PS_SOLID, 1, ::GetSysColor(COLOR_WINDOWTEXT));
- CBrush brush;
- brush.CreateSolidBrush(::GetSysColor(COLOR_WINDOWTEXT));
- HPEN hPenOld = dc.SelectPen(pen);
- HBRUSH hBrushOld = dc.SelectBrush(brush);
- int x = rect.left;
- int y = rect.top;
- POINT ptsTop[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y + m_cyMoveMark } };
- dc.Polygon(ptsTop, 3);
- y = rect.bottom - 1;
- POINT ptsBottom[3] = { { x, y }, { x + m_cxMoveMark, y }, { x + (m_cxMoveMark / 2), y - m_cyMoveMark } };
- dc.Polygon(ptsBottom, 3);
- dc.SelectPen(hPenOld);
- dc.SelectBrush(hBrushOld);
- }
- }
- void GetMoveMarkRect(RECT& rect) const
- {
- m_tab.GetClientRect(&rect);
- RECT rcItem = {};
- m_tab.GetItemRect(m_nInsertItem, &rcItem);
- if(m_nInsertItem <= m_nActivePage)
- {
- rect.left = rcItem.left - m_cxMoveMark / 2 - 1;
- rect.right = rcItem.left + m_cxMoveMark / 2;
- }
- else
- {
- rect.left = rcItem.right - m_cxMoveMark / 2 - 1;
- rect.right = rcItem.right + m_cxMoveMark / 2;
- }
- }
- void SetMoveCursor(bool bCanMove)
- {
- ::SetCursor(::LoadCursor(NULL, bCanMove ? IDC_ARROW : IDC_NO));
- }
- void GenerateDragImage(int nItem)
- {
- ATLASSERT(IsValidPageIndex(nItem));
- RECT rcItem = {};
- m_tab.GetItemRect(nItem, &rcItem);
- ::InflateRect(&rcItem, 2, 2); // make bigger to cover selected item
- ATLASSERT(m_ilDrag.m_hImageList == NULL);
- m_ilDrag.Create(rcItem.right - rcItem.left, rcItem.bottom - rcItem.top, ILC_COLORDDB | ILC_MASK, 1, 1);
- CClientDC dc(this->m_hWnd);
- CDC dcMem;
- dcMem.CreateCompatibleDC(dc);
- ATLASSERT(dcMem.m_hDC != NULL);
- dcMem.SetViewportOrg(-rcItem.left, -rcItem.top);
- CBitmap bmp;
- bmp.CreateCompatibleBitmap(dc, rcItem.right - rcItem.left, rcItem.bottom - rcItem.top);
- ATLASSERT(bmp.m_hBitmap != NULL);
- HBITMAP hBmpOld = dcMem.SelectBitmap(bmp);
- m_tab.SendMessage(WM_PRINTCLIENT, (WPARAM)dcMem.m_hDC);
- dcMem.SelectBitmap(hBmpOld);
- ATLVERIFY(m_ilDrag.Add(bmp.m_hBitmap, RGB(255, 0, 255)) != -1);
- }
- void ShortenTitle(LPCTSTR lpstrTitle, LPTSTR lpstrShortTitle, int cchShortTitle)
- {
- if(lstrlen(lpstrTitle) >= cchShortTitle)
- {
- LPCTSTR lpstrEllipsis = _T("...");
- int cchEllipsis = lstrlen(lpstrEllipsis);
- ATL::Checked::tcsncpy_s(lpstrShortTitle, cchShortTitle, lpstrTitle, cchShortTitle - cchEllipsis - 1);
- ATL::Checked::tcscat_s(lpstrShortTitle, cchShortTitle, lpstrEllipsis);
- }
- else
- {
- ATL::Checked::tcscpy_s(lpstrShortTitle, cchShortTitle, lpstrTitle);
- }
- }
- void UpdateTooltipText(LPNMTTDISPINFO pTTDI)
- {
- ATLASSERT(pTTDI != NULL);
- pTTDI->lpszText = (LPTSTR)GetPageTitle((int)pTTDI->hdr.idFrom);
- }
- int DragHitTest(POINT pt) const
- {
- RECT rect = {};
- this->GetClientRect(&rect);
- if(::PtInRect(&rect, pt) == FALSE)
- return -1;
- m_tab.GetClientRect(&rect);
- TCHITTESTINFO hti = {};
- hti.pt.x = pt.x;
- hti.pt.y = rect.bottom / 2; // use middle to ignore
- int nItem = m_tab.HitTest(&hti);
- if(nItem == -1)
- {
- int nLast = m_tab.GetItemCount() - 1;
- RECT rcItem = {};
- m_tab.GetItemRect(nLast, &rcItem);
- if(pt.x >= rcItem.right)
- nItem = nLast;
- }
- return nItem;
- }
- void StartStopAutoScroll(int x)
- {
- AutoScroll scroll = _AUTOSCROLL_NONE;
- if(x != -1)
- {
- RECT rect = {};
- m_tab.GetClientRect(&rect);
- int dx = ::GetSystemMetrics(SM_CXVSCROLL);
- if((x >= 0) && (x < dx))
- {
- RECT rcItem = {};
- m_tab.GetItemRect(0, &rcItem);
- if(rcItem.left < rect.left)
- scroll = _AUTOSCROLL_LEFT;
- }
- else if((x >= (rect.right - dx)) && (x < rect.right))
- {
- RECT rcItem = {};
- m_tab.GetItemRect(m_tab.GetItemCount() - 1, &rcItem);
- if(rcItem.right > rect.right)
- scroll = _AUTOSCROLL_RIGHT;
- }
- }
- if(scroll != _AUTOSCROLL_NONE)
- {
- if(m_ud.m_hWnd == NULL)
- m_ud = m_tab.GetWindow(GW_CHILD);
- if(m_AutoScroll != scroll)
- {
- m_AutoScroll = scroll;
- this->SetTimer(_nAutoScrollTimerID, 300);
- }
- }
- else
- {
- this->KillTimer(_nAutoScrollTimerID);
- m_AutoScroll = _AUTOSCROLL_NONE;
- }
- }
- void DoAutoScroll()
- {
- ATLASSERT(m_AutoScroll != _AUTOSCROLL_NONE);
- int nMin = -1, nMax = -1;
- m_ud.GetRange(nMin, nMax);
- int nPos = m_ud.GetPos();
- int nNewPos = -1;
- if((m_AutoScroll == _AUTOSCROLL_LEFT) && (nPos > nMin))
- nNewPos = nPos - 1;
- else if((m_AutoScroll == _AUTOSCROLL_RIGHT) && (nPos < nMax))
- nNewPos = nPos + 1;
- if(nNewPos != -1)
- {
- m_tab.SendMessage(WM_HSCROLL, MAKEWPARAM(SB_THUMBPOSITION, nNewPos));
- m_tab.SendMessage(WM_HSCROLL, MAKEWPARAM(SB_ENDSCROLL, 0));
- POINT pt = {};
- ::GetCursorPos(&pt);
- m_tab.ScreenToClient(&pt);
- m_tab.SendMessage(WM_MOUSEMOVE, NULL, MAKELPARAM(pt.x, pt.y));
- }
- }
- // Text for menu items and title bar - override to provide different strings
- static LPCTSTR GetEmptyListText()
- {
- return _T("(Empty)");
- }
- static LPCTSTR GetWindowsMenuItemText()
- {
- return _T("&Windows...");
- }
- static LPCTSTR GetTitleDividerText()
- {
- return _T(" - ");
- }
- // Notifications - override to provide different behavior
- void OnPageActivated(int nPage)
- {
- NMHDR nmhdr = {};
- nmhdr.hwndFrom = this->m_hWnd;
- nmhdr.idFrom = nPage;
- nmhdr.code = TBVN_PAGEACTIVATED;
- this->GetParent().SendMessage(WM_NOTIFY, this->GetDlgCtrlID(), (LPARAM)&nmhdr);
- }
- void OnContextMenu(int nPage, POINT pt)
- {
- TBVCONTEXTMENUINFO cmi = {};
- cmi.hdr.hwndFrom = this->m_hWnd;
- cmi.hdr.idFrom = nPage;
- cmi.hdr.code = TBVN_CONTEXTMENU;
- cmi.pt = pt;
- this->GetParent().SendMessage(WM_NOTIFY, this->GetDlgCtrlID(), (LPARAM)&cmi);
- }
- void OnTabCloseBtn(int nPage)
- {
- NMHDR nmhdr = {};
- nmhdr.hwndFrom = this->m_hWnd;
- nmhdr.idFrom = nPage;
- nmhdr.code = TBVN_TABCLOSEBTN;
- LRESULT lRet = this->GetParent().SendMessage(WM_NOTIFY, this->GetDlgCtrlID(), (LPARAM)&nmhdr);
- if(lRet == 0) // default - close page
- {
- T* pT = static_cast<T*>(this);
- pT->RemovePage(m_nCloseItem);
- m_nCloseItem = -1;
- pT->DestroyCloseButton();
- }
- else
- {
- m_tab.SendMessage(WM_MOUSELEAVE);
- }
- }
- // Close button overrideables
- void CreateCloseButton(int nItem)
- {
- ATLASSERT(m_btnClose.m_hWnd == NULL);
- m_btnClose.m_bPressed = false;
- T* pT = static_cast<T*>(this);
- RECT rcClose = {};
- pT->CalcCloseButtonRect(nItem, rcClose);
- m_btnClose.Create(m_tab.m_hWnd, rcClose, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, T::_nCloseBtnID);
- ATLASSERT(m_btnClose.IsWindow());
- if(m_btnClose.m_hWnd != NULL)
- {
- // create a tool tip
- ATLASSERT(m_btnClose.m_tip.m_hWnd == NULL);
- m_btnClose.m_tip.Create(m_btnClose.m_hWnd);
- ATLASSERT(m_btnClose.m_tip.IsWindow());
- if(m_btnClose.m_tip.IsWindow())
- {
- m_btnClose.m_tip.Activate(TRUE);
- RECT rect = {};
- m_btnClose.GetClientRect(&rect);
- m_btnClose.m_tip.AddTool(m_btnClose.m_hWnd, LPSTR_TEXTCALLBACK, &rect, T::_nCloseBtnID);
- }
- }
- }
- void DestroyCloseButton()
- {
- ATLASSERT(m_btnClose.m_hWnd != NULL);
- if(m_btnClose.m_hWnd != NULL)
- {
- if(m_btnClose.m_tip.IsWindow())
- {
- m_btnClose.m_tip.DestroyWindow();
- m_btnClose.m_tip.m_hWnd = NULL;
- }
- m_btnClose.DestroyWindow();
- }
- }
- void CalcCloseButtonRect(int nItem, RECT& rcClose)
- {
- RECT rcItem = {};
- m_tab.GetItemRect(nItem, &rcItem);
- int cy = (rcItem.bottom - rcItem.top - _cyCloseBtn) / 2;
- int cx = (nItem == m_tab.GetCurSel()) ? _cxCloseBtnMarginSel : _cxCloseBtnMargin;
- ::SetRect(&rcClose, rcItem.right - cx - _cxCloseBtn, rcItem.top + cy,
- rcItem.right - cx, rcItem.top + cy + _cyCloseBtn);
- }
- };
- class CTabView : public CTabViewImpl<CTabView>
- {
- public:
- DECLARE_WND_CLASS_EX(_T("WTL_TabView"), 0, COLOR_APPWORKSPACE)
- };
- } // namespace WTL
- #endif // __ATLCTRLX_H__
|