GridCtrl.cpp 220 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604
  1. #include "pch.h"
  2. #include "MemDCEx.h"
  3. #include "GridCtrl.h"
  4. // OLE stuff for clipboard operations
  5. #include <afxadv.h> // For CSharedFile
  6. #include <afxconv.h> // For LPTSTR -> LPSTR macros
  7. // Spit out some messages as a sanity check for programmers
  8. #ifdef GRIDCONTROL_NO_TITLETIPS
  9. #pragma message(" -- CGridCtrl: No titletips for cells with large data")
  10. #endif
  11. #ifdef GRIDCONTROL_NO_DRAGDROP
  12. #pragma message(" -- CGridCtrl: No OLE drag and drop")
  13. #endif
  14. #ifdef GRIDCONTROL_NO_CLIPBOARD
  15. #pragma message(" -- CGridCtrl: No clipboard support")
  16. #endif
  17. #ifdef GRIDCONTROL_NO_PRINTING
  18. #pragma message(" -- CGridCtrl: No printing support")
  19. #endif
  20. IMPLEMENT_DYNCREATE(CGridCtrl, CWnd)
  21. // Get the number of lines to scroll with each mouse wheel notch
  22. // Why doesn't windows give us this function???
  23. UINT GetMouseScrollLines()
  24. {
  25. int nScrollLines = 3; // reasonable default
  26. SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);
  27. return nScrollLines;
  28. }
  29. /////////////////////////////////////////////////////////////////////////////
  30. // CGridCtrl
  31. CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
  32. {
  33. RegisterWindowClass();
  34. #if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
  35. _AFX_THREAD_STATE* pState = AfxGetThreadState();
  36. if (!pState->m_bNeedTerm && !AfxOleInit())
  37. AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
  38. #endif
  39. // Store the system colours in case they change. The gridctrl uses
  40. // these colours, and in OnSysColorChange we can check to see if
  41. // the gridctrl colours have been changed from the system colours.
  42. // If they have, then leave them, otherwise change them to reflect
  43. // the new system colours.
  44. m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
  45. m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
  46. m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
  47. m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
  48. m_crGridLineColour = RGB(192, 192, 192);
  49. m_nRows = 0;
  50. m_nCols = 0;
  51. m_nFixedRows = 0;
  52. m_nFixedCols = 0;
  53. m_bVirtualMode = FALSE;
  54. m_pfnCallback = NULL;
  55. m_nVScrollMax = 0; // Scroll position
  56. m_nHScrollMax = 0;
  57. m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
  58. // per mouse wheel notch to scroll
  59. m_nBarState = GVL_NONE;
  60. m_MouseMode = MOUSE_NOTHING;
  61. m_nGridLines = GVL_BOTH;
  62. m_bEditable = TRUE;
  63. m_bListMode = FALSE;
  64. m_bSingleRowSelection = FALSE;
  65. m_bSingleColSelection = FALSE;
  66. m_bLMouseButtonDown = FALSE;
  67. m_bRMouseButtonDown = FALSE;
  68. m_bAllowDraw = TRUE; // allow draw updates
  69. m_bEnableSelection = TRUE;
  70. m_bFixedColumnSelection = TRUE;
  71. m_bFixedRowSelection = TRUE;
  72. m_bAllowRowResize = TRUE;
  73. m_bAllowColumnResize = TRUE;
  74. m_bSortOnClick = FALSE; // Sort on header row click
  75. m_bHandleTabKey = TRUE;
  76. #ifdef _WIN32_WCE
  77. m_bDoubleBuffer = FALSE; // Use double buffering to avoid flicker?
  78. #else
  79. m_bDoubleBuffer = TRUE; // Use double buffering to avoid flicker?
  80. #endif
  81. m_bTitleTips = TRUE; // show cell title tips
  82. m_bWysiwygPrinting = FALSE; // use size-to-width printing
  83. m_bHiddenColUnhide = TRUE; // 0-width columns can be expanded via mouse
  84. m_bHiddenRowUnhide = TRUE; // 0-Height rows can be expanded via mouse
  85. m_bAllowColHide = TRUE; // Columns can be contracted to 0-width via mouse
  86. m_bAllowRowHide = TRUE; // Rows can be contracted to 0-height via mouse
  87. m_bAscending = TRUE; // sorting stuff
  88. m_nSortColumn = -1;
  89. m_pfnCompare = NULL;
  90. m_nAutoSizeColumnStyle = GVS_BOTH; // Autosize grid using header and data info
  91. m_nTimerID = 0; // For drag-selection
  92. m_nTimerInterval = 25; // (in milliseconds)
  93. m_nResizeCaptureRange = 3; // When resizing columns/row, the cursor has to be
  94. // within +/-3 pixels of the dividing line for
  95. // resizing to be possible
  96. m_pImageList = NULL; // Images in the grid
  97. m_bAllowDragAndDrop = FALSE; // for drag and drop - EFW - off by default
  98. m_bTrackFocusCell = TRUE; // Track Focus cell?
  99. m_bFrameFocus = TRUE; // Frame the selected cell?
  100. m_pRtcDefault = RUNTIME_CLASS(CGridCell);
  101. SetupDefaultCells();
  102. SetGridBkColor(m_crShadow);
  103. // Set up the initial grid size
  104. SetRowCount(nRows);
  105. SetColumnCount(nCols);
  106. SetFixedRowCount(nFixedRows);
  107. SetFixedColumnCount(nFixedCols);
  108. SetTitleTipTextClr(CLR_DEFAULT); //FNA
  109. SetTitleTipBackClr(CLR_DEFAULT);
  110. // set initial selection range (ie. none)
  111. m_SelectedCellMap.RemoveAll();
  112. m_PrevSelectedCellMap.RemoveAll();
  113. #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  114. // EFW - Added to support shaded/unshaded printout and
  115. // user-definable margins.
  116. m_bShadedPrintOut = TRUE;
  117. SetPrintMarginInfo(2, 2, 4, 4, 1, 1, 1);
  118. #endif
  119. }
  120. CGridCtrl::~CGridCtrl()
  121. {
  122. DeleteAllItems();
  123. #ifndef GRIDCONTROL_NO_TITLETIPS
  124. if (m_bTitleTips && ::IsWindow(m_TitleTip.GetSafeHwnd()))
  125. m_TitleTip.DestroyWindow();
  126. #endif
  127. DestroyWindow();
  128. #if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
  129. // BUG FIX - EFW
  130. COleDataSource *pSource = COleDataSource::GetClipboardOwner();
  131. if (pSource)
  132. COleDataSource::FlushClipboard();
  133. #endif
  134. }
  135. // Register the window class if it has not already been registered.
  136. BOOL CGridCtrl::RegisterWindowClass()
  137. {
  138. WNDCLASS wndcls;
  139. HINSTANCE hInst = AfxGetInstanceHandle();
  140. //HINSTANCE hInst = AfxGetResourceHandle();
  141. if (!(::GetClassInfo(hInst, GRIDCTRL_CLASSNAME, &wndcls)))
  142. {
  143. // otherwise we need to register a new class
  144. wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
  145. wndcls.lpfnWndProc = ::DefWindowProc;
  146. wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
  147. wndcls.hInstance = hInst;
  148. wndcls.hIcon = NULL;
  149. #ifndef _WIN32_WCE_NO_CURSOR
  150. wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
  151. #else
  152. wndcls.hCursor = 0;
  153. #endif
  154. wndcls.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
  155. wndcls.lpszMenuName = NULL;
  156. wndcls.lpszClassName = GRIDCTRL_CLASSNAME;
  157. if (!AfxRegisterClass(&wndcls))
  158. {
  159. AfxThrowResourceException();
  160. return FALSE;
  161. }
  162. }
  163. return TRUE;
  164. }
  165. BOOL CGridCtrl::Initialise()
  166. {
  167. // Stop re-entry problems
  168. static BOOL bInProcedure = FALSE;
  169. if (bInProcedure)
  170. return FALSE;
  171. bInProcedure = TRUE;
  172. #ifndef GRIDCONTROL_NO_TITLETIPS
  173. m_TitleTip.SetParentWnd(this);
  174. #endif
  175. // This would be a good place to register the droptarget but
  176. // unfortunately this causes problems if you are using the
  177. // grid in a view.
  178. // Moved from OnSize.
  179. //#ifndef GRIDCONTROL_NO_DRAGDROP
  180. // m_DropTarget.Register(this);
  181. //#endif
  182. // Deleted by HYF
  183. // if (::IsWindow(m_hWnd))
  184. // ModifyStyleEx(0, WS_EX_CLIENTEDGE);
  185. // Kludge: Make sure the client edge shows
  186. // This is so horrible it makes my eyes water.
  187. CRect rect;
  188. GetWindowRect(rect);
  189. CWnd* pParent = GetParent();
  190. if (pParent != NULL)
  191. pParent->ScreenToClient(rect);
  192. rect.InflateRect(1, 1); MoveWindow(rect);
  193. rect.DeflateRect(1, 1); MoveWindow(rect);
  194. bInProcedure = FALSE;
  195. return TRUE;
  196. }
  197. // creates the control - use like any other window create control
  198. BOOL CGridCtrl::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwStyle)
  199. {
  200. ASSERT(pParentWnd->GetSafeHwnd());
  201. if (!CWnd::Create(GRIDCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID))
  202. return FALSE;
  203. //Initialise(); - called in PreSubclassWnd
  204. // The number of rows and columns will only be non-zero if the constructor
  205. // was called with non-zero initialising parameters. If this window was created
  206. // using a dialog template then the number of rows and columns will be 0 (which
  207. // means that the code below will not be needed - which is lucky 'cause it ain't
  208. // gonna get called in a dialog-template-type-situation.
  209. TRY
  210. {
  211. m_arRowHeights.SetSize(m_nRows); // initialize row heights
  212. m_arColWidths.SetSize(m_nCols); // initialize column widths
  213. }
  214. CATCH(CMemoryException, e)
  215. {
  216. e->ReportError();
  217. return FALSE;
  218. }
  219. END_CATCH
  220. int i;
  221. for (i = 0; i < m_nRows; i++)
  222. m_arRowHeights[i] = m_cellDefault.GetHeight();
  223. for (i = 0; i < m_nCols; i++)
  224. m_arColWidths[i] = m_cellDefault.GetWidth();
  225. return TRUE;
  226. }
  227. void CGridCtrl::SetupDefaultCells()
  228. {
  229. m_cellDefault.SetGrid(this); // Normal editable cell
  230. m_cellFixedColDef.SetGrid(this); // Cell for fixed columns
  231. m_cellFixedRowDef.SetGrid(this); // Cell for fixed rows
  232. m_cellFixedRowColDef.SetGrid(this); // Cell for area overlapped by fixed columns/rows
  233. m_cellDefault.SetTextClr(m_crWindowText);
  234. m_cellDefault.SetBackClr(m_crWindowColour);
  235. m_cellFixedColDef.SetTextClr(m_crWindowText);
  236. m_cellFixedColDef.SetBackClr(m_cr3DFace);
  237. m_cellFixedRowDef.SetTextClr(m_crWindowText);
  238. m_cellFixedRowDef.SetBackClr(m_cr3DFace);
  239. m_cellFixedRowColDef.SetTextClr(m_crWindowText);
  240. m_cellFixedRowColDef.SetBackClr(m_cr3DFace);
  241. }
  242. void CGridCtrl::PreSubclassWindow()
  243. {
  244. CWnd::PreSubclassWindow();
  245. //HFONT hFont = ::CreateFontIndirect(m_cellDefault.GetFont());
  246. //OnSetFont((LPARAM)hFont, 0);
  247. //DeleteObject(hFont);
  248. Initialise();
  249. }
  250. // Sends a message to the parent in the form of a WM_NOTIFY message with
  251. // a NM_GRIDVIEW structure attached
  252. LRESULT CGridCtrl::SendMessageToParent(int nRow, int nCol, int nMessage) const
  253. {
  254. if (!IsWindow(m_hWnd))
  255. return 0;
  256. NM_GRIDVIEW nmgv;
  257. nmgv.iRow = nRow;
  258. nmgv.iColumn = nCol;
  259. nmgv.hdr.hwndFrom = m_hWnd;
  260. nmgv.hdr.idFrom = GetDlgCtrlID();
  261. nmgv.hdr.code = nMessage;
  262. CWnd *pOwner = GetOwner();
  263. if (pOwner && IsWindow(pOwner->m_hWnd))
  264. return pOwner->SendMessage(WM_NOTIFY, nmgv.hdr.idFrom, (LPARAM)&nmgv);
  265. else
  266. return 0;
  267. }
  268. // Send a request to the parent to return information on a given cell
  269. LRESULT CGridCtrl::SendDisplayRequestToParent(GV_DISPINFO* pDisplayInfo) const
  270. {
  271. if (!IsWindow(m_hWnd))
  272. return 0;
  273. // Fix up the message headers
  274. pDisplayInfo->hdr.hwndFrom = m_hWnd;
  275. pDisplayInfo->hdr.idFrom = GetDlgCtrlID();
  276. pDisplayInfo->hdr.code = GVN_GETDISPINFO;
  277. // Send the message
  278. CWnd *pOwner = GetOwner();
  279. if (pOwner && IsWindow(pOwner->m_hWnd))
  280. return pOwner->SendMessage(WM_NOTIFY, pDisplayInfo->hdr.idFrom, (LPARAM)pDisplayInfo);
  281. else
  282. return 0;
  283. }
  284. // Send a hint to the parent about caching information
  285. LRESULT CGridCtrl::SendCacheHintToParent(const CCellRange& range) const
  286. {
  287. if (!IsWindow(m_hWnd))
  288. return 0;
  289. GV_CACHEHINT CacheHint;
  290. // Fix up the message headers
  291. CacheHint.hdr.hwndFrom = m_hWnd;
  292. CacheHint.hdr.idFrom = GetDlgCtrlID();
  293. CacheHint.hdr.code = GVN_ODCACHEHINT;
  294. CacheHint.range = range;
  295. // Send the message
  296. CWnd *pOwner = GetOwner();
  297. if (pOwner && IsWindow(pOwner->m_hWnd))
  298. return pOwner->SendMessage(WM_NOTIFY, CacheHint.hdr.idFrom, (LPARAM)&CacheHint);
  299. else
  300. return 0;
  301. }
  302. BEGIN_MESSAGE_MAP(CGridCtrl, CWnd)
  303. //EFW - Added ON_WM_RBUTTONUP
  304. //{{AFX_MSG_MAP(CGridCtrl)
  305. ON_WM_PAINT()
  306. ON_WM_HSCROLL()
  307. ON_WM_VSCROLL()
  308. ON_WM_SIZE()
  309. ON_WM_LBUTTONUP()
  310. ON_WM_LBUTTONDOWN()
  311. ON_WM_MOUSEMOVE()
  312. ON_WM_TIMER()
  313. ON_WM_GETDLGCODE()
  314. ON_WM_KEYDOWN()
  315. ON_WM_CHAR()
  316. ON_WM_LBUTTONDBLCLK()
  317. ON_WM_ERASEBKGND()
  318. ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateEditSelectAll)
  319. ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
  320. ON_WM_SYSKEYDOWN()
  321. //}}AFX_MSG_MAP
  322. #ifndef _WIN32_WCE_NO_CURSOR
  323. ON_WM_SETCURSOR()
  324. #endif
  325. #ifndef _WIN32_WCE
  326. ON_WM_RBUTTONUP()
  327. ON_WM_SYSCOLORCHANGE()
  328. ON_WM_CAPTURECHANGED()
  329. #endif
  330. #ifndef GRIDCONTROL_NO_CLIPBOARD
  331. ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
  332. ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
  333. ON_COMMAND(ID_EDIT_CUT, OnEditCut)
  334. ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)
  335. ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
  336. ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
  337. #endif
  338. #if (_WIN32_WCE >= 210)
  339. ON_WM_SETTINGCHANGE()
  340. #endif
  341. #if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
  342. ON_WM_MOUSEWHEEL()
  343. #endif
  344. ON_MESSAGE(WM_SETFONT, OnSetFont)
  345. ON_MESSAGE(WM_GETFONT, OnGetFont)
  346. ON_MESSAGE(WM_IME_CHAR, OnImeChar)
  347. ON_NOTIFY(GVN_ENDLABELEDIT, IDC_INPLACE_CONTROL, OnEndInPlaceEdit)
  348. END_MESSAGE_MAP()
  349. /////////////////////////////////////////////////////////////////////////////
  350. // CGridCtrl message handlers
  351. void CGridCtrl::OnPaint()
  352. {
  353. CPaintDC dc(this); // device context for painting
  354. if (m_bDoubleBuffer) // Use a memory DC to remove flicker
  355. {
  356. CMemDCEx MemDC(&dc);
  357. OnDraw(&MemDC);
  358. }
  359. else // Draw raw - this helps in debugging vis problems.
  360. OnDraw(&dc);
  361. }
  362. BOOL CGridCtrl::OnEraseBkgnd(CDC* /*pDC*/)
  363. {
  364. return TRUE; // Don't erase the background.
  365. }
  366. // Custom background erasure. This gets called from within the OnDraw function,
  367. // since we will (most likely) be using a memory DC to stop flicker. If we just
  368. // erase the background normally through OnEraseBkgnd, and didn't fill the memDC's
  369. // selected bitmap with colour, then all sorts of vis problems would occur
  370. void CGridCtrl::EraseBkgnd(CDC* pDC)
  371. {
  372. CRect VisRect, ClipRect, rect;
  373. CBrush FixedRowColBack(GetDefaultCell(TRUE, TRUE)->GetBackClr()),
  374. FixedRowBack(GetDefaultCell(TRUE, FALSE)->GetBackClr()),
  375. FixedColBack(GetDefaultCell(FALSE, TRUE)->GetBackClr()),
  376. TextBack(GetDefaultCell(FALSE, FALSE)->GetBackClr());
  377. CBrush Back(GetGridBkColor());
  378. //CBrush Back(GetTextBkColor());
  379. if (pDC->GetClipBox(ClipRect) == ERROR)
  380. return;
  381. GetVisibleNonFixedCellRange(VisRect);
  382. int nFixedColumnWidth = GetFixedColumnWidth();
  383. int nFixedRowHeight = GetFixedRowHeight();
  384. // Draw Fixed row/column background
  385. if (ClipRect.left < nFixedColumnWidth && ClipRect.top < nFixedRowHeight)
  386. pDC->FillRect(CRect(ClipRect.left, ClipRect.top,
  387. nFixedColumnWidth, nFixedRowHeight),
  388. &FixedRowColBack);
  389. // Draw Fixed columns background
  390. if (ClipRect.left < nFixedColumnWidth && ClipRect.top < VisRect.bottom)
  391. pDC->FillRect(CRect(ClipRect.left, ClipRect.top,
  392. nFixedColumnWidth, VisRect.bottom),
  393. &FixedColBack);
  394. // Draw Fixed rows background
  395. if (ClipRect.top < nFixedRowHeight &&
  396. ClipRect.right > nFixedColumnWidth && ClipRect.left < VisRect.right)
  397. pDC->FillRect(CRect(nFixedColumnWidth - 1, ClipRect.top,
  398. VisRect.right, nFixedRowHeight),
  399. &FixedRowBack);
  400. // Draw non-fixed cell background
  401. if (rect.IntersectRect(VisRect, ClipRect))
  402. {
  403. CRect CellRect(max(nFixedColumnWidth, rect.left),
  404. max(nFixedRowHeight, rect.top),
  405. rect.right, rect.bottom);
  406. pDC->FillRect(CellRect, &TextBack);
  407. }
  408. // Draw right hand side of window outside grid
  409. if (VisRect.right < ClipRect.right)
  410. pDC->FillRect(CRect(VisRect.right, ClipRect.top,
  411. ClipRect.right, ClipRect.bottom),
  412. &Back);
  413. // Draw bottom of window below grid
  414. if (VisRect.bottom < ClipRect.bottom && ClipRect.left < VisRect.right)
  415. pDC->FillRect(CRect(ClipRect.left, VisRect.bottom,
  416. VisRect.right, ClipRect.bottom),
  417. &Back);
  418. }
  419. void CGridCtrl::OnSize(UINT nType, int cx, int cy)
  420. {
  421. static BOOL bAlreadyInsideThisProcedure = FALSE;
  422. if (bAlreadyInsideThisProcedure)
  423. return;
  424. if (!::IsWindow(m_hWnd))
  425. return;
  426. // This is not the ideal place to register the droptarget
  427. #ifndef GRIDCONTROL_NO_DRAGDROP
  428. m_DropTarget.Register(this);
  429. #endif
  430. // Start re-entry blocking
  431. bAlreadyInsideThisProcedure = TRUE;
  432. EndEditing(); // destroy any InPlaceEdit's
  433. CWnd::OnSize(nType, cx, cy);
  434. ResetScrollBars();
  435. // End re-entry blocking
  436. bAlreadyInsideThisProcedure = FALSE;
  437. }
  438. UINT CGridCtrl::OnGetDlgCode()
  439. {
  440. UINT nCode = DLGC_WANTARROWS | DLGC_WANTCHARS; // DLGC_WANTALLKEYS; //
  441. if (m_bHandleTabKey && !IsCTRLpressed())
  442. nCode |= DLGC_WANTTAB;
  443. return nCode;
  444. }
  445. #ifndef _WIN32_WCE
  446. // If system colours change, then redo colours
  447. void CGridCtrl::OnSysColorChange()
  448. {
  449. CWnd::OnSysColorChange();
  450. if (GetDefaultCell(FALSE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
  451. GetDefaultCell(FALSE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  452. if (GetDefaultCell(FALSE, FALSE)->GetBackClr() == m_crWindowColour)
  453. GetDefaultCell(FALSE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  454. if (GetDefaultCell(TRUE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
  455. GetDefaultCell(TRUE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  456. if (GetDefaultCell(TRUE, FALSE)->GetBackClr() == m_crWindowColour)
  457. GetDefaultCell(TRUE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  458. if (GetDefaultCell(FALSE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
  459. GetDefaultCell(FALSE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  460. if (GetDefaultCell(FALSE, TRUE)->GetBackClr() == m_crWindowColour)
  461. GetDefaultCell(FALSE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  462. if (GetDefaultCell(TRUE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
  463. GetDefaultCell(TRUE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  464. if (GetDefaultCell(TRUE, TRUE)->GetBackClr() == m_crWindowColour)
  465. GetDefaultCell(TRUE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  466. if (GetGridBkColor() == m_crShadow)
  467. SetGridBkColor(::GetSysColor(COLOR_3DSHADOW));
  468. m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
  469. m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
  470. m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
  471. m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
  472. }
  473. #endif
  474. #ifndef _WIN32_WCE_NO_CURSOR
  475. // If we are drag-selecting cells, or drag and dropping, stop now
  476. void CGridCtrl::OnCaptureChanged(CWnd *pWnd)
  477. {
  478. if (pWnd->GetSafeHwnd() == GetSafeHwnd())
  479. return;
  480. // kill timer if active
  481. if (m_nTimerID != 0)
  482. {
  483. KillTimer(m_nTimerID);
  484. m_nTimerID = 0;
  485. }
  486. #ifndef GRIDCONTROL_NO_DRAGDROP
  487. // Kill drag and drop if active
  488. if (m_MouseMode == MOUSE_DRAGGING)
  489. m_MouseMode = MOUSE_NOTHING;
  490. #endif
  491. }
  492. #endif
  493. #if (_MFC_VER >= 0x0421) || (_WIN32_WCE >= 210)
  494. // If system settings change, then redo colours
  495. void CGridCtrl::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
  496. {
  497. CWnd::OnSettingChange(uFlags, lpszSection);
  498. if (GetDefaultCell(FALSE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
  499. GetDefaultCell(FALSE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  500. if (GetDefaultCell(FALSE, FALSE)->GetBackClr() == m_crWindowColour)
  501. GetDefaultCell(FALSE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  502. if (GetDefaultCell(TRUE, FALSE)->GetTextClr() == m_crWindowText) // Still using system colours
  503. GetDefaultCell(TRUE, FALSE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  504. if (GetDefaultCell(TRUE, FALSE)->GetBackClr() == m_crWindowColour)
  505. GetDefaultCell(TRUE, FALSE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  506. if (GetDefaultCell(FALSE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
  507. GetDefaultCell(FALSE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  508. if (GetDefaultCell(FALSE, TRUE)->GetBackClr() == m_crWindowColour)
  509. GetDefaultCell(FALSE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  510. if (GetDefaultCell(TRUE, TRUE)->GetTextClr() == m_crWindowText) // Still using system colours
  511. GetDefaultCell(TRUE, TRUE)->SetTextClr(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
  512. if (GetDefaultCell(TRUE, TRUE)->GetBackClr() == m_crWindowColour)
  513. GetDefaultCell(TRUE, TRUE)->SetBackClr(::GetSysColor(COLOR_WINDOW));
  514. if (GetGridBkColor() == m_crShadow)
  515. SetGridBkColor(::GetSysColor(COLOR_3DSHADOW));
  516. m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
  517. m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
  518. m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
  519. m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
  520. m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
  521. }
  522. #endif
  523. // For drag-selection. Scrolls hidden cells into view
  524. // TODO: decrease timer interval over time to speed up selection over time
  525. void CGridCtrl::OnTimer(UINT_PTR nIDEvent)
  526. {
  527. ASSERT(nIDEvent == WM_LBUTTONDOWN);
  528. if (nIDEvent != WM_LBUTTONDOWN)
  529. return;
  530. CPoint pt, origPt;
  531. #ifdef _WIN32_WCE
  532. if (m_MouseMode == MOUSE_NOTHING)
  533. return;
  534. origPt = GetMessagePos();
  535. #else
  536. if (!GetCursorPos(&origPt))
  537. return;
  538. #endif
  539. ScreenToClient(&origPt);
  540. CRect rect;
  541. GetClientRect(rect);
  542. int nFixedRowHeight = GetFixedRowHeight();
  543. int nFixedColWidth = GetFixedColumnWidth();
  544. pt = origPt;
  545. if (pt.y > rect.bottom)
  546. {
  547. //SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  548. SendMessage(WM_KEYDOWN, VK_DOWN, 0);
  549. if (pt.x < rect.left)
  550. pt.x = rect.left;
  551. if (pt.x > rect.right)
  552. pt.x = rect.right;
  553. pt.y = rect.bottom;
  554. OnSelecting(GetCellFromPt(pt));
  555. }
  556. else if (pt.y < nFixedRowHeight)
  557. {
  558. //SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  559. SendMessage(WM_KEYDOWN, VK_UP, 0);
  560. if (pt.x < rect.left)
  561. pt.x = rect.left;
  562. if (pt.x > rect.right)
  563. pt.x = rect.right;
  564. pt.y = nFixedRowHeight + 1;
  565. OnSelecting(GetCellFromPt(pt));
  566. }
  567. pt = origPt;
  568. if (pt.x > rect.right)
  569. {
  570. // SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  571. SendMessage(WM_KEYDOWN, VK_RIGHT, 0);
  572. if (pt.y < rect.top)
  573. pt.y = rect.top;
  574. if (pt.y > rect.bottom)
  575. pt.y = rect.bottom;
  576. pt.x = rect.right;
  577. OnSelecting(GetCellFromPt(pt));
  578. }
  579. else if (pt.x < nFixedColWidth)
  580. {
  581. //SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  582. SendMessage(WM_KEYDOWN, VK_LEFT, 0);
  583. if (pt.y < rect.top)
  584. pt.y = rect.top;
  585. if (pt.y > rect.bottom)
  586. pt.y = rect.bottom;
  587. pt.x = nFixedColWidth + 1;
  588. OnSelecting(GetCellFromPt(pt));
  589. }
  590. }
  591. // move about with keyboard
  592. void CGridCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  593. {
  594. if (!IsValid(m_idCurrentCell))
  595. {
  596. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  597. return;
  598. }
  599. CCellID next = m_idCurrentCell;
  600. BOOL bChangeLine = FALSE;
  601. BOOL bHorzScrollAction = FALSE;
  602. BOOL bVertScrollAction = FALSE;
  603. if (IsCTRLpressed())
  604. {
  605. switch (nChar)
  606. {
  607. case 'A':
  608. OnEditSelectAll();
  609. break;
  610. #ifndef GRIDCONTROL_NO_CLIPBOARD
  611. case 'X':
  612. OnEditCut();
  613. break;
  614. case VK_INSERT:
  615. case 'C':
  616. OnEditCopy();
  617. break;
  618. case 'V':
  619. OnEditPaste();
  620. break;
  621. #endif
  622. }
  623. }
  624. #ifndef GRIDCONTROL_NO_CLIPBOARD
  625. if (IsSHIFTpressed() && (nChar == VK_INSERT))
  626. OnEditPaste();
  627. #endif
  628. BOOL bFoundVisible;
  629. int iOrig;
  630. if (nChar == VK_DELETE)
  631. {
  632. CutSelectedText();
  633. }
  634. else if (nChar == VK_DOWN)
  635. {
  636. // don't let user go to a hidden row
  637. bFoundVisible = FALSE;
  638. iOrig = next.row;
  639. next.row++;
  640. while (next.row < GetRowCount())
  641. {
  642. if (GetRowHeight(next.row) > 0)
  643. {
  644. bFoundVisible = TRUE;
  645. break;
  646. }
  647. next.row++;
  648. }
  649. if (!bFoundVisible)
  650. next.row = iOrig;
  651. }
  652. else if (nChar == VK_UP)
  653. {
  654. // don't let user go to a hidden row
  655. bFoundVisible = FALSE;
  656. iOrig = next.row;
  657. next.row--;
  658. while (next.row >= m_nFixedRows)
  659. {
  660. if (GetRowHeight(next.row) > 0)
  661. {
  662. bFoundVisible = TRUE;
  663. break;
  664. }
  665. next.row--;
  666. }
  667. if (!bFoundVisible)
  668. next.row = iOrig;
  669. }
  670. else if (nChar == VK_RIGHT || (nChar == VK_TAB && !IsSHIFTpressed()))
  671. {
  672. // don't let user go to a hidden column
  673. bFoundVisible = FALSE;
  674. iOrig = next.col;
  675. next.col++;
  676. if (nChar == VK_TAB)
  677. {
  678. // If we're at the end of a row, go down a row till we find a non-hidden row
  679. if (next.col == (GetColumnCount()) && next.row < (GetRowCount() - 1))
  680. {
  681. next.row++;
  682. while (next.row < GetRowCount())
  683. {
  684. if (GetRowHeight(next.row) > 0)
  685. {
  686. bFoundVisible = TRUE;
  687. break;
  688. }
  689. next.row++;
  690. }
  691. next.col = m_nFixedCols; // Place focus on first non-fixed column
  692. bChangeLine = TRUE;
  693. }
  694. else
  695. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  696. }
  697. // We're on a non-hidden row, so look across for the next non-hidden column
  698. while (next.col < GetColumnCount())
  699. {
  700. if (GetColumnWidth(next.col) > 0)
  701. {
  702. bFoundVisible = TRUE;
  703. break;
  704. }
  705. next.col++;
  706. }
  707. // If nothing worked then don't bother
  708. if (!bFoundVisible)
  709. next.col = iOrig;
  710. }
  711. else if (nChar == VK_LEFT || (nChar == VK_TAB && IsSHIFTpressed()))
  712. {
  713. // don't let user go to a hidden column
  714. bFoundVisible = FALSE;
  715. iOrig = next.col;
  716. next.col--;
  717. if (nChar == VK_TAB)
  718. {
  719. if (next.col == (GetFixedColumnCount() - 1) && next.row > GetFixedRowCount())
  720. {
  721. next.row--;
  722. while (next.row > GetFixedRowCount())
  723. {
  724. if (GetRowHeight(next.row) > 0)
  725. {
  726. bFoundVisible = TRUE;
  727. break;
  728. }
  729. next.row--;
  730. }
  731. next.col = GetColumnCount() - 1;
  732. bChangeLine = TRUE;
  733. }
  734. else
  735. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  736. }
  737. while (next.col >= m_nFixedCols)
  738. {
  739. if (GetColumnWidth(next.col) > 0)
  740. {
  741. bFoundVisible = TRUE;
  742. break;
  743. }
  744. next.col--;
  745. }
  746. if (!bFoundVisible)
  747. next.col = iOrig;
  748. }
  749. else if (nChar == VK_NEXT)
  750. {
  751. CCellID idOldTopLeft = GetTopleftNonFixedCell();
  752. SendMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
  753. bVertScrollAction = TRUE;
  754. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  755. int increment = idNewTopLeft.row - idOldTopLeft.row;
  756. if (increment)
  757. {
  758. next.row += increment;
  759. if (next.row > (GetRowCount() - 1))
  760. next.row = GetRowCount() - 1;
  761. }
  762. else
  763. next.row = GetRowCount() - 1;
  764. }
  765. else if (nChar == VK_PRIOR)
  766. {
  767. CCellID idOldTopLeft = GetTopleftNonFixedCell();
  768. SendMessage(WM_VSCROLL, SB_PAGEUP, 0);
  769. bVertScrollAction = TRUE;
  770. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  771. int increment = idNewTopLeft.row - idOldTopLeft.row;
  772. if (increment)
  773. {
  774. next.row += increment;
  775. if (next.row < m_nFixedRows)
  776. next.row = m_nFixedRows;
  777. }
  778. else
  779. next.row = m_nFixedRows;
  780. }
  781. else if (nChar == VK_HOME)
  782. {
  783. // Home and Ctrl-Home work more like Excel
  784. // and don't let user go to a hidden cell
  785. if (IsCTRLpressed())
  786. {
  787. SendMessage(WM_VSCROLL, SB_TOP, 0);
  788. SendMessage(WM_HSCROLL, SB_LEFT, 0);
  789. bVertScrollAction = TRUE;
  790. bHorzScrollAction = TRUE;
  791. next.row = m_nFixedRows;
  792. next.col = m_nFixedCols;
  793. }
  794. else
  795. {
  796. SendMessage(WM_HSCROLL, SB_LEFT, 0);
  797. bHorzScrollAction = TRUE;
  798. next.col = m_nFixedCols;
  799. }
  800. // adjust column to avoid hidden columns and rows
  801. while (next.col < GetColumnCount() - 1)
  802. {
  803. if (GetColumnWidth(next.col) > 0)
  804. break;
  805. next.col++;
  806. }
  807. while (next.row < GetRowCount() - 1)
  808. {
  809. if (GetRowHeight(next.row) > 0)
  810. break;
  811. next.row++;
  812. }
  813. }
  814. else if (nChar == VK_END)
  815. {
  816. // End and Ctrl-End work more like Excel
  817. // and don't let user go to a hidden cell
  818. if (IsCTRLpressed())
  819. {
  820. SendMessage(WM_VSCROLL, SB_BOTTOM, 0);
  821. SendMessage(WM_HSCROLL, SB_RIGHT, 0);
  822. bHorzScrollAction = TRUE;
  823. bVertScrollAction = TRUE;
  824. next.row = GetRowCount() - 1;
  825. next.col = GetColumnCount() - 1;
  826. }
  827. else
  828. {
  829. SendMessage(WM_HSCROLL, SB_RIGHT, 0);
  830. bHorzScrollAction = TRUE;
  831. next.col = GetColumnCount() - 1;
  832. }
  833. // adjust column to avoid hidden columns and rows
  834. while (next.col > m_nFixedCols + 1)
  835. {
  836. if (GetColumnWidth(next.col) > 0)
  837. break;
  838. next.col--;
  839. }
  840. while (next.row > m_nFixedRows + 1)
  841. {
  842. if (GetRowHeight(next.row) > 0)
  843. break;
  844. next.row--;
  845. }
  846. }
  847. else if (nChar == VK_F2)
  848. {
  849. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint(-1, -1), VK_LBUTTON);
  850. }
  851. else
  852. {
  853. CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
  854. return;
  855. }
  856. if (next != m_idCurrentCell)
  857. {
  858. // While moving with the Cursorkeys the current ROW/CELL will get selected
  859. // OR Selection will get expanded when SHIFT is pressed
  860. // Cut n paste from OnLButtonDown - Franco Bez
  861. // Added check for NULL mouse mode - Chris Maunder.
  862. if (m_MouseMode == MOUSE_NOTHING)
  863. {
  864. m_PrevSelectedCellMap.RemoveAll();
  865. m_MouseMode = m_bListMode ? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
  866. if (!IsSHIFTpressed() || nChar == VK_TAB)
  867. m_SelectionStartCell = next;
  868. // Notify parent that selection is changing - Arthur Westerman/Scot Brennecke
  869. SendMessageToParent(next.row, next.col, GVN_SELCHANGING);
  870. OnSelecting(next);
  871. SendMessageToParent(next.row, next.col, GVN_SELCHANGED);
  872. m_MouseMode = MOUSE_NOTHING;
  873. }
  874. SetFocusCell(next);
  875. if (!IsCellVisible(next))
  876. {
  877. switch (nChar)
  878. {
  879. case VK_RIGHT:
  880. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  881. bHorzScrollAction = TRUE;
  882. break;
  883. case VK_LEFT:
  884. SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  885. bHorzScrollAction = TRUE;
  886. break;
  887. case VK_DOWN:
  888. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  889. bVertScrollAction = TRUE;
  890. break;
  891. case VK_UP:
  892. SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  893. bVertScrollAction = TRUE;
  894. break;
  895. case VK_TAB:
  896. if (IsSHIFTpressed())
  897. {
  898. if (bChangeLine)
  899. {
  900. SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  901. bVertScrollAction = TRUE;
  902. SetScrollPos32(SB_HORZ, m_nHScrollMax);
  903. break;
  904. }
  905. else
  906. {
  907. SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  908. bHorzScrollAction = TRUE;
  909. }
  910. }
  911. else
  912. {
  913. if (bChangeLine)
  914. {
  915. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  916. bVertScrollAction = TRUE;
  917. SetScrollPos32(SB_HORZ, 0);
  918. break;
  919. }
  920. else
  921. {
  922. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  923. bHorzScrollAction = TRUE;
  924. }
  925. }
  926. break;
  927. }
  928. EnsureVisible(next); // Make sure cell is visible
  929. Invalidate();
  930. }
  931. EnsureVisible(next); // Make sure cell is visible
  932. if (bHorzScrollAction)
  933. SendMessage(WM_HSCROLL, SB_ENDSCROLL, 0);
  934. if (bVertScrollAction)
  935. SendMessage(WM_VSCROLL, SB_ENDSCROLL, 0);
  936. }
  937. }
  938. void CGridCtrl::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
  939. {
  940. CWnd::OnKeyUp(nChar, nRepCnt, nFlags);
  941. }
  942. void CGridCtrl::OnSysKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
  943. {
  944. #ifdef GRIDCONTROL_USE_TITLETIPS
  945. m_TitleTip.Hide(); // hide any titletips
  946. #endif
  947. CWnd::OnSysKeyDown(nChar, nRepCnt, nFlags);
  948. }
  949. // Instant editing of cells when keys are pressed
  950. void CGridCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
  951. {
  952. // EFW - BUG FIX
  953. if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING && nChar != VK_ESCAPE)
  954. {
  955. if (!m_bHandleTabKey || (m_bHandleTabKey && nChar != VK_TAB))
  956. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint(-1, -1), nChar);
  957. }
  958. CWnd::OnChar(nChar, nRepCnt, nFlags);
  959. }
  960. // Added by KiteFly
  961. LRESULT CGridCtrl::OnImeChar(WPARAM wCharCode, LPARAM)
  962. {
  963. // EFW - BUG FIX
  964. if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING && wCharCode != VK_ESCAPE)
  965. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint(-1, -1), (UINT)wCharCode);
  966. return 0;
  967. }
  968. // Callback from any CInPlaceEdits that ended. This just calls OnEndEditCell,
  969. // refreshes the edited cell and moves onto next cell if the return character
  970. // from the edit says we should.
  971. void CGridCtrl::OnEndInPlaceEdit(NMHDR* pNMHDR, LRESULT* pResult)
  972. {
  973. GV_DISPINFO *pgvDispInfo = (GV_DISPINFO *)pNMHDR;
  974. GV_ITEM *pgvItem = &pgvDispInfo->item;
  975. // In case OnEndInPlaceEdit called as window is being destroyed
  976. if (!IsWindow(GetSafeHwnd()))
  977. return;
  978. OnEndEditCell(pgvItem->row, pgvItem->col, pgvItem->strText);
  979. //InvalidateCellRect(CCellID(pgvItem->row, pgvItem->col));
  980. switch (pgvItem->lParam)
  981. {
  982. case VK_TAB:
  983. case VK_DOWN:
  984. case VK_UP:
  985. case VK_RIGHT:
  986. case VK_LEFT:
  987. case VK_NEXT:
  988. case VK_PRIOR:
  989. case VK_HOME:
  990. case VK_END:
  991. OnKeyDown((UINT)pgvItem->lParam, 0, 0);
  992. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, CPoint(-1, -1), (UINT)pgvItem->lParam);
  993. }
  994. *pResult = 0;
  995. }
  996. // Handle horz scrollbar notifications
  997. void CGridCtrl::OnHScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
  998. {
  999. EndEditing();
  1000. #ifndef GRIDCONTROL_NO_TITLETIPS
  1001. m_TitleTip.Hide(); // hide any titletips
  1002. #endif
  1003. int scrollPos = GetScrollPos32(SB_HORZ);
  1004. CCellID idTopLeft = GetTopleftNonFixedCell();
  1005. CRect rect;
  1006. GetClientRect(rect);
  1007. switch (nSBCode)
  1008. {
  1009. case SB_LINERIGHT:
  1010. if (scrollPos < m_nHScrollMax)
  1011. {
  1012. // may have contiguous hidden columns. Blow by them
  1013. while (idTopLeft.col < (GetColumnCount() - 1)
  1014. && GetColumnWidth(idTopLeft.col) < 1)
  1015. {
  1016. idTopLeft.col++;
  1017. }
  1018. int xScroll = GetColumnWidth(idTopLeft.col);
  1019. SetScrollPos32(SB_HORZ, scrollPos + xScroll);
  1020. if (GetScrollPos32(SB_HORZ) == scrollPos)
  1021. break; // didn't work
  1022. rect.left = GetFixedColumnWidth();
  1023. //rect.left = GetFixedColumnWidth() + xScroll;
  1024. //ScrollWindow(-xScroll, 0, rect);
  1025. //rect.left = rect.right - xScroll;
  1026. InvalidateRect(rect);
  1027. }
  1028. break;
  1029. case SB_LINELEFT:
  1030. if (scrollPos > 0 && idTopLeft.col > GetFixedColumnCount())
  1031. {
  1032. int iColToUse = idTopLeft.col - 1;
  1033. // may have contiguous hidden columns. Blow by them
  1034. while (iColToUse > GetFixedColumnCount()
  1035. && GetColumnWidth(iColToUse) < 1)
  1036. {
  1037. iColToUse--;
  1038. }
  1039. int xScroll = GetColumnWidth(iColToUse);
  1040. SetScrollPos32(SB_HORZ, max(0, scrollPos - xScroll));
  1041. rect.left = GetFixedColumnWidth();
  1042. //ScrollWindow(xScroll, 0, rect);
  1043. //rect.right = rect.left + xScroll;
  1044. InvalidateRect(rect);
  1045. }
  1046. break;
  1047. case SB_PAGERIGHT:
  1048. if (scrollPos < m_nHScrollMax)
  1049. {
  1050. rect.left = GetFixedColumnWidth();
  1051. int offset = rect.Width();
  1052. int pos = min(m_nHScrollMax, scrollPos + offset);
  1053. SetScrollPos32(SB_HORZ, pos);
  1054. rect.left = GetFixedColumnWidth();
  1055. InvalidateRect(rect);
  1056. }
  1057. break;
  1058. case SB_PAGELEFT:
  1059. if (scrollPos > 0)
  1060. {
  1061. rect.left = GetFixedColumnWidth();
  1062. int offset = -rect.Width();
  1063. int pos = max(0, scrollPos + offset);
  1064. SetScrollPos32(SB_HORZ, pos);
  1065. rect.left = GetFixedColumnWidth();
  1066. InvalidateRect(rect);
  1067. }
  1068. break;
  1069. case SB_THUMBPOSITION:
  1070. case SB_THUMBTRACK:
  1071. {
  1072. SetScrollPos32(SB_HORZ, GetScrollPos32(SB_HORZ, TRUE));
  1073. m_idTopLeftCell.row = -1;
  1074. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  1075. if (idNewTopLeft != idTopLeft)
  1076. {
  1077. rect.left = GetFixedColumnWidth();
  1078. InvalidateRect(rect);
  1079. }
  1080. }
  1081. break;
  1082. case SB_LEFT:
  1083. if (scrollPos > 0)
  1084. {
  1085. SetScrollPos32(SB_HORZ, 0);
  1086. Invalidate();
  1087. }
  1088. break;
  1089. case SB_RIGHT:
  1090. if (scrollPos < m_nHScrollMax)
  1091. {
  1092. SetScrollPos32(SB_HORZ, m_nHScrollMax);
  1093. Invalidate();
  1094. }
  1095. break;
  1096. default:
  1097. break;
  1098. }
  1099. }
  1100. // Handle vert scrollbar notifications
  1101. void CGridCtrl::OnVScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
  1102. {
  1103. EndEditing();
  1104. #ifndef GRIDCONTROL_NO_TITLETIPS
  1105. m_TitleTip.Hide(); // hide any titletips
  1106. #endif
  1107. // Get the scroll position ourselves to ensure we get a 32 bit value
  1108. int scrollPos = GetScrollPos32(SB_VERT);
  1109. CCellID idTopLeft = GetTopleftNonFixedCell();
  1110. CRect rect;
  1111. GetClientRect(rect);
  1112. switch (nSBCode)
  1113. {
  1114. case SB_LINEDOWN:
  1115. if (scrollPos < m_nVScrollMax)
  1116. {
  1117. // may have contiguous hidden rows. Blow by them
  1118. while (idTopLeft.row < (GetRowCount() - 1)
  1119. && GetRowHeight(idTopLeft.row) < 1)
  1120. {
  1121. idTopLeft.row++;
  1122. }
  1123. int yScroll = GetRowHeight(idTopLeft.row);
  1124. SetScrollPos32(SB_VERT, scrollPos + yScroll);
  1125. if (GetScrollPos32(SB_VERT) == scrollPos)
  1126. break; // didn't work
  1127. rect.top = GetFixedRowHeight();
  1128. //rect.top = GetFixedRowHeight() + yScroll;
  1129. //ScrollWindow(0, -yScroll, rect);
  1130. //rect.top = rect.bottom - yScroll;
  1131. InvalidateRect(rect);
  1132. }
  1133. break;
  1134. case SB_LINEUP:
  1135. if (scrollPos > 0 && idTopLeft.row > GetFixedRowCount())
  1136. {
  1137. int iRowToUse = idTopLeft.row - 1;
  1138. // may have contiguous hidden rows. Blow by them
  1139. while (iRowToUse > GetFixedRowCount()
  1140. && GetRowHeight(iRowToUse) < 1)
  1141. {
  1142. iRowToUse--;
  1143. }
  1144. int yScroll = GetRowHeight(iRowToUse);
  1145. SetScrollPos32(SB_VERT, max(0, scrollPos - yScroll));
  1146. rect.top = GetFixedRowHeight();
  1147. //ScrollWindow(0, yScroll, rect);
  1148. //rect.bottom = rect.top + yScroll;
  1149. InvalidateRect(rect);
  1150. }
  1151. break;
  1152. case SB_PAGEDOWN:
  1153. if (scrollPos < m_nVScrollMax)
  1154. {
  1155. rect.top = GetFixedRowHeight();
  1156. scrollPos = min(m_nVScrollMax, scrollPos + rect.Height());
  1157. SetScrollPos32(SB_VERT, scrollPos);
  1158. rect.top = GetFixedRowHeight();
  1159. InvalidateRect(rect);
  1160. }
  1161. break;
  1162. case SB_PAGEUP:
  1163. if (scrollPos > 0)
  1164. {
  1165. rect.top = GetFixedRowHeight();
  1166. int offset = -rect.Height();
  1167. int pos = max(0, scrollPos + offset);
  1168. SetScrollPos32(SB_VERT, pos);
  1169. rect.top = GetFixedRowHeight();
  1170. InvalidateRect(rect);
  1171. }
  1172. break;
  1173. case SB_THUMBPOSITION:
  1174. case SB_THUMBTRACK:
  1175. {
  1176. SetScrollPos32(SB_VERT, GetScrollPos32(SB_VERT, TRUE));
  1177. m_idTopLeftCell.row = -1;
  1178. CCellID idNewTopLeft = GetTopleftNonFixedCell();
  1179. if (idNewTopLeft != idTopLeft)
  1180. {
  1181. rect.top = GetFixedRowHeight();
  1182. InvalidateRect(rect);
  1183. }
  1184. }
  1185. break;
  1186. case SB_TOP:
  1187. if (scrollPos > 0)
  1188. {
  1189. SetScrollPos32(SB_VERT, 0);
  1190. Invalidate();
  1191. }
  1192. break;
  1193. case SB_BOTTOM:
  1194. if (scrollPos < m_nVScrollMax)
  1195. {
  1196. SetScrollPos32(SB_VERT, m_nVScrollMax);
  1197. Invalidate();
  1198. }
  1199. default:
  1200. break;
  1201. }
  1202. }
  1203. /////////////////////////////////////////////////////////////////////////////
  1204. // CGridCtrl implementation functions
  1205. void CGridCtrl::OnDraw(CDC* pDC)
  1206. {
  1207. if (!m_bAllowDraw)
  1208. return;
  1209. CRect clipRect;
  1210. if (pDC->GetClipBox(&clipRect) == ERROR)
  1211. return;
  1212. EraseBkgnd(pDC); // OnEraseBkgnd does nothing, so erase bkgnd here.
  1213. // This necessary since we may be using a Memory DC.
  1214. #ifdef _DEBUG
  1215. LARGE_INTEGER iStartCount;
  1216. QueryPerformanceCounter(&iStartCount);
  1217. #endif
  1218. CRect rect;
  1219. int row, col;
  1220. CGridCellBase* pCell;
  1221. int nFixedRowHeight = GetFixedRowHeight();
  1222. int nFixedColWidth = GetFixedColumnWidth();
  1223. CCellID idTopLeft = GetTopleftNonFixedCell();
  1224. int minVisibleRow = idTopLeft.row,
  1225. minVisibleCol = idTopLeft.col;
  1226. CRect VisRect;
  1227. CCellRange VisCellRange = GetVisibleNonFixedCellRange(VisRect);
  1228. int maxVisibleRow = VisCellRange.GetMaxRow(),
  1229. maxVisibleCol = VisCellRange.GetMaxCol();
  1230. if (GetVirtualMode())
  1231. SendCacheHintToParent(VisCellRange);
  1232. CPen pen;
  1233. pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
  1234. pDC->SelectObject(&pen);
  1235. // draw vertical lines (drawn at ends of cells)
  1236. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  1237. {
  1238. int x = nFixedColWidth;
  1239. for (col = minVisibleCol; col <= maxVisibleCol; col++)
  1240. {
  1241. if (GetColumnWidth(col) <= 0) continue;
  1242. x += GetColumnWidth(col);
  1243. pDC->MoveTo(x - 1, nFixedRowHeight);
  1244. pDC->LineTo(x - 1, VisRect.bottom);
  1245. }
  1246. }
  1247. // draw horizontal lines (drawn at bottom of each cell)
  1248. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  1249. {
  1250. int y = nFixedRowHeight;
  1251. for (row = minVisibleRow; row <= maxVisibleRow; row++)
  1252. {
  1253. if (GetRowHeight(row) <= 0) continue;
  1254. y += GetRowHeight(row);
  1255. pDC->MoveTo(nFixedColWidth, y - 1);
  1256. pDC->LineTo(VisRect.right, y - 1);
  1257. }
  1258. }
  1259. pDC->SelectStockObject(NULL_PEN);
  1260. // draw rest of non-fixed cells
  1261. rect.bottom = nFixedRowHeight - 1;
  1262. for (row = minVisibleRow; row <= maxVisibleRow; row++)
  1263. {
  1264. if (GetRowHeight(row) <= 0) continue;
  1265. rect.top = rect.bottom + 1;
  1266. rect.bottom = rect.top + GetRowHeight(row) - 1;
  1267. // rect.bottom = bottom pixel of previous row
  1268. if (rect.top > clipRect.bottom)
  1269. break; // Gone past cliprect
  1270. if (rect.bottom < clipRect.top)
  1271. continue; // Reached cliprect yet?
  1272. rect.right = nFixedColWidth - 1;
  1273. for (col = minVisibleCol; col <= maxVisibleCol; col++)
  1274. {
  1275. if (GetColumnWidth(col) <= 0) continue;
  1276. rect.left = rect.right + 1;
  1277. rect.right = rect.left + GetColumnWidth(col) - 1;
  1278. if (rect.left > clipRect.right)
  1279. break; // gone past cliprect
  1280. if (rect.right < clipRect.left)
  1281. continue; // Reached cliprect yet?
  1282. pCell = GetCell(row, col);
  1283. // TRACE(_T("Cell %d,%d type: %s\n"), row, col, pCell->GetRuntimeClass()->m_lpszClassName);
  1284. if (pCell)
  1285. {
  1286. //Used for merge cells
  1287. //by Huang Wei
  1288. if (!pCell->IsMerged())
  1289. {
  1290. if (!pCell->IsMergeWithOthers())
  1291. {
  1292. pCell->SetCoords(row, col);
  1293. pCell->Draw(pDC, row, col, rect, FALSE);
  1294. }
  1295. else
  1296. {
  1297. CGridCellBase* pMergedCell = GetCell(pCell->GetMergeCellID());
  1298. CRect mergerect = rect;
  1299. if (GetCellRangeRect(pMergedCell->m_MergeRange, &mergerect))
  1300. {
  1301. mergerect.DeflateRect(0, 0, 1, 1);
  1302. pMergedCell->SetCoords(pCell->GetMergeCellID().row, pCell->GetMergeCellID().col);
  1303. pMergedCell->Draw(pDC, pCell->GetMergeCellID().row, pCell->GetMergeCellID().col, mergerect, TRUE);
  1304. }
  1305. }
  1306. }
  1307. else
  1308. {
  1309. CRect mergerect = rect;
  1310. if (GetCellRangeRect(pCell->m_MergeRange, &mergerect))
  1311. {
  1312. mergerect.DeflateRect(0, 0, 1, 1);
  1313. pCell->SetCoords(row, col);
  1314. pCell->Draw(pDC, row, col, mergerect, TRUE);
  1315. }
  1316. }
  1317. }
  1318. }
  1319. }
  1320. // draw fixed column cells: m_nFixedRows..n, 0..m_nFixedCols-1
  1321. rect.bottom = nFixedRowHeight - 1;
  1322. for (row = minVisibleRow; row <= maxVisibleRow; row++)
  1323. {
  1324. if (GetRowHeight(row) <= 0) continue;
  1325. rect.top = rect.bottom + 1;
  1326. rect.bottom = rect.top + GetRowHeight(row) - 1;
  1327. // rect.bottom = bottom pixel of previous row
  1328. if (rect.top > clipRect.bottom)
  1329. break; // Gone past cliprect
  1330. if (rect.bottom < clipRect.top)
  1331. continue; // Reached cliprect yet?
  1332. rect.right = -1;
  1333. for (col = 0; col < m_nFixedCols; col++)
  1334. {
  1335. if (GetColumnWidth(col) <= 0) continue;
  1336. rect.left = rect.right + 1;
  1337. rect.right = rect.left + GetColumnWidth(col) - 1;
  1338. if (rect.left > clipRect.right)
  1339. break; // gone past cliprect
  1340. if (rect.right < clipRect.left)
  1341. continue; // Reached cliprect yet?
  1342. pCell = GetCell(row, col);
  1343. // if (pCell)
  1344. //{
  1345. // pCell->SetCoords(row,col);
  1346. // pCell->Draw(pDC, row, col, rect, TRUE);
  1347. //}
  1348. if (pCell)
  1349. {
  1350. //Used for merge cells
  1351. //by Huang Wei
  1352. if (!pCell->IsMerged())
  1353. {
  1354. if (!pCell->IsMergeWithOthers())
  1355. {
  1356. pCell->SetCoords(row, col);
  1357. pCell->Draw(pDC, row, col, rect, FALSE);
  1358. }
  1359. else
  1360. {
  1361. CGridCellBase* pMergedCell = GetCell(pCell->GetMergeCellID());
  1362. CRect mergerect = rect;
  1363. if (GetCellRangeRect(pMergedCell->m_MergeRange, &mergerect))
  1364. {
  1365. mergerect.DeflateRect(0, 0, 1, 1);
  1366. pMergedCell->SetCoords(pCell->GetMergeCellID().row, pCell->GetMergeCellID().col);
  1367. pMergedCell->Draw(pDC, pCell->GetMergeCellID().row, pCell->GetMergeCellID().col, mergerect, TRUE);
  1368. }
  1369. }
  1370. }
  1371. else
  1372. {
  1373. CRect mergerect = rect;
  1374. if (GetCellRangeRect(pCell->m_MergeRange, &mergerect))
  1375. {
  1376. mergerect.DeflateRect(0, 0, 1, 1);
  1377. pCell->SetCoords(row, col);
  1378. pCell->Draw(pDC, row, col, mergerect, TRUE);
  1379. }
  1380. }
  1381. }
  1382. }
  1383. }
  1384. // draw fixed row cells 0..m_nFixedRows, m_nFixedCols..n
  1385. rect.bottom = -1;
  1386. for (row = 0; row < m_nFixedRows; row++)
  1387. {
  1388. if (GetRowHeight(row) <= 0) continue;
  1389. rect.top = rect.bottom + 1;
  1390. rect.bottom = rect.top + GetRowHeight(row) - 1;
  1391. // rect.bottom = bottom pixel of previous row
  1392. if (rect.top > clipRect.bottom)
  1393. break; // Gone past cliprect
  1394. if (rect.bottom < clipRect.top)
  1395. continue; // Reached cliprect yet?
  1396. rect.right = nFixedColWidth - 1;
  1397. for (col = minVisibleCol; col <= maxVisibleCol; col++)
  1398. {
  1399. if (GetColumnWidth(col) <= 0) continue;
  1400. rect.left = rect.right + 1;
  1401. rect.right = rect.left + GetColumnWidth(col) - 1;
  1402. if (rect.left > clipRect.right)
  1403. break; // gone past cliprect
  1404. if (rect.right < clipRect.left)
  1405. continue; // Reached cliprect yet?
  1406. pCell = GetCell(row, col);
  1407. // if (pCell)
  1408. //{
  1409. // pCell->SetCoords(row,col);
  1410. // pCell->Draw(pDC, row, col, rect, TRUE);
  1411. //}
  1412. if (pCell)
  1413. {
  1414. //Used for merge cells
  1415. //by Huang Wei
  1416. if (!pCell->IsMerged())
  1417. {
  1418. if (!pCell->IsMergeWithOthers())
  1419. {
  1420. pCell->SetCoords(row, col);
  1421. pCell->Draw(pDC, row, col, rect, FALSE);
  1422. }
  1423. else
  1424. {
  1425. CGridCellBase* pMergedCell = GetCell(pCell->GetMergeCellID());
  1426. CRect mergerect = rect;
  1427. if (GetCellRangeRect(pMergedCell->m_MergeRange, &mergerect))
  1428. {
  1429. mergerect.DeflateRect(0, 0, 1, 1);
  1430. pMergedCell->SetCoords(pCell->GetMergeCellID().row, pCell->GetMergeCellID().col);
  1431. pMergedCell->Draw(pDC, pCell->GetMergeCellID().row, pCell->GetMergeCellID().col, mergerect, TRUE);
  1432. }
  1433. }
  1434. }
  1435. else
  1436. {
  1437. CRect mergerect = rect;
  1438. if (GetCellRangeRect(pCell->m_MergeRange, &mergerect))
  1439. {
  1440. mergerect.DeflateRect(0, 0, 1, 1);
  1441. pCell->SetCoords(row, col);
  1442. pCell->Draw(pDC, row, col, mergerect, TRUE);
  1443. }
  1444. }
  1445. }
  1446. }
  1447. }
  1448. /*
  1449. // draw top-left cells 0..m_nFixedRows-1, 0..m_nFixedCols-1
  1450. rect.bottom = -1;
  1451. for (row = 0; row < m_nFixedRows; row++)
  1452. {
  1453. if (GetRowHeight(row) <= 0) continue;
  1454. rect.top = rect.bottom+1;
  1455. rect.bottom = rect.top + GetRowHeight(row)-1;
  1456. rect.right = -1;
  1457. for (col = 0; col < m_nFixedCols; col++)
  1458. {
  1459. if (GetColumnWidth(col) <= 0) continue;
  1460. rect.left = rect.right+1;
  1461. rect.right = rect.left + GetColumnWidth(col)-1;
  1462. pCell = GetCell(row, col);
  1463. if (pCell)
  1464. {
  1465. pCell->SetCoords(row,col);
  1466. pCell->Draw(pDC, row, col, rect, FALSE);
  1467. }
  1468. }
  1469. }
  1470. */
  1471. // draw top-left cells 0..m_nFixedRows-1, 0..m_nFixedCols-1
  1472. rect.bottom = -1;
  1473. for (row = 0; row < m_nFixedRows; row++)
  1474. {
  1475. if (GetRowHeight(row) <= 0) continue;
  1476. rect.top = rect.bottom + 1;
  1477. rect.bottom = rect.top + GetRowHeight(row) - 1;
  1478. rect.right = -1;
  1479. for (col = 0; col < m_nFixedCols; col++)
  1480. {
  1481. if (GetColumnWidth(col) <= 0) continue;
  1482. rect.left = rect.right + 1;
  1483. rect.right = rect.left + GetColumnWidth(col) - 1;
  1484. pCell = GetCell(row, col);
  1485. /* if (pCell)
  1486. {
  1487. pCell->SetCoords(row,col);
  1488. pCell->Draw(pDC, row, col, rect, FALSE);
  1489. }*/
  1490. if (pCell)
  1491. {
  1492. //Used for merge cells by Huang Wei
  1493. //bugfix by Luther Bruck
  1494. if (!pCell->IsMerged())
  1495. {
  1496. if (!pCell->IsMergeWithOthers())
  1497. {
  1498. pCell->SetCoords(row, col);
  1499. pCell->Draw(pDC, row, col, rect, FALSE);
  1500. }
  1501. else
  1502. {
  1503. CGridCellBase* pMergedCell = GetCell(pCell->GetMergeCellID());
  1504. CRect mergerect = rect;
  1505. if (GetCellRangeRect(pMergedCell->m_MergeRange, &mergerect))
  1506. {
  1507. mergerect.DeflateRect(0, 0, 1, 1);
  1508. pMergedCell->SetCoords(pCell->GetMergeCellID().row, pCell->GetMergeCellID().col);
  1509. pMergedCell->Draw(pDC, pCell->GetMergeCellID().row, pCell->GetMergeCellID().col, mergerect, TRUE);
  1510. }
  1511. }
  1512. }
  1513. else
  1514. {
  1515. CRect mergerect = rect;
  1516. if (GetCellRangeRect(pCell->m_MergeRange, &mergerect))
  1517. {
  1518. mergerect.DeflateRect(0, 0, 1, 1);
  1519. pCell->SetCoords(row, col);
  1520. pCell->Draw(pDC, row, col, mergerect, TRUE);
  1521. }
  1522. }
  1523. }
  1524. }
  1525. }
  1526. // Let parent know it can discard it's data if it needs to.
  1527. if (GetVirtualMode())
  1528. SendCacheHintToParent(CCellRange(-1, -1, -1, -1));
  1529. #ifdef _DEBUG
  1530. //LARGE_INTEGER iEndCount;
  1531. //QueryPerformanceCounter(&iEndCount);
  1532. //TRACE1("Draw counter ticks: %d\n", iEndCount.LowPart - iStartCount.LowPart);
  1533. #endif
  1534. }
  1535. ////////////////////////////////////////////////////////////////////////////////////////
  1536. // CGridCtrl Cell selection stuff
  1537. // Is a given cell designation valid (ie within the bounds of our number
  1538. // of columns/rows)?
  1539. BOOL CGridCtrl::IsValid(int nRow, int nCol) const
  1540. {
  1541. return (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols);
  1542. }
  1543. BOOL CGridCtrl::IsValid(const CCellID& cell) const
  1544. {
  1545. return IsValid(cell.row, cell.col);
  1546. }
  1547. // Is a given cell range valid (ie within the bounds of our number
  1548. // of columns/rows)?
  1549. BOOL CGridCtrl::IsValid(const CCellRange& range) const
  1550. {
  1551. return (range.GetMinRow() >= 0 && range.GetMinCol() >= 0 &&
  1552. range.GetMaxRow() >= 0 && range.GetMaxCol() >= 0 &&
  1553. range.GetMaxRow() < m_nRows && range.GetMaxCol() < m_nCols &&
  1554. range.GetMinRow() <= range.GetMaxRow() && range.GetMinCol() <= range.GetMaxCol());
  1555. }
  1556. // Enables/Disables redraw for certain operations like columns auto-sizing etc,
  1557. // but not for user caused things such as selection changes.
  1558. void CGridCtrl::SetRedraw(BOOL bAllowDraw, BOOL bResetScrollBars /* = FALSE */)
  1559. {
  1560. // TRACE(_T("%s: Setting redraw to %s\n"),
  1561. // GetRuntimeClass()->m_lpszClassName, bAllowDraw? _T("TRUE") : _T("FALSE"));
  1562. if (bAllowDraw && !m_bAllowDraw)
  1563. {
  1564. m_bAllowDraw = TRUE;
  1565. Refresh();
  1566. }
  1567. m_bAllowDraw = bAllowDraw;
  1568. if (bResetScrollBars)
  1569. ResetScrollBars();
  1570. }
  1571. // Forces a redraw of a cell immediately (using a direct DC construction,
  1572. // or the supplied dc)
  1573. BOOL CGridCtrl::RedrawCell(const CCellID& cell, CDC* pDC /* = NULL */)
  1574. {
  1575. return RedrawCell(cell.row, cell.col, pDC);
  1576. }
  1577. BOOL CGridCtrl::RedrawCell(int nRow, int nCol, CDC* pDC /* = NULL */)
  1578. {
  1579. BOOL bResult = TRUE;
  1580. BOOL bMustReleaseDC = FALSE;
  1581. if (!m_bAllowDraw || !IsCellVisible(nRow, nCol))
  1582. return FALSE;
  1583. CRect rect;
  1584. if (!GetCellRect(nRow, nCol, rect))
  1585. return FALSE;
  1586. if (!pDC)
  1587. {
  1588. pDC = GetDC();
  1589. if (pDC)
  1590. bMustReleaseDC = TRUE;
  1591. }
  1592. if (pDC)
  1593. {
  1594. // Redraw cells directly
  1595. if (nRow < m_nFixedRows || nCol < m_nFixedCols)
  1596. {
  1597. CGridCellBase* pCell = GetCell(nRow, nCol);
  1598. if (pCell)
  1599. bResult = pCell->Draw(pDC, nRow, nCol, rect, TRUE);
  1600. }
  1601. else
  1602. {
  1603. CGridCellBase* pCell = GetCell(nRow, nCol);
  1604. if (pCell)
  1605. bResult = pCell->Draw(pDC, nRow, nCol, rect, TRUE);
  1606. // Since we have erased the background, we will need to redraw the gridlines
  1607. CPen pen;
  1608. pen.CreatePen(PS_SOLID, 0, m_crGridLineColour);
  1609. CPen* pOldPen = (CPen*)pDC->SelectObject(&pen);
  1610. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  1611. {
  1612. pDC->MoveTo(rect.left, rect.bottom);
  1613. pDC->LineTo(rect.right + 1, rect.bottom);
  1614. }
  1615. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  1616. {
  1617. pDC->MoveTo(rect.right, rect.top);
  1618. pDC->LineTo(rect.right, rect.bottom + 1);
  1619. }
  1620. pDC->SelectObject(pOldPen);
  1621. }
  1622. }
  1623. else
  1624. InvalidateRect(rect, TRUE); // Could not get a DC - invalidate it anyway
  1625. // and hope that OnPaint manages to get one
  1626. if (bMustReleaseDC)
  1627. ReleaseDC(pDC);
  1628. return bResult;
  1629. }
  1630. // redraw a complete row
  1631. BOOL CGridCtrl::RedrawRow(int row)
  1632. {
  1633. BOOL bResult = TRUE;
  1634. CDC* pDC = GetDC();
  1635. for (int col = 0; col < GetColumnCount(); col++)
  1636. bResult = RedrawCell(row, col, pDC) && bResult;
  1637. if (pDC)
  1638. ReleaseDC(pDC);
  1639. return bResult;
  1640. }
  1641. // redraw a complete column
  1642. BOOL CGridCtrl::RedrawColumn(int col)
  1643. {
  1644. BOOL bResult = TRUE;
  1645. CDC* pDC = GetDC();
  1646. for (int row = 0; row < GetRowCount(); row++)
  1647. bResult = RedrawCell(row, col, pDC) && bResult;
  1648. if (pDC)
  1649. ReleaseDC(pDC);
  1650. return bResult;
  1651. }
  1652. // Sets the currently selected cell, returning the previous current cell
  1653. CCellID CGridCtrl::SetFocusCell(int nRow, int nCol)
  1654. {
  1655. return SetFocusCell(CCellID(nRow, nCol));
  1656. }
  1657. CCellID CGridCtrl::SetFocusCell(CCellID cell)
  1658. {
  1659. if (cell == m_idCurrentCell)
  1660. return m_idCurrentCell;
  1661. CCellID idPrev = m_idCurrentCell;
  1662. // EFW - Bug Fix - Force focus to be in a non-fixed cell
  1663. if (cell.row != -1 && cell.row < GetFixedRowCount())
  1664. cell.row = GetFixedRowCount();
  1665. if (cell.col != -1 && cell.col < GetFixedColumnCount())
  1666. cell.col = GetFixedColumnCount();
  1667. m_idCurrentCell = cell;
  1668. if (IsValid(idPrev))
  1669. {
  1670. SetItemState(idPrev.row, idPrev.col,
  1671. GetItemState(idPrev.row, idPrev.col) & ~GVIS_FOCUSED);
  1672. RedrawCell(idPrev); // comment to reduce flicker
  1673. if (GetTrackFocusCell() && idPrev.col != m_idCurrentCell.col)
  1674. for (int row = 0; row < m_nFixedRows; row++)
  1675. RedrawCell(row, idPrev.col);
  1676. if (GetTrackFocusCell() && idPrev.row != m_idCurrentCell.row)
  1677. for (int col = 0; col < m_nFixedCols; col++)
  1678. RedrawCell(idPrev.row, col);
  1679. }
  1680. if (IsValid(m_idCurrentCell))
  1681. {
  1682. SetItemState(m_idCurrentCell.row, m_idCurrentCell.col,
  1683. GetItemState(m_idCurrentCell.row, m_idCurrentCell.col) | GVIS_FOCUSED);
  1684. RedrawCell(m_idCurrentCell); // comment to reduce flicker
  1685. if (GetTrackFocusCell() && idPrev.col != m_idCurrentCell.col)
  1686. for (int row = 0; row < m_nFixedRows; row++)
  1687. RedrawCell(row, m_idCurrentCell.col);
  1688. if (GetTrackFocusCell() && idPrev.row != m_idCurrentCell.row)
  1689. for (int col = 0; col < m_nFixedCols; col++)
  1690. RedrawCell(m_idCurrentCell.row, col);
  1691. // EFW - New addition. If in list mode, make sure the selected
  1692. // row highlight follows the cursor.
  1693. // Removed by C Maunder 27 May
  1694. //if (m_bListMode)
  1695. //{
  1696. // m_PrevSelectedCellMap.RemoveAll();
  1697. // m_MouseMode = MOUSE_SELECT_ROW;
  1698. // OnSelecting(m_idCurrentCell);
  1699. // Leave this off so that you can still drag the highlight around
  1700. // without selecting rows.
  1701. // m_MouseMode = MOUSE_NOTHING;
  1702. //}
  1703. }
  1704. return idPrev;
  1705. }
  1706. // Sets the range of currently selected cells
  1707. void CGridCtrl::SetSelectedRange(const CCellRange& Range,
  1708. BOOL bForceRepaint /* = FALSE */, BOOL bSelectCells/*=TRUE*/)
  1709. {
  1710. SetSelectedRange(Range.GetMinRow(), Range.GetMinCol(),
  1711. Range.GetMaxRow(), Range.GetMaxCol(),
  1712. bForceRepaint, bSelectCells);
  1713. }
  1714. void CGridCtrl::SetSelectedRange(int nMinRow, int nMinCol, int nMaxRow, int nMaxCol,
  1715. BOOL bForceRepaint /* = FALSE */, BOOL bSelectCells/*=TRUE*/)
  1716. {
  1717. if (!m_bEnableSelection)
  1718. return;
  1719. CWaitCursor wait; // Thomas Haase
  1720. CDC* pDC = NULL;
  1721. if (bForceRepaint)
  1722. pDC = GetDC();
  1723. // Only redraw visible cells
  1724. CCellRange VisCellRange;
  1725. if (IsWindow(GetSafeHwnd()))
  1726. VisCellRange = GetVisibleNonFixedCellRange();
  1727. // EFW - Bug fix - Don't allow selection of fixed rows
  1728. if (nMinRow >= 0 && nMinRow < GetFixedRowCount())
  1729. nMinRow = GetFixedRowCount();
  1730. if (nMaxRow >= 0 && nMaxRow < GetFixedRowCount())
  1731. nMaxRow = GetFixedRowCount();
  1732. if (nMinCol >= 0 && nMinCol < GetFixedColumnCount())
  1733. nMinCol = GetFixedColumnCount();
  1734. if (nMaxCol >= 0 && nMaxCol < GetFixedColumnCount())
  1735. nMaxCol = GetFixedColumnCount();
  1736. // If we are selecting cells, then first clear out the list of currently selected cells, then
  1737. if (bSelectCells)
  1738. {
  1739. POSITION pos;
  1740. // Unselect all previously selected cells
  1741. for (pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
  1742. {
  1743. DWORD key;
  1744. CCellID cell;
  1745. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  1746. // Reset the selection flag on the cell
  1747. if (IsValid(cell))
  1748. {
  1749. // This will remove the cell from the m_SelectedCellMap map
  1750. SetItemState(cell.row, cell.col,
  1751. GetItemState(cell.row, cell.col) & ~GVIS_SELECTED);
  1752. // If this is to be reselected, continue on past the redraw
  1753. if (nMinRow <= cell.row && cell.row <= nMaxRow &&
  1754. nMinCol <= cell.col && cell.col <= nMaxCol)
  1755. continue;
  1756. if (VisCellRange.IsValid() && VisCellRange.InRange(cell))
  1757. {
  1758. if (bForceRepaint && pDC) // Redraw NOW
  1759. RedrawCell(cell.row, cell.col, pDC);
  1760. else
  1761. InvalidateCellRect(cell); // Redraw at leisure
  1762. }
  1763. }
  1764. else
  1765. {
  1766. m_SelectedCellMap.RemoveKey(key); // if it's not valid, get rid of it!
  1767. }
  1768. }
  1769. // if we are selecting cells, and there are previous selected cells to be retained
  1770. // (eg Ctrl is being held down) then copy them to the newly created list, and mark
  1771. // all these cells as selected
  1772. // Note that if we are list mode, single row selection, then we won't be adding
  1773. // the previous cells. Only the current row of cells will be added (see below)
  1774. if (!GetSingleRowSelection() &&
  1775. nMinRow >= 0 && nMinCol >= 0 && nMaxRow >= 0 && nMaxCol >= 0)
  1776. {
  1777. for (pos = m_PrevSelectedCellMap.GetStartPosition(); pos != NULL; /* nothing */)
  1778. {
  1779. DWORD key;
  1780. CCellID cell;
  1781. m_PrevSelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  1782. if (!IsValid(cell))
  1783. continue;
  1784. int nState = GetItemState(cell.row, cell.col);
  1785. // Set state as Selected. This will add the cell to m_SelectedCellMap
  1786. SetItemState(cell.row, cell.col, nState | GVIS_SELECTED);
  1787. if (VisCellRange.IsValid() && VisCellRange.InRange(cell))
  1788. {
  1789. // Redraw (immediately or at leisure)
  1790. if (bForceRepaint && pDC)
  1791. RedrawCell(cell.row, cell.col, pDC);
  1792. else
  1793. InvalidateCellRect(cell);
  1794. }
  1795. }
  1796. }
  1797. }
  1798. // Now select/deselect all cells in the cell range specified. If selecting, and the cell
  1799. // has already been marked as selected (above) then ignore it. If we are deselecting and
  1800. // the cell isn't selected, then ignore
  1801. if (nMinRow >= 0 && nMinCol >= 0 && nMaxRow >= 0 && nMaxCol >= 0 &&
  1802. nMaxRow < m_nRows && nMaxCol < m_nCols &&
  1803. nMinRow <= nMaxRow && nMinCol <= nMaxCol)
  1804. {
  1805. for (int row = nMinRow; row <= nMaxRow; row++)
  1806. for (int col = nMinCol; col <= nMaxCol; col++)
  1807. {
  1808. BOOL bCellSelected = IsCellSelected(row, col);
  1809. if (bSelectCells == bCellSelected)
  1810. continue; // Already selected or deselected - ignore
  1811. // Set the selected state. This will add/remove the cell to m_SelectedCellMap
  1812. if (bSelectCells)
  1813. SetItemState(row, col, GetItemState(row, col) | GVIS_SELECTED);
  1814. else
  1815. SetItemState(row, col, GetItemState(row, col) & ~GVIS_SELECTED);
  1816. if (VisCellRange.IsValid() && VisCellRange.InRange(row, col))
  1817. {
  1818. // Redraw (immediately or at leisure)
  1819. if (bForceRepaint && pDC)
  1820. RedrawCell(row, col, pDC);
  1821. else
  1822. InvalidateCellRect(row, col);
  1823. }
  1824. }
  1825. }
  1826. // TRACE(_T("%d cells selected.\n"), m_SelectedCellMap.GetCount());
  1827. if (pDC != NULL)
  1828. ReleaseDC(pDC);
  1829. }
  1830. // selects all cells
  1831. void CGridCtrl::SelectAllCells()
  1832. {
  1833. if (!m_bEnableSelection)
  1834. return;
  1835. SetSelectedRange(m_nFixedRows, m_nFixedCols, GetRowCount() - 1, GetColumnCount() - 1);
  1836. }
  1837. // selects columns
  1838. void CGridCtrl::SelectColumns(CCellID currentCell,
  1839. BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
  1840. {
  1841. if (!m_bEnableSelection)
  1842. return;
  1843. //if (currentCell.col == m_idCurrentCell.col) return;
  1844. if (currentCell.col < m_nFixedCols)
  1845. return;
  1846. if (!IsValid(currentCell))
  1847. return;
  1848. if (GetSingleColSelection())
  1849. SetSelectedRange(GetFixedRowCount(), currentCell.col,
  1850. GetRowCount() - 1, currentCell.col,
  1851. bForceRedraw, bSelectCells);
  1852. else
  1853. SetSelectedRange(GetFixedRowCount(),
  1854. min(m_SelectionStartCell.col, currentCell.col),
  1855. GetRowCount() - 1,
  1856. max(m_SelectionStartCell.col, currentCell.col),
  1857. bForceRedraw, bSelectCells);
  1858. }
  1859. // selects rows
  1860. void CGridCtrl::SelectRows(CCellID currentCell,
  1861. BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
  1862. {
  1863. if (!m_bEnableSelection)
  1864. return;
  1865. //if (currentCell.row; == m_idCurrentCell.row) return;
  1866. if (currentCell.row < m_nFixedRows)
  1867. return;
  1868. if (!IsValid(currentCell))
  1869. return;
  1870. if (GetSingleRowSelection())
  1871. SetSelectedRange(currentCell.row, GetFixedColumnCount(),
  1872. currentCell.row, GetColumnCount() - 1,
  1873. bForceRedraw, bSelectCells);
  1874. else
  1875. SetSelectedRange(min(m_SelectionStartCell.row, currentCell.row),
  1876. GetFixedColumnCount(),
  1877. max(m_SelectionStartCell.row, currentCell.row),
  1878. GetColumnCount() - 1,
  1879. bForceRedraw, bSelectCells);
  1880. }
  1881. // selects cells
  1882. void CGridCtrl::SelectCells(CCellID currentCell,
  1883. BOOL bForceRedraw /*=FALSE*/, BOOL bSelectCells /*=TRUE*/)
  1884. {
  1885. if (!m_bEnableSelection)
  1886. return;
  1887. int row = currentCell.row;
  1888. int col = currentCell.col;
  1889. if (row < m_nFixedRows || col < m_nFixedCols)
  1890. return;
  1891. if (!IsValid(currentCell))
  1892. return;
  1893. // Prevent unnecessary redraws
  1894. //if (currentCell == m_LeftClickDownCell) return;
  1895. //else if (currentCell == m_idCurrentCell) return;
  1896. SetSelectedRange(min(m_SelectionStartCell.row, row),
  1897. min(m_SelectionStartCell.col, col),
  1898. max(m_SelectionStartCell.row, row),
  1899. max(m_SelectionStartCell.col, col),
  1900. bForceRedraw, bSelectCells);
  1901. }
  1902. // Called when mouse/keyboard selection is a-happening.
  1903. void CGridCtrl::OnSelecting(const CCellID& currentCell)
  1904. {
  1905. if (!m_bEnableSelection)
  1906. return;
  1907. switch (m_MouseMode)
  1908. {
  1909. case MOUSE_SELECT_ALL:
  1910. SelectAllCells();
  1911. break;
  1912. case MOUSE_SELECT_COL:
  1913. SelectColumns(currentCell, FALSE);
  1914. break;
  1915. case MOUSE_SELECT_ROW:
  1916. SelectRows(currentCell, FALSE);
  1917. break;
  1918. case MOUSE_SELECT_CELLS:
  1919. SelectCells(currentCell, FALSE);
  1920. break;
  1921. }
  1922. // EFW - Bug fix [REMOVED CJM: this will cause infinite loop in list mode]
  1923. // SetFocusCell(max(currentCell.row, m_nFixedRows), max(currentCell.col, m_nFixedCols));
  1924. }
  1925. void CGridCtrl::ValidateAndModifyCellContents(int nRow, int nCol, LPCTSTR strText)
  1926. {
  1927. if (!IsCellEditable(nRow, nCol))
  1928. return;
  1929. if (SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT) >= 0)
  1930. {
  1931. CString strCurrentText = GetItemText(nRow, nCol);
  1932. if (strCurrentText != strText)
  1933. {
  1934. SetItemText(nRow, nCol, strText);
  1935. if (ValidateEdit(nRow, nCol, strText) &&
  1936. SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT) >= 0)
  1937. {
  1938. SetModified(TRUE, nRow, nCol);
  1939. RedrawCell(nRow, nCol);
  1940. }
  1941. else
  1942. {
  1943. SetItemText(nRow, nCol, strCurrentText);
  1944. }
  1945. }
  1946. }
  1947. }
  1948. void CGridCtrl::ClearCells(CCellRange Selection)
  1949. {
  1950. for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
  1951. {
  1952. for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
  1953. {
  1954. // don't clear hidden cells
  1955. if (m_arRowHeights[row] > 0 && m_arColWidths[col] > 0)
  1956. {
  1957. ValidateAndModifyCellContents(row, col, _T(""));
  1958. }
  1959. }
  1960. }
  1961. Refresh();
  1962. }
  1963. #ifndef GRIDCONTROL_NO_CLIPBOARD
  1964. ////////////////////////////////////////////////////////////////////////////////////////
  1965. // Clipboard functions
  1966. // Deletes the contents from the selected cells
  1967. void CGridCtrl::CutSelectedText()
  1968. {
  1969. if (!IsEditable())
  1970. return;
  1971. for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
  1972. {
  1973. DWORD key;
  1974. CCellID cell;
  1975. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  1976. ValidateAndModifyCellContents(cell.row, cell.col, _T(""));
  1977. }
  1978. }
  1979. // Copies text from the selected cells to the clipboard
  1980. COleDataSource* CGridCtrl::CopyTextFromGrid()
  1981. {
  1982. USES_CONVERSION;
  1983. CCellRange Selection = GetSelectedCellRange();
  1984. if (!IsValid(Selection))
  1985. return NULL;
  1986. if (GetVirtualMode())
  1987. SendCacheHintToParent(Selection);
  1988. // Write to shared file (REMEBER: CF_TEXT is ANSI, not UNICODE, so we need to convert)
  1989. CSharedFile sf(GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
  1990. // Get a tab delimited string to copy to cache
  1991. CString str;
  1992. CGridCellBase *pCell;
  1993. for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
  1994. {
  1995. // don't copy hidden cells
  1996. if (m_arRowHeights[row] <= 0)
  1997. continue;
  1998. str.Empty();
  1999. for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
  2000. {
  2001. // don't copy hidden cells
  2002. if (m_arColWidths[col] <= 0)
  2003. continue;
  2004. pCell = GetCell(row, col);
  2005. if (pCell && (pCell->GetState() & GVIS_SELECTED))
  2006. {
  2007. // if (!pCell->GetText())
  2008. // str += _T(" ");
  2009. // else
  2010. str += pCell->GetText();
  2011. }
  2012. if (col != Selection.GetMaxCol())
  2013. str += _T("\t");
  2014. }
  2015. if (row != Selection.GetMaxRow())
  2016. str += _T("\n");
  2017. sf.Write(T2A(str.GetBuffer(1)), str.GetLength());
  2018. str.ReleaseBuffer();
  2019. }
  2020. char c = '\0';
  2021. sf.Write(&c, 1);
  2022. if (GetVirtualMode())
  2023. SendCacheHintToParent(CCellRange(-1, -1, -1, -1));
  2024. DWORD dwLen = (DWORD)sf.GetLength();
  2025. HGLOBAL hMem = sf.Detach();
  2026. if (!hMem)
  2027. return NULL;
  2028. hMem = ::GlobalReAlloc(hMem, dwLen, GMEM_MOVEABLE | GMEM_DDESHARE | GMEM_ZEROINIT);
  2029. if (!hMem)
  2030. return NULL;
  2031. // Cache data
  2032. COleDataSource* pSource = new COleDataSource();
  2033. pSource->CacheGlobalData(CF_TEXT, hMem);
  2034. return pSource;
  2035. }
  2036. // Pastes text from the clipboard to the selected cells
  2037. BOOL CGridCtrl::PasteTextToGrid(CCellID cell, COleDataObject* pDataObject,
  2038. BOOL bSelectPastedCells /*=TRUE*/)
  2039. {
  2040. if (!IsValid(cell) || !IsCellEditable(cell) || !pDataObject->IsDataAvailable(CF_TEXT))
  2041. return FALSE;
  2042. // Get the text from the COleDataObject
  2043. HGLOBAL hmem = pDataObject->GetGlobalData(CF_TEXT);
  2044. CMemFile sf((BYTE*) ::GlobalLock(hmem), (UINT)::GlobalSize(hmem));
  2045. // CF_TEXT is ANSI text, so we need to allocate a char* buffer
  2046. // to hold this.
  2047. LPSTR szBuffer = new char[::GlobalSize(hmem)];
  2048. if (!szBuffer)
  2049. return FALSE;
  2050. sf.Read(szBuffer, (UINT)::GlobalSize(hmem));
  2051. ::GlobalUnlock(hmem);
  2052. // Now store in generic TCHAR form so we no longer have to deal with
  2053. // ANSI/UNICODE problems
  2054. CString strText = szBuffer;
  2055. delete szBuffer;
  2056. // Parse text data and set in cells...
  2057. strText.LockBuffer();
  2058. CString strLine = strText;
  2059. int nLine = 0;
  2060. // Find the end of the first line
  2061. CCellRange PasteRange(cell.row, cell.col, -1, -1);
  2062. int nIndex;
  2063. do
  2064. {
  2065. int nColumn = 0;
  2066. nIndex = strLine.Find(_T("\n"));
  2067. // Store the remaining chars after the newline
  2068. CString strNext = (nIndex < 0) ? _T("") : strLine.Mid(nIndex + 1);
  2069. // Remove all chars after the newline
  2070. if (nIndex >= 0)
  2071. strLine = strLine.Left(nIndex);
  2072. int nLineIndex = strLine.FindOneOf(_T("\t,"));
  2073. CString strCellText = (nLineIndex >= 0) ? strLine.Left(nLineIndex) : strLine;
  2074. // skip hidden rows
  2075. int iRowVis = cell.row + nLine;
  2076. while (iRowVis < GetRowCount())
  2077. {
  2078. if (GetRowHeight(iRowVis) > 0)
  2079. break;
  2080. nLine++;
  2081. iRowVis++;
  2082. }
  2083. while (!strLine.IsEmpty())
  2084. {
  2085. // skip hidden columns
  2086. int iColVis = cell.col + nColumn;
  2087. while (iColVis < GetColumnCount())
  2088. {
  2089. if (GetColumnWidth(iColVis) > 0)
  2090. break;
  2091. nColumn++;
  2092. iColVis++;
  2093. }
  2094. CCellID TargetCell(iRowVis, iColVis);
  2095. if (IsValid(TargetCell))
  2096. {
  2097. strCellText.TrimLeft();
  2098. strCellText.TrimRight();
  2099. ValidateAndModifyCellContents(TargetCell.row, TargetCell.col, strCellText);
  2100. // Make sure cell is not selected to avoid data loss
  2101. SetItemState(TargetCell.row, TargetCell.col,
  2102. GetItemState(TargetCell.row, TargetCell.col) & ~GVIS_SELECTED);
  2103. if (iRowVis > PasteRange.GetMaxRow()) PasteRange.SetMaxRow(iRowVis);
  2104. if (iColVis > PasteRange.GetMaxCol()) PasteRange.SetMaxCol(iColVis);
  2105. }
  2106. strLine = (nLineIndex >= 0) ? strLine.Mid(nLineIndex + 1) : _T("");
  2107. nLineIndex = strLine.FindOneOf(_T("\t,"));
  2108. strCellText = (nLineIndex >= 0) ? strLine.Left(nLineIndex) : strLine;
  2109. nColumn++;
  2110. }
  2111. strLine = strNext;
  2112. nLine++;
  2113. } while (nIndex >= 0);
  2114. strText.UnlockBuffer();
  2115. if (bSelectPastedCells)
  2116. SetSelectedRange(PasteRange, TRUE);
  2117. else
  2118. {
  2119. ResetSelectedRange();
  2120. Refresh();
  2121. }
  2122. return TRUE;
  2123. }
  2124. #endif
  2125. #ifndef GRIDCONTROL_NO_DRAGDROP
  2126. // Start drag n drop
  2127. void CGridCtrl::OnBeginDrag()
  2128. {
  2129. if (!m_bAllowDragAndDrop)
  2130. return;
  2131. COleDataSource* pSource = CopyTextFromGrid();
  2132. if (pSource)
  2133. {
  2134. SendMessageToParent(GetSelectedCellRange().GetTopLeft().row,
  2135. GetSelectedCellRange().GetTopLeft().col,
  2136. GVN_BEGINDRAG);
  2137. m_MouseMode = MOUSE_DRAGGING;
  2138. m_bLMouseButtonDown = FALSE;
  2139. DROPEFFECT dropEffect = pSource->DoDragDrop(DROPEFFECT_COPY | DROPEFFECT_MOVE);
  2140. if (dropEffect & DROPEFFECT_MOVE)
  2141. CutSelectedText();
  2142. if (pSource)
  2143. delete pSource; // Did not pass source to clipboard, so must delete
  2144. }
  2145. }
  2146. // Handle drag over grid
  2147. DROPEFFECT CGridCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState,
  2148. CPoint point)
  2149. {
  2150. // Any text data available for us?
  2151. if (!m_bAllowDragAndDrop || !IsEditable() || !pDataObject->IsDataAvailable(CF_TEXT))
  2152. return DROPEFFECT_NONE;
  2153. // Find which cell we are over and drop-highlight it
  2154. CCellID cell = GetCellFromPt(point, FALSE);
  2155. // If not valid, set the previously drop-highlighted cell as no longer drop-highlighted
  2156. if (!IsValid(cell))
  2157. {
  2158. OnDragLeave();
  2159. m_LastDragOverCell = CCellID(-1, -1);
  2160. return DROPEFFECT_NONE;
  2161. }
  2162. if (!IsCellEditable(cell))
  2163. return DROPEFFECT_NONE;
  2164. // Have we moved over a different cell than last time?
  2165. if (cell != m_LastDragOverCell)
  2166. {
  2167. // Set the previously drop-highlighted cell as no longer drop-highlighted
  2168. if (IsValid(m_LastDragOverCell))
  2169. {
  2170. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  2171. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  2172. nState & ~GVIS_DROPHILITED);
  2173. RedrawCell(m_LastDragOverCell);
  2174. }
  2175. m_LastDragOverCell = cell;
  2176. // Set the new cell as drop-highlighted
  2177. if (IsValid(m_LastDragOverCell))
  2178. {
  2179. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  2180. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  2181. nState | GVIS_DROPHILITED);
  2182. RedrawCell(m_LastDragOverCell);
  2183. }
  2184. }
  2185. // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
  2186. if (dwKeyState & MK_CONTROL)
  2187. return DROPEFFECT_COPY;
  2188. else
  2189. return DROPEFFECT_MOVE;
  2190. }
  2191. // Something has just been dragged onto the grid
  2192. DROPEFFECT CGridCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState,
  2193. CPoint point)
  2194. {
  2195. // Any text data available for us?
  2196. if (!m_bAllowDragAndDrop || !pDataObject->IsDataAvailable(CF_TEXT))
  2197. return DROPEFFECT_NONE;
  2198. // Find which cell we are over and drop-highlight it
  2199. m_LastDragOverCell = GetCellFromPt(point, FALSE);
  2200. if (!IsValid(m_LastDragOverCell))
  2201. return DROPEFFECT_NONE;
  2202. if (!IsCellEditable(m_LastDragOverCell))
  2203. return DROPEFFECT_NONE;
  2204. if (IsValid(m_LastDragOverCell))
  2205. {
  2206. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  2207. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  2208. nState | GVIS_DROPHILITED);
  2209. RedrawCell(m_LastDragOverCell);
  2210. }
  2211. // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
  2212. if (dwKeyState & MK_CONTROL)
  2213. return DROPEFFECT_COPY;
  2214. else
  2215. return DROPEFFECT_MOVE;
  2216. }
  2217. // Something has just been dragged away from the grid
  2218. void CGridCtrl::OnDragLeave()
  2219. {
  2220. // Set the previously drop-highlighted cell as no longer drop-highlighted
  2221. if (IsValid(m_LastDragOverCell))
  2222. {
  2223. UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
  2224. SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
  2225. nState & ~GVIS_DROPHILITED);
  2226. RedrawCell(m_LastDragOverCell);
  2227. }
  2228. }
  2229. // Something has just been dropped onto the grid
  2230. BOOL CGridCtrl::OnDrop(COleDataObject* pDataObject, DROPEFFECT /*dropEffect*/,
  2231. CPoint /* point */)
  2232. {
  2233. m_MouseMode = MOUSE_NOTHING;
  2234. if (!m_bAllowDragAndDrop || !IsCellEditable(m_LastDragOverCell))
  2235. return FALSE;
  2236. OnDragLeave();
  2237. return PasteTextToGrid(m_LastDragOverCell, pDataObject, FALSE);
  2238. }
  2239. #endif
  2240. #ifndef GRIDCONTROL_NO_CLIPBOARD
  2241. void CGridCtrl::OnEditCut()
  2242. {
  2243. if (!IsEditable())
  2244. return;
  2245. COleDataSource* pSource = CopyTextFromGrid();
  2246. if (!pSource)
  2247. return;
  2248. pSource->SetClipboard();
  2249. CutSelectedText();
  2250. }
  2251. void CGridCtrl::OnEditCopy()
  2252. {
  2253. COleDataSource* pSource = CopyTextFromGrid();
  2254. if (!pSource)
  2255. return;
  2256. pSource->SetClipboard();
  2257. }
  2258. void CGridCtrl::OnEditPaste()
  2259. {
  2260. if (!IsEditable())
  2261. return;
  2262. CCellRange cellRange = GetSelectedCellRange();
  2263. // Get the top-left selected cell, or the Focus cell, or the topleft (non-fixed) cell
  2264. CCellID cell;
  2265. if (cellRange.IsValid())
  2266. {
  2267. cell.row = cellRange.GetMinRow();
  2268. cell.col = cellRange.GetMinCol();
  2269. }
  2270. else
  2271. {
  2272. cell = GetFocusCell();
  2273. if (!IsValid(cell))
  2274. cell = GetTopleftNonFixedCell();
  2275. if (!IsValid(cell))
  2276. return;
  2277. }
  2278. // If a cell is being edited, then call it's edit window paste function.
  2279. if (IsItemEditing(cell.row, cell.col))
  2280. {
  2281. CGridCellBase* pCell = GetCell(cell.row, cell.col);
  2282. ASSERT(pCell);
  2283. if (!pCell) return;
  2284. CWnd* pEditWnd = pCell->GetEditWnd();
  2285. if (pEditWnd && pEditWnd->IsKindOf(RUNTIME_CLASS(CEdit)))
  2286. {
  2287. ((CEdit*)pEditWnd)->Paste();
  2288. return;
  2289. }
  2290. }
  2291. // Attach a COleDataObject to the clipboard and paste the data to the grid
  2292. COleDataObject obj;
  2293. if (obj.AttachClipboard())
  2294. PasteTextToGrid(cell, &obj);
  2295. }
  2296. #endif
  2297. void CGridCtrl::OnEditSelectAll()
  2298. {
  2299. SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
  2300. SelectAllCells();
  2301. SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
  2302. }
  2303. #ifndef GRIDCONTROL_NO_CLIPBOARD
  2304. void CGridCtrl::OnUpdateEditCopy(CCmdUI* pCmdUI)
  2305. {
  2306. pCmdUI->Enable(GetSelectedCount() > 0); // - Thomas Haase
  2307. //CCellRange Selection = GetSelectedCellRange();
  2308. //pCmdUI->Enable(Selection.Count() && IsValid(Selection));
  2309. }
  2310. void CGridCtrl::OnUpdateEditCut(CCmdUI* pCmdUI)
  2311. {
  2312. pCmdUI->Enable(IsEditable() && GetSelectedCount() > 0); // - Thomas Haase
  2313. //CCellRange Selection = GetSelectedCellRange();
  2314. //pCmdUI->Enable(IsEditable() && Selection.Count() && IsValid(Selection));
  2315. }
  2316. void CGridCtrl::OnUpdateEditPaste(CCmdUI* pCmdUI)
  2317. {
  2318. CCellID cell = GetFocusCell();
  2319. BOOL bCanPaste = IsValid(cell) && IsCellEditable(cell) &&
  2320. ::IsClipboardFormatAvailable(CF_TEXT);
  2321. pCmdUI->Enable(bCanPaste);
  2322. }
  2323. #endif
  2324. void CGridCtrl::OnUpdateEditSelectAll(CCmdUI* pCmdUI)
  2325. {
  2326. pCmdUI->Enable(m_bEnableSelection);
  2327. }
  2328. ////////////////////////////////////////////////////////////////////////////////////////
  2329. // hittest-like functions
  2330. // TRUE if the mouse is over a row resize area
  2331. BOOL CGridCtrl::MouseOverRowResizeArea(CPoint& point)
  2332. {
  2333. if (point.x >= GetFixedColumnWidth())
  2334. return FALSE;
  2335. CCellID idCurrentCell = GetCellFromPt(point);
  2336. CPoint start;
  2337. if (!GetCellOrigin(idCurrentCell, &start))
  2338. return FALSE;
  2339. //int endy = start.y + GetRowHeight(idCurrentCell.row);
  2340. //Merge the selected cells
  2341. //by Huang Wei
  2342. int endy = start.y + GetMergeCellHeight(idCurrentCell);
  2343. if ((point.y - start.y < m_nResizeCaptureRange && idCurrentCell.row != 0) ||
  2344. endy - point.y < m_nResizeCaptureRange)
  2345. {
  2346. return TRUE;
  2347. }
  2348. else
  2349. return FALSE;
  2350. }
  2351. // TRUE if the mouse is over a column resize area. point is in Client coords
  2352. BOOL CGridCtrl::MouseOverColumnResizeArea(CPoint& point)
  2353. {
  2354. if (point.y >= GetFixedRowHeight())
  2355. return FALSE;
  2356. CCellID idCurrentCell = GetCellFromPt(point);
  2357. CPoint start;
  2358. if (!GetCellOrigin(idCurrentCell, &start))
  2359. return FALSE;
  2360. //int endx = start.x + GetColumnWidth(idCurrentCell.col);
  2361. //Merge the selected cells
  2362. //by Huang Wei
  2363. int endx = start.x + GetMergeCellWidth(idCurrentCell);
  2364. if ((point.x - start.x < m_nResizeCaptureRange && idCurrentCell.col != 0) ||
  2365. endx - point.x < m_nResizeCaptureRange)
  2366. {
  2367. return TRUE;
  2368. }
  2369. else
  2370. return FALSE;
  2371. }
  2372. // Get cell from point.
  2373. // point - client coordinates
  2374. // bAllowFixedCellCheck - if TRUE then fixed cells are checked
  2375. CCellID CGridCtrl::GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck /*=TRUE*/)
  2376. {
  2377. CCellID cellID; // return value
  2378. CCellID idTopLeft = GetTopleftNonFixedCell();
  2379. if (!bAllowFixedCellCheck && !IsValid(idTopLeft))
  2380. return cellID;
  2381. // calculate column index
  2382. int fixedColWidth = GetFixedColumnWidth();
  2383. if (point.x < 0 || (!bAllowFixedCellCheck && point.x < fixedColWidth)) // not in window
  2384. cellID.col = -1;
  2385. else if (point.x < fixedColWidth) // in fixed col
  2386. {
  2387. int xpos = 0;
  2388. int col = 0;
  2389. while (col < m_nFixedCols)
  2390. {
  2391. xpos += GetColumnWidth(col);
  2392. if (xpos > point.x)
  2393. break;
  2394. col++;
  2395. }
  2396. cellID.col = col;
  2397. }
  2398. else // in non-fixed col
  2399. {
  2400. int xpos = fixedColWidth;
  2401. int col = idTopLeft.col; //m_nFixedCols;
  2402. while (col < GetColumnCount())
  2403. {
  2404. xpos += GetColumnWidth(col);
  2405. if (xpos > point.x)
  2406. break;
  2407. col++;
  2408. }
  2409. if (col >= GetColumnCount())
  2410. cellID.col = -1;
  2411. else
  2412. cellID.col = col;
  2413. }
  2414. // calculate row index
  2415. int fixedRowHeight = GetFixedRowHeight();
  2416. if (point.y < 0 || (!bAllowFixedCellCheck && point.y < fixedRowHeight)) // not in window
  2417. cellID.row = -1;
  2418. else if (point.y < fixedRowHeight) // in fixed col
  2419. {
  2420. int ypos = 0;
  2421. int row = 0;
  2422. while (row < m_nFixedRows)
  2423. {
  2424. ypos += GetRowHeight(row);
  2425. if (ypos > point.y)
  2426. break;
  2427. row++;
  2428. }
  2429. cellID.row = row;
  2430. }
  2431. else
  2432. {
  2433. int ypos = fixedRowHeight;
  2434. int row = idTopLeft.row; //m_nFixedRows;
  2435. while (row < GetRowCount())
  2436. {
  2437. ypos += GetRowHeight(row);
  2438. if (ypos > point.y)
  2439. break;
  2440. row++;
  2441. }
  2442. if (row >= GetRowCount())
  2443. cellID.row = -1;
  2444. else
  2445. cellID.row = row;
  2446. }
  2447. cellID = GetMergeCellID(cellID);
  2448. return cellID;
  2449. }
  2450. ////////////////////////////////////////////////////////////////////////////////
  2451. // CGridCtrl cellrange functions
  2452. // Gets the first non-fixed cell ID
  2453. CCellID CGridCtrl::GetTopleftNonFixedCell(BOOL bForceRecalculation /*=FALSE*/)
  2454. {
  2455. // Used cached value if possible
  2456. if (m_idTopLeftCell.IsValid() && !bForceRecalculation)
  2457. return m_idTopLeftCell;
  2458. int nVertScroll = GetScrollPos(SB_VERT),
  2459. nHorzScroll = GetScrollPos(SB_HORZ);
  2460. m_idTopLeftCell.col = m_nFixedCols;
  2461. int nRight = 0;
  2462. while (nRight < nHorzScroll && m_idTopLeftCell.col < (GetColumnCount() - 1))
  2463. nRight += GetColumnWidth(m_idTopLeftCell.col++);
  2464. m_idTopLeftCell.row = m_nFixedRows;
  2465. int nTop = 0;
  2466. while (nTop < nVertScroll && m_idTopLeftCell.row < (GetRowCount() - 1))
  2467. nTop += GetRowHeight(m_idTopLeftCell.row++);
  2468. //TRACE2("TopLeft cell is row %d, col %d\n",m_idTopLeftCell.row, m_idTopLeftCell.col);
  2469. return m_idTopLeftCell;
  2470. }
  2471. // This gets even partially visible cells
  2472. CCellRange CGridCtrl::GetVisibleNonFixedCellRange(LPRECT pRect /*=NULL*/,
  2473. BOOL bForceRecalculation /*=FALSE*/)
  2474. {
  2475. CRect rect;
  2476. GetClientRect(rect);
  2477. CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);
  2478. // calc bottom
  2479. int bottom = GetFixedRowHeight();
  2480. int i;
  2481. for (i = idTopLeft.row; i < GetRowCount(); i++)
  2482. {
  2483. bottom += GetRowHeight(i);
  2484. if (bottom >= rect.bottom)
  2485. {
  2486. bottom = rect.bottom;
  2487. break;
  2488. }
  2489. }
  2490. int maxVisibleRow = min(i, GetRowCount() - 1);
  2491. // calc right
  2492. int right = GetFixedColumnWidth();
  2493. for (i = idTopLeft.col; i < GetColumnCount(); i++)
  2494. {
  2495. right += GetColumnWidth(i);
  2496. if (right >= rect.right)
  2497. {
  2498. right = rect.right;
  2499. break;
  2500. }
  2501. }
  2502. int maxVisibleCol = min(i, GetColumnCount() - 1);
  2503. if (pRect)
  2504. {
  2505. pRect->left = pRect->top = 0;
  2506. pRect->right = right;
  2507. pRect->bottom = bottom;
  2508. }
  2509. return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
  2510. }
  2511. // used by ResetScrollBars() - This gets only fully visible cells
  2512. CCellRange CGridCtrl::GetUnobstructedNonFixedCellRange(BOOL bForceRecalculation /*=FALSE*/)
  2513. {
  2514. CRect rect;
  2515. GetClientRect(rect);
  2516. CCellID idTopLeft = GetTopleftNonFixedCell(bForceRecalculation);
  2517. // calc bottom
  2518. int bottom = GetFixedRowHeight();
  2519. int i;
  2520. for (i = idTopLeft.row; i < GetRowCount(); i++)
  2521. {
  2522. bottom += GetRowHeight(i);
  2523. if (bottom >= rect.bottom)
  2524. break;
  2525. }
  2526. int maxVisibleRow = min(i, GetRowCount() - 1);
  2527. if (maxVisibleRow > 0 && bottom > rect.bottom)
  2528. maxVisibleRow--;
  2529. // calc right
  2530. int right = GetFixedColumnWidth();
  2531. for (i = idTopLeft.col; i < GetColumnCount(); i++)
  2532. {
  2533. right += GetColumnWidth(i);
  2534. if (right >= rect.right)
  2535. break;
  2536. }
  2537. int maxVisibleCol = min(i, GetColumnCount() - 1);
  2538. if (maxVisibleCol > 0 && right > rect.right)
  2539. maxVisibleCol--;
  2540. return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
  2541. }
  2542. // Returns the minimum bounding range of the current selection
  2543. // If no selection, then the returned CCellRange will be invalid
  2544. CCellRange CGridCtrl::GetSelectedCellRange() const
  2545. {
  2546. CCellRange Selection(GetRowCount(), GetColumnCount(), -1, -1);
  2547. for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
  2548. {
  2549. DWORD key;
  2550. CCellID cell;
  2551. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  2552. Selection.SetMinRow(min(Selection.GetMinRow(), cell.row));
  2553. Selection.SetMinCol(min(Selection.GetMinCol(), cell.col));
  2554. Selection.SetMaxRow(max(Selection.GetMaxRow(), cell.row));
  2555. Selection.SetMaxCol(max(Selection.GetMaxCol(), cell.col));
  2556. }
  2557. return Selection;
  2558. }
  2559. // Returns ALL the cells in the grid
  2560. CCellRange CGridCtrl::GetCellRange() const
  2561. {
  2562. return CCellRange(0, 0, GetRowCount() - 1, GetColumnCount() - 1);
  2563. }
  2564. // Resets the selected cell range to the empty set.
  2565. void CGridCtrl::ResetSelectedRange()
  2566. {
  2567. m_PrevSelectedCellMap.RemoveAll();
  2568. SetSelectedRange(-1, -1, -1, -1);
  2569. SetFocusCell(-1, -1);
  2570. }
  2571. // Get/Set scroll position using 32 bit functions
  2572. int CGridCtrl::GetScrollPos32(int nBar, BOOL bGetTrackPos /* = FALSE */)
  2573. {
  2574. SCROLLINFO si;
  2575. si.cbSize = sizeof(SCROLLINFO);
  2576. if (bGetTrackPos)
  2577. {
  2578. if (GetScrollInfo(nBar, &si, SIF_TRACKPOS))
  2579. return si.nTrackPos;
  2580. }
  2581. else
  2582. {
  2583. if (GetScrollInfo(nBar, &si, SIF_POS))
  2584. return si.nPos;
  2585. }
  2586. return 0;
  2587. }
  2588. BOOL CGridCtrl::SetScrollPos32(int nBar, int nPos, BOOL bRedraw /* = TRUE */)
  2589. {
  2590. m_idTopLeftCell.row = -1;
  2591. SCROLLINFO si;
  2592. si.cbSize = sizeof(SCROLLINFO);
  2593. si.fMask = SIF_POS;
  2594. si.nPos = nPos;
  2595. return SetScrollInfo(nBar, &si, bRedraw);
  2596. }
  2597. void CGridCtrl::EnableScrollBars(int nBar, BOOL bEnable /*=TRUE*/)
  2598. {
  2599. if (bEnable)
  2600. {
  2601. if (!IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
  2602. {
  2603. m_nBarState |= GVL_HORZ;
  2604. CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
  2605. }
  2606. if (!IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
  2607. {
  2608. m_nBarState |= GVL_VERT;
  2609. CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
  2610. }
  2611. }
  2612. else
  2613. {
  2614. if (IsVisibleHScroll() && (nBar == SB_HORZ || nBar == SB_BOTH))
  2615. {
  2616. m_nBarState &= ~GVL_HORZ;
  2617. CWnd::EnableScrollBarCtrl(SB_HORZ, bEnable);
  2618. }
  2619. if (IsVisibleVScroll() && (nBar == SB_VERT || nBar == SB_BOTH))
  2620. {
  2621. m_nBarState &= ~GVL_VERT;
  2622. CWnd::EnableScrollBarCtrl(SB_VERT, bEnable);
  2623. }
  2624. }
  2625. }
  2626. // If resizing or cell counts/sizes change, call this - it'll fix up the scroll bars
  2627. void CGridCtrl::ResetScrollBars()
  2628. {
  2629. // Force a refresh.
  2630. m_idTopLeftCell.row = -1;
  2631. if (!m_bAllowDraw || !::IsWindow(GetSafeHwnd()))
  2632. return;
  2633. CRect rect;
  2634. // This would have caused OnSize event - Brian
  2635. //EnableScrollBars(SB_BOTH, FALSE);
  2636. GetClientRect(rect);
  2637. if (rect.left == rect.right || rect.top == rect.bottom)
  2638. return;
  2639. if (IsVisibleVScroll())
  2640. rect.right += GetSystemMetrics(SM_CXVSCROLL) + GetSystemMetrics(SM_CXBORDER);
  2641. if (IsVisibleHScroll())
  2642. rect.bottom += GetSystemMetrics(SM_CYHSCROLL) + GetSystemMetrics(SM_CYBORDER);
  2643. rect.left += GetFixedColumnWidth();
  2644. rect.top += GetFixedRowHeight();
  2645. if (rect.left >= rect.right || rect.top >= rect.bottom)
  2646. {
  2647. EnableScrollBarCtrl(SB_BOTH, FALSE);
  2648. return;
  2649. }
  2650. CRect VisibleRect(GetFixedColumnWidth(), GetFixedRowHeight(),
  2651. rect.right, rect.bottom);
  2652. CRect VirtualRect(GetFixedColumnWidth(), GetFixedRowHeight(),
  2653. GetVirtualWidth(), GetVirtualHeight());
  2654. // Removed to fix single row scrollbar problem (Pontus Goffe)
  2655. // CCellRange visibleCells = GetUnobstructedNonFixedCellRange();
  2656. // if (!IsValid(visibleCells)) return;
  2657. //TRACE(_T("Visible: %d x %d, Virtual %d x %d. H %d, V %d\n"),
  2658. // VisibleRect.Width(), VisibleRect.Height(),
  2659. // VirtualRect.Width(), VirtualRect.Height(),
  2660. // IsVisibleHScroll(), IsVisibleVScroll());
  2661. // If vertical scroll bar, horizontal space is reduced
  2662. if (VisibleRect.Height() < VirtualRect.Height())
  2663. VisibleRect.right -= ::GetSystemMetrics(SM_CXVSCROLL);
  2664. // If horz scroll bar, vert space is reduced
  2665. if (VisibleRect.Width() < VirtualRect.Width())
  2666. VisibleRect.bottom -= ::GetSystemMetrics(SM_CYHSCROLL);
  2667. // Recheck vertical scroll bar
  2668. //if (VisibleRect.Height() < VirtualRect.Height())
  2669. // VisibleRect.right -= ::GetSystemMetrics(SM_CXVSCROLL);
  2670. if (VisibleRect.Height() < VirtualRect.Height())
  2671. {
  2672. EnableScrollBars(SB_VERT, TRUE);
  2673. m_nVScrollMax = VirtualRect.Height() - 1;
  2674. }
  2675. else
  2676. {
  2677. EnableScrollBars(SB_VERT, FALSE);
  2678. m_nVScrollMax = 0;
  2679. }
  2680. if (VisibleRect.Width() < VirtualRect.Width())
  2681. {
  2682. EnableScrollBars(SB_HORZ, TRUE);
  2683. m_nHScrollMax = VirtualRect.Width() - 1;
  2684. }
  2685. else
  2686. {
  2687. EnableScrollBars(SB_HORZ, FALSE);
  2688. m_nHScrollMax = 0;
  2689. }
  2690. ASSERT(m_nVScrollMax < INT_MAX && m_nHScrollMax < INT_MAX); // This should be fine
  2691. /* Old code - CJM
  2692. SCROLLINFO si;
  2693. si.cbSize = sizeof(SCROLLINFO);
  2694. si.fMask = SIF_PAGE;
  2695. si.nPage = (m_nHScrollMax>0)? VisibleRect.Width() : 0;
  2696. SetScrollInfo(SB_HORZ, &si, FALSE);
  2697. si.nPage = (m_nVScrollMax>0)? VisibleRect.Height() : 0;
  2698. SetScrollInfo(SB_VERT, &si, FALSE);
  2699. SetScrollRange(SB_VERT, 0, m_nVScrollMax, TRUE);
  2700. SetScrollRange(SB_HORZ, 0, m_nHScrollMax, TRUE);
  2701. */
  2702. // New code - Paul Runstedler
  2703. SCROLLINFO si;
  2704. si.cbSize = sizeof(SCROLLINFO);
  2705. si.fMask = SIF_PAGE | SIF_RANGE;
  2706. si.nPage = (m_nHScrollMax > 0) ? VisibleRect.Width() : 0;
  2707. si.nMin = 0;
  2708. si.nMax = m_nHScrollMax;
  2709. SetScrollInfo(SB_HORZ, &si, TRUE);
  2710. si.fMask |= SIF_DISABLENOSCROLL;
  2711. si.nPage = (m_nVScrollMax > 0) ? VisibleRect.Height() : 0;
  2712. si.nMin = 0;
  2713. si.nMax = m_nVScrollMax;
  2714. SetScrollInfo(SB_VERT, &si, TRUE);
  2715. }
  2716. ////////////////////////////////////////////////////////////////////////////////////
  2717. // Row/Column position functions
  2718. // returns the top left point of the cell. Returns FALSE if cell not visible.
  2719. // consider cell's merge
  2720. BOOL CGridCtrl::GetCellOrigin(int nRow, int nCol, LPPOINT p)
  2721. {
  2722. int i;
  2723. if (!IsValid(nRow, nCol))
  2724. return FALSE;
  2725. CCellID idTopLeft;
  2726. if (nCol >= m_nFixedCols || nRow >= m_nFixedRows)
  2727. idTopLeft = GetTopleftNonFixedCell();
  2728. //Merge the selected cells
  2729. //by Huang Wei
  2730. //if ((nRow >= m_nFixedRows && nRow < idTopLeft.row) ||
  2731. // (nCol>= m_nFixedCols && nCol < idTopLeft.col))
  2732. // return FALSE;
  2733. p->x = 0;
  2734. if (nCol < m_nFixedCols) // is a fixed column
  2735. for (i = 0; i < nCol; i++)
  2736. p->x += GetColumnWidth(i);
  2737. else
  2738. { // is a scrollable data column
  2739. for (i = 0; i < m_nFixedCols; i++)
  2740. p->x += GetColumnWidth(i);
  2741. //Merge the selected cells
  2742. //by Huang Wei
  2743. if (nCol > idTopLeft.col)
  2744. {
  2745. for (i = idTopLeft.col; i < nCol; i++)
  2746. p->x += GetColumnWidth(i);
  2747. }
  2748. else
  2749. {
  2750. for (i = nCol; i < idTopLeft.col; i++)
  2751. p->x -= GetColumnWidth(i);
  2752. }
  2753. }
  2754. p->y = 0;
  2755. if (nRow < m_nFixedRows) // is a fixed row
  2756. for (i = 0; i < nRow; i++)
  2757. p->y += GetRowHeight(i);
  2758. else
  2759. { // is a scrollable data row
  2760. for (i = 0; i < m_nFixedRows; i++)
  2761. p->y += GetRowHeight(i);
  2762. //Merge the selected cells
  2763. //by Huang Wei
  2764. if (nRow > idTopLeft.row)
  2765. {
  2766. for (i = idTopLeft.row; i < nRow; i++)
  2767. p->y += GetRowHeight(i);
  2768. }
  2769. else
  2770. {
  2771. for (i = nRow; i < idTopLeft.row; i++)
  2772. p->y -= GetRowHeight(i);
  2773. }
  2774. }
  2775. return TRUE;
  2776. }
  2777. // returns the top left point of the cell. Returns FALSE if cell not visible.
  2778. // don't consider cell's merge
  2779. BOOL CGridCtrl::GetCellOriginNoMerge(int nRow, int nCol, LPPOINT p)
  2780. {
  2781. int i;
  2782. if (!IsValid(nRow, nCol))
  2783. return FALSE;
  2784. CCellID idTopLeft;
  2785. if (nCol >= m_nFixedCols || nRow >= m_nFixedRows)
  2786. idTopLeft = GetTopleftNonFixedCell();
  2787. if ((nRow >= m_nFixedRows && nRow < idTopLeft.row) ||
  2788. (nCol >= m_nFixedCols && nCol < idTopLeft.col))
  2789. return FALSE;
  2790. p->x = 0;
  2791. if (nCol < m_nFixedCols) // is a fixed column
  2792. for (i = 0; i < nCol; i++)
  2793. p->x += GetColumnWidth(i);
  2794. else
  2795. { // is a scrollable data column
  2796. for (i = 0; i < m_nFixedCols; i++)
  2797. p->x += GetColumnWidth(i);
  2798. for (i = idTopLeft.col; i < nCol; i++)
  2799. p->x += GetColumnWidth(i);
  2800. }
  2801. p->y = 0;
  2802. if (nRow < m_nFixedRows) // is a fixed row
  2803. for (i = 0; i < nRow; i++)
  2804. p->y += GetRowHeight(i);
  2805. else
  2806. { // is a scrollable data row
  2807. for (i = 0; i < m_nFixedRows; i++)
  2808. p->y += GetRowHeight(i);
  2809. for (i = idTopLeft.row; i < nRow; i++)
  2810. p->y += GetRowHeight(i);
  2811. }
  2812. return TRUE;
  2813. }
  2814. BOOL CGridCtrl::GetCellOrigin(const CCellID& cell, LPPOINT p)
  2815. {
  2816. return GetCellOrigin(cell.row, cell.col, p);
  2817. }
  2818. BOOL CGridCtrl::GetCellOriginNoMerge(const CCellID& cell, LPPOINT p)
  2819. {
  2820. return GetCellOriginNoMerge(cell.row, cell.col, p);
  2821. }
  2822. // Returns the bounding box of the cell
  2823. BOOL CGridCtrl::GetCellRect(const CCellID& cell, LPRECT pRect)
  2824. {
  2825. return GetCellRect(cell.row, cell.col, pRect);
  2826. }
  2827. BOOL CGridCtrl::GetCellRect(int nRow, int nCol, LPRECT pRect)
  2828. {
  2829. CPoint CellOrigin;
  2830. if (!GetCellOrigin(nRow, nCol, &CellOrigin))
  2831. return FALSE;
  2832. //Merge the selected cells
  2833. //by Huang Wei
  2834. CGridCellBase *pCell = (CGridCellBase*)GetCell(nRow, nCol);
  2835. if (!pCell->IsMerged())
  2836. {
  2837. pRect->left = CellOrigin.x;
  2838. pRect->top = CellOrigin.y;
  2839. pRect->right = CellOrigin.x + GetColumnWidth(nCol) - 1;
  2840. pRect->bottom = CellOrigin.y + GetRowHeight(nRow) - 1;
  2841. }
  2842. else
  2843. {
  2844. GetCellRangeRect(pCell->m_MergeRange, pRect);
  2845. }
  2846. //TRACE("Row %d, col %d: L %d, T %d, W %d, H %d: %d,%d - %d,%d\n",
  2847. // nRow,nCol, CellOrigin.x, CellOrigin.y, GetColumnWidth(nCol), GetRowHeight(nRow),
  2848. // pRect->left, pRect->top, pRect->right, pRect->bottom);
  2849. return TRUE;
  2850. }
  2851. BOOL CGridCtrl::GetTextRect(const CCellID& cell, LPRECT pRect)
  2852. {
  2853. return GetTextRect(cell.row, cell.col, pRect);
  2854. }
  2855. BOOL CGridCtrl::GetTextRect(int nRow, int nCol, LPRECT pRect)
  2856. {
  2857. CGridCellBase* pCell = GetCell(nRow, nCol);
  2858. if (pCell == NULL)
  2859. return FALSE;
  2860. if (!GetCellRect(nRow, nCol, pRect))
  2861. return FALSE;
  2862. return pCell->GetTextRect(pRect);
  2863. }
  2864. // Returns the bounding box of a range of cells
  2865. BOOL CGridCtrl::GetCellRangeRect(const CCellRange& cellRange, LPRECT lpRect)
  2866. {
  2867. CPoint MinOrigin, MaxOrigin;
  2868. if (!GetCellOrigin(cellRange.GetMinRow(), cellRange.GetMinCol(), &MinOrigin))
  2869. return FALSE;
  2870. if (!GetCellOrigin(cellRange.GetMaxRow(), cellRange.GetMaxCol(), &MaxOrigin))
  2871. return FALSE;
  2872. lpRect->left = MinOrigin.x;
  2873. lpRect->top = MinOrigin.y;
  2874. lpRect->right = MaxOrigin.x + GetColumnWidth(cellRange.GetMaxCol()) - 1;
  2875. lpRect->bottom = MaxOrigin.y + GetRowHeight(cellRange.GetMaxRow()) - 1;
  2876. return TRUE;
  2877. }
  2878. ////////////////////////////////////////////////////////////////////////////////////
  2879. // Grid attribute functions
  2880. LRESULT CGridCtrl::OnSetFont(WPARAM hFont, LPARAM /*lParam */)
  2881. {
  2882. LRESULT result = Default();
  2883. // Get the logical font
  2884. LOGFONT lf;
  2885. if (!GetObject((HFONT)hFont, sizeof(LOGFONT), &lf))
  2886. return result;
  2887. m_cellDefault.SetFont(&lf);
  2888. m_cellFixedColDef.SetFont(&lf);
  2889. m_cellFixedRowDef.SetFont(&lf);
  2890. m_cellFixedRowColDef.SetFont(&lf);
  2891. Refresh();
  2892. return result;
  2893. }
  2894. LRESULT CGridCtrl::OnGetFont(WPARAM /*wParam*/, LPARAM /*lParam*/)
  2895. {
  2896. //LOGFONT lf;
  2897. //m_cellDefault.GetFontObject()->GetLogFont(&lf);
  2898. return (LRESULT)m_cellDefault.GetFontObject()->GetSafeHandle();
  2899. }
  2900. #ifndef _WIN32_WCE_NO_CURSOR
  2901. BOOL CGridCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
  2902. {
  2903. if (nHitTest == HTCLIENT)
  2904. {
  2905. switch (m_MouseMode)
  2906. {
  2907. case MOUSE_OVER_COL_DIVIDE:
  2908. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  2909. break;
  2910. case MOUSE_OVER_ROW_DIVIDE:
  2911. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
  2912. break;
  2913. #ifndef GRIDCONTROL_NO_DRAGDROP
  2914. case MOUSE_DRAGGING:
  2915. break;
  2916. #endif
  2917. default:
  2918. if (!GetVirtualMode())
  2919. {
  2920. CPoint pt(GetMessagePos());
  2921. ScreenToClient(&pt);
  2922. CCellID cell = GetCellFromPt(pt);
  2923. if (IsValid(cell))
  2924. {
  2925. CGridCellBase* pCell = GetCell(cell.row, cell.col);
  2926. if (pCell)
  2927. return pCell->OnSetCursor();
  2928. }
  2929. }
  2930. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  2931. }
  2932. return TRUE;
  2933. }
  2934. return CWnd::OnSetCursor(pWnd, nHitTest, message);
  2935. }
  2936. #endif
  2937. ////////////////////////////////////////////////////////////////////////////////////
  2938. // Row/Column count functions
  2939. BOOL CGridCtrl::SetFixedRowCount(int nFixedRows)
  2940. {
  2941. if (m_nFixedRows == nFixedRows)
  2942. return TRUE;
  2943. ASSERT(nFixedRows >= 0);
  2944. ResetSelectedRange();
  2945. // Force recalculation
  2946. m_idTopLeftCell.col = -1;
  2947. if (nFixedRows > GetRowCount())
  2948. if (!SetRowCount(nFixedRows))
  2949. return FALSE;
  2950. if (m_idCurrentCell.row < nFixedRows)
  2951. SetFocusCell(-1, -1);
  2952. if (!GetVirtualMode())
  2953. {
  2954. if (nFixedRows > m_nFixedRows)
  2955. {
  2956. for (int i = m_nFixedRows; i < nFixedRows; i++)
  2957. for (int j = 0; j < GetColumnCount(); j++)
  2958. {
  2959. SetItemState(i, j, GetItemState(i, j) | GVIS_FIXED | GVIS_FIXEDROW);
  2960. SetItemBkColour(i, j, CLR_DEFAULT);
  2961. SetItemFgColour(i, j, CLR_DEFAULT);
  2962. }
  2963. }
  2964. else
  2965. {
  2966. for (int i = nFixedRows; i < m_nFixedRows; i++)
  2967. {
  2968. int j;
  2969. for (j = 0; j < GetFixedColumnCount(); j++)
  2970. SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDROW);
  2971. for (j = GetFixedColumnCount(); j < GetColumnCount(); j++)
  2972. {
  2973. SetItemState(i, j, GetItemState(i, j) & ~(GVIS_FIXED | GVIS_FIXEDROW));
  2974. SetItemBkColour(i, j, CLR_DEFAULT);
  2975. SetItemFgColour(i, j, CLR_DEFAULT);
  2976. }
  2977. }
  2978. }
  2979. }
  2980. m_nFixedRows = nFixedRows;
  2981. Refresh();
  2982. return TRUE;
  2983. }
  2984. BOOL CGridCtrl::SetFixedColumnCount(int nFixedCols)
  2985. {
  2986. if (m_nFixedCols == nFixedCols)
  2987. return TRUE;
  2988. ASSERT(nFixedCols >= 0);
  2989. if (nFixedCols > GetColumnCount())
  2990. if (!SetColumnCount(nFixedCols))
  2991. return FALSE;
  2992. if (m_idCurrentCell.col < nFixedCols)
  2993. SetFocusCell(-1, -1);
  2994. ResetSelectedRange();
  2995. // Force recalculation
  2996. m_idTopLeftCell.col = -1;
  2997. if (!GetVirtualMode())
  2998. {
  2999. if (nFixedCols > m_nFixedCols)
  3000. {
  3001. for (int i = 0; i < GetRowCount(); i++)
  3002. for (int j = m_nFixedCols; j < nFixedCols; j++)
  3003. {
  3004. SetItemState(i, j, GetItemState(i, j) | GVIS_FIXED | GVIS_FIXEDCOL);
  3005. SetItemBkColour(i, j, CLR_DEFAULT);
  3006. SetItemFgColour(i, j, CLR_DEFAULT);
  3007. }
  3008. }
  3009. else
  3010. {
  3011. { // Scope limit i,j
  3012. for (int i = 0; i < GetFixedRowCount(); i++)
  3013. for (int j = nFixedCols; j < m_nFixedCols; j++)
  3014. SetItemState(i, j, GetItemState(i, j) & ~GVIS_FIXEDCOL);
  3015. }
  3016. {// Scope limit i,j
  3017. for (int i = GetFixedRowCount(); i < GetRowCount(); i++)
  3018. for (int j = nFixedCols; j < m_nFixedCols; j++)
  3019. {
  3020. SetItemState(i, j, GetItemState(i, j) & ~(GVIS_FIXED | GVIS_FIXEDCOL));
  3021. SetItemBkColour(i, j, CLR_DEFAULT);
  3022. SetItemFgColour(i, j, CLR_DEFAULT);
  3023. }
  3024. }
  3025. }
  3026. }
  3027. m_nFixedCols = nFixedCols;
  3028. Refresh();
  3029. return TRUE;
  3030. }
  3031. BOOL CGridCtrl::SetRowCount(int nRows)
  3032. {
  3033. BOOL bResult = TRUE;
  3034. ASSERT(nRows >= 0);
  3035. if (nRows == GetRowCount())
  3036. return bResult;
  3037. // Force recalculation
  3038. m_idTopLeftCell.col = -1;
  3039. if (nRows < m_nFixedRows)
  3040. m_nFixedRows = nRows;
  3041. if (m_idCurrentCell.row >= nRows)
  3042. SetFocusCell(-1, -1);
  3043. int addedRows = nRows - GetRowCount();
  3044. // If we are about to lose rows, then we need to delete the GridCell objects
  3045. // in each column within each row
  3046. if (addedRows < 0)
  3047. {
  3048. if (!GetVirtualMode())
  3049. {
  3050. for (int row = nRows; row < m_nRows; row++)
  3051. {
  3052. // Delete cells
  3053. for (int col = 0; col < m_nCols; col++)
  3054. DestroyCell(row, col);
  3055. // Delete rows
  3056. GRID_ROW* pRow = m_RowData[row];
  3057. if (pRow)
  3058. delete pRow;
  3059. }
  3060. }
  3061. m_nRows = nRows;
  3062. }
  3063. TRY
  3064. {
  3065. m_arRowHeights.SetSize(nRows);
  3066. if (GetVirtualMode())
  3067. {
  3068. m_nRows = nRows;
  3069. if (addedRows > 0)
  3070. {
  3071. int startRow = nRows - addedRows;
  3072. for (int row = startRow; row < nRows; row++)
  3073. m_arRowHeights[row] = m_cellDefault.GetHeight();
  3074. }
  3075. }
  3076. else
  3077. {
  3078. // Change the number of rows.
  3079. m_RowData.SetSize(nRows);
  3080. // If we have just added rows, we need to construct new elements for each cell
  3081. // and set the default row height
  3082. if (addedRows > 0)
  3083. {
  3084. // initialize row heights and data
  3085. int startRow = nRows - addedRows;
  3086. for (int row = startRow; row < nRows; row++)
  3087. {
  3088. m_arRowHeights[row] = m_cellDefault.GetHeight();
  3089. m_RowData[row] = new GRID_ROW;
  3090. m_RowData[row]->SetSize(m_nCols);
  3091. for (int col = 0; col < m_nCols; col++)
  3092. {
  3093. GRID_ROW* pRow = m_RowData[row];
  3094. if (pRow && !GetVirtualMode())
  3095. pRow->SetAt(col, CreateCell(row, col));
  3096. }
  3097. m_nRows++;
  3098. }
  3099. }
  3100. }
  3101. }
  3102. CATCH(CMemoryException, e)
  3103. {
  3104. e->ReportError();
  3105. bResult = FALSE;
  3106. }
  3107. END_CATCH
  3108. SetModified();
  3109. ResetScrollBars();
  3110. Refresh();
  3111. return bResult;
  3112. }
  3113. BOOL CGridCtrl::SetColumnCount(int nCols)
  3114. {
  3115. BOOL bResult = TRUE;
  3116. ASSERT(nCols >= 0);
  3117. if (nCols == GetColumnCount())
  3118. return bResult;
  3119. // Force recalculation
  3120. m_idTopLeftCell.col = -1;
  3121. if (nCols < m_nFixedCols)
  3122. m_nFixedCols = nCols;
  3123. if (m_idCurrentCell.col >= nCols)
  3124. SetFocusCell(-1, -1);
  3125. int addedCols = nCols - GetColumnCount();
  3126. // If we are about to lose columns, then we need to delete the GridCell objects
  3127. // within each column
  3128. if (addedCols < 0 && !GetVirtualMode())
  3129. {
  3130. for (int row = 0; row < m_nRows; row++)
  3131. for (int col = nCols; col < GetColumnCount(); col++)
  3132. DestroyCell(row, col);
  3133. }
  3134. TRY
  3135. {
  3136. // Change the number of columns.
  3137. m_arColWidths.SetSize(nCols);
  3138. // Change the number of columns in each row.
  3139. if (!GetVirtualMode())
  3140. for (int i = 0; i < m_nRows; i++)
  3141. if (m_RowData[i])
  3142. m_RowData[i]->SetSize(nCols);
  3143. // If we have just added columns, we need to construct new elements for each cell
  3144. // and set the default column width
  3145. if (addedCols > 0)
  3146. {
  3147. // initialized column widths
  3148. int startCol = nCols - addedCols;
  3149. for (int col = startCol; col < nCols; col++)
  3150. m_arColWidths[col] = m_cellFixedColDef.GetWidth();
  3151. // initialise column data
  3152. if (!GetVirtualMode())
  3153. {
  3154. for (int row = 0; row < m_nRows; row++)
  3155. for (int col = startCol; col < nCols; col++)
  3156. {
  3157. GRID_ROW* pRow = m_RowData[row];
  3158. if (pRow)
  3159. pRow->SetAt(col, CreateCell(row, col));
  3160. }
  3161. }
  3162. }
  3163. // else // check for selected cell ranges
  3164. // ResetSelectedRange();
  3165. }
  3166. CATCH(CMemoryException, e)
  3167. {
  3168. e->ReportError();
  3169. bResult = FALSE;
  3170. }
  3171. END_CATCH
  3172. m_nCols = nCols;
  3173. SetModified();
  3174. ResetScrollBars();
  3175. Refresh();
  3176. return bResult;
  3177. }
  3178. // Insert a column at a given position, or add to end of columns (if nColumn = -1)
  3179. int CGridCtrl::InsertColumn(LPCTSTR strHeading,
  3180. UINT nFormat /* = DT_CENTER|DT_VCENTER|DT_SINGLELINE */,
  3181. int nColumn /* = -1 */)
  3182. {
  3183. if (nColumn >= 0 && nColumn < m_nFixedCols)
  3184. {
  3185. // TODO: Fix it so column insertion works for in the fixed column area
  3186. ASSERT(FALSE);
  3187. return -1;
  3188. }
  3189. // If the insertion is for a specific column, check it's within range.
  3190. if (nColumn >= 0 && nColumn > GetColumnCount())
  3191. return -1;
  3192. // Force recalculation
  3193. m_idTopLeftCell.col = -1;
  3194. ResetSelectedRange();
  3195. // Gotta be able to at least _see_ some of the column.
  3196. if (m_nRows < 1)
  3197. SetRowCount(1);
  3198. // Allow the user to insert after the last of the columns, but process it as a
  3199. // "-1" column, meaning it gets flaged as being the last column, and not a regular
  3200. // "insert" routine.
  3201. if (nColumn == GetColumnCount())
  3202. nColumn = -1;
  3203. TRY
  3204. {
  3205. if (nColumn < 0)
  3206. {
  3207. nColumn = m_nCols;
  3208. m_arColWidths.Add(0);
  3209. if (!GetVirtualMode())
  3210. {
  3211. for (int row = 0; row < m_nRows; row++)
  3212. {
  3213. GRID_ROW* pRow = m_RowData[row];
  3214. if (!pRow)
  3215. return -1;
  3216. pRow->Add(CreateCell(row, nColumn));
  3217. }
  3218. }
  3219. }
  3220. else
  3221. {
  3222. m_arColWidths.InsertAt((INT_PTR)nColumn, (UINT)0);
  3223. if (!GetVirtualMode())
  3224. {
  3225. for (int row = 0; row < m_nRows; row++)
  3226. {
  3227. GRID_ROW* pRow = m_RowData[row];
  3228. if (!pRow)
  3229. return -1;
  3230. pRow->InsertAt(nColumn, CreateCell(row, nColumn));
  3231. }
  3232. }
  3233. }
  3234. }
  3235. CATCH(CMemoryException, e)
  3236. {
  3237. e->ReportError();
  3238. return FALSE;
  3239. }
  3240. END_CATCH
  3241. m_nCols++;
  3242. // Initialise column data
  3243. SetItemText(0, nColumn, strHeading);
  3244. for (int row = 0; row < m_nRows; row++)
  3245. SetItemFormat(row, nColumn, nFormat);
  3246. // initialized column width
  3247. m_arColWidths[nColumn] = GetTextExtent(0, nColumn, strHeading).cx;
  3248. if (m_idCurrentCell.col != -1 && nColumn < m_idCurrentCell.col)
  3249. m_idCurrentCell.col++;
  3250. ResetScrollBars();
  3251. SetModified();
  3252. return nColumn;
  3253. }
  3254. // Insert a row at a given position, or add to end of rows (if nRow = -1)
  3255. int CGridCtrl::InsertRow(LPCTSTR strHeading, int nRow /* = -1 */)
  3256. {
  3257. if (nRow >= 0 && nRow < m_nFixedRows)
  3258. {
  3259. // TODO: Fix it so column insertion works for in the fixed row area
  3260. ASSERT(FALSE);
  3261. return -1;
  3262. }
  3263. // If the insertion is for a specific row, check it's within range.
  3264. if (nRow >= 0 && nRow >= GetRowCount())
  3265. return -1;
  3266. // Force recalculation
  3267. m_idTopLeftCell.col = -1;
  3268. ResetSelectedRange();
  3269. // Gotta be able to at least _see_ some of the row.
  3270. if (m_nCols < 1)
  3271. SetColumnCount(1);
  3272. TRY
  3273. {
  3274. // Adding a row to the bottom
  3275. if (nRow < 0)
  3276. {
  3277. nRow = m_nRows;
  3278. m_arRowHeights.Add(0);
  3279. if (!GetVirtualMode())
  3280. m_RowData.Add(new GRID_ROW);
  3281. }
  3282. else
  3283. {
  3284. m_arRowHeights.InsertAt((INT_PTR)nRow, (UINT)0);
  3285. if (!GetVirtualMode())
  3286. m_RowData.InsertAt(nRow, new GRID_ROW);
  3287. }
  3288. if (!GetVirtualMode())
  3289. m_RowData[nRow]->SetSize(m_nCols);
  3290. }
  3291. CATCH(CMemoryException, e)
  3292. {
  3293. e->ReportError();
  3294. return FALSE;
  3295. }
  3296. END_CATCH
  3297. m_nRows++;
  3298. // Initialise cell data
  3299. if (!GetVirtualMode())
  3300. {
  3301. for (int col = 0; col < m_nCols; col++)
  3302. {
  3303. GRID_ROW* pRow = m_RowData[nRow];
  3304. if (!pRow)
  3305. return -1;
  3306. pRow->SetAt(col, CreateCell(nRow, col));
  3307. }
  3308. }
  3309. // Set row title
  3310. SetItemText(nRow, 0, strHeading);
  3311. // initialized row height
  3312. if (strHeading && strHeading[0])
  3313. m_arRowHeights[nRow] = GetTextExtent(nRow, 0, strHeading).cy;
  3314. else
  3315. m_arRowHeights[nRow] = m_cellFixedRowDef.GetHeight();
  3316. if (m_idCurrentCell.row != -1 && nRow < m_idCurrentCell.row)
  3317. m_idCurrentCell.row++;
  3318. ResetScrollBars();
  3319. SetModified();
  3320. return nRow;
  3321. }
  3322. ///////////////////////////////////////////////////////////////////////////////
  3323. // Cell creation stuff
  3324. BOOL CGridCtrl::SetCellType(int nRow, int nCol, CRuntimeClass* pRuntimeClass)
  3325. {
  3326. if (GetVirtualMode())
  3327. return FALSE;
  3328. ASSERT(IsValid(nRow, nCol));
  3329. if (!IsValid(nRow, nCol))
  3330. return FALSE;
  3331. if (!pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
  3332. {
  3333. ASSERT(FALSE);
  3334. return FALSE;
  3335. }
  3336. CGridCellBase* pNewCell = (CGridCellBase*)pRuntimeClass->CreateObject();
  3337. CGridCellBase* pCurrCell = GetCell(nRow, nCol);
  3338. if (pCurrCell)
  3339. *pNewCell = *pCurrCell;
  3340. SetCell(nRow, nCol, pNewCell);
  3341. delete pCurrCell;
  3342. return TRUE;
  3343. }
  3344. BOOL CGridCtrl::SetDefaultCellType(CRuntimeClass* pRuntimeClass)
  3345. {
  3346. ASSERT(pRuntimeClass != NULL);
  3347. if (!pRuntimeClass->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
  3348. {
  3349. ASSERT(FALSE);
  3350. return FALSE;
  3351. }
  3352. m_pRtcDefault = pRuntimeClass;
  3353. return TRUE;
  3354. }
  3355. // Creates a new grid cell and performs any necessary initialisation
  3356. /*virtual*/ CGridCellBase* CGridCtrl::CreateCell(int nRow, int nCol)
  3357. {
  3358. ASSERT(!GetVirtualMode());
  3359. if (!m_pRtcDefault || !m_pRtcDefault->IsDerivedFrom(RUNTIME_CLASS(CGridCellBase)))
  3360. {
  3361. ASSERT(FALSE);
  3362. return NULL;
  3363. }
  3364. CGridCellBase* pCell = (CGridCellBase*)m_pRtcDefault->CreateObject();
  3365. if (!pCell)
  3366. return NULL;
  3367. pCell->SetGrid(this);
  3368. pCell->SetCoords(nRow, nCol);
  3369. if (nCol < m_nFixedCols)
  3370. pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDCOL);
  3371. if (nRow < m_nFixedRows)
  3372. pCell->SetState(pCell->GetState() | GVIS_FIXED | GVIS_FIXEDROW);
  3373. pCell->SetFormat(pCell->GetDefaultCell()->GetFormat());
  3374. return pCell;
  3375. }
  3376. // Performs any cell cleanup necessary to maintain grid integrity
  3377. /*virtual*/ void CGridCtrl::DestroyCell(int nRow, int nCol)
  3378. {
  3379. // Should NEVER get here in virtual mode.
  3380. ASSERT(!GetVirtualMode());
  3381. // Set the cells state to 0. If the cell is selected, this
  3382. // will remove the cell from the selected list.
  3383. SetItemState(nRow, nCol, 0);
  3384. delete GetCell(nRow, nCol);
  3385. }
  3386. BOOL CGridCtrl::DeleteColumn(int nColumn)
  3387. {
  3388. if (nColumn < 0 || nColumn >= GetColumnCount())
  3389. return FALSE;
  3390. ResetSelectedRange();
  3391. if (!GetVirtualMode())
  3392. {
  3393. for (int row = 0; row < GetRowCount(); row++)
  3394. {
  3395. GRID_ROW* pRow = m_RowData[row];
  3396. if (!pRow)
  3397. return FALSE;
  3398. DestroyCell(row, nColumn);
  3399. pRow->RemoveAt(nColumn);
  3400. }
  3401. }
  3402. m_arColWidths.RemoveAt(nColumn);
  3403. m_nCols--;
  3404. if (nColumn < m_nFixedCols)
  3405. m_nFixedCols--;
  3406. if (nColumn == m_idCurrentCell.col)
  3407. m_idCurrentCell.row = m_idCurrentCell.col = -1;
  3408. else if (nColumn < m_idCurrentCell.col)
  3409. m_idCurrentCell.col--;
  3410. ResetScrollBars();
  3411. SetModified();
  3412. return TRUE;
  3413. }
  3414. BOOL CGridCtrl::DeleteRow(int nRow)
  3415. {
  3416. if (nRow < 0 || nRow >= GetRowCount())
  3417. return FALSE;
  3418. ResetSelectedRange();
  3419. if (!GetVirtualMode())
  3420. {
  3421. GRID_ROW* pRow = m_RowData[nRow];
  3422. if (!pRow)
  3423. return FALSE;
  3424. for (int col = 0; col < GetColumnCount(); col++)
  3425. DestroyCell(nRow, col);
  3426. delete pRow;
  3427. m_RowData.RemoveAt(nRow);
  3428. }
  3429. m_arRowHeights.RemoveAt(nRow);
  3430. m_nRows--;
  3431. if (nRow < m_nFixedRows)
  3432. m_nFixedRows--;
  3433. if (nRow == m_idCurrentCell.row)
  3434. m_idCurrentCell.row = m_idCurrentCell.col = -1;
  3435. else if (nRow < m_idCurrentCell.row)
  3436. m_idCurrentCell.row--;
  3437. ResetScrollBars();
  3438. SetModified();
  3439. return TRUE;
  3440. }
  3441. // Handy function that removes all non-fixed rows
  3442. BOOL CGridCtrl::DeleteNonFixedRows()
  3443. {
  3444. ResetSelectedRange();
  3445. int nFixed = GetFixedRowCount();
  3446. int nCount = GetRowCount();
  3447. // Delete all data rows
  3448. for (int nRow = nCount; nRow >= nFixed; nRow--)
  3449. DeleteRow(nRow);
  3450. return TRUE;
  3451. }
  3452. // Removes all rows, columns and data from the grid.
  3453. BOOL CGridCtrl::DeleteAllItems()
  3454. {
  3455. ResetSelectedRange();
  3456. m_arColWidths.RemoveAll();
  3457. m_arRowHeights.RemoveAll();
  3458. // Delete all cells in the grid
  3459. if (!GetVirtualMode())
  3460. {
  3461. for (int row = 0; row < m_nRows; row++)
  3462. {
  3463. for (int col = 0; col < m_nCols; col++)
  3464. DestroyCell(row, col);
  3465. GRID_ROW* pRow = m_RowData[row];
  3466. delete pRow;
  3467. }
  3468. // Remove all rows
  3469. m_RowData.RemoveAll();
  3470. }
  3471. m_idCurrentCell.row = m_idCurrentCell.col = -1;
  3472. m_nRows = m_nFixedRows = m_nCols = m_nFixedCols = 0;
  3473. ResetScrollBars();
  3474. SetModified();
  3475. return TRUE;
  3476. }
  3477. void CGridCtrl::AutoFill()
  3478. {
  3479. if (!::IsWindow(m_hWnd))
  3480. return;
  3481. CRect rect;
  3482. GetClientRect(rect);
  3483. SetColumnCount(rect.Width() / m_cellDefault.GetWidth() + 1);
  3484. SetRowCount(rect.Height() / m_cellDefault.GetHeight() + 1);
  3485. SetFixedRowCount(1);
  3486. SetFixedColumnCount(1);
  3487. ExpandToFit();
  3488. }
  3489. /////////////////////////////////////////////////////////////////////////////
  3490. // CGridCtrl data functions
  3491. // Set CListCtrl::GetNextItem for details
  3492. CCellID CGridCtrl::GetNextItem(CCellID& cell, int nFlags) const
  3493. {
  3494. if ((nFlags & GVNI_ALL) == GVNI_ALL)
  3495. { // GVNI_ALL Search whole Grid beginning from cell
  3496. // First row (cell.row) -- ONLY Columns to the right of cell
  3497. // following rows -- ALL Columns
  3498. int row = cell.row, col = cell.col + 1;
  3499. if (row <= 0)
  3500. row = GetFixedRowCount();
  3501. for (; row < GetRowCount(); row++)
  3502. {
  3503. if (col <= 0)
  3504. col = GetFixedColumnCount();
  3505. for (; col < GetColumnCount(); col++)
  3506. {
  3507. int nState = GetItemState(row, col);
  3508. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3509. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3510. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3511. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3512. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3513. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3514. return CCellID(row, col);
  3515. }
  3516. // go to First Column
  3517. col = GetFixedColumnCount();
  3518. }
  3519. }
  3520. else if ((nFlags & GVNI_BELOW) == GVNI_BELOW &&
  3521. (nFlags & GVNI_TORIGHT) == GVNI_TORIGHT)
  3522. { // GVNI_AREA Search Grid beginning from cell to Lower-Right of Grid
  3523. // Only rows starting with cell.row and below
  3524. // All rows -- ONLY Columns to the right of cell
  3525. int row = cell.row;
  3526. if (row <= 0)
  3527. row = GetFixedRowCount();
  3528. for (; row < GetRowCount(); row++)
  3529. {
  3530. int col = cell.col + 1;
  3531. if (col <= 0)
  3532. col = GetFixedColumnCount();
  3533. for (; col < GetColumnCount(); col++)
  3534. {
  3535. int nState = GetItemState(row, col);
  3536. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3537. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3538. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3539. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3540. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3541. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3542. return CCellID(row, col);
  3543. }
  3544. }
  3545. }
  3546. else if ((nFlags & GVNI_ABOVE) == GVNI_ABOVE)
  3547. {
  3548. for (int row = cell.row - 1; row >= GetFixedRowCount(); row--)
  3549. {
  3550. int nState = GetItemState(row, cell.col);
  3551. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3552. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3553. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3554. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3555. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3556. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3557. return CCellID(row, cell.col);
  3558. }
  3559. }
  3560. else if ((nFlags & GVNI_BELOW) == GVNI_BELOW)
  3561. {
  3562. for (int row = cell.row + 1; row < GetRowCount(); row++)
  3563. {
  3564. int nState = GetItemState(row, cell.col);
  3565. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3566. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3567. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3568. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3569. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3570. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3571. return CCellID(row, cell.col);
  3572. }
  3573. }
  3574. else if ((nFlags & GVNI_TOLEFT) == GVNI_TOLEFT)
  3575. {
  3576. for (int col = cell.col - 1; col >= GetFixedColumnCount(); col--)
  3577. {
  3578. int nState = GetItemState(cell.row, col);
  3579. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3580. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3581. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3582. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3583. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3584. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3585. return CCellID(cell.row, col);
  3586. }
  3587. }
  3588. else if ((nFlags & GVNI_TORIGHT) == GVNI_TORIGHT)
  3589. {
  3590. for (int col = cell.col + 1; col < GetColumnCount(); col++)
  3591. {
  3592. int nState = GetItemState(cell.row, col);
  3593. if ((nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED) ||
  3594. (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED) ||
  3595. (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED) ||
  3596. (nFlags & GVNI_READONLY && nState & GVIS_READONLY) ||
  3597. (nFlags & GVNI_FIXED && nState & GVIS_FIXED) ||
  3598. (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED))
  3599. return CCellID(cell.row, col);
  3600. }
  3601. }
  3602. return CCellID(-1, -1);
  3603. }
  3604. // Sorts on a given column using the cell text
  3605. BOOL CGridCtrl::SortTextItems(int nCol, BOOL bAscending, LPARAM data /* = 0 */)
  3606. {
  3607. SetSortColumn(nCol);
  3608. SetSortAscending(bAscending);
  3609. ResetSelectedRange();
  3610. SetFocusCell(-1, -1);
  3611. return CGridCtrl::SortItems(pfnCellTextCompare, nCol, bAscending, data);
  3612. }
  3613. void CGridCtrl::SetCompareFunction(PFNLVCOMPARE pfnCompare)
  3614. {
  3615. m_pfnCompare = pfnCompare;
  3616. }
  3617. // Sorts on a given column using the cell text and using the specified comparison
  3618. // function
  3619. BOOL CGridCtrl::SortItems(int nCol, BOOL bAscending, LPARAM data /* = 0 */)
  3620. {
  3621. SetSortColumn(nCol);
  3622. SetSortAscending(bAscending);
  3623. ResetSelectedRange();
  3624. SetFocusCell(-1, -1);
  3625. if (m_pfnCompare == NULL)
  3626. return CGridCtrl::SortItems(pfnCellTextCompare, nCol, bAscending, data);
  3627. else
  3628. return CGridCtrl::SortItems(m_pfnCompare, nCol, bAscending, data);
  3629. }
  3630. // Sorts on a given column using the supplied compare function (see CListCtrl::SortItems)
  3631. BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending,
  3632. LPARAM data /* = 0 */)
  3633. {
  3634. SetSortColumn(nCol);
  3635. SetSortAscending(bAscending);
  3636. ResetSelectedRange();
  3637. SetFocusCell(-1, -1);
  3638. return SortItems(pfnCompare, nCol, bAscending, data, GetFixedRowCount(), -1);
  3639. }
  3640. int CALLBACK CGridCtrl::pfnCellTextCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  3641. {
  3642. UNUSED_ALWAYS(lParamSort);
  3643. CGridCellBase* pCell1 = (CGridCellBase*)lParam1;
  3644. CGridCellBase* pCell2 = (CGridCellBase*)lParam2;
  3645. if (!pCell1 || !pCell2) return 0;
  3646. return _tcscmp(pCell1->GetText(), pCell2->GetText());
  3647. }
  3648. int CALLBACK CGridCtrl::pfnCellNumericCompare(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
  3649. {
  3650. UNUSED_ALWAYS(lParamSort);
  3651. CGridCellBase* pCell1 = (CGridCellBase*)lParam1;
  3652. CGridCellBase* pCell2 = (CGridCellBase*)lParam2;
  3653. if (!pCell1 || !pCell2) return 0;
  3654. int nValue1 = _ttol(pCell1->GetText());
  3655. int nValue2 = _ttol(pCell2->GetText());
  3656. if (nValue1 < nValue2)
  3657. return -1;
  3658. else if (nValue1 == nValue2)
  3659. return 0;
  3660. else
  3661. return 1;
  3662. }
  3663. // private recursive sort implementation
  3664. BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data,
  3665. int low, int high)
  3666. {
  3667. if (nCol >= GetColumnCount())
  3668. return FALSE;
  3669. if (high == -1)
  3670. high = GetRowCount() - 1;
  3671. int lo = low;
  3672. int hi = high;
  3673. if (hi <= lo)
  3674. return FALSE;
  3675. //LPARAM midItem = GetItemData((lo + hi)/2, nCol);
  3676. LPARAM pMidCell = (LPARAM)GetCell((lo + hi) / 2, nCol);
  3677. // loop through the list until indices cross
  3678. while (lo <= hi)
  3679. {
  3680. // Find the first element that is greater than or equal to the partition
  3681. // element starting from the left Index.
  3682. if (bAscending)
  3683. while (lo < high && pfnCompare((LPARAM)GetCell(lo, nCol), (LPARAM)pMidCell, data) < 0)
  3684. ++lo;
  3685. else
  3686. while (lo < high && pfnCompare((LPARAM)GetCell(lo, nCol), pMidCell, data) > 0)
  3687. ++lo;
  3688. // Find an element that is smaller than or equal to the partition
  3689. // element starting from the right Index.
  3690. if (bAscending)
  3691. while (hi > low && pfnCompare((LPARAM)GetCell(hi, nCol), pMidCell, data) > 0)
  3692. --hi;
  3693. else
  3694. while (hi > low && pfnCompare((LPARAM)GetCell(hi, nCol), pMidCell, data) < 0)
  3695. --hi;
  3696. // If the indexes have not crossed, swap if the items are not equal
  3697. if (lo <= hi)
  3698. {
  3699. // swap only if the items are not equal
  3700. if (pfnCompare((LPARAM)GetCell(lo, nCol), (LPARAM)GetCell(hi, nCol), data) != 0)
  3701. {
  3702. for (int col = 0; col < GetColumnCount(); col++)
  3703. {
  3704. CGridCellBase *pCell = GetCell(lo, col);
  3705. SetCell(lo, col, GetCell(hi, col));
  3706. SetCell(hi, col, pCell);
  3707. }
  3708. UINT nRowHeight = m_arRowHeights[lo];
  3709. m_arRowHeights[lo] = m_arRowHeights[hi];
  3710. m_arRowHeights[hi] = nRowHeight;
  3711. }
  3712. ++lo;
  3713. --hi;
  3714. }
  3715. }
  3716. // If the right index has not reached the left side of array
  3717. // must now sort the left partition.
  3718. if (low < hi)
  3719. SortItems(pfnCompare, nCol, bAscending, data, low, hi);
  3720. // If the left index has not reached the right side of array
  3721. // must now sort the right partition.
  3722. if (lo < high)
  3723. SortItems(pfnCompare, nCol, bAscending, data, lo, high);
  3724. return TRUE;
  3725. }
  3726. /////////////////////////////////////////////////////////////////////////////
  3727. // CGridCtrl data functions
  3728. BOOL CGridCtrl::SetItem(const GV_ITEM* pItem)
  3729. {
  3730. if (!pItem || GetVirtualMode())
  3731. return FALSE;
  3732. CGridCellBase* pCell = GetCell(pItem->row, pItem->col);
  3733. if (!pCell)
  3734. return FALSE;
  3735. SetModified(TRUE, pItem->row, pItem->col);
  3736. if (pItem->mask & GVIF_TEXT)
  3737. pCell->SetText(pItem->strText);
  3738. if (pItem->mask & GVIF_PARAM)
  3739. pCell->SetData(pItem->lParam);
  3740. if (pItem->mask & GVIF_IMAGE)
  3741. pCell->SetImage(pItem->iImage);
  3742. if (pItem->mask & GVIF_STATE)
  3743. SetItemState(pItem->row, pItem->col, pItem->nState);
  3744. if (pItem->mask & GVIF_FORMAT)
  3745. pCell->SetFormat(pItem->nFormat);
  3746. if (pItem->mask & GVIF_BKCLR)
  3747. pCell->SetBackClr(pItem->crBkClr);
  3748. if (pItem->mask & GVIF_FGCLR)
  3749. pCell->SetTextClr(pItem->crFgClr);
  3750. if (pItem->mask & GVIF_FONT)
  3751. pCell->SetFont(&(pItem->lfFont));
  3752. if (pItem->mask & GVIF_MARGIN)
  3753. pCell->SetMargin(pItem->nMargin);
  3754. if (pItem->mask & GVIF_BORDER) // HYF
  3755. pCell->SetBorder(pItem->nBorder); // HYF
  3756. if (pItem->mask & GVIF_BORDERCLR) // HYF
  3757. pCell->SetBorderClr(pItem->crBorderClr); // HYF
  3758. return TRUE;
  3759. }
  3760. BOOL CGridCtrl::GetItem(GV_ITEM* pItem)
  3761. {
  3762. if (!pItem)
  3763. return FALSE;
  3764. CGridCellBase* pCell = GetCell(pItem->row, pItem->col);
  3765. if (!pCell)
  3766. return FALSE;
  3767. if (pItem->mask & GVIF_TEXT)
  3768. pItem->strText = GetItemText(pItem->row, pItem->col);
  3769. if (pItem->mask & GVIF_PARAM)
  3770. pItem->lParam = pCell->GetData();;
  3771. if (pItem->mask & GVIF_IMAGE)
  3772. pItem->iImage = pCell->GetImage();
  3773. if (pItem->mask & GVIF_STATE)
  3774. pItem->nState = pCell->GetState();
  3775. if (pItem->mask & GVIF_FORMAT)
  3776. pItem->nFormat = pCell->GetFormat();
  3777. if (pItem->mask & GVIF_BKCLR)
  3778. pItem->crBkClr = pCell->GetBackClr();
  3779. if (pItem->mask & GVIF_FGCLR)
  3780. pItem->crFgClr = pCell->GetTextClr();
  3781. if (pItem->mask & GVIF_FONT)
  3782. memcpy(&(pItem->lfFont), pCell->GetFont(), sizeof(LOGFONT));
  3783. if (pItem->mask & GVIF_MARGIN)
  3784. pItem->nMargin = pCell->GetMargin();
  3785. return TRUE;
  3786. }
  3787. BOOL CGridCtrl::SetItemText(int nRow, int nCol, LPCTSTR str)
  3788. {
  3789. if (GetVirtualMode())
  3790. return FALSE;
  3791. CGridCellBase* pCell = GetCell(nRow, nCol);
  3792. if (!pCell)
  3793. return FALSE;
  3794. pCell->SetText(str);
  3795. SetModified(TRUE, nRow, nCol);
  3796. return TRUE;
  3797. }
  3798. #if !defined(_WIN32_WCE) || (_WIN32_WCE >= 210)
  3799. // EFW - 06/13/99 - Added to support printf-style formatting codes
  3800. BOOL CGridCtrl::SetItemTextFmt(int nRow, int nCol, LPCTSTR szFmt, ...)
  3801. {
  3802. if (GetVirtualMode())
  3803. return FALSE;
  3804. CString strText;
  3805. va_list argptr;
  3806. CGridCellBase* pCell = GetCell(nRow, nCol);
  3807. if (!pCell)
  3808. return FALSE;
  3809. // Format the message text
  3810. va_start(argptr, szFmt);
  3811. strText.FormatV(szFmt, argptr);
  3812. va_end(argptr);
  3813. pCell->SetText(strText);
  3814. SetModified(TRUE, nRow, nCol);
  3815. return TRUE;
  3816. }
  3817. // EFW - 06/13/99 - Added to support string resource ID. Supports
  3818. // a variable argument list too.
  3819. BOOL CGridCtrl::SetItemTextFmtID(int nRow, int nCol, UINT nID, ...)
  3820. {
  3821. if (GetVirtualMode())
  3822. return FALSE;
  3823. CString strFmt, strText;
  3824. va_list argptr;
  3825. CGridCellBase* pCell = GetCell(nRow, nCol);
  3826. if (!pCell)
  3827. return FALSE;
  3828. // Format the message text
  3829. va_start(argptr, nID);
  3830. VERIFY(strFmt.LoadString(nID));
  3831. strText.FormatV(strFmt, argptr);
  3832. va_end(argptr);
  3833. pCell->SetText(strText);
  3834. SetModified(TRUE, nRow, nCol);
  3835. return TRUE;
  3836. }
  3837. #endif
  3838. BOOL CGridCtrl::SetItemData(int nRow, int nCol, LPARAM lParam)
  3839. {
  3840. if (GetVirtualMode())
  3841. return FALSE;
  3842. CGridCellBase* pCell = GetCell(nRow, nCol);
  3843. if (!pCell)
  3844. return FALSE;
  3845. pCell->SetData(lParam);
  3846. SetModified(TRUE, nRow, nCol);
  3847. return TRUE;
  3848. }
  3849. LPARAM CGridCtrl::GetItemData(int nRow, int nCol) const
  3850. {
  3851. CGridCellBase* pCell = GetCell(nRow, nCol);
  3852. if (!pCell)
  3853. return (LPARAM)0;
  3854. return pCell->GetData();
  3855. }
  3856. BOOL CGridCtrl::SetItemImage(int nRow, int nCol, int iImage)
  3857. {
  3858. if (GetVirtualMode())
  3859. return FALSE;
  3860. CGridCellBase* pCell = GetCell(nRow, nCol);
  3861. if (!pCell)
  3862. return FALSE;
  3863. pCell->SetImage(iImage);
  3864. SetModified(TRUE, nRow, nCol);
  3865. return TRUE;
  3866. }
  3867. int CGridCtrl::GetItemImage(int nRow, int nCol) const
  3868. {
  3869. CGridCellBase* pCell = GetCell(nRow, nCol);
  3870. ASSERT(pCell);
  3871. if (!pCell)
  3872. return -1;
  3873. return pCell->GetImage();
  3874. }
  3875. BOOL CGridCtrl::SetItemState(int nRow, int nCol, UINT state)
  3876. {
  3877. BOOL bSelected = IsCellSelected(nRow, nCol);
  3878. // If the cell is being unselected, remove it from the selected list
  3879. if (bSelected && !(state & GVIS_SELECTED))
  3880. {
  3881. CCellID cell;
  3882. DWORD key = MAKELONG(nRow, nCol);
  3883. if (m_SelectedCellMap.Lookup(key, (CCellID&)cell))
  3884. m_SelectedCellMap.RemoveKey(key);
  3885. }
  3886. // If cell is being selected, add it to the list of selected cells
  3887. else if (!bSelected && (state & GVIS_SELECTED))
  3888. {
  3889. CCellID cell(nRow, nCol);
  3890. m_SelectedCellMap.SetAt(MAKELONG(nRow, nCol), cell);
  3891. }
  3892. if (GetVirtualMode())
  3893. return FALSE;
  3894. CGridCellBase* pCell = GetCell(nRow, nCol);
  3895. ASSERT(pCell);
  3896. if (!pCell)
  3897. return FALSE;
  3898. // Set the cell's state
  3899. pCell->SetState(state);
  3900. return TRUE;
  3901. }
  3902. UINT CGridCtrl::GetItemState(int nRow, int nCol) const
  3903. {
  3904. CGridCellBase* pCell = GetCell(nRow, nCol);
  3905. ASSERT(pCell);
  3906. if (!pCell)
  3907. return 0;
  3908. return pCell->GetState();
  3909. }
  3910. BOOL CGridCtrl::SetItemFormat(int nRow, int nCol, UINT nFormat)
  3911. {
  3912. if (GetVirtualMode())
  3913. return FALSE;
  3914. CGridCellBase* pCell = GetCell(nRow, nCol);
  3915. ASSERT(pCell);
  3916. if (!pCell)
  3917. return FALSE;
  3918. pCell->SetFormat(nFormat);
  3919. return TRUE;
  3920. }
  3921. UINT CGridCtrl::GetItemFormat(int nRow, int nCol) const
  3922. {
  3923. CGridCellBase* pCell = GetCell(nRow, nCol);
  3924. ASSERT(pCell);
  3925. if (!pCell)
  3926. return 0;
  3927. return pCell->GetFormat();
  3928. }
  3929. BOOL CGridCtrl::SetItemBkColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
  3930. {
  3931. if (GetVirtualMode())
  3932. return FALSE;
  3933. CGridCellBase* pCell = GetCell(nRow, nCol);
  3934. ASSERT(pCell);
  3935. if (!pCell)
  3936. return FALSE;
  3937. pCell->SetBackClr(cr);
  3938. return TRUE;
  3939. }
  3940. COLORREF CGridCtrl::GetItemBkColour(int nRow, int nCol) const
  3941. {
  3942. CGridCellBase* pCell = GetCell(nRow, nCol);
  3943. ASSERT(pCell);
  3944. if (!pCell)
  3945. return 0;
  3946. return pCell->GetBackClr();
  3947. }
  3948. BOOL CGridCtrl::SetItemFgColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
  3949. {
  3950. if (GetVirtualMode())
  3951. return FALSE;
  3952. CGridCellBase* pCell = GetCell(nRow, nCol);
  3953. ASSERT(pCell);
  3954. if (!pCell)
  3955. return FALSE;
  3956. pCell->SetTextClr(cr);
  3957. return TRUE;
  3958. }
  3959. COLORREF CGridCtrl::GetItemFgColour(int nRow, int nCol) const
  3960. {
  3961. CGridCellBase* pCell = GetCell(nRow, nCol);
  3962. ASSERT(pCell);
  3963. if (!pCell)
  3964. return 0;
  3965. return pCell->GetTextClr();
  3966. }
  3967. BOOL CGridCtrl::SetItemFont(int nRow, int nCol, const LOGFONT* plf)
  3968. {
  3969. if (GetVirtualMode())
  3970. return FALSE;
  3971. CGridCellBase* pCell = GetCell(nRow, nCol);
  3972. ASSERT(pCell);
  3973. if (!pCell)
  3974. return FALSE;
  3975. pCell->SetFont(plf);
  3976. return TRUE;
  3977. }
  3978. const LOGFONT* CGridCtrl::GetItemFont(int nRow, int nCol)
  3979. {
  3980. CGridCellBase* pCell = GetCell(nRow, nCol);
  3981. ASSERT(pCell);
  3982. if (!pCell)
  3983. return GetDefaultCell(nRow < GetFixedRowCount(), nCol < GetFixedColumnCount())->GetFont();
  3984. return pCell->GetFont();
  3985. }
  3986. BOOL CGridCtrl::IsItemEditing(int nRow, int nCol)
  3987. {
  3988. CGridCellBase* pCell = GetCell(nRow, nCol);
  3989. ASSERT(pCell);
  3990. if (!pCell)
  3991. return FALSE;
  3992. return pCell->IsEditing();
  3993. }
  3994. ////////////////////////////////////////////////////////////////////////////////////
  3995. // Row/Column size functions
  3996. long CGridCtrl::GetVirtualWidth() const
  3997. {
  3998. long lVirtualWidth = 0;
  3999. int iColCount = GetColumnCount();
  4000. for (int i = 0; i < iColCount; i++)
  4001. lVirtualWidth += m_arColWidths[i];
  4002. return lVirtualWidth;
  4003. }
  4004. long CGridCtrl::GetVirtualHeight() const
  4005. {
  4006. long lVirtualHeight = 0;
  4007. int iRowCount = GetRowCount();
  4008. for (int i = 0; i < iRowCount; i++)
  4009. lVirtualHeight += m_arRowHeights[i];
  4010. return lVirtualHeight;
  4011. }
  4012. int CGridCtrl::GetRowHeight(int nRow) const
  4013. {
  4014. ASSERT(nRow >= 0 && nRow < m_nRows);
  4015. if (nRow < 0 || nRow >= m_nRows)
  4016. return -1;
  4017. return m_arRowHeights[nRow];
  4018. }
  4019. int CGridCtrl::GetColumnWidth(int nCol) const
  4020. {
  4021. ASSERT(nCol >= 0 && nCol < m_nCols);
  4022. if (nCol < 0 || nCol >= m_nCols)
  4023. return -1;
  4024. return m_arColWidths[nCol];
  4025. }
  4026. BOOL CGridCtrl::SetRowHeight(int nRow, int height)
  4027. {
  4028. ASSERT(nRow >= 0 && nRow < m_nRows && height >= 0);
  4029. if (nRow < 0 || nRow >= m_nRows || height < 0)
  4030. return FALSE;
  4031. m_arRowHeights[nRow] = height;
  4032. ResetScrollBars();
  4033. return TRUE;
  4034. }
  4035. BOOL CGridCtrl::SetColumnWidth(int nCol, int width)
  4036. {
  4037. ASSERT(nCol >= 0 && nCol < m_nCols && width >= 0);
  4038. if (nCol < 0 || nCol >= m_nCols || width < 0)
  4039. return FALSE;
  4040. m_arColWidths[nCol] = width;
  4041. ResetScrollBars();
  4042. return TRUE;
  4043. }
  4044. int CGridCtrl::GetFixedRowHeight() const
  4045. {
  4046. int nHeight = 0;
  4047. for (int i = 0; i < m_nFixedRows; i++)
  4048. nHeight += GetRowHeight(i);
  4049. return nHeight;
  4050. }
  4051. int CGridCtrl::GetFixedColumnWidth() const
  4052. {
  4053. int nWidth = 0;
  4054. for (int i = 0; i < m_nFixedCols; i++)
  4055. nWidth += GetColumnWidth(i);
  4056. return nWidth;
  4057. }
  4058. BOOL CGridCtrl::AutoSizeColumn(int nCol, UINT nAutoSizeStyle /*=GVS_DEFAULT*/,
  4059. BOOL bResetScroll /*=TRUE*/)
  4060. {
  4061. ASSERT(nCol >= 0 && nCol < m_nCols);
  4062. if (nCol < 0 || nCol >= m_nCols)
  4063. return FALSE;
  4064. // Skip hidden columns when autosizing
  4065. if (GetColumnWidth(nCol) <= 0)
  4066. return FALSE;
  4067. CSize size;
  4068. CDC* pDC = GetDC();
  4069. if (!pDC)
  4070. return FALSE;
  4071. int nWidth = 0;
  4072. ASSERT(GVS_DEFAULT <= nAutoSizeStyle && nAutoSizeStyle <= GVS_BOTH);
  4073. if (nAutoSizeStyle == GVS_DEFAULT)
  4074. nAutoSizeStyle = GetAutoSizeStyle();
  4075. int nStartRow = (nAutoSizeStyle & GVS_HEADER) ? 0 : GetFixedRowCount();
  4076. int nEndRow = (nAutoSizeStyle & GVS_DATA) ? GetRowCount() - 1 : GetFixedRowCount() - 1;
  4077. if (GetVirtualMode())
  4078. SendCacheHintToParent(CCellRange(nStartRow, nCol, nEndRow, nCol));
  4079. for (int nRow = nStartRow; nRow <= nEndRow; nRow++)
  4080. {
  4081. CGridCellBase* pCell = GetCell(nRow, nCol);
  4082. if (pCell)
  4083. size = pCell->GetCellExtent(pDC);
  4084. if (size.cx > nWidth)
  4085. nWidth = size.cx;
  4086. }
  4087. if (GetVirtualMode())
  4088. SendCacheHintToParent(CCellRange(-1, -1, -1, -1));
  4089. m_arColWidths[nCol] = nWidth;
  4090. ReleaseDC(pDC);
  4091. if (bResetScroll)
  4092. ResetScrollBars();
  4093. return TRUE;
  4094. }
  4095. BOOL CGridCtrl::AutoSizeRow(int nRow, BOOL bResetScroll /*=TRUE*/)
  4096. {
  4097. ASSERT(nRow >= 0 && nRow < m_nRows);
  4098. if (nRow < 0 || nRow >= m_nRows)
  4099. return FALSE;
  4100. // Skip hidden rows when autosizing
  4101. if (GetRowHeight(nRow) <= 0)
  4102. return FALSE;
  4103. CSize size;
  4104. CDC* pDC = GetDC();
  4105. if (!pDC)
  4106. return FALSE;
  4107. int nHeight = 0;
  4108. int nNumColumns = GetColumnCount();
  4109. if (GetVirtualMode())
  4110. SendCacheHintToParent(CCellRange(nRow, 0, nRow, nNumColumns));
  4111. for (int nCol = 0; nCol < nNumColumns; nCol++)
  4112. {
  4113. CGridCellBase* pCell = GetCell(nRow, nCol);
  4114. if (pCell)
  4115. size = pCell->GetCellExtent(pDC);
  4116. if (size.cy > nHeight)
  4117. nHeight = size.cy;
  4118. }
  4119. m_arRowHeights[nRow] = nHeight;
  4120. if (GetVirtualMode())
  4121. SendCacheHintToParent(CCellRange(-1, -1, -1, -1));
  4122. ReleaseDC(pDC);
  4123. if (bResetScroll)
  4124. ResetScrollBars();
  4125. return TRUE;
  4126. }
  4127. void CGridCtrl::AutoSizeColumns(UINT nAutoSizeStyle /*=GVS_DEFAULT*/)
  4128. {
  4129. int nNumColumns = GetColumnCount();
  4130. for (int nCol = 0; nCol < nNumColumns; nCol++)
  4131. {
  4132. // Skip hidden columns when autosizing
  4133. if (GetColumnWidth(nCol) > 0)
  4134. AutoSizeColumn(nCol, nAutoSizeStyle, FALSE);
  4135. }
  4136. ResetScrollBars();
  4137. }
  4138. void CGridCtrl::AutoSizeRows()
  4139. {
  4140. int nNumRows = GetRowCount();
  4141. for (int nRow = 0; nRow < nNumRows; nRow++)
  4142. {
  4143. // Skip hidden rows when autosizing
  4144. if (GetRowHeight(nRow) > 0)
  4145. AutoSizeRow(nRow, FALSE);
  4146. }
  4147. ResetScrollBars();
  4148. }
  4149. // sizes all rows and columns
  4150. // faster than calling both AutoSizeColumns() and AutoSizeRows()
  4151. void CGridCtrl::AutoSize(UINT nAutoSizeStyle /*=GVS_DEFAULT*/)
  4152. {
  4153. CDC* pDC = GetDC();
  4154. if (!pDC)
  4155. return;
  4156. int nNumColumns = GetColumnCount();
  4157. int nCol, nRow;
  4158. ASSERT(GVS_DEFAULT <= nAutoSizeStyle && nAutoSizeStyle <= GVS_BOTH);
  4159. if (nAutoSizeStyle == GVS_DEFAULT)
  4160. nAutoSizeStyle = GetAutoSizeStyle();
  4161. int nStartRow = (nAutoSizeStyle & GVS_HEADER) ? 0 : GetFixedRowCount();
  4162. int nEndRow = (nAutoSizeStyle & GVS_DATA) ? GetRowCount() - 1 : GetFixedRowCount() - 1;
  4163. if (GetVirtualMode())
  4164. SendCacheHintToParent(CCellRange(nStartRow, 0, nEndRow, nNumColumns));
  4165. // Row initialisation - only work on rows whose height is > 0
  4166. for (nRow = nStartRow; nRow <= nEndRow; nRow++)
  4167. {
  4168. if (GetRowHeight(nRow) > 0)
  4169. m_arRowHeights[nRow] = 1;
  4170. }
  4171. CSize size;
  4172. for (nCol = 0; nCol < nNumColumns; nCol++)
  4173. {
  4174. // Don't size hidden columns or rows
  4175. if (GetColumnWidth(nCol) > 0)
  4176. {
  4177. // Skip columns that are hidden, but now initialize
  4178. m_arColWidths[nCol] = 0;
  4179. for (nRow = nStartRow; nRow <= nEndRow; nRow++)
  4180. {
  4181. if (GetRowHeight(nRow) > 0)
  4182. {
  4183. CGridCellBase* pCell = GetCell(nRow, nCol);
  4184. if (pCell)
  4185. size = pCell->GetCellExtent(pDC);
  4186. if (size.cx > (int)m_arColWidths[nCol])
  4187. m_arColWidths[nCol] = size.cx;
  4188. if (size.cy > (int)m_arRowHeights[nRow])
  4189. m_arRowHeights[nRow] = size.cy;
  4190. }
  4191. }
  4192. }
  4193. }
  4194. if (GetVirtualMode())
  4195. SendCacheHintToParent(CCellRange(-1, -1, -1, -1));
  4196. ReleaseDC(pDC);
  4197. ResetScrollBars();
  4198. Refresh();
  4199. }
  4200. // Expands the columns to fit the screen space. If bExpandFixed is FALSE then fixed
  4201. // columns will not be affected
  4202. void CGridCtrl::ExpandColumnsToFit(BOOL bExpandFixed /*=TRUE*/)
  4203. {
  4204. if (bExpandFixed)
  4205. {
  4206. if (GetColumnCount() <= 0) return;
  4207. }
  4208. else
  4209. {
  4210. if (GetColumnCount() <= GetFixedColumnCount()) return;
  4211. }
  4212. EnableScrollBars(SB_HORZ, FALSE);
  4213. CRect rect;
  4214. GetClientRect(rect);
  4215. int nFirstColumn = (bExpandFixed) ? 0 : GetFixedColumnCount();
  4216. int nNumColumnsAffected = 0;
  4217. for (int col = nFirstColumn; col < GetColumnCount(); col++)
  4218. {
  4219. if (m_arColWidths[col] > 0)
  4220. nNumColumnsAffected++;
  4221. }
  4222. if (nNumColumnsAffected <= 0)
  4223. return;
  4224. long virtualWidth = GetVirtualWidth();
  4225. int nDifference = rect.Width() - (int)virtualWidth;
  4226. int nColumnAdjustment = nDifference / nNumColumnsAffected;
  4227. for (int col = nFirstColumn; col < GetColumnCount(); col++)
  4228. {
  4229. if (m_arColWidths[col] > 0)
  4230. m_arColWidths[col] += nColumnAdjustment;
  4231. }
  4232. if (nDifference > 0)
  4233. {
  4234. int leftOver = nDifference % nNumColumnsAffected;
  4235. for (int nCount = 0, col = nFirstColumn;
  4236. (col < GetColumnCount()) && (nCount < leftOver); col++, nCount++)
  4237. {
  4238. if (m_arColWidths[col] > 0)
  4239. m_arColWidths[col] += 1;
  4240. }
  4241. }
  4242. else
  4243. {
  4244. int leftOver = (-nDifference) % nNumColumnsAffected;
  4245. for (int nCount = 0, col = nFirstColumn;
  4246. (col < GetColumnCount()) && (nCount < leftOver); col++, nCount++)
  4247. {
  4248. if (m_arColWidths[col] > 0)
  4249. m_arColWidths[col] -= 1;
  4250. }
  4251. }
  4252. Refresh();
  4253. ResetScrollBars();
  4254. }
  4255. void CGridCtrl::ExpandLastColumn()
  4256. {
  4257. if (GetColumnCount() <= 0)
  4258. return;
  4259. // Search for last non-hidden column
  4260. int nLastColumn = GetColumnCount() - 1;
  4261. while (m_arColWidths[nLastColumn] <= 0)
  4262. nLastColumn--;
  4263. if (nLastColumn <= 0)
  4264. return;
  4265. EnableScrollBars(SB_HORZ, FALSE);
  4266. CRect rect;
  4267. GetClientRect(rect);
  4268. long virtualWidth = GetVirtualWidth();
  4269. int nDifference = rect.Width() - (int)virtualWidth;
  4270. if (nDifference > 0)
  4271. {
  4272. //if (GetVirtualHeight() > rect.Height())
  4273. // nDifference -= GetSystemMetrics(SM_CXVSCROLL);
  4274. m_arColWidths[nLastColumn] += nDifference;
  4275. Refresh();
  4276. }
  4277. ResetScrollBars();
  4278. }
  4279. // Expands the rows to fit the screen space. If bExpandFixed is FALSE then fixed
  4280. // rows will not be affected
  4281. void CGridCtrl::ExpandRowsToFit(BOOL bExpandFixed /*=TRUE*/)
  4282. {
  4283. if (bExpandFixed)
  4284. {
  4285. if (GetRowCount() <= 0) return;
  4286. }
  4287. else
  4288. {
  4289. if (GetRowCount() <= GetFixedRowCount()) return;
  4290. }
  4291. EnableScrollBars(SB_VERT, FALSE);
  4292. CRect rect;
  4293. GetClientRect(rect);
  4294. int nFirstRow = (bExpandFixed) ? 0 : GetFixedRowCount();
  4295. int nNumRowsAffected = 0;
  4296. for (int row = nFirstRow; row < GetRowCount(); row++)
  4297. {
  4298. if (m_arRowHeights[row] > 0)
  4299. nNumRowsAffected++;
  4300. }
  4301. if (nNumRowsAffected <= 0)
  4302. return;
  4303. long virtualHeight = GetVirtualHeight();
  4304. int nDifference = rect.Height() - (int)virtualHeight;
  4305. int nRowAdjustment = nDifference / nNumRowsAffected;
  4306. for (int row = nFirstRow; row < GetRowCount(); row++)
  4307. {
  4308. if (m_arRowHeights[row] > 0)
  4309. m_arRowHeights[row] += nRowAdjustment;
  4310. }
  4311. if (nDifference > 0)
  4312. {
  4313. int leftOver = nDifference % nNumRowsAffected;
  4314. for (int nCount = 0, row = nFirstRow;
  4315. (row < GetRowCount()) && (nCount < leftOver); row++, nCount++)
  4316. {
  4317. if (m_arRowHeights[row] > 0)
  4318. m_arRowHeights[row] += 1;
  4319. }
  4320. }
  4321. else
  4322. {
  4323. int leftOver = (-nDifference) % nNumRowsAffected;
  4324. for (int nCount = 0, row = nFirstRow;
  4325. (row < GetRowCount()) && (nCount < leftOver); row++, nCount++)
  4326. {
  4327. if (m_arRowHeights[row] > 0)
  4328. m_arRowHeights[row] -= 1;
  4329. }
  4330. }
  4331. Refresh();
  4332. ResetScrollBars();
  4333. }
  4334. // Expands the cells to fit the screen space. If bExpandFixed is FALSE then fixed
  4335. // cells will not be affected
  4336. void CGridCtrl::ExpandToFit(BOOL bExpandFixed /*=TRUE*/)
  4337. {
  4338. ExpandColumnsToFit(bExpandFixed); // This will remove any existing horz scrollbar
  4339. ExpandRowsToFit(bExpandFixed); // This will remove any existing vert scrollbar
  4340. ExpandColumnsToFit(bExpandFixed); // Just in case the first adjustment was with a vert
  4341. // scrollbar in place
  4342. Refresh();
  4343. }
  4344. /////////////////////////////////////////////////////////////////////////////////////
  4345. // Attributes
  4346. void CGridCtrl::SetVirtualMode(BOOL bVirtual)
  4347. {
  4348. DeleteAllItems();
  4349. m_bVirtualMode = bVirtual;
  4350. // Force some defaults here.
  4351. if (m_bVirtualMode)
  4352. {
  4353. SetEditable(FALSE);
  4354. SetHeaderSort(FALSE);
  4355. SetAutoSizeStyle(GVS_HEADER);
  4356. SetFixedColumnSelection(FALSE);
  4357. SetFixedRowSelection(FALSE);
  4358. }
  4359. }
  4360. void CGridCtrl::SetGridLines(int nWhichLines /*=GVL_BOTH*/)
  4361. {
  4362. m_nGridLines = nWhichLines;
  4363. Refresh();
  4364. }
  4365. void CGridCtrl::SetListMode(BOOL bEnableListMode /*=TRUE*/)
  4366. {
  4367. ResetSelectedRange();
  4368. SetSortColumn(-1);
  4369. m_bListMode = bEnableListMode;
  4370. SetFixedRowSelection(FALSE);
  4371. Refresh();
  4372. }
  4373. void CGridCtrl::SetSortColumn(int nCol)
  4374. {
  4375. if (m_nSortColumn >= 0)
  4376. InvalidateCellRect(0, m_nSortColumn);
  4377. m_nSortColumn = nCol;
  4378. if (nCol >= 0)
  4379. InvalidateCellRect(0, nCol);
  4380. }
  4381. BOOL CGridCtrl::IsCellFixed(int nRow, int nCol)
  4382. {
  4383. return (nRow < GetFixedRowCount() || nCol < GetFixedColumnCount());
  4384. }
  4385. void CGridCtrl::SetModified(BOOL bModified /*=TRUE*/, int nRow /*=-1*/, int nCol /*=-1*/)
  4386. {
  4387. // Cannot guarantee sorting anymore...
  4388. if (nCol < 0 || nCol == GetSortColumn())
  4389. SetSortColumn(-1);
  4390. if (nRow >= 0 && nCol >= 0)
  4391. {
  4392. if (bModified)
  4393. {
  4394. SetItemState(nRow, nCol, GetItemState(nRow, nCol) | GVIS_MODIFIED);
  4395. m_bModified = TRUE;
  4396. }
  4397. else
  4398. SetItemState(nRow, nCol, GetItemState(nRow, nCol) & ~GVIS_MODIFIED);
  4399. }
  4400. else
  4401. m_bModified = bModified;
  4402. if (!m_bModified)
  4403. {
  4404. for (int row = 0; row < GetRowCount(); row++)
  4405. for (int col = 0; col < GetColumnCount(); col++)
  4406. SetItemState(row, col, GetItemState(row, col) & ~GVIS_MODIFIED);
  4407. }
  4408. }
  4409. BOOL CGridCtrl::GetModified(int nRow /*=-1*/, int nCol /*=-1*/)
  4410. {
  4411. if (nRow >= 0 && nCol >= 0)
  4412. return ((GetItemState(nRow, nCol) & GVIS_MODIFIED) == GVIS_MODIFIED);
  4413. else
  4414. return m_bModified;
  4415. }
  4416. /////////////////////////////////////////////////////////////////////////////////////
  4417. // GridCtrl cell visibility tests and invalidation/redraw functions
  4418. void CGridCtrl::Refresh()
  4419. {
  4420. if (GetSafeHwnd() && m_bAllowDraw)
  4421. Invalidate();
  4422. }
  4423. // EnsureVisible supplied by Roelf Werkman
  4424. void CGridCtrl::EnsureVisible(int nRow, int nCol)
  4425. {
  4426. if (!m_bAllowDraw)
  4427. return;
  4428. CRect rectWindow;
  4429. /*
  4430. // set the scroll to the approximate position of row (Nigel Page-Jones)
  4431. int nPos = (int)((float)nRow / GetRowCount() * 1000);
  4432. float fPos = (float)nPos / 1000;
  4433. SCROLLINFO scrollInfo;
  4434. GetScrollInfo(SB_VERT, &scrollInfo);
  4435. scrollInfo.nPos = (int)(scrollInfo.nMax * fPos);
  4436. SetScrollInfo(SB_VERT, &scrollInfo, FALSE);
  4437. GetClientRect(rectWindow);
  4438. // redraw cells if necessary (Nigel Page-Jones)
  4439. CCellID idTopLeft = GetTopleftNonFixedCell(FALSE);
  4440. CCellID idNewTopLeft = GetTopleftNonFixedCell(TRUE);
  4441. if (idNewTopLeft != idTopLeft)
  4442. {
  4443. rectWindow.top = GetFixedRowHeight();
  4444. InvalidateRect(rectWindow);
  4445. }
  4446. */
  4447. // We are gonna send some scroll messages, which will steal the focus
  4448. // from it's rightful owner. Squirrel it away ourselves so we can give
  4449. // it back. (Damir)
  4450. CWnd* pFocusWnd = GetFocus();
  4451. CCellRange VisibleCells = GetVisibleNonFixedCellRange();
  4452. int right = nCol - VisibleCells.GetMaxCol();
  4453. int left = VisibleCells.GetMinCol() - nCol;
  4454. int down = nRow - VisibleCells.GetMaxRow();
  4455. int up = VisibleCells.GetMinRow() - nRow;
  4456. int iColumnStart;
  4457. int iRowStart;
  4458. iColumnStart = VisibleCells.GetMaxCol() + 1;
  4459. while (right > 0)
  4460. {
  4461. if (GetColumnWidth(iColumnStart) > 0)
  4462. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  4463. right--;
  4464. iColumnStart++;
  4465. }
  4466. iColumnStart = VisibleCells.GetMinCol() - 1;
  4467. while (left > 0)
  4468. {
  4469. if (GetColumnWidth(iColumnStart) > 0)
  4470. SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
  4471. left--;
  4472. iColumnStart--;
  4473. }
  4474. iRowStart = VisibleCells.GetMaxRow() + 1;
  4475. while (down > 0)
  4476. {
  4477. if (GetRowHeight(iRowStart) > 0)
  4478. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  4479. down--;
  4480. iRowStart++;
  4481. }
  4482. iRowStart = VisibleCells.GetMinRow() - 1;
  4483. while (up > 0)
  4484. {
  4485. if (GetRowHeight(iRowStart) > 0)
  4486. SendMessage(WM_VSCROLL, SB_LINEUP, 0);
  4487. up--;
  4488. iRowStart--;
  4489. }
  4490. // Move one more if we only see a snall bit of the cell
  4491. CRect rectCell;
  4492. if (!GetCellRect(nRow, nCol, rectCell))
  4493. {
  4494. if (pFocusWnd && ::IsWindow(pFocusWnd->GetSafeHwnd()))
  4495. pFocusWnd->SetFocus();
  4496. return;
  4497. }
  4498. GetClientRect(rectWindow);
  4499. // The previous fix was fixed properly by Martin Richter <martin.richter@grutzeck.de>
  4500. while (rectCell.right > rectWindow.right
  4501. && rectCell.left > GetFixedColumnWidth())
  4502. {
  4503. SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
  4504. if (!GetCellRect(nRow, nCol, rectCell))
  4505. {
  4506. if (pFocusWnd && ::IsWindow(pFocusWnd->GetSafeHwnd()))
  4507. pFocusWnd->SetFocus();
  4508. return;
  4509. }
  4510. }
  4511. while (rectCell.bottom > rectWindow.bottom
  4512. && rectCell.top > GetFixedRowHeight())
  4513. {
  4514. SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  4515. if (!GetCellRect(nRow, nCol, rectCell))
  4516. {
  4517. if (pFocusWnd && ::IsWindow(pFocusWnd->GetSafeHwnd()))
  4518. pFocusWnd->SetFocus();
  4519. return;
  4520. }
  4521. }
  4522. // restore focus to whoever owned it
  4523. if (pFocusWnd && ::IsWindow(pFocusWnd->GetSafeHwnd()))
  4524. pFocusWnd->SetFocus();
  4525. }
  4526. BOOL CGridCtrl::IsCellEditable(CCellID &cell) const
  4527. {
  4528. return IsCellEditable(cell.row, cell.col);
  4529. }
  4530. BOOL CGridCtrl::IsCellEditable(int nRow, int nCol) const
  4531. {
  4532. return IsEditable() && ((GetItemState(nRow, nCol) & GVIS_READONLY) != GVIS_READONLY);
  4533. }
  4534. BOOL CGridCtrl::IsCellSelected(CCellID &cell) const
  4535. {
  4536. return IsCellSelected(cell.row, cell.col);
  4537. }
  4538. BOOL CGridCtrl::IsCellSelected(int nRow, int nCol) const
  4539. {
  4540. if (GetVirtualMode())
  4541. {
  4542. if (!IsSelectable())
  4543. return FALSE;
  4544. CCellID cell;
  4545. DWORD key = MAKELONG(nRow, nCol);
  4546. return (m_SelectedCellMap.Lookup(key, (CCellID&)cell));
  4547. }
  4548. else
  4549. return IsSelectable() && ((GetItemState(nRow, nCol) & GVIS_SELECTED) == GVIS_SELECTED);
  4550. }
  4551. BOOL CGridCtrl::IsCellVisible(CCellID cell)
  4552. {
  4553. return IsCellVisible(cell.row, cell.col);
  4554. }
  4555. BOOL CGridCtrl::IsCellVisible(int nRow, int nCol)
  4556. {
  4557. if (!IsWindow(m_hWnd))
  4558. return FALSE;
  4559. int x, y;
  4560. CCellID TopLeft;
  4561. if (nCol >= GetFixedColumnCount() || nRow >= GetFixedRowCount())
  4562. {
  4563. TopLeft = GetTopleftNonFixedCell();
  4564. if (nCol >= GetFixedColumnCount() && nCol < TopLeft.col)
  4565. return FALSE;
  4566. if (nRow >= GetFixedRowCount() && nRow < TopLeft.row)
  4567. return FALSE;
  4568. }
  4569. CRect rect;
  4570. GetClientRect(rect);
  4571. if (nCol < GetFixedColumnCount())
  4572. {
  4573. x = 0;
  4574. for (int i = 0; i <= nCol; i++)
  4575. {
  4576. if (x >= rect.right)
  4577. return FALSE;
  4578. x += GetColumnWidth(i);
  4579. }
  4580. }
  4581. else
  4582. {
  4583. x = GetFixedColumnWidth();
  4584. for (int i = TopLeft.col; i <= nCol; i++)
  4585. {
  4586. if (x >= rect.right)
  4587. return FALSE;
  4588. x += GetColumnWidth(i);
  4589. }
  4590. }
  4591. if (nRow < GetFixedRowCount())
  4592. {
  4593. y = 0;
  4594. for (int i = 0; i <= nRow; i++)
  4595. {
  4596. if (y >= rect.bottom)
  4597. return FALSE;
  4598. y += GetRowHeight(i);
  4599. }
  4600. }
  4601. else
  4602. {
  4603. if (nRow < TopLeft.row)
  4604. return FALSE;
  4605. y = GetFixedRowHeight();
  4606. for (int i = TopLeft.row; i <= nRow; i++)
  4607. {
  4608. if (y >= rect.bottom)
  4609. return FALSE;
  4610. y += GetRowHeight(i);
  4611. }
  4612. }
  4613. return TRUE;
  4614. }
  4615. BOOL CGridCtrl::InvalidateCellRect(const CCellID& cell)
  4616. {
  4617. return InvalidateCellRect(cell.row, cell.col);
  4618. }
  4619. BOOL CGridCtrl::InvalidateCellRect(const int row, const int col)
  4620. {
  4621. if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw)
  4622. return FALSE;
  4623. if (!IsValid(row, col))
  4624. return FALSE;
  4625. if (!IsCellVisible(row, col))
  4626. return FALSE;
  4627. CRect rect;
  4628. if (!GetCellRect(row, col, rect))
  4629. return FALSE;
  4630. rect.right++;
  4631. rect.bottom++;
  4632. InvalidateRect(rect, TRUE);
  4633. return TRUE;
  4634. }
  4635. BOOL CGridCtrl::InvalidateCellRect(const CCellRange& cellRange)
  4636. {
  4637. ASSERT(IsValid(cellRange));
  4638. if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw)
  4639. return FALSE;
  4640. CCellRange visibleCellRange = GetVisibleNonFixedCellRange().Intersect(cellRange);
  4641. CRect rect;
  4642. if (!GetCellRangeRect(visibleCellRange, rect))
  4643. return FALSE;
  4644. rect.right++;
  4645. rect.bottom++;
  4646. InvalidateRect(rect, TRUE);
  4647. return TRUE;
  4648. }
  4649. /////////////////////////////////////////////////////////////////////////////
  4650. // CGridCtrl Mouse stuff
  4651. // Handles mouse wheel notifications
  4652. // Note - if this doesn't work for win95 then use OnRegisteredMouseWheel instead
  4653. #if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
  4654. BOOL CGridCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
  4655. {
  4656. // A m_nRowsPerWheelNotch value less than 0 indicates that the mouse
  4657. // wheel scrolls whole pages, not just lines.
  4658. if (m_nRowsPerWheelNotch == -1)
  4659. {
  4660. int nPagesScrolled = zDelta / 120;
  4661. if (nPagesScrolled > 0)
  4662. {
  4663. for (int i = 0; i < nPagesScrolled; i++)
  4664. {
  4665. PostMessage(WM_VSCROLL, SB_PAGEUP, 0);
  4666. }
  4667. }
  4668. else
  4669. {
  4670. for (int i = 0; i > nPagesScrolled; i--)
  4671. {
  4672. PostMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
  4673. }
  4674. }
  4675. }
  4676. else
  4677. {
  4678. int nRowsScrolled = m_nRowsPerWheelNotch * zDelta / 120;
  4679. if (nRowsScrolled > 0)
  4680. {
  4681. for (int i = 0; i < nRowsScrolled; i++)
  4682. {
  4683. PostMessage(WM_VSCROLL, SB_LINEUP, 0);
  4684. }
  4685. }
  4686. else
  4687. {
  4688. for (int i = 0; i > nRowsScrolled; i--)
  4689. {
  4690. PostMessage(WM_VSCROLL, SB_LINEDOWN, 0);
  4691. }
  4692. }
  4693. }
  4694. return CWnd::OnMouseWheel(nFlags, zDelta, pt);
  4695. }
  4696. #endif // !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
  4697. void CGridCtrl::OnMouseMove(UINT /*nFlags*/, CPoint point)
  4698. {
  4699. CRect rect;
  4700. GetClientRect(rect);
  4701. #ifndef GRIDCONTROL_NO_DRAGDROP
  4702. // If outside client area, return (unless we are drag n dropping)
  4703. if (m_MouseMode != MOUSE_DRAGGING && !rect.PtInRect(point))
  4704. return;
  4705. #endif
  4706. // Sometimes a MOUSEMOVE message can come after the left buttons
  4707. // has been let go, but before the BUTTONUP message hs been processed.
  4708. // We'll keep track of mouse buttons manually to avoid this.
  4709. // All bMouseButtonDown's have been replaced with the member m_bLMouseButtonDown
  4710. // BOOL bMouseButtonDown = ((nFlags & MK_LBUTTON) == MK_LBUTTON);
  4711. // If the left mouse button is up, then test to see if row/column sizing is imminent
  4712. if (!m_bLMouseButtonDown ||
  4713. (m_bLMouseButtonDown && m_MouseMode == MOUSE_NOTHING))
  4714. {
  4715. if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
  4716. {
  4717. if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
  4718. {
  4719. #ifndef _WIN32_WCE_NO_CURSOR
  4720. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  4721. #endif
  4722. m_MouseMode = MOUSE_OVER_COL_DIVIDE;
  4723. }
  4724. }
  4725. else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
  4726. {
  4727. if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
  4728. {
  4729. #ifndef _WIN32_WCE_NO_CURSOR
  4730. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
  4731. #endif
  4732. m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
  4733. }
  4734. }
  4735. else if (m_MouseMode != MOUSE_NOTHING)
  4736. {
  4737. #ifndef _WIN32_WCE_NO_CURSOR
  4738. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  4739. #endif
  4740. m_MouseMode = MOUSE_NOTHING;
  4741. }
  4742. if (m_MouseMode == MOUSE_NOTHING)
  4743. {
  4744. CGridCellBase* pCell = NULL;
  4745. CCellID idCurrentCell;
  4746. if (!GetVirtualMode() || m_bTitleTips)
  4747. {
  4748. // Let the cell know that a big fat cursor is currently hovering
  4749. // over it.
  4750. idCurrentCell = GetCellFromPt(point);
  4751. pCell = GetCell(idCurrentCell.row, idCurrentCell.col);
  4752. if (pCell)
  4753. pCell->OnMouseOver();
  4754. }
  4755. #ifndef GRIDCONTROL_NO_TITLETIPS
  4756. // Titletips anyone? anyone?
  4757. if (m_bTitleTips)
  4758. {
  4759. CRect TextRect, CellRect;
  4760. if (pCell)
  4761. {
  4762. LPCTSTR szTipText = pCell->GetTipText();
  4763. if (!m_bRMouseButtonDown
  4764. && szTipText && szTipText[0]
  4765. && !pCell->IsEditing()
  4766. && GetCellRect(idCurrentCell.row, idCurrentCell.col, &TextRect)
  4767. && pCell->GetTipTextRect(&TextRect)
  4768. && GetCellRect(idCurrentCell.row, idCurrentCell.col, CellRect))
  4769. {
  4770. TRACE0("Showing TitleTip\n");
  4771. m_TitleTip.Show(TextRect, pCell->GetTipText(), 0, CellRect,
  4772. pCell->GetFont(), GetTitleTipTextClr(), GetTitleTipBackClr());
  4773. }
  4774. }
  4775. }
  4776. #endif
  4777. }
  4778. m_LastMousePoint = point;
  4779. return;
  4780. }
  4781. if (!IsValid(m_LeftClickDownCell))
  4782. {
  4783. m_LastMousePoint = point;
  4784. return;
  4785. }
  4786. // If the left mouse button is down, then process appropriately
  4787. if (m_bLMouseButtonDown)
  4788. {
  4789. switch (m_MouseMode)
  4790. {
  4791. case MOUSE_SELECT_ALL:
  4792. break;
  4793. case MOUSE_SELECT_COL:
  4794. case MOUSE_SELECT_ROW:
  4795. case MOUSE_SELECT_CELLS:
  4796. {
  4797. CCellID idCurrentCell = GetCellFromPt(point);
  4798. if (!IsValid(idCurrentCell))
  4799. return;
  4800. if (idCurrentCell != GetFocusCell())
  4801. {
  4802. OnSelecting(idCurrentCell);
  4803. // EFW - BUG FIX - Keep the appropriate cell row and/or
  4804. // column focused. A fix in SetFocusCell() will place
  4805. // the cursor in a non-fixed cell as needed.
  4806. if ((idCurrentCell.row >= m_nFixedRows &&
  4807. idCurrentCell.col >= m_nFixedCols) ||
  4808. m_MouseMode == MOUSE_SELECT_COL ||
  4809. m_MouseMode == MOUSE_SELECT_ROW)
  4810. {
  4811. SetFocusCell(idCurrentCell);
  4812. }
  4813. }
  4814. break;
  4815. }
  4816. case MOUSE_SIZING_COL:
  4817. {
  4818. CDC* pDC = GetDC();
  4819. if (!pDC)
  4820. break;
  4821. CRect oldInvertedRect(m_LastMousePoint.x, rect.top,
  4822. m_LastMousePoint.x + 2, rect.bottom);
  4823. pDC->InvertRect(&oldInvertedRect);
  4824. CRect newInvertedRect(point.x, rect.top,
  4825. point.x + 2, rect.bottom);
  4826. pDC->InvertRect(&newInvertedRect);
  4827. ReleaseDC(pDC);
  4828. }
  4829. break;
  4830. case MOUSE_SIZING_ROW:
  4831. {
  4832. CDC* pDC = GetDC();
  4833. if (!pDC)
  4834. break;
  4835. CRect oldInvertedRect(rect.left, m_LastMousePoint.y,
  4836. rect.right, m_LastMousePoint.y + 2);
  4837. pDC->InvertRect(&oldInvertedRect);
  4838. CRect newInvertedRect(rect.left, point.y,
  4839. rect.right, point.y + 2);
  4840. pDC->InvertRect(&newInvertedRect);
  4841. ReleaseDC(pDC);
  4842. }
  4843. break;
  4844. #ifndef GRIDCONTROL_NO_DRAGDROP
  4845. case MOUSE_PREPARE_EDIT:
  4846. case MOUSE_PREPARE_DRAG:
  4847. m_MouseMode = MOUSE_PREPARE_DRAG;
  4848. OnBeginDrag();
  4849. break;
  4850. #endif
  4851. }
  4852. }
  4853. m_LastMousePoint = point;
  4854. }
  4855. // Returns the point inside the cell that was clicked (coords relative to cell top left)
  4856. CPoint CGridCtrl::GetPointClicked(int nRow, int nCol, const CPoint& point)
  4857. {
  4858. CPoint PointCellOrigin;
  4859. if (!GetCellOrigin(nRow, nCol, &PointCellOrigin))
  4860. return CPoint(0, 0);
  4861. CPoint PointClickedCellRelative(point);
  4862. PointClickedCellRelative -= PointCellOrigin;
  4863. return PointClickedCellRelative;
  4864. }
  4865. void CGridCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
  4866. {
  4867. TRACE0("CGridCtrl::OnLButtonDblClk\n");
  4868. CCellID cell = GetCellFromPt(point);
  4869. if (!IsValid(cell))
  4870. {
  4871. //ASSERT(FALSE);
  4872. return;
  4873. }
  4874. #ifdef _WIN32_WCE
  4875. if (MouseOverColumnResizeArea(point))
  4876. #else
  4877. if (m_MouseMode == MOUSE_OVER_COL_DIVIDE)
  4878. #endif
  4879. {
  4880. CPoint start;
  4881. if (!GetCellOrigin(0, cell.col, &start))
  4882. return;
  4883. if (point.x - start.x < m_nResizeCaptureRange) // Clicked right of border
  4884. cell.col--;
  4885. // ignore columns that are hidden and look left towards first visible column
  4886. BOOL bFoundVisible = FALSE;
  4887. while (cell.col >= 0)
  4888. {
  4889. if (GetColumnWidth(cell.col) > 0)
  4890. {
  4891. bFoundVisible = TRUE;
  4892. break;
  4893. }
  4894. cell.col--;
  4895. }
  4896. if (!bFoundVisible)
  4897. return;
  4898. AutoSizeColumn(cell.col, GetAutoSizeStyle());
  4899. Invalidate();
  4900. }
  4901. #ifdef _WIN32_WCE
  4902. else if (MouseOverRowResizeArea(point))
  4903. #else
  4904. else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE)
  4905. #endif
  4906. {
  4907. CPoint start;
  4908. if (!GetCellOrigin(0, cell.col, &start))
  4909. return;
  4910. if (point.y - start.y < m_nResizeCaptureRange) // Clicked below border
  4911. cell.row--;
  4912. // ignore rows that are hidden and look up towards first visible row
  4913. BOOL bFoundVisible = FALSE;
  4914. while (cell.row >= 0)
  4915. {
  4916. if (GetRowHeight(cell.row) > 0)
  4917. {
  4918. bFoundVisible = TRUE;
  4919. break;
  4920. }
  4921. cell.row--;
  4922. }
  4923. if (!bFoundVisible)
  4924. return;
  4925. AutoSizeRow(cell.row);
  4926. Invalidate();
  4927. }
  4928. else if (m_MouseMode == MOUSE_NOTHING)
  4929. {
  4930. CPoint pointClickedRel;
  4931. pointClickedRel = GetPointClicked(cell.row, cell.col, point);
  4932. CGridCellBase* pCell = NULL;
  4933. if (IsValid(cell))
  4934. pCell = GetCell(cell.row, cell.col);
  4935. // Clicked in the text area? Only then will cell selection work
  4936. BOOL bInTextArea = FALSE;
  4937. if (pCell)
  4938. {
  4939. CRect rectCell;
  4940. if (GetCellRect(cell.row, cell.col, rectCell) && pCell->GetTextRect(rectCell))
  4941. bInTextArea = rectCell.PtInRect(point);
  4942. }
  4943. if (cell.row >= m_nFixedRows && IsValid(m_LeftClickDownCell) &&
  4944. cell.col >= m_nFixedCols && bInTextArea)
  4945. {
  4946. OnEditCell(cell.row, cell.col, pointClickedRel, VK_LBUTTON);
  4947. }
  4948. else if (m_bListMode)
  4949. {
  4950. if (!IsValid(cell))
  4951. return;
  4952. if (cell.row >= m_nFixedRows && cell.col >= m_nFixedCols && bInTextArea)
  4953. OnEditCell(cell.row, cell.col, pointClickedRel, VK_LBUTTON);
  4954. }
  4955. if (IsValid(cell))
  4956. {
  4957. CGridCellBase* pCell = GetCell(cell.row, cell.col);
  4958. if (pCell)
  4959. pCell->OnDblClick(pointClickedRel);
  4960. SendMessageToParent(cell.row, cell.col, NM_DBLCLK);
  4961. }
  4962. }
  4963. CWnd::OnLButtonDblClk(nFlags, point);
  4964. }
  4965. void CGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
  4966. {
  4967. #ifdef GRIDCONTROL_USE_TITLETIPS
  4968. // EFW - Bug Fix
  4969. m_TitleTip.Hide(); // hide any titletips
  4970. #endif
  4971. // TRACE0("CGridCtrl::OnLButtonDown\n");
  4972. // CWnd::OnLButtonDown(nFlags, point);
  4973. SetFocus();
  4974. m_bLMouseButtonDown = TRUE;
  4975. m_LeftClickDownPoint = point;
  4976. m_LeftClickDownCell = GetCellFromPt(point);
  4977. if (!IsValid(m_LeftClickDownCell))
  4978. return;
  4979. // If the SHIFT key is not down, then the start of the selection area should be the
  4980. // cell just clicked. Otherwise, keep the previous selection-start-cell so the user
  4981. // can add to their previous cell selections in an intuitive way. If no selection-
  4982. // start-cell has been specified, then set it's value here and now.
  4983. if ((nFlags & MK_SHIFT) != MK_SHIFT)
  4984. m_SelectionStartCell = m_LeftClickDownCell;
  4985. else
  4986. {
  4987. if (!IsValid(m_SelectionStartCell))
  4988. m_SelectionStartCell = m_idCurrentCell;
  4989. }
  4990. EndEditing();
  4991. // tell the cell about it
  4992. CGridCellBase* pCell = GetCell(m_LeftClickDownCell.row, m_LeftClickDownCell.col);
  4993. if (pCell)
  4994. pCell->OnClickDown(GetPointClicked(m_LeftClickDownCell.row, m_LeftClickDownCell.col, point));
  4995. // Clicked in the text area? Only then will cell selection work
  4996. BOOL bInTextArea = FALSE;
  4997. if (pCell)
  4998. {
  4999. CRect rectCell;
  5000. if (GetCellRect(m_LeftClickDownCell.row, m_LeftClickDownCell.col, rectCell) &&
  5001. pCell->GetTextRect(rectCell))
  5002. {
  5003. bInTextArea = rectCell.PtInRect(point);
  5004. }
  5005. }
  5006. // If the user clicks on the current cell, then prepare to edit it.
  5007. // (If the user moves the mouse, then dragging occurs)
  5008. if (m_LeftClickDownCell == m_idCurrentCell &&
  5009. !(nFlags & MK_CONTROL) && bInTextArea &&
  5010. IsCellEditable(m_LeftClickDownCell))
  5011. {
  5012. m_MouseMode = MOUSE_PREPARE_EDIT;
  5013. return;
  5014. }
  5015. // If the user clicks on a selected cell, then prepare to drag it.
  5016. // (If the user moves the mouse, then dragging occurs)
  5017. else if (IsCellSelected(m_LeftClickDownCell))
  5018. {
  5019. // If control is pressed then unselect the cell or row (depending on the list mode)
  5020. if (nFlags & MK_CONTROL)
  5021. {
  5022. SetFocusCell(m_LeftClickDownCell);
  5023. if (GetListMode())
  5024. SelectRows(m_LeftClickDownCell, TRUE, FALSE);
  5025. else
  5026. SelectCells(m_LeftClickDownCell, TRUE, FALSE);
  5027. return;
  5028. }
  5029. #ifndef GRIDCONTROL_NO_DRAGDROP
  5030. else if (m_bAllowDragAndDrop)
  5031. m_MouseMode = MOUSE_PREPARE_DRAG;
  5032. #endif
  5033. }
  5034. else if (m_MouseMode != MOUSE_OVER_COL_DIVIDE &&
  5035. m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
  5036. {
  5037. if (m_LeftClickDownCell.row >= GetFixedRowCount() &&
  5038. m_LeftClickDownCell.col >= GetFixedColumnCount())
  5039. {
  5040. SetFocusCell(m_LeftClickDownCell.row, m_LeftClickDownCell.col);
  5041. }
  5042. else
  5043. SetFocusCell(-1, -1);
  5044. //Don't set focus on any cell if the user clicked on a fixed cell - David Pritchard
  5045. //if (GetRowCount() > GetFixedRowCount() &&
  5046. // GetColumnCount() > GetFixedColumnCount())
  5047. // SetFocusCell(max(m_LeftClickDownCell.row, m_nFixedRows),
  5048. // max(m_LeftClickDownCell.col, m_nFixedCols));
  5049. }
  5050. SetCapture();
  5051. if (m_MouseMode == MOUSE_NOTHING)
  5052. {
  5053. if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
  5054. {
  5055. if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
  5056. {
  5057. #ifndef _WIN32_WCE_NO_CURSOR
  5058. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
  5059. #endif
  5060. m_MouseMode = MOUSE_OVER_COL_DIVIDE;
  5061. }
  5062. }
  5063. else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
  5064. {
  5065. if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
  5066. {
  5067. #ifndef _WIN32_WCE_NO_CURSOR
  5068. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
  5069. #endif
  5070. m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
  5071. }
  5072. }
  5073. // else if (m_MouseMode != MOUSE_NOTHING)
  5074. //{
  5075. // SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  5076. // m_MouseMode = MOUSE_NOTHING;
  5077. //}
  5078. }
  5079. if (m_MouseMode == MOUSE_OVER_COL_DIVIDE) // sizing column
  5080. {
  5081. m_MouseMode = MOUSE_SIZING_COL;
  5082. // Kludge for if we are over the last column...
  5083. if (GetColumnWidth(GetColumnCount() - 1) < m_nResizeCaptureRange)
  5084. {
  5085. CRect VisRect;
  5086. GetVisibleNonFixedCellRange(VisRect);
  5087. if (abs(point.x - VisRect.right) < m_nResizeCaptureRange)
  5088. m_LeftClickDownCell.col = GetColumnCount() - 1;
  5089. }
  5090. CPoint start;
  5091. if (!GetCellOrigin(0, m_LeftClickDownCell.col, &start))
  5092. return;
  5093. if (!m_bHiddenColUnhide)
  5094. {
  5095. // ignore columns that are hidden and look left towards first visible column
  5096. BOOL bLookForVisible = TRUE;
  5097. BOOL bIsCellRightBorder = point.x - start.x >= m_nResizeCaptureRange;
  5098. if (bIsCellRightBorder
  5099. && m_LeftClickDownCell.col + 1 >= GetColumnCount())
  5100. {
  5101. // clicked on last column's right border
  5102. // if last column is visible, don't do anything
  5103. if (m_LeftClickDownCell.col >= 0)
  5104. bLookForVisible = FALSE;
  5105. }
  5106. if (bLookForVisible)
  5107. {
  5108. // clicked on column divider other than last right border
  5109. BOOL bFoundVisible = FALSE;
  5110. int iOffset = 1;
  5111. if (bIsCellRightBorder)
  5112. iOffset = 0;
  5113. while (m_LeftClickDownCell.col - iOffset >= 0)
  5114. {
  5115. if (GetColumnWidth(m_LeftClickDownCell.col - iOffset) > 0)
  5116. {
  5117. bFoundVisible = TRUE;
  5118. break;
  5119. }
  5120. m_LeftClickDownCell.col--;
  5121. }
  5122. if (!bFoundVisible)
  5123. return;
  5124. }
  5125. }
  5126. CRect rect;
  5127. GetClientRect(rect);
  5128. CRect invertedRect(point.x, rect.top, point.x + 2, rect.bottom);
  5129. CDC* pDC = GetDC();
  5130. if (pDC)
  5131. {
  5132. pDC->InvertRect(&invertedRect);
  5133. ReleaseDC(pDC);
  5134. }
  5135. // If we clicked to the right of the colimn divide, then reset the click-down cell
  5136. // as the cell to the left of the column divide - UNLESS we clicked on the last column
  5137. // and the last column is teensy (kludge fix)
  5138. if (point.x - start.x < m_nResizeCaptureRange)
  5139. {
  5140. if (m_LeftClickDownCell.col < GetColumnCount() - 1 ||
  5141. GetColumnWidth(GetColumnCount() - 1) >= m_nResizeCaptureRange)
  5142. {
  5143. if (!GetCellOrigin(0, --m_LeftClickDownCell.col, &start))
  5144. return;
  5145. }
  5146. }
  5147. // Allow a cell resize width no greater than that which can be viewed within
  5148. // the grid itself
  5149. int nMaxCellWidth = rect.Width() - GetFixedColumnWidth();
  5150. rect.left = start.x + 1;
  5151. rect.right = rect.left + nMaxCellWidth;
  5152. ClientToScreen(rect);
  5153. #ifndef _WIN32_WCE_NO_CURSOR
  5154. ClipCursor(rect);
  5155. #endif
  5156. }
  5157. else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE) // sizing row
  5158. {
  5159. m_MouseMode = MOUSE_SIZING_ROW;
  5160. // Kludge for if we are over the last column...
  5161. if (GetRowHeight(GetRowCount() - 1) < m_nResizeCaptureRange)
  5162. {
  5163. CRect VisRect;
  5164. GetVisibleNonFixedCellRange(VisRect);
  5165. if (abs(point.y - VisRect.bottom) < m_nResizeCaptureRange)
  5166. m_LeftClickDownCell.row = GetRowCount() - 1;
  5167. }
  5168. CPoint start;
  5169. if (!GetCellOrigin(m_LeftClickDownCell, &start))
  5170. return;
  5171. if (!m_bHiddenRowUnhide)
  5172. {
  5173. // ignore rows that are hidden and look up towards first visible row
  5174. BOOL bLookForVisible = TRUE;
  5175. BOOL bIsCellBottomBorder = point.y - start.y >= m_nResizeCaptureRange;
  5176. if (bIsCellBottomBorder
  5177. && m_LeftClickDownCell.row + 1 >= GetRowCount())
  5178. {
  5179. // clicked on last row's bottom border
  5180. // if last row is visible, don't do anything
  5181. if (m_LeftClickDownCell.row >= 0)
  5182. bLookForVisible = FALSE;
  5183. }
  5184. if (bLookForVisible)
  5185. {
  5186. // clicked on row divider other than last bottom border
  5187. BOOL bFoundVisible = FALSE;
  5188. int iOffset = 1;
  5189. if (bIsCellBottomBorder)
  5190. iOffset = 0;
  5191. while (m_LeftClickDownCell.row - iOffset >= 0)
  5192. {
  5193. if (GetRowHeight(m_LeftClickDownCell.row - iOffset) > 0)
  5194. {
  5195. bFoundVisible = TRUE;
  5196. break;
  5197. }
  5198. m_LeftClickDownCell.row--;
  5199. }
  5200. if (!bFoundVisible)
  5201. return;
  5202. }
  5203. }
  5204. CRect rect;
  5205. GetClientRect(rect);
  5206. CRect invertedRect(rect.left, point.y, rect.right, point.y + 2);
  5207. CDC* pDC = GetDC();
  5208. if (pDC)
  5209. {
  5210. pDC->InvertRect(&invertedRect);
  5211. ReleaseDC(pDC);
  5212. }
  5213. // If we clicked below the row divide, then reset the click-down cell
  5214. // as the cell above the row divide - UNLESS we clicked on the last row
  5215. // and the last row is teensy (kludge fix)
  5216. if (point.y - start.y < m_nResizeCaptureRange) // clicked below border
  5217. {
  5218. if (m_LeftClickDownCell.row < GetRowCount() - 1 ||
  5219. GetRowHeight(GetRowCount() - 1) >= m_nResizeCaptureRange)
  5220. {
  5221. if (!GetCellOrigin(--m_LeftClickDownCell.row, 0, &start))
  5222. return;
  5223. }
  5224. }
  5225. int nMaxCellHeight = rect.Height() - GetFixedRowHeight();
  5226. rect.top = start.y + 1;
  5227. rect.bottom = rect.top + nMaxCellHeight;
  5228. ClientToScreen(rect);
  5229. #ifndef _WIN32_WCE_NO_CURSOR
  5230. ClipCursor(rect);
  5231. #endif
  5232. }
  5233. else
  5234. #ifndef GRIDCONTROL_NO_DRAGDROP
  5235. if (m_MouseMode != MOUSE_PREPARE_DRAG) // not sizing or editing -- selecting
  5236. #endif
  5237. {
  5238. SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
  5239. // If Ctrl pressed, save the current cell selection. This will get added
  5240. // to the new cell selection at the end of the cell selection process
  5241. m_PrevSelectedCellMap.RemoveAll();
  5242. if (nFlags & MK_CONTROL)
  5243. {
  5244. for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
  5245. {
  5246. DWORD key;
  5247. CCellID cell;
  5248. m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
  5249. m_PrevSelectedCellMap.SetAt(key, cell);
  5250. }
  5251. }
  5252. if (m_LeftClickDownCell.row < GetFixedRowCount())
  5253. OnFixedRowClick(m_LeftClickDownCell);
  5254. else if (m_LeftClickDownCell.col < GetFixedColumnCount())
  5255. OnFixedColumnClick(m_LeftClickDownCell);
  5256. else
  5257. {
  5258. m_MouseMode = m_bListMode ? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
  5259. OnSelecting(m_LeftClickDownCell);
  5260. m_nTimerID = (int)SetTimer(WM_LBUTTONDOWN, (UINT)m_nTimerInterval, 0);
  5261. }
  5262. }
  5263. m_LastMousePoint = point;
  5264. }
  5265. void CGridCtrl::OnLButtonUp(UINT nFlags, CPoint point)
  5266. {
  5267. // TRACE0("CGridCtrl::OnLButtonUp\n");
  5268. CWnd::OnLButtonUp(nFlags, point);
  5269. m_bLMouseButtonDown = FALSE;
  5270. #ifndef _WIN32_WCE_NO_CURSOR
  5271. ClipCursor(NULL);
  5272. #endif
  5273. if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
  5274. {
  5275. ReleaseCapture();
  5276. KillTimer(m_nTimerID);
  5277. m_nTimerID = 0;
  5278. }
  5279. CPoint pointClickedRel;
  5280. pointClickedRel = GetPointClicked(m_idCurrentCell.row, m_idCurrentCell.col, point);
  5281. // m_MouseMode == MOUSE_PREPARE_EDIT only if user clicked down on current cell
  5282. // and then didn't move mouse before clicking up (releasing button)
  5283. if (m_MouseMode == MOUSE_PREPARE_EDIT)
  5284. {
  5285. OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, pointClickedRel, VK_LBUTTON);
  5286. }
  5287. #ifndef GRIDCONTROL_NO_DRAGDROP
  5288. // m_MouseMode == MOUSE_PREPARE_DRAG only if user clicked down on a selected cell
  5289. // and then didn't move mouse before clicking up (releasing button)
  5290. else if (m_MouseMode == MOUSE_PREPARE_DRAG)
  5291. {
  5292. CGridCellBase* pCell = GetCell(m_idCurrentCell.row, m_idCurrentCell.col);
  5293. if (pCell)
  5294. pCell->OnClick(GetPointClicked(m_idCurrentCell.row, m_idCurrentCell.col, point));
  5295. SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, NM_CLICK);
  5296. SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, GVN_SELCHANGING);
  5297. ResetSelectedRange();
  5298. SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
  5299. }
  5300. #endif
  5301. else if (m_MouseMode == MOUSE_SIZING_COL)
  5302. {
  5303. CRect rect;
  5304. GetClientRect(rect);
  5305. CRect invertedRect(m_LastMousePoint.x, rect.top, m_LastMousePoint.x + 2, rect.bottom);
  5306. CDC* pDC = GetDC();
  5307. if (pDC)
  5308. {
  5309. pDC->InvertRect(&invertedRect);
  5310. ReleaseDC(pDC);
  5311. }
  5312. if (m_LeftClickDownPoint != point && (point.x != 0 || point.y != 0)) // 0 pt fix by email1@bierling.net
  5313. {
  5314. CPoint start;
  5315. //Used for merge cells
  5316. //by Huang Wei
  5317. m_LeftClickDownCell = GetMergeCellID(m_LeftClickDownCell);
  5318. if (!GetCellOrigin(m_LeftClickDownCell, &start))
  5319. return;
  5320. int nColumnWidth = max(point.x - start.x, m_bAllowColHide ? 0 : 1);
  5321. //Used for merge cells
  5322. //by Huang Wei
  5323. int mergewidth = GetMergeCellWidth(m_LeftClickDownCell) - GetColumnWidth(m_LeftClickDownCell.col);
  5324. SetColumnWidth(m_LeftClickDownCell.col, nColumnWidth - mergewidth);
  5325. ResetScrollBars();
  5326. Invalidate();
  5327. }
  5328. }
  5329. else if (m_MouseMode == MOUSE_SIZING_ROW)
  5330. {
  5331. CRect rect;
  5332. GetClientRect(rect);
  5333. CRect invertedRect(rect.left, m_LastMousePoint.y, rect.right, m_LastMousePoint.y + 2);
  5334. CDC* pDC = GetDC();
  5335. if (pDC)
  5336. {
  5337. pDC->InvertRect(&invertedRect);
  5338. ReleaseDC(pDC);
  5339. }
  5340. if (m_LeftClickDownPoint != point && (point.x != 0 || point.y != 0)) // 0 pt fix by email1@bierling.net
  5341. {
  5342. CPoint start;
  5343. //Used for merge cells
  5344. //by Huang Wei
  5345. m_LeftClickDownCell = GetMergeCellID(m_LeftClickDownCell);
  5346. if (!GetCellOrigin(m_LeftClickDownCell, &start))
  5347. return;
  5348. int nRowHeight = max(point.y - start.y, m_bAllowRowHide ? 0 : 1);
  5349. //Used for merge cells
  5350. //by Huang Wei
  5351. int mergeheight = GetMergeCellHeight(m_LeftClickDownCell) - GetRowHeight(m_LeftClickDownCell.row);
  5352. SetRowHeight(m_LeftClickDownCell.row, nRowHeight - mergeheight);
  5353. ResetScrollBars();
  5354. Invalidate();
  5355. }
  5356. }
  5357. else
  5358. {
  5359. SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
  5360. CGridCellBase* pCell = GetCell(m_idCurrentCell.row, m_idCurrentCell.col);
  5361. if (pCell)
  5362. pCell->OnClick(GetPointClicked(m_idCurrentCell.row, m_idCurrentCell.col, point));
  5363. SendMessageToParent(m_LeftClickDownCell.row, m_LeftClickDownCell.col, NM_CLICK);
  5364. }
  5365. m_MouseMode = MOUSE_NOTHING;
  5366. #ifndef _WIN32_WCE_NO_CURSOR
  5367. SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
  5368. #endif
  5369. if (!IsValid(m_LeftClickDownCell))
  5370. return;
  5371. CWnd *pOwner = GetOwner();
  5372. if (pOwner && IsWindow(pOwner->m_hWnd))
  5373. pOwner->PostMessage(WM_COMMAND, MAKELONG(GetDlgCtrlID(), BN_CLICKED),
  5374. (LPARAM)GetSafeHwnd());
  5375. }
  5376. #ifndef _WIN32_WCE
  5377. void CGridCtrl::OnRButtonDown(UINT nFlags, CPoint point)
  5378. {
  5379. CWnd::OnRButtonDown(nFlags, point);
  5380. m_bRMouseButtonDown = TRUE;
  5381. #ifdef GRIDCONTROL_USE_TITLETIPS
  5382. TRACE0("Hiding TitleTip\n");
  5383. m_TitleTip.Hide(); // hide any titletips
  5384. #endif
  5385. }
  5386. // EFW - Added to forward right click to parent so that a context
  5387. // menu can be shown without deriving a new grid class.
  5388. void CGridCtrl::OnRButtonUp(UINT nFlags, CPoint point)
  5389. {
  5390. CWnd::OnRButtonUp(nFlags, point);
  5391. m_bRMouseButtonDown = FALSE;
  5392. CCellID FocusCell;
  5393. FocusCell = GetCellFromPt(point);
  5394. EndEditing(); // Auto-destroy any InPlaceEdit's
  5395. // If not a valid cell, pass -1 for row and column
  5396. if (!IsValid(FocusCell))
  5397. SendMessageToParent(-1, -1, NM_RCLICK);
  5398. else
  5399. {
  5400. SetFocusCell(-1, -1);
  5401. SetFocusCell(max(FocusCell.row, m_nFixedRows),
  5402. max(FocusCell.col, m_nFixedCols));
  5403. // tell the cell about it
  5404. CGridCellBase* pCell = GetCell(FocusCell.row, FocusCell.col);
  5405. if (pCell)
  5406. pCell->OnRClick(GetPointClicked(FocusCell.row, FocusCell.col, point));
  5407. SendMessageToParent(FocusCell.row, FocusCell.col, NM_RCLICK);
  5408. }
  5409. }
  5410. #endif
  5411. #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  5412. /////////////////////////////////////////////////////////////////////////////
  5413. // CGridCtrl printing
  5414. // EFW - New print margin support functions
  5415. void CGridCtrl::SetPrintMarginInfo(int nHeaderHeight, int nFooterHeight,
  5416. int nLeftMargin, int nRightMargin, int nTopMargin,
  5417. int nBottomMargin, int nGap)
  5418. {
  5419. // If any parameter is -1, keep the existing setting
  5420. if (nHeaderHeight > -1)
  5421. m_nHeaderHeight = nHeaderHeight;
  5422. if (nFooterHeight > -1)
  5423. m_nFooterHeight = nFooterHeight;
  5424. if (nLeftMargin > -1)
  5425. m_nLeftMargin = nLeftMargin;
  5426. if (nRightMargin > -1)
  5427. m_nRightMargin = nRightMargin;
  5428. if (nTopMargin > -1)
  5429. m_nTopMargin = nTopMargin;
  5430. if (nBottomMargin > -1)
  5431. m_nBottomMargin = nBottomMargin;
  5432. if (nGap > -1)
  5433. m_nGap = nGap;
  5434. }
  5435. void CGridCtrl::GetPrintMarginInfo(int &nHeaderHeight, int &nFooterHeight,
  5436. int &nLeftMargin, int &nRightMargin, int &nTopMargin,
  5437. int &nBottomMargin, int &nGap)
  5438. {
  5439. nHeaderHeight = m_nHeaderHeight;
  5440. nFooterHeight = m_nFooterHeight;
  5441. nLeftMargin = m_nLeftMargin;
  5442. nRightMargin = m_nRightMargin;
  5443. nTopMargin = m_nTopMargin;
  5444. nBottomMargin = m_nBottomMargin;
  5445. nGap = m_nGap;
  5446. }
  5447. void CGridCtrl::Print(CPrintDialog* pPrntDialog /*=NULL*/)
  5448. {
  5449. CDC dc;
  5450. if (pPrntDialog == NULL)
  5451. {
  5452. CPrintDialog printDlg(FALSE);
  5453. if (printDlg.DoModal() != IDOK) // Get printer settings from user
  5454. return;
  5455. dc.Attach(printDlg.GetPrinterDC()); // attach a printer DC
  5456. }
  5457. else
  5458. dc.Attach(pPrntDialog->GetPrinterDC()); // attach a printer DC
  5459. dc.m_bPrinting = TRUE;
  5460. CString strTitle;
  5461. strTitle.LoadString(AFX_IDS_APP_TITLE);
  5462. if (strTitle.IsEmpty())
  5463. {
  5464. CWnd *pParentWnd = GetParent();
  5465. while (pParentWnd)
  5466. {
  5467. pParentWnd->GetWindowText(strTitle);
  5468. if (strTitle.GetLength()) // can happen if it is a CView, CChildFrm has the title
  5469. break;
  5470. pParentWnd = pParentWnd->GetParent();
  5471. }
  5472. }
  5473. DOCINFO di; // Initialise print doc details
  5474. memset(&di, 0, sizeof(DOCINFO));
  5475. di.cbSize = sizeof(DOCINFO);
  5476. di.lpszDocName = strTitle;
  5477. BOOL bPrintingOK = dc.StartDoc(&di); // Begin a new print job
  5478. CPrintInfo Info;
  5479. Info.m_rectDraw.SetRect(0, 0, dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES));
  5480. OnBeginPrinting(&dc, &Info); // Initialise printing
  5481. for (UINT page = Info.GetMinPage(); page <= Info.GetMaxPage() && bPrintingOK; page++)
  5482. {
  5483. dc.StartPage(); // begin new page
  5484. Info.m_nCurPage = page;
  5485. OnPrint(&dc, &Info); // Print page
  5486. bPrintingOK = (dc.EndPage() > 0); // end page
  5487. }
  5488. OnEndPrinting(&dc, &Info); // Clean up after printing
  5489. if (bPrintingOK)
  5490. dc.EndDoc(); // end a print job
  5491. else
  5492. dc.AbortDoc(); // abort job.
  5493. dc.Detach(); // detach the printer DC
  5494. }
  5495. /////////////////////////////////////////////////////////////////////////////
  5496. // CGridCtrl printing overridables - for Doc/View print/print preview framework
  5497. // EFW - Various changes in the next few functions to support the
  5498. // new print margins and a few other adjustments.
  5499. void CGridCtrl::OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo)
  5500. {
  5501. // OnBeginPrinting() is called after the user has committed to
  5502. // printing by OK'ing the Print dialog, and after the framework
  5503. // has created a CDC object for the printer or the preview view.
  5504. // This is the right opportunity to set up the page range.
  5505. // Given the CDC object, we can determine how many rows will
  5506. // fit on a page, so we can in turn determine how many printed
  5507. // pages represent the entire document.
  5508. ASSERT(pDC && pInfo);
  5509. if (!pDC || !pInfo) return;
  5510. // Get a DC for the current window (will be a screen DC for print previewing)
  5511. CDC *pCurrentDC = GetDC(); // will have dimensions of the client area
  5512. if (!pCurrentDC) return;
  5513. CSize PaperPixelsPerInch(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
  5514. CSize ScreenPixelsPerInch(pCurrentDC->GetDeviceCaps(LOGPIXELSX), pCurrentDC->GetDeviceCaps(LOGPIXELSY));
  5515. // Create the printer font
  5516. int nFontSize = -10;
  5517. CString strFontName = "Arial";
  5518. m_PrinterFont.CreateFont(nFontSize, 0, 0, 0, FW_NORMAL, 0, 0, 0, DEFAULT_CHARSET,
  5519. OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,
  5520. DEFAULT_PITCH | FF_DONTCARE, strFontName);
  5521. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  5522. // Get the average character width (in GridCtrl units) and hence the margins
  5523. m_CharSize = pDC->GetTextExtent(_T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSATUVWXYZ"), 52);
  5524. m_CharSize.cx /= 52;
  5525. int nMargins = (m_nLeftMargin + m_nRightMargin)*m_CharSize.cx;
  5526. // Get the page sizes (physical and logical)
  5527. m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
  5528. if (m_bWysiwygPrinting)
  5529. {
  5530. m_LogicalPageSize.cx = ScreenPixelsPerInch.cx * m_PaperSize.cx / PaperPixelsPerInch.cx * 3 / 4;
  5531. m_LogicalPageSize.cy = ScreenPixelsPerInch.cy * m_PaperSize.cy / PaperPixelsPerInch.cy * 3 / 4;
  5532. }
  5533. else
  5534. {
  5535. m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
  5536. m_LogicalPageSize.cx = GetVirtualWidth() + nMargins;
  5537. #ifdef _WIN32_WCE
  5538. m_LogicalPageSize.cy = (m_LogicalPageSize.cx * m_PaperSize.cy) / m_PaperSize.cx;
  5539. #else
  5540. m_LogicalPageSize.cy = MulDiv(m_LogicalPageSize.cx, m_PaperSize.cy, m_PaperSize.cx);
  5541. #endif
  5542. }
  5543. m_nPageHeight = m_LogicalPageSize.cy - GetFixedRowHeight()
  5544. - (m_nHeaderHeight + m_nFooterHeight + 2 * m_nGap)*m_CharSize.cy;
  5545. // Get the number of pages. Assumes no row is bigger than the page size.
  5546. int nTotalRowHeight = 0;
  5547. m_nNumPages = 1;
  5548. for (int row = GetFixedRowCount(); row < GetRowCount(); row++)
  5549. {
  5550. nTotalRowHeight += GetRowHeight(row);
  5551. if (nTotalRowHeight > m_nPageHeight) {
  5552. m_nNumPages++;
  5553. nTotalRowHeight = GetRowHeight(row);
  5554. }
  5555. }
  5556. // now, figure out how many additional pages must print out if rows ARE bigger
  5557. // than page size
  5558. int iColumnOffset = 0;
  5559. int i1;
  5560. for (i1 = 0; i1 < GetFixedColumnCount(); i1++)
  5561. {
  5562. iColumnOffset += GetColumnWidth(i1);
  5563. }
  5564. m_nPageWidth = m_LogicalPageSize.cx - iColumnOffset
  5565. - nMargins;
  5566. m_nPageMultiplier = 1;
  5567. if (m_bWysiwygPrinting)
  5568. {
  5569. int iTotalRowWidth = 0;
  5570. for (i1 = GetFixedColumnCount(); i1 < GetColumnCount(); i1++)
  5571. {
  5572. iTotalRowWidth += GetColumnWidth(i1);
  5573. if (iTotalRowWidth > m_nPageWidth)
  5574. {
  5575. m_nPageMultiplier++;
  5576. iTotalRowWidth = GetColumnWidth(i1);
  5577. }
  5578. }
  5579. m_nNumPages *= m_nPageMultiplier;
  5580. }
  5581. // Set up the print info
  5582. pInfo->SetMaxPage(m_nNumPages);
  5583. pInfo->m_nCurPage = 1; // start printing at page# 1
  5584. ReleaseDC(pCurrentDC);
  5585. pDC->SelectObject(pOldFont);
  5586. }
  5587. void CGridCtrl::OnPrint(CDC *pDC, CPrintInfo *pInfo)
  5588. {
  5589. if (!pDC || !pInfo)
  5590. return;
  5591. //CRect rcPage(pInfo->m_rectDraw);
  5592. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  5593. // Set the page map mode to use GridCtrl units, and setup margin
  5594. pDC->SetMapMode(MM_ANISOTROPIC);
  5595. pDC->SetWindowExt(m_LogicalPageSize);
  5596. pDC->SetViewportExt(m_PaperSize);
  5597. pDC->SetWindowOrg(-m_nLeftMargin * m_CharSize.cx, 0);
  5598. // Header
  5599. pInfo->m_rectDraw.top = 0;
  5600. pInfo->m_rectDraw.left = 0;
  5601. pInfo->m_rectDraw.right = m_LogicalPageSize.cx - (m_nLeftMargin + m_nRightMargin) * m_CharSize.cx;
  5602. pInfo->m_rectDraw.bottom = m_nHeaderHeight * m_CharSize.cy;
  5603. PrintHeader(pDC, pInfo);
  5604. pDC->OffsetWindowOrg(0, -m_nHeaderHeight * m_CharSize.cy);
  5605. // Gap between header and column headings
  5606. pDC->OffsetWindowOrg(0, -m_nGap * m_CharSize.cy);
  5607. pDC->OffsetWindowOrg(0, -GetFixedRowHeight());
  5608. // We need to find out which row to start printing for this page.
  5609. int nTotalRowHeight = 0;
  5610. UINT nNumPages = 1;
  5611. m_nCurrPrintRow = GetFixedRowCount();
  5612. // Not only the row, but we need to figure out column, too
  5613. // Can print 4 pages, where page 1 and 2 represent the same rows but
  5614. // with different WIDE columns.
  5615. //
  5616. // .......
  5617. // .1 .2 . If representing page 3 --> iPageIfIgnoredWideCols = 2
  5618. // ....... iWideColPageOffset = 0
  5619. // .3 .4 . If representing page 2 --> iPageIfIgnoredWideCols = 1
  5620. // ....... iWideColPageOffset = 1
  5621. int iPageIfIgnoredWideCols = pInfo->m_nCurPage / m_nPageMultiplier;
  5622. int iWideColPageOffset = pInfo->m_nCurPage - (iPageIfIgnoredWideCols * m_nPageMultiplier);
  5623. if (iWideColPageOffset > 0)
  5624. iPageIfIgnoredWideCols++;
  5625. if (iWideColPageOffset == 0)
  5626. iWideColPageOffset = m_nPageMultiplier;
  5627. iWideColPageOffset--;
  5628. // calculate current print row based on iPageIfIgnoredWideCols
  5629. while (m_nCurrPrintRow < GetRowCount()
  5630. && (int)nNumPages < iPageIfIgnoredWideCols)
  5631. {
  5632. nTotalRowHeight += GetRowHeight(m_nCurrPrintRow);
  5633. if (nTotalRowHeight > m_nPageHeight) {
  5634. nNumPages++;
  5635. if ((int)nNumPages == iPageIfIgnoredWideCols) break;
  5636. nTotalRowHeight = GetRowHeight(m_nCurrPrintRow);
  5637. }
  5638. m_nCurrPrintRow++;
  5639. }
  5640. m_nPrintColumn = GetFixedColumnCount();
  5641. int iTotalRowWidth = 0;
  5642. int i1, i2;
  5643. // now, calculate which print column to start displaying
  5644. for (i1 = 0; i1 < iWideColPageOffset; i1++)
  5645. {
  5646. for (i2 = m_nPrintColumn; i2 < GetColumnCount(); i2++)
  5647. {
  5648. iTotalRowWidth += GetColumnWidth(i2);
  5649. if (iTotalRowWidth > m_nPageWidth)
  5650. {
  5651. m_nPrintColumn = i2;
  5652. iTotalRowWidth = 0;
  5653. break;
  5654. }
  5655. }
  5656. }
  5657. PrintRowButtons(pDC, pInfo); // print row buttons on each page
  5658. int iColumnOffset = 0;
  5659. for (i1 = 0; i1 < GetFixedColumnCount(); i1++)
  5660. {
  5661. iColumnOffset += GetColumnWidth(i1);
  5662. }
  5663. // Print the column headings
  5664. pInfo->m_rectDraw.bottom = GetFixedRowHeight();
  5665. if (m_nPrintColumn == GetFixedColumnCount())
  5666. {
  5667. // have the column headings fcn draw the upper left fixed cells
  5668. // for the very first columns, only
  5669. pDC->OffsetWindowOrg(0, +GetFixedRowHeight());
  5670. m_nPageWidth += iColumnOffset;
  5671. m_nPrintColumn = 0;
  5672. PrintColumnHeadings(pDC, pInfo);
  5673. m_nPageWidth -= iColumnOffset;
  5674. m_nPrintColumn = GetFixedColumnCount();
  5675. pDC->OffsetWindowOrg(-iColumnOffset, -GetFixedRowHeight());
  5676. }
  5677. else
  5678. {
  5679. // changed all of this here to match above almost exactly same
  5680. pDC->OffsetWindowOrg(0, +GetFixedRowHeight());
  5681. m_nPageWidth += iColumnOffset;
  5682. // print from column 0 ... last column that fits on the current page
  5683. PrintColumnHeadings(pDC, pInfo);
  5684. m_nPageWidth -= iColumnOffset;
  5685. pDC->OffsetWindowOrg(-iColumnOffset, -GetFixedRowHeight());
  5686. }
  5687. if (m_nCurrPrintRow >= GetRowCount()) return;
  5688. // Draw as many rows as will fit on the printed page.
  5689. // Clip the printed page so that there is no partially shown
  5690. // row at the bottom of the page (the same row which will be fully
  5691. // shown at the top of the next page).
  5692. BOOL bFirstPrintedRow = TRUE;
  5693. CRect rect;
  5694. rect.bottom = -1;
  5695. //Used for merge cells
  5696. //by Huang Wei
  5697. int Row = m_nCurrPrintRow;
  5698. CRect range;
  5699. range.bottom = -1;
  5700. while (Row < GetRowCount())
  5701. {
  5702. range.top = range.bottom + 1;
  5703. range.bottom = range.top + GetRowHeight(Row) - 1;
  5704. if (range.bottom > m_nPageHeight)
  5705. {
  5706. range.bottom = range.top;
  5707. break;
  5708. }
  5709. Row++;
  5710. }
  5711. while (m_nCurrPrintRow < GetRowCount())
  5712. {
  5713. rect.top = rect.bottom + 1;
  5714. rect.bottom = rect.top + GetRowHeight(m_nCurrPrintRow) - 1;
  5715. if (rect.bottom > m_nPageHeight) break; // Gone past end of page
  5716. rect.right = -1;
  5717. // modified to allow printing of wide grids on multiple pages
  5718. for (int col = m_nPrintColumn; col < GetColumnCount(); col++)
  5719. {
  5720. rect.left = rect.right + 1;
  5721. rect.right = rect.left
  5722. + GetColumnWidth(col)
  5723. - 1;
  5724. if (rect.right > m_nPageWidth)
  5725. break;
  5726. CGridCellBase* pCell = GetCell(m_nCurrPrintRow, col);
  5727. if (pCell)
  5728. {
  5729. //Used for merge cells
  5730. //by Huang Wei
  5731. int row = m_nCurrPrintRow;
  5732. if (!pCell->IsMerged())
  5733. {
  5734. if (!pCell->IsMergeWithOthers())
  5735. {
  5736. pCell->PrintCell(pDC, row, col, rect);
  5737. }
  5738. }
  5739. else
  5740. {
  5741. CRect mergerect = rect;
  5742. if (GetCellRangeRect(pCell->m_MergeRange, &mergerect))
  5743. {
  5744. //mergerect.DeflateRect(0,0,1,1);
  5745. mergerect.OffsetRect(rect.TopLeft() - mergerect.TopLeft());
  5746. pCell->PrintCell(pDC, row, col, mergerect);
  5747. }
  5748. }
  5749. }
  5750. //if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  5751. //{
  5752. // int Overlap = (col == 0)? 0:1;
  5753. // pDC->MoveTo(rect.left-Overlap, rect.bottom);
  5754. // pDC->LineTo(rect.right, rect.bottom);
  5755. // if (m_nCurrPrintRow == 0) {
  5756. // pDC->MoveTo(rect.left-Overlap, rect.top);
  5757. // pDC->LineTo(rect.right, rect.top);
  5758. // }
  5759. //}
  5760. //if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  5761. //{
  5762. // int Overlap = (bFirstPrintedRow)? 0:1;
  5763. // pDC->MoveTo(rect.right, rect.top-Overlap);
  5764. // pDC->LineTo(rect.right, rect.bottom);
  5765. // if (col == 0) {
  5766. // pDC->MoveTo(rect.left, rect.top-Overlap);
  5767. // pDC->LineTo(rect.left, rect.bottom);
  5768. // }
  5769. //}
  5770. }
  5771. m_nCurrPrintRow++;
  5772. bFirstPrintedRow = FALSE;
  5773. }
  5774. //Used for merge cells
  5775. //by Huang Wei
  5776. CRect white_rect(CPoint(0, 0), m_LogicalPageSize);
  5777. white_rect.top = range.bottom + 1;
  5778. pDC->FillSolidRect(white_rect, RGB(255, 255, 255));
  5779. // Footer
  5780. pInfo->m_rectDraw.bottom = m_nFooterHeight * m_CharSize.cy;
  5781. pDC->SetWindowOrg(-m_nLeftMargin * m_CharSize.cx,
  5782. -m_LogicalPageSize.cy + m_nFooterHeight * m_CharSize.cy);
  5783. PrintFooter(pDC, pInfo);
  5784. // SetWindowOrg back for next page
  5785. pDC->SetWindowOrg(0, 0);
  5786. pDC->SelectObject(pOldFont);
  5787. }
  5788. // added by M.Fletcher 12/17/00
  5789. void CGridCtrl::PrintFixedRowCells(int nStartColumn, int nStopColumn, int& row, CRect& rect,
  5790. CDC *pDC, BOOL& bFirst)
  5791. {
  5792. // print all cells from nStartColumn to nStopColumn on row
  5793. for (int col = nStartColumn; col < nStopColumn; col++)
  5794. {
  5795. rect.left = rect.right + 1;
  5796. rect.right = rect.left + GetColumnWidth(col) - 1;
  5797. if (rect.right > m_nPageWidth)
  5798. break;
  5799. CGridCellBase* pCell = GetCell(row, col);
  5800. if (pCell)
  5801. {
  5802. //Used for merge cells
  5803. //by Huang Wei
  5804. int row = m_nCurrPrintRow;
  5805. if (!pCell->IsMerged())
  5806. {
  5807. if (!pCell->IsMergeWithOthers())
  5808. {
  5809. pCell->PrintCell(pDC, row, col, rect);
  5810. }
  5811. }
  5812. else
  5813. {
  5814. CRect mergerect = rect;
  5815. if (GetCellRangeRect(pCell->m_MergeRange, &mergerect))
  5816. {
  5817. //mergerect.DeflateRect(0,0,1,1);
  5818. mergerect.OffsetRect(rect.TopLeft() - mergerect.TopLeft());
  5819. pCell->PrintCell(pDC, row, col, mergerect);
  5820. }
  5821. }
  5822. }
  5823. //if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  5824. //{
  5825. // int Overlap = (col == 0)? 0:1;
  5826. //
  5827. // pDC->MoveTo(rect.left-Overlap, rect.bottom);
  5828. // pDC->LineTo(rect.right, rect.bottom);
  5829. //
  5830. // if (row == 0)
  5831. // {
  5832. // pDC->MoveTo(rect.left-Overlap, rect.top);
  5833. // pDC->LineTo(rect.right, rect.top);
  5834. // }
  5835. //}
  5836. //if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  5837. //{
  5838. // int Overlap = (row == 0)? 0:1;
  5839. // pDC->MoveTo(rect.right, rect.top-Overlap);
  5840. // pDC->LineTo(rect.right, rect.bottom);
  5841. //
  5842. // if( bFirst)
  5843. // {
  5844. // pDC->MoveTo(rect.left-1, rect.top-Overlap);
  5845. // pDC->LineTo(rect.left-1, rect.bottom);
  5846. // bFirst = FALSE;
  5847. // }
  5848. // }
  5849. } // end of column cells loop
  5850. } // end of CGridCtrl::PrintFixedRowCells
  5851. void CGridCtrl::PrintColumnHeadings(CDC *pDC, CPrintInfo* /*pInfo*/)
  5852. {
  5853. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  5854. CRect rect;
  5855. rect.bottom = -1;
  5856. BOOL bFirst = TRUE;
  5857. BOOL bOriginal;
  5858. // modified to allow column hdr printing of multi-page wide grids
  5859. for (int row = 0; row < GetFixedRowCount(); row++)
  5860. {
  5861. rect.top = rect.bottom + 1;
  5862. rect.bottom = rect.top + GetRowHeight(row) - 1;
  5863. rect.right = -1;
  5864. // if printColumn > fixedcolumncount we are on page 2 or more
  5865. // lets printout those fixed cell headings again the 1 or more that would be missed
  5866. // added by M.Fletcher 12/17/00
  5867. if (m_nPrintColumn >= GetFixedColumnCount())
  5868. {
  5869. bOriginal = bFirst;
  5870. // lets print the missing fixed cells on left first out to last fixed column
  5871. PrintFixedRowCells(0, GetFixedColumnCount(), row, rect, pDC, bFirst);
  5872. bFirst = bOriginal;
  5873. }
  5874. // now back to normal business print cells in heading after all fixed columns
  5875. PrintFixedRowCells(m_nPrintColumn, GetColumnCount(), row, rect, pDC, bFirst);
  5876. } // end of Row Loop
  5877. pDC->SelectObject(pOldFont);
  5878. } // end of CGridCtrl::PrintColumnHeadings
  5879. /*****************************************************************************
  5880. Prints line of row buttons on each page of the printout. Assumes that
  5881. the window origin is setup before calling
  5882. *****************************************************************************/
  5883. void CGridCtrl::PrintRowButtons(CDC *pDC, CPrintInfo* /*pInfo*/)
  5884. {
  5885. CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
  5886. CRect rect;
  5887. rect.right = -1;
  5888. BOOL bFirst = TRUE;
  5889. for (int iCol = 0; iCol < GetFixedColumnCount(); iCol++)
  5890. {
  5891. rect.left = rect.right + 1;
  5892. rect.right = rect.left
  5893. + GetColumnWidth(iCol)
  5894. - 1;
  5895. rect.bottom = -1;
  5896. for (int iRow = m_nCurrPrintRow; iRow < GetRowCount(); iRow++)
  5897. {
  5898. rect.top = rect.bottom + 1;
  5899. rect.bottom = rect.top + GetRowHeight(iRow) - 1;
  5900. if (rect.bottom > m_nPageHeight)
  5901. break;
  5902. CGridCellBase* pCell = GetCell(iRow, iCol);
  5903. if (pCell)
  5904. pCell->PrintCell(pDC, iRow, iCol, rect);
  5905. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
  5906. {
  5907. int Overlap = (iCol == 0) ? 0 : 1;
  5908. pDC->MoveTo(rect.left - Overlap, rect.bottom);
  5909. pDC->LineTo(rect.right, rect.bottom);
  5910. if (bFirst) {
  5911. pDC->MoveTo(rect.left - Overlap, rect.top - 1);
  5912. pDC->LineTo(rect.right, rect.top - 1);
  5913. bFirst = FALSE;
  5914. }
  5915. }
  5916. if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
  5917. {
  5918. int Overlap = (iRow == 0) ? 0 : 1;
  5919. pDC->MoveTo(rect.right, rect.top - Overlap);
  5920. pDC->LineTo(rect.right, rect.bottom);
  5921. if (iCol == 0) {
  5922. pDC->MoveTo(rect.left, rect.top - Overlap);
  5923. pDC->LineTo(rect.left, rect.bottom);
  5924. }
  5925. }
  5926. }
  5927. }
  5928. pDC->SelectObject(pOldFont);
  5929. }
  5930. void CGridCtrl::PrintHeader(CDC *pDC, CPrintInfo *pInfo)
  5931. {
  5932. // print App title on top right margin
  5933. CString strRight;
  5934. strRight.LoadString(AFX_IDS_APP_TITLE);
  5935. // print parent window title in the centre (Gert Rijs)
  5936. CString strCenter;
  5937. CWnd *pParentWnd = GetParent();
  5938. while (pParentWnd)
  5939. {
  5940. pParentWnd->GetWindowText(strCenter);
  5941. if (strCenter.GetLength()) // can happen if it is a CView, CChildFrm has the title
  5942. break;
  5943. pParentWnd = pParentWnd->GetParent();
  5944. }
  5945. CFont BoldFont;
  5946. LOGFONT lf;
  5947. //create bold font for header and footer
  5948. VERIFY(m_PrinterFont.GetLogFont(&lf));
  5949. lf.lfWeight = FW_BOLD;
  5950. VERIFY(BoldFont.CreateFontIndirect(&lf));
  5951. CFont *pNormalFont = pDC->SelectObject(&BoldFont);
  5952. int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
  5953. CRect rc(pInfo->m_rectDraw);
  5954. if (!strCenter.IsEmpty())
  5955. pDC->DrawText(strCenter, &rc, DT_CENTER | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  5956. if (!strRight.IsEmpty())
  5957. pDC->DrawText(strRight, &rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  5958. pDC->SetBkMode(nPrevBkMode);
  5959. pDC->SelectObject(pNormalFont);
  5960. BoldFont.DeleteObject();
  5961. // draw ruled-line across top
  5962. pDC->SelectStockObject(BLACK_PEN);
  5963. pDC->MoveTo(rc.left, rc.bottom);
  5964. pDC->LineTo(rc.right, rc.bottom);
  5965. }
  5966. //print footer with a line and date, and page number
  5967. void CGridCtrl::PrintFooter(CDC *pDC, CPrintInfo *pInfo)
  5968. {
  5969. // page numbering on left
  5970. CString strLeft;
  5971. strLeft.Format(_T("Page %d of %d"), pInfo->m_nCurPage, pInfo->GetMaxPage());
  5972. // date and time on the right
  5973. CString strRight;
  5974. COleDateTime t = COleDateTime::GetCurrentTime();
  5975. strRight = t.Format(_T("%c"));
  5976. CRect rc(pInfo->m_rectDraw);
  5977. // draw ruled line on bottom
  5978. pDC->SelectStockObject(BLACK_PEN);
  5979. pDC->MoveTo(rc.left, rc.top);
  5980. pDC->LineTo(rc.right, rc.top);
  5981. CFont BoldFont;
  5982. LOGFONT lf;
  5983. //create bold font for header and footer
  5984. m_PrinterFont.GetLogFont(&lf);
  5985. lf.lfWeight = FW_BOLD;
  5986. BoldFont.CreateFontIndirect(&lf);
  5987. CFont *pNormalFont = pDC->SelectObject(&BoldFont);
  5988. int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
  5989. // EFW - Bug fix - Force text color to black. It doesn't always
  5990. // get set to a printable color when it gets here.
  5991. pDC->SetTextColor(RGB(0, 0, 0));
  5992. if (!strLeft.IsEmpty())
  5993. pDC->DrawText(strLeft, &rc, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  5994. if (!strRight.IsEmpty())
  5995. pDC->DrawText(strRight, &rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
  5996. pDC->SetBkMode(nPrevBkMode);
  5997. pDC->SelectObject(pNormalFont);
  5998. BoldFont.DeleteObject();
  5999. }
  6000. void CGridCtrl::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
  6001. {
  6002. m_PrinterFont.DeleteObject();
  6003. }
  6004. #endif // !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
  6005. #ifndef _WIN32_WCE
  6006. /////////////////////////////////////////////////////////////////////////////
  6007. // CGridCtrl persistance
  6008. BOOL CGridCtrl::Save(LPCTSTR filename, TCHAR chSeparator/*=_T(',')*/)
  6009. {
  6010. CStdioFile File;
  6011. CFileException ex;
  6012. CString strSeparator(chSeparator);
  6013. if (!File.Open(filename, CFile::modeWrite | CFile::modeCreate | CFile::typeText, &ex))
  6014. {
  6015. ex.ReportError();
  6016. return FALSE;
  6017. }
  6018. TRY
  6019. {
  6020. int nNumColumns = GetColumnCount();
  6021. for (int i = 0; i < GetRowCount(); i++)
  6022. {
  6023. for (int j = 0; j < nNumColumns; j++)
  6024. {
  6025. File.WriteString(GetItemText(i,j));
  6026. File.WriteString((j == (nNumColumns - 1)) ? _T("\n") : strSeparator);
  6027. }
  6028. }
  6029. File.Close();
  6030. }
  6031. CATCH(CFileException, e)
  6032. {
  6033. AfxMessageBox(_T("Unable to save grid list"));
  6034. return FALSE;
  6035. }
  6036. END_CATCH
  6037. return TRUE;
  6038. }
  6039. BOOL CGridCtrl::Load(LPCTSTR filename, TCHAR chSeparator/*=_T(',')*/)
  6040. {
  6041. if (GetVirtualMode())
  6042. return FALSE;
  6043. TCHAR *token, *end;
  6044. TCHAR buffer[1024];
  6045. CStdioFile File;
  6046. CFileException ex;
  6047. if (!File.Open(filename, CFile::modeRead | CFile::typeText))
  6048. {
  6049. ex.ReportError();
  6050. return FALSE;
  6051. }
  6052. DeleteAllItems();
  6053. TRY
  6054. {
  6055. // Read Header off file
  6056. File.ReadString(buffer, 1024);
  6057. // Get first token
  6058. for (token = buffer, end = buffer;
  6059. *end && (*end != chSeparator) && (*end != _T('\n'));
  6060. end++)
  6061. ;
  6062. if ((*end == _T('\0')) && (token == end))
  6063. token = NULL;
  6064. *end = _T('\0');
  6065. while (token)
  6066. {
  6067. InsertColumn(token);
  6068. // Get next token
  6069. for (token = ++end; *end && (*end != chSeparator) && (*end != _T('\n'));
  6070. end++)
  6071. ;
  6072. if ((*end == _T('\0')) && (token == end))
  6073. token = NULL;
  6074. *end = _T('\0');
  6075. }
  6076. // Read in rest of data
  6077. int nItem = 0;
  6078. while (File.ReadString(buffer, 1024))
  6079. {
  6080. // Get first token
  6081. for (token = buffer, end = buffer;
  6082. *end && (*end != chSeparator) && (*end != _T('\n')); end++)
  6083. ;
  6084. if ((*end == _T('\0')) && (token == end))
  6085. token = NULL;
  6086. *end = _T('\0');
  6087. int nSubItem = 0;
  6088. while (token)
  6089. {
  6090. if (!nSubItem)
  6091. InsertRow(token);
  6092. else
  6093. SetItemText(nItem, nSubItem, token);
  6094. // Get next token
  6095. for (token = ++end; *end && (*end != chSeparator) && (*end != _T('\n'));
  6096. end++)
  6097. ;
  6098. if ((*end == _T('\0')) && (token == end))
  6099. token = NULL;
  6100. *end = _T('\0');
  6101. nSubItem++;
  6102. }
  6103. nItem++;
  6104. }
  6105. AutoSizeColumns(GetAutoSizeStyle());
  6106. File.Close();
  6107. }
  6108. CATCH(CFileException, e)
  6109. {
  6110. AfxMessageBox(_T("Unable to load grid data"));
  6111. return FALSE;
  6112. }
  6113. END_CATCH
  6114. return TRUE;
  6115. }
  6116. #endif
  6117. /////////////////////////////////////////////////////////////////////////////
  6118. // CGridCtrl overrideables
  6119. #ifndef GRIDCONTROL_NO_DRAGDROP
  6120. // This is no longer needed since I've changed to OLE drag and drop - but it's
  6121. // still cool code. :)
  6122. CImageList* CGridCtrl::CreateDragImage(CPoint *pHotSpot)
  6123. {
  6124. CDC* pDC = GetDC();
  6125. if (!pDC)
  6126. return NULL;
  6127. CRect rect;
  6128. CCellID cell = GetFocusCell();
  6129. if (!GetCellRect(cell.row, cell.col, rect))
  6130. return NULL;
  6131. // Translate coordinate system
  6132. rect.BottomRight() = CPoint(rect.Width(), rect.Height());
  6133. rect.TopLeft() = CPoint(0, 0);
  6134. *pHotSpot = rect.BottomRight();
  6135. // Create a new imagelist (the caller of this function has responsibility
  6136. // for deleting this list)
  6137. CImageList* pList = new CImageList;
  6138. if (!pList || !pList->Create(rect.Width(), rect.Height(), ILC_MASK, 1, 1))
  6139. {
  6140. if (pList)
  6141. delete pList;
  6142. return NULL;
  6143. }
  6144. // Create mem DC and bitmap
  6145. CDC MemDC;
  6146. CBitmap bm;
  6147. MemDC.CreateCompatibleDC(pDC);
  6148. bm.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
  6149. CBitmap* pOldBitmap = MemDC.SelectObject(&bm);
  6150. MemDC.SetWindowOrg(0, 0);
  6151. // Draw cell onto bitmap in memDC
  6152. CGridCellBase* pCell = GetCell(cell.row, cell.col);
  6153. if (pCell)
  6154. pCell->Draw(&MemDC, cell.row, cell.col, rect, FALSE);
  6155. // Clean up
  6156. MemDC.SelectObject(pOldBitmap);
  6157. ReleaseDC(pDC);
  6158. // Add the bitmap we just drew to the image list.
  6159. pList->Add(&bm, GetDefaultCell(FALSE, FALSE)->GetBackClr());
  6160. bm.DeleteObject();
  6161. return pList;
  6162. }
  6163. #endif
  6164. void CGridCtrl::OnFixedRowClick(CCellID& cell)
  6165. {
  6166. if (!IsValid(cell))
  6167. return;
  6168. if (GetHeaderSort())
  6169. {
  6170. CWaitCursor waiter;
  6171. if (cell.col == GetSortColumn())
  6172. SortItems(cell.col, !GetSortAscending());
  6173. else
  6174. SortItems(cell.col, TRUE);
  6175. Invalidate();
  6176. }
  6177. // Did the user click on a fixed column cell (so the cell was within the overlap of
  6178. // fixed row and column cells) - (fix by David Pritchard)
  6179. if (GetFixedColumnSelection())
  6180. {
  6181. if (cell.col < GetFixedColumnCount())
  6182. {
  6183. m_MouseMode = MOUSE_SELECT_ALL;
  6184. OnSelecting(cell);
  6185. }
  6186. else
  6187. {
  6188. m_MouseMode = MOUSE_SELECT_COL;
  6189. OnSelecting(cell);
  6190. }
  6191. }
  6192. }
  6193. void CGridCtrl::OnFixedColumnClick(CCellID& cell)
  6194. {
  6195. if (!IsValid(cell))
  6196. return;
  6197. // if (m_bListMode && (GetItemState(cell.row, m_nFixedCols) & GVNI_SELECTED))
  6198. // {
  6199. // OnEditCell(cell.row, cell.col, VK_LBUTTON);
  6200. // return;
  6201. // }
  6202. // Did the user click on a fixed row cell (so the cell was within the overlap of
  6203. // fixed row and column cells) - (fix by David Pritchard)
  6204. if (GetFixedRowSelection())
  6205. {
  6206. if (cell.row < GetFixedRowCount())
  6207. {
  6208. m_MouseMode = MOUSE_SELECT_ALL;
  6209. OnSelecting(cell);
  6210. }
  6211. else
  6212. {
  6213. m_MouseMode = MOUSE_SELECT_ROW;
  6214. OnSelecting(cell);
  6215. }
  6216. }
  6217. }
  6218. // Gets the extent of the text pointed to by str (no CDC needed)
  6219. // By default this uses the selected font (which is a bigger font)
  6220. CSize CGridCtrl::GetTextExtent(int nRow, int nCol, LPCTSTR str)
  6221. {
  6222. CGridCellBase* pCell = GetCell(nRow, nCol);
  6223. if (!pCell)
  6224. return CSize(0, 0);
  6225. else
  6226. return pCell->GetTextExtent(str);
  6227. }
  6228. // virtual
  6229. void CGridCtrl::OnEditCell(int nRow, int nCol, CPoint point, UINT nChar)
  6230. {
  6231. #ifndef GRIDCONTROL_NO_TITLETIPS
  6232. m_TitleTip.Hide(); // hide any titletips
  6233. #endif
  6234. // Can we do it?
  6235. CCellID cell(nRow, nCol);
  6236. if (!IsValid(cell) || !IsCellEditable(nRow, nCol))
  6237. return;
  6238. // Can we see what we are doing?
  6239. EnsureVisible(nRow, nCol);
  6240. if (!IsCellVisible(nRow, nCol))
  6241. return;
  6242. // Where, exactly, are we gonna do it??
  6243. CRect rect;
  6244. if (!GetCellRect(cell, rect))
  6245. return;
  6246. // Check we can edit...
  6247. if (SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT) >= 0)
  6248. {
  6249. // Let's do it...
  6250. CGridCellBase* pCell = GetCell(nRow, nCol);
  6251. if (pCell)
  6252. pCell->Edit(nRow, nCol, rect, point, IDC_INPLACE_CONTROL, nChar);
  6253. }
  6254. }
  6255. // virtual
  6256. void CGridCtrl::EndEditing()
  6257. {
  6258. CCellID cell = GetFocusCell();
  6259. if (!IsValid(cell)) return;
  6260. CGridCellBase *pCell = GetCell(cell.row, cell.col);
  6261. if (pCell)
  6262. pCell->EndEdit();
  6263. }
  6264. // virtual
  6265. void CGridCtrl::OnEndEditCell(int nRow, int nCol, CString str)
  6266. {
  6267. CString strCurrentText = GetItemText(nRow, nCol);
  6268. if (strCurrentText != str)
  6269. {
  6270. SetItemText(nRow, nCol, str);
  6271. if (ValidateEdit(nRow, nCol, str) &&
  6272. SendMessageToParent(nRow, nCol, GVN_ENDLABELEDIT) >= 0)
  6273. {
  6274. SetModified(TRUE, nRow, nCol);
  6275. RedrawCell(nRow, nCol);
  6276. }
  6277. else
  6278. {
  6279. SetItemText(nRow, nCol, strCurrentText);
  6280. }
  6281. }
  6282. CGridCellBase* pCell = GetCell(nRow, nCol);
  6283. if (pCell)
  6284. pCell->OnEndEdit();
  6285. }
  6286. // If this returns FALSE then the editing isn't allowed
  6287. // virtual
  6288. BOOL CGridCtrl::ValidateEdit(int nRow, int nCol, LPCTSTR str)
  6289. {
  6290. CGridCellBase* pCell = GetCell(nRow, nCol);
  6291. ASSERT(pCell);
  6292. if (!pCell)
  6293. return TRUE;
  6294. return pCell->ValidateEdit(str);
  6295. }
  6296. // virtual
  6297. CString CGridCtrl::GetItemText(int nRow, int nCol) const
  6298. {
  6299. if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols)
  6300. return _T("");
  6301. CGridCellBase* pCell = GetCell(nRow, nCol);
  6302. ASSERT(pCell);
  6303. if (!pCell)
  6304. return _T("");
  6305. return pCell->GetText();
  6306. }
  6307. //Merge the selected cells
  6308. //by Huang Wei
  6309. CCellID CGridCtrl::GetMergeCellID(CCellID cell)
  6310. {
  6311. CGridCellBase *pCell = (CGridCellBase*)GetCell(cell);
  6312. if (pCell && pCell->IsMergeWithOthers())
  6313. return pCell->GetMergeCellID();
  6314. return cell;
  6315. }
  6316. //Merge the selected cells
  6317. //by Huang Wei
  6318. CGridCellBase* CGridCtrl::GetCell(CCellID cell)
  6319. {
  6320. return GetCell(cell.row, cell.col);
  6321. }
  6322. //Merge the selected cells
  6323. //by Huang Wei
  6324. void CGridCtrl::MergeSelectedCells()
  6325. {
  6326. CCellRange range = GetSelectedCellRange();
  6327. if (range.GetColSpan() <= 1 && range.GetRowSpan() <= 1)
  6328. return;
  6329. MergeCells(range.GetMinRow(), range.GetMinCol(), range.GetMaxRow(), range.GetMaxCol());
  6330. }
  6331. //Merge the selected cells
  6332. //by Huang Wei
  6333. void CGridCtrl::MergeCells(int nStartRow, int nStartCol, int nEndRow, int nEndCol)
  6334. {
  6335. for (int row = nStartRow; row <= nEndRow; row++)
  6336. {
  6337. for (int col = nStartCol; col <= nEndCol; col++)
  6338. {
  6339. CGridCellBase *pCell = (CGridCellBase*)GetCell(row, col);
  6340. pCell->Show(false);
  6341. if (row == nStartRow && col == nStartCol)
  6342. {
  6343. CCellRange range(nStartRow, nStartCol, nEndRow, nEndCol);
  6344. pCell->SetMergeRange(range);
  6345. }
  6346. else
  6347. {
  6348. CCellID cell(nStartRow, nStartCol);
  6349. pCell->SetMergeCellID(cell);
  6350. }
  6351. }
  6352. }
  6353. Invalidate();
  6354. }
  6355. //Merge the selected cells
  6356. //by Huang Wei
  6357. void CGridCtrl::UnMergeSelectedCells()
  6358. {
  6359. CCellRange range = GetSelectedCellRange();
  6360. UnMergeCells(range.GetMinRow(), range.GetMinCol(), range.GetMaxRow(), range.GetMaxCol());
  6361. }
  6362. //Merge the selected cells
  6363. //by Huang Wei
  6364. void CGridCtrl::UnMergeCells(int nStartRow, int nStartCol, int nEndRow, int nEndCol)
  6365. {
  6366. for (int row = nStartRow; row <= nEndRow; row++)
  6367. {
  6368. for (int col = nStartCol; col <= nEndCol; col++)
  6369. {
  6370. CGridCellBase *pCell = (CGridCellBase*)GetCell(row, col);
  6371. if (pCell->IsMerged())
  6372. {
  6373. for (int mergerow = pCell->GetMergeRange().GetMaxRow(); mergerow >= pCell->GetMergeRange().GetMinRow(); mergerow--)
  6374. for (int mergecol = pCell->GetMergeRange().GetMaxCol(); mergecol >= pCell->GetMergeRange().GetMinCol(); mergecol--)
  6375. {
  6376. if (pCell->GetMergeRange().GetMaxRow() == -1 || pCell->GetMergeRange().GetMaxCol() == -1)
  6377. break;
  6378. CGridCellBase *pMergedCell = (CGridCellBase*)GetCell(mergerow, mergecol);
  6379. pMergedCell->UnMerge();
  6380. }
  6381. }
  6382. else
  6383. pCell->UnMerge();
  6384. }
  6385. }
  6386. Invalidate();
  6387. }
  6388. //Merge the selected cells
  6389. //by Huang Wei
  6390. int CGridCtrl::GetMergeCellWidth(CCellID cell)
  6391. {
  6392. CCellID mergecell = GetMergeCellID(cell);
  6393. CGridCellBase *pCell = (CGridCellBase*)GetCell(mergecell);
  6394. if (!pCell->IsMerged())
  6395. return GetColumnWidth(cell.col);
  6396. int width = 0;
  6397. for (int mergecol = pCell->GetMergeRange().GetMaxCol(); mergecol >= pCell->GetMergeRange().GetMinCol(); mergecol--)
  6398. {
  6399. width += GetColumnWidth(mergecol);
  6400. }
  6401. return width;
  6402. }
  6403. //Merge the selected cells
  6404. //by Huang Wei
  6405. int CGridCtrl::GetMergeCellHeight(CCellID cell)
  6406. {
  6407. CCellID mergecell = GetMergeCellID(cell);
  6408. CGridCellBase *pCell = (CGridCellBase*)GetCell(mergecell);
  6409. if (!pCell->IsMerged())
  6410. return GetRowHeight(cell.row);
  6411. int height = 0;
  6412. for (int mergerow = pCell->GetMergeRange().GetMaxRow(); mergerow >= pCell->GetMergeRange().GetMinRow(); mergerow--)
  6413. {
  6414. height += GetRowHeight(mergerow);
  6415. }
  6416. return height;
  6417. }