GridCtrl.cpp 163 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396
  1. // GridCtrl.cpp : implementation file
  2. //
  3. // MFC Grid Control
  4. //
  5. // Written by Chris Maunder
  6. // mailto:chrismaunder@codeguru.com
  7. //
  8. // Copyright (c) 1998-1999.
  9. //
  10. // The code contained in this file is based on the original
  11. // WorldCom Grid control written by Joe Willcoxson,
  12. // mailto:chinajoe@aol.com
  13. // http://users.aol.com/chinajoe
  14. // The code has gone through so many modifications that I'm
  15. // not sure if there is even a single original line of code.
  16. // In any case Joe's code was a great framewaork on which to
  17. // build.
  18. //
  19. // This code may be used in compiled form in any way you desire. This
  20. // file may be redistributed unmodified by any means PROVIDING it is
  21. // not sold for profit without the authors written consent, and
  22. // providing that this notice and the authors name and all copyright
  23. // notices remains intact. If the source code in this file is used in
  24. // any commercial application then a statement along the lines of
  25. // "Portions copyright (c) Chris Maunder, 1998" must be included in
  26. // the startup banner, "About" box or printed documentation. An email
  27. // letting me know that you are using it would be nice as well. That's
  28. // not much to ask considering the amount of work that went into this.
  29. //
  30. // This file is provided "as is" with no expressed or implied warranty.
  31. // The author accepts no liability for any damage/loss of business that
  32. // this product may cause.
  33. //
  34. // Expect bugs!
  35. //
  36. // Please use and enjoy, and let me know of any bugs/mods/improvements
  37. // that you have found/implemented and I will fix/incorporate them into
  38. // this file.
  39. //
  40. // History:
  41. // --------
  42. // This control is constantly evolving, sometimes due to new features that I
  43. // feel are necessary, and sometimes due to existing bugs. Where possible I
  44. // have credited the changes to those who contributed code corrections or
  45. // enhancements (names in brackets) or code suggestions (suggested by...)
  46. //
  47. // 1.0 20 Feb 1998 First release version.
  48. // 1.01 24 Feb 1998 Memory leak fix (Jens Bohlmann)
  49. // Fixec typo (my fault!) in CMemDC.h - Claus Arend-Schneider)
  50. // Bug in GetSelectedCount (Lyn Newton)
  51. // 1.02 4 Mar 1998 Scrolling a little neater (less dead area)
  52. // Cell selection via OnTimer correctly updates Focus cell (Suggested by Lyn Newton)
  53. // 1.03 17 Mar 1998 Clipboard functions added, Intellimouse support
  54. // Using 32 bit scroll pos functions instead of 16 bit ("cronos")
  55. // Added OLE drag and drop.
  56. // 1.04 6 Apr 1998 Added Ctrl-A = Select All, fixed CGridDropTarget
  57. // problem, minor bug in CopyTextFromGrid (assert on
  58. // empty string). Cleaned up reponse to m_bEditable
  59. // (OnDrop and Ctrl-X disabled)
  60. // 1.05 10 May 1998 Memory leak fixed. (Yuheng Zhao)
  61. // Changed OLE initialisation (Carlo Comino)
  62. // Added separate fore + background cell colours (Suggested by John Crane)
  63. // ExpandToFit etc cleaned up - now decreases and
  64. // increases cell sizes to fit client area.
  65. // Added notification messages for the grid's parent (Suggested by
  66. // Added GVIS_READONLY state
  67. // 1.06 20 May 1998 Added TAB key handling. (Daniela Rybarova)
  68. // Intellimouse code correction for whole page scrolling (Paul Grant)
  69. // Fixed 16 bit thumb track problems (now 32 bit) (Paul Grant)
  70. // Fixed accelerator key problem in CInPlaceEdit (Matt Weagle)
  71. // Fixed Stupid ClassWizard code parsing problem (Michael A. Barnhart)
  72. // Double buffering now programmatically selectable
  73. // Workaround for win95 drag and drop registration problem
  74. // Corrected UNICODE implementation of clipboard stuff
  75. // Dragging and dropping from a selection onto itself no
  76. // no longer causes the cells to be emptied
  77. // 1.07 28 Jul 1998 Added EnsureVisible. (Roelf Werkman)
  78. // Fixed delete key problem on read-only cells. (Serge Weinstock)
  79. // OnEndInPlaceEdit sends notification AFTER storing
  80. // the modified text in the cell.
  81. // Added CreateInPlaceEditControl to make it easier to
  82. // change the way cells are edited. (suggested by Chris Clark)
  83. // Added Set/GetGridColor.
  84. // CopyTextToClipboard and PasteTextToGrid problem with
  85. // blank cells fixed, and CopyTextToClipboard tweaked.
  86. // SetModified called when cutting text or hitting DEL. (Jonathan Watters)
  87. // Focus cell made visible when editing begins.
  88. // Blank lines now treated correctly when pasting data.
  89. // Removed ES_MULTILINE style from the default edit control.
  90. // Added virtual CreateCell(row, col) function.
  91. // Fonts now specified on a per-cell basis using Get/SetItemFont.
  92. // 1.08 6 Aug 1998 Ctrl+arrows now allows cell navigation. Modified
  93. // CreateInPlaceEditControl to accept ID of control.
  94. // Added Titletips to grid cells. (Added EnableTitleTips / GetTitleTips)
  95. // 1.09 12 Sep 1998 When printing, parent window title is printed in header - Gert Rijs
  96. // GetNextItem search with GVNI_DROPHILITED now returns
  97. // cells with GVIS_DROPHILITED set, instead of GVIS_FOCUSED (Franco Bez)
  98. // (Also fixed minor bug in GetNextItem) (Franco Bez)
  99. // Cell selection using Shift+arrows works - Franco Bez
  100. // SetModified called after edits ONLY if contents changed (Franco Bez)
  101. // Cell colours now dithered in 256 colour screens.
  102. // Support for MSVC 4.2 (Graham Cheetham)
  103. // 1.10 30 Nov 1998 Titletips now disappear on a scroll event. Compiler errors
  104. // fixed. Grid lines drawing fixed (Graham Cheetham).
  105. // Cell focus fix on Isert Row/Col (Jochen Kauffmann)
  106. // Added DeleteNonFixedRows() (John Rackley)
  107. // Message #define conflict fixed (Oskar Wieland)
  108. // Titletips & cell insert/delete fix (Ramesh Dhar)
  109. // Titletips repeat-creation bug fixed.
  110. // GVN_SELCHANGED message now sends current cell ID
  111. // Font resource leak in GetTextExtent fixed (Gavin Jerman)
  112. // More TAB fixes (Andreas Ruh)
  113. // 1.11 1 Dec 1998 GetNextItem bug fix (suggested by Francis Fu)
  114. // InsertColumn (-1) fix (Roy Hopkins)
  115. // Was too liberal with the "IsEditable"'s. oops. (Michel Hete)
  116. // 1.11a 4 Jan 1999 Compiler errors in VC6 fixed.
  117. // 1.12 10 Apr 1999 Cleanup to allow GRIDCONTROL_NO_CLIPBOARD define
  118. // CE #defines added. (Thanks to Frank Uzzolino for a start on this)
  119. // TitleTip display fixed for cells with images, plus it now uses cell font
  120. // Added GetTextRect and IsCellFixed
  121. // Focus change problem when resizing columns fixed (Sergey Nikiforenko)
  122. // Grid line drawing problem in fixed cells fixed (Sergey Nikiforenko)
  123. // CreateCell format persistance bug fixed (Sergey Nikiforenko)
  124. // DeleteColumn now returns TRUE (oops) (R. Elmer)
  125. // Enter, Tab and Esc key problem (finally) fixed - Darren Webb and Koay Kah Hoe
  126. // OnSize infinite loop fixed - Steve Kowald
  127. // GVN_SELCHANGING and GVN_SELCHANGED values changed to avoid conflicts (Hiroaki Watanabe)
  128. // Added single row selection mode (Yao Cai)
  129. // Fixed image drawing clip problem
  130. // Reduced unnecessary redraws significantly
  131. // GetNextItem additions and bug fix, and GVNI_AREA search option (Franco Bez)
  132. // Added GVIS_MODIFIED style for cells, so individual cells can have their
  133. // modification status queried. (Franco Bez)
  134. // 1.12a 15 Apr 1999 Removed the SetModified/GetModified inlines (no compiler warning!)
  135. // Renamed IDC_INPLACE_CONTROL to IDC_INPLACE_CONTROL and moved
  136. // to the header
  137. //
  138. // TODO:
  139. // - OnOutOfMemory function instead of exceptions
  140. // - Decrease timer interval over time to speed up selection over time
  141. //
  142. // NOTE: Grid data is stored row-by-row, so all operations on large numbers
  143. // of cells should be done row-by-row as well.
  144. //
  145. // KNOWN ISSUES TO BE ADDRESSED (Please don't send bug reports):
  146. // * Killfocus comes to late when a command is selected by the Menu.
  147. // When you are editing a cell and choose a Menuitem that searches for all the
  148. // modified cells it is not found. When you chose the menu a second time it is
  149. // found. I assume that the Menu command is executed before the cell receives the
  150. // KillFocus event. Expect similar Problems with accelerators. (Franco Bez)
  151. // * When you select a cell and move the mouse around (with the Left button down
  152. // i.e continuing with your selection) - if the mouse is over the Fixed column
  153. // or Row the drawing of the selected region is strange - in particular as you
  154. // move up and down say the Left Fixed Column notice the behaviour of the Focus
  155. // Cell - it is out of sync. (Vinay Desai)
  156. //
  157. /////////////////////////////////////////////////////////////////////////////
  158. #include "stdafx.h"
  159. #include "MemDC.h"
  160. #include "GridCtrl.h"
  161. #include "InPlaceEdit.h"
  162. #include "ModeDlg.h"
  163. #include "ReliefDlg.h"
  164. // OLE stuff for clipboard operations
  165. #include <afxadv.h> // For CSharedFile
  166. #include <afxconv.h> // For LPTSTR -> LPSTR macros
  167. #ifdef _DEBUG
  168. #define new DEBUG_NEW
  169. #undef THIS_FILE
  170. static char THIS_FILE[] = __FILE__;
  171. #endif
  172. #define HEADER_HEIGHT 2 // For printing
  173. #define FOOTER_HEIGHT 2
  174. #define LEFT_MARGIN 4
  175. #define RIGHT_MARGIN 4
  176. #define TOP_MARGIN 1
  177. #define BOTTOM_MARGIN 1
  178. #define GAP 1
  179. #define SELECTED_CELL_FONT_WEIGHT 600 // weight of text for selected items
  180. IMPLEMENT_DYNCREATE(CGridCtrl, CWnd)
  181. void AFXAPI DDX_GridControl(CDataExchange* pDX, int nIDC, CGridCtrl& rControl)
  182. {
  183. if (rControl.GetSafeHwnd() == NULL) // not subclassed yet
  184. {
  185. ASSERT(!pDX->m_bSaveAndValidate);
  186. HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
  187. if (!rControl.SubclassWindow(hWndCtrl))
  188. {
  189. ASSERT(FALSE); // possibly trying to subclass twice?
  190. AfxThrowNotSupportedException();
  191. }
  192. #ifndef _AFX_NO_OCC_SUPPORT
  193. else
  194. {
  195. // If the control has reparented itself (e.g., invisible control),
  196. // make sure that the CWnd gets properly wired to its control site.
  197. if (pDX->m_pDlgWnd->GetSafeHwnd() != ::GetParent(rControl.GetSafeHwnd()))
  198. rControl.AttachControlSite(pDX->m_pDlgWnd);
  199. }
  200. #endif //!_AFX_NO_OCC_SUPPORT
  201. }
  202. }
  203. // Get the number of lines to scroll with each mouse wheel notch
  204. // Why doesn't windows give us this function???
  205. UINT GetMouseScrollLines()
  206. {
  207. int nScrollLines = 3; // reasonable default
  208. HKEY hKey;
  209. if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"),
  210. 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
  211. {
  212. TCHAR szData[128];
  213. DWORD dwKeyDataType;
  214. DWORD dwDataBufSize = sizeof(szData);
  215. if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
  216. (LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
  217. {
  218. nScrollLines = _tcstoul(szData, NULL, 10);
  219. }
  220. RegCloseKey(hKey);
  221. }
  222. return nScrollLines;
  223. }
  224. /////////////////////////////////////////////////////////////////////////////
  225. // CGridCtrl
  226. CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
  227. {
  228. RegisterWindowClass();
  229. nParentType = 0;
  230. bEditing = false;
  231. // Initialize OLE libraries
  232. m_bMustUninitOLE = FALSE;
  233. #if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
  234. _AFX_THREAD_STATE* pState = AfxGetThreadState();
  235. if (!pState->m_bNeedTerm)
  236. {
  237. SCODE sc = ::OleInitialize(NULL);
  238. if (FAILED(sc))
  239. AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
  240. else
  241. m_bMustUninitOLE = TRUE;
  242. }
  243. #endif
  244. // Store the system colours in case they change. The gridctrl uses
  245. // these colours, and in OnSysColorChange we can check to see if
  246. // the gridctrl colours have been changed from the system colours.
  247. // If they have, then leave them, otherwise change them to reflect
  248. // the new system colours.
  249. m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
  250. m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
  251. m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
  252. m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
  253. m_crGridColour = RGB(192,192,192);
  254. m_nRows = 0;
  255. m_nCols = 0;
  256. m_nFixedRows = 0;
  257. m_nFixedCols = 0;
  258. m_nDefCellHeight = 10; // These will get changed to something meaningful
  259. m_nDefCellWidth = 30; // when the window is created or subclassed
  260. m_nVScrollMax = 0; // Scroll position
  261. m_nHScrollMax = 0;
  262. m_nMargin = 0; // cell padding
  263. m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
  264. // per mouse wheel notch to scroll
  265. m_MouseMode = MOUSE_NOTHING;
  266. m_nGridLines = GVL_BOTH;
  267. m_bEditable = TRUE;
  268. m_bListMode = FALSE;
  269. m_bSingleRowSelection = FALSE;
  270. m_bAllowDraw = TRUE; // allow draw updates
  271. m_bEnableSelection = TRUE;
  272. m_bAllowRowResize = TRUE;
  273. m_bAllowColumnResize = TRUE;
  274. m_bSortOnClick = TRUE; // Sort on header row click if in list mode
  275. m_bHandleTabKey = TRUE;
  276. #ifdef _WIN32_WCE
  277. m_bDoubleBuffer = FALSE; // Use double buffering to avoid flicker?
  278. #else
  279. m_bDoubleBuffer = TRUE; // Use double buffering to avoid flicker?
  280. #endif
  281. m_bTitleTips = TRUE; // show cell title tips
  282. m_bAscending = TRUE; // sorting stuff
  283. m_SortColumn = -1;
  284. m_nTimerID = 0; // For drag-selection
  285. m_nTimerInterval = 25; // (in milliseconds)
  286. m_nResizeCaptureRange = 3; // When resizing columns/row, the cursor has to be
  287. // within +/-3 pixels of the dividing line for
  288. // resizing to be possible
  289. m_pImageList = NULL;
  290. m_bAllowDragAndDrop = FALSE; // for drag and drop
  291. #ifndef _WIN32_WCE
  292. // Initially use the system message font for the GridCtrl font
  293. NONCLIENTMETRICS ncm;
  294. ncm.cbSize = sizeof(NONCLIENTMETRICS);
  295. VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
  296. memcpy(&m_Logfont, &(ncm.lfMessageFont), sizeof(LOGFONT));
  297. #else
  298. LOGFONT lf;
  299. GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lf);
  300. memcpy(&m_Logfont, &lf, sizeof(LOGFONT));
  301. #endif
  302. // Set up the initial grid size
  303. SetRowCount(nRows);
  304. SetColumnCount(nCols);
  305. SetFixedRowCount(nFixedRows);
  306. SetFixedColumnCount(nFixedCols);
  307. // Set the colours
  308. SetTextColor(m_crWindowText);
  309. SetTextBkColor(m_crWindowColour);
  310. SetBkColor(m_crShadow);
  311. SetFixedTextColor(m_crWindowText);
  312. SetFixedBkColor(m_cr3DFace);
  313. // set initial selection range (ie. none)
  314. m_SelectedCellMap.RemoveAll();
  315. m_PrevSelectedCellMap.RemoveAll();
  316. }
  317. CGridCtrl::~CGridCtrl()
  318. {
  319. DeleteAllItems();
  320. DestroyWindow();
  321. m_Font.DeleteObject();
  322. #if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
  323. // Uninitialize OLE support
  324. if (m_bMustUninitOLE)
  325. ::OleUninitialize();
  326. #endif
  327. }
  328. // Register the window class if it has not already been registered.
  329. BOOL CGridCtrl::RegisterWindowClass()
  330. {
  331. WNDCLASS wndcls;
  332. HINSTANCE hInst = AfxGetInstanceHandle();
  333. // HINSTANCE hInst = AfxGetResourceHandle();
  334. if (!(::GetClassInfo(hInst, GRIDCTRL_CLASSNAME, &wndcls)))
  335. {
  336. // otherwise we need to register a new class
  337. wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  338. wndcls.lpfnWndProc = ::DefWindowProc;
  339. wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
  340. wndcls.hInstance = hInst;
  341. wndcls.hIcon = NULL;
  342. wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
  343. wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
  344. wndcls.lpszMenuName = NULL;
  345. wndcls.lpszClassName = GRIDCTRL_CLASSNAME;
  346. if (!AfxRegisterClass(&wndcls)) {
  347. AfxThrowResourceException();
  348. return FALSE;
  349. }
  350. }
  351. return TRUE;
  352. }
  353. BOOL CGridCtrl::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwStyle)
  354. {
  355. ASSERT(pParentWnd->GetSafeHwnd());
  356. if (!CWnd::Create(GRIDCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID))
  357. return FALSE;
  358. #ifndef GRIDCONTROL_NO_DRAGDROP
  359. m_DropTarget.Register(this);
  360. #endif
  361. // Create titletips
  362. #ifndef GRIDCONTROL_NO_TITLETIPS
  363. if (m_bTitleTips)
  364. m_TitleTip.Create(this);
  365. #endif
  366. // The number of rows and columns will only be non-zero if the constructor
  367. // was called with non-zero initialising parameters. If this window was created
  368. // using a dialog template then the number of rows and columns will be 0 (which
  369. // means that the code below will not be needed - which is lucky 'cause it ain't
  370. // gonna get called in a dialog-template-type-situation.
  371. TRY {
  372. m_arRowHeights.SetSize(m_nRows); // initialize row heights
  373. m_arColWidths.SetSize(m_nCols); // initialize column widths
  374. }
  375. CATCH (CMemoryException, e) {
  376. e->ReportError();
  377. e->Delete();
  378. return FALSE;
  379. }
  380. END_CATCH
  381. for (int i = 0; i < m_nRows; i++) m_arRowHeights[i] = m_nDefCellHeight;
  382. for (int i = 0; i < m_nCols; i++) m_arColWidths[i] = m_nDefCellWidth;
  383. ResetScrollBars();
  384. return TRUE;
  385. }
  386. void CGridCtrl::PreSubclassWindow()
  387. {
  388. CWnd::PreSubclassWindow();
  389. HFONT hFont = ::CreateFontIndirect(&m_Logfont);
  390. OnSetFont((LPARAM)hFont, 0);
  391. DeleteObject(hFont);
  392. ResetScrollBars();
  393. }
  394. BOOL CGridCtrl::SubclassWindow(HWND hWnd)
  395. {
  396. if (!CWnd::SubclassWindow(hWnd))
  397. return FALSE;
  398. #ifndef GRIDCONTROL_NO_DRAGDROP
  399. m_DropTarget.Register(this);
  400. #endif
  401. #ifndef GRIDCONTROL_NO_TITLETIPS
  402. if (m_bTitleTips && !IsWindow(m_TitleTip.m_hWnd))
  403. m_TitleTip.Create(this);
  404. #endif
  405. return TRUE;
  406. }
  407. LRESULT CGridCtrl::SendMessageToParent(int nRow, int nCol, int nMessage)
  408. {
  409. if (!IsWindow(m_hWnd))
  410. return 0;
  411. NM_GRIDVIEW nmgv;
  412. nmgv.iRow = nRow;
  413. nmgv.iColumn = nCol;
  414. nmgv.hdr.hwndFrom = m_hWnd;
  415. nmgv.hdr.idFrom = GetDlgCtrlID();
  416. nmgv.hdr.code = nMessage;
  417. CWnd *pOwner = GetOwner();
  418. if (pOwner && IsWindow(pOwner->m_hWnd))
  419. return pOwner->SendMessage(WM_NOTIFY, nmgv.hdr.idFrom, (LPARAM)&nmgv);
  420. else
  421. return 0;
  422. }
  423. BEGIN_MESSAGE_MAP(CGridCtrl, CWnd)
  424. //{{AFX_MSG_MAP(CGridCtrl)
  425. ON_WM_PAINT()
  426. ON_WM_HSCROLL()
  427. ON_WM_VSCROLL()
  428. ON_WM_SIZE()
  429. ON_WM_LBUTTONUP()
  430. ON_WM_LBUTTONDOWN()
  431. ON_WM_MOUSEMOVE()
  432. ON_WM_TIMER()
  433. ON_WM_GETDLGCODE()
  434. ON_WM_KEYDOWN()
  435. ON_WM_CHAR()
  436. ON_WM_LBUTTONDBLCLK()
  437. ON_WM_ERASEBKGND()
  438. ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
  439. ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateEditSelectAll)
  440. //}}AFX_MSG_MAP
  441. #ifndef _WIN32_WCE_NO_CURSOR
  442. ON_WM_SETCURSOR()
  443. #endif
  444. #ifndef _WIN32_WCE
  445. ON_WM_SYSCOLORCHANGE()
  446. ON_WM_CAPTURECHANGED()
  447. #endif
  448. #ifndef GRIDCONTROL_NO_CLIPBOARD
  449. ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  450. ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
  451. ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  452. ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)
  453. ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  454. ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
  455. #endif
  456. #if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
  457. ON_WM_MOUSEWHEEL()
  458. #endif
  459. #if (_WIN32_WCE >= 210)
  460. ON_WM_SETTINGCHANGE()
  461. #endif
  462. ON_MESSAGE(WM_SETFONT, OnSetFont)
  463. ON_MESSAGE(WM_GETFONT, OnGetFont)
  464. ON_NOTIFY(GVN_ENDLABELEDIT, IDC_INPLACE_CONTROL, OnEndInPlaceEdit)
  465. END_MESSAGE_MAP()
  466. /////////////////////////////////////////////////////////////////////////////
  467. // CGridCtrl message handlers
  468. void CGridCtrl::OnPaint()
  469. {
  470. CPaintDC dc(this); // device context for painting
  471. if (m_bDoubleBuffer) // Use a memory DC to remove flicker
  472. {
  473. CMyMemDC MemDC(&dc);
  474. OnDraw(&MemDC);
  475. }
  476. else // Draw raw - this helps in debugging vis problems.
  477. OnDraw(&dc);
  478. }
  479. BOOL CGridCtrl::OnEraseBkgnd(CDC* /*pDC*/)
  480. {
  481. return TRUE; // Don't erase the background.
  482. }
  483. // Custom background erasure. This gets called from within the OnDraw function,
  484. // since we will (most likely) be using a memory DC to stop flicker. If we just
  485. // erase the background normally through OnEraseBkgnd, and didn't fill the memDC's
  486. // selected bitmap with colour, then all sorts of vis problems would occur
  487. void CGridCtrl::EraseBkgnd(CDC* pDC)
  488. {
  489. CRect VisRect, ClipRect, rect;
  490. CBrush FixedBack(GetFixedBkColor()),
  491. TextBack(GetTextBkColor()),
  492. Back(GetBkColor());
  493. if (pDC->GetClipBox(ClipRect) == ERROR)
  494. return;
  495. GetVisibleNonFixedCellRange(VisRect);
  496. // Draw Fixed columns background
  497. int nFixedColumnWidth = GetFixedColumnWidth();
  498. if (ClipRect.left < nFixedColumnWidth && ClipRect.top < VisRect.bottom)
  499. pDC->FillRect(CRect(ClipRect.left, ClipRect.top,
  500. nFixedColumnWidth, VisRect.bottom),
  501. &FixedBack);
  502. // Draw Fixed rows background
  503. int nFixedRowHeight = GetFixedRowHeight();
  504. if (ClipRect.top < nFixedRowHeight &&
  505. ClipRect.right > nFixedColumnWidth && ClipRect.left < VisRect.right)
  506. pDC->FillRect(CRect(nFixedColumnWidth-1, ClipRect.top,
  507. VisRect.right, nFixedRowHeight),
  508. &FixedBack);
  509. // Draw non-fixed cell background
  510. if (rect.IntersectRect(VisRect, ClipRect))
  511. {
  512. CRect CellRect(max(nFixedColumnWidth, rect.left),
  513. max(nFixedRowHeight, rect.top),
  514. rect.right, rect.bottom);
  515. pDC->FillRect(CellRect, &TextBack);
  516. }
  517. // Draw right hand side of window outside grid
  518. if (VisRect.right < ClipRect.right)
  519. pDC->FillRect(CRect(VisRect.right, ClipRect.top,
  520. ClipRect.right, ClipRect.bottom),
  521. &Back);
  522. // Draw bottom of window below grid
  523. if (VisRect.bottom < ClipRect.bottom && ClipRect.left < VisRect.right)
  524. pDC->FillRect(CRect(ClipRect.left, VisRect.bottom,
  525. VisRect.right, ClipRect.bottom),
  526. &Back);
  527. }
  528. void CGridCtrl::OnSize(UINT nType, int cx, int cy)
  529. {
  530. static BOOL bAlreadyInsideThisProcedure = FALSE;
  531. if (bAlreadyInsideThisProcedure)
  532. return;
  533. if (!::IsWindow(m_hWnd))
  534. return;
  535. // Start re-entry blocking
  536. bAlreadyInsideThisProcedure = TRUE;
  537. // if (::IsWindow(GetSafeHwnd()) && GetFocus()->GetSafeHwnd() != GetSafeHwnd())
  538. SetFocus(); // Auto-destroy any InPlaceEdit's
  539. CWnd::OnSize(nType, cx, cy);
  540. ResetScrollBars();
  541. // End re-entry blocking
  542. bAlreadyInsideThisProcedure = FALSE;
  543. }
  544. UINT CGridCtrl::OnGetDlgCode()
  545. {
  546. UINT nCode = DLGC_WANTARROWS | DLGC_WANTCHARS; // DLGC_WANTALLKEYS; //
  547. if (m_bHandleTabKey && !IsCTRLpressed())
  548. nCode |= DLGC_WANTTAB;
  549. return nCode;
  550. }
  551. #ifndef _WIN32_WCE
  552. // If system colours change, then redo colours
  553. void CGridCtrl::OnSysColorChange()
  554. {
  555. CWnd::OnSysColorChange();
  556. if (GetTextColor() == m_crWindowText) // Still using system colours
  557. SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  558. if (GetTextBkColor() == m_crWindowColour)
  559. SetTextBkColor(::GetSysColor(COLOR_WINDOW));
  560. if (GetBkColor() == m_crShadow)
  561. SetBkColor(::GetSysColor(COLOR_3DSHADOW));
  562. if (GetFixedTextColor() == m_crWindowText)
  563. SetFixedTextColor(::GetSysColor(COLOR_WINDOWTEXT));
  564. if (GetFixedBkColor() == m_cr3DFace)
  565. SetFixedBkColor(::GetSysColor(COLOR_3DFACE));
  566. m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
  567. m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
  568. m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
  569. m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
  570. }
  571. #endif
  572. #ifndef _WIN32_WCE_NO_CURSOR
  573. // If we are drag-selecting cells, or drag and dropping, stop now
  574. void CGridCtrl::OnCaptureChanged(CWnd *pWnd)
  575. {
  576. if (pWnd->GetSafeHwnd() == GetSafeHwnd()) return;
  577. // kill timer if active
  578. if (m_nTimerID != 0)
  579. {
  580. KillTimer(m_nTimerID);
  581. m_nTimerID = 0;
  582. }
  583. #ifndef GRIDCONTROL_NO_DRAGDROP
  584. // Kill drag and drop if active
  585. if (m_MouseMode == MOUSE_DRAGGING)
  586. m_MouseMode = MOUSE_NOTHING;
  587. #endif
  588. }
  589. #endif
  590. #if (_MFC_VER >= 0x0421) || (_WIN32_WCE >= 210)
  591. // If system settings change, then redo colours
  592. void CGridCtrl::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
  593. {
  594. CWnd::OnSettingChange(uFlags, lpszSection);
  595. if (GetTextColor() == m_crWindowText) // Still using system colours
  596. SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  597. if (GetTextBkColor() == m_crWindowColour)
  598. SetTextBkColor(::GetSysColor(COLOR_WINDOW));
  599. if (GetBkColor() == m_crShadow)
  600. SetBkColor(::GetSysColor(COLOR_3DSHADOW));
  601. if (GetFixedTextColor() == m_crWindowText)
  602. SetFixedTextColor(::GetSysColor(COLOR_WINDOWTEXT));
  603. if (GetFixedBkColor() == m_cr3DFace)
  604. SetFixedBkColor(::GetSysColor(COLOR_3DFACE));
  605. m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
  606. m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
  607. m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
  608. m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
  609. m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
  610. }
  611. #endif
  612. // For drag-selection. Scrolls hidden cells into view
  613. // TODO: decrease timer interval over time to speed up selection over time
  614. void CGridCtrl::OnTimer(UINT nIDEvent)
  615. {
  616. ASSERT(nIDEvent == WM_LBUTTONDOWN);
  617. if (nIDEvent != WM_LBUTTONDOWN)
  618. return;
  619. CPoint pt, origPt;
  620. #ifdef _WIN32_WCE
  621. if (m_MouseMode == MOUSE_NOTHING)
  622. return;
  623. origPt = GetMessagePos();
  624. #else
  625. if (!GetCursorPos(&origPt))
  626. return;
  627. #endif
  628. ScreenToClient(&origPt);
  629. CRect rect;
  630. GetClientRect(rect);
  631. int nFixedRowHeight = GetFixedRowHeight();
  632. int nFixedColWidth = GetFixedColumnWidth();
  633. pt = origPt;
  634. if (pt.y > rect.bottom)
  635. {
  636. //SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  637. SendMessage(WM_KEYDOWN, VK_DOWN, 0);
  638. if (pt.x < rect.left)
  639. pt.x = rect.left;
  640. if (pt.x > rect.right)
  641. pt.x = rect.right;
  642. pt.y = rect.bottom;
  643. OnSelecting(GetCellFromPt(pt));
  644. }
  645. else if (pt.y < nFixedRowHeight)
  646. {
  647. //SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  648. SendMessage(WM_KEYDOWN, VK_UP, 0);
  649. if (pt.x < rect.left)
  650. pt.x = rect.left;
  651. if (pt.x > rect.right)
  652. pt.x = rect.right;
  653. pt.y = nFixedRowHeight + 1;
  654. OnSelecting(GetCellFromPt(pt));
  655. }
  656. pt = origPt;
  657. if (pt.x > rect.right)
  658. {
  659. // SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  660. SendMessage(WM_KEYDOWN, VK_RIGHT, 0);
  661. if (pt.y < rect.top)
  662. pt.y = rect.top;
  663. if (pt.y > rect.bottom)
  664. pt.y = rect.bottom;
  665. pt.x = rect.right;
  666. OnSelecting(GetCellFromPt(pt));
  667. }
  668. else if (pt.x < nFixedColWidth)
  669. {
  670. //SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  671. SendMessage(WM_KEYDOWN, VK_LEFT, 0);
  672. if (pt.y < rect.top)
  673. pt.y = rect.top;
  674. if (pt.y > rect.bottom)
  675. pt.y = rect.bottom;
  676. pt.x = nFixedColWidth + 1;
  677. OnSelecting(GetCellFromPt(pt));
  678. }
  679. }
  680. // move about with keyboard
  681. void CGridCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  682. {
  683. if (!IsValid(m_idCurrentCell))
  684. {
  685. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  686. return;
  687. }
  688. CCellID next = m_idCurrentCell;
  689. BOOL bChangeLine = FALSE;
  690. if (IsCTRLpressed())
  691. {
  692. switch (nChar)
  693. {
  694. case 'A': OnEditSelectAll(); break;
  695. #ifndef GRIDCONTROL_NO_CLIPBOARD
  696. case 'X': OnEditCut(); break;
  697. case 'C': OnEditCopy(); break;
  698. case 'V': OnEditPaste(); break;
  699. #endif
  700. }
  701. }
  702. switch (nChar)
  703. {
  704. case VK_DELETE:
  705. if (IsCellEditable(m_idCurrentCell.row, m_idCurrentCell.col))
  706. {
  707. SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_BEGINLABELEDIT);
  708. SetItemText(m_idCurrentCell.row, m_idCurrentCell.col, _T(""));
  709. SetModified(TRUE, m_idCurrentCell.row, m_idCurrentCell.col);
  710. SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_ENDLABELEDIT);
  711. RedrawCell(m_idCurrentCell);
  712. }
  713. break;
  714. case VK_TAB:
  715. if (IsSHIFTpressed())
  716. {
  717. if (next.col > m_nFixedCols)
  718. next.col--;
  719. else if (next.col == m_nFixedCols && next.row > m_nFixedRows)
  720. {
  721. next.row--;
  722. next.col = GetColumnCount() - 1;
  723. bChangeLine = TRUE;
  724. }
  725. else
  726. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  727. }
  728. else
  729. {
  730. if (next.col < (GetColumnCount() - 1))
  731. next.col++;
  732. else if (next.col == (GetColumnCount() - 1) &&
  733. next.row < (GetRowCount() - 1) )
  734. {
  735. next.row++;
  736. next.col = m_nFixedCols;
  737. bChangeLine = TRUE;
  738. }
  739. else
  740. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  741. }
  742. break;
  743. case VK_DOWN:
  744. if (next.row < (GetRowCount() - 1))
  745. next.row++;
  746. break;
  747. case VK_UP:
  748. if (next.row > m_nFixedRows)
  749. next.row--;
  750. break;
  751. case VK_RIGHT:
  752. if (next.col < (GetColumnCount() - 1))
  753. next.col++;
  754. break;
  755. case VK_LEFT:
  756. if (next.col > m_nFixedCols)
  757. next.col--;
  758. break;
  759. case VK_NEXT:
  760. {
  761. CCellID idOldTopLeft = GetTopleftNonFixedCell();
  762. SendMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
  763. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  764. int increment = idNewTopLeft.row - idOldTopLeft.row;
  765. if (increment) {
  766. next.row += increment;
  767. if (next.row > (GetRowCount() - 1))
  768. next.row = GetRowCount() - 1;
  769. }
  770. else
  771. next.row = GetRowCount() - 1;
  772. break;
  773. }
  774. case VK_PRIOR:
  775. {
  776. CCellID idOldTopLeft = GetTopleftNonFixedCell();
  777. SendMessage(WM_VSCROLL, SB_PAGEUP, 0);
  778. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  779. int increment = idNewTopLeft.row - idOldTopLeft.row;
  780. if (increment)
  781. {
  782. next.row += increment;
  783. if (next.row < m_nFixedRows)
  784. next.row = m_nFixedRows;
  785. } else
  786. next.row = m_nFixedRows;
  787. break;
  788. }
  789. case VK_HOME:
  790. SendMessage(WM_VSCROLL, SB_TOP, 0);
  791. next.row = m_nFixedRows;
  792. break;
  793. case VK_END:
  794. SendMessage(WM_VSCROLL, SB_BOTTOM, 0);
  795. next.row = GetRowCount() - 1;
  796. break;
  797. default:
  798. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  799. }
  800. if (next != m_idCurrentCell)
  801. {
  802. // While moving with the Cursorkeys the current ROW/CELL will get selected
  803. // OR Selection will get expanded when SHIFT is pressed
  804. // Cut n paste from OnLButtonDown - Franco Bez
  805. // Added check for NULL mouse mode - Chris Maunder.
  806. if (m_MouseMode == MOUSE_NOTHING)
  807. {
  808. m_PrevSelectedCellMap.RemoveAll();
  809. m_MouseMode = m_bListMode? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
  810. if (!IsSHIFTpressed() || nChar == VK_TAB)
  811. m_SelectionStartCell = next;
  812. OnSelecting(next);
  813. m_MouseMode = MOUSE_NOTHING;
  814. }
  815. SetFocusCell(next);
  816. if (!IsCellVisible(next))
  817. {
  818. EnsureVisible(next); // Make sure cell is visible
  819. switch (nChar) {
  820. case VK_RIGHT:
  821. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  822. break;
  823. case VK_LEFT:
  824. SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  825. break;
  826. case VK_DOWN:
  827. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  828. break;
  829. case VK_UP:
  830. SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  831. break;
  832. case VK_TAB:
  833. if (IsSHIFTpressed())
  834. {
  835. if (bChangeLine)
  836. {
  837. SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  838. SetScrollPos32(SB_HORZ, m_nHScrollMax);
  839. break;
  840. }
  841. else
  842. SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  843. }
  844. else
  845. {
  846. if (bChangeLine)
  847. {
  848. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  849. SetScrollPos32(SB_HORZ, 0);
  850. break;
  851. }
  852. else
  853. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  854. }
  855. break;
  856. }
  857. Invalidate();
  858. }
  859. }
  860. }
  861. // Instant editing of cells when keys are pressed
  862. void CGridCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  863. {
  864. if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING)
  865. {
  866. if (!m_bHandleTabKey || (m_bHandleTabKey && nChar != VK_TAB))
  867. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, nChar);
  868. }
  869. CWnd::OnChar(nChar, nRepCnt, nFlags);
  870. }
  871. // Callback from any CInPlaceEdits that ended. This just calls OnEndEditCell,
  872. // refreshes the edited cell and moves onto next cell if the return character
  873. // from the edit says we should.
  874. void CGridCtrl::OnEndInPlaceEdit(NMHDR* pNMHDR, LRESULT* pResult)
  875. {
  876. GV_DISPINFO *pgvDispInfo = (GV_DISPINFO *)pNMHDR;
  877. GV_ITEM *pgvItem = &pgvDispInfo->item;
  878. // In case OnEndInPlaceEdit called as window is being destroyed
  879. if (!IsWindow(GetSafeHwnd()))
  880. return;
  881. OnEndEditCell(pgvItem->row, pgvItem->col, pgvItem->szText);
  882. InvalidateCellRect(CCellID(pgvItem->row, pgvItem->col));
  883. SendMessageToParent(pgvItem->row, pgvItem->col, GVN_ENDLABELEDIT);
  884. switch (pgvItem->lParam)
  885. {
  886. case VK_TAB:
  887. case VK_DOWN:
  888. case VK_UP:
  889. case VK_RIGHT:
  890. case VK_LEFT:
  891. case VK_NEXT:
  892. case VK_PRIOR:
  893. case VK_HOME:
  894. case VK_END:
  895. OnKeyDown(pgvItem->lParam, 0, 0);
  896. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, pgvItem->lParam);
  897. }
  898. *pResult = 0;
  899. }
  900. // Handle horz scrollbar notifications
  901. void CGridCtrl::OnHScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
  902. {
  903. if (GetFocus()->GetSafeHwnd() != GetSafeHwnd())
  904. SetFocus(); // Auto-destroy any InPlaceEdit's
  905. #ifndef GRIDCONTROL_NO_TITLETIPS
  906. // m_TitleTip.Hide(); // hide any titletips
  907. #endif
  908. int scrollPos = GetScrollPos32(SB_HORZ);
  909. CCellID idTopLeft = GetTopleftNonFixedCell();
  910. CRect rect;
  911. GetClientRect(rect);
  912. switch (nSBCode)
  913. {
  914. case SB_LINERIGHT:
  915. if (scrollPos < m_nHScrollMax)
  916. {
  917. int xScroll = GetColumnWidth(idTopLeft.col);
  918. SetScrollPos32(SB_HORZ, scrollPos + xScroll);
  919. if (GetScrollPos32(SB_HORZ) == scrollPos) break; // didn't work
  920. rect.left = GetFixedColumnWidth() + xScroll;
  921. ScrollWindow(-xScroll, 0, rect);
  922. rect.left = rect.right - xScroll;
  923. InvalidateRect(rect);
  924. }
  925. break;
  926. case SB_LINELEFT:
  927. if (scrollPos > 0 && idTopLeft.col > GetFixedColumnCount())
  928. {
  929. int xScroll = GetColumnWidth(idTopLeft.col-1);
  930. SetScrollPos32(SB_HORZ, max(0,scrollPos - xScroll));
  931. rect.left = GetFixedColumnWidth();
  932. ScrollWindow(xScroll, 0, rect);
  933. rect.right = rect.left + xScroll;
  934. InvalidateRect(rect);
  935. }
  936. break;
  937. case SB_PAGERIGHT:
  938. if (scrollPos < m_nHScrollMax)
  939. {
  940. rect.left = GetFixedColumnWidth();
  941. int offset = rect.Width();
  942. int pos = min(m_nHScrollMax, scrollPos + offset);
  943. SetScrollPos32(SB_HORZ, pos);
  944. rect.left = GetFixedColumnWidth();
  945. InvalidateRect(rect);
  946. }
  947. break;
  948. case SB_PAGELEFT:
  949. if (scrollPos > 0)
  950. {
  951. rect.left = GetFixedColumnWidth();
  952. int offset = -rect.Width();
  953. int pos = max(0, scrollPos + offset);
  954. SetScrollPos32(SB_HORZ, pos);
  955. rect.left = GetFixedColumnWidth();
  956. InvalidateRect(rect);
  957. }
  958. break;
  959. case SB_THUMBPOSITION:
  960. case SB_THUMBTRACK:
  961. {
  962. SetScrollPos32(SB_HORZ, GetScrollPos32(SB_HORZ, TRUE));
  963. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  964. if (idNewTopLeft != idTopLeft)
  965. {
  966. rect.left = GetFixedColumnWidth();
  967. InvalidateRect(rect);
  968. }
  969. }
  970. break;
  971. case SB_LEFT:
  972. if (scrollPos > 0)
  973. {
  974. SetScrollPos32(SB_HORZ, 0);
  975. Invalidate();
  976. }
  977. break;
  978. case SB_RIGHT:
  979. if (scrollPos < m_nHScrollMax)
  980. {
  981. SetScrollPos32(SB_HORZ, m_nHScrollMax);
  982. Invalidate();
  983. }
  984. break;
  985. default: break;
  986. }
  987. }
  988. // Handle vert scrollbar notifications
  989. void CGridCtrl::OnVScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
  990. {
  991. if (GetFocus()->GetSafeHwnd() != GetSafeHwnd())
  992. SetFocus(); // Auto-destroy any InPlaceEdit's
  993. #ifndef GRIDCONTROL_NO_TITLETIPS
  994. // m_TitleTip.Hide(); // hide any titletips
  995. #endif
  996. // Get the scroll position ourselves to ensure we get a 32 bit value
  997. int scrollPos = GetScrollPos32(SB_VERT);
  998. CCellID idTopLeft = GetTopleftNonFixedCell();
  999. CRect rect;
  1000. GetClientRect(rect);
  1001. switch (nSBCode)
  1002. {
  1003. case SB_LINEDOWN:
  1004. if (scrollPos < m_nVScrollMax)
  1005. {
  1006. int yScroll = GetRowHeight(idTopLeft.row);
  1007. SetScrollPos32(SB_VERT, scrollPos + yScroll);
  1008. if (GetScrollPos32(SB_VERT) == scrollPos)
  1009. break; // didn't work
  1010. rect.top = GetFixedRowHeight() + yScroll;
  1011. ScrollWindow( 0, -yScroll, rect);
  1012. rect.top = rect.bottom - yScroll;
  1013. InvalidateRect(rect);
  1014. }
  1015. break;
  1016. case SB_LINEUP:
  1017. if (scrollPos > 0 && idTopLeft.row > GetFixedRowCount())
  1018. {
  1019. int yScroll = GetRowHeight(idTopLeft.row-1);
  1020. SetScrollPos32(SB_VERT, max(0, scrollPos - yScroll));
  1021. rect.top = GetFixedRowHeight();
  1022. ScrollWindow(0, yScroll, rect);
  1023. rect.bottom = rect.top + yScroll;
  1024. InvalidateRect(rect);
  1025. }
  1026. break;
  1027. case SB_PAGEDOWN:
  1028. if (scrollPos < m_nVScrollMax)
  1029. {
  1030. rect.top = GetFixedRowHeight();
  1031. scrollPos = min(m_nVScrollMax, scrollPos + rect.Height());
  1032. SetScrollPos32(SB_VERT, scrollPos);
  1033. rect.top = GetFixedRowHeight();
  1034. InvalidateRect(rect);
  1035. }
  1036. break;
  1037. case SB_PAGEUP:
  1038. if (scrollPos > 0)
  1039. {
  1040. rect.top = GetFixedRowHeight();
  1041. int offset = -rect.Height();
  1042. int pos = max(0, scrollPos + offset);
  1043. SetScrollPos32(SB_VERT, pos);
  1044. rect.top = GetFixedRowHeight();
  1045. InvalidateRect(rect);
  1046. }
  1047. break;
  1048. case SB_THUMBPOSITION:
  1049. case SB_THUMBTRACK:
  1050. {
  1051. SetScrollPos32(SB_VERT, GetScrollPos32(SB_VERT, TRUE));
  1052. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  1053. if (idNewTopLeft != idTopLeft)
  1054. {
  1055. rect.top = GetFixedRowHeight();
  1056. InvalidateRect(rect);
  1057. }
  1058. }
  1059. break;
  1060. case SB_TOP:
  1061. if (scrollPos > 0)
  1062. {
  1063. SetScrollPos32(SB_VERT, 0);
  1064. Invalidate();
  1065. }
  1066. break;
  1067. case SB_BOTTOM:
  1068. if (scrollPos < m_nVScrollMax)
  1069. {
  1070. SetScrollPos32(SB_VERT, m_nVScrollMax);
  1071. Invalidate();
  1072. }
  1073. default: break;
  1074. }
  1075. }
  1076. /////////////////////////////////////////////////////////////////////////////
  1077. // CGridCtrl implementation functions
  1078. void CGridCtrl::OnDraw(CDC* pDC)
  1079. {
  1080. CRect rect;
  1081. int row,col;
  1082. CRect clipRect;
  1083. if (pDC->GetClipBox(&clipRect) == ERROR)
  1084. return;
  1085. EraseBkgnd(pDC); // OnEraseBkgnd does nothing, so erase bkgnd here.
  1086. // This necessary since we may be using a Memory DC.
  1087. int nFixedRowHeight = GetFixedRowHeight();
  1088. int nFixedColWidth = GetFixedColumnWidth();
  1089. CCellID idTopLeft = GetTopleftNonFixedCell();
  1090. int minVisibleRow = idTopLeft.row,
  1091. minVisibleCol = idTopLeft.col;
  1092. CRect VisRect;
  1093. CCellRange VisCellRange = GetVisibleNonFixedCellRange(VisRect);
  1094. int maxVisibleRow = VisCellRange.GetMaxRow(),
  1095. maxVisibleCol = VisCellRange.GetMaxCol();
  1096. // draw top-left cells 0..m_nFixedRows-1, 0..m_nFixedCols-1
  1097. rect.bottom = -1;
  1098. for (row = 0; row < m_nFixedRows; row++)
  1099. {
  1100. rect.top = rect.bottom+1;
  1101. rect.bottom = rect.top + GetRowHeight(row)-1;
  1102. rect.right = -1;
  1103. for (col = 0; col < m_nFixedCols; col++)
  1104. {
  1105. rect.left = rect.right+1;
  1106. rect.right = rect.left + GetColumnWidth(col)-1;
  1107. DrawFixedCell(pDC, row, col, rect);
  1108. }
  1109. }
  1110. // draw fixed column cells: m_nFixedRows..n, 0..m_nFixedCols-1
  1111. rect.bottom = nFixedRowHeight-1;
  1112. for (row = minVisibleRow; row <= maxVisibleRow; row++)
  1113. {
  1114. rect.top = rect.bottom+1;
  1115. rect.bottom = rect.top + GetRowHeight(row)-1;
  1116. // rect.bottom = bottom pixel of previous row
  1117. if (rect.top > clipRect.bottom)
  1118. break; // Gone past cliprect
  1119. if (rect.bottom < clipRect.top)
  1120. continue; // Reached cliprect yet?
  1121. rect.right = -1;
  1122. for (col = 0; col < m_nFixedCols; col++)
  1123. {
  1124. rect.left = rect.right+1;
  1125. rect.right = rect.left + GetColumnWidth(col)-1;
  1126. if (rect.left > clipRect.right)
  1127. break; // gone past cliprect
  1128. if (rect.right < clipRect.left)
  1129. continue; // Reached cliprect yet?
  1130. DrawFixedCell(pDC, row, col, rect);
  1131. }
  1132. }
  1133. // draw fixed row cells 0..m_nFixedRows, m_nFixedCols..n
  1134. rect.bottom = -1;
  1135. for (row = 0; row < m_nFixedRows; row++)
  1136. {
  1137. rect.top = rect.bottom+1;
  1138. rect.bottom = rect.top + GetRowHeight(row)-1;
  1139. // rect.bottom = bottom pixel of previous row
  1140. if (rect.top > clipRect.bottom)
  1141. break; // Gone past cliprect
  1142. if (rect.bottom < clipRect.top)
  1143. continue; // Reached cliprect yet?
  1144. rect.right = nFixedColWidth-1;
  1145. for (col = minVisibleCol; col <= maxVisibleCol; col++)
  1146. {
  1147. rect.left = rect.right+1;
  1148. rect.right = rect.left + GetColumnWidth(col)-1;
  1149. if (rect.left > clipRect.right)
  1150. break; // gone past cliprect
  1151. if (rect.right < clipRect.left)
  1152. continue; // Reached cliprect yet?
  1153. DrawFixedCell(pDC, row, col, rect);
  1154. }
  1155. }
  1156. // draw rest of non-fixed cells
  1157. rect.bottom = nFixedRowHeight-1;
  1158. for (row = minVisibleRow; row <= maxVisibleRow; row++)
  1159. {
  1160. rect.top = rect.bottom+1;
  1161. rect.bottom = rect.top + GetRowHeight(row)-1;
  1162. // rect.bottom = bottom pixel of previous row
  1163. if (rect.top > clipRect.bottom)
  1164. break; // Gone past cliprect
  1165. if (rect.bottom < clipRect.top)
  1166. continue; // Reached cliprect yet?
  1167. rect.right = nFixedColWidth-1;
  1168. for (col = minVisibleCol; col <= maxVisibleCol; col++)
  1169. {
  1170. rect.left = rect.right+1;
  1171. rect.right = rect.left + GetColumnWidth(col)-1;
  1172. if (rect.left > clipRect.right)
  1173. break; // gone past cliprect
  1174. if (rect.right < clipRect.left)
  1175. continue; // Reached cliprect yet?
  1176. DrawCell(pDC, row, col, rect);
  1177. }
  1178. }
  1179. CPen pen;
  1180. TRY {
  1181. pen.CreatePen(PS_SOLID, 0, m_crGridColour);
  1182. }
  1183. CATCH (CResourceException, e)
  1184. {
  1185. e->Delete();
  1186. return;
  1187. }
  1188. END_CATCH
  1189. pDC->SelectObject(&pen);
  1190. // draw vertical lines (drawn at ends of cells)
  1191. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  1192. {
  1193. int x = nFixedColWidth;
  1194. for (col = minVisibleCol; col <= maxVisibleCol; col++) {
  1195. x += GetColumnWidth(col);
  1196. pDC->MoveTo(x-1, nFixedRowHeight);
  1197. pDC->LineTo(x-1, VisRect.bottom);
  1198. }
  1199. }
  1200. // draw horizontal lines (drawn at bottom of each cell)
  1201. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  1202. {
  1203. int y = nFixedRowHeight;
  1204. for (row = minVisibleRow; row <= maxVisibleRow; row++) {
  1205. y += GetRowHeight(row);
  1206. pDC->MoveTo(nFixedColWidth, y-1);
  1207. pDC->LineTo(VisRect.right, y-1);
  1208. }
  1209. }
  1210. pDC->SelectStockObject(NULL_PEN);
  1211. #ifdef USE_MEMDC // Use a memDC for flicker free update
  1212. }
  1213. #else // Use normal DC - this helps in debugging
  1214. }
  1215. #endif
  1216. ////////////////////////////////////////////////////////////////////////////////////////
  1217. // CGridCtrl Cell selection stuff
  1218. BOOL CGridCtrl::IsValid(int nRow, int nCol) const
  1219. {
  1220. return (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols);
  1221. }
  1222. BOOL CGridCtrl::IsValid(const CCellID& cell) const
  1223. {
  1224. return IsValid(cell.row, cell.col);
  1225. }
  1226. BOOL CGridCtrl::IsValid(const CCellRange& range) const
  1227. {
  1228. return (range.GetMinRow() >= 0 && range.GetMinCol() >= 0 &&
  1229. range.GetMaxRow() >= 0 && range.GetMaxCol() >= 0 &&
  1230. range.GetMaxRow() < m_nRows && range.GetMaxCol() < m_nCols &&
  1231. range.GetMinRow() <= range.GetMaxRow() && range.GetMinCol() <= range.GetMaxCol());
  1232. }
  1233. // Enables/Disables redraw for certain operations like columns auto-sizing etc,
  1234. // but not for user caused things such as selection changes.
  1235. void CGridCtrl::SetRedraw(BOOL bAllowDraw, BOOL bResetScrollBars /* = FALSE */)
  1236. {
  1237. TRACE(_T("%s: Setting redraw to %s\n"),
  1238. GetRuntimeClass()->m_lpszClassName, bAllowDraw? _T("TRUE") : _T("FALSE"));
  1239. if (bAllowDraw && !m_bAllowDraw)
  1240. Invalidate();
  1241. m_bAllowDraw = bAllowDraw;
  1242. if (bResetScrollBars)
  1243. ResetScrollBars();
  1244. }
  1245. // Forces a redraw of a cell immediately (using a direct DC construction,
  1246. // or the supplied dc)
  1247. BOOL CGridCtrl::RedrawCell(const CCellID& cell, CDC* pDC /* = NULL */)
  1248. {
  1249. return RedrawCell(cell.row, cell.col, pDC);
  1250. }
  1251. BOOL CGridCtrl::RedrawCell(int nRow, int nCol, CDC* pDC /* = NULL */)
  1252. {
  1253. BOOL bResult = TRUE;
  1254. BOOL bMustReleaseDC = FALSE;
  1255. if (!m_bAllowDraw || !IsCellVisible(nRow, nCol))
  1256. return FALSE;
  1257. CRect rect;
  1258. if (!GetCellRect(nRow, nCol, rect))
  1259. return FALSE;
  1260. if (!pDC) {
  1261. pDC = GetDC();
  1262. if (pDC)
  1263. bMustReleaseDC = TRUE;
  1264. }
  1265. if (pDC)
  1266. {
  1267. // Redraw cells directly
  1268. if (nRow < m_nFixedRows || nCol < m_nFixedCols)
  1269. {
  1270. bResult = DrawFixedCell(pDC, nRow, nCol, rect, TRUE);
  1271. }
  1272. else
  1273. {
  1274. bResult = DrawCell(pDC, nRow, nCol, rect, TRUE);
  1275. // Since we have erased the background, we will need to redraw the gridlines
  1276. CPen pen;
  1277. TRY {
  1278. pen.CreatePen(PS_SOLID, 0, m_crGridColour);
  1279. } CATCH (CException, e) {e->Delete();} END_CATCH
  1280. CPen* pOldPen = (CPen*) pDC->SelectObject(&pen);
  1281. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  1282. {
  1283. pDC->MoveTo(rect.left, rect.bottom);
  1284. pDC->LineTo(rect.right+1, rect.bottom);
  1285. }
  1286. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  1287. {
  1288. pDC->MoveTo(rect.right, rect.top);
  1289. pDC->LineTo(rect.right, rect.bottom+1);
  1290. }
  1291. pDC->SelectObject(pOldPen);
  1292. }
  1293. } else
  1294. InvalidateRect(rect, TRUE); // Could not get a DC - invalidate it anyway
  1295. // and hope that OnPaint manages to get one
  1296. if (bMustReleaseDC)
  1297. ReleaseDC(pDC);
  1298. return bResult;
  1299. }
  1300. // redraw a complete row
  1301. BOOL CGridCtrl::RedrawRow(int row)
  1302. {
  1303. BOOL bResult = TRUE;
  1304. CDC* pDC = GetDC();
  1305. for (int col = 0; col < GetColumnCount(); col++)
  1306. bResult = RedrawCell(row, col, pDC) && bResult;
  1307. if (pDC)
  1308. ReleaseDC(pDC);
  1309. return bResult;
  1310. }
  1311. // redraw a complete column
  1312. BOOL CGridCtrl::RedrawColumn(int col)
  1313. {
  1314. BOOL bResult = TRUE;
  1315. CDC* pDC = GetDC();
  1316. for (int row = 0; row < GetRowCount(); row++)
  1317. bResult = RedrawCell(row, col, pDC) && bResult;
  1318. if (pDC)
  1319. ReleaseDC(pDC);
  1320. return bResult;
  1321. }
  1322. // Sets the currently selected cell, returning the previous current cell
  1323. CCellID CGridCtrl::SetFocusCell(int nRow, int nCol)
  1324. {
  1325. return SetFocusCell(CCellID(nRow, nCol));
  1326. }
  1327. CCellID CGridCtrl::SetFocusCell(CCellID cell)
  1328. {
  1329. if (cell == m_idCurrentCell)
  1330. return m_idCurrentCell;
  1331. CCellID idPrev = m_idCurrentCell;
  1332. m_idCurrentCell = cell;
  1333. if (IsValid(idPrev))
  1334. {
  1335. SendMessageToParent(idPrev.row, idPrev.col, GVN_SELCHANGING);
  1336. SetItemState(idPrev.row, idPrev.col,
  1337. GetItemState(idPrev.row, idPrev.col) & ~GVIS_FOCUSED);
  1338. RedrawCell(idPrev);
  1339. if (idPrev.col != m_idCurrentCell.col)
  1340. for (int row = 0; row < m_nFixedRows; row++)
  1341. RedrawCell(row, idPrev.col);
  1342. if (idPrev.row != m_idCurrentCell.row)
  1343. for (int col = 0; col < m_nFixedCols; col++)
  1344. RedrawCell(idPrev.row, col);
  1345. }
  1346. if (IsValid(m_idCurrentCell)) {
  1347. SetItemState(m_idCurrentCell.row, m_idCurrentCell.col,
  1348. GetItemState(m_idCurrentCell.row, m_idCurrentCell.col) | GVIS_FOCUSED);
  1349. RedrawCell(m_idCurrentCell);
  1350. if (idPrev.col != m_idCurrentCell.col)
  1351. for (int row = 0; row < m_nFixedRows; row++)
  1352. RedrawCell(row, m_idCurrentCell.col);
  1353. if (idPrev.row != m_idCurrentCell.row)
  1354. for (int col = 0; col < m_nFixedCols; col++)
  1355. RedrawCell(m_idCurrentCell.row, col);
  1356. SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
  1357. }
  1358. return idPrev;
  1359. }
  1360. // Sets the range of currently selected cells
  1361. void CGridCtrl::SetSelectedRange(const CCellRange& Range,
  1362. BOOL bForceRepaint /* = FALSE */)
  1363. {
  1364. SetSelectedRange(Range.GetMinRow(), Range.GetMinCol(),
  1365. Range.GetMaxRow(), Range.GetMaxCol(),
  1366. bForceRepaint);
  1367. }
  1368. void CGridCtrl::SetSelectedRange(int nMinRow, int nMinCol, int nMaxRow, int nMaxCol,
  1369. BOOL bForceRepaint /* = FALSE */)
  1370. {
  1371. if (!m_bEnableSelection) return;
  1372. CDC* pDC = NULL;
  1373. if (bForceRepaint) pDC = GetDC();
  1374. // Unselect all previously selected cells
  1375. for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
  1376. {
  1377. DWORD key;
  1378. CCellID cell;
  1379. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  1380. // Reset the selection flag on the cell
  1381. if (IsValid(cell)) {
  1382. SetItemState(cell.row, cell.col,
  1383. GetItemState(cell.row, cell.col) & ~GVIS_SELECTED);
  1384. // If this is to be reselected, continue on past the redraw
  1385. if (nMinRow <= cell.row && cell.row <= nMaxRow &&
  1386. nMinCol <= cell.col && cell.col <= nMaxCol)
  1387. continue;
  1388. if (bForceRepaint && pDC) // Redraw NOW
  1389. RedrawCell(cell.row, cell.col, pDC);
  1390. else
  1391. InvalidateCellRect(cell); // Redraw at leisure
  1392. }
  1393. }
  1394. // if any previous selected cells are to be retained (eg Ctrl is being held down)
  1395. // then copy them to the newly created list, and mark all these cells as
  1396. // selected
  1397. if (!GetSingleRowSelection())
  1398. for (POSITION pos = m_PrevSelectedCellMap.GetStartPosition(); pos != NULL; /* nothing */)
  1399. {
  1400. DWORD key;
  1401. CCellID cell;
  1402. m_PrevSelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  1403. if (!IsValid(cell))
  1404. continue;
  1405. int nState = GetItemState(cell.row, cell.col);
  1406. // Set state as Selected. This will add the cell to m_SelectedCells[]
  1407. SetItemState(cell.row, cell.col, nState | GVIS_SELECTED);
  1408. // Redraw (immediately or at leisure)
  1409. if (bForceRepaint && pDC)
  1410. RedrawCell(cell.row, cell.col, pDC);
  1411. else
  1412. InvalidateCellRect(cell);
  1413. }
  1414. // Now select all cells in the cell range specified. If the cell has already
  1415. // been marked as selected (above) then ignore it.
  1416. if (nMinRow >= 0 && nMinCol >= 0 && nMaxRow >= 0 && nMaxCol >= 0 &&
  1417. nMaxRow < m_nRows && nMaxCol < m_nCols &&
  1418. nMinRow <= nMaxRow && nMinCol <= nMaxCol)
  1419. {
  1420. for (int row = nMinRow; row <= nMaxRow; row++)
  1421. for (int col = nMinCol; col <= nMaxCol; col++)
  1422. {
  1423. int nState = GetItemState(row, col);
  1424. if (nState & GVIS_SELECTED)
  1425. continue; // Already selected - ignore
  1426. // Add to list of selected cells
  1427. CCellID cell(row, col);
  1428. // Set state as Selected. This will add the cell to m_SelectedCells[]
  1429. SetItemState(row, col, nState | GVIS_SELECTED);
  1430. // Redraw (immediately or at leisure)
  1431. if (bForceRepaint && pDC)
  1432. RedrawCell(row, col, pDC);
  1433. else
  1434. InvalidateCellRect(cell);
  1435. }
  1436. }
  1437. // TRACE(_T("%d cells selected.\n"), m_SelectedCellMap.GetCount());
  1438. if (pDC != NULL)
  1439. ReleaseDC(pDC);
  1440. }
  1441. // selects all cells
  1442. void CGridCtrl::SelectAllCells()
  1443. {
  1444. if (!m_bEnableSelection)
  1445. return;
  1446. SetSelectedRange(m_nFixedRows, m_nFixedCols, GetRowCount()-1, GetColumnCount()-1);
  1447. }
  1448. // selects columns
  1449. void CGridCtrl::SelectColumns(CCellID currentCell)
  1450. {
  1451. if (!m_bEnableSelection)
  1452. return;
  1453. //if (currentCell.col == m_idCurrentCell.col) return;
  1454. if (currentCell.col < m_nFixedCols)
  1455. return;
  1456. if (!IsValid(currentCell))
  1457. return;
  1458. SetSelectedRange(GetFixedRowCount(),
  1459. min(m_SelectionStartCell.col, currentCell.col),
  1460. GetRowCount()-1,
  1461. max(m_SelectionStartCell.col, currentCell.col));
  1462. }
  1463. // selects rows
  1464. void CGridCtrl::SelectRows(CCellID currentCell)
  1465. {
  1466. if (!m_bEnableSelection)
  1467. return;
  1468. //if (currentCell.row; == m_idCurrentCell.row) return;
  1469. if (currentCell.row < m_nFixedRows)
  1470. return;
  1471. if (!IsValid(currentCell))
  1472. return;
  1473. if (GetListMode() && GetSingleRowSelection())
  1474. SetSelectedRange(currentCell.row, GetFixedColumnCount(),
  1475. currentCell.row, GetColumnCount()-1);
  1476. else
  1477. SetSelectedRange(min(m_SelectionStartCell.row, currentCell.row),
  1478. GetFixedColumnCount(),
  1479. max(m_SelectionStartCell.row, currentCell.row),
  1480. GetColumnCount()-1);
  1481. }
  1482. // selects cells
  1483. void CGridCtrl::SelectCells(CCellID currentCell)
  1484. {
  1485. if (!m_bEnableSelection)
  1486. return;
  1487. int row = currentCell.row;
  1488. int col = currentCell.col;
  1489. if (row < m_nFixedRows || col < m_nFixedCols)
  1490. return;
  1491. if (!IsValid(currentCell))
  1492. return;
  1493. // Prevent unnecessary redraws
  1494. //if (currentCell == m_LeftClickDownCell) return;
  1495. //else if (currentCell == m_idCurrentCell) return;
  1496. SetSelectedRange(min(m_SelectionStartCell.row, row),
  1497. min(m_SelectionStartCell.col, col),
  1498. max(m_SelectionStartCell.row, row),
  1499. max(m_SelectionStartCell.col, col));
  1500. }
  1501. void CGridCtrl::OnSelecting(const CCellID& currentCell)
  1502. {
  1503. if (!m_bEnableSelection)
  1504. return;
  1505. switch(m_MouseMode)
  1506. {
  1507. case MOUSE_SELECT_ALL: SelectAllCells(); break;
  1508. case MOUSE_SELECT_COL: SelectColumns(currentCell); break;
  1509. case MOUSE_SELECT_ROW: SelectRows(currentCell); break;
  1510. case MOUSE_SELECT_CELLS: SelectCells(currentCell); break;
  1511. }
  1512. }
  1513. #ifndef GRIDCONTROL_NO_CLIPBOARD
  1514. ////////////////////////////////////////////////////////////////////////////////////////
  1515. // Clipboard functions
  1516. void CGridCtrl::CutSelectedText()
  1517. {
  1518. if (!IsEditable())
  1519. return;
  1520. // Clear contents of selected cells.
  1521. for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
  1522. {
  1523. DWORD key;
  1524. CCellID cell;
  1525. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  1526. if (!IsCellEditable(cell))
  1527. continue;
  1528. CGridCell* pCell = GetCell(cell.row, cell.col);
  1529. if (pCell)
  1530. {
  1531. SendMessageToParent(cell.row, cell.col, GVN_BEGINLABELEDIT);
  1532. EmptyCell(pCell, cell.row, cell.col);
  1533. SetModified(TRUE, cell.row, cell.col);
  1534. SendMessageToParent(cell.row, cell.col, GVN_ENDLABELEDIT);
  1535. }
  1536. }
  1537. Invalidate();
  1538. }
  1539. COleDataSource* CGridCtrl::CopyTextFromGrid()
  1540. {
  1541. USES_CONVERSION;
  1542. CCellRange Selection = GetSelectedCellRange();
  1543. if (!IsValid(Selection)) return NULL;
  1544. // Write to shared file (REMEBER: CF_TEXT is ANSI, not UNICODE, so we need to convert)
  1545. CSharedFile sf(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT);
  1546. // Get a tab delimited string to copy to cache
  1547. CString str;
  1548. CGridCell *pCell;
  1549. for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
  1550. {
  1551. str.Empty();
  1552. for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
  1553. {
  1554. pCell = GetCell(row,col);
  1555. if (pCell && (pCell->state & GVIS_SELECTED))
  1556. {
  1557. if (pCell->szText.IsEmpty())
  1558. str += _T(" ");
  1559. else
  1560. str += pCell->szText;
  1561. }
  1562. if (col != Selection.GetMaxCol())
  1563. str += _T("\t");
  1564. }
  1565. if (row != Selection.GetMaxRow())
  1566. str += _T("\n");
  1567. sf.Write(T2A(str.GetBuffer(1)), str.GetLength());
  1568. str.ReleaseBuffer();
  1569. }
  1570. char c = '\0';
  1571. sf.Write(&c, 1);
  1572. DWORD dwLen = (DWORD)sf.GetLength();
  1573. HGLOBAL hMem = sf.Detach();
  1574. if (!hMem)
  1575. return NULL;
  1576. hMem = ::GlobalReAlloc(hMem, dwLen, GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT);
  1577. if (!hMem)
  1578. return NULL;
  1579. // Cache data
  1580. COleDataSource* pSource = new COleDataSource();
  1581. pSource->CacheGlobalData(CF_TEXT, hMem);
  1582. return pSource;
  1583. }
  1584. BOOL CGridCtrl::PasteTextToGrid(CCellID cell, COleDataObject* pDataObject)
  1585. {
  1586. if (!IsValid(cell) || !IsCellEditable(cell) || !pDataObject->IsDataAvailable(CF_TEXT))
  1587. return FALSE;
  1588. // Get the text from the COleDataObject
  1589. HGLOBAL hmem = pDataObject->GetGlobalData(CF_TEXT);
  1590. CMemFile sf((BYTE*) ::GlobalLock(hmem), ::GlobalSize(hmem));
  1591. // CF_TEXT is ANSI text, so we need to allocate a char* buffer
  1592. // to hold this.
  1593. LPSTR szBuffer = new char[::GlobalSize(hmem)];
  1594. if (!szBuffer)
  1595. return FALSE;
  1596. sf.Read(szBuffer, ::GlobalSize(hmem));
  1597. ::GlobalUnlock(hmem);
  1598. // Now store in generic TCHAR form so we no longer have to deal with
  1599. // ANSI/UNICODE problems
  1600. CString strText = szBuffer;
  1601. delete szBuffer;
  1602. // Parse text data and set in cells...
  1603. strText.LockBuffer();
  1604. CString strLine = strText;
  1605. int nLine = 0;
  1606. // Find the end of the first line
  1607. int nIndex;
  1608. do {
  1609. int nColumn = 0;
  1610. nIndex = strLine.Find(_T("\n"));
  1611. // Store the remaining chars after the newline
  1612. CString strNext = (nIndex < 0)? _T("") : strLine.Mid(nIndex+1);
  1613. // Remove all chars after the newline
  1614. if (nIndex >= 0)
  1615. strLine = strLine.Left(nIndex);
  1616. // Make blank entries a "space"
  1617. if (strLine.IsEmpty() && nIndex >= 0)
  1618. strLine = _T(" ");
  1619. LPTSTR szLine = strLine.GetBuffer(1);
  1620. // Break the current line into tokens (tab or comma delimited)
  1621. LPTSTR pszCellText = _tcstok(szLine, _T("\t,\n"));
  1622. while (pszCellText != NULL)
  1623. {
  1624. CCellID TargetCell(cell.row + nLine, cell.col + nColumn);
  1625. if (IsValid(TargetCell))
  1626. {
  1627. CString strCellText = pszCellText;
  1628. strCellText.TrimLeft(); strCellText.TrimRight();
  1629. SendMessageToParent(TargetCell.row, TargetCell.col, GVN_BEGINLABELEDIT);
  1630. SetItemText(TargetCell.row, TargetCell.col, strCellText);
  1631. SetModified(TRUE, TargetCell.row, TargetCell.col);
  1632. SendMessageToParent(TargetCell.row, TargetCell.col, GVN_ENDLABELEDIT);
  1633. // Make sure cell is not selected to avoid data loss
  1634. SetItemState(TargetCell.row, TargetCell.col,
  1635. GetItemState(TargetCell.row, TargetCell.col) & ~GVIS_SELECTED);
  1636. }
  1637. pszCellText = _tcstok(NULL, _T("\t,\n"));
  1638. nColumn++;
  1639. }
  1640. strLine.ReleaseBuffer();
  1641. strLine = strNext;
  1642. nLine++;
  1643. } while (nIndex >= 0);
  1644. strText.UnlockBuffer();
  1645. Invalidate();
  1646. return TRUE;
  1647. }
  1648. #endif
  1649. #ifndef GRIDCONTROL_NO_DRAGDROP
  1650. void CGridCtrl::OnBeginDrag()
  1651. {
  1652. if (!m_bAllowDragAndDrop) return;
  1653. COleDataSource* pSource = CopyTextFromGrid();
  1654. if (pSource)
  1655. {
  1656. SendMessageToParent(GetSelectedCellRange().GetTopLeft().row,
  1657. GetSelectedCellRange().GetTopLeft().col,
  1658. GVN_BEGINDRAG);
  1659. m_MouseMode = MOUSE_DRAGGING;
  1660. DROPEFFECT dropEffect = pSource->DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE);
  1661. if (dropEffect & DROPEFFECT_MOVE)
  1662. CutSelectedText();
  1663. if (pSource)
  1664. delete pSource; // Did not pass source to clipboard, so must delete
  1665. }
  1666. }
  1667. DROPEFFECT CGridCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState,
  1668. CPoint point)
  1669. {
  1670. // Any text data available for us?
  1671. if (!m_bAllowDragAndDrop || !IsEditable() || !pDataObject->IsDataAvailable(CF_TEXT))
  1672. return DROPEFFECT_NONE;
  1673. // Find which cell we are over and drop-highlight it
  1674. CCellID cell = GetCellFromPt(point, FALSE);
  1675. // If not valid, set the previously drop-highlighted cell as no longer drop-highlighted
  1676. if (!IsValid(cell))
  1677. {
  1678. OnDragLeave();
  1679. m_LastDragOverCell = CCellID(-1,-1);
  1680. return DROPEFFECT_NONE;
  1681. }
  1682. if (!IsCellEditable(cell))
  1683. return DROPEFFECT_NONE;
  1684. // Have we moved over a different cell than last time?
  1685. if (cell != m_LastDragOverCell)
  1686. {
  1687. // Set the previously drop-highlighted cell as no longer drop-highlighted
  1688. if (IsValid(m_LastDragOverCell)) {
  1689. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  1690. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  1691. nState & ~GVIS_DROPHILITED);
  1692. RedrawCell(m_LastDragOverCell);
  1693. }
  1694. m_LastDragOverCell = cell;
  1695. // Set the new cell as drop-highlighted
  1696. if (IsValid(m_LastDragOverCell)) {
  1697. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  1698. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  1699. nState | GVIS_DROPHILITED);
  1700. RedrawCell(m_LastDragOverCell);
  1701. }
  1702. }
  1703. // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
  1704. if (dwKeyState & MK_CONTROL)
  1705. return DROPEFFECT_COPY;
  1706. else
  1707. return DROPEFFECT_MOVE;
  1708. }
  1709. DROPEFFECT CGridCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState,
  1710. CPoint point)
  1711. {
  1712. // Any text data available for us?
  1713. if (!m_bAllowDragAndDrop || !pDataObject->IsDataAvailable(CF_TEXT))
  1714. return DROPEFFECT_NONE;
  1715. // Find which cell we are over and drop-highlight it
  1716. m_LastDragOverCell = GetCellFromPt(point, FALSE);
  1717. if (!IsValid(m_LastDragOverCell))
  1718. return DROPEFFECT_NONE;
  1719. if (!IsCellEditable(m_LastDragOverCell))
  1720. return DROPEFFECT_NONE;
  1721. if (IsValid(m_LastDragOverCell))
  1722. {
  1723. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  1724. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  1725. nState | GVIS_DROPHILITED);
  1726. RedrawCell(m_LastDragOverCell);
  1727. }
  1728. // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
  1729. if (dwKeyState & MK_CONTROL)
  1730. return DROPEFFECT_COPY;
  1731. else
  1732. return DROPEFFECT_MOVE;
  1733. }
  1734. void CGridCtrl::OnDragLeave()
  1735. {
  1736. // Set the previously drop-highlighted cell as no longer drop-highlighted
  1737. if (IsValid(m_LastDragOverCell)) {
  1738. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  1739. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  1740. nState & ~GVIS_DROPHILITED);
  1741. RedrawCell(m_LastDragOverCell);
  1742. }
  1743. }
  1744. BOOL CGridCtrl::OnDrop(COleDataObject* pDataObject, DROPEFFECT /*dropEffect*/,
  1745. CPoint /* point */)
  1746. {
  1747. BOOL bResult = FALSE;
  1748. if (!m_bAllowDragAndDrop || !IsCellEditable(m_LastDragOverCell))
  1749. return bResult;
  1750. m_MouseMode = MOUSE_NOTHING;
  1751. OnDragLeave();
  1752. return PasteTextToGrid(m_LastDragOverCell, pDataObject);
  1753. }
  1754. #endif
  1755. #ifndef GRIDCONTROL_NO_CLIPBOARD
  1756. void CGridCtrl::OnEditCut()
  1757. {
  1758. if (!IsEditable())
  1759. return;
  1760. COleDataSource* pSource = CopyTextFromGrid();
  1761. if (!pSource) return;
  1762. pSource->SetClipboard();
  1763. CutSelectedText();
  1764. }
  1765. void CGridCtrl::OnEditCopy()
  1766. {
  1767. COleDataSource* pSource = CopyTextFromGrid();
  1768. if (!pSource) return;
  1769. pSource->SetClipboard();
  1770. }
  1771. void CGridCtrl::OnEditPaste()
  1772. {
  1773. if (!IsEditable())
  1774. return;
  1775. // Get the Focus cell, or if none, get the topleft (non-fixed) cell
  1776. CCellID cell = GetFocusCell();
  1777. if (!IsValid(cell)) cell = GetTopleftNonFixedCell();
  1778. if (!IsValid(cell)) return;
  1779. // Attach a COleDataObject to the clipboard and paste the data to the grid
  1780. COleDataObject obj;
  1781. if (obj.AttachClipboard())
  1782. PasteTextToGrid(cell, &obj);
  1783. }
  1784. #endif
  1785. void CGridCtrl::OnEditSelectAll()
  1786. {
  1787. SelectAllCells();
  1788. }
  1789. #ifndef GRIDCONTROL_NO_CLIPBOARD
  1790. void CGridCtrl::OnUpdateEditCopy(CCmdUI* pCmdUI)
  1791. {
  1792. CCellRange Selection = GetSelectedCellRange();
  1793. pCmdUI->Enable(Selection.Count() && IsValid(Selection));
  1794. }
  1795. void CGridCtrl::OnUpdateEditCut(CCmdUI* pCmdUI)
  1796. {
  1797. CCellRange Selection = GetSelectedCellRange();
  1798. pCmdUI->Enable(IsEditable() && Selection.Count() && IsValid(Selection));
  1799. }
  1800. void CGridCtrl::OnUpdateEditPaste(CCmdUI* pCmdUI)
  1801. {
  1802. CCellID cell = GetFocusCell();
  1803. BOOL bCanPaste = IsValid(cell) && IsCellEditable(cell) &&
  1804. ::IsClipboardFormatAvailable(CF_TEXT);
  1805. pCmdUI->Enable(bCanPaste);
  1806. }
  1807. #endif
  1808. void CGridCtrl::OnUpdateEditSelectAll(CCmdUI* pCmdUI)
  1809. {
  1810. pCmdUI->Enable(m_bEnableSelection);
  1811. }
  1812. ////////////////////////////////////////////////////////////////////////////////////////
  1813. // hittest-like functions
  1814. BOOL CGridCtrl::MouseOverRowResizeArea(CPoint& point) const
  1815. {
  1816. if (point.x >= GetFixedColumnWidth())
  1817. return FALSE;
  1818. CCellID idCurrentCell = GetCellFromPt(point);
  1819. CPoint start;
  1820. if (!GetCellOrigin(idCurrentCell, &start))
  1821. return FALSE;
  1822. int endy = start.y + GetRowHeight(idCurrentCell.row);
  1823. if ((point.y - start.y <= m_nResizeCaptureRange && idCurrentCell.row != 0) ||
  1824. endy - point.y <= m_nResizeCaptureRange)
  1825. {
  1826. return TRUE;
  1827. }
  1828. else
  1829. return FALSE;
  1830. }
  1831. BOOL CGridCtrl::MouseOverColumnResizeArea(CPoint& point) const
  1832. {
  1833. if (point.y >= GetFixedRowHeight())
  1834. return FALSE;
  1835. CCellID idCurrentCell = GetCellFromPt(point);
  1836. CPoint start;
  1837. if (!GetCellOrigin(idCurrentCell, &start))
  1838. return FALSE;
  1839. int endx = start.x + GetColumnWidth(idCurrentCell.col);
  1840. if ((point.x - start.x <= m_nResizeCaptureRange && idCurrentCell.col != 0) ||
  1841. endx - point.x <= m_nResizeCaptureRange)
  1842. {
  1843. return TRUE;
  1844. }
  1845. else
  1846. return FALSE;
  1847. }
  1848. // Get cell from point
  1849. CCellID CGridCtrl::GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck /*=TRUE*/) const
  1850. {
  1851. CCellID idTopLeft = GetTopleftNonFixedCell();
  1852. CCellID cellID; // return value
  1853. // calculate column index
  1854. int fixedColWidth = GetFixedColumnWidth();
  1855. if (point.x < 0 || (!bAllowFixedCellCheck && point.x < fixedColWidth)) // not in window
  1856. cellID.col = -1;
  1857. else if (point.x < fixedColWidth) // in fixed col
  1858. {
  1859. int xpos = 0;
  1860. int col = 0;
  1861. for (col = 0; col < m_nFixedCols; col++)
  1862. {
  1863. xpos += GetColumnWidth(col);
  1864. if (xpos > point.x) break;
  1865. }
  1866. cellID.col = col;
  1867. }
  1868. else // in non-fixed col
  1869. {
  1870. int xpos = fixedColWidth;
  1871. int col = 0;
  1872. for (col = idTopLeft.col; col < GetColumnCount(); col++)
  1873. {
  1874. xpos += GetColumnWidth(col);
  1875. if (xpos > point.x) break;
  1876. }
  1877. if (col >= GetColumnCount())
  1878. cellID.col = -1;
  1879. else
  1880. cellID.col = col;
  1881. }
  1882. // calculate row index
  1883. int fixedRowHeight = GetFixedRowHeight();
  1884. if (point.y < 0 || (!bAllowFixedCellCheck && point.y < fixedRowHeight)) // not in window
  1885. cellID.row = -1;
  1886. else if (point.y < fixedRowHeight) // in fixed col
  1887. {
  1888. int ypos = 0;
  1889. int row = 0;
  1890. for (row = 0; row < m_nFixedRows; row++)
  1891. {
  1892. ypos += GetRowHeight(row);
  1893. if (ypos > point.y) break;
  1894. }
  1895. cellID.row = row;
  1896. }
  1897. else
  1898. {
  1899. int ypos = fixedRowHeight;
  1900. int row = 0;
  1901. for (row = idTopLeft.row; row < GetRowCount(); row++)
  1902. {
  1903. ypos += GetRowHeight(row);
  1904. if (ypos > point.y) break;
  1905. }
  1906. if (row >= GetRowCount())
  1907. cellID.row = -1;
  1908. else
  1909. cellID.row = row;
  1910. }
  1911. return cellID;
  1912. }
  1913. ////////////////////////////////////////////////////////////////////////////////
  1914. // CGridCtrl cellrange functions
  1915. CCellID CGridCtrl::GetTopleftNonFixedCell() const
  1916. {
  1917. int nVertScroll = GetScrollPos(SB_VERT),
  1918. nHorzScroll = GetScrollPos(SB_HORZ);
  1919. int nColumn = m_nFixedCols, nRight = 0;
  1920. while (nRight < nHorzScroll && nColumn < (GetColumnCount()-1))
  1921. nRight += GetColumnWidth(nColumn++);
  1922. int nRow = m_nFixedRows, nTop = 0;
  1923. while (nTop < nVertScroll && nRow < (GetRowCount()-1))
  1924. nTop += GetRowHeight(nRow++);
  1925. //TRACE("TopLeft cell is row %d, col %d\n",nRow, nColumn);
  1926. return CCellID(nRow, nColumn);
  1927. }
  1928. // This gets even partially visible cells
  1929. CCellRange CGridCtrl::GetVisibleNonFixedCellRange(LPRECT pRect /*=NULL*/) const
  1930. {
  1931. CRect rect;
  1932. GetClientRect(rect);
  1933. CCellID idTopLeft = GetTopleftNonFixedCell();
  1934. // calc bottom
  1935. int bottom = GetFixedRowHeight();
  1936. int i = 0;
  1937. for (i = idTopLeft.row; i < GetRowCount(); i++)
  1938. {
  1939. bottom += GetRowHeight(i);
  1940. if (bottom >= rect.bottom) {
  1941. bottom = rect.bottom;
  1942. break;
  1943. }
  1944. }
  1945. int maxVisibleRow = min(i, GetRowCount() - 1);
  1946. // calc right
  1947. int right = GetFixedColumnWidth();
  1948. for (i = idTopLeft.col; i < GetColumnCount(); i++)
  1949. {
  1950. right += GetColumnWidth(i);
  1951. if (right >= rect.right) {
  1952. right = rect.right;
  1953. break;
  1954. }
  1955. }
  1956. int maxVisibleCol = min(i, GetColumnCount() - 1);
  1957. if (pRect) {
  1958. pRect->left = pRect->top = 0;
  1959. pRect->right = right;
  1960. pRect->bottom = bottom;
  1961. }
  1962. return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
  1963. }
  1964. // used by ResetScrollBars() - This gets only fully visible cells
  1965. CCellRange CGridCtrl::GetUnobstructedNonFixedCellRange() const
  1966. {
  1967. CRect rect;
  1968. GetClientRect(rect);
  1969. CCellID idTopLeft = GetTopleftNonFixedCell();
  1970. // calc bottom
  1971. int bottom = GetFixedRowHeight();
  1972. int i = 0;
  1973. for (i = idTopLeft.row; i < GetRowCount(); i++)
  1974. {
  1975. bottom += GetRowHeight(i);
  1976. if (bottom >= rect.bottom) break;
  1977. }
  1978. int maxVisibleRow = min(i, GetRowCount() - 1);
  1979. if (maxVisibleRow > 0 && bottom > rect.bottom) maxVisibleRow--;
  1980. // calc right
  1981. int right = GetFixedColumnWidth();
  1982. for (i = idTopLeft.col; i < GetColumnCount(); i++)
  1983. {
  1984. right += GetColumnWidth(i);
  1985. if (right >= rect.right) break;
  1986. }
  1987. int maxVisibleCol = min(i, GetColumnCount() - 1);
  1988. if (maxVisibleCol > 0 && right > rect.right) maxVisibleCol--;
  1989. return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
  1990. }
  1991. // Returns the minimum bounding range of the current selection
  1992. // If no selection, then the returned CCellRange will be invalid
  1993. CCellRange CGridCtrl::GetSelectedCellRange() const
  1994. {
  1995. CCellRange Selection(GetRowCount(), GetColumnCount(), -1,-1);
  1996. for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
  1997. {
  1998. DWORD key;
  1999. CCellID cell;
  2000. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  2001. Selection.SetMinRow( min(Selection.GetMinRow(), cell.row) );
  2002. Selection.SetMinCol( min(Selection.GetMinCol(), cell.col) );
  2003. Selection.SetMaxRow( max(Selection.GetMaxRow(), cell.row) );
  2004. Selection.SetMaxCol( max(Selection.GetMaxCol(), cell.col) );
  2005. }
  2006. return Selection;
  2007. }
  2008. // Returns ALL the cells in the grid
  2009. CCellRange CGridCtrl::GetCellRange() const
  2010. {
  2011. return CCellRange(0, 0, GetRowCount() - 1, GetColumnCount() - 1);
  2012. }
  2013. void CGridCtrl::ResetSelectedRange()
  2014. {
  2015. SetSelectedRange(-1,-1,-1,-1);
  2016. SetFocusCell(-1,-1);
  2017. }
  2018. // Get/Set scroll position using 32 bit functions
  2019. int CGridCtrl::GetScrollPos32(int nBar, BOOL bGetTrackPos /* = FALSE */)
  2020. {
  2021. SCROLLINFO si;
  2022. si.cbSize = sizeof(SCROLLINFO);
  2023. if (bGetTrackPos)
  2024. {
  2025. if (GetScrollInfo(nBar, &si, SIF_TRACKPOS))
  2026. return si.nTrackPos;
  2027. }
  2028. else
  2029. {
  2030. if (GetScrollInfo(nBar, &si, SIF_POS))
  2031. return si.nPos;
  2032. }
  2033. return 0;
  2034. }
  2035. BOOL CGridCtrl::SetScrollPos32(int nBar, int nPos, BOOL bRedraw /* = TRUE */)
  2036. {
  2037. SCROLLINFO si;
  2038. si.cbSize = sizeof(SCROLLINFO);
  2039. si.fMask = SIF_POS;
  2040. si.nPos = nPos;
  2041. return SetScrollInfo(nBar, &si, bRedraw);
  2042. }
  2043. void CGridCtrl::ResetScrollBars()
  2044. {
  2045. if (!m_bAllowDraw || !::IsWindow(GetSafeHwnd()))
  2046. return;
  2047. CRect rect;
  2048. GetClientRect(rect);
  2049. rect.left += GetFixedColumnWidth();
  2050. rect.top += GetFixedRowHeight();
  2051. if (rect.left >= rect.right || rect.top >= rect.bottom) return;
  2052. CRect VisibleRect(GetFixedColumnWidth(), GetFixedRowHeight(), rect.right, rect.bottom);
  2053. CRect VirtualRect(GetFixedColumnWidth(), GetFixedRowHeight(), GetVirtualWidth(), GetVirtualHeight());
  2054. CCellRange visibleCells = GetUnobstructedNonFixedCellRange();
  2055. if (!IsValid(visibleCells)) return;
  2056. SCROLLINFO si;
  2057. si.cbSize = sizeof(SCROLLINFO);
  2058. si.fMask = SIF_PAGE;
  2059. si.nPage = VisibleRect.Width(); SetScrollInfo(SB_HORZ, &si, FALSE);
  2060. si.nPage = VisibleRect.Height(); SetScrollInfo(SB_VERT, &si, FALSE);
  2061. if (VisibleRect.Height() < VirtualRect.Height())
  2062. m_nVScrollMax = VirtualRect.Height()-1; //+ GetRowHeight(visibleCells.GetTopLeft().row);
  2063. else
  2064. m_nVScrollMax = 0;
  2065. if (VisibleRect.Width() < VirtualRect.Width())
  2066. m_nHScrollMax = VirtualRect.Width()-1; //+ GetColumnWidth(visibleCells.GetTopLeft().col);
  2067. else
  2068. m_nHScrollMax = 0;
  2069. ASSERT(m_nVScrollMax < INT_MAX && m_nHScrollMax < INT_MAX); // This should be fine :)
  2070. SetScrollRange(SB_VERT, 0, m_nVScrollMax, TRUE);
  2071. SetScrollRange(SB_HORZ, 0, m_nHScrollMax, TRUE);
  2072. }
  2073. ////////////////////////////////////////////////////////////////////////////////////
  2074. // Row/Column position functions
  2075. // returns the top left point of the cell. Returns FALSE if cell not visible.
  2076. BOOL CGridCtrl::GetCellOrigin(int nRow, int nCol, LPPOINT p) const
  2077. {
  2078. int i;
  2079. if (!IsValid(nRow, nCol)) return FALSE;
  2080. CCellID idTopLeft;
  2081. if (nCol >= m_nFixedCols || nRow >= m_nFixedRows)
  2082. idTopLeft = GetTopleftNonFixedCell();
  2083. if ((nRow >= m_nFixedRows && nRow < idTopLeft.row) ||
  2084. (nCol>= m_nFixedCols && nCol < idTopLeft.col))
  2085. return FALSE;
  2086. p->x = 0;
  2087. if (nCol < m_nFixedCols) // is a fixed column
  2088. for (i = 0; i < nCol; i++)
  2089. p->x += GetColumnWidth(i);
  2090. else { // is a scrollable data column
  2091. for (i = 0; i < m_nFixedCols; i++)
  2092. p->x += GetColumnWidth(i);
  2093. for (i = idTopLeft.col; i < nCol; i++)
  2094. p->x += GetColumnWidth(i);
  2095. }
  2096. p->y = 0;
  2097. if (nRow < m_nFixedRows) // is a fixed row
  2098. for (i = 0; i < nRow; i++)
  2099. p->y += GetRowHeight(i);
  2100. else { // is a scrollable data row
  2101. for (i = 0; i < m_nFixedRows; i++)
  2102. p->y += GetRowHeight(i);
  2103. for (i = idTopLeft.row; i < nRow; i++)
  2104. p->y += GetRowHeight(i);
  2105. }
  2106. return TRUE;
  2107. }
  2108. BOOL CGridCtrl::GetCellOrigin(const CCellID& cell, LPPOINT p) const
  2109. {
  2110. return GetCellOrigin(cell.row, cell.col, p);
  2111. }
  2112. // Returns the bounding box of the cell
  2113. BOOL CGridCtrl::GetCellRect(const CCellID& cell, LPRECT pRect) const
  2114. {
  2115. return GetCellRect(cell.row, cell.col, pRect);
  2116. }
  2117. BOOL CGridCtrl::GetCellRect(int nRow, int nCol, LPRECT pRect) const
  2118. {
  2119. CPoint CellOrigin;
  2120. if (!GetCellOrigin(nRow, nCol, &CellOrigin)) return FALSE;
  2121. pRect->left = CellOrigin.x;
  2122. pRect->top = CellOrigin.y;
  2123. pRect->right = CellOrigin.x + GetColumnWidth(nCol)-1;
  2124. pRect->bottom = CellOrigin.y + GetRowHeight(nRow)-1;
  2125. //TRACE("Row %d, col %d: L %d, T %d, W %d, H %d: %d,%d - %d,%d\n",
  2126. // nRow,nCol, CellOrigin.x, CellOrigin.y, GetColumnWidth(nCol), GetRowHeight(nRow),
  2127. // pRect->left, pRect->top, pRect->right, pRect->bottom);
  2128. return TRUE;
  2129. }
  2130. BOOL CGridCtrl::GetTextRect(const CCellID& cell, LPRECT pRect)
  2131. {
  2132. return GetTextRect(cell.row, cell.col, pRect);
  2133. }
  2134. BOOL CGridCtrl::GetTextRect(int nRow, int nCol, LPRECT pRect)
  2135. {
  2136. GV_ITEM Item;
  2137. Item.mask = GVIF_IMAGE;
  2138. Item.row = nRow;
  2139. Item.col = nCol;
  2140. if (!GetItem(&Item))
  2141. return FALSE;
  2142. if (!GetCellRect(nRow, nCol, pRect))
  2143. return FALSE;
  2144. //pRect->left += m_nMargin;
  2145. //pRect->right -= m_nMargin;
  2146. if (m_pImageList && Item.iImage >= 0) {
  2147. IMAGEINFO Info;
  2148. if (m_pImageList->GetImageInfo(Item.iImage, &Info)) {
  2149. int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
  2150. pRect->left += nImageWidth+m_nMargin;
  2151. }
  2152. }
  2153. return TRUE;
  2154. }
  2155. // Returns the bounding box of a range of cells
  2156. BOOL CGridCtrl::GetCellRangeRect(const CCellRange& cellRange, LPRECT lpRect) const
  2157. {
  2158. CPoint MinOrigin,MaxOrigin;
  2159. if (!GetCellOrigin(cellRange.GetMinRow(), cellRange.GetMinCol(), &MinOrigin))
  2160. return FALSE;
  2161. if (!GetCellOrigin(cellRange.GetMaxRow(), cellRange.GetMaxCol(), &MaxOrigin))
  2162. return FALSE;
  2163. lpRect->left = MinOrigin.x;
  2164. lpRect->top = MinOrigin.y;
  2165. lpRect->right = MaxOrigin.x + GetColumnWidth(cellRange.GetMaxCol()-1);
  2166. lpRect->bottom = MaxOrigin.y + GetRowHeight(cellRange.GetMaxRow()-1);
  2167. return TRUE;
  2168. }
  2169. ////////////////////////////////////////////////////////////////////////////////////
  2170. // Grid attribute functions
  2171. LRESULT CGridCtrl::OnSetFont(WPARAM hFont, LPARAM /*lParam */)
  2172. {
  2173. LRESULT result = Default();
  2174. // Get the logical font
  2175. LOGFONT lf;
  2176. if (!GetObject((HFONT) hFont, sizeof(LOGFONT), &lf))
  2177. return result;
  2178. // Store font as the global default
  2179. memcpy(&m_Logfont, &lf, sizeof(LOGFONT));
  2180. // reset all cells' fonts
  2181. for (int row = 0; row < GetRowCount(); row++)
  2182. for (int col = 0; col < GetColumnCount(); col++)
  2183. SetItemFont(row, col, &lf);
  2184. // Get the font size and hence the default cell size
  2185. CDC* pDC = GetDC();
  2186. if (pDC)
  2187. {
  2188. m_Font.DeleteObject();
  2189. m_Font.CreateFontIndirect(&m_Logfont);
  2190. CFont* pOldFont = pDC->SelectObject(&m_Font);
  2191. TEXTMETRIC tm;
  2192. pDC->GetTextMetrics(&tm);
  2193. m_nMargin = pDC->GetTextExtent(_T(" "),1).cx;
  2194. pDC->SelectObject(pOldFont);
  2195. ReleaseDC(pDC);
  2196. m_nDefCellHeight = tm.tmHeight+tm.tmExternalLeading + 1*m_nMargin;
  2197. m_nDefCellWidth = tm.tmAveCharWidth*12 + 2*m_nMargin;
  2198. }
  2199. if (::IsWindow(GetSafeHwnd()))
  2200. Invalidate();
  2201. return result;
  2202. }
  2203. LRESULT CGridCtrl::OnGetFont(WPARAM /*wParam*/, LPARAM /*lParam*/)
  2204. {
  2205. return (LRESULT) (HFONT) m_Font;
  2206. }
  2207. #ifndef _WIN32_WCE_NO_CURSOR
  2208. BOOL CGridCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  2209. {
  2210. if (nHitTest == HTCLIENT)
  2211. {
  2212. switch (m_MouseMode)
  2213. {
  2214. case MOUSE_OVER_COL_DIVIDE: SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE)); break;
  2215. case MOUSE_OVER_ROW_DIVIDE: SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS)); break;
  2216. #ifndef GRIDCONTROL_NO_DRAGDROP
  2217. case MOUSE_DRAGGING: break;
  2218. #endif
  2219. default: SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  2220. }
  2221. return TRUE;
  2222. }
  2223. return CWnd::OnSetCursor(pWnd, nHitTest, message);
  2224. }
  2225. #endif
  2226. ////////////////////////////////////////////////////////////////////////////////////
  2227. // Row/Column count functions
  2228. BOOL CGridCtrl::SetFixedRowCount(int nFixedRows)
  2229. {
  2230. ASSERT(nFixedRows >= 0);
  2231. if (nFixedRows > GetRowCount())
  2232. if (!SetRowCount(nFixedRows)) return FALSE;
  2233. if (m_idCurrentCell.row < nFixedRows)
  2234. SetFocusCell(-1,-1);
  2235. m_nFixedRows = nFixedRows;
  2236. if (GetSafeHwnd() && m_bAllowDraw)
  2237. Invalidate();
  2238. return TRUE;
  2239. }
  2240. BOOL CGridCtrl::SetFixedColumnCount(int nFixedCols)
  2241. {
  2242. ASSERT(nFixedCols >= 0);
  2243. if (nFixedCols > GetColumnCount())
  2244. if (!SetColumnCount(nFixedCols)) return FALSE;
  2245. if (m_idCurrentCell.col < nFixedCols)
  2246. SetFocusCell(-1,-1);
  2247. m_nFixedCols = nFixedCols;
  2248. if (GetSafeHwnd() && m_bAllowDraw)
  2249. Invalidate();
  2250. return TRUE;
  2251. }
  2252. BOOL CGridCtrl::SetRowCount(int nRows)
  2253. {
  2254. ASSERT(nRows >= 0);
  2255. if (nRows == GetRowCount()) return TRUE;
  2256. if (nRows < m_nFixedRows)
  2257. m_nFixedRows = nRows;
  2258. if (m_idCurrentCell.row >= nRows)
  2259. SetFocusCell(-1,-1);
  2260. int addedRows = nRows - GetRowCount();
  2261. // If we are about to lose rows, then we need to delete the GridCell objects
  2262. // in each column within each row
  2263. if (addedRows < 0) {
  2264. for (int row = nRows; row < m_nRows; row++)
  2265. {
  2266. // Delete cells
  2267. for (int col = 0; col < m_nCols; col++)
  2268. {
  2269. CGridCell* pCell = GetCell(row, col);
  2270. if (pCell) {
  2271. EmptyCell(pCell, row, col);
  2272. delete pCell;
  2273. }
  2274. }
  2275. // Delete rows
  2276. GRID_ROW* pRow = m_RowData[row];
  2277. if (pRow) delete pRow;
  2278. }
  2279. }
  2280. // Change the number of rows.
  2281. m_nRows = nRows;
  2282. m_RowData.SetSize(m_nRows);
  2283. m_arRowHeights.SetSize(nRows);
  2284. // If we have just added rows, we need to construct new elements for each cell
  2285. // and set the default row height
  2286. if (addedRows > 0) {
  2287. // initialize row heights and data
  2288. int startRow = nRows - addedRows;
  2289. for (int row = startRow; row < GetRowCount(); row++) {
  2290. m_arRowHeights[row] = m_nDefCellHeight;
  2291. m_RowData[row] = new GRID_ROW;
  2292. m_RowData[row]->SetSize(m_nCols);
  2293. for (int col = 0; col < m_nCols; col++)
  2294. {
  2295. GRID_ROW* pRow = m_RowData[row];
  2296. if (pRow) pRow->SetAt(col, CreateCell(row, col));
  2297. }
  2298. }
  2299. }
  2300. //else
  2301. // ResetSelectedRange();
  2302. if (GetSafeHwnd() && m_bAllowDraw)
  2303. {
  2304. ResetScrollBars();
  2305. Invalidate();
  2306. }
  2307. return TRUE;
  2308. }
  2309. BOOL CGridCtrl::SetColumnCount(int nCols)
  2310. {
  2311. ASSERT(nCols >= 0);
  2312. if (nCols == GetColumnCount()) return TRUE;
  2313. if (nCols < m_nFixedCols)
  2314. m_nFixedCols = nCols;
  2315. if (m_idCurrentCell.col >= nCols)
  2316. SetFocusCell(-1,-1);
  2317. int addedCols = nCols - GetColumnCount();
  2318. // If we are about to lose columns, then we need to delete the GridCell objects
  2319. // within each column
  2320. if (addedCols < 0) {
  2321. for (int row = 0; row < m_nRows; row++)
  2322. for (int col = nCols; col < GetColumnCount(); col++)
  2323. {
  2324. CGridCell* pCell = GetCell(row, col);
  2325. if (pCell) {
  2326. EmptyCell(pCell, row, col);
  2327. delete pCell;
  2328. }
  2329. }
  2330. }
  2331. // Change the number of columns.
  2332. m_nCols = nCols;
  2333. m_arColWidths.SetSize(nCols);
  2334. // Change the number of columns in each row.
  2335. for (int i = 0; i < m_nRows; i++)
  2336. if (m_RowData[i]) m_RowData[i]->SetSize(nCols);
  2337. // If we have just added columns, we need to construct new elements for each cell
  2338. // and set the default column width
  2339. if (addedCols > 0)
  2340. {
  2341. // initialized column widths
  2342. int startCol = nCols - addedCols;
  2343. int col = 0;
  2344. for (col = startCol; col < GetColumnCount(); col++)
  2345. m_arColWidths[col] = m_nDefCellWidth;
  2346. // initialise column data
  2347. for (int row = 0; row < m_nRows; row++)
  2348. for (col = startCol; col < GetColumnCount(); col++)
  2349. {
  2350. GRID_ROW* pRow = m_RowData[row];
  2351. if (pRow) pRow->SetAt(col, CreateCell(row,col));
  2352. }
  2353. }
  2354. //else // check for selected cell ranges
  2355. // ResetSelectedRange();
  2356. if (GetSafeHwnd() && m_bAllowDraw)
  2357. {
  2358. ResetScrollBars();
  2359. Invalidate();
  2360. }
  2361. return TRUE;
  2362. }
  2363. // Insert a column at a given position, or add to end of columns (if nColumn = -1)
  2364. int CGridCtrl::InsertColumn(LPCTSTR strHeading,
  2365. UINT nFormat /* = DT_CENTER|DT_VCENTER|DT_SINGLELINE */,
  2366. int nColumn /* = -1 */)
  2367. {
  2368. // If the insertion is for a specific column, check it's within range.
  2369. if (nColumn >= 0 && nColumn >= GetColumnCount())
  2370. return -1;
  2371. ResetSelectedRange();
  2372. // Gotta be able to at least _see_ some of the column.
  2373. if (m_nRows < 1)
  2374. SetRowCount(1);
  2375. if (nColumn < 0)
  2376. {
  2377. nColumn = m_nCols;
  2378. m_arColWidths.Add(0);
  2379. for (int row = 0; row < m_nRows; row++)
  2380. {
  2381. GRID_ROW* pRow = m_RowData[row];
  2382. if (!pRow) return -1;
  2383. pRow->Add(CreateCell(row, nColumn));
  2384. }
  2385. }
  2386. else
  2387. {
  2388. m_arColWidths.InsertAt(nColumn, (UINT)0);
  2389. for (int row = 0; row < m_nRows; row++)
  2390. {
  2391. GRID_ROW* pRow = m_RowData[row];
  2392. if (!pRow) return -1;
  2393. pRow->InsertAt(nColumn, CreateCell(row, nColumn));
  2394. }
  2395. }
  2396. m_nCols++;
  2397. // Initialise column data
  2398. SetItemText(0, nColumn, strHeading);
  2399. for (int row = 0; row < m_nRows; row++)
  2400. {
  2401. SetItemFormat(row, nColumn, nFormat);
  2402. }
  2403. // initialized column width
  2404. m_arColWidths[nColumn] = GetTextExtent(strHeading).cx;
  2405. if (m_idCurrentCell.col != -1 && nColumn < m_idCurrentCell.col)
  2406. m_idCurrentCell.col++;
  2407. ResetScrollBars();
  2408. return nColumn;
  2409. }
  2410. // Insert a row at a given position, or add to end of rows (if nRow = -1)
  2411. int CGridCtrl::InsertRow(LPCTSTR strHeading, int nRow /* = -1 */)
  2412. {
  2413. // If the insertion is for a specific row, check it's within range.
  2414. if (nRow >= 0 && nRow > GetRowCount())
  2415. return -1;
  2416. ResetSelectedRange();
  2417. // Gotta be able to at least _see_ some of the row.
  2418. if (m_nCols < 1)
  2419. SetColumnCount(1);
  2420. // Adding a row to the bottom
  2421. if (nRow < 0)
  2422. {
  2423. nRow = m_nRows;
  2424. m_arRowHeights.Add(0);
  2425. m_RowData.Add(new GRID_ROW);
  2426. }
  2427. else
  2428. {
  2429. m_arRowHeights.InsertAt(nRow, (UINT)0);
  2430. m_RowData.InsertAt(nRow, new GRID_ROW);
  2431. }
  2432. m_nRows++;
  2433. m_RowData[nRow]->SetSize(m_nCols);
  2434. // Initialise cell data
  2435. for (int col = 0; col < m_nCols; col++)
  2436. {
  2437. GRID_ROW* pRow = m_RowData[nRow];
  2438. if (!pRow) return -1;
  2439. pRow->SetAt(col, CreateCell(nRow, col));
  2440. }
  2441. // Set row title
  2442. SetItemText(nRow, 0, strHeading);
  2443. // initialized row height
  2444. m_arRowHeights[nRow] = GetTextExtent(strHeading).cy;
  2445. if (m_idCurrentCell.row != -1 && nRow < m_idCurrentCell.row)
  2446. m_idCurrentCell.row++;
  2447. ResetScrollBars();
  2448. return nRow;
  2449. }
  2450. // Creates a new grid cell and performs any necessary initialisation
  2451. CGridCell* CGridCtrl::CreateCell(int nRow, int nCol)
  2452. {
  2453. CGridCell* pCell = new CGridCell;
  2454. if (!pCell)
  2455. return NULL;
  2456. // Make format same as cell above
  2457. if (nRow > 0 && nCol >= 0 && nCol < m_nCols)
  2458. pCell->nFormat = GetItemFormat(nRow-1, nCol);
  2459. // Make font default grid font
  2460. memcpy(&(pCell->lfFont), &m_Logfont, sizeof(LOGFONT));
  2461. return pCell;
  2462. }
  2463. // Performs any cell cleanup necessary to maintain grid integrity
  2464. void CGridCtrl::EmptyCell(CGridCell* pCell, int nRow, int nCol)
  2465. {
  2466. // Set the cells state to 0. If the cell is selected, this
  2467. // will remove the cell from the selected list.
  2468. SetItemState(nRow, nCol, 0);
  2469. // Empty strings
  2470. pCell->szText.Empty();
  2471. }
  2472. BOOL CGridCtrl::DeleteColumn(int nColumn)
  2473. {
  2474. if (nColumn < 0 || nColumn >= GetColumnCount())
  2475. return FALSE;
  2476. ResetSelectedRange();
  2477. for (int row = 0; row < GetRowCount(); row++)
  2478. {
  2479. GRID_ROW* pRow = m_RowData[row];
  2480. if (!pRow) return FALSE;
  2481. CGridCell* pCell = pRow->GetAt(nColumn);
  2482. if (pCell) {
  2483. EmptyCell(pCell, row, nColumn);
  2484. delete pCell;
  2485. }
  2486. pRow->RemoveAt(nColumn);
  2487. }
  2488. m_arColWidths.RemoveAt(nColumn);
  2489. m_nCols--;
  2490. if (nColumn < m_nFixedCols) m_nFixedCols--;
  2491. if (nColumn == m_idCurrentCell.col)
  2492. m_idCurrentCell.row = m_idCurrentCell.col = -1;
  2493. else if (nColumn < m_idCurrentCell.col)
  2494. m_idCurrentCell.col--;
  2495. ResetScrollBars();
  2496. return TRUE;
  2497. }
  2498. BOOL CGridCtrl::DeleteRow(int nRow)
  2499. {
  2500. if ( nRow < 0 || nRow >= GetRowCount())
  2501. return FALSE;
  2502. GRID_ROW* pRow = m_RowData[nRow];
  2503. if (!pRow) return FALSE;
  2504. ResetSelectedRange();
  2505. for (int col = 0; col < GetColumnCount(); col++)
  2506. {
  2507. CGridCell* pCell = pRow->GetAt(col);
  2508. if (pCell) {
  2509. EmptyCell(pCell, nRow, col);
  2510. delete pCell;
  2511. }
  2512. }
  2513. delete pRow;
  2514. m_RowData.RemoveAt(nRow);
  2515. m_arRowHeights.RemoveAt(nRow);
  2516. m_nRows--;
  2517. if (nRow < m_nFixedRows) m_nFixedRows--;
  2518. if (nRow == m_idCurrentCell.row)
  2519. m_idCurrentCell.row = m_idCurrentCell.col = -1;
  2520. else if (nRow < m_idCurrentCell.row)
  2521. m_idCurrentCell.row--;
  2522. ResetScrollBars();
  2523. return TRUE;
  2524. }
  2525. // Handy function that removes all non-fixed rows
  2526. BOOL CGridCtrl::DeleteNonFixedRows()
  2527. {
  2528. int nFixed = GetFixedRowCount();
  2529. int nCount = GetRowCount();
  2530. // Delete all data rows
  2531. for (int nRow = nCount; nRow >= nFixed; nRow--)
  2532. DeleteRow(nRow);
  2533. return TRUE;
  2534. }
  2535. // Removes all rows, columns and data from the grid.
  2536. BOOL CGridCtrl::DeleteAllItems()
  2537. {
  2538. ResetSelectedRange();
  2539. m_arColWidths.RemoveAll();
  2540. m_arRowHeights.RemoveAll();
  2541. // Delete all cells in the grid
  2542. for (int row = 0; row < m_nRows; row++)
  2543. {
  2544. GRID_ROW* pRow = m_RowData[row];
  2545. if (!pRow) continue;
  2546. for (int col = 0; col < m_nCols; col++)
  2547. {
  2548. CGridCell* pCell = pRow->GetAt(col);
  2549. if (pCell) {
  2550. EmptyCell(pCell, row, col); // TODO - this is a bit of a performance hit.
  2551. delete pCell; // better to call m_SelectedCells.RemoveAll()
  2552. } // instead. This is safer for changes though.
  2553. }
  2554. delete pRow;
  2555. }
  2556. // Remove all rows
  2557. m_RowData.RemoveAll();
  2558. m_idCurrentCell.row = m_idCurrentCell.col = -1;
  2559. m_nRows = m_nFixedRows = m_nCols = m_nFixedCols = 0;
  2560. ResetScrollBars();
  2561. return TRUE;
  2562. }
  2563. /////////////////////////////////////////////////////////////////////////////
  2564. // CGridCtrl data functions
  2565. // Set CListCtrl::GetNextItem for details
  2566. CCellID CGridCtrl::GetNextItem(CCellID& cell, int nFlags) const
  2567. {
  2568. if (nFlags & GVNI_ALL)
  2569. { // GVNI_ALL Search whole Grid beginning from cell
  2570. // First row (cell.row) -- ONLY Columns to the right of cell
  2571. // following rows -- ALL Columns
  2572. int row = cell.row , col = cell.col + 1;
  2573. if (row <= 0) row = GetFixedRowCount();
  2574. for (; row < GetRowCount(); row++)
  2575. {
  2576. if (col <= 0 ) col = GetFixedColumnCount();
  2577. for (; col < GetColumnCount(); col++)
  2578. {
  2579. int nState = GetItemState(row, col);
  2580. if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
  2581. return CCellID(row, col);
  2582. if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
  2583. return CCellID(row, col);
  2584. if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
  2585. return CCellID(row, col);
  2586. if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
  2587. return CCellID(row, col);
  2588. if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
  2589. return CCellID(row, col);
  2590. }
  2591. // go to First Column
  2592. col=GetFixedColumnCount();
  2593. }
  2594. }
  2595. else if ((nFlags & GVNI_BELOW) && (nFlags & GVNI_TORIGHT))
  2596. { // GVNI_AREA Search Grid beginning from cell to Lower-Right of Grid
  2597. // Only rows starting with cell.row and below
  2598. // All rows -- ONLY Columns to the right of cell
  2599. int row = cell.row;
  2600. if (row <= 0) row = GetFixedRowCount();
  2601. for (; row < GetRowCount(); row++)
  2602. {
  2603. int col = cell.col + 1;
  2604. if (col <= 0) col = GetFixedColumnCount();
  2605. for (; col < GetColumnCount(); col++)
  2606. {
  2607. int nState = GetItemState(row, col);
  2608. if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
  2609. return CCellID(row, col);
  2610. if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
  2611. return CCellID(row, col);
  2612. if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
  2613. return CCellID(row, col);
  2614. if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
  2615. return CCellID(row, col);
  2616. if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
  2617. return CCellID(row, col);
  2618. }
  2619. }
  2620. }
  2621. else if (nFlags & GVNI_ABOVE)
  2622. {
  2623. for (int row = cell.row-1; row >= GetFixedRowCount(); row--)
  2624. {
  2625. int nState = GetItemState(row, cell.col);
  2626. if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
  2627. return CCellID(row, cell.col);
  2628. if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
  2629. return CCellID(row, cell.col);
  2630. if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
  2631. return CCellID(row, cell.col);
  2632. if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
  2633. return CCellID(row, cell.col);
  2634. if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
  2635. return CCellID(row, cell.col);
  2636. }
  2637. }
  2638. else if (nFlags & GVNI_BELOW)
  2639. {
  2640. for (int row = cell.row+1; row < GetRowCount(); row++)
  2641. {
  2642. int nState = GetItemState(row, cell.col);
  2643. if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
  2644. return CCellID(row, cell.col);
  2645. if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
  2646. return CCellID(row, cell.col);
  2647. if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
  2648. return CCellID(row, cell.col);
  2649. if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
  2650. return CCellID(row, cell.col);
  2651. if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
  2652. return CCellID(row, cell.col);
  2653. }
  2654. }
  2655. else if (nFlags & GVNI_TOLEFT)
  2656. {
  2657. for (int col = cell.col-1; col >= GetFixedColumnCount(); col--)
  2658. {
  2659. int nState = GetItemState(cell.row, col);
  2660. if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
  2661. return CCellID(cell.row, col);
  2662. if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
  2663. return CCellID(cell.row, col);
  2664. if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
  2665. return CCellID(cell.row, col);
  2666. if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
  2667. return CCellID(cell.row, col);
  2668. if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
  2669. return CCellID(cell.row, col);
  2670. }
  2671. }
  2672. else if (nFlags & GVNI_TORIGHT)
  2673. {
  2674. for (int col = cell.col+1; col < GetColumnCount(); col++)
  2675. {
  2676. int nState = GetItemState(cell.row, col);
  2677. if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
  2678. return CCellID(cell.row, col);
  2679. if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
  2680. return CCellID(cell.row, col);
  2681. if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
  2682. return CCellID(cell.row, col);
  2683. if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
  2684. return CCellID(cell.row, col);
  2685. if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
  2686. return CCellID(cell.row, col);
  2687. }
  2688. }
  2689. return CCellID(-1, -1);
  2690. }
  2691. // Sorts on a given column using the cell text
  2692. BOOL CGridCtrl::SortTextItems(int nCol, BOOL bAscending)
  2693. {
  2694. ResetSelectedRange();
  2695. SetFocusCell(-1,-1);
  2696. return SortTextItems(nCol, bAscending, GetFixedRowCount(),-1);
  2697. }
  2698. // recursive sort implementation
  2699. BOOL CGridCtrl::SortTextItems(int nCol, BOOL bAscending, int low, int high)
  2700. {
  2701. if (nCol >= GetColumnCount()) return FALSE;
  2702. if (high == -1) high = GetRowCount() - 1;
  2703. int lo = low;
  2704. int hi = high;
  2705. if( hi <= lo ) return FALSE;
  2706. CString midItem = GetItemText( (lo+hi)/2, nCol );
  2707. // loop through the list until indices cross
  2708. while( lo <= hi )
  2709. {
  2710. // Find the first element that is greater than or equal to the partition
  2711. // element starting from the left Index.
  2712. if( bAscending )
  2713. while (lo < high && GetItemText(lo, nCol) < midItem)
  2714. ++lo;
  2715. else
  2716. while (lo < high && GetItemText(lo, nCol) > midItem)
  2717. ++lo;
  2718. // Find an element that is smaller than or equal to the partition
  2719. // element starting from the right Index.
  2720. if( bAscending )
  2721. while (hi > low && GetItemText(hi, nCol) > midItem)
  2722. --hi;
  2723. else
  2724. while (hi > low && GetItemText(hi, nCol) < midItem)
  2725. --hi;
  2726. // If the indexes have not crossed, swap if the items are not equal
  2727. if (lo <= hi)
  2728. {
  2729. // swap only if the items are not equal
  2730. if (GetItemText(lo, nCol) != GetItemText(hi, nCol))
  2731. {
  2732. for (int col = 0; col < GetColumnCount(); col++)
  2733. {
  2734. CGridCell *pCell = GetCell(lo, col);
  2735. SetCell(lo, col, GetCell(hi, col));
  2736. SetCell(hi, col, pCell);
  2737. }
  2738. UINT nRowHeight = m_arRowHeights[lo];
  2739. m_arRowHeights[lo] = m_arRowHeights[hi];
  2740. m_arRowHeights[hi] = nRowHeight;
  2741. }
  2742. ++lo;
  2743. --hi;
  2744. }
  2745. }
  2746. // If the right index has not reached the left side of array
  2747. // must now sort the left partition.
  2748. if( low < hi )
  2749. SortTextItems(nCol, bAscending, low, hi);
  2750. // If the left index has not reached the right side of array
  2751. // must now sort the right partition.
  2752. if( lo < high )
  2753. SortTextItems(nCol, bAscending, lo, high);
  2754. return TRUE;
  2755. }
  2756. // Sorts on a given column using the supplied compare function (see CListCtrl::SortItems)
  2757. BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending,
  2758. LPARAM data /* = 0 */)
  2759. {
  2760. ResetSelectedRange();
  2761. SetFocusCell(-1,-1);
  2762. return SortItems(pfnCompare, nCol, bAscending, data, GetFixedRowCount(), -1);
  2763. }
  2764. // recursive sort implementation
  2765. BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data,
  2766. int low, int high)
  2767. {
  2768. if (nCol >= GetColumnCount()) return FALSE;
  2769. if (high == -1) high = GetRowCount() - 1;
  2770. int lo = low;
  2771. int hi = high;
  2772. if( hi <= lo ) return FALSE;
  2773. LPARAM midItem = GetItemData( (lo+hi)/2, nCol );
  2774. // loop through the list until indices cross
  2775. while( lo <= hi )
  2776. {
  2777. // Find the first element that is greater than or equal to the partition
  2778. // element starting from the left Index.
  2779. if( bAscending )
  2780. while (lo < high && pfnCompare(GetItemData(lo, nCol), midItem, data) < 0)
  2781. ++lo;
  2782. else
  2783. while (lo < high && pfnCompare(GetItemData(lo, nCol), midItem, data) > 0)
  2784. ++lo;
  2785. // Find an element that is smaller than or equal to the partition
  2786. // element starting from the right Index.
  2787. if( bAscending )
  2788. while (hi > low && pfnCompare(GetItemData(hi, nCol), midItem, data) > 0)
  2789. --hi;
  2790. else
  2791. while (hi > low && pfnCompare(GetItemData(hi, nCol), midItem, data) < 0)
  2792. --hi;
  2793. // If the indexes have not crossed, swap if the items are not equal
  2794. if (lo <= hi)
  2795. {
  2796. // swap only if the items are not equal
  2797. if (pfnCompare(GetItemData(lo, nCol), GetItemData(hi, nCol), data) != 0)
  2798. {
  2799. for (int col = 0; col < GetColumnCount(); col++)
  2800. {
  2801. CGridCell *pCell = GetCell(lo, col);
  2802. SetCell(lo, col, GetCell(hi, col));
  2803. SetCell(hi, col, pCell);
  2804. }
  2805. UINT nRowHeight = m_arRowHeights[lo];
  2806. m_arRowHeights[lo] = m_arRowHeights[hi];
  2807. m_arRowHeights[hi] = nRowHeight;
  2808. }
  2809. ++lo;
  2810. --hi;
  2811. }
  2812. }
  2813. // If the right index has not reached the left side of array
  2814. // must now sort the left partition.
  2815. if( low < hi )
  2816. SortItems(pfnCompare, nCol, bAscending, data, low, hi);
  2817. // If the left index has not reached the right side of array
  2818. // must now sort the right partition.
  2819. if( lo < high )
  2820. SortItems(pfnCompare, nCol, bAscending, data, lo, high);
  2821. return TRUE;
  2822. }
  2823. /////////////////////////////////////////////////////////////////////////////
  2824. // CGridCtrl data functions
  2825. BOOL CGridCtrl::SetItem(const GV_ITEM* pItem)
  2826. {
  2827. if (!pItem)
  2828. return FALSE;
  2829. CGridCell* pCell = GetCell(pItem->row, pItem->col);
  2830. if (!pCell)
  2831. return FALSE;
  2832. if (pItem->mask & GVIF_TEXT) pCell->szText = pItem->szText;
  2833. if (pItem->mask & GVIF_PARAM) pCell->lParam = pItem->lParam;
  2834. if (pItem->mask & GVIF_IMAGE) pCell->iImage = pItem->iImage;
  2835. if (pItem->mask & GVIF_STATE) pCell->state = pItem->state;
  2836. if (pItem->mask & GVIF_FORMAT) pCell->nFormat = pItem->nFormat;
  2837. if (pItem->mask & GVIF_BKCLR) pCell->crBkClr = pItem->crBkClr;
  2838. if (pItem->mask & GVIF_FGCLR) pCell->crFgClr = pItem->crFgClr;
  2839. if (pItem->mask & GVIF_FONT) memcpy(&(pCell->lfFont), &(pItem->lfFont), sizeof(LOGFONT));
  2840. return TRUE;
  2841. }
  2842. BOOL CGridCtrl::GetItem(GV_ITEM* pItem)
  2843. {
  2844. if (!pItem)
  2845. return FALSE;
  2846. CGridCell* pCell = GetCell(pItem->row, pItem->col);
  2847. if (!pCell)
  2848. return FALSE;
  2849. if (pItem->mask & GVIF_TEXT) pItem->szText = GetItemText(pItem->row, pItem->col);
  2850. if (pItem->mask & GVIF_PARAM) pItem->lParam = pCell->lParam;
  2851. if (pItem->mask & GVIF_IMAGE) pItem->iImage = pCell->iImage;
  2852. if (pItem->mask & GVIF_STATE) pItem->state = pCell->state;
  2853. if (pItem->mask & GVIF_FORMAT) pItem->nFormat = pCell->nFormat;
  2854. if (pItem->mask & GVIF_BKCLR) pItem->crBkClr = pCell->crBkClr;
  2855. if (pItem->mask & GVIF_FGCLR) pItem->crFgClr = pCell->crFgClr;
  2856. if (pItem->mask & GVIF_FONT) memcpy(&(pItem->lfFont), &(pCell->lfFont), sizeof(LOGFONT));
  2857. return TRUE;
  2858. }
  2859. BOOL CGridCtrl::SetItemText(int nRow, int nCol, LPCTSTR str)
  2860. {
  2861. CGridCell* pCell = GetCell(nRow, nCol);
  2862. if (!pCell)
  2863. return FALSE;
  2864. pCell->szText = str;
  2865. return TRUE;
  2866. }
  2867. BOOL CGridCtrl::SetItemData(int nRow, int nCol, LPARAM lParam)
  2868. {
  2869. CGridCell* pCell = GetCell(nRow, nCol);
  2870. if (!pCell)
  2871. return FALSE;
  2872. pCell->lParam = lParam;
  2873. return TRUE;
  2874. }
  2875. LPARAM CGridCtrl::GetItemData(int nRow, int nCol) const
  2876. {
  2877. CGridCell* pCell = GetCell(nRow, nCol);
  2878. if (!pCell)
  2879. return (LPARAM) 0;
  2880. return pCell->lParam;
  2881. }
  2882. BOOL CGridCtrl::SetItemImage(int nRow, int nCol, int iImage)
  2883. {
  2884. CGridCell* pCell = GetCell(nRow, nCol);
  2885. if (!pCell)
  2886. return FALSE;
  2887. pCell->iImage = iImage;
  2888. return TRUE;
  2889. }
  2890. int CGridCtrl::GetItemImage(int nRow, int nCol) const
  2891. {
  2892. CGridCell* pCell = GetCell(nRow, nCol);
  2893. ASSERT(pCell);
  2894. if (!pCell)
  2895. return -1;
  2896. return pCell->iImage;
  2897. }
  2898. BOOL CGridCtrl::SetItemState(int nRow, int nCol, UINT state)
  2899. {
  2900. CGridCell* pCell = GetCell(nRow, nCol);
  2901. ASSERT(pCell);
  2902. if (!pCell)
  2903. return FALSE;
  2904. // If the cell is being unselected, remove it from the selected list
  2905. if ((pCell->state & GVIS_SELECTED) && !(state & GVIS_SELECTED))
  2906. {
  2907. CCellID cell;
  2908. DWORD key = MAKELONG(nRow, nCol);
  2909. if (m_SelectedCellMap.Lookup(key, (CCellID&)cell))
  2910. m_SelectedCellMap.RemoveKey(key);
  2911. }
  2912. // If cell is being selected, add it to the list of selected cells
  2913. else if (!(pCell->state & GVIS_SELECTED) && (state & GVIS_SELECTED))
  2914. {
  2915. CCellID cell(nRow, nCol);
  2916. m_SelectedCellMap.SetAt(MAKELONG(nRow, nCol), cell);
  2917. }
  2918. // Set the cell's state
  2919. pCell->state = state;
  2920. return TRUE;
  2921. }
  2922. UINT CGridCtrl::GetItemState(int nRow, int nCol) const
  2923. {
  2924. CGridCell* pCell = GetCell(nRow, nCol);
  2925. ASSERT(pCell);
  2926. if (!pCell)
  2927. return 0;
  2928. return pCell->state;
  2929. }
  2930. BOOL CGridCtrl::SetItemFormat(int nRow, int nCol, UINT nFormat)
  2931. {
  2932. CGridCell* pCell = GetCell(nRow, nCol);
  2933. ASSERT(pCell);
  2934. if (!pCell)
  2935. return FALSE;
  2936. pCell->nFormat = nFormat;
  2937. return TRUE;
  2938. }
  2939. UINT CGridCtrl::GetItemFormat(int nRow, int nCol) const
  2940. {
  2941. CGridCell* pCell = GetCell(nRow, nCol);
  2942. ASSERT(pCell);
  2943. if (!pCell)
  2944. return 0;
  2945. return pCell->nFormat;
  2946. }
  2947. BOOL CGridCtrl::SetItemBkColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
  2948. {
  2949. CGridCell* pCell = GetCell(nRow, nCol);
  2950. ASSERT(pCell);
  2951. if (!pCell)
  2952. return FALSE;
  2953. pCell->crBkClr = cr;
  2954. return TRUE;
  2955. }
  2956. COLORREF CGridCtrl::GetItemBkColour(int nRow, int nCol) const
  2957. {
  2958. CGridCell* pCell = GetCell(nRow, nCol);
  2959. ASSERT(pCell);
  2960. if (!pCell)
  2961. return 0;
  2962. return pCell->crBkClr;
  2963. }
  2964. BOOL CGridCtrl::SetItemFgColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
  2965. {
  2966. CGridCell* pCell = GetCell(nRow, nCol);
  2967. ASSERT(pCell);
  2968. if (!pCell)
  2969. return FALSE;
  2970. pCell->crFgClr = cr;
  2971. return TRUE;
  2972. }
  2973. COLORREF CGridCtrl::GetItemFgColour(int nRow, int nCol) const
  2974. {
  2975. CGridCell* pCell = GetCell(nRow, nCol);
  2976. ASSERT(pCell);
  2977. if (!pCell)
  2978. return 0;
  2979. return pCell->crFgClr;
  2980. }
  2981. BOOL CGridCtrl::SetItemFont(int nRow, int nCol, LOGFONT* lf)
  2982. {
  2983. CGridCell* pCell = GetCell(nRow, nCol);
  2984. ASSERT(pCell);
  2985. if (!pCell)
  2986. return FALSE;
  2987. memcpy(&(pCell->lfFont), lf, sizeof(LOGFONT));
  2988. return TRUE;
  2989. }
  2990. LOGFONT* CGridCtrl::GetItemFont(int nRow, int nCol)
  2991. {
  2992. CGridCell* pCell = GetCell(nRow, nCol);
  2993. ASSERT(pCell);
  2994. if (!pCell)
  2995. return &m_Logfont;
  2996. return &(pCell->lfFont);
  2997. }
  2998. ////////////////////////////////////////////////////////////////////////////////////
  2999. // Row/Column size functions
  3000. long CGridCtrl::GetVirtualWidth() const
  3001. {
  3002. long lVirtualWidth = 0;
  3003. int iColCount = GetColumnCount();
  3004. for (int i = 0; i < iColCount; i++)
  3005. lVirtualWidth += m_arColWidths[i];
  3006. return lVirtualWidth;
  3007. }
  3008. long CGridCtrl::GetVirtualHeight() const
  3009. {
  3010. long lVirtualHeight = 0;
  3011. int iRowCount = GetRowCount();
  3012. for (int i = 0; i < iRowCount; i++)
  3013. lVirtualHeight += m_arRowHeights[i];
  3014. return lVirtualHeight;
  3015. }
  3016. int CGridCtrl::GetRowHeight(int nRow) const
  3017. {
  3018. ASSERT(nRow >= 0 && nRow < m_nRows);
  3019. if (nRow < 0 || nRow >= m_nRows) return -1;
  3020. return m_arRowHeights[nRow];
  3021. }
  3022. int CGridCtrl::GetColumnWidth(int nCol) const
  3023. {
  3024. ASSERT(nCol >= 0 && nCol < m_nCols);
  3025. if (nCol < 0 || nCol >= m_nCols) return -1;
  3026. return m_arColWidths[nCol];
  3027. }
  3028. BOOL CGridCtrl::SetRowHeight(int nRow, int height)
  3029. {
  3030. ASSERT(nRow >= 0 && nRow < m_nRows && height >= 0);
  3031. if (nRow < 0 || nRow >= m_nRows || height < 0) return FALSE;
  3032. m_arRowHeights[nRow] = height;
  3033. return TRUE;
  3034. }
  3035. BOOL CGridCtrl::SetColumnWidth(int nCol, int width)
  3036. {
  3037. ASSERT(nCol >= 0 && nCol < m_nCols && width >= 0);
  3038. if (nCol < 0 || nCol >= m_nCols || width < 0) return FALSE;
  3039. m_arColWidths[nCol] = width;
  3040. return TRUE;
  3041. }
  3042. int CGridCtrl::GetFixedRowHeight() const
  3043. {
  3044. int nHeight = 0;
  3045. for (int i = 0; i < m_nFixedRows; i++)
  3046. nHeight += GetRowHeight(i);
  3047. return nHeight;
  3048. }
  3049. int CGridCtrl::GetFixedColumnWidth() const
  3050. {
  3051. int nWidth = 0;
  3052. for (int i = 0; i < m_nFixedCols; i++)
  3053. nWidth += GetColumnWidth(i);
  3054. return nWidth;
  3055. }
  3056. BOOL CGridCtrl::AutoSizeColumn(int nCol)
  3057. {
  3058. ASSERT(nCol >= 0 && nCol < m_nCols);
  3059. if (nCol < 0 || nCol >= m_nCols) return FALSE;
  3060. CSize size;
  3061. CDC* pDC = GetDC();
  3062. if (!pDC) return FALSE;
  3063. int nWidth = 0;
  3064. int nNumRows = GetRowCount();
  3065. for (int nRow = 0; nRow < nNumRows; nRow++)
  3066. {
  3067. size = GetCellExtent(nRow, nCol, pDC);
  3068. if (size.cx > nWidth) nWidth = size.cx;
  3069. }
  3070. m_arColWidths[nCol] = nWidth;
  3071. ReleaseDC(pDC);
  3072. ResetScrollBars();
  3073. return TRUE;
  3074. }
  3075. BOOL CGridCtrl::AutoSizeRow(int nRow)
  3076. {
  3077. ASSERT(nRow >= 0 && nRow < m_nRows);
  3078. if (nRow < 0 || nRow >= m_nRows) return FALSE;
  3079. CSize size;
  3080. CDC* pDC = GetDC();
  3081. if (!pDC) return FALSE;
  3082. int nHeight = 0;
  3083. int nNumColumns = GetColumnCount();
  3084. for (int nCol = 0; nCol < nNumColumns; nCol++)
  3085. {
  3086. size = GetCellExtent(nRow, nCol, pDC);
  3087. if (size.cy > nHeight) nHeight = size.cy;
  3088. }
  3089. m_arRowHeights[nRow] = nHeight;
  3090. ReleaseDC(pDC);
  3091. ResetScrollBars();
  3092. return TRUE;
  3093. }
  3094. void CGridCtrl::AutoSizeColumns()
  3095. {
  3096. int nNumColumns = GetColumnCount();
  3097. for (int nCol = 0; nCol < nNumColumns; nCol++)
  3098. AutoSizeColumn(nCol);
  3099. }
  3100. void CGridCtrl::AutoSizeRows()
  3101. {
  3102. int nNumRows = GetRowCount();
  3103. for (int nRow = 0; nRow < nNumRows; nRow++)
  3104. AutoSizeRow(nRow);
  3105. }
  3106. // sizes all rows and columns
  3107. // faster than calling both AutoSizeColumns() and AutoSizeRows()
  3108. void CGridCtrl::AutoSize()
  3109. {
  3110. CDC* pDC = GetDC();
  3111. if (!pDC) return;
  3112. int nNumColumns = GetColumnCount();
  3113. int nNumRows = GetRowCount();
  3114. // initialize column widths to zero
  3115. for (int nCol = 0; nCol < nNumColumns; nCol++)
  3116. m_arColWidths[nCol] = 0;
  3117. // initialize row heights to zero
  3118. for (int nRow = 0; nRow < nNumRows; nRow++)
  3119. m_arRowHeights[nRow] = 0;
  3120. CSize size;
  3121. for (int nCol = 0; nCol < nNumColumns; nCol++)
  3122. for (int nRow = 0; nRow < nNumRows; nRow++)
  3123. {
  3124. size = GetCellExtent(nRow, nCol, pDC);
  3125. if (size.cx > (int) m_arColWidths[nCol]) m_arColWidths[nCol] = size.cx;
  3126. if (size.cy > (int) m_arRowHeights[nRow]) m_arRowHeights[nRow] = size.cy;
  3127. }
  3128. ReleaseDC(pDC);
  3129. if (m_bAllowDraw) {
  3130. ResetScrollBars();
  3131. Invalidate();
  3132. }
  3133. }
  3134. void CGridCtrl::ExpandColumnsToFit()
  3135. {
  3136. if (GetColumnCount() <= 0) return;
  3137. CRect rect;
  3138. GetClientRect(rect);
  3139. long virtualWidth = GetVirtualWidth();
  3140. int nDifference = rect.Width() - (int) virtualWidth;
  3141. int nColumnAdjustment = nDifference / GetColumnCount();
  3142. for (int i = 0; i < GetColumnCount(); i++)
  3143. m_arColWidths[i] += nColumnAdjustment;
  3144. if (nDifference > 0)
  3145. {
  3146. int leftOver = nDifference % GetColumnCount();
  3147. for (int i = 0; i < leftOver; i++)
  3148. m_arColWidths[i] += 1;
  3149. }
  3150. else
  3151. {
  3152. int leftOver = (-nDifference) % GetColumnCount();
  3153. for (int i = 0; i < leftOver; i++)
  3154. m_arColWidths[i] -= 1;
  3155. }
  3156. if (m_bAllowDraw)
  3157. Invalidate();
  3158. }
  3159. void CGridCtrl::ExpandRowsToFit()
  3160. {
  3161. if (GetRowCount() <= 0) return;
  3162. CRect rect;
  3163. GetClientRect(rect);
  3164. long virtualHeight = GetVirtualHeight();
  3165. int nDifference = rect.Height() - (int) virtualHeight;
  3166. int nRowAdjustment = nDifference / GetRowCount();
  3167. for (int i = 0; i < GetRowCount(); i++)
  3168. m_arRowHeights[i] += nRowAdjustment;
  3169. if (nDifference > 0)
  3170. {
  3171. int leftOver = nDifference % GetRowCount();
  3172. for (int i = 0; i < leftOver; i++)
  3173. m_arRowHeights[i] += 1;
  3174. }
  3175. else
  3176. {
  3177. int leftOver = (-nDifference) % GetRowCount();
  3178. for (int i = 0; i < leftOver; i++)
  3179. m_arRowHeights[i] -= 1;
  3180. }
  3181. if (m_bAllowDraw)
  3182. Invalidate();
  3183. }
  3184. void CGridCtrl::ExpandToFit()
  3185. {
  3186. ExpandColumnsToFit(); // This will remove any existing horz scrollbar
  3187. ExpandRowsToFit(); // This will remove any existing vert scrollbar
  3188. ExpandColumnsToFit(); // Just in case the first adjustment was with a vert
  3189. // scrollbar in place
  3190. }
  3191. BOOL CGridCtrl::IsCellFixed(int nRow, int nCol)
  3192. {
  3193. return (nRow < GetFixedRowCount() || nCol < GetFixedColumnCount());
  3194. }
  3195. void CGridCtrl::SetModified(BOOL bModified /*=TRUE*/, int nRow /*=-1*/, int nCol /*=-1*/)
  3196. {
  3197. if (nRow > 0 && nCol > 0)
  3198. {
  3199. if (bModified)
  3200. {
  3201. SetItemState(nRow, nCol, GetItemState(nRow, nCol) | GVIS_MODIFIED);
  3202. m_bModified = TRUE;
  3203. }
  3204. else
  3205. SetItemState(nRow, nCol, GetItemState(nRow, nCol) & ~GVIS_MODIFIED);
  3206. }
  3207. else
  3208. m_bModified = bModified;
  3209. if (!m_bModified)
  3210. {
  3211. for (int row = 0; row < GetRowCount(); row++)
  3212. for (int col = 0; col < GetColumnCount(); col++)
  3213. SetItemState(row, col, GetItemState(row, col) & ~GVIS_MODIFIED);
  3214. }
  3215. }
  3216. BOOL CGridCtrl::GetModified(int nRow /*=-1*/, int nCol /*=-1*/)
  3217. {
  3218. if (nRow > 0 && nCol > 0)
  3219. return ( (GetItemState(nRow, nCol) & GVIS_MODIFIED) == GVIS_MODIFIED );
  3220. else
  3221. return m_bModified;
  3222. }
  3223. /////////////////////////////////////////////////////////////////////////////////////
  3224. // GridCtrl cell visibility tests and invalidation/redraw functions
  3225. // EnsureVisible supplied by Roelf Werkman
  3226. void CGridCtrl::EnsureVisible(int nRow, int nCol)
  3227. {
  3228. CCellRange VisibleCells = GetVisibleNonFixedCellRange();
  3229. int right = nCol - VisibleCells.GetMaxCol();
  3230. int left = VisibleCells.GetMinCol() - nCol;
  3231. int down = nRow - VisibleCells.GetMaxRow();
  3232. int up = VisibleCells.GetMinRow() - nRow;
  3233. while (right > 0)
  3234. {
  3235. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  3236. right--;
  3237. }
  3238. while (left > 0)
  3239. {
  3240. SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  3241. left--;
  3242. }
  3243. while (down > 0)
  3244. {
  3245. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  3246. down--;
  3247. }
  3248. while (up > 0)
  3249. {
  3250. SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  3251. up--;
  3252. }
  3253. // Move one more if we only see a snall bit of the cell
  3254. CRect rectCell, rectWindow;
  3255. GetCellRect(nRow, nCol, rectCell);
  3256. GetClientRect(rectWindow);
  3257. if (rectCell.right > rectWindow.right)
  3258. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  3259. if (rectCell.bottom > rectWindow.bottom)
  3260. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  3261. }
  3262. BOOL CGridCtrl::IsCellEditable(CCellID &cell) const
  3263. {
  3264. return IsCellEditable(cell.row, cell.col);
  3265. }
  3266. BOOL CGridCtrl::IsCellEditable(int nRow, int nCol) const
  3267. {
  3268. return IsEditable() && ((GetItemState(nRow, nCol) & GVIS_READONLY) != GVIS_READONLY);
  3269. }
  3270. BOOL CGridCtrl::IsCellVisible(CCellID cell) const
  3271. {
  3272. return IsCellVisible(cell.row, cell.col);
  3273. }
  3274. BOOL CGridCtrl::IsCellVisible(int nRow, int nCol) const
  3275. {
  3276. if (!IsWindow(m_hWnd))
  3277. return FALSE;
  3278. int x,y;
  3279. CCellID TopLeft;
  3280. if (nCol >= GetFixedColumnCount() || nRow >= GetFixedRowCount())
  3281. {
  3282. TopLeft = GetTopleftNonFixedCell();
  3283. if (nCol >= GetFixedColumnCount() && nCol < TopLeft.col) return FALSE;
  3284. if (nRow >= GetFixedRowCount() && nRow < TopLeft.row) return FALSE;
  3285. }
  3286. CRect rect;
  3287. GetClientRect(rect);
  3288. if (nCol < GetFixedColumnCount())
  3289. {
  3290. x = 0;
  3291. for (int i = 0; i <= nCol; i++)
  3292. {
  3293. if (x >= rect.right) return FALSE;
  3294. x += GetColumnWidth(i);
  3295. }
  3296. }
  3297. else
  3298. {
  3299. x = GetFixedColumnWidth();
  3300. for (int i = TopLeft.col; i <= nCol; i++)
  3301. {
  3302. if (x >= rect.right) return FALSE;
  3303. x += GetColumnWidth(i);
  3304. }
  3305. }
  3306. if (nRow < GetFixedRowCount())
  3307. {
  3308. y = 0;
  3309. for (int i = 0; i <= nRow; i++)
  3310. {
  3311. if (y >= rect.bottom) return FALSE;
  3312. y += GetRowHeight(i);
  3313. }
  3314. }
  3315. else
  3316. {
  3317. if (nRow < TopLeft.row) return FALSE;
  3318. y = GetFixedRowHeight();
  3319. for (int i = TopLeft.row; i <= nRow; i++)
  3320. {
  3321. if (y >= rect.bottom) return FALSE;
  3322. y += GetRowHeight(i);
  3323. }
  3324. }
  3325. return TRUE;
  3326. }
  3327. BOOL CGridCtrl::InvalidateCellRect(const CCellID& cell)
  3328. {
  3329. if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw)
  3330. return FALSE;
  3331. ASSERT(IsValid(cell));
  3332. if (!IsCellVisible(cell.row, cell.col)) return FALSE;
  3333. CRect rect;
  3334. if (!GetCellRect(cell, rect)) return FALSE;
  3335. rect.right++; rect.bottom++;
  3336. InvalidateRect(rect, TRUE);
  3337. return TRUE;
  3338. }
  3339. BOOL CGridCtrl::InvalidateCellRect(const CCellRange& cellRange)
  3340. {
  3341. ASSERT(IsValid(cellRange));
  3342. if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw) return FALSE;
  3343. CCellRange visibleCellRange = GetVisibleNonFixedCellRange().Intersect(cellRange);
  3344. CRect rect;
  3345. if (!GetCellRangeRect(visibleCellRange, rect)) return FALSE;
  3346. rect.right++; rect.bottom++;
  3347. InvalidateRect(rect, TRUE);
  3348. return TRUE;
  3349. }
  3350. /////////////////////////////////////////////////////////////////////////////
  3351. // CGridCtrl Mouse stuff
  3352. // Handles mouse wheel notifications
  3353. // Note - if this doesn't work for win95 then use OnRegisteredMouseWheel instead
  3354. #if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
  3355. BOOL CGridCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
  3356. {
  3357. // A m_nRowsPerWheelNotch value less than 0 indicates that the mouse
  3358. // wheel scrolls whole pages, not just lines.
  3359. if (m_nRowsPerWheelNotch == -1)
  3360. {
  3361. int nPagesScrolled = zDelta / 120;
  3362. if (nPagesScrolled > 0)
  3363. for (int i = 0; i < nPagesScrolled; i++)
  3364. PostMessage(WM_VSCROLL, SB_PAGEUP, 0);
  3365. else
  3366. for (int i = 0; i > nPagesScrolled; i--)
  3367. PostMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
  3368. }
  3369. else
  3370. {
  3371. int nRowsScrolled = m_nRowsPerWheelNotch * zDelta / 120;
  3372. if (nRowsScrolled > 0)
  3373. for (int i = 0; i < nRowsScrolled; i++)
  3374. PostMessage(WM_VSCROLL, SB_LINEUP, 0);
  3375. else
  3376. for (int i = 0; i > nRowsScrolled; i--)
  3377. PostMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  3378. }
  3379. return CWnd::OnMouseWheel(nFlags, zDelta, pt);
  3380. }
  3381. #endif // !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
  3382. void CGridCtrl::OnMouseMove(UINT nFlags, CPoint point)
  3383. {
  3384. CRect rect;
  3385. GetClientRect(rect);
  3386. #ifndef GRIDCONTROL_NO_DRAGDROP
  3387. // If outside client area, return (unless we are drag n dropping)
  3388. if (m_MouseMode != MOUSE_DRAGGING && !rect.PtInRect(point))
  3389. return;
  3390. #endif
  3391. // If the left mouse button is up, then test to see if row/column sizing is imminent
  3392. if (!(nFlags & MK_LBUTTON)
  3393. || (m_MouseMode == MOUSE_NOTHING && (nFlags & MK_LBUTTON)))
  3394. {
  3395. if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
  3396. {
  3397. if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
  3398. {
  3399. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  3400. m_MouseMode = MOUSE_OVER_COL_DIVIDE;
  3401. }
  3402. }
  3403. else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
  3404. {
  3405. if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
  3406. {
  3407. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
  3408. m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
  3409. }
  3410. }
  3411. else if (m_MouseMode != MOUSE_NOTHING)
  3412. {
  3413. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  3414. m_MouseMode = MOUSE_NOTHING;
  3415. }
  3416. #ifndef GRIDCONTROL_NO_TITLETIPS
  3417. if (m_MouseMode == MOUSE_NOTHING && m_bTitleTips)
  3418. {
  3419. CCellID idCurrentCell = GetCellFromPt(point);
  3420. CRect TextRect, CellRect;
  3421. if (GetTextRect(idCurrentCell.row, idCurrentCell.col, TextRect) &&
  3422. GetCellRect(idCurrentCell.row, idCurrentCell.col, CellRect))
  3423. {
  3424. // m_TitleTip.Show(TextRect,
  3425. // GetItemText(idCurrentCell.row, idCurrentCell.col),
  3426. // 0,
  3427. // CellRect,
  3428. // GetItemFont(idCurrentCell.row, idCurrentCell.col));
  3429. }
  3430. }
  3431. #endif
  3432. m_LastMousePoint = point;
  3433. return;
  3434. }
  3435. if (!IsValid(m_LeftClickDownCell))
  3436. {
  3437. m_LastMousePoint = point;
  3438. return;
  3439. }
  3440. // If the left mouse button is down, then process appropriately
  3441. if (nFlags & MK_LBUTTON)
  3442. {
  3443. switch(m_MouseMode)
  3444. {
  3445. case MOUSE_SELECT_ALL:
  3446. break;
  3447. case MOUSE_SELECT_COL:
  3448. case MOUSE_SELECT_ROW:
  3449. case MOUSE_SELECT_CELLS:
  3450. {
  3451. CCellID idCurrentCell = GetCellFromPt(point);
  3452. if (!IsValid(idCurrentCell))
  3453. return;
  3454. if (idCurrentCell != GetFocusCell())
  3455. {
  3456. OnSelecting(idCurrentCell);
  3457. //SetFocusCell(max(idCurrentCell.row, m_nFixedRows),
  3458. // max(idCurrentCell.col, m_nFixedCols));
  3459. if (idCurrentCell.row >= m_nFixedRows &&
  3460. idCurrentCell.col >= m_nFixedCols)
  3461. {
  3462. SetFocusCell(idCurrentCell);
  3463. }
  3464. }
  3465. break;
  3466. }
  3467. case MOUSE_SIZING_COL:
  3468. {
  3469. CDC* pDC = GetDC();
  3470. if (!pDC) break;
  3471. CRect oldInvertedRect(m_LastMousePoint.x, rect.top,
  3472. m_LastMousePoint.x + 2, rect.bottom);
  3473. pDC->InvertRect(&oldInvertedRect);
  3474. CRect newInvertedRect(point.x, rect.top,
  3475. point.x + 2, rect.bottom);
  3476. pDC->InvertRect(&newInvertedRect);
  3477. ReleaseDC(pDC);
  3478. }
  3479. break;
  3480. case MOUSE_SIZING_ROW:
  3481. {
  3482. CDC* pDC = GetDC();
  3483. if (!pDC) break;
  3484. CRect oldInvertedRect(rect.left, m_LastMousePoint.y,
  3485. rect.right, m_LastMousePoint.y + 2);
  3486. pDC->InvertRect(&oldInvertedRect);
  3487. CRect newInvertedRect(rect.left, point.y,
  3488. rect.right, point.y + 2);
  3489. pDC->InvertRect(&newInvertedRect);
  3490. ReleaseDC(pDC);
  3491. }
  3492. break;
  3493. #ifndef GRIDCONTROL_NO_DRAGDROP
  3494. case MOUSE_PREPARE_DRAG:
  3495. OnBeginDrag();
  3496. break;
  3497. #endif
  3498. }
  3499. }
  3500. m_LastMousePoint = point;
  3501. }
  3502. void CGridCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
  3503. {
  3504. if (m_MouseMode == MOUSE_OVER_COL_DIVIDE)
  3505. {
  3506. CCellID cell = GetCellFromPt(point);
  3507. ASSERT(IsValid(cell));
  3508. CPoint start;
  3509. if (!GetCellOrigin(0, cell.col, &start)) return;
  3510. if (point.x - start.x <= m_nResizeCaptureRange) // Clicked right of border
  3511. cell.col--;
  3512. AutoSizeColumn(cell.col);
  3513. Invalidate();
  3514. }
  3515. else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE)
  3516. {
  3517. CCellID cell = GetCellFromPt(point);
  3518. ASSERT(IsValid(cell));
  3519. CPoint start;
  3520. if (!GetCellOrigin(0, cell.col, &start)) return;
  3521. if (point.y - start.y <= m_nResizeCaptureRange) // Clicked below border
  3522. cell.row--;
  3523. AutoSizeRow(cell.row);
  3524. Invalidate();
  3525. }
  3526. else if (m_MouseMode == MOUSE_NOTHING)
  3527. {
  3528. if (m_LeftClickDownCell.row >= m_nFixedRows &&
  3529. IsValid(m_LeftClickDownCell) &&
  3530. m_LeftClickDownCell.col >= m_nFixedCols)
  3531. {
  3532. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, VK_LBUTTON);
  3533. }
  3534. else if (m_bListMode)
  3535. {
  3536. CCellID cell = GetCellFromPt(point);
  3537. if (!IsValid(cell)) return;
  3538. if (cell.row >= m_nFixedRows && cell.col < GetFixedColumnCount())
  3539. OnEditCell(cell.row, cell.col, VK_LBUTTON);
  3540. }
  3541. }
  3542. CWnd::OnLButtonDblClk(nFlags, point);
  3543. }
  3544. void CGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
  3545. {
  3546. HWND hOldFocusWnd = ::GetFocus();
  3547. m_LeftClickDownPoint = point;
  3548. m_LeftClickDownCell = GetCellFromPt(point);
  3549. if (!IsValid(m_LeftClickDownCell)) return;
  3550. m_SelectionStartCell = (nFlags & MK_SHIFT)? m_idCurrentCell : m_LeftClickDownCell;
  3551. SetFocus(); // Auto-destroy any InPlaceEdit's
  3552. // If the user clicks on the current cell, then prepare to edit it.
  3553. // (If the user moves the mouse, then dragging occurs)
  3554. if (m_LeftClickDownCell == m_idCurrentCell)
  3555. {
  3556. m_MouseMode = MOUSE_PREPARE_EDIT;
  3557. return;
  3558. }
  3559. else if (m_MouseMode != MOUSE_OVER_COL_DIVIDE &&
  3560. m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
  3561. {
  3562. SetFocusCell(-1,-1);
  3563. SetFocusCell(max(m_LeftClickDownCell.row, m_nFixedRows),
  3564. max(m_LeftClickDownCell.col, m_nFixedCols));
  3565. }
  3566. #ifndef GRIDCONTROL_NO_DRAGDROP
  3567. // If the user clicks on a selected cell, then prepare to drag it.
  3568. // (If the user moves the mouse, then dragging occurs)
  3569. if (m_bAllowDragAndDrop && hOldFocusWnd == GetSafeHwnd() &&
  3570. GetItemState(m_LeftClickDownCell.row, m_LeftClickDownCell.col) & GVNI_SELECTED)
  3571. {
  3572. m_MouseMode = MOUSE_PREPARE_DRAG;
  3573. return;
  3574. }
  3575. #endif
  3576. SetCapture();
  3577. if (m_MouseMode == MOUSE_NOTHING)
  3578. {
  3579. if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
  3580. {
  3581. if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
  3582. {
  3583. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  3584. m_MouseMode = MOUSE_OVER_COL_DIVIDE;
  3585. }
  3586. }
  3587. else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
  3588. {
  3589. if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
  3590. {
  3591. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
  3592. m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
  3593. }
  3594. }
  3595. //else if (m_MouseMode != MOUSE_NOTHING)
  3596. //{
  3597. // SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  3598. // m_MouseMode = MOUSE_NOTHING;
  3599. //}
  3600. }
  3601. if (m_MouseMode == MOUSE_OVER_COL_DIVIDE) // sizing column
  3602. {
  3603. m_MouseMode = MOUSE_SIZING_COL;
  3604. CPoint start;
  3605. if (!GetCellOrigin(0, m_LeftClickDownCell.col, &start)) return;
  3606. CRect rect;
  3607. GetClientRect(rect);
  3608. CRect invertedRect(point.x, rect.top, point.x + 2, rect.bottom);
  3609. CDC* pDC = GetDC();
  3610. if (pDC) {
  3611. pDC->InvertRect(&invertedRect);
  3612. ReleaseDC(pDC);
  3613. }
  3614. if (point.x - start.x <= m_nResizeCaptureRange) // clicked right of border
  3615. if (!GetCellOrigin(0, --m_LeftClickDownCell.col, &start)) return;
  3616. rect.left = start.x;
  3617. ClientToScreen(rect);
  3618. #ifndef _WIN32_WCE_NO_CURSOR
  3619. ClipCursor(rect);
  3620. #endif
  3621. }
  3622. else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE) // sizing row
  3623. {
  3624. m_MouseMode = MOUSE_SIZING_ROW;
  3625. CPoint start;
  3626. if (!GetCellOrigin(m_LeftClickDownCell, &start)) return;
  3627. CRect rect;
  3628. GetClientRect(rect);
  3629. CRect invertedRect(rect.left, point.y, rect.right, point.y + 2);
  3630. CDC* pDC = GetDC();
  3631. if (pDC) {
  3632. pDC->InvertRect(&invertedRect);
  3633. ReleaseDC(pDC);
  3634. }
  3635. if (point.y - start.y <= m_nResizeCaptureRange) // clicked below border
  3636. if (!GetCellOrigin(--m_LeftClickDownCell.row, 0, &start)) return;
  3637. rect.top = start.y;
  3638. ClientToScreen(rect);
  3639. #ifndef _WIN32_WCE_NO_CURSOR
  3640. ClipCursor(rect);
  3641. #endif
  3642. }
  3643. else // not sizing or editing -- selecting
  3644. {
  3645. // If Ctrl pressed, save the current cell selection. This will get added
  3646. // to the new cell selection at the end of the cell selection process
  3647. m_PrevSelectedCellMap.RemoveAll();
  3648. if (nFlags & MK_CONTROL) {
  3649. for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
  3650. {
  3651. DWORD key;
  3652. CCellID cell;
  3653. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  3654. m_PrevSelectedCellMap.SetAt(key, cell);
  3655. }
  3656. }
  3657. if (m_LeftClickDownCell.row < GetFixedRowCount())
  3658. OnFixedRowClick(m_LeftClickDownCell);
  3659. else if (m_LeftClickDownCell.col < GetFixedColumnCount())
  3660. OnFixedColumnClick(m_LeftClickDownCell);
  3661. else
  3662. {
  3663. m_MouseMode = m_bListMode? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
  3664. OnSelecting(m_LeftClickDownCell);
  3665. }
  3666. m_nTimerID = SetTimer(WM_LBUTTONDOWN, m_nTimerInterval, 0);
  3667. }
  3668. m_LastMousePoint = point;
  3669. }
  3670. void CGridCtrl::OnLButtonUp(UINT nFlags, CPoint point)
  3671. {
  3672. CWnd::OnLButtonUp(nFlags, point);
  3673. #ifndef _WIN32_WCE_NO_CURSOR
  3674. ClipCursor(NULL);
  3675. #endif
  3676. if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
  3677. {
  3678. ReleaseCapture();
  3679. KillTimer(m_nTimerID);
  3680. m_nTimerID = 0;
  3681. }
  3682. // m_MouseMode == MOUSE_PREPARE_EDIT only if user clicked down on current cell
  3683. // and then didn't move mouse before clicking up (releasing button)
  3684. if (m_MouseMode == MOUSE_PREPARE_EDIT)
  3685. {
  3686. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, VK_LBUTTON);
  3687. }
  3688. #ifndef GRIDCONTROL_NO_DRAGDROP
  3689. // m_MouseMode == MOUSE_PREPARE_DRAG only if user clicked down on a selected cell
  3690. // and then didn't move mouse before clicking up (releasing button)
  3691. else if (m_MouseMode == MOUSE_PREPARE_DRAG)
  3692. {
  3693. ResetSelectedRange();
  3694. }
  3695. #endif
  3696. else if (m_MouseMode == MOUSE_SIZING_COL)
  3697. {
  3698. CRect rect;
  3699. GetClientRect(rect);
  3700. CRect invertedRect(m_LastMousePoint.x, rect.top, m_LastMousePoint.x + 2, rect.bottom);
  3701. CDC* pDC = GetDC();
  3702. if (pDC) {
  3703. pDC->InvertRect(&invertedRect);
  3704. ReleaseDC(pDC);
  3705. }
  3706. if (m_LeftClickDownPoint != point)
  3707. {
  3708. CPoint start;
  3709. if (!GetCellOrigin(m_LeftClickDownCell, &start)) return;
  3710. SetColumnWidth(m_LeftClickDownCell.col, point.x - start.x);
  3711. ResetScrollBars();
  3712. Invalidate();
  3713. }
  3714. }
  3715. else if (m_MouseMode == MOUSE_SIZING_ROW)
  3716. {
  3717. CRect rect;
  3718. GetClientRect(rect);
  3719. CRect invertedRect(rect.left, m_LastMousePoint.y, rect.right, m_LastMousePoint.y + 2);
  3720. CDC* pDC = GetDC();
  3721. if (pDC) {
  3722. pDC->InvertRect(&invertedRect);
  3723. ReleaseDC(pDC);
  3724. }
  3725. if (m_LeftClickDownPoint != point)
  3726. {
  3727. CPoint start;
  3728. if (!GetCellOrigin(m_LeftClickDownCell, &start)) return;
  3729. SetRowHeight(m_LeftClickDownCell.row, point.y - start.y);
  3730. ResetScrollBars();
  3731. Invalidate();
  3732. }
  3733. }
  3734. m_MouseMode = MOUSE_NOTHING;
  3735. #ifndef _WIN32_WCE_NO_CURSOR
  3736. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  3737. #endif
  3738. if (!IsValid(m_LeftClickDownCell)) return;
  3739. CWnd *pOwner = GetOwner();
  3740. if (pOwner && IsWindow(pOwner->m_hWnd))
  3741. pOwner->PostMessage(WM_COMMAND, MAKELONG(GetDlgCtrlID(), BN_CLICKED),
  3742. (LPARAM) GetSafeHwnd());
  3743. }
  3744. #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  3745. /////////////////////////////////////////////////////////////////////////////
  3746. // CGridCtrl printing
  3747. void CGridCtrl::Print()
  3748. {
  3749. CDC dc;
  3750. CPrintDialog printDlg(FALSE);
  3751. if (printDlg.DoModal() != IDOK) // Get printer settings from user
  3752. return;
  3753. dc.Attach(printDlg.GetPrinterDC()); // attach a printer DC
  3754. dc.m_bPrinting = TRUE;
  3755. CString strTitle;
  3756. strTitle.LoadString(AFX_IDS_APP_TITLE);
  3757. DOCINFO di; // Initialise print doc details
  3758. memset(&di, 0, sizeof (DOCINFO));
  3759. di.cbSize = sizeof (DOCINFO);
  3760. di.lpszDocName = strTitle;
  3761. BOOL bPrintingOK = dc.StartDoc(&di); // Begin a new print job
  3762. CPrintInfo Info;
  3763. Info.m_rectDraw.SetRect(0,0, dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES));
  3764. OnBeginPrinting(&dc, &Info); // Initialise printing
  3765. for (UINT page = Info.GetMinPage(); page <= Info.GetMaxPage() && bPrintingOK; page++)
  3766. {
  3767. dc.StartPage(); // begin new page
  3768. Info.m_nCurPage = page;
  3769. OnPrint(&dc, &Info); // Print page
  3770. bPrintingOK = (dc.EndPage() > 0); // end page
  3771. }
  3772. OnEndPrinting(&dc, &Info); // Clean up after printing
  3773. if (bPrintingOK)
  3774. dc.EndDoc(); // end a print job
  3775. else
  3776. dc.AbortDoc(); // abort job.
  3777. dc.Detach(); // detach the printer DC
  3778. }
  3779. /////////////////////////////////////////////////////////////////////////////
  3780. // CGridCtrl printing overridables - for Doc/View print/print preview framework
  3781. void CGridCtrl::OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo)
  3782. {
  3783. // OnBeginPrinting() is called after the user has committed to
  3784. // printing by OK'ing the Print dialog, and after the framework
  3785. // has created a CDC object for the printer or the preview view.
  3786. // This is the right opportunity to set up the page range.
  3787. // Given the CDC object, we can determine how many rows will
  3788. // fit on a page, so we can in turn determine how many printed
  3789. // pages represent the entire document.
  3790. ASSERT(pDC && pInfo);
  3791. if (!pDC || !pInfo) return;
  3792. int nMaxRowCount = GetRowCount() - GetFixedRowCount();
  3793. if (!nMaxRowCount) return;
  3794. // Get a DC for the current window (will be a screen DC for print previewing)
  3795. CDC *pCurrentDC = GetDC(); // will have dimensions of the client area
  3796. if (!pCurrentDC) return;
  3797. CSize PaperPixelsPerInch(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
  3798. CSize ScreenPixelsPerInch(pCurrentDC->GetDeviceCaps(LOGPIXELSX), pCurrentDC->GetDeviceCaps(LOGPIXELSY));
  3799. // Create the printer font
  3800. int nFontSize = -9;
  3801. CString strFontName = "Times New Roman";
  3802. m_PrinterFont.CreateFont(nFontSize, 0,0,0, FW_NORMAL, 0,0,0, DEFAULT_CHARSET,
  3803. OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,
  3804. DEFAULT_PITCH | FF_DONTCARE, strFontName);
  3805. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  3806. // Get the average character width (in GridCtrl units) and hence the margins
  3807. m_CharSize = pDC->GetTextExtent(_T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSATUVWXYZ"),52);
  3808. m_CharSize.cx /= 52;
  3809. int nMargins = (LEFT_MARGIN+RIGHT_MARGIN)*m_CharSize.cx;
  3810. // Get the page sizes (physical and logical)
  3811. m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
  3812. m_LogicalPageSize.cx = GetVirtualWidth()+nMargins;
  3813. #ifdef _WIN32_WCE
  3814. m_LogicalPageSize.cy = (m_LogicalPageSize.cx * m_PaperSize.cy) / m_PaperSize.cx;
  3815. #else
  3816. m_LogicalPageSize.cy = MulDiv(m_LogicalPageSize.cx, m_PaperSize.cy, m_PaperSize.cx);
  3817. #endif
  3818. m_nPageHeight = m_LogicalPageSize.cy - GetFixedRowHeight()
  3819. - (HEADER_HEIGHT+FOOTER_HEIGHT + 2*GAP)*m_CharSize.cy;
  3820. // Get the number of pages. Assumes no row is bigger than the page size.
  3821. int nTotalRowHeight = 0;
  3822. int nNumPages = 1;
  3823. for (int row = GetFixedRowCount(); row < GetRowCount(); row++)
  3824. {
  3825. nTotalRowHeight += GetRowHeight(row);
  3826. if (nTotalRowHeight > m_nPageHeight) {
  3827. nNumPages++;
  3828. nTotalRowHeight = GetRowHeight(row);
  3829. }
  3830. }
  3831. // Set up the print info
  3832. pInfo->SetMaxPage(nNumPages);
  3833. pInfo->m_nCurPage = 1; // start printing at page# 1
  3834. ReleaseDC(pCurrentDC);
  3835. pDC->SelectObject(pOldFont);
  3836. }
  3837. void CGridCtrl::OnPrint(CDC *pDC, CPrintInfo *pInfo)
  3838. {
  3839. if (!pDC || !pInfo) return;
  3840. //CRect rcPage(pInfo->m_rectDraw);
  3841. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  3842. // Set the page map mode to use GridCtrl units, and setup margin
  3843. pDC->SetMapMode(MM_ANISOTROPIC);
  3844. pDC->SetWindowExt(m_LogicalPageSize);
  3845. pDC->SetViewportExt(m_PaperSize);
  3846. pDC->SetWindowOrg(-LEFT_MARGIN*m_CharSize.cx, 0);
  3847. // Header
  3848. pInfo->m_rectDraw.top = 0;
  3849. pInfo->m_rectDraw.left = 0;
  3850. pInfo->m_rectDraw.right = m_LogicalPageSize.cx - (LEFT_MARGIN+RIGHT_MARGIN)*m_CharSize.cx;
  3851. pInfo->m_rectDraw.bottom = HEADER_HEIGHT*m_CharSize.cy;
  3852. PrintHeader(pDC, pInfo);
  3853. pDC->OffsetWindowOrg(0, -HEADER_HEIGHT*m_CharSize.cy);
  3854. // Gap between header and column headings
  3855. pDC->OffsetWindowOrg(0, -GAP*m_CharSize.cy);
  3856. // Print the column headings
  3857. pInfo->m_rectDraw.bottom = GetFixedRowHeight();
  3858. PrintColumnHeadings(pDC, pInfo);
  3859. pDC->OffsetWindowOrg(0, -GetFixedRowHeight());
  3860. // We need to find out which row to start printing for this page.
  3861. int nTotalRowHeight = 0;
  3862. UINT nNumPages = 1;
  3863. int nCurrPrintRow = GetFixedRowCount();
  3864. while (nCurrPrintRow < GetRowCount() && nNumPages < pInfo->m_nCurPage)
  3865. {
  3866. nTotalRowHeight += GetRowHeight(nCurrPrintRow);
  3867. if (nTotalRowHeight > m_nPageHeight) {
  3868. nNumPages++;
  3869. if (nNumPages == pInfo->m_nCurPage) break;
  3870. nTotalRowHeight = GetRowHeight(nCurrPrintRow);
  3871. }
  3872. nCurrPrintRow++;
  3873. }
  3874. if (nCurrPrintRow >= GetRowCount()) return;
  3875. // Draw as many rows as will fit on the printed page.
  3876. // Clip the printed page so that there is no partially shown
  3877. // row at the bottom of the page (the same row which will be fully
  3878. // shown at the top of the next page).
  3879. BOOL bFirstPrintedRow = TRUE;
  3880. CRect rect;
  3881. rect.bottom = -1;
  3882. while (nCurrPrintRow < GetRowCount())
  3883. {
  3884. rect.top = rect.bottom+1;
  3885. rect.bottom = rect.top + GetRowHeight(nCurrPrintRow) - 1;
  3886. if (rect.bottom > m_nPageHeight) break; // Gone past end of page
  3887. rect.right = -1;
  3888. for (int col = 0; col < GetColumnCount(); col++)
  3889. {
  3890. rect.left = rect.right+1;
  3891. rect.right = rect.left + GetColumnWidth(col) - 1;
  3892. DrawCell(pDC, nCurrPrintRow, col, rect);
  3893. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  3894. {
  3895. int Overlap = (col == 0)? 0:1;
  3896. pDC->MoveTo(rect.left-Overlap, rect.bottom);
  3897. pDC->LineTo(rect.right, rect.bottom);
  3898. if (nCurrPrintRow == 0) {
  3899. pDC->MoveTo(rect.left-Overlap, rect.top);
  3900. pDC->LineTo(rect.right, rect.top);
  3901. }
  3902. }
  3903. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  3904. {
  3905. int Overlap = (bFirstPrintedRow)? 0:1;
  3906. pDC->MoveTo(rect.right, rect.top-Overlap);
  3907. pDC->LineTo(rect.right, rect.bottom);
  3908. if (col == 0) {
  3909. pDC->MoveTo(rect.left, rect.top-Overlap);
  3910. pDC->LineTo(rect.left, rect.bottom);
  3911. }
  3912. }
  3913. }
  3914. nCurrPrintRow++;
  3915. bFirstPrintedRow = FALSE;
  3916. }
  3917. // Footer
  3918. pInfo->m_rectDraw.bottom = FOOTER_HEIGHT*m_CharSize.cy;
  3919. pDC->SetWindowOrg(-LEFT_MARGIN*m_CharSize.cx, -m_LogicalPageSize.cy + FOOTER_HEIGHT*m_CharSize.cy);
  3920. PrintFooter(pDC, pInfo);
  3921. // SetWindowOrg back for next page
  3922. pDC->SetWindowOrg(0,0);
  3923. pDC->SelectObject(pOldFont);
  3924. }
  3925. void CGridCtrl::PrintColumnHeadings(CDC *pDC, CPrintInfo* /*pInfo*/)
  3926. {
  3927. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  3928. CRect rect;
  3929. rect.bottom = -1;
  3930. for (int row = 0; row < GetFixedRowCount(); row++)
  3931. {
  3932. rect.top = rect.bottom+1;
  3933. rect.bottom = rect.top + GetRowHeight(row) - 1;
  3934. rect.right = -1;
  3935. for (int col = 0; col < GetColumnCount(); col++)
  3936. {
  3937. rect.left = rect.right+1;
  3938. rect.right = rect.left + GetColumnWidth(col) - 1;
  3939. DrawFixedCell(pDC, row, col, rect);
  3940. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  3941. {
  3942. int Overlap = (col == 0)? 0:1;
  3943. pDC->MoveTo(rect.left-Overlap, rect.bottom);
  3944. pDC->LineTo(rect.right, rect.bottom);
  3945. if (row == 0) {
  3946. pDC->MoveTo(rect.left-Overlap, rect.top);
  3947. pDC->LineTo(rect.right, rect.top);
  3948. }
  3949. }
  3950. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  3951. {
  3952. int Overlap = (row == 0)? 0:1;
  3953. pDC->MoveTo(rect.right, rect.top-Overlap);
  3954. pDC->LineTo(rect.right, rect.bottom);
  3955. if (col == 0) {
  3956. pDC->MoveTo(rect.left, rect.top-Overlap);
  3957. pDC->LineTo(rect.left, rect.bottom);
  3958. }
  3959. }
  3960. }
  3961. }
  3962. pDC->SelectObject(pOldFont);
  3963. }
  3964. void CGridCtrl::PrintHeader(CDC *pDC, CPrintInfo *pInfo)
  3965. {
  3966. CRect rc(pInfo->m_rectDraw);
  3967. CString strHeaderString;
  3968. CFont BoldFont;
  3969. LOGFONT lf;
  3970. //create bold font for header and footer
  3971. VERIFY(m_PrinterFont.GetLogFont(&lf));
  3972. lf.lfWeight = FW_BOLD;
  3973. VERIFY(BoldFont.CreateFontIndirect(&lf));
  3974. CFont *pNormalFont = pDC->SelectObject(&BoldFont);
  3975. int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
  3976. // print App title on top right margin
  3977. strHeaderString.LoadString(AFX_IDS_APP_TITLE);
  3978. pDC->DrawText(strHeaderString, &rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  3979. // print parent window title in the centre (Gert Rijs)
  3980. CWnd *pParentWnd = GetParent();
  3981. while (pParentWnd)
  3982. {
  3983. pParentWnd->GetWindowText(strHeaderString);
  3984. if (strHeaderString.GetLength()) // can happen if it is a CView, CChildFrm has the title
  3985. break;
  3986. pParentWnd = pParentWnd->GetParent();
  3987. }
  3988. pDC->DrawText(strHeaderString, &rc, DT_CENTER | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  3989. pDC->SetBkMode(nPrevBkMode);
  3990. pDC->SelectObject(pNormalFont);
  3991. BoldFont.DeleteObject();
  3992. pDC->SelectStockObject(BLACK_PEN);
  3993. pDC->MoveTo(rc.left, rc.bottom);
  3994. pDC->LineTo(rc.right, rc.bottom);
  3995. }
  3996. //print footer with a line and date, and page number
  3997. void CGridCtrl::PrintFooter(CDC *pDC, CPrintInfo *pInfo)
  3998. {
  3999. CRect rc(pInfo->m_rectDraw);
  4000. CFont BoldFont;
  4001. LOGFONT lf;
  4002. //draw line
  4003. pDC->MoveTo(rc.left, rc.top);
  4004. pDC->LineTo(rc.right, rc.top);
  4005. //create bold font for header and footer
  4006. m_PrinterFont.GetLogFont(&lf);
  4007. lf.lfWeight = FW_BOLD;
  4008. BoldFont.CreateFontIndirect(&lf);
  4009. CFont *pNormalFont = pDC->SelectObject(&BoldFont);
  4010. int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
  4011. // draw page number
  4012. CString sTemp ;
  4013. rc.OffsetRect(0, m_CharSize.cy/2);
  4014. sTemp.Format(_T("Page %d of %d"), pInfo->m_nCurPage, pInfo->GetMaxPage());
  4015. pDC->DrawText(sTemp,-1,rc, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
  4016. CTime t = CTime::GetCurrentTime();
  4017. sTemp = t.Format(_T("%c"));
  4018. pDC->DrawText(sTemp,-1,rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
  4019. pDC->SetBkMode(nPrevBkMode);
  4020. pDC->SelectObject(pNormalFont);
  4021. BoldFont.DeleteObject();
  4022. }
  4023. void CGridCtrl::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
  4024. {
  4025. m_PrinterFont.DeleteObject();
  4026. }
  4027. #endif // !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  4028. #ifndef _WIN32_WCE
  4029. /////////////////////////////////////////////////////////////////////////////
  4030. // CGridCtrl persistance
  4031. BOOL CGridCtrl::Save(LPCTSTR filename)
  4032. {
  4033. CStdioFile File;
  4034. CFileException ex;
  4035. if (!File.Open(filename, CFile::modeWrite | CFile::modeCreate| CFile::typeText, &ex)) {
  4036. ex.ReportError();
  4037. return FALSE;
  4038. }
  4039. TRY {
  4040. int nNumColumns = GetColumnCount();
  4041. for (int i = 0; i < nNumColumns; i++) {
  4042. File.WriteString(GetItemText(0,i));
  4043. File.WriteString((i==(nNumColumns-1))? _T("\n"):_T(","));
  4044. }
  4045. for (int i = 0; i < GetRowCount(); i++) {
  4046. for (int j = 0; j < nNumColumns; j++) {
  4047. File.WriteString(GetItemText(i,j));
  4048. File.WriteString((j==(nNumColumns-1))? _T("\n"):_T(","));
  4049. }
  4050. }
  4051. File.Close();
  4052. }
  4053. CATCH (CFileException, e) {
  4054. AfxMessageBox(_T("Unable to save grid list"));
  4055. e->Delete();
  4056. return FALSE;
  4057. }
  4058. END_CATCH
  4059. return TRUE;
  4060. }
  4061. BOOL CGridCtrl::Load(LPCTSTR filename)
  4062. {
  4063. TCHAR *token, *end;
  4064. TCHAR buffer[1024];
  4065. CStdioFile File;
  4066. CFileException ex;
  4067. if (!File.Open(filename, CFile::modeRead | CFile::typeText)) {
  4068. ex.ReportError();
  4069. return FALSE;
  4070. }
  4071. DeleteAllItems();
  4072. TRY {
  4073. // Read Header off file
  4074. File.ReadString(buffer, 1024);
  4075. // Get first token
  4076. for (token=buffer, end=buffer;
  4077. *end && (*end != _T(',')) && (*end != _T('\n')); end++);
  4078. if ((*end == _T('\0')) && (token == end)) token = NULL;
  4079. *end = _T('\0');
  4080. while (token)
  4081. {
  4082. InsertColumn(token);
  4083. // Get next token
  4084. for (token=++end; *end && (*end != _T(',')) && (*end != _T('\n'));
  4085. end++);
  4086. if ((*end == _T('\0')) && (token == end)) token = NULL;
  4087. *end = _T('\0');
  4088. }
  4089. // Read in rest of data
  4090. int nItem = 0;
  4091. while (File.ReadString(buffer, 1024)) {
  4092. // Get first token
  4093. for (token=buffer, end=buffer;
  4094. *end && (*end != _T(',')) && (*end != _T('\n')); end++);
  4095. if ((*end == _T('\0')) && (token == end)) token = NULL;
  4096. *end = _T('\0');
  4097. int nSubItem = 0;
  4098. while (token) {
  4099. if (!nSubItem)
  4100. InsertRow(token);
  4101. else
  4102. SetItemText(nItem, nSubItem, token);
  4103. // Get next token
  4104. for (token=++end; *end && (*end != _T(',')) && (*end != _T('\n'));
  4105. end++);
  4106. if ((*end == _T('\0')) && (token == end)) token = NULL;
  4107. *end = _T('\0');
  4108. nSubItem++;
  4109. }
  4110. nItem++;
  4111. }
  4112. AutoSizeColumns();
  4113. File.Close();
  4114. }
  4115. CATCH (CFileException, e) {
  4116. AfxMessageBox(_T("Unable to load grid data"));
  4117. e->Delete();
  4118. return FALSE;
  4119. }
  4120. END_CATCH
  4121. return TRUE;
  4122. }
  4123. #endif
  4124. /////////////////////////////////////////////////////////////////////////////
  4125. // CGridCtrl overrideables
  4126. #ifndef GRIDCONTROL_NO_DRAGDROP
  4127. // This is no longer needed since I've changed to OLE drag and drop - but it's
  4128. // still cool code. :)
  4129. CImageList* CGridCtrl::CreateDragImage(CPoint *pHotSpot)
  4130. {
  4131. CDC* pDC = GetDC();
  4132. if (!pDC) return NULL;
  4133. CRect rect;
  4134. CCellID cell = GetFocusCell();
  4135. if (!GetCellRect(cell.row, cell.col, rect)) return NULL;
  4136. // Translate coordinate system
  4137. rect.BottomRight() = CPoint(rect.Width(), rect.Height());
  4138. rect.TopLeft() = CPoint(0,0);
  4139. *pHotSpot = rect.BottomRight();
  4140. // Create a new imagelist (the caller of this function has responsibility
  4141. // for deleting this list)
  4142. CImageList* pList = new CImageList;
  4143. if (!pList || !pList->Create(rect.Width(), rect.Height(), ILC_MASK, 1,1))
  4144. {
  4145. if (pList) delete pList;
  4146. return NULL;
  4147. }
  4148. // Create mem DC and bitmap
  4149. CDC MemDC;
  4150. CBitmap bm;
  4151. MemDC.CreateCompatibleDC(pDC);
  4152. bm.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
  4153. CBitmap* pOldBitmap = MemDC.SelectObject(&bm);
  4154. MemDC.SetWindowOrg(0,0);
  4155. // Draw cell onto bitmap in memDC
  4156. DrawCell(&MemDC, cell.row, cell.col, rect, TRUE);
  4157. // Clean up
  4158. MemDC.SelectObject(pOldBitmap);
  4159. ReleaseDC(pDC);
  4160. // Add the bitmap we just drew to the image list.
  4161. pList->Add(&bm, GetTextBkColor());
  4162. bm.DeleteObject();
  4163. return pList;
  4164. }
  4165. #endif
  4166. void CGridCtrl::OnFixedRowClick(CCellID& cell)
  4167. {
  4168. if (!IsValid(cell))
  4169. return;
  4170. if (m_bListMode)
  4171. {
  4172. if (!m_bSortOnClick)
  4173. return;
  4174. CWaitCursor waiter;
  4175. if (cell.col == m_SortColumn)
  4176. m_bAscending = !m_bAscending;
  4177. else
  4178. {
  4179. m_bAscending = TRUE;
  4180. m_SortColumn = cell.col;
  4181. }
  4182. SortTextItems(m_SortColumn, m_bAscending);
  4183. Invalidate();
  4184. }
  4185. else if (cell.col < GetFixedColumnCount())
  4186. {
  4187. m_MouseMode = MOUSE_SELECT_ALL;
  4188. OnSelecting(cell);
  4189. }
  4190. else
  4191. {
  4192. m_MouseMode = MOUSE_SELECT_COL;
  4193. OnSelecting(cell);
  4194. }
  4195. }
  4196. void CGridCtrl::OnFixedColumnClick(CCellID& cell)
  4197. {
  4198. if (!IsValid(cell))
  4199. return;
  4200. // if (m_bListMode && (GetItemState(cell.row, m_nFixedCols) & GVNI_SELECTED))
  4201. // {
  4202. // OnEditCell(cell.row, cell.col, VK_LBUTTON);
  4203. // return;
  4204. // }
  4205. if (cell.row < GetFixedRowCount())
  4206. {
  4207. m_MouseMode = MOUSE_SELECT_ALL;
  4208. OnSelecting(cell);
  4209. }
  4210. else
  4211. {
  4212. m_MouseMode = MOUSE_SELECT_ROW;
  4213. OnSelecting(cell);
  4214. }
  4215. }
  4216. // Gets the extent of the text pointed to by str (no CDC needed)
  4217. // By default this uses the selected font (which is a bigger font)
  4218. CSize CGridCtrl::GetTextExtent(LPCTSTR str, BOOL bUseSelectedFont /* = TRUE */)
  4219. {
  4220. CDC* pDC = GetDC();
  4221. if (!pDC) return CSize(0,0);
  4222. CFont *pOldFont, font;
  4223. if (bUseSelectedFont)
  4224. {
  4225. LOGFONT lf;
  4226. memcpy(&lf, &m_Logfont, sizeof(LOGFONT));
  4227. lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
  4228. font.CreateFontIndirect(&lf);
  4229. pOldFont = pDC->SelectObject(&font);
  4230. }
  4231. else
  4232. pOldFont = pDC->SelectObject(&m_Font);
  4233. CSize size = pDC->GetTextExtent(str);
  4234. pDC->SelectObject(pOldFont);
  4235. ReleaseDC(pDC);
  4236. return size + CSize(2*m_nMargin, 2*m_nMargin);
  4237. }
  4238. CSize CGridCtrl::GetCellExtent(int nRow, int nCol, CDC* pDC)
  4239. {
  4240. LOGFONT *pLF = GetItemFont(nRow, nCol);
  4241. // use selected font since it's thicker
  4242. LOGFONT lf;
  4243. memcpy(&lf, pLF, sizeof(LOGFONT));
  4244. if (nRow < m_nFixedRows || nCol < m_nFixedCols)
  4245. lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
  4246. CFont font;
  4247. font.CreateFontIndirect(&lf);
  4248. CFont* pOldFont = pDC->SelectObject(&font);
  4249. CSize size = pDC->GetTextExtent(GetItemText(nRow, nCol));
  4250. pDC->SelectObject(pOldFont);
  4251. size += CSize(4*m_nMargin, 2*m_nMargin);
  4252. CSize ImageSize(0,0);
  4253. if (m_pImageList) {
  4254. int nImage = GetItemImage(nRow, nCol);
  4255. if (nImage >= 0) {
  4256. IMAGEINFO Info;
  4257. if (m_pImageList->GetImageInfo(nImage, &Info))
  4258. ImageSize = CSize(Info.rcImage.right-Info.rcImage.left+1,
  4259. Info.rcImage.bottom-Info.rcImage.top+1);
  4260. }
  4261. }
  4262. return CSize(size.cx + ImageSize.cx, max(size.cy, ImageSize.cy));
  4263. }
  4264. BOOL CGridCtrl::DrawFixedCell(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBk)
  4265. {
  4266. if (!m_bAllowDraw)
  4267. return FALSE;
  4268. GV_ITEM Item;
  4269. Item.mask = GVIF_TEXT | GVIF_FORMAT | GVIF_IMAGE | GVIF_BKCLR | GVIF_FGCLR;
  4270. Item.row = nRow;
  4271. Item.col = nCol;
  4272. if (!GetItem(&Item))
  4273. return FALSE;
  4274. // Force redraw of background if custom colour
  4275. //if (Item.crBkClr != CLR_DEFAULT)
  4276. bEraseBk = TRUE;
  4277. if (bEraseBk
  4278. #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  4279. && !pDC->IsPrinting()
  4280. #endif
  4281. )
  4282. {
  4283. CBrush brush((Item.crBkClr == CLR_DEFAULT)? GetFixedBkColor() : Item.crBkClr);
  4284. pDC->FillRect(rect, &brush);
  4285. }
  4286. pDC->SetTextColor((Item.crFgClr == CLR_DEFAULT)? GetFixedTextColor() : Item.crFgClr);
  4287. int nSavedDC = pDC->SaveDC();
  4288. // Create the appropriate font and select into DC
  4289. LOGFONT *pLF = GetItemFont(nRow, nCol);
  4290. CCellID FocusCell = GetFocusCell();
  4291. // if (IsCellFixed(nRow, nCol) && (FocusCell.row == nRow || FocusCell.col == nCol))
  4292. //{
  4293. if (FocusCell.row == nRow || FocusCell.col == nCol)
  4294. {
  4295. static LOGFONT lf;
  4296. memcpy(&lf, pLF, sizeof(LOGFONT));
  4297. lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
  4298. pLF = &lf;
  4299. }
  4300. CFont Font;
  4301. Font.CreateFontIndirect(pLF);
  4302. pDC->SelectObject(&Font);
  4303. if (IsValid(FocusCell) && (FocusCell.row == nRow || FocusCell.col == nCol))
  4304. {
  4305. rect.right++; rect.bottom++;
  4306. pDC->DrawEdge(rect, BDR_SUNKENINNER /*EDGE_RAISED*/, BF_RECT);
  4307. rect.DeflateRect(1,1);
  4308. }
  4309. else
  4310. {
  4311. CPen lightpen(PS_SOLID, 1, ::GetSysColor(COLOR_3DHIGHLIGHT)),
  4312. darkpen(PS_SOLID, 1, ::GetSysColor(COLOR_3DDKSHADOW)),
  4313. *pOldPen = pDC->GetCurrentPen();
  4314. pDC->SelectObject(&lightpen);
  4315. pDC->MoveTo(rect.right, rect.top);
  4316. pDC->LineTo(rect.left, rect.top);
  4317. pDC->LineTo(rect.left, rect.bottom);
  4318. pDC->SelectObject(&darkpen);
  4319. pDC->MoveTo(rect.right, rect.top);
  4320. pDC->LineTo(rect.right, rect.bottom);
  4321. pDC->LineTo(rect.left, rect.bottom);
  4322. pDC->SelectObject(pOldPen);
  4323. rect.DeflateRect(1,1);
  4324. }
  4325. pDC->SetBkMode(TRANSPARENT);
  4326. rect.DeflateRect(m_nMargin, 0);
  4327. if (m_pImageList && Item.iImage >= 0)
  4328. {
  4329. IMAGEINFO Info;
  4330. if (m_pImageList->GetImageInfo(Item.iImage, &Info))
  4331. {
  4332. //CRgn rgn;
  4333. //rgn.CreateRectRgnIndirect(rect);
  4334. //pDC->SelectClipRgn(&rgn);
  4335. //rgn.DeleteObject();
  4336. int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
  4337. m_pImageList->Draw(pDC, Item.iImage, rect.TopLeft(), ILD_NORMAL);
  4338. rect.left += nImageWidth+m_nMargin;
  4339. }
  4340. }
  4341. // rect.bottom += 10;
  4342. // Item.nFormat = DT_LEFT|DT_VCENTER;
  4343. DrawText(pDC->m_hDC, Item.szText, -1, rect, Item.nFormat);
  4344. pDC->RestoreDC(nSavedDC);
  4345. Font.DeleteObject();
  4346. return TRUE;
  4347. }
  4348. BOOL CGridCtrl::DrawCell(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBk)
  4349. {
  4350. if (!m_bAllowDraw)
  4351. return FALSE;
  4352. GV_ITEM Item;
  4353. Item.mask = GVIF_TEXT | GVIF_FORMAT | GVIF_STATE | GVIF_IMAGE | GVIF_BKCLR | GVIF_FGCLR;
  4354. Item.row = nRow;
  4355. Item.col = nCol;
  4356. if (!GetItem(&Item))
  4357. return FALSE;
  4358. COLORREF TextBkClr = (Item.crBkClr == CLR_DEFAULT)? GetTextBkColor() : Item.crBkClr;
  4359. COLORREF TextClr = (Item.crFgClr == CLR_DEFAULT)? GetTextColor() : Item.crFgClr;
  4360. // Force redraw of background if custom colour
  4361. //if (Item.crBkClr != CLR_DEFAULT)
  4362. bEraseBk = TRUE;
  4363. int nSavedDC = pDC->SaveDC();
  4364. pDC->SetBkMode(TRANSPARENT);
  4365. if (Item.state & GVIS_FOCUSED
  4366. #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  4367. && !pDC->IsPrinting()
  4368. #endif
  4369. )
  4370. {
  4371. rect.right++; rect.bottom++; // FillRect doesn't draw RHS or bottom
  4372. if (bEraseBk)
  4373. {
  4374. CBrush brush(TextBkClr);
  4375. pDC->FillRect(rect, &brush);
  4376. }
  4377. rect.right--; rect.bottom--;
  4378. pDC->SelectStockObject(BLACK_PEN);
  4379. pDC->SelectStockObject(NULL_BRUSH);
  4380. pDC->Rectangle(rect);
  4381. pDC->SetTextColor(TextClr);
  4382. rect.DeflateRect(1,1);
  4383. }
  4384. else if (Item.state & GVIS_SELECTED
  4385. #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  4386. && !pDC->IsPrinting()
  4387. #endif
  4388. )
  4389. {
  4390. rect.right++; rect.bottom++; // FillRect doesn't draw RHS or bottom
  4391. pDC->FillSolidRect(rect, ::GetSysColor(COLOR_HIGHLIGHT));
  4392. rect.right--; rect.bottom--;
  4393. pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
  4394. } else {
  4395. rect.right++; rect.bottom++; // FillRect doesn't draw RHS or bottom
  4396. if (bEraseBk)
  4397. {
  4398. CBrush brush(TextBkClr);
  4399. pDC->FillRect(rect, &brush);
  4400. }
  4401. rect.right--; rect.bottom--;
  4402. pDC->SetTextColor(TextClr);
  4403. }
  4404. if (Item.state & GVIS_DROPHILITED
  4405. #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  4406. && !pDC->IsPrinting()
  4407. #endif
  4408. )
  4409. {
  4410. pDC->SelectStockObject(BLACK_PEN);
  4411. pDC->SelectStockObject(NULL_BRUSH);
  4412. pDC->Rectangle(rect);
  4413. }
  4414. // Create the appropriate font and select into DC
  4415. LOGFONT *pLF = GetItemFont(nRow, nCol);
  4416. //CCellID FocusCell = GetFocusCell();
  4417. //if (IsCellFixed(nRow, nCol) && (FocusCell.row == nRow || FocusCell.col == nCol))
  4418. //{
  4419. // static LOGFONT lf;
  4420. // memcpy(&lf, pLF, sizeof(LOGFONT));
  4421. // lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
  4422. // pLF = &lf;
  4423. //}
  4424. CFont Font;
  4425. Font.CreateFontIndirect(pLF);
  4426. pDC->SelectObject(&Font);
  4427. rect.DeflateRect(m_nMargin, 0);
  4428. if (m_pImageList && Item.iImage >= 0)
  4429. {
  4430. IMAGEINFO Info;
  4431. if (m_pImageList->GetImageInfo(Item.iImage, &Info))
  4432. {
  4433. //CRgn rgn;
  4434. //rgn.CreateRectRgnIndirect(rect);
  4435. //pDC->SelectClipRgn(&rgn);
  4436. //rgn.DeleteObject();
  4437. int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
  4438. m_pImageList->Draw(pDC, Item.iImage, rect.TopLeft(), ILD_NORMAL);
  4439. rect.left += nImageWidth+m_nMargin;
  4440. }
  4441. }
  4442. DrawText(pDC->m_hDC, Item.szText, -1, rect, Item.nFormat);
  4443. pDC->RestoreDC(nSavedDC);
  4444. Font.DeleteObject();
  4445. return TRUE;
  4446. }
  4447. void CGridCtrl::OnEditCell(int nRow, int nCol, UINT nChar)
  4448. {
  4449. EnsureVisible(nRow, nCol);
  4450. CCellID cell(nRow, nCol);
  4451. if (!IsValid(cell) || !IsCellEditable(nRow, nCol) || !IsCellVisible(nRow, nCol))
  4452. return;
  4453. bEditing = true;
  4454. CRect rect;
  4455. if (!GetCellRect(cell, rect)) return;
  4456. SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT);
  4457. GV_ITEM Item;
  4458. Item.mask = GVIF_TEXT | GVIF_FORMAT;
  4459. Item.row = nRow;
  4460. Item.col = nCol;
  4461. if (!GetItem(&Item)) return;
  4462. DWORD dwStyle = ES_LEFT;
  4463. if (Item.nFormat & DT_RIGHT) dwStyle = ES_RIGHT;
  4464. else if (Item.nFormat & DT_CENTER) dwStyle = ES_CENTER;
  4465. CreateInPlaceEditControl(rect, dwStyle, IDC_INPLACE_CONTROL,
  4466. nRow, nCol, Item.szText, nChar);
  4467. }
  4468. void CGridCtrl::CreateInPlaceEditControl(CRect& rect, DWORD dwStyle, UINT nID,
  4469. int nRow, int nCol,
  4470. LPCTSTR szText, int nChar)
  4471. {
  4472. // InPlaceEdit auto-deletes itself
  4473. new CInPlaceEdit(this, rect, dwStyle, nID, nRow, nCol, szText, nChar);
  4474. }
  4475. void CGridCtrl::OnEndEditCell(int nRow, int nCol, CString str)
  4476. {
  4477. CString strCurrent = GetItemText(nRow,nCol);
  4478. if (strCurrent != str)
  4479. {
  4480. SetModified(TRUE, nRow, nCol);
  4481. SetItemText(nRow, nCol, str);
  4482. }
  4483. if( nParentType == 1 )
  4484. {
  4485. CModeDlg* pModeDlg = ((CModeDlg*)GetParent());
  4486. pModeDlg->GridVerifyData();
  4487. bEditing = false;
  4488. }
  4489. else if( nParentType == 2 )
  4490. {
  4491. CReliefDlg* pReliefDlg = ((CReliefDlg*)GetParent());
  4492. pReliefDlg->GridVerifyData();
  4493. bEditing = false;
  4494. }
  4495. }
  4496. CString CGridCtrl::GetItemText(int nRow, int nCol)
  4497. {
  4498. if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols) return "";
  4499. CGridCell* pCell = GetCell(nRow, nCol);
  4500. ASSERT(pCell);
  4501. if (!pCell) return "";
  4502. return pCell->szText;
  4503. }