1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362 |
- // GridCtrl.cpp : implementation file
- //
- // MFC Grid Control
- //
- // Written by Chris Maunder
- // mailto:chrismaunder@codeguru.com
- //
- // Copyright (c) 1998-1999.
- //
- // The code contained in this file is based on the original
- // WorldCom Grid control written by Joe Willcoxson,
- // mailto:chinajoe@aol.com
- // http://users.aol.com/chinajoe
- // The code has gone through so many modifications that I'm
- // not sure if there is even a single original line of code.
- // In any case Joe's code was a great framewaork on which to
- // build.
- //
- // This code may be used in compiled form in any way you desire. This
- // file may be redistributed unmodified by any means PROVIDING it is
- // not sold for profit without the authors written consent, and
- // providing that this notice and the authors name and all copyright
- // notices remains intact. If the source code in this file is used in
- // any commercial application then a statement along the lines of
- // "Portions copyright (c) Chris Maunder, 1998" must be included in
- // the startup banner, "About" box or printed documentation. An email
- // letting me know that you are using it would be nice as well. That's
- // not much to ask considering the amount of work that went into this.
- //
- // This file is provided "as is" with no expressed or implied warranty.
- // The author accepts no liability for any damage/loss of business that
- // this product may cause.
- //
- // Expect bugs!
- //
- // Please use and enjoy, and let me know of any bugs/mods/improvements
- // that you have found/implemented and I will fix/incorporate them into
- // this file.
- //
- // History:
- // --------
- // This control is constantly evolving, sometimes due to new features that I
- // feel are necessary, and sometimes due to existing bugs. Where possible I
- // have credited the changes to those who contributed code corrections or
- // enhancements (names in brackets) or code suggestions (suggested by...)
- //
- // 1.0 20 Feb 1998 First release version.
- // 1.01 24 Feb 1998 Memory leak fix (Jens Bohlmann)
- // Fixec typo (my fault!) in CMemDC.h - Claus Arend-Schneider)
- // Bug in GetSelectedCount (Lyn Newton)
- // 1.02 4 Mar 1998 Scrolling a little neater (less dead area)
- // Cell selection via OnTimer correctly updates Focus cell (Suggested by Lyn Newton)
- // 1.03 17 Mar 1998 Clipboard functions added, Intellimouse support
- // Using 32 bit scroll pos functions instead of 16 bit ("cronos")
- // Added OLE drag and drop.
- // 1.04 6 Apr 1998 Added Ctrl-A = Select All, fixed CGridDropTarget
- // problem, minor bug in CopyTextFromGrid (assert on
- // empty string). Cleaned up reponse to m_bEditable
- // (OnDrop and Ctrl-X disabled)
- // 1.05 10 May 1998 Memory leak fixed. (Yuheng Zhao)
- // Changed OLE initialisation (Carlo Comino)
- // Added separate fore + background cell colours (Suggested by John Crane)
- // ExpandToFit etc cleaned up - now decreases and
- // increases cell sizes to fit client area.
- // Added notification messages for the grid's parent (Suggested by
- // Added GVIS_READONLY state
- // 1.06 20 May 1998 Added TAB key handling. (Daniela Rybarova)
- // Intellimouse code correction for whole page scrolling (Paul Grant)
- // Fixed 16 bit thumb track problems (now 32 bit) (Paul Grant)
- // Fixed accelerator key problem in CInPlaceEdit (Matt Weagle)
- // Fixed Stupid ClassWizard code parsing problem (Michael A. Barnhart)
- // Double buffering now programmatically selectable
- // Workaround for win95 drag and drop registration problem
- // Corrected UNICODE implementation of clipboard stuff
- // Dragging and dropping from a selection onto itself no
- // no longer causes the cells to be emptied
- // 1.07 28 Jul 1998 Added EnsureVisible. (Roelf Werkman)
- // Fixed delete key problem on read-only cells. (Serge Weinstock)
- // OnEndInPlaceEdit sends notification AFTER storing
- // the modified text in the cell.
- // Added CreateInPlaceEditControl to make it easier to
- // change the way cells are edited. (suggested by Chris Clark)
- // Added Set/GetGridColor.
- // CopyTextToClipboard and PasteTextToGrid problem with
- // blank cells fixed, and CopyTextToClipboard tweaked.
- // SetModified called when cutting text or hitting DEL. (Jonathan Watters)
- // Focus cell made visible when editing begins.
- // Blank lines now treated correctly when pasting data.
- // Removed ES_MULTILINE style from the default edit control.
- // Added virtual CreateCell(row, col) function.
- // Fonts now specified on a per-cell basis using Get/SetItemFont.
- // 1.08 6 Aug 1998 Ctrl+arrows now allows cell navigation. Modified
- // CreateInPlaceEditControl to accept ID of control.
- // Added Titletips to grid cells. (Added EnableTitleTips / GetTitleTips)
- // 1.09 12 Sep 1998 When printing, parent window title is printed in header - Gert Rijs
- // GetNextItem search with GVNI_DROPHILITED now returns
- // cells with GVIS_DROPHILITED set, instead of GVIS_FOCUSED (Franco Bez)
- // (Also fixed minor bug in GetNextItem) (Franco Bez)
- // Cell selection using Shift+arrows works - Franco Bez
- // SetModified called after edits ONLY if contents changed (Franco Bez)
- // Cell colours now dithered in 256 colour screens.
- // Support for MSVC 4.2 (Graham Cheetham)
- // 1.10 30 Nov 1998 Titletips now disappear on a scroll event. Compiler errors
- // fixed. Grid lines drawing fixed (Graham Cheetham).
- // Cell focus fix on Isert Row/Col (Jochen Kauffmann)
- // Added DeleteNonFixedRows() (John Rackley)
- // Message #define conflict fixed (Oskar Wieland)
- // Titletips & cell insert/delete fix (Ramesh Dhar)
- // Titletips repeat-creation bug fixed.
- // GVN_SELCHANGED message now sends current cell ID
- // Font resource leak in GetTextExtent fixed (Gavin Jerman)
- // More TAB fixes (Andreas Ruh)
- // 1.11 1 Dec 1998 GetNextItem bug fix (suggested by Francis Fu)
- // InsertColumn (-1) fix (Roy Hopkins)
- // Was too liberal with the "IsEditable"'s. oops. (Michel Hete)
- // 1.11a 4 Jan 1999 Compiler errors in VC6 fixed.
- // 1.12 10 Apr 1999 Cleanup to allow GRIDCONTROL_NO_CLIPBOARD define
- // CE #defines added. (Thanks to Frank Uzzolino for a start on this)
- // TitleTip display fixed for cells with images, plus it now uses cell font
- // Added GetTextRect and IsCellFixed
- // Focus change problem when resizing columns fixed (Sergey Nikiforenko)
- // Grid line drawing problem in fixed cells fixed (Sergey Nikiforenko)
- // CreateCell format persistance bug fixed (Sergey Nikiforenko)
- // DeleteColumn now returns TRUE (oops) (R. Elmer)
- // Enter, Tab and Esc key problem (finally) fixed - Darren Webb and Koay Kah Hoe
- // OnSize infinite loop fixed - Steve Kowald
- // GVN_SELCHANGING and GVN_SELCHANGED values changed to avoid conflicts (Hiroaki Watanabe)
- // Added single row selection mode (Yao Cai)
- // Fixed image drawing clip problem
- // Reduced unnecessary redraws significantly
- // GetNextItem additions and bug fix, and GVNI_AREA search option (Franco Bez)
- // Added GVIS_MODIFIED style for cells, so individual cells can have their
- // modification status queried. (Franco Bez)
- // 1.12a 15 Apr 1999 Removed the SetModified/GetModified inlines (no compiler warning!)
- // Renamed IDC_INPLACE_CONTROL to IDC_INPLACE_CONTROL and moved
- // to the header
- //
- // TODO:
- // - OnOutOfMemory function instead of exceptions
- // - Decrease timer interval over time to speed up selection over time
- //
- // NOTE: Grid data is stored row-by-row, so all operations on large numbers
- // of cells should be done row-by-row as well.
- //
- // KNOWN ISSUES TO BE ADDRESSED (Please don't send bug reports):
- // * Killfocus comes to late when a command is selected by the Menu.
- // When you are editing a cell and choose a Menuitem that searches for all the
- // modified cells it is not found. When you chose the menu a second time it is
- // found. I assume that the Menu command is executed before the cell receives the
- // KillFocus event. Expect similar Problems with accelerators. (Franco Bez)
- // * When you select a cell and move the mouse around (with the Left button down
- // i.e continuing with your selection) - if the mouse is over the Fixed column
- // or Row the drawing of the selected region is strange - in particular as you
- // move up and down say the Left Fixed Column notice the behaviour of the Focus
- // Cell - it is out of sync. (Vinay Desai)
- //
- /////////////////////////////////////////////////////////////////////////////
-
- #include "stdafx.h"
- #include "MemDC.h"
- #include "GridCtrl.h"
- #include "InPlaceEdit.h"
- // OLE stuff for clipboard operations
- #include <afxadv.h> // For CSharedFile
- #include <afxconv.h> // For LPTSTR -> LPSTR macros
- #ifdef _DEBUG
- #define new DEBUG_NEW
- #undef THIS_FILE
- static char THIS_FILE[] = __FILE__;
- #endif
- #define HEADER_HEIGHT 2 // For printing
- #define FOOTER_HEIGHT 2
- #define LEFT_MARGIN 4
- #define RIGHT_MARGIN 4
- #define TOP_MARGIN 1
- #define BOTTOM_MARGIN 1
- #define GAP 1
- #define SELECTED_CELL_FONT_WEIGHT 600 // weight of text for selected items
- IMPLEMENT_DYNCREATE(CGridCtrl, CWnd)
- void AFXAPI DDX_GridControl(CDataExchange* pDX, int nIDC, CGridCtrl& rControl)
- {
- if (rControl.GetSafeHwnd() == NULL) // not subclassed yet
- {
- ASSERT(!pDX->m_bSaveAndValidate);
- HWND hWndCtrl = pDX->PrepareCtrl(nIDC);
- if (!rControl.SubclassWindow(hWndCtrl))
- {
- ASSERT(FALSE); // possibly trying to subclass twice?
- AfxThrowNotSupportedException();
- }
- #ifndef _AFX_NO_OCC_SUPPORT
- else
- {
- // If the control has reparented itself (e.g., invisible control),
- // make sure that the CWnd gets properly wired to its control site.
- if (pDX->m_pDlgWnd->GetSafeHwnd() != ::GetParent(rControl.GetSafeHwnd()))
- rControl.AttachControlSite(pDX->m_pDlgWnd);
- }
- #endif //!_AFX_NO_OCC_SUPPORT
- }
- }
- // Get the number of lines to scroll with each mouse wheel notch
- // Why doesn't windows give us this function???
- UINT GetMouseScrollLines()
- {
- int nScrollLines = 3; // reasonable default
- HKEY hKey;
- if (RegOpenKeyEx(HKEY_CURRENT_USER, _T("Control Panel\\Desktop"),
- 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
- {
- TCHAR szData[128];
- DWORD dwKeyDataType;
- DWORD dwDataBufSize = sizeof(szData);
- if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
- (LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
- {
- nScrollLines = _tcstoul(szData, NULL, 10);
- }
- RegCloseKey(hKey);
- }
- return nScrollLines;
- }
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl
- CGridCtrl::CGridCtrl(int nRows, int nCols, int nFixedRows, int nFixedCols)
- {
- RegisterWindowClass();
- // Initialize OLE libraries
- m_bMustUninitOLE = FALSE;
- #if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
- _AFX_THREAD_STATE* pState = AfxGetThreadState();
- if (!pState->m_bNeedTerm)
- {
- SCODE sc = ::OleInitialize(NULL);
- if (FAILED(sc))
- AfxMessageBox(_T("OLE initialization failed. Make sure that the OLE libraries are the correct version"));
- else
- m_bMustUninitOLE = TRUE;
- }
- #endif
- // Store the system colours in case they change. The gridctrl uses
- // these colours, and in OnSysColorChange we can check to see if
- // the gridctrl colours have been changed from the system colours.
- // If they have, then leave them, otherwise change them to reflect
- // the new system colours.
- m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
- m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
- m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
- m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
- m_crGridColour = RGB(192,192,192);
- m_nRows = 0;
- m_nCols = 0;
- m_nFixedRows = 0;
- m_nFixedCols = 0;
- m_nDefCellHeight = 10; // These will get changed to something meaningful
- m_nDefCellWidth = 30; // when the window is created or subclassed
- m_nVScrollMax = 0; // Scroll position
- m_nHScrollMax = 0;
- m_nMargin = 0; // cell padding
- m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
- // per mouse wheel notch to scroll
- m_MouseMode = MOUSE_NOTHING;
- m_nGridLines = GVL_BOTH;
- m_bEditable = TRUE;
- m_bListMode = FALSE;
- m_bSingleRowSelection = FALSE;
- m_bAllowDraw = TRUE; // allow draw updates
- m_bEnableSelection = TRUE;
- m_bAllowRowResize = TRUE;
- m_bAllowColumnResize = TRUE;
- m_bSortOnClick = TRUE; // Sort on header row click if in list mode
- m_bHandleTabKey = TRUE;
- #ifdef _WIN32_WCE
- m_bDoubleBuffer = FALSE; // Use double buffering to avoid flicker?
- #else
- m_bDoubleBuffer = TRUE; // Use double buffering to avoid flicker?
- #endif
- m_bTitleTips = TRUE; // show cell title tips
- m_bAscending = TRUE; // sorting stuff
- m_SortColumn = -1;
- m_nTimerID = 0; // For drag-selection
- m_nTimerInterval = 25; // (in milliseconds)
- m_nResizeCaptureRange = 3; // When resizing columns/row, the cursor has to be
- // within +/-3 pixels of the dividing line for
- // resizing to be possible
- m_pImageList = NULL;
- m_bAllowDragAndDrop = FALSE; // for drag and drop
- #ifndef _WIN32_WCE
- // Initially use the system message font for the GridCtrl font
- NONCLIENTMETRICS ncm;
- ncm.cbSize = sizeof(NONCLIENTMETRICS);
- VERIFY(SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm, 0));
- memcpy(&m_Logfont, &(ncm.lfMessageFont), sizeof(LOGFONT));
- #else
- LOGFONT lf;
- GetObject(GetStockObject(SYSTEM_FONT), sizeof(LOGFONT), &lf);
- memcpy(&m_Logfont, &lf, sizeof(LOGFONT));
- #endif
- // Set up the initial grid size
- SetRowCount(nRows);
- SetColumnCount(nCols);
- SetFixedRowCount(nFixedRows);
- SetFixedColumnCount(nFixedCols);
- // Set the colours
- SetTextColor(m_crWindowText);
- SetTextBkColor(m_crWindowColour);
- SetBkColor(m_crShadow);
- SetFixedTextColor(m_crWindowText);
- SetFixedBkColor(m_cr3DFace);
- // set initial selection range (ie. none)
- m_SelectedCellMap.RemoveAll();
- m_PrevSelectedCellMap.RemoveAll();
- }
- CGridCtrl::~CGridCtrl()
- {
- DeleteAllItems();
- DestroyWindow();
- m_Font.DeleteObject();
- #if !defined(GRIDCONTROL_NO_DRAGDROP) || !defined(GRIDCONTROL_NO_CLIPBOARD)
- // Uninitialize OLE support
- if (m_bMustUninitOLE)
- ::OleUninitialize();
- #endif
- }
- // Register the window class if it has not already been registered.
- BOOL CGridCtrl::RegisterWindowClass()
- {
- WNDCLASS wndcls;
- HINSTANCE hInst = AfxGetInstanceHandle();
- // HINSTANCE hInst = AfxGetResourceHandle();
- if (!(::GetClassInfo(hInst, GRIDCTRL_CLASSNAME, &wndcls)))
- {
- // otherwise we need to register a new class
- wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
- wndcls.lpfnWndProc = ::DefWindowProc;
- wndcls.cbClsExtra = wndcls.cbWndExtra = 0;
- wndcls.hInstance = hInst;
- wndcls.hIcon = NULL;
- wndcls.hCursor = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
- wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1);
- wndcls.lpszMenuName = NULL;
- wndcls.lpszClassName = GRIDCTRL_CLASSNAME;
- if (!AfxRegisterClass(&wndcls)) {
- AfxThrowResourceException();
- return FALSE;
- }
- }
- return TRUE;
- }
- BOOL CGridCtrl::Create(const RECT& rect, CWnd* pParentWnd, UINT nID, DWORD dwStyle)
- {
- ASSERT(pParentWnd->GetSafeHwnd());
- if (!CWnd::Create(GRIDCTRL_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID))
- return FALSE;
- #ifndef GRIDCONTROL_NO_DRAGDROP
- m_DropTarget.Register(this);
- #endif
- // Create titletips
- #ifndef GRIDCONTROL_NO_TITLETIPS
- if (m_bTitleTips)
- m_TitleTip.Create(this);
- #endif
- // The number of rows and columns will only be non-zero if the constructor
- // was called with non-zero initialising parameters. If this window was created
- // using a dialog template then the number of rows and columns will be 0 (which
- // means that the code below will not be needed - which is lucky 'cause it ain't
- // gonna get called in a dialog-template-type-situation.
- TRY {
- m_arRowHeights.SetSize(m_nRows); // initialize row heights
- m_arColWidths.SetSize(m_nCols); // initialize column widths
- }
- CATCH (CMemoryException, e) {
- e->ReportError();
- e->Delete();
- return FALSE;
- }
- END_CATCH
- for (int i = 0; i < m_nRows; i++) m_arRowHeights[i] = m_nDefCellHeight;
- for (i = 0; i < m_nCols; i++) m_arColWidths[i] = m_nDefCellWidth;
- ResetScrollBars();
- return TRUE;
- }
- void CGridCtrl::PreSubclassWindow()
- {
- CWnd::PreSubclassWindow();
- HFONT hFont = ::CreateFontIndirect(&m_Logfont);
- OnSetFont((LPARAM)hFont, 0);
- DeleteObject(hFont);
-
- ResetScrollBars();
- }
- BOOL CGridCtrl::SubclassWindow(HWND hWnd)
- {
- if (!CWnd::SubclassWindow(hWnd))
- return FALSE;
- #ifndef GRIDCONTROL_NO_DRAGDROP
- m_DropTarget.Register(this);
- #endif
- #ifndef GRIDCONTROL_NO_TITLETIPS
- if (m_bTitleTips && !IsWindow(m_TitleTip.m_hWnd))
- m_TitleTip.Create(this);
- #endif
- return TRUE;
- }
- LRESULT CGridCtrl::SendMessageToParent(int nRow, int nCol, int nMessage)
- {
- if (!IsWindow(m_hWnd))
- return 0;
- NM_GRIDVIEW nmgv;
- nmgv.iRow = nRow;
- nmgv.iColumn = nCol;
- nmgv.hdr.hwndFrom = m_hWnd;
- nmgv.hdr.idFrom = GetDlgCtrlID();
- nmgv.hdr.code = nMessage;
- CWnd *pOwner = GetOwner();
- if (pOwner && IsWindow(pOwner->m_hWnd))
- return pOwner->SendMessage(WM_NOTIFY, nmgv.hdr.idFrom, (LPARAM)&nmgv);
- else
- return 0;
- }
- BEGIN_MESSAGE_MAP(CGridCtrl, CWnd)
- //{{AFX_MSG_MAP(CGridCtrl)
- ON_WM_PAINT()
- ON_WM_HSCROLL()
- ON_WM_VSCROLL()
- ON_WM_SIZE()
- ON_WM_LBUTTONUP()
- ON_WM_LBUTTONDOWN()
- ON_WM_MOUSEMOVE()
- ON_WM_TIMER()
- ON_WM_GETDLGCODE()
- ON_WM_KEYDOWN()
- ON_WM_CHAR()
- ON_WM_LBUTTONDBLCLK()
- ON_WM_ERASEBKGND()
- ON_COMMAND(ID_EDIT_SELECT_ALL, OnEditSelectAll)
- ON_UPDATE_COMMAND_UI(ID_EDIT_SELECT_ALL, OnUpdateEditSelectAll)
- //}}AFX_MSG_MAP
- #ifndef _WIN32_WCE_NO_CURSOR
- ON_WM_SETCURSOR()
- #endif
- #ifndef _WIN32_WCE
- ON_WM_SYSCOLORCHANGE()
- ON_WM_CAPTURECHANGED()
- #endif
- #ifndef GRIDCONTROL_NO_CLIPBOARD
- ON_COMMAND(ID_EDIT_COPY, OnEditCopy)
- ON_UPDATE_COMMAND_UI(ID_EDIT_COPY, OnUpdateEditCopy)
- ON_COMMAND(ID_EDIT_CUT, OnEditCut)
- ON_UPDATE_COMMAND_UI(ID_EDIT_CUT, OnUpdateEditCut)
- ON_COMMAND(ID_EDIT_PASTE, OnEditPaste)
- ON_UPDATE_COMMAND_UI(ID_EDIT_PASTE, OnUpdateEditPaste)
- #endif
- #if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
- ON_WM_MOUSEWHEEL()
- #endif
- #if (_WIN32_WCE >= 210)
- ON_WM_SETTINGCHANGE()
- #endif
- ON_MESSAGE(WM_SETFONT, OnSetFont)
- ON_MESSAGE(WM_GETFONT, OnGetFont)
- ON_NOTIFY(GVN_ENDLABELEDIT, IDC_INPLACE_CONTROL, OnEndInPlaceEdit)
- END_MESSAGE_MAP()
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl message handlers
- void CGridCtrl::OnPaint()
- {
- CPaintDC dc(this); // device context for painting
- if (m_bDoubleBuffer) // Use a memory DC to remove flicker
- {
- CMemDC MemDC(&dc);
- OnDraw(&MemDC);
- }
- else // Draw raw - this helps in debugging vis problems.
- OnDraw(&dc);
- }
- BOOL CGridCtrl::OnEraseBkgnd(CDC* /*pDC*/)
- {
- return TRUE; // Don't erase the background.
- }
- // Custom background erasure. This gets called from within the OnDraw function,
- // since we will (most likely) be using a memory DC to stop flicker. If we just
- // erase the background normally through OnEraseBkgnd, and didn't fill the memDC's
- // selected bitmap with colour, then all sorts of vis problems would occur
- void CGridCtrl::EraseBkgnd(CDC* pDC)
- {
- CRect VisRect, ClipRect, rect;
- CBrush FixedBack(GetFixedBkColor()),
- TextBack(GetTextBkColor()),
- Back(GetBkColor());
- if (pDC->GetClipBox(ClipRect) == ERROR)
- return;
- GetVisibleNonFixedCellRange(VisRect);
- // Draw Fixed columns background
- int nFixedColumnWidth = GetFixedColumnWidth();
- if (ClipRect.left < nFixedColumnWidth && ClipRect.top < VisRect.bottom)
- pDC->FillRect(CRect(ClipRect.left, ClipRect.top,
- nFixedColumnWidth, VisRect.bottom),
- &FixedBack);
-
- // Draw Fixed rows background
- int nFixedRowHeight = GetFixedRowHeight();
- if (ClipRect.top < nFixedRowHeight &&
- ClipRect.right > nFixedColumnWidth && ClipRect.left < VisRect.right)
- pDC->FillRect(CRect(nFixedColumnWidth-1, ClipRect.top,
- VisRect.right, nFixedRowHeight),
- &FixedBack);
- // Draw non-fixed cell background
- if (rect.IntersectRect(VisRect, ClipRect))
- {
- CRect CellRect(max(nFixedColumnWidth, rect.left),
- max(nFixedRowHeight, rect.top),
- rect.right, rect.bottom);
- pDC->FillRect(CellRect, &TextBack);
- }
- // Draw right hand side of window outside grid
- if (VisRect.right < ClipRect.right)
- pDC->FillRect(CRect(VisRect.right, ClipRect.top,
- ClipRect.right, ClipRect.bottom),
- &Back);
- // Draw bottom of window below grid
- if (VisRect.bottom < ClipRect.bottom && ClipRect.left < VisRect.right)
- pDC->FillRect(CRect(ClipRect.left, VisRect.bottom,
- VisRect.right, ClipRect.bottom),
- &Back);
- }
- void CGridCtrl::OnSize(UINT nType, int cx, int cy)
- {
- static BOOL bAlreadyInsideThisProcedure = FALSE;
- if (bAlreadyInsideThisProcedure)
- return;
- if (!::IsWindow(m_hWnd))
- return;
- // Start re-entry blocking
- bAlreadyInsideThisProcedure = TRUE;
- // if (::IsWindow(GetSafeHwnd()) && GetFocus()->GetSafeHwnd() != GetSafeHwnd())
- SetFocus(); // Auto-destroy any InPlaceEdit's
- CWnd::OnSize(nType, cx, cy);
- ResetScrollBars();
- // End re-entry blocking
- bAlreadyInsideThisProcedure = FALSE;
- }
- UINT CGridCtrl::OnGetDlgCode()
- {
- UINT nCode = DLGC_WANTARROWS | DLGC_WANTCHARS; // DLGC_WANTALLKEYS; //
- if (m_bHandleTabKey && !IsCTRLpressed())
- nCode |= DLGC_WANTTAB;
- return nCode;
- }
- #ifndef _WIN32_WCE
- // If system colours change, then redo colours
- void CGridCtrl::OnSysColorChange()
- {
- CWnd::OnSysColorChange();
-
- if (GetTextColor() == m_crWindowText) // Still using system colours
- SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
- if (GetTextBkColor() == m_crWindowColour)
- SetTextBkColor(::GetSysColor(COLOR_WINDOW));
- if (GetBkColor() == m_crShadow)
- SetBkColor(::GetSysColor(COLOR_3DSHADOW));
- if (GetFixedTextColor() == m_crWindowText)
- SetFixedTextColor(::GetSysColor(COLOR_WINDOWTEXT));
- if (GetFixedBkColor() == m_cr3DFace)
- SetFixedBkColor(::GetSysColor(COLOR_3DFACE));
- m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
- m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
- m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
- m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
- }
- #endif
- #ifndef _WIN32_WCE_NO_CURSOR
- // If we are drag-selecting cells, or drag and dropping, stop now
- void CGridCtrl::OnCaptureChanged(CWnd *pWnd)
- {
- if (pWnd->GetSafeHwnd() == GetSafeHwnd()) return;
- // kill timer if active
- if (m_nTimerID != 0)
- {
- KillTimer(m_nTimerID);
- m_nTimerID = 0;
- }
- #ifndef GRIDCONTROL_NO_DRAGDROP
- // Kill drag and drop if active
- if (m_MouseMode == MOUSE_DRAGGING)
- m_MouseMode = MOUSE_NOTHING;
- #endif
- }
- #endif
- #if (_MFC_VER >= 0x0421) || (_WIN32_WCE >= 210)
- // If system settings change, then redo colours
- void CGridCtrl::OnSettingChange(UINT uFlags, LPCTSTR lpszSection)
- {
- CWnd::OnSettingChange(uFlags, lpszSection);
-
- if (GetTextColor() == m_crWindowText) // Still using system colours
- SetTextColor(::GetSysColor(COLOR_WINDOWTEXT)); // set to new system colour
- if (GetTextBkColor() == m_crWindowColour)
- SetTextBkColor(::GetSysColor(COLOR_WINDOW));
- if (GetBkColor() == m_crShadow)
- SetBkColor(::GetSysColor(COLOR_3DSHADOW));
- if (GetFixedTextColor() == m_crWindowText)
- SetFixedTextColor(::GetSysColor(COLOR_WINDOWTEXT));
- if (GetFixedBkColor() == m_cr3DFace)
- SetFixedBkColor(::GetSysColor(COLOR_3DFACE));
- m_crWindowText = ::GetSysColor(COLOR_WINDOWTEXT);
- m_crWindowColour = ::GetSysColor(COLOR_WINDOW);
- m_cr3DFace = ::GetSysColor(COLOR_3DFACE);
- m_crShadow = ::GetSysColor(COLOR_3DSHADOW);
- m_nRowsPerWheelNotch = GetMouseScrollLines(); // Get the number of lines
- }
- #endif
- // For drag-selection. Scrolls hidden cells into view
- // TODO: decrease timer interval over time to speed up selection over time
- void CGridCtrl::OnTimer(UINT nIDEvent)
- {
- ASSERT(nIDEvent == WM_LBUTTONDOWN);
- if (nIDEvent != WM_LBUTTONDOWN)
- return;
- CPoint pt, origPt;
- #ifdef _WIN32_WCE
- if (m_MouseMode == MOUSE_NOTHING)
- return;
- origPt = GetMessagePos();
- #else
- if (!GetCursorPos(&origPt))
- return;
- #endif
- ScreenToClient(&origPt);
- CRect rect;
- GetClientRect(rect);
- int nFixedRowHeight = GetFixedRowHeight();
- int nFixedColWidth = GetFixedColumnWidth();
- pt = origPt;
- if (pt.y > rect.bottom)
- {
- //SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
- SendMessage(WM_KEYDOWN, VK_DOWN, 0);
- if (pt.x < rect.left)
- pt.x = rect.left;
- if (pt.x > rect.right)
- pt.x = rect.right;
- pt.y = rect.bottom;
- OnSelecting(GetCellFromPt(pt));
- }
- else if (pt.y < nFixedRowHeight)
- {
- //SendMessage(WM_VSCROLL, SB_LINEUP, 0);
- SendMessage(WM_KEYDOWN, VK_UP, 0);
- if (pt.x < rect.left)
- pt.x = rect.left;
- if (pt.x > rect.right)
- pt.x = rect.right;
- pt.y = nFixedRowHeight + 1;
- OnSelecting(GetCellFromPt(pt));
- }
- pt = origPt;
- if (pt.x > rect.right)
- {
- // SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
- SendMessage(WM_KEYDOWN, VK_RIGHT, 0);
- if (pt.y < rect.top)
- pt.y = rect.top;
- if (pt.y > rect.bottom)
- pt.y = rect.bottom;
- pt.x = rect.right;
- OnSelecting(GetCellFromPt(pt));
- }
- else if (pt.x < nFixedColWidth)
- {
- //SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
- SendMessage(WM_KEYDOWN, VK_LEFT, 0);
- if (pt.y < rect.top)
- pt.y = rect.top;
- if (pt.y > rect.bottom)
- pt.y = rect.bottom;
- pt.x = nFixedColWidth + 1;
- OnSelecting(GetCellFromPt(pt));
- }
- }
- // move about with keyboard
- void CGridCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
- {
- if (!IsValid(m_idCurrentCell))
- {
- CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
- return;
- }
- CCellID next = m_idCurrentCell;
- BOOL bChangeLine = FALSE;
- if (IsCTRLpressed())
- {
- switch (nChar)
- {
- case 'A': OnEditSelectAll(); break;
- #ifndef GRIDCONTROL_NO_CLIPBOARD
- case 'X': OnEditCut(); break;
- case 'C': OnEditCopy(); break;
- case 'V': OnEditPaste(); break;
- #endif
- }
- }
- switch (nChar)
- {
- case VK_DELETE:
- if (IsCellEditable(m_idCurrentCell.row, m_idCurrentCell.col))
- {
- SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_BEGINLABELEDIT);
- SetItemText(m_idCurrentCell.row, m_idCurrentCell.col, _T(""));
- SetModified(TRUE, m_idCurrentCell.row, m_idCurrentCell.col);
- SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_ENDLABELEDIT);
- RedrawCell(m_idCurrentCell);
- }
- break;
- case VK_TAB:
- if (IsSHIFTpressed())
- {
- if (next.col > m_nFixedCols)
- next.col--;
- else if (next.col == m_nFixedCols && next.row > m_nFixedRows)
- {
- next.row--;
- next.col = GetColumnCount() - 1;
- bChangeLine = TRUE;
- }
- else
- CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
- }
- else
- {
- if (next.col < (GetColumnCount() - 1))
- next.col++;
- else if (next.col == (GetColumnCount() - 1) &&
- next.row < (GetRowCount() - 1) )
- {
- next.row++;
- next.col = m_nFixedCols;
- bChangeLine = TRUE;
- }
- else
- CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
- }
- break;
- case VK_DOWN:
- if (next.row < (GetRowCount() - 1))
- next.row++;
- break;
-
- case VK_UP:
- if (next.row > m_nFixedRows)
- next.row--;
- break;
- case VK_RIGHT:
- if (next.col < (GetColumnCount() - 1))
- next.col++;
- break;
-
- case VK_LEFT:
- if (next.col > m_nFixedCols)
- next.col--;
- break;
- case VK_NEXT:
- {
- CCellID idOldTopLeft = GetTopleftNonFixedCell();
- SendMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
- CCellID idNewTopLeft = GetTopleftNonFixedCell();
- int increment = idNewTopLeft.row - idOldTopLeft.row;
- if (increment) {
- next.row += increment;
- if (next.row > (GetRowCount() - 1))
- next.row = GetRowCount() - 1;
- }
- else
- next.row = GetRowCount() - 1;
- break;
- }
-
- case VK_PRIOR:
- {
- CCellID idOldTopLeft = GetTopleftNonFixedCell();
- SendMessage(WM_VSCROLL, SB_PAGEUP, 0);
- CCellID idNewTopLeft = GetTopleftNonFixedCell();
- int increment = idNewTopLeft.row - idOldTopLeft.row;
- if (increment)
- {
- next.row += increment;
- if (next.row < m_nFixedRows)
- next.row = m_nFixedRows;
- } else
- next.row = m_nFixedRows;
- break;
- }
-
- case VK_HOME:
- SendMessage(WM_VSCROLL, SB_TOP, 0);
- next.row = m_nFixedRows;
- break;
-
- case VK_END:
- SendMessage(WM_VSCROLL, SB_BOTTOM, 0);
- next.row = GetRowCount() - 1;
- break;
-
- default:
- CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
- }
-
- if (next != m_idCurrentCell)
- {
- // While moving with the Cursorkeys the current ROW/CELL will get selected
- // OR Selection will get expanded when SHIFT is pressed
- // Cut n paste from OnLButtonDown - Franco Bez
- // Added check for NULL mouse mode - Chris Maunder.
- if (m_MouseMode == MOUSE_NOTHING)
- {
- m_PrevSelectedCellMap.RemoveAll();
- m_MouseMode = m_bListMode? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
- if (!IsSHIFTpressed() || nChar == VK_TAB)
- m_SelectionStartCell = next;
- OnSelecting(next);
- m_MouseMode = MOUSE_NOTHING;
- }
- SetFocusCell(next);
- if (!IsCellVisible(next))
- {
- EnsureVisible(next); // Make sure cell is visible
- switch (nChar) {
- case VK_RIGHT:
- SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
- break;
- case VK_LEFT:
- SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
- break;
- case VK_DOWN:
- SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
- break;
-
- case VK_UP:
- SendMessage(WM_VSCROLL, SB_LINEUP, 0);
- break;
-
- case VK_TAB:
- if (IsSHIFTpressed())
- {
- if (bChangeLine)
- {
- SendMessage(WM_VSCROLL, SB_LINEUP, 0);
- SetScrollPos32(SB_HORZ, m_nHScrollMax);
- break;
- }
- else
- SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
- }
- else
- {
- if (bChangeLine)
- {
- SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
- SetScrollPos32(SB_HORZ, 0);
- break;
- }
- else
- SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
- }
- break;
- }
- Invalidate();
- }
- }
- }
- // Instant editing of cells when keys are pressed
- void CGridCtrl::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
- {
- if (!IsCTRLpressed() && m_MouseMode == MOUSE_NOTHING)
- {
- if (!m_bHandleTabKey || (m_bHandleTabKey && nChar != VK_TAB))
- OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, nChar);
- }
- CWnd::OnChar(nChar, nRepCnt, nFlags);
- }
- // Callback from any CInPlaceEdits that ended. This just calls OnEndEditCell,
- // refreshes the edited cell and moves onto next cell if the return character
- // from the edit says we should.
- void CGridCtrl::OnEndInPlaceEdit(NMHDR* pNMHDR, LRESULT* pResult)
- {
- GV_DISPINFO *pgvDispInfo = (GV_DISPINFO *)pNMHDR;
- GV_ITEM *pgvItem = &pgvDispInfo->item;
- // In case OnEndInPlaceEdit called as window is being destroyed
- if (!IsWindow(GetSafeHwnd()))
- return;
- OnEndEditCell(pgvItem->row, pgvItem->col, pgvItem->szText);
- InvalidateCellRect(CCellID(pgvItem->row, pgvItem->col));
- SendMessageToParent(pgvItem->row, pgvItem->col, GVN_ENDLABELEDIT);
- switch (pgvItem->lParam)
- {
- case VK_TAB:
- case VK_DOWN:
- case VK_UP:
- case VK_RIGHT:
- case VK_LEFT:
- case VK_NEXT:
- case VK_PRIOR:
- case VK_HOME:
- case VK_END:
- OnKeyDown(pgvItem->lParam, 0, 0);
- OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, pgvItem->lParam);
- }
- *pResult = 0;
- }
- // Handle horz scrollbar notifications
- void CGridCtrl::OnHScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
- {
- if (GetFocus()->GetSafeHwnd() != GetSafeHwnd())
- SetFocus(); // Auto-destroy any InPlaceEdit's
- #ifndef GRIDCONTROL_NO_TITLETIPS
- m_TitleTip.Hide(); // hide any titletips
- #endif
- int scrollPos = GetScrollPos32(SB_HORZ);
- CCellID idTopLeft = GetTopleftNonFixedCell();
- CRect rect;
- GetClientRect(rect);
- switch (nSBCode)
- {
- case SB_LINERIGHT:
- if (scrollPos < m_nHScrollMax)
- {
- int xScroll = GetColumnWidth(idTopLeft.col);
- SetScrollPos32(SB_HORZ, scrollPos + xScroll);
- if (GetScrollPos32(SB_HORZ) == scrollPos) break; // didn't work
- rect.left = GetFixedColumnWidth() + xScroll;
- ScrollWindow(-xScroll, 0, rect);
- rect.left = rect.right - xScroll;
- InvalidateRect(rect);
- }
- break;
- case SB_LINELEFT:
- if (scrollPos > 0 && idTopLeft.col > GetFixedColumnCount())
- {
- int xScroll = GetColumnWidth(idTopLeft.col-1);
- SetScrollPos32(SB_HORZ, max(0,scrollPos - xScroll));
- rect.left = GetFixedColumnWidth();
- ScrollWindow(xScroll, 0, rect);
- rect.right = rect.left + xScroll;
- InvalidateRect(rect);
- }
- break;
- case SB_PAGERIGHT:
- if (scrollPos < m_nHScrollMax)
- {
- rect.left = GetFixedColumnWidth();
- int offset = rect.Width();
- int pos = min(m_nHScrollMax, scrollPos + offset);
- SetScrollPos32(SB_HORZ, pos);
- rect.left = GetFixedColumnWidth();
- InvalidateRect(rect);
- }
- break;
- case SB_PAGELEFT:
- if (scrollPos > 0)
- {
- rect.left = GetFixedColumnWidth();
- int offset = -rect.Width();
- int pos = max(0, scrollPos + offset);
- SetScrollPos32(SB_HORZ, pos);
- rect.left = GetFixedColumnWidth();
- InvalidateRect(rect);
- }
- break;
- case SB_THUMBPOSITION:
- case SB_THUMBTRACK:
- {
- SetScrollPos32(SB_HORZ, GetScrollPos32(SB_HORZ, TRUE));
- CCellID idNewTopLeft = GetTopleftNonFixedCell();
- if (idNewTopLeft != idTopLeft)
- {
- rect.left = GetFixedColumnWidth();
- InvalidateRect(rect);
- }
- }
- break;
- case SB_LEFT:
- if (scrollPos > 0)
- {
- SetScrollPos32(SB_HORZ, 0);
- Invalidate();
- }
- break;
- case SB_RIGHT:
- if (scrollPos < m_nHScrollMax)
- {
- SetScrollPos32(SB_HORZ, m_nHScrollMax);
- Invalidate();
- }
- break;
- default: break;
- }
- }
- // Handle vert scrollbar notifications
- void CGridCtrl::OnVScroll(UINT nSBCode, UINT /*nPos*/, CScrollBar* /*pScrollBar*/)
- {
- if (GetFocus()->GetSafeHwnd() != GetSafeHwnd())
- SetFocus(); // Auto-destroy any InPlaceEdit's
- #ifndef GRIDCONTROL_NO_TITLETIPS
- m_TitleTip.Hide(); // hide any titletips
- #endif
- // Get the scroll position ourselves to ensure we get a 32 bit value
- int scrollPos = GetScrollPos32(SB_VERT);
- CCellID idTopLeft = GetTopleftNonFixedCell();
- CRect rect;
- GetClientRect(rect);
- switch (nSBCode)
- {
- case SB_LINEDOWN:
- if (scrollPos < m_nVScrollMax)
- {
- int yScroll = GetRowHeight(idTopLeft.row);
- SetScrollPos32(SB_VERT, scrollPos + yScroll);
- if (GetScrollPos32(SB_VERT) == scrollPos)
- break; // didn't work
- rect.top = GetFixedRowHeight() + yScroll;
- ScrollWindow( 0, -yScroll, rect);
- rect.top = rect.bottom - yScroll;
- InvalidateRect(rect);
- }
- break;
- case SB_LINEUP:
- if (scrollPos > 0 && idTopLeft.row > GetFixedRowCount())
- {
- int yScroll = GetRowHeight(idTopLeft.row-1);
- SetScrollPos32(SB_VERT, max(0, scrollPos - yScroll));
- rect.top = GetFixedRowHeight();
- ScrollWindow(0, yScroll, rect);
- rect.bottom = rect.top + yScroll;
- InvalidateRect(rect);
- }
- break;
- case SB_PAGEDOWN:
- if (scrollPos < m_nVScrollMax)
- {
- rect.top = GetFixedRowHeight();
- scrollPos = min(m_nVScrollMax, scrollPos + rect.Height());
- SetScrollPos32(SB_VERT, scrollPos);
- rect.top = GetFixedRowHeight();
- InvalidateRect(rect);
- }
- break;
- case SB_PAGEUP:
- if (scrollPos > 0)
- {
- rect.top = GetFixedRowHeight();
- int offset = -rect.Height();
- int pos = max(0, scrollPos + offset);
- SetScrollPos32(SB_VERT, pos);
- rect.top = GetFixedRowHeight();
- InvalidateRect(rect);
- }
- break;
- case SB_THUMBPOSITION:
- case SB_THUMBTRACK:
- {
- SetScrollPos32(SB_VERT, GetScrollPos32(SB_VERT, TRUE));
- CCellID idNewTopLeft = GetTopleftNonFixedCell();
- if (idNewTopLeft != idTopLeft)
- {
- rect.top = GetFixedRowHeight();
- InvalidateRect(rect);
- }
- }
- break;
- case SB_TOP:
- if (scrollPos > 0)
- {
- SetScrollPos32(SB_VERT, 0);
- Invalidate();
- }
- break;
- case SB_BOTTOM:
- if (scrollPos < m_nVScrollMax)
- {
- SetScrollPos32(SB_VERT, m_nVScrollMax);
- Invalidate();
- }
- default: break;
- }
- }
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl implementation functions
- void CGridCtrl::OnDraw(CDC* pDC)
- {
- CRect rect;
- int row,col;
- CRect clipRect;
- if (pDC->GetClipBox(&clipRect) == ERROR)
- return;
- EraseBkgnd(pDC); // OnEraseBkgnd does nothing, so erase bkgnd here.
- // This necessary since we may be using a Memory DC.
- int nFixedRowHeight = GetFixedRowHeight();
- int nFixedColWidth = GetFixedColumnWidth();
- CCellID idTopLeft = GetTopleftNonFixedCell();
- int minVisibleRow = idTopLeft.row,
- minVisibleCol = idTopLeft.col;
- CRect VisRect;
- CCellRange VisCellRange = GetVisibleNonFixedCellRange(VisRect);
- int maxVisibleRow = VisCellRange.GetMaxRow(),
- maxVisibleCol = VisCellRange.GetMaxCol();
- // draw top-left cells 0..m_nFixedRows-1, 0..m_nFixedCols-1
- rect.bottom = -1;
- for (row = 0; row < m_nFixedRows; row++)
- {
- rect.top = rect.bottom+1;
- rect.bottom = rect.top + GetRowHeight(row)-1;
- rect.right = -1;
- for (col = 0; col < m_nFixedCols; col++)
- {
- rect.left = rect.right+1;
- rect.right = rect.left + GetColumnWidth(col)-1;
-
- DrawFixedCell(pDC, row, col, rect);
- }
- }
-
- // draw fixed column cells: m_nFixedRows..n, 0..m_nFixedCols-1
- rect.bottom = nFixedRowHeight-1;
- for (row = minVisibleRow; row <= maxVisibleRow; row++)
- {
- rect.top = rect.bottom+1;
- rect.bottom = rect.top + GetRowHeight(row)-1;
- // rect.bottom = bottom pixel of previous row
- if (rect.top > clipRect.bottom)
- break; // Gone past cliprect
- if (rect.bottom < clipRect.top)
- continue; // Reached cliprect yet?
- rect.right = -1;
- for (col = 0; col < m_nFixedCols; col++)
- {
- rect.left = rect.right+1;
- rect.right = rect.left + GetColumnWidth(col)-1;
- if (rect.left > clipRect.right)
- break; // gone past cliprect
- if (rect.right < clipRect.left)
- continue; // Reached cliprect yet?
- DrawFixedCell(pDC, row, col, rect);
- }
- }
-
- // draw fixed row cells 0..m_nFixedRows, m_nFixedCols..n
- rect.bottom = -1;
- for (row = 0; row < m_nFixedRows; row++)
- {
- rect.top = rect.bottom+1;
- rect.bottom = rect.top + GetRowHeight(row)-1;
- // rect.bottom = bottom pixel of previous row
- if (rect.top > clipRect.bottom)
- break; // Gone past cliprect
- if (rect.bottom < clipRect.top)
- continue; // Reached cliprect yet?
- rect.right = nFixedColWidth-1;
- for (col = minVisibleCol; col <= maxVisibleCol; col++)
- {
- rect.left = rect.right+1;
- rect.right = rect.left + GetColumnWidth(col)-1;
- if (rect.left > clipRect.right)
- break; // gone past cliprect
- if (rect.right < clipRect.left)
- continue; // Reached cliprect yet?
- DrawFixedCell(pDC, row, col, rect);
- }
- }
-
- // draw rest of non-fixed cells
- rect.bottom = nFixedRowHeight-1;
- for (row = minVisibleRow; row <= maxVisibleRow; row++)
- {
- rect.top = rect.bottom+1;
- rect.bottom = rect.top + GetRowHeight(row)-1;
- // rect.bottom = bottom pixel of previous row
- if (rect.top > clipRect.bottom)
- break; // Gone past cliprect
- if (rect.bottom < clipRect.top)
- continue; // Reached cliprect yet?
- rect.right = nFixedColWidth-1;
- for (col = minVisibleCol; col <= maxVisibleCol; col++)
- {
- rect.left = rect.right+1;
- rect.right = rect.left + GetColumnWidth(col)-1;
- if (rect.left > clipRect.right)
- break; // gone past cliprect
- if (rect.right < clipRect.left)
- continue; // Reached cliprect yet?
- DrawCell(pDC, row, col, rect);
- }
- }
- CPen pen;
- TRY {
- pen.CreatePen(PS_SOLID, 0, m_crGridColour);
- }
- CATCH (CResourceException, e)
- {
- e->Delete();
- return;
- }
- END_CATCH
- pDC->SelectObject(&pen);
- // draw vertical lines (drawn at ends of cells)
- if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
- {
- int x = nFixedColWidth;
- for (col = minVisibleCol; col <= maxVisibleCol; col++) {
- x += GetColumnWidth(col);
- pDC->MoveTo(x-1, nFixedRowHeight);
- pDC->LineTo(x-1, VisRect.bottom);
- }
- }
-
- // draw horizontal lines (drawn at bottom of each cell)
- if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
- {
- int y = nFixedRowHeight;
- for (row = minVisibleRow; row <= maxVisibleRow; row++) {
- y += GetRowHeight(row);
- pDC->MoveTo(nFixedColWidth, y-1);
- pDC->LineTo(VisRect.right, y-1);
- }
- }
- pDC->SelectStockObject(NULL_PEN);
- #ifdef USE_MEMDC // Use a memDC for flicker free update
- }
- #else // Use normal DC - this helps in debugging
- }
- #endif
- ////////////////////////////////////////////////////////////////////////////////////////
- // CGridCtrl Cell selection stuff
- BOOL CGridCtrl::IsValid(int nRow, int nCol) const
- {
- return (nRow >= 0 && nRow < m_nRows && nCol >= 0 && nCol < m_nCols);
- }
- BOOL CGridCtrl::IsValid(const CCellID& cell) const
- {
- return IsValid(cell.row, cell.col);
- }
- BOOL CGridCtrl::IsValid(const CCellRange& range) const
- {
- return (range.GetMinRow() >= 0 && range.GetMinCol() >= 0 &&
- range.GetMaxRow() >= 0 && range.GetMaxCol() >= 0 &&
- range.GetMaxRow() < m_nRows && range.GetMaxCol() < m_nCols &&
- range.GetMinRow() <= range.GetMaxRow() && range.GetMinCol() <= range.GetMaxCol());
- }
- // Enables/Disables redraw for certain operations like columns auto-sizing etc,
- // but not for user caused things such as selection changes.
- void CGridCtrl::SetRedraw(BOOL bAllowDraw, BOOL bResetScrollBars /* = FALSE */)
- {
- TRACE(_T("%s: Setting redraw to %s\n"),
- GetRuntimeClass()->m_lpszClassName, bAllowDraw? _T("TRUE") : _T("FALSE"));
- if (bAllowDraw && !m_bAllowDraw)
- Invalidate();
- m_bAllowDraw = bAllowDraw;
- if (bResetScrollBars)
- ResetScrollBars();
- }
- // Forces a redraw of a cell immediately (using a direct DC construction,
- // or the supplied dc)
- BOOL CGridCtrl::RedrawCell(const CCellID& cell, CDC* pDC /* = NULL */)
- {
- return RedrawCell(cell.row, cell.col, pDC);
- }
- BOOL CGridCtrl::RedrawCell(int nRow, int nCol, CDC* pDC /* = NULL */)
- {
- BOOL bResult = TRUE;
- BOOL bMustReleaseDC = FALSE;
- if (!m_bAllowDraw || !IsCellVisible(nRow, nCol))
- return FALSE;
- CRect rect;
- if (!GetCellRect(nRow, nCol, rect))
- return FALSE;
- if (!pDC) {
- pDC = GetDC();
- if (pDC)
- bMustReleaseDC = TRUE;
- }
- if (pDC)
- {
- // Redraw cells directly
- if (nRow < m_nFixedRows || nCol < m_nFixedCols)
- {
- bResult = DrawFixedCell(pDC, nRow, nCol, rect, TRUE);
- }
- else
- {
- bResult = DrawCell(pDC, nRow, nCol, rect, TRUE);
-
- // Since we have erased the background, we will need to redraw the gridlines
- CPen pen;
- TRY {
- pen.CreatePen(PS_SOLID, 0, m_crGridColour);
- } CATCH (CException, e) {e->Delete();} END_CATCH
-
- CPen* pOldPen = (CPen*) pDC->SelectObject(&pen);
- if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
- {
- pDC->MoveTo(rect.left, rect.bottom);
- pDC->LineTo(rect.right+1, rect.bottom);
- }
- if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
- {
- pDC->MoveTo(rect.right, rect.top);
- pDC->LineTo(rect.right, rect.bottom+1);
- }
- pDC->SelectObject(pOldPen);
- }
- } else
- InvalidateRect(rect, TRUE); // Could not get a DC - invalidate it anyway
- // and hope that OnPaint manages to get one
- if (bMustReleaseDC)
- ReleaseDC(pDC);
- return bResult;
- }
- // redraw a complete row
- BOOL CGridCtrl::RedrawRow(int row)
- {
- BOOL bResult = TRUE;
- CDC* pDC = GetDC();
- for (int col = 0; col < GetColumnCount(); col++)
- bResult = RedrawCell(row, col, pDC) && bResult;
- if (pDC)
- ReleaseDC(pDC);
- return bResult;
- }
- // redraw a complete column
- BOOL CGridCtrl::RedrawColumn(int col)
- {
- BOOL bResult = TRUE;
- CDC* pDC = GetDC();
- for (int row = 0; row < GetRowCount(); row++)
- bResult = RedrawCell(row, col, pDC) && bResult;
- if (pDC)
- ReleaseDC(pDC);
- return bResult;
- }
- // Sets the currently selected cell, returning the previous current cell
- CCellID CGridCtrl::SetFocusCell(int nRow, int nCol)
- {
- return SetFocusCell(CCellID(nRow, nCol));
- }
- CCellID CGridCtrl::SetFocusCell(CCellID cell)
- {
- if (cell == m_idCurrentCell)
- return m_idCurrentCell;
- CCellID idPrev = m_idCurrentCell;
- m_idCurrentCell = cell;
- if (IsValid(idPrev))
- {
- SendMessageToParent(idPrev.row, idPrev.col, GVN_SELCHANGING);
- SetItemState(idPrev.row, idPrev.col,
- GetItemState(idPrev.row, idPrev.col) & ~GVIS_FOCUSED);
- RedrawCell(idPrev);
- if (idPrev.col != m_idCurrentCell.col)
- for (int row = 0; row < m_nFixedRows; row++)
- RedrawCell(row, idPrev.col);
- if (idPrev.row != m_idCurrentCell.row)
- for (int col = 0; col < m_nFixedCols; col++)
- RedrawCell(idPrev.row, col);
- }
- if (IsValid(m_idCurrentCell)) {
- SetItemState(m_idCurrentCell.row, m_idCurrentCell.col,
- GetItemState(m_idCurrentCell.row, m_idCurrentCell.col) | GVIS_FOCUSED);
- RedrawCell(m_idCurrentCell);
- if (idPrev.col != m_idCurrentCell.col)
- for (int row = 0; row < m_nFixedRows; row++)
- RedrawCell(row, m_idCurrentCell.col);
- if (idPrev.row != m_idCurrentCell.row)
- for (int col = 0; col < m_nFixedCols; col++)
- RedrawCell(m_idCurrentCell.row, col);
- SendMessageToParent(m_idCurrentCell.row, m_idCurrentCell.col, GVN_SELCHANGED);
- }
- return idPrev;
- }
- // Sets the range of currently selected cells
- void CGridCtrl::SetSelectedRange(const CCellRange& Range,
- BOOL bForceRepaint /* = FALSE */)
- {
- SetSelectedRange(Range.GetMinRow(), Range.GetMinCol(),
- Range.GetMaxRow(), Range.GetMaxCol(),
- bForceRepaint);
- }
- void CGridCtrl::SetSelectedRange(int nMinRow, int nMinCol, int nMaxRow, int nMaxCol,
- BOOL bForceRepaint /* = FALSE */)
- {
- if (!m_bEnableSelection) return;
- CDC* pDC = NULL;
- if (bForceRepaint) pDC = GetDC();
- // Unselect all previously selected cells
- for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
- {
- DWORD key;
- CCellID cell;
- m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
- // Reset the selection flag on the cell
- if (IsValid(cell)) {
- SetItemState(cell.row, cell.col,
- GetItemState(cell.row, cell.col) & ~GVIS_SELECTED);
- // If this is to be reselected, continue on past the redraw
- if (nMinRow <= cell.row && cell.row <= nMaxRow &&
- nMinCol <= cell.col && cell.col <= nMaxCol)
- continue;
- if (bForceRepaint && pDC) // Redraw NOW
- RedrawCell(cell.row, cell.col, pDC);
- else
- InvalidateCellRect(cell); // Redraw at leisure
- }
- }
-
- // if any previous selected cells are to be retained (eg Ctrl is being held down)
- // then copy them to the newly created list, and mark all these cells as
- // selected
- if (!GetSingleRowSelection())
- for (pos = m_PrevSelectedCellMap.GetStartPosition(); pos != NULL; /* nothing */)
- {
- DWORD key;
- CCellID cell;
- m_PrevSelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
- if (!IsValid(cell))
- continue;
- int nState = GetItemState(cell.row, cell.col);
- // Set state as Selected. This will add the cell to m_SelectedCells[]
- SetItemState(cell.row, cell.col, nState | GVIS_SELECTED);
- // Redraw (immediately or at leisure)
- if (bForceRepaint && pDC)
- RedrawCell(cell.row, cell.col, pDC);
- else
- InvalidateCellRect(cell);
- }
- // Now select all cells in the cell range specified. If the cell has already
- // been marked as selected (above) then ignore it.
- if (nMinRow >= 0 && nMinCol >= 0 && nMaxRow >= 0 && nMaxCol >= 0 &&
- nMaxRow < m_nRows && nMaxCol < m_nCols &&
- nMinRow <= nMaxRow && nMinCol <= nMaxCol)
- {
- for (int row = nMinRow; row <= nMaxRow; row++)
- for (int col = nMinCol; col <= nMaxCol; col++)
- {
- int nState = GetItemState(row, col);
- if (nState & GVIS_SELECTED)
- continue; // Already selected - ignore
- // Add to list of selected cells
- CCellID cell(row, col);
- // Set state as Selected. This will add the cell to m_SelectedCells[]
- SetItemState(row, col, nState | GVIS_SELECTED);
- // Redraw (immediately or at leisure)
- if (bForceRepaint && pDC)
- RedrawCell(row, col, pDC);
- else
- InvalidateCellRect(cell);
- }
- }
- // TRACE(_T("%d cells selected.\n"), m_SelectedCellMap.GetCount());
- if (pDC != NULL)
- ReleaseDC(pDC);
- }
- // selects all cells
- void CGridCtrl::SelectAllCells()
- {
- if (!m_bEnableSelection)
- return;
- SetSelectedRange(m_nFixedRows, m_nFixedCols, GetRowCount()-1, GetColumnCount()-1);
- }
- // selects columns
- void CGridCtrl::SelectColumns(CCellID currentCell)
- {
- if (!m_bEnableSelection)
- return;
- //if (currentCell.col == m_idCurrentCell.col) return;
- if (currentCell.col < m_nFixedCols)
- return;
- if (!IsValid(currentCell))
- return;
- SetSelectedRange(GetFixedRowCount(),
- min(m_SelectionStartCell.col, currentCell.col),
- GetRowCount()-1,
- max(m_SelectionStartCell.col, currentCell.col));
- }
- // selects rows
- void CGridCtrl::SelectRows(CCellID currentCell)
- {
- if (!m_bEnableSelection)
- return;
- //if (currentCell.row; == m_idCurrentCell.row) return;
- if (currentCell.row < m_nFixedRows)
- return;
- if (!IsValid(currentCell))
- return;
- if (GetListMode() && GetSingleRowSelection())
- SetSelectedRange(currentCell.row, GetFixedColumnCount(),
- currentCell.row, GetColumnCount()-1);
- else
- SetSelectedRange(min(m_SelectionStartCell.row, currentCell.row),
- GetFixedColumnCount(),
- max(m_SelectionStartCell.row, currentCell.row),
- GetColumnCount()-1);
- }
- // selects cells
- void CGridCtrl::SelectCells(CCellID currentCell)
- {
- if (!m_bEnableSelection)
- return;
- int row = currentCell.row;
- int col = currentCell.col;
- if (row < m_nFixedRows || col < m_nFixedCols)
- return;
- if (!IsValid(currentCell))
- return;
- // Prevent unnecessary redraws
- //if (currentCell == m_LeftClickDownCell) return;
- //else if (currentCell == m_idCurrentCell) return;
- SetSelectedRange(min(m_SelectionStartCell.row, row),
- min(m_SelectionStartCell.col, col),
- max(m_SelectionStartCell.row, row),
- max(m_SelectionStartCell.col, col));
- }
- void CGridCtrl::OnSelecting(const CCellID& currentCell)
- {
- if (!m_bEnableSelection)
- return;
- switch(m_MouseMode)
- {
- case MOUSE_SELECT_ALL: SelectAllCells(); break;
- case MOUSE_SELECT_COL: SelectColumns(currentCell); break;
- case MOUSE_SELECT_ROW: SelectRows(currentCell); break;
- case MOUSE_SELECT_CELLS: SelectCells(currentCell); break;
- }
- }
- #ifndef GRIDCONTROL_NO_CLIPBOARD
- ////////////////////////////////////////////////////////////////////////////////////////
- // Clipboard functions
- void CGridCtrl::CutSelectedText()
- {
- if (!IsEditable())
- return;
- // Clear contents of selected cells.
- for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
- {
- DWORD key;
- CCellID cell;
- m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
- if (!IsCellEditable(cell))
- continue;
- CGridCell* pCell = GetCell(cell.row, cell.col);
- if (pCell)
- {
- SendMessageToParent(cell.row, cell.col, GVN_BEGINLABELEDIT);
- EmptyCell(pCell, cell.row, cell.col);
- SetModified(TRUE, cell.row, cell.col);
- SendMessageToParent(cell.row, cell.col, GVN_ENDLABELEDIT);
- }
- }
- Invalidate();
- }
- COleDataSource* CGridCtrl::CopyTextFromGrid()
- {
- USES_CONVERSION;
- CCellRange Selection = GetSelectedCellRange();
- if (!IsValid(Selection)) return NULL;
- // Write to shared file (REMEBER: CF_TEXT is ANSI, not UNICODE, so we need to convert)
- CSharedFile sf(GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT);
- // Get a tab delimited string to copy to cache
- CString str;
- CGridCell *pCell;
- for (int row = Selection.GetMinRow(); row <= Selection.GetMaxRow(); row++)
- {
- str.Empty();
- for (int col = Selection.GetMinCol(); col <= Selection.GetMaxCol(); col++)
- {
- pCell = GetCell(row,col);
- if (pCell && (pCell->state & GVIS_SELECTED))
- {
- if (pCell->szText.IsEmpty())
- str += _T(" ");
- else
- str += pCell->szText;
- }
- if (col != Selection.GetMaxCol())
- str += _T("\t");
- }
- if (row != Selection.GetMaxRow())
- str += _T("\n");
- sf.Write(T2A(str.GetBuffer(1)), str.GetLength());
- str.ReleaseBuffer();
- }
- char c = '\0';
- sf.Write(&c, 1);
- DWORD dwLen = sf.GetLength();
- HGLOBAL hMem = sf.Detach();
- if (!hMem)
- return NULL;
- hMem = ::GlobalReAlloc(hMem, dwLen, GMEM_MOVEABLE|GMEM_DDESHARE|GMEM_ZEROINIT);
- if (!hMem)
- return NULL;
- // Cache data
- COleDataSource* pSource = new COleDataSource();
- pSource->CacheGlobalData(CF_TEXT, hMem);
- return pSource;
- }
- BOOL CGridCtrl::PasteTextToGrid(CCellID cell, COleDataObject* pDataObject)
- {
- if (!IsValid(cell) || !IsCellEditable(cell) || !pDataObject->IsDataAvailable(CF_TEXT))
- return FALSE;
- // Get the text from the COleDataObject
- HGLOBAL hmem = pDataObject->GetGlobalData(CF_TEXT);
- CMemFile sf((BYTE*) ::GlobalLock(hmem), ::GlobalSize(hmem));
- // CF_TEXT is ANSI text, so we need to allocate a char* buffer
- // to hold this.
- LPSTR szBuffer = new char[::GlobalSize(hmem)];
- if (!szBuffer)
- return FALSE;
- sf.Read(szBuffer, ::GlobalSize(hmem));
- ::GlobalUnlock(hmem);
- // Now store in generic TCHAR form so we no longer have to deal with
- // ANSI/UNICODE problems
- CString strText = szBuffer;
- delete szBuffer;
- // Parse text data and set in cells...
- strText.LockBuffer();
- CString strLine = strText;
- int nLine = 0;
- // Find the end of the first line
- int nIndex;
- do {
- int nColumn = 0;
- nIndex = strLine.Find(_T("\n"));
- // Store the remaining chars after the newline
- CString strNext = (nIndex < 0)? _T("") : strLine.Mid(nIndex+1);
- // Remove all chars after the newline
- if (nIndex >= 0)
- strLine = strLine.Left(nIndex);
- // Make blank entries a "space"
- if (strLine.IsEmpty() && nIndex >= 0)
- strLine = _T(" ");
- LPTSTR szLine = strLine.GetBuffer(1);
- // Break the current line into tokens (tab or comma delimited)
- LPTSTR pszCellText = _tcstok(szLine, _T("\t,\n"));
- while (pszCellText != NULL)
- {
- CCellID TargetCell(cell.row + nLine, cell.col + nColumn);
- if (IsValid(TargetCell))
- {
- CString strCellText = pszCellText;
- strCellText.TrimLeft(); strCellText.TrimRight();
- SendMessageToParent(TargetCell.row, TargetCell.col, GVN_BEGINLABELEDIT);
- SetItemText(TargetCell.row, TargetCell.col, strCellText);
- SetModified(TRUE, TargetCell.row, TargetCell.col);
- SendMessageToParent(TargetCell.row, TargetCell.col, GVN_ENDLABELEDIT);
- // Make sure cell is not selected to avoid data loss
- SetItemState(TargetCell.row, TargetCell.col,
- GetItemState(TargetCell.row, TargetCell.col) & ~GVIS_SELECTED);
- }
- pszCellText = _tcstok(NULL, _T("\t,\n"));
- nColumn++;
- }
- strLine.ReleaseBuffer();
- strLine = strNext;
- nLine++;
- } while (nIndex >= 0);
- strText.UnlockBuffer();
- Invalidate();
- return TRUE;
- }
- #endif
- #ifndef GRIDCONTROL_NO_DRAGDROP
- void CGridCtrl::OnBeginDrag()
- {
- if (!m_bAllowDragAndDrop) return;
- COleDataSource* pSource = CopyTextFromGrid();
- if (pSource)
- {
- SendMessageToParent(GetSelectedCellRange().GetTopLeft().row,
- GetSelectedCellRange().GetTopLeft().col,
- GVN_BEGINDRAG);
- m_MouseMode = MOUSE_DRAGGING;
- DROPEFFECT dropEffect = pSource->DoDragDrop(DROPEFFECT_COPY|DROPEFFECT_MOVE);
- if (dropEffect & DROPEFFECT_MOVE)
- CutSelectedText();
- if (pSource)
- delete pSource; // Did not pass source to clipboard, so must delete
- }
- }
- DROPEFFECT CGridCtrl::OnDragOver(COleDataObject* pDataObject, DWORD dwKeyState,
- CPoint point)
- {
- // Any text data available for us?
- if (!m_bAllowDragAndDrop || !IsEditable() || !pDataObject->IsDataAvailable(CF_TEXT))
- return DROPEFFECT_NONE;
- // Find which cell we are over and drop-highlight it
- CCellID cell = GetCellFromPt(point, FALSE);
- // If not valid, set the previously drop-highlighted cell as no longer drop-highlighted
- if (!IsValid(cell))
- {
- OnDragLeave();
- m_LastDragOverCell = CCellID(-1,-1);
- return DROPEFFECT_NONE;
- }
- if (!IsCellEditable(cell))
- return DROPEFFECT_NONE;
- // Have we moved over a different cell than last time?
- if (cell != m_LastDragOverCell)
- {
- // Set the previously drop-highlighted cell as no longer drop-highlighted
- if (IsValid(m_LastDragOverCell)) {
- UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
- SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
- nState & ~GVIS_DROPHILITED);
- RedrawCell(m_LastDragOverCell);
- }
- m_LastDragOverCell = cell;
- // Set the new cell as drop-highlighted
- if (IsValid(m_LastDragOverCell)) {
- UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
- SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
- nState | GVIS_DROPHILITED);
- RedrawCell(m_LastDragOverCell);
- }
- }
- // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
- if (dwKeyState & MK_CONTROL)
- return DROPEFFECT_COPY;
- else
- return DROPEFFECT_MOVE;
- }
- DROPEFFECT CGridCtrl::OnDragEnter(COleDataObject* pDataObject, DWORD dwKeyState,
- CPoint point)
- {
- // Any text data available for us?
- if (!m_bAllowDragAndDrop || !pDataObject->IsDataAvailable(CF_TEXT))
- return DROPEFFECT_NONE;
- // Find which cell we are over and drop-highlight it
- m_LastDragOverCell = GetCellFromPt(point, FALSE);
- if (!IsValid(m_LastDragOverCell))
- return DROPEFFECT_NONE;
- if (!IsCellEditable(m_LastDragOverCell))
- return DROPEFFECT_NONE;
- if (IsValid(m_LastDragOverCell))
- {
- UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
- SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
- nState | GVIS_DROPHILITED);
- RedrawCell(m_LastDragOverCell);
- }
- // Return an appropraite value of DROPEFFECT so mouse cursor is set properly
- if (dwKeyState & MK_CONTROL)
- return DROPEFFECT_COPY;
- else
- return DROPEFFECT_MOVE;
- }
- void CGridCtrl::OnDragLeave()
- {
- // Set the previously drop-highlighted cell as no longer drop-highlighted
- if (IsValid(m_LastDragOverCell)) {
- UINT nState = GetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col);
- SetItemState(m_LastDragOverCell.row, m_LastDragOverCell.col,
- nState & ~GVIS_DROPHILITED);
- RedrawCell(m_LastDragOverCell);
- }
- }
- BOOL CGridCtrl::OnDrop(COleDataObject* pDataObject, DROPEFFECT /*dropEffect*/,
- CPoint /* point */)
- {
- BOOL bResult = FALSE;
- if (!m_bAllowDragAndDrop || !IsCellEditable(m_LastDragOverCell))
- return bResult;
- m_MouseMode = MOUSE_NOTHING;
- OnDragLeave();
- return PasteTextToGrid(m_LastDragOverCell, pDataObject);
- }
- #endif
- #ifndef GRIDCONTROL_NO_CLIPBOARD
- void CGridCtrl::OnEditCut()
- {
- if (!IsEditable())
- return;
- COleDataSource* pSource = CopyTextFromGrid();
- if (!pSource) return;
- pSource->SetClipboard();
- CutSelectedText();
- }
- void CGridCtrl::OnEditCopy()
- {
- COleDataSource* pSource = CopyTextFromGrid();
- if (!pSource) return;
- pSource->SetClipboard();
- }
- void CGridCtrl::OnEditPaste()
- {
- if (!IsEditable())
- return;
- // Get the Focus cell, or if none, get the topleft (non-fixed) cell
- CCellID cell = GetFocusCell();
- if (!IsValid(cell)) cell = GetTopleftNonFixedCell();
- if (!IsValid(cell)) return;
- // Attach a COleDataObject to the clipboard and paste the data to the grid
- COleDataObject obj;
- if (obj.AttachClipboard())
- PasteTextToGrid(cell, &obj);
- }
- #endif
- void CGridCtrl::OnEditSelectAll()
- {
- SelectAllCells();
- }
- #ifndef GRIDCONTROL_NO_CLIPBOARD
- void CGridCtrl::OnUpdateEditCopy(CCmdUI* pCmdUI)
- {
- CCellRange Selection = GetSelectedCellRange();
- pCmdUI->Enable(Selection.Count() && IsValid(Selection));
- }
- void CGridCtrl::OnUpdateEditCut(CCmdUI* pCmdUI)
- {
- CCellRange Selection = GetSelectedCellRange();
- pCmdUI->Enable(IsEditable() && Selection.Count() && IsValid(Selection));
- }
- void CGridCtrl::OnUpdateEditPaste(CCmdUI* pCmdUI)
- {
- CCellID cell = GetFocusCell();
- BOOL bCanPaste = IsValid(cell) && IsCellEditable(cell) &&
- ::IsClipboardFormatAvailable(CF_TEXT);
- pCmdUI->Enable(bCanPaste);
- }
- #endif
- void CGridCtrl::OnUpdateEditSelectAll(CCmdUI* pCmdUI)
- {
- pCmdUI->Enable(m_bEnableSelection);
- }
- ////////////////////////////////////////////////////////////////////////////////////////
- // hittest-like functions
- BOOL CGridCtrl::MouseOverRowResizeArea(CPoint& point) const
- {
- if (point.x >= GetFixedColumnWidth())
- return FALSE;
-
- CCellID idCurrentCell = GetCellFromPt(point);
- CPoint start;
- if (!GetCellOrigin(idCurrentCell, &start))
- return FALSE;
-
- int endy = start.y + GetRowHeight(idCurrentCell.row);
-
- if ((point.y - start.y <= m_nResizeCaptureRange && idCurrentCell.row != 0) ||
- endy - point.y <= m_nResizeCaptureRange)
- {
- return TRUE;
- }
- else
- return FALSE;
- }
- BOOL CGridCtrl::MouseOverColumnResizeArea(CPoint& point) const
- {
- if (point.y >= GetFixedRowHeight())
- return FALSE;
-
- CCellID idCurrentCell = GetCellFromPt(point);
- CPoint start;
- if (!GetCellOrigin(idCurrentCell, &start))
- return FALSE;
-
- int endx = start.x + GetColumnWidth(idCurrentCell.col);
-
- if ((point.x - start.x <= m_nResizeCaptureRange && idCurrentCell.col != 0) ||
- endx - point.x <= m_nResizeCaptureRange)
- {
- return TRUE;
- }
- else
- return FALSE;
- }
- // Get cell from point
- CCellID CGridCtrl::GetCellFromPt(CPoint point, BOOL bAllowFixedCellCheck /*=TRUE*/) const
- {
- CCellID idTopLeft = GetTopleftNonFixedCell();
- CCellID cellID; // return value
- // calculate column index
- int fixedColWidth = GetFixedColumnWidth();
- if (point.x < 0 || (!bAllowFixedCellCheck && point.x < fixedColWidth)) // not in window
- cellID.col = -1;
- else if (point.x < fixedColWidth) // in fixed col
- {
- int xpos = 0;
- for (int col = 0; col < m_nFixedCols; col++)
- {
- xpos += GetColumnWidth(col);
- if (xpos > point.x) break;
- }
- cellID.col = col;
- }
- else // in non-fixed col
- {
- int xpos = fixedColWidth;
- for (int col = idTopLeft.col; col < GetColumnCount(); col++)
- {
- xpos += GetColumnWidth(col);
- if (xpos > point.x) break;
- }
- if (col >= GetColumnCount())
- cellID.col = -1;
- else
- cellID.col = col;
- }
-
- // calculate row index
- int fixedRowHeight = GetFixedRowHeight();
- if (point.y < 0 || (!bAllowFixedCellCheck && point.y < fixedRowHeight)) // not in window
- cellID.row = -1;
- else if (point.y < fixedRowHeight) // in fixed col
- {
- int ypos = 0;
- for (int row = 0; row < m_nFixedRows; row++)
- {
- ypos += GetRowHeight(row);
- if (ypos > point.y) break;
- }
- cellID.row = row;
- }
- else
- {
- int ypos = fixedRowHeight;
- for (int row = idTopLeft.row; row < GetRowCount(); row++)
- {
- ypos += GetRowHeight(row);
- if (ypos > point.y) break;
- }
- if (row >= GetRowCount())
- cellID.row = -1;
- else
- cellID.row = row;
- }
- return cellID;
- }
- ////////////////////////////////////////////////////////////////////////////////
- // CGridCtrl cellrange functions
- CCellID CGridCtrl::GetTopleftNonFixedCell() const
- {
- int nVertScroll = GetScrollPos(SB_VERT),
- nHorzScroll = GetScrollPos(SB_HORZ);
- int nColumn = m_nFixedCols, nRight = 0;
- while (nRight < nHorzScroll && nColumn < (GetColumnCount()-1))
- nRight += GetColumnWidth(nColumn++);
- int nRow = m_nFixedRows, nTop = 0;
- while (nTop < nVertScroll && nRow < (GetRowCount()-1))
- nTop += GetRowHeight(nRow++);
- //TRACE("TopLeft cell is row %d, col %d\n",nRow, nColumn);
- return CCellID(nRow, nColumn);
- }
- // This gets even partially visible cells
- CCellRange CGridCtrl::GetVisibleNonFixedCellRange(LPRECT pRect /*=NULL*/) const
- {
- CRect rect;
- GetClientRect(rect);
- CCellID idTopLeft = GetTopleftNonFixedCell();
- // calc bottom
- int bottom = GetFixedRowHeight();
- for (int i = idTopLeft.row; i < GetRowCount(); i++)
- {
- bottom += GetRowHeight(i);
- if (bottom >= rect.bottom) {
- bottom = rect.bottom;
- break;
- }
- }
- int maxVisibleRow = min(i, GetRowCount() - 1);
-
- // calc right
- int right = GetFixedColumnWidth();
- for (i = idTopLeft.col; i < GetColumnCount(); i++)
- {
- right += GetColumnWidth(i);
- if (right >= rect.right) {
- right = rect.right;
- break;
- }
- }
- int maxVisibleCol = min(i, GetColumnCount() - 1);
- if (pRect) {
- pRect->left = pRect->top = 0;
- pRect->right = right;
- pRect->bottom = bottom;
- }
- return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
- }
- // used by ResetScrollBars() - This gets only fully visible cells
- CCellRange CGridCtrl::GetUnobstructedNonFixedCellRange() const
- {
- CRect rect;
- GetClientRect(rect);
- CCellID idTopLeft = GetTopleftNonFixedCell();
- // calc bottom
- int bottom = GetFixedRowHeight();
- for (int i = idTopLeft.row; i < GetRowCount(); i++)
- {
- bottom += GetRowHeight(i);
- if (bottom >= rect.bottom) break;
- }
- int maxVisibleRow = min(i, GetRowCount() - 1);
- if (maxVisibleRow > 0 && bottom > rect.bottom) maxVisibleRow--;
-
- // calc right
- int right = GetFixedColumnWidth();
- for (i = idTopLeft.col; i < GetColumnCount(); i++)
- {
- right += GetColumnWidth(i);
- if (right >= rect.right) break;
- }
- int maxVisibleCol = min(i, GetColumnCount() - 1);
- if (maxVisibleCol > 0 && right > rect.right) maxVisibleCol--;
- return CCellRange(idTopLeft.row, idTopLeft.col, maxVisibleRow, maxVisibleCol);
- }
- // Returns the minimum bounding range of the current selection
- // If no selection, then the returned CCellRange will be invalid
- CCellRange CGridCtrl::GetSelectedCellRange() const
- {
- CCellRange Selection(GetRowCount(), GetColumnCount(), -1,-1);
- for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
- {
- DWORD key;
- CCellID cell;
- m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
- Selection.SetMinRow( min(Selection.GetMinRow(), cell.row) );
- Selection.SetMinCol( min(Selection.GetMinCol(), cell.col) );
- Selection.SetMaxRow( max(Selection.GetMaxRow(), cell.row) );
- Selection.SetMaxCol( max(Selection.GetMaxCol(), cell.col) );
- }
- return Selection;
- }
- // Returns ALL the cells in the grid
- CCellRange CGridCtrl::GetCellRange() const
- {
- return CCellRange(0, 0, GetRowCount() - 1, GetColumnCount() - 1);
- }
- void CGridCtrl::ResetSelectedRange()
- {
- SetSelectedRange(-1,-1,-1,-1);
- SetFocusCell(-1,-1);
- }
- // Get/Set scroll position using 32 bit functions
- int CGridCtrl::GetScrollPos32(int nBar, BOOL bGetTrackPos /* = FALSE */)
- {
- SCROLLINFO si;
- si.cbSize = sizeof(SCROLLINFO);
- if (bGetTrackPos)
- {
- if (GetScrollInfo(nBar, &si, SIF_TRACKPOS))
- return si.nTrackPos;
- }
- else
- {
- if (GetScrollInfo(nBar, &si, SIF_POS))
- return si.nPos;
- }
- return 0;
- }
- BOOL CGridCtrl::SetScrollPos32(int nBar, int nPos, BOOL bRedraw /* = TRUE */)
- {
- SCROLLINFO si;
- si.cbSize = sizeof(SCROLLINFO);
- si.fMask = SIF_POS;
- si.nPos = nPos;
- return SetScrollInfo(nBar, &si, bRedraw);
- }
- void CGridCtrl::ResetScrollBars()
- {
- if (!m_bAllowDraw || !::IsWindow(GetSafeHwnd()))
- return;
- CRect rect;
- GetClientRect(rect);
- rect.left += GetFixedColumnWidth();
- rect.top += GetFixedRowHeight();
- if (rect.left >= rect.right || rect.top >= rect.bottom) return;
- CRect VisibleRect(GetFixedColumnWidth(), GetFixedRowHeight(), rect.right, rect.bottom);
- CRect VirtualRect(GetFixedColumnWidth(), GetFixedRowHeight(), GetVirtualWidth(), GetVirtualHeight());
- CCellRange visibleCells = GetUnobstructedNonFixedCellRange();
- if (!IsValid(visibleCells)) return;
- SCROLLINFO si;
- si.cbSize = sizeof(SCROLLINFO);
- si.fMask = SIF_PAGE;
- si.nPage = VisibleRect.Width(); SetScrollInfo(SB_HORZ, &si, FALSE);
- si.nPage = VisibleRect.Height(); SetScrollInfo(SB_VERT, &si, FALSE);
- if (VisibleRect.Height() < VirtualRect.Height())
- m_nVScrollMax = VirtualRect.Height()-1; //+ GetRowHeight(visibleCells.GetTopLeft().row);
- else
- m_nVScrollMax = 0;
- if (VisibleRect.Width() < VirtualRect.Width())
- m_nHScrollMax = VirtualRect.Width()-1; //+ GetColumnWidth(visibleCells.GetTopLeft().col);
- else
- m_nHScrollMax = 0;
- ASSERT(m_nVScrollMax < INT_MAX && m_nHScrollMax < INT_MAX); // This should be fine :)
- SetScrollRange(SB_VERT, 0, m_nVScrollMax, TRUE);
- SetScrollRange(SB_HORZ, 0, m_nHScrollMax, TRUE);
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // Row/Column position functions
- // returns the top left point of the cell. Returns FALSE if cell not visible.
- BOOL CGridCtrl::GetCellOrigin(int nRow, int nCol, LPPOINT p) const
- {
- int i;
- if (!IsValid(nRow, nCol)) return FALSE;
- CCellID idTopLeft;
- if (nCol >= m_nFixedCols || nRow >= m_nFixedRows)
- idTopLeft = GetTopleftNonFixedCell();
- if ((nRow >= m_nFixedRows && nRow < idTopLeft.row) ||
- (nCol>= m_nFixedCols && nCol < idTopLeft.col))
- return FALSE;
- p->x = 0;
- if (nCol < m_nFixedCols) // is a fixed column
- for (i = 0; i < nCol; i++)
- p->x += GetColumnWidth(i);
- else { // is a scrollable data column
- for (i = 0; i < m_nFixedCols; i++)
- p->x += GetColumnWidth(i);
- for (i = idTopLeft.col; i < nCol; i++)
- p->x += GetColumnWidth(i);
- }
- p->y = 0;
- if (nRow < m_nFixedRows) // is a fixed row
- for (i = 0; i < nRow; i++)
- p->y += GetRowHeight(i);
- else { // is a scrollable data row
- for (i = 0; i < m_nFixedRows; i++)
- p->y += GetRowHeight(i);
- for (i = idTopLeft.row; i < nRow; i++)
- p->y += GetRowHeight(i);
- }
- return TRUE;
- }
- BOOL CGridCtrl::GetCellOrigin(const CCellID& cell, LPPOINT p) const
- {
- return GetCellOrigin(cell.row, cell.col, p);
- }
- // Returns the bounding box of the cell
- BOOL CGridCtrl::GetCellRect(const CCellID& cell, LPRECT pRect) const
- {
- return GetCellRect(cell.row, cell.col, pRect);
- }
- BOOL CGridCtrl::GetCellRect(int nRow, int nCol, LPRECT pRect) const
- {
- CPoint CellOrigin;
- if (!GetCellOrigin(nRow, nCol, &CellOrigin)) return FALSE;
- pRect->left = CellOrigin.x;
- pRect->top = CellOrigin.y;
- pRect->right = CellOrigin.x + GetColumnWidth(nCol)-1;
- pRect->bottom = CellOrigin.y + GetRowHeight(nRow)-1;
- //TRACE("Row %d, col %d: L %d, T %d, W %d, H %d: %d,%d - %d,%d\n",
- // nRow,nCol, CellOrigin.x, CellOrigin.y, GetColumnWidth(nCol), GetRowHeight(nRow),
- // pRect->left, pRect->top, pRect->right, pRect->bottom);
- return TRUE;
- }
- BOOL CGridCtrl::GetTextRect(const CCellID& cell, LPRECT pRect)
- {
- return GetTextRect(cell.row, cell.col, pRect);
- }
- BOOL CGridCtrl::GetTextRect(int nRow, int nCol, LPRECT pRect)
- {
- GV_ITEM Item;
- Item.mask = GVIF_IMAGE;
- Item.row = nRow;
- Item.col = nCol;
- if (!GetItem(&Item))
- return FALSE;
- if (!GetCellRect(nRow, nCol, pRect))
- return FALSE;
- //pRect->left += m_nMargin;
- //pRect->right -= m_nMargin;
- if (m_pImageList && Item.iImage >= 0) {
- IMAGEINFO Info;
- if (m_pImageList->GetImageInfo(Item.iImage, &Info)) {
- int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
- pRect->left += nImageWidth+m_nMargin;
- }
- }
- return TRUE;
- }
- // Returns the bounding box of a range of cells
- BOOL CGridCtrl::GetCellRangeRect(const CCellRange& cellRange, LPRECT lpRect) const
- {
- CPoint MinOrigin,MaxOrigin;
- if (!GetCellOrigin(cellRange.GetMinRow(), cellRange.GetMinCol(), &MinOrigin))
- return FALSE;
- if (!GetCellOrigin(cellRange.GetMaxRow(), cellRange.GetMaxCol(), &MaxOrigin))
- return FALSE;
- lpRect->left = MinOrigin.x;
- lpRect->top = MinOrigin.y;
- lpRect->right = MaxOrigin.x + GetColumnWidth(cellRange.GetMaxCol()-1);
- lpRect->bottom = MaxOrigin.y + GetRowHeight(cellRange.GetMaxRow()-1);
- return TRUE;
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // Grid attribute functions
- LRESULT CGridCtrl::OnSetFont(WPARAM hFont, LPARAM /*lParam */)
- {
- LRESULT result = Default();
- // Get the logical font
- LOGFONT lf;
- if (!GetObject((HFONT) hFont, sizeof(LOGFONT), &lf))
- return result;
-
- // Store font as the global default
- memcpy(&m_Logfont, &lf, sizeof(LOGFONT));
-
- // reset all cells' fonts
- for (int row = 0; row < GetRowCount(); row++)
- for (int col = 0; col < GetColumnCount(); col++)
- SetItemFont(row, col, &lf);
- // Get the font size and hence the default cell size
- CDC* pDC = GetDC();
- if (pDC)
- {
- m_Font.DeleteObject();
- m_Font.CreateFontIndirect(&m_Logfont);
- CFont* pOldFont = pDC->SelectObject(&m_Font);
-
- TEXTMETRIC tm;
- pDC->GetTextMetrics(&tm);
-
- m_nMargin = pDC->GetTextExtent(_T(" "),1).cx;
- pDC->SelectObject(pOldFont);
- ReleaseDC(pDC);
- m_nDefCellHeight = tm.tmHeight+tm.tmExternalLeading + 2*m_nMargin;
- m_nDefCellWidth = tm.tmAveCharWidth*12 + 2*m_nMargin;
- }
- if (::IsWindow(GetSafeHwnd()))
- Invalidate();
- return result;
- }
- LRESULT CGridCtrl::OnGetFont(WPARAM /*wParam*/, LPARAM /*lParam*/)
- {
- return (LRESULT) (HFONT) m_Font;
- }
- #ifndef _WIN32_WCE_NO_CURSOR
- BOOL CGridCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
- {
- if (nHitTest == HTCLIENT)
- {
- switch (m_MouseMode)
- {
- case MOUSE_OVER_COL_DIVIDE: SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE)); break;
- case MOUSE_OVER_ROW_DIVIDE: SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS)); break;
- #ifndef GRIDCONTROL_NO_DRAGDROP
- case MOUSE_DRAGGING: break;
- #endif
- default: SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
- }
- return TRUE;
- }
- return CWnd::OnSetCursor(pWnd, nHitTest, message);
- }
- #endif
- ////////////////////////////////////////////////////////////////////////////////////
- // Row/Column count functions
- BOOL CGridCtrl::SetFixedRowCount(int nFixedRows)
- {
- ASSERT(nFixedRows >= 0);
- if (nFixedRows > GetRowCount())
- if (!SetRowCount(nFixedRows)) return FALSE;
- if (m_idCurrentCell.row < nFixedRows)
- SetFocusCell(-1,-1);
- m_nFixedRows = nFixedRows;
- if (GetSafeHwnd() && m_bAllowDraw)
- Invalidate();
- return TRUE;
- }
- BOOL CGridCtrl::SetFixedColumnCount(int nFixedCols)
- {
- ASSERT(nFixedCols >= 0);
- if (nFixedCols > GetColumnCount())
- if (!SetColumnCount(nFixedCols)) return FALSE;
- if (m_idCurrentCell.col < nFixedCols)
- SetFocusCell(-1,-1);
- m_nFixedCols = nFixedCols;
- if (GetSafeHwnd() && m_bAllowDraw)
- Invalidate();
- return TRUE;
- }
- BOOL CGridCtrl::SetRowCount(int nRows)
- {
- ASSERT(nRows >= 0);
- if (nRows == GetRowCount()) return TRUE;
- if (nRows < m_nFixedRows)
- m_nFixedRows = nRows;
- if (m_idCurrentCell.row >= nRows)
- SetFocusCell(-1,-1);
- int addedRows = nRows - GetRowCount();
- // If we are about to lose rows, then we need to delete the GridCell objects
- // in each column within each row
- if (addedRows < 0) {
- for (int row = nRows; row < m_nRows; row++)
- {
- // Delete cells
- for (int col = 0; col < m_nCols; col++)
- {
- CGridCell* pCell = GetCell(row, col);
- if (pCell) {
- EmptyCell(pCell, row, col);
- delete pCell;
- }
- }
- // Delete rows
- GRID_ROW* pRow = m_RowData[row];
- if (pRow) delete pRow;
- }
- }
- // Change the number of rows.
- m_nRows = nRows;
- m_RowData.SetSize(m_nRows);
- m_arRowHeights.SetSize(nRows);
- // If we have just added rows, we need to construct new elements for each cell
- // and set the default row height
- if (addedRows > 0) {
- // initialize row heights and data
- int startRow = nRows - addedRows;
- for (int row = startRow; row < GetRowCount(); row++) {
- m_arRowHeights[row] = m_nDefCellHeight;
- m_RowData[row] = new GRID_ROW;
- m_RowData[row]->SetSize(m_nCols);
- for (int col = 0; col < m_nCols; col++)
- {
- GRID_ROW* pRow = m_RowData[row];
- if (pRow) pRow->SetAt(col, CreateCell(row, col));
- }
- }
- }
- //else
- // ResetSelectedRange();
-
- if (GetSafeHwnd() && m_bAllowDraw)
- {
- ResetScrollBars();
- Invalidate();
- }
- return TRUE;
- }
- BOOL CGridCtrl::SetColumnCount(int nCols)
- {
- ASSERT(nCols >= 0);
- if (nCols == GetColumnCount()) return TRUE;
- if (nCols < m_nFixedCols)
- m_nFixedCols = nCols;
- if (m_idCurrentCell.col >= nCols)
- SetFocusCell(-1,-1);
- int addedCols = nCols - GetColumnCount();
- // If we are about to lose columns, then we need to delete the GridCell objects
- // within each column
- if (addedCols < 0) {
- for (int row = 0; row < m_nRows; row++)
- for (int col = nCols; col < GetColumnCount(); col++)
- {
- CGridCell* pCell = GetCell(row, col);
- if (pCell) {
- EmptyCell(pCell, row, col);
- delete pCell;
- }
- }
- }
- // Change the number of columns.
- m_nCols = nCols;
- m_arColWidths.SetSize(nCols);
- // Change the number of columns in each row.
- for (int i = 0; i < m_nRows; i++)
- if (m_RowData[i]) m_RowData[i]->SetSize(nCols);
- // If we have just added columns, we need to construct new elements for each cell
- // and set the default column width
- if (addedCols > 0)
- {
- // initialized column widths
- int startCol = nCols - addedCols;
- for (int col = startCol; col < GetColumnCount(); col++)
- m_arColWidths[col] = m_nDefCellWidth;
- // initialise column data
- for (int row = 0; row < m_nRows; row++)
- for (col = startCol; col < GetColumnCount(); col++)
- {
- GRID_ROW* pRow = m_RowData[row];
- if (pRow) pRow->SetAt(col, CreateCell(row,col));
- }
- }
- //else // check for selected cell ranges
- // ResetSelectedRange();
-
- if (GetSafeHwnd() && m_bAllowDraw)
- {
- ResetScrollBars();
- Invalidate();
- }
- return TRUE;
- }
- // Insert a column at a given position, or add to end of columns (if nColumn = -1)
- int CGridCtrl::InsertColumn(LPCTSTR strHeading,
- UINT nFormat /* = DT_CENTER|DT_VCENTER|DT_SINGLELINE */,
- int nColumn /* = -1 */)
- {
- // If the insertion is for a specific column, check it's within range.
- if (nColumn >= 0 && nColumn >= GetColumnCount())
- return -1;
- ResetSelectedRange();
- // Gotta be able to at least _see_ some of the column.
- if (m_nRows < 1)
- SetRowCount(1);
- if (nColumn < 0)
- {
- nColumn = m_nCols;
- m_arColWidths.Add(0);
- for (int row = 0; row < m_nRows; row++)
- {
- GRID_ROW* pRow = m_RowData[row];
- if (!pRow) return -1;
- pRow->Add(CreateCell(row, nColumn));
- }
- }
- else
- {
- m_arColWidths.InsertAt(nColumn, (int)0);
- for (int row = 0; row < m_nRows; row++)
- {
- GRID_ROW* pRow = m_RowData[row];
- if (!pRow) return -1;
- pRow->InsertAt(nColumn, CreateCell(row, nColumn));
- }
- }
- m_nCols++;
- // Initialise column data
- SetItemText(0, nColumn, strHeading);
- for (int row = 0; row < m_nRows; row++)
- {
- SetItemFormat(row, nColumn, nFormat);
- }
- // initialized column width
- m_arColWidths[nColumn] = GetTextExtent(strHeading).cx;
- if (m_idCurrentCell.col != -1 && nColumn < m_idCurrentCell.col)
- m_idCurrentCell.col++;
-
- ResetScrollBars();
- return nColumn;
- }
- // Insert a row at a given position, or add to end of rows (if nRow = -1)
- int CGridCtrl::InsertRow(LPCTSTR strHeading, int nRow /* = -1 */)
- {
- // If the insertion is for a specific row, check it's within range.
- if (nRow >= 0 && nRow >= GetRowCount())
- return -1;
- ResetSelectedRange();
- // Gotta be able to at least _see_ some of the row.
- if (m_nCols < 1)
- SetColumnCount(1);
- // Adding a row to the bottom
- if (nRow < 0)
- {
- nRow = m_nRows;
- m_arRowHeights.Add(0);
- m_RowData.Add(new GRID_ROW);
- }
- else
- {
- m_arRowHeights.InsertAt(nRow, (int)0);
- m_RowData.InsertAt(nRow, new GRID_ROW);
- }
-
- m_nRows++;
- m_RowData[nRow]->SetSize(m_nCols);
- // Initialise cell data
- for (int col = 0; col < m_nCols; col++)
- {
- GRID_ROW* pRow = m_RowData[nRow];
- if (!pRow) return -1;
- pRow->SetAt(col, CreateCell(nRow, col));
- }
- // Set row title
- SetItemText(nRow, 0, strHeading);
- // initialized row height
- m_arRowHeights[nRow] = GetTextExtent(strHeading).cy;
- if (m_idCurrentCell.row != -1 && nRow < m_idCurrentCell.row)
- m_idCurrentCell.row++;
-
- ResetScrollBars();
- return nRow;
- }
- // Creates a new grid cell and performs any necessary initialisation
- CGridCell* CGridCtrl::CreateCell(int nRow, int nCol)
- {
- CGridCell* pCell = new CGridCell;
- if (!pCell)
- return NULL;
-
- // Make format same as cell above
- if (nRow > 0 && nCol >= 0 && nCol < m_nCols)
- pCell->nFormat = GetItemFormat(nRow-1, nCol);
-
- // Make font default grid font
- memcpy(&(pCell->lfFont), &m_Logfont, sizeof(LOGFONT));
-
- return pCell;
- }
- // Performs any cell cleanup necessary to maintain grid integrity
- void CGridCtrl::EmptyCell(CGridCell* pCell, int nRow, int nCol)
- {
- // Set the cells state to 0. If the cell is selected, this
- // will remove the cell from the selected list.
- SetItemState(nRow, nCol, 0);
- // Empty strings
- pCell->szText.Empty();
- }
- BOOL CGridCtrl::DeleteColumn(int nColumn)
- {
- if (nColumn < 0 || nColumn >= GetColumnCount())
- return FALSE;
- ResetSelectedRange();
- for (int row = 0; row < GetRowCount(); row++)
- {
- GRID_ROW* pRow = m_RowData[row];
- if (!pRow) return FALSE;
- CGridCell* pCell = pRow->GetAt(nColumn);
- if (pCell) {
- EmptyCell(pCell, row, nColumn);
- delete pCell;
- }
- pRow->RemoveAt(nColumn);
- }
- m_arColWidths.RemoveAt(nColumn);
- m_nCols--;
- if (nColumn < m_nFixedCols) m_nFixedCols--;
- if (nColumn == m_idCurrentCell.col)
- m_idCurrentCell.row = m_idCurrentCell.col = -1;
- else if (nColumn < m_idCurrentCell.col)
- m_idCurrentCell.col--;
- ResetScrollBars();
- return TRUE;
- }
- BOOL CGridCtrl::DeleteRow(int nRow)
- {
- if ( nRow < 0 || nRow >= GetRowCount())
- return FALSE;
- GRID_ROW* pRow = m_RowData[nRow];
- if (!pRow) return FALSE;
- ResetSelectedRange();
- for (int col = 0; col < GetColumnCount(); col++)
- {
- CGridCell* pCell = pRow->GetAt(col);
- if (pCell) {
- EmptyCell(pCell, nRow, col);
- delete pCell;
- }
- }
- delete pRow;
- m_RowData.RemoveAt(nRow);
- m_arRowHeights.RemoveAt(nRow);
- m_nRows--;
- if (nRow < m_nFixedRows) m_nFixedRows--;
- if (nRow == m_idCurrentCell.row)
- m_idCurrentCell.row = m_idCurrentCell.col = -1;
- else if (nRow < m_idCurrentCell.row)
- m_idCurrentCell.row--;
- ResetScrollBars();
- return TRUE;
- }
- // Handy function that removes all non-fixed rows
- BOOL CGridCtrl::DeleteNonFixedRows()
- {
- int nFixed = GetFixedRowCount();
- int nCount = GetRowCount();
- // Delete all data rows
- for (int nRow = nCount; nRow >= nFixed; nRow--)
- DeleteRow(nRow);
- return TRUE;
- }
- // Removes all rows, columns and data from the grid.
- BOOL CGridCtrl::DeleteAllItems()
- {
- ResetSelectedRange();
- m_arColWidths.RemoveAll();
- m_arRowHeights.RemoveAll();
- // Delete all cells in the grid
- for (int row = 0; row < m_nRows; row++)
- {
- GRID_ROW* pRow = m_RowData[row];
- if (!pRow) continue;
- for (int col = 0; col < m_nCols; col++)
- {
- CGridCell* pCell = pRow->GetAt(col);
- if (pCell) {
- EmptyCell(pCell, row, col); // TODO - this is a bit of a performance hit.
- delete pCell; // better to call m_SelectedCells.RemoveAll()
- } // instead. This is safer for changes though.
- }
- delete pRow;
- }
- // Remove all rows
- m_RowData.RemoveAll();
- m_idCurrentCell.row = m_idCurrentCell.col = -1;
- m_nRows = m_nFixedRows = m_nCols = m_nFixedCols = 0;
- ResetScrollBars();
- return TRUE;
- }
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl data functions
- // Set CListCtrl::GetNextItem for details
- CCellID CGridCtrl::GetNextItem(CCellID& cell, int nFlags) const
- {
- if (nFlags & GVNI_ALL)
- { // GVNI_ALL Search whole Grid beginning from cell
- // First row (cell.row) -- ONLY Columns to the right of cell
- // following rows -- ALL Columns
- int row = cell.row , col = cell.col + 1;
- if (row <= 0) row = GetFixedRowCount();
- for (; row < GetRowCount(); row++)
- {
- if (col <= 0 ) col = GetFixedColumnCount();
- for (; col < GetColumnCount(); col++)
- {
- int nState = GetItemState(row, col);
- if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
- return CCellID(row, col);
- if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
- return CCellID(row, col);
- if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
- return CCellID(row, col);
- if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
- return CCellID(row, col);
- if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
- return CCellID(row, col);
- }
- // go to First Column
- col=GetFixedColumnCount();
- }
- }
- else if ((nFlags & GVNI_BELOW) && (nFlags & GVNI_TORIGHT))
- { // GVNI_AREA Search Grid beginning from cell to Lower-Right of Grid
- // Only rows starting with cell.row and below
- // All rows -- ONLY Columns to the right of cell
- int row = cell.row;
- if (row <= 0) row = GetFixedRowCount();
- for (; row < GetRowCount(); row++)
- {
- int col = cell.col + 1;
- if (col <= 0) col = GetFixedColumnCount();
- for (; col < GetColumnCount(); col++)
- {
- int nState = GetItemState(row, col);
- if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
- return CCellID(row, col);
- if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
- return CCellID(row, col);
- if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
- return CCellID(row, col);
- if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
- return CCellID(row, col);
- if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
- return CCellID(row, col);
- }
- }
- }
- else if (nFlags & GVNI_ABOVE)
- {
- for (int row = cell.row-1; row >= GetFixedRowCount(); row--)
- {
- int nState = GetItemState(row, cell.col);
- if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
- return CCellID(row, cell.col);
- if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
- return CCellID(row, cell.col);
- if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
- return CCellID(row, cell.col);
- if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
- return CCellID(row, cell.col);
- if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
- return CCellID(row, cell.col);
- }
- }
- else if (nFlags & GVNI_BELOW)
- {
- for (int row = cell.row+1; row < GetRowCount(); row++)
- {
- int nState = GetItemState(row, cell.col);
- if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
- return CCellID(row, cell.col);
- if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
- return CCellID(row, cell.col);
- if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
- return CCellID(row, cell.col);
- if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
- return CCellID(row, cell.col);
- if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
- return CCellID(row, cell.col);
- }
- }
- else if (nFlags & GVNI_TOLEFT)
- {
- for (int col = cell.col-1; col >= GetFixedColumnCount(); col--)
- {
- int nState = GetItemState(cell.row, col);
- if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
- return CCellID(cell.row, col);
- if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
- return CCellID(cell.row, col);
- if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
- return CCellID(cell.row, col);
- if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
- return CCellID(cell.row, col);
- if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
- return CCellID(cell.row, col);
- }
- }
- else if (nFlags & GVNI_TORIGHT)
- {
- for (int col = cell.col+1; col < GetColumnCount(); col++)
- {
- int nState = GetItemState(cell.row, col);
- if (nFlags & GVNI_DROPHILITED && nState & GVIS_DROPHILITED)
- return CCellID(cell.row, col);
- if (nFlags & GVNI_FOCUSED && nState & GVIS_FOCUSED)
- return CCellID(cell.row, col);
- if (nFlags & GVNI_SELECTED && nState & GVIS_SELECTED)
- return CCellID(cell.row, col);
- if (nFlags & GVNI_READONLY && nState & GVIS_READONLY)
- return CCellID(cell.row, col);
- if (nFlags & GVNI_MODIFIED && nState & GVIS_MODIFIED)
- return CCellID(cell.row, col);
- }
- }
- return CCellID(-1, -1);
- }
- // Sorts on a given column using the cell text
- BOOL CGridCtrl::SortTextItems(int nCol, BOOL bAscending)
- {
- ResetSelectedRange();
- SetFocusCell(-1,-1);
- return SortTextItems(nCol, bAscending, GetFixedRowCount(),-1);
- }
- // recursive sort implementation
- BOOL CGridCtrl::SortTextItems(int nCol, BOOL bAscending, int low, int high)
- {
- if (nCol >= GetColumnCount()) return FALSE;
- if (high == -1) high = GetRowCount() - 1;
- int lo = low;
- int hi = high;
- if( hi <= lo ) return FALSE;
- CString midItem = GetItemText( (lo+hi)/2, nCol );
- // loop through the list until indices cross
- while( lo <= hi )
- {
- // Find the first element that is greater than or equal to the partition
- // element starting from the left Index.
- if( bAscending )
- while (lo < high && GetItemText(lo, nCol) < midItem)
- ++lo;
- else
- while (lo < high && GetItemText(lo, nCol) > midItem)
- ++lo;
- // Find an element that is smaller than or equal to the partition
- // element starting from the right Index.
- if( bAscending )
- while (hi > low && GetItemText(hi, nCol) > midItem)
- --hi;
- else
- while (hi > low && GetItemText(hi, nCol) < midItem)
- --hi;
- // If the indexes have not crossed, swap if the items are not equal
- if (lo <= hi)
- {
- // swap only if the items are not equal
- if (GetItemText(lo, nCol) != GetItemText(hi, nCol))
- {
- for (int col = 0; col < GetColumnCount(); col++)
- {
- CGridCell *pCell = GetCell(lo, col);
- SetCell(lo, col, GetCell(hi, col));
- SetCell(hi, col, pCell);
- }
- UINT nRowHeight = m_arRowHeights[lo];
- m_arRowHeights[lo] = m_arRowHeights[hi];
- m_arRowHeights[hi] = nRowHeight;
- }
- ++lo;
- --hi;
- }
- }
- // If the right index has not reached the left side of array
- // must now sort the left partition.
- if( low < hi )
- SortTextItems(nCol, bAscending, low, hi);
- // If the left index has not reached the right side of array
- // must now sort the right partition.
- if( lo < high )
- SortTextItems(nCol, bAscending, lo, high);
- return TRUE;
- }
- // Sorts on a given column using the supplied compare function (see CListCtrl::SortItems)
- BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending,
- LPARAM data /* = 0 */)
- {
- ResetSelectedRange();
- SetFocusCell(-1,-1);
- return SortItems(pfnCompare, nCol, bAscending, data, GetFixedRowCount(), -1);
- }
- // recursive sort implementation
- BOOL CGridCtrl::SortItems(PFNLVCOMPARE pfnCompare, int nCol, BOOL bAscending, LPARAM data,
- int low, int high)
- {
- if (nCol >= GetColumnCount()) return FALSE;
- if (high == -1) high = GetRowCount() - 1;
- int lo = low;
- int hi = high;
- if( hi <= lo ) return FALSE;
- LPARAM midItem = GetItemData( (lo+hi)/2, nCol );
- // loop through the list until indices cross
- while( lo <= hi )
- {
- // Find the first element that is greater than or equal to the partition
- // element starting from the left Index.
- if( bAscending )
- while (lo < high && pfnCompare(GetItemData(lo, nCol), midItem, data) < 0)
- ++lo;
- else
- while (lo < high && pfnCompare(GetItemData(lo, nCol), midItem, data) > 0)
- ++lo;
- // Find an element that is smaller than or equal to the partition
- // element starting from the right Index.
- if( bAscending )
- while (hi > low && pfnCompare(GetItemData(hi, nCol), midItem, data) > 0)
- --hi;
- else
- while (hi > low && pfnCompare(GetItemData(hi, nCol), midItem, data) < 0)
- --hi;
- // If the indexes have not crossed, swap if the items are not equal
- if (lo <= hi)
- {
- // swap only if the items are not equal
- if (pfnCompare(GetItemData(lo, nCol), GetItemData(hi, nCol), data) != 0)
- {
- for (int col = 0; col < GetColumnCount(); col++)
- {
- CGridCell *pCell = GetCell(lo, col);
- SetCell(lo, col, GetCell(hi, col));
- SetCell(hi, col, pCell);
- }
- UINT nRowHeight = m_arRowHeights[lo];
- m_arRowHeights[lo] = m_arRowHeights[hi];
- m_arRowHeights[hi] = nRowHeight;
- }
- ++lo;
- --hi;
- }
- }
- // If the right index has not reached the left side of array
- // must now sort the left partition.
- if( low < hi )
- SortItems(pfnCompare, nCol, bAscending, data, low, hi);
- // If the left index has not reached the right side of array
- // must now sort the right partition.
- if( lo < high )
- SortItems(pfnCompare, nCol, bAscending, data, lo, high);
- return TRUE;
- }
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl data functions
- BOOL CGridCtrl::SetItem(const GV_ITEM* pItem)
- {
- if (!pItem)
- return FALSE;
- CGridCell* pCell = GetCell(pItem->row, pItem->col);
- if (!pCell)
- return FALSE;
- if (pItem->mask & GVIF_TEXT) pCell->szText = pItem->szText;
- if (pItem->mask & GVIF_PARAM) pCell->lParam = pItem->lParam;
- if (pItem->mask & GVIF_IMAGE) pCell->iImage = pItem->iImage;
- if (pItem->mask & GVIF_STATE) pCell->state = pItem->state;
- if (pItem->mask & GVIF_FORMAT) pCell->nFormat = pItem->nFormat;
- if (pItem->mask & GVIF_BKCLR) pCell->crBkClr = pItem->crBkClr;
- if (pItem->mask & GVIF_FGCLR) pCell->crFgClr = pItem->crFgClr;
- if (pItem->mask & GVIF_FONT) memcpy(&(pCell->lfFont), &(pItem->lfFont), sizeof(LOGFONT));
- return TRUE;
- }
- BOOL CGridCtrl::GetItem(GV_ITEM* pItem)
- {
- if (!pItem)
- return FALSE;
- CGridCell* pCell = GetCell(pItem->row, pItem->col);
- if (!pCell)
- return FALSE;
- if (pItem->mask & GVIF_TEXT) pItem->szText = GetItemText(pItem->row, pItem->col);
- if (pItem->mask & GVIF_PARAM) pItem->lParam = pCell->lParam;
- if (pItem->mask & GVIF_IMAGE) pItem->iImage = pCell->iImage;
- if (pItem->mask & GVIF_STATE) pItem->state = pCell->state;
- if (pItem->mask & GVIF_FORMAT) pItem->nFormat = pCell->nFormat;
- if (pItem->mask & GVIF_BKCLR) pItem->crBkClr = pCell->crBkClr;
- if (pItem->mask & GVIF_FGCLR) pItem->crFgClr = pCell->crFgClr;
- if (pItem->mask & GVIF_FONT) memcpy(&(pItem->lfFont), &(pCell->lfFont), sizeof(LOGFONT));
- return TRUE;
- }
- BOOL CGridCtrl::SetItemText(int nRow, int nCol, LPCTSTR str)
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- if (!pCell)
- return FALSE;
- pCell->szText = str;
- return TRUE;
- }
- BOOL CGridCtrl::SetItemData(int nRow, int nCol, LPARAM lParam)
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- if (!pCell)
- return FALSE;
- pCell->lParam = lParam;
- return TRUE;
- }
- LPARAM CGridCtrl::GetItemData(int nRow, int nCol) const
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- if (!pCell)
- return (LPARAM) 0;
- return pCell->lParam;
- }
- BOOL CGridCtrl::SetItemImage(int nRow, int nCol, int iImage)
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- if (!pCell)
- return FALSE;
- pCell->iImage = iImage;
- return TRUE;
- }
- int CGridCtrl::GetItemImage(int nRow, int nCol) const
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return -1;
- return pCell->iImage;
- }
- BOOL CGridCtrl::SetItemState(int nRow, int nCol, UINT state)
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return FALSE;
- // If the cell is being unselected, remove it from the selected list
- if ((pCell->state & GVIS_SELECTED) && !(state & GVIS_SELECTED))
- {
- CCellID cell;
- DWORD key = MAKELONG(nRow, nCol);
- if (m_SelectedCellMap.Lookup(key, (CCellID&)cell))
- m_SelectedCellMap.RemoveKey(key);
- }
- // If cell is being selected, add it to the list of selected cells
- else if (!(pCell->state & GVIS_SELECTED) && (state & GVIS_SELECTED))
- {
- CCellID cell(nRow, nCol);
- m_SelectedCellMap.SetAt(MAKELONG(nRow, nCol), cell);
- }
- // Set the cell's state
- pCell->state = state;
- return TRUE;
- }
- UINT CGridCtrl::GetItemState(int nRow, int nCol) const
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return 0;
- return pCell->state;
- }
- BOOL CGridCtrl::SetItemFormat(int nRow, int nCol, UINT nFormat)
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return FALSE;
- pCell->nFormat = nFormat;
- return TRUE;
- }
- UINT CGridCtrl::GetItemFormat(int nRow, int nCol) const
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return 0;
- return pCell->nFormat;
- }
- BOOL CGridCtrl::SetItemBkColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return FALSE;
- pCell->crBkClr = cr;
- return TRUE;
- }
- COLORREF CGridCtrl::GetItemBkColour(int nRow, int nCol) const
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return 0;
- return pCell->crBkClr;
- }
- BOOL CGridCtrl::SetItemFgColour(int nRow, int nCol, COLORREF cr /* = CLR_DEFAULT */)
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return FALSE;
- pCell->crFgClr = cr;
- return TRUE;
- }
- COLORREF CGridCtrl::GetItemFgColour(int nRow, int nCol) const
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return 0;
- return pCell->crFgClr;
- }
- BOOL CGridCtrl::SetItemFont(int nRow, int nCol, LOGFONT* lf)
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return FALSE;
- memcpy(&(pCell->lfFont), lf, sizeof(LOGFONT));
- return TRUE;
- }
- LOGFONT* CGridCtrl::GetItemFont(int nRow, int nCol)
- {
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell)
- return &m_Logfont;
- return &(pCell->lfFont);
- }
- ////////////////////////////////////////////////////////////////////////////////////
- // Row/Column size functions
- long CGridCtrl::GetVirtualWidth() const
- {
- long lVirtualWidth = 0;
- int iColCount = GetColumnCount();
- for (int i = 0; i < iColCount; i++)
- lVirtualWidth += m_arColWidths[i];
- return lVirtualWidth;
- }
- long CGridCtrl::GetVirtualHeight() const
- {
- long lVirtualHeight = 0;
- int iRowCount = GetRowCount();
- for (int i = 0; i < iRowCount; i++)
- lVirtualHeight += m_arRowHeights[i];
- return lVirtualHeight;
- }
- int CGridCtrl::GetRowHeight(int nRow) const
- {
- ASSERT(nRow >= 0 && nRow < m_nRows);
- if (nRow < 0 || nRow >= m_nRows) return -1;
- return m_arRowHeights[nRow];
- }
- int CGridCtrl::GetColumnWidth(int nCol) const
- {
- ASSERT(nCol >= 0 && nCol < m_nCols);
- if (nCol < 0 || nCol >= m_nCols) return -1;
- return m_arColWidths[nCol];
- }
- BOOL CGridCtrl::SetRowHeight(int nRow, int height)
- {
- ASSERT(nRow >= 0 && nRow < m_nRows && height >= 0);
- if (nRow < 0 || nRow >= m_nRows || height < 0) return FALSE;
- m_arRowHeights[nRow] = height;
- return TRUE;
- }
- BOOL CGridCtrl::SetColumnWidth(int nCol, int width)
- {
- ASSERT(nCol >= 0 && nCol < m_nCols && width >= 0);
- if (nCol < 0 || nCol >= m_nCols || width < 0) return FALSE;
- m_arColWidths[nCol] = width;
- return TRUE;
- }
- int CGridCtrl::GetFixedRowHeight() const
- {
- int nHeight = 0;
- for (int i = 0; i < m_nFixedRows; i++)
- nHeight += GetRowHeight(i);
- return nHeight;
- }
- int CGridCtrl::GetFixedColumnWidth() const
- {
- int nWidth = 0;
- for (int i = 0; i < m_nFixedCols; i++)
- nWidth += GetColumnWidth(i);
- return nWidth;
- }
- BOOL CGridCtrl::AutoSizeColumn(int nCol)
- {
- ASSERT(nCol >= 0 && nCol < m_nCols);
- if (nCol < 0 || nCol >= m_nCols) return FALSE;
- CSize size;
- CDC* pDC = GetDC();
- if (!pDC) return FALSE;
- int nWidth = 0;
- int nNumRows = GetRowCount();
- for (int nRow = 0; nRow < nNumRows; nRow++)
- {
- size = GetCellExtent(nRow, nCol, pDC);
- if (size.cx > nWidth) nWidth = size.cx;
- }
- m_arColWidths[nCol] = nWidth;
- ReleaseDC(pDC);
- ResetScrollBars();
- return TRUE;
- }
- BOOL CGridCtrl::AutoSizeRow(int nRow)
- {
- ASSERT(nRow >= 0 && nRow < m_nRows);
- if (nRow < 0 || nRow >= m_nRows) return FALSE;
- CSize size;
- CDC* pDC = GetDC();
- if (!pDC) return FALSE;
- int nHeight = 0;
- int nNumColumns = GetColumnCount();
- for (int nCol = 0; nCol < nNumColumns; nCol++)
- {
- size = GetCellExtent(nRow, nCol, pDC);
- if (size.cy > nHeight) nHeight = size.cy;
- }
- m_arRowHeights[nRow] = nHeight;
- ReleaseDC(pDC);
- ResetScrollBars();
- return TRUE;
- }
- void CGridCtrl::AutoSizeColumns()
- {
- int nNumColumns = GetColumnCount();
- for (int nCol = 0; nCol < nNumColumns; nCol++)
- AutoSizeColumn(nCol);
- }
- void CGridCtrl::AutoSizeRows()
- {
- int nNumRows = GetRowCount();
- for (int nRow = 0; nRow < nNumRows; nRow++)
- AutoSizeRow(nRow);
- }
- // sizes all rows and columns
- // faster than calling both AutoSizeColumns() and AutoSizeRows()
- void CGridCtrl::AutoSize()
- {
- CDC* pDC = GetDC();
- if (!pDC) return;
- int nNumColumns = GetColumnCount();
- int nNumRows = GetRowCount();
-
- // initialize column widths to zero
- for (int nCol = 0; nCol < nNumColumns; nCol++)
- m_arColWidths[nCol] = 0;
-
- // initialize row heights to zero
- for (int nRow = 0; nRow < nNumRows; nRow++)
- m_arRowHeights[nRow] = 0;
-
- CSize size;
- for (nCol = 0; nCol < nNumColumns; nCol++)
- for (nRow = 0; nRow < nNumRows; nRow++)
- {
- size = GetCellExtent(nRow, nCol, pDC);
- if (size.cx > (int) m_arColWidths[nCol]) m_arColWidths[nCol] = size.cx;
- if (size.cy > (int) m_arRowHeights[nRow]) m_arRowHeights[nRow] = size.cy;
- }
-
- ReleaseDC(pDC);
- if (m_bAllowDraw) {
- ResetScrollBars();
- Invalidate();
- }
- }
- void CGridCtrl::ExpandColumnsToFit()
- {
- if (GetColumnCount() <= 0) return;
- CRect rect;
- GetClientRect(rect);
- long virtualWidth = GetVirtualWidth();
- int nDifference = rect.Width() - (int) virtualWidth;
- int nColumnAdjustment = nDifference / GetColumnCount();
- for (int i = 0; i < GetColumnCount(); i++)
- m_arColWidths[i] += nColumnAdjustment;
- if (nDifference > 0)
- {
- int leftOver = nDifference % GetColumnCount();
- for (i = 0; i < leftOver; i++)
- m_arColWidths[i] += 1;
- }
- else
- {
- int leftOver = (-nDifference) % GetColumnCount();
- for (i = 0; i < leftOver; i++)
- m_arColWidths[i] -= 1;
- }
- if (m_bAllowDraw)
- Invalidate();
- }
- void CGridCtrl::ExpandRowsToFit()
- {
- if (GetRowCount() <= 0) return;
- CRect rect;
- GetClientRect(rect);
- long virtualHeight = GetVirtualHeight();
- int nDifference = rect.Height() - (int) virtualHeight;
- int nRowAdjustment = nDifference / GetRowCount();
- for (int i = 0; i < GetRowCount(); i++)
- m_arRowHeights[i] += nRowAdjustment;
- if (nDifference > 0)
- {
- int leftOver = nDifference % GetRowCount();
- for (i = 0; i < leftOver; i++)
- m_arRowHeights[i] += 1;
- }
- else
- {
- int leftOver = (-nDifference) % GetRowCount();
- for (i = 0; i < leftOver; i++)
- m_arRowHeights[i] -= 1;
- }
- if (m_bAllowDraw)
- Invalidate();
- }
- void CGridCtrl::ExpandToFit()
- {
- ExpandColumnsToFit(); // This will remove any existing horz scrollbar
- ExpandRowsToFit(); // This will remove any existing vert scrollbar
- ExpandColumnsToFit(); // Just in case the first adjustment was with a vert
- // scrollbar in place
- }
- BOOL CGridCtrl::IsCellFixed(int nRow, int nCol)
- {
- return (nRow < GetFixedRowCount() || nCol < GetFixedColumnCount());
- }
- void CGridCtrl::SetModified(BOOL bModified /*=TRUE*/, int nRow /*=-1*/, int nCol /*=-1*/)
- {
- if (nRow > 0 && nCol > 0)
- {
- if (bModified)
- {
- SetItemState(nRow, nCol, GetItemState(nRow, nCol) | GVIS_MODIFIED);
- m_bModified = TRUE;
- }
- else
- SetItemState(nRow, nCol, GetItemState(nRow, nCol) & ~GVIS_MODIFIED);
- }
- else
- m_bModified = bModified;
- if (!m_bModified)
- {
- for (int row = 0; row < GetRowCount(); row++)
- for (int col = 0; col < GetColumnCount(); col++)
- SetItemState(row, col, GetItemState(row, col) & ~GVIS_MODIFIED);
- }
- }
- BOOL CGridCtrl::GetModified(int nRow /*=-1*/, int nCol /*=-1*/)
- {
- if (nRow > 0 && nCol > 0)
- return ( (GetItemState(nRow, nCol) & GVIS_MODIFIED) == GVIS_MODIFIED );
- else
- return m_bModified;
- }
- /////////////////////////////////////////////////////////////////////////////////////
- // GridCtrl cell visibility tests and invalidation/redraw functions
- // EnsureVisible supplied by Roelf Werkman
- void CGridCtrl::EnsureVisible(int nRow, int nCol)
- {
- CCellRange VisibleCells = GetVisibleNonFixedCellRange();
- int right = nCol - VisibleCells.GetMaxCol();
- int left = VisibleCells.GetMinCol() - nCol;
- int down = nRow - VisibleCells.GetMaxRow();
- int up = VisibleCells.GetMinRow() - nRow;
- while (right > 0)
- {
- SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
- right--;
- }
- while (left > 0)
- {
- SendMessage(WM_HSCROLL, SB_LINELEFT, 0);
- left--;
- }
- while (down > 0)
- {
- SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
- down--;
- }
- while (up > 0)
- {
- SendMessage(WM_VSCROLL, SB_LINEUP, 0);
- up--;
- }
- // Move one more if we only see a snall bit of the cell
- CRect rectCell, rectWindow;
- GetCellRect(nRow, nCol, rectCell);
- GetClientRect(rectWindow);
- if (rectCell.right > rectWindow.right)
- SendMessage(WM_HSCROLL, SB_LINERIGHT, 0);
- if (rectCell.bottom > rectWindow.bottom)
- SendMessage(WM_VSCROLL, SB_LINEDOWN, 0);
- }
- BOOL CGridCtrl::IsCellEditable(CCellID &cell) const
- {
- return IsCellEditable(cell.row, cell.col);
- }
- BOOL CGridCtrl::IsCellEditable(int nRow, int nCol) const
- {
- return IsEditable() && ((GetItemState(nRow, nCol) & GVIS_READONLY) != GVIS_READONLY);
- }
- BOOL CGridCtrl::IsCellVisible(CCellID cell) const
- {
- return IsCellVisible(cell.row, cell.col);
- }
- BOOL CGridCtrl::IsCellVisible(int nRow, int nCol) const
- {
- if (!IsWindow(m_hWnd))
- return FALSE;
- int x,y;
- CCellID TopLeft;
- if (nCol >= GetFixedColumnCount() || nRow >= GetFixedRowCount())
- {
- TopLeft = GetTopleftNonFixedCell();
- if (nCol >= GetFixedColumnCount() && nCol < TopLeft.col) return FALSE;
- if (nRow >= GetFixedRowCount() && nRow < TopLeft.row) return FALSE;
- }
- CRect rect;
- GetClientRect(rect);
- if (nCol < GetFixedColumnCount())
- {
- x = 0;
- for (int i = 0; i <= nCol; i++)
- {
- if (x >= rect.right) return FALSE;
- x += GetColumnWidth(i);
- }
- }
- else
- {
- x = GetFixedColumnWidth();
- for (int i = TopLeft.col; i <= nCol; i++)
- {
- if (x >= rect.right) return FALSE;
- x += GetColumnWidth(i);
- }
- }
- if (nRow < GetFixedRowCount())
- {
- y = 0;
- for (int i = 0; i <= nRow; i++)
- {
- if (y >= rect.bottom) return FALSE;
- y += GetRowHeight(i);
- }
- }
- else
- {
- if (nRow < TopLeft.row) return FALSE;
- y = GetFixedRowHeight();
- for (int i = TopLeft.row; i <= nRow; i++)
- {
- if (y >= rect.bottom) return FALSE;
- y += GetRowHeight(i);
- }
- }
- return TRUE;
- }
- BOOL CGridCtrl::InvalidateCellRect(const CCellID& cell)
- {
- if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw)
- return FALSE;
- ASSERT(IsValid(cell));
- if (!IsCellVisible(cell.row, cell.col)) return FALSE;
- CRect rect;
- if (!GetCellRect(cell, rect)) return FALSE;
- rect.right++; rect.bottom++;
- InvalidateRect(rect, TRUE);
- return TRUE;
- }
- BOOL CGridCtrl::InvalidateCellRect(const CCellRange& cellRange)
- {
- ASSERT(IsValid(cellRange));
- if (!::IsWindow(GetSafeHwnd()) || !m_bAllowDraw) return FALSE;
- CCellRange visibleCellRange = GetVisibleNonFixedCellRange().Intersect(cellRange);
- CRect rect;
- if (!GetCellRangeRect(visibleCellRange, rect)) return FALSE;
- rect.right++; rect.bottom++;
- InvalidateRect(rect, TRUE);
- return TRUE;
- }
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl Mouse stuff
- // Handles mouse wheel notifications
- // Note - if this doesn't work for win95 then use OnRegisteredMouseWheel instead
- #if !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
- BOOL CGridCtrl::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
- {
- // A m_nRowsPerWheelNotch value less than 0 indicates that the mouse
- // wheel scrolls whole pages, not just lines.
- if (m_nRowsPerWheelNotch == -1)
- {
- int nPagesScrolled = zDelta / 120;
- if (nPagesScrolled > 0)
- for (int i = 0; i < nPagesScrolled; i++)
- PostMessage(WM_VSCROLL, SB_PAGEUP, 0);
- else
- for (int i = 0; i > nPagesScrolled; i--)
- PostMessage(WM_VSCROLL, SB_PAGEDOWN, 0);
- }
- else
- {
- int nRowsScrolled = m_nRowsPerWheelNotch * zDelta / 120;
- if (nRowsScrolled > 0)
- for (int i = 0; i < nRowsScrolled; i++)
- PostMessage(WM_VSCROLL, SB_LINEUP, 0);
- else
- for (int i = 0; i > nRowsScrolled; i--)
- PostMessage(WM_VSCROLL, SB_LINEDOWN, 0);
- }
- return CWnd::OnMouseWheel(nFlags, zDelta, pt);
- }
- #endif // !defined(_WIN32_WCE) && (_MFC_VER >= 0x0421)
- void CGridCtrl::OnMouseMove(UINT nFlags, CPoint point)
- {
- CRect rect;
- GetClientRect(rect);
- #ifndef GRIDCONTROL_NO_DRAGDROP
- // If outside client area, return (unless we are drag n dropping)
- if (m_MouseMode != MOUSE_DRAGGING && !rect.PtInRect(point))
- return;
- #endif
- // If the left mouse button is up, then test to see if row/column sizing is imminent
- if (!(nFlags & MK_LBUTTON)
- || (m_MouseMode == MOUSE_NOTHING && (nFlags & MK_LBUTTON)))
- {
- if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
- {
- if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
- {
- SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
- m_MouseMode = MOUSE_OVER_COL_DIVIDE;
- }
- }
- else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
- {
- if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
- {
- SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
- m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
- }
- }
- else if (m_MouseMode != MOUSE_NOTHING)
- {
- SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
- m_MouseMode = MOUSE_NOTHING;
- }
- #ifndef GRIDCONTROL_NO_TITLETIPS
- if (m_MouseMode == MOUSE_NOTHING && m_bTitleTips)
- {
- CCellID idCurrentCell = GetCellFromPt(point);
- CRect TextRect, CellRect;
- if (GetTextRect(idCurrentCell.row, idCurrentCell.col, TextRect) &&
- GetCellRect(idCurrentCell.row, idCurrentCell.col, CellRect))
- m_TitleTip.Show(TextRect,
- GetItemText(idCurrentCell.row, idCurrentCell.col),
- 0,
- CellRect,
- GetItemFont(idCurrentCell.row, idCurrentCell.col));
- }
- #endif
- m_LastMousePoint = point;
- return;
- }
- if (!IsValid(m_LeftClickDownCell))
- {
- m_LastMousePoint = point;
- return;
- }
- // If the left mouse button is down, then process appropriately
- if (nFlags & MK_LBUTTON)
- {
- switch(m_MouseMode)
- {
- case MOUSE_SELECT_ALL:
- break;
- case MOUSE_SELECT_COL:
- case MOUSE_SELECT_ROW:
- case MOUSE_SELECT_CELLS:
- {
- CCellID idCurrentCell = GetCellFromPt(point);
- if (!IsValid(idCurrentCell))
- return;
- if (idCurrentCell != GetFocusCell())
- {
- OnSelecting(idCurrentCell);
- //SetFocusCell(max(idCurrentCell.row, m_nFixedRows),
- // max(idCurrentCell.col, m_nFixedCols));
- if (idCurrentCell.row >= m_nFixedRows &&
- idCurrentCell.col >= m_nFixedCols)
- {
- SetFocusCell(idCurrentCell);
- }
- }
- break;
- }
- case MOUSE_SIZING_COL:
- {
- CDC* pDC = GetDC();
- if (!pDC) break;
-
- CRect oldInvertedRect(m_LastMousePoint.x, rect.top,
- m_LastMousePoint.x + 2, rect.bottom);
- pDC->InvertRect(&oldInvertedRect);
- CRect newInvertedRect(point.x, rect.top,
- point.x + 2, rect.bottom);
- pDC->InvertRect(&newInvertedRect);
- ReleaseDC(pDC);
- }
- break;
-
- case MOUSE_SIZING_ROW:
- {
- CDC* pDC = GetDC();
- if (!pDC) break;
-
- CRect oldInvertedRect(rect.left, m_LastMousePoint.y,
- rect.right, m_LastMousePoint.y + 2);
- pDC->InvertRect(&oldInvertedRect);
- CRect newInvertedRect(rect.left, point.y,
- rect.right, point.y + 2);
- pDC->InvertRect(&newInvertedRect);
- ReleaseDC(pDC);
- }
- break;
- #ifndef GRIDCONTROL_NO_DRAGDROP
- case MOUSE_PREPARE_DRAG:
- OnBeginDrag();
- break;
- #endif
- }
- }
- m_LastMousePoint = point;
- }
- void CGridCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
- {
- if (m_MouseMode == MOUSE_OVER_COL_DIVIDE)
- {
- CCellID cell = GetCellFromPt(point);
- ASSERT(IsValid(cell));
- CPoint start;
- if (!GetCellOrigin(0, cell.col, &start)) return;
- if (point.x - start.x <= m_nResizeCaptureRange) // Clicked right of border
- cell.col--;
- AutoSizeColumn(cell.col);
- Invalidate();
- }
- else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE)
- {
- CCellID cell = GetCellFromPt(point);
- ASSERT(IsValid(cell));
- CPoint start;
- if (!GetCellOrigin(0, cell.col, &start)) return;
- if (point.y - start.y <= m_nResizeCaptureRange) // Clicked below border
- cell.row--;
- AutoSizeRow(cell.row);
- Invalidate();
- }
- else if (m_MouseMode == MOUSE_NOTHING)
- {
- if (m_LeftClickDownCell.row >= m_nFixedRows &&
- IsValid(m_LeftClickDownCell) &&
- m_LeftClickDownCell.col >= m_nFixedCols)
- {
- OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, VK_LBUTTON);
- }
- else if (m_bListMode)
- {
- CCellID cell = GetCellFromPt(point);
- if (!IsValid(cell)) return;
- if (cell.row >= m_nFixedRows && cell.col < GetFixedColumnCount())
- OnEditCell(cell.row, cell.col, VK_LBUTTON);
- }
- }
- CWnd::OnLButtonDblClk(nFlags, point);
- }
- void CGridCtrl::OnLButtonDown(UINT nFlags, CPoint point)
- {
- HWND hOldFocusWnd = ::GetFocus();
- m_LeftClickDownPoint = point;
- m_LeftClickDownCell = GetCellFromPt(point);
- if (!IsValid(m_LeftClickDownCell)) return;
- m_SelectionStartCell = (nFlags & MK_SHIFT)? m_idCurrentCell : m_LeftClickDownCell;
- SetFocus(); // Auto-destroy any InPlaceEdit's
- // If the user clicks on the current cell, then prepare to edit it.
- // (If the user moves the mouse, then dragging occurs)
- if (m_LeftClickDownCell == m_idCurrentCell)
- {
- m_MouseMode = MOUSE_PREPARE_EDIT;
- return;
- }
- else if (m_MouseMode != MOUSE_OVER_COL_DIVIDE &&
- m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
- {
- SetFocusCell(-1,-1);
- SetFocusCell(max(m_LeftClickDownCell.row, m_nFixedRows),
- max(m_LeftClickDownCell.col, m_nFixedCols));
- }
- #ifndef GRIDCONTROL_NO_DRAGDROP
- // If the user clicks on a selected cell, then prepare to drag it.
- // (If the user moves the mouse, then dragging occurs)
- if (m_bAllowDragAndDrop && hOldFocusWnd == GetSafeHwnd() &&
- GetItemState(m_LeftClickDownCell.row, m_LeftClickDownCell.col) & GVNI_SELECTED)
- {
- m_MouseMode = MOUSE_PREPARE_DRAG;
- return;
- }
- #endif
- SetCapture();
- if (m_MouseMode == MOUSE_NOTHING)
- {
- if (m_bAllowColumnResize && MouseOverColumnResizeArea(point))
- {
- if (m_MouseMode != MOUSE_OVER_COL_DIVIDE)
- {
- SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
- m_MouseMode = MOUSE_OVER_COL_DIVIDE;
- }
- }
- else if (m_bAllowRowResize && MouseOverRowResizeArea(point))
- {
- if (m_MouseMode != MOUSE_OVER_ROW_DIVIDE)
- {
- SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
- m_MouseMode = MOUSE_OVER_ROW_DIVIDE;
- }
- }
- //else if (m_MouseMode != MOUSE_NOTHING)
- //{
- // SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
- // m_MouseMode = MOUSE_NOTHING;
- //}
- }
- if (m_MouseMode == MOUSE_OVER_COL_DIVIDE) // sizing column
- {
- m_MouseMode = MOUSE_SIZING_COL;
- CPoint start;
- if (!GetCellOrigin(0, m_LeftClickDownCell.col, &start)) return;
- CRect rect;
- GetClientRect(rect);
- CRect invertedRect(point.x, rect.top, point.x + 2, rect.bottom);
- CDC* pDC = GetDC();
- if (pDC) {
- pDC->InvertRect(&invertedRect);
- ReleaseDC(pDC);
- }
- if (point.x - start.x <= m_nResizeCaptureRange) // clicked right of border
- if (!GetCellOrigin(0, --m_LeftClickDownCell.col, &start)) return;
- rect.left = start.x;
- ClientToScreen(rect);
- #ifndef _WIN32_WCE_NO_CURSOR
- ClipCursor(rect);
- #endif
- }
- else if (m_MouseMode == MOUSE_OVER_ROW_DIVIDE) // sizing row
- {
- m_MouseMode = MOUSE_SIZING_ROW;
- CPoint start;
- if (!GetCellOrigin(m_LeftClickDownCell, &start)) return;
- CRect rect;
- GetClientRect(rect);
- CRect invertedRect(rect.left, point.y, rect.right, point.y + 2);
- CDC* pDC = GetDC();
- if (pDC) {
- pDC->InvertRect(&invertedRect);
- ReleaseDC(pDC);
- }
- if (point.y - start.y <= m_nResizeCaptureRange) // clicked below border
- if (!GetCellOrigin(--m_LeftClickDownCell.row, 0, &start)) return;
- rect.top = start.y;
- ClientToScreen(rect);
- #ifndef _WIN32_WCE_NO_CURSOR
- ClipCursor(rect);
- #endif
- }
- else // not sizing or editing -- selecting
- {
- // If Ctrl pressed, save the current cell selection. This will get added
- // to the new cell selection at the end of the cell selection process
- m_PrevSelectedCellMap.RemoveAll();
- if (nFlags & MK_CONTROL) {
- for (POSITION pos = m_SelectedCellMap.GetStartPosition(); pos != NULL; )
- {
- DWORD key;
- CCellID cell;
- m_SelectedCellMap.GetNextAssoc(pos, key, (CCellID&)cell);
- m_PrevSelectedCellMap.SetAt(key, cell);
- }
- }
-
- if (m_LeftClickDownCell.row < GetFixedRowCount())
- OnFixedRowClick(m_LeftClickDownCell);
- else if (m_LeftClickDownCell.col < GetFixedColumnCount())
- OnFixedColumnClick(m_LeftClickDownCell);
- else
- {
- m_MouseMode = m_bListMode? MOUSE_SELECT_ROW : MOUSE_SELECT_CELLS;
- OnSelecting(m_LeftClickDownCell);
- }
- m_nTimerID = SetTimer(WM_LBUTTONDOWN, m_nTimerInterval, 0);
- }
- m_LastMousePoint = point;
- }
- void CGridCtrl::OnLButtonUp(UINT nFlags, CPoint point)
- {
- CWnd::OnLButtonUp(nFlags, point);
- #ifndef _WIN32_WCE_NO_CURSOR
- ClipCursor(NULL);
- #endif
- if (GetCapture()->GetSafeHwnd() == GetSafeHwnd())
- {
- ReleaseCapture();
- KillTimer(m_nTimerID);
- m_nTimerID = 0;
- }
- // m_MouseMode == MOUSE_PREPARE_EDIT only if user clicked down on current cell
- // and then didn't move mouse before clicking up (releasing button)
- if (m_MouseMode == MOUSE_PREPARE_EDIT)
- {
- OnEditCell(m_idCurrentCell.row, m_idCurrentCell.col, VK_LBUTTON);
- }
- #ifndef GRIDCONTROL_NO_DRAGDROP
- // m_MouseMode == MOUSE_PREPARE_DRAG only if user clicked down on a selected cell
- // and then didn't move mouse before clicking up (releasing button)
- else if (m_MouseMode == MOUSE_PREPARE_DRAG)
- {
- ResetSelectedRange();
- }
- #endif
- else if (m_MouseMode == MOUSE_SIZING_COL)
- {
- CRect rect;
- GetClientRect(rect);
- CRect invertedRect(m_LastMousePoint.x, rect.top, m_LastMousePoint.x + 2, rect.bottom);
- CDC* pDC = GetDC();
- if (pDC) {
- pDC->InvertRect(&invertedRect);
- ReleaseDC(pDC);
- }
- if (m_LeftClickDownPoint != point)
- {
- CPoint start;
- if (!GetCellOrigin(m_LeftClickDownCell, &start)) return;
- SetColumnWidth(m_LeftClickDownCell.col, point.x - start.x);
- ResetScrollBars();
- Invalidate();
- }
- }
- else if (m_MouseMode == MOUSE_SIZING_ROW)
- {
- CRect rect;
- GetClientRect(rect);
- CRect invertedRect(rect.left, m_LastMousePoint.y, rect.right, m_LastMousePoint.y + 2);
-
- CDC* pDC = GetDC();
- if (pDC) {
- pDC->InvertRect(&invertedRect);
- ReleaseDC(pDC);
- }
-
- if (m_LeftClickDownPoint != point)
- {
- CPoint start;
- if (!GetCellOrigin(m_LeftClickDownCell, &start)) return;
- SetRowHeight(m_LeftClickDownCell.row, point.y - start.y);
- ResetScrollBars();
- Invalidate();
- }
- }
- m_MouseMode = MOUSE_NOTHING;
- #ifndef _WIN32_WCE_NO_CURSOR
- SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
- #endif
- if (!IsValid(m_LeftClickDownCell)) return;
- CWnd *pOwner = GetOwner();
- if (pOwner && IsWindow(pOwner->m_hWnd))
- pOwner->PostMessage(WM_COMMAND, MAKELONG(GetDlgCtrlID(), BN_CLICKED),
- (LPARAM) GetSafeHwnd());
- }
- #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl printing
- void CGridCtrl::Print()
- {
- CDC dc;
- CPrintDialog printDlg(FALSE);
- if (printDlg.DoModal() != IDOK) // Get printer settings from user
- return;
- dc.Attach(printDlg.GetPrinterDC()); // attach a printer DC
- dc.m_bPrinting = TRUE;
- CString strTitle;
- strTitle.LoadString(AFX_IDS_APP_TITLE);
- DOCINFO di; // Initialise print doc details
- memset(&di, 0, sizeof (DOCINFO));
- di.cbSize = sizeof (DOCINFO);
- di.lpszDocName = strTitle;
- BOOL bPrintingOK = dc.StartDoc(&di); // Begin a new print job
- CPrintInfo Info;
- Info.m_rectDraw.SetRect(0,0, dc.GetDeviceCaps(HORZRES), dc.GetDeviceCaps(VERTRES));
- OnBeginPrinting(&dc, &Info); // Initialise printing
- for (UINT page = Info.GetMinPage(); page <= Info.GetMaxPage() && bPrintingOK; page++)
- {
- dc.StartPage(); // begin new page
- Info.m_nCurPage = page;
- OnPrint(&dc, &Info); // Print page
- bPrintingOK = (dc.EndPage() > 0); // end page
- }
- OnEndPrinting(&dc, &Info); // Clean up after printing
- if (bPrintingOK)
- dc.EndDoc(); // end a print job
- else
- dc.AbortDoc(); // abort job.
- dc.Detach(); // detach the printer DC
- }
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl printing overridables - for Doc/View print/print preview framework
- void CGridCtrl::OnBeginPrinting(CDC *pDC, CPrintInfo *pInfo)
- {
- // OnBeginPrinting() is called after the user has committed to
- // printing by OK'ing the Print dialog, and after the framework
- // has created a CDC object for the printer or the preview view.
- // This is the right opportunity to set up the page range.
- // Given the CDC object, we can determine how many rows will
- // fit on a page, so we can in turn determine how many printed
- // pages represent the entire document.
- ASSERT(pDC && pInfo);
- if (!pDC || !pInfo) return;
- int nMaxRowCount = GetRowCount() - GetFixedRowCount();
- if (!nMaxRowCount) return;
- // Get a DC for the current window (will be a screen DC for print previewing)
- CDC *pCurrentDC = GetDC(); // will have dimensions of the client area
- if (!pCurrentDC) return;
- CSize PaperPixelsPerInch(pDC->GetDeviceCaps(LOGPIXELSX), pDC->GetDeviceCaps(LOGPIXELSY));
- CSize ScreenPixelsPerInch(pCurrentDC->GetDeviceCaps(LOGPIXELSX), pCurrentDC->GetDeviceCaps(LOGPIXELSY));
- // Create the printer font
- int nFontSize = -9;
- CString strFontName = "Times New Roman";
- m_PrinterFont.CreateFont(nFontSize, 0,0,0, FW_NORMAL, 0,0,0, DEFAULT_CHARSET,
- OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS, DEFAULT_QUALITY,
- DEFAULT_PITCH | FF_DONTCARE, strFontName);
-
- CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
- // Get the average character width (in GridCtrl units) and hence the margins
- m_CharSize = pDC->GetTextExtent(_T("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSATUVWXYZ"),52);
- m_CharSize.cx /= 52;
- int nMargins = (LEFT_MARGIN+RIGHT_MARGIN)*m_CharSize.cx;
- // Get the page sizes (physical and logical)
- m_PaperSize = CSize(pDC->GetDeviceCaps(HORZRES), pDC->GetDeviceCaps(VERTRES));
- m_LogicalPageSize.cx = GetVirtualWidth()+nMargins;
- #ifdef _WIN32_WCE
- m_LogicalPageSize.cy = (m_LogicalPageSize.cx * m_PaperSize.cy) / m_PaperSize.cx;
- #else
- m_LogicalPageSize.cy = MulDiv(m_LogicalPageSize.cx, m_PaperSize.cy, m_PaperSize.cx);
- #endif
- m_nPageHeight = m_LogicalPageSize.cy - GetFixedRowHeight()
- - (HEADER_HEIGHT+FOOTER_HEIGHT + 2*GAP)*m_CharSize.cy;
- // Get the number of pages. Assumes no row is bigger than the page size.
- int nTotalRowHeight = 0;
- int nNumPages = 1;
- for (int row = GetFixedRowCount(); row < GetRowCount(); row++)
- {
- nTotalRowHeight += GetRowHeight(row);
- if (nTotalRowHeight > m_nPageHeight) {
- nNumPages++;
- nTotalRowHeight = GetRowHeight(row);
- }
- }
- // Set up the print info
- pInfo->SetMaxPage(nNumPages);
- pInfo->m_nCurPage = 1; // start printing at page# 1
- ReleaseDC(pCurrentDC);
- pDC->SelectObject(pOldFont);
- }
- void CGridCtrl::OnPrint(CDC *pDC, CPrintInfo *pInfo)
- {
- if (!pDC || !pInfo) return;
- //CRect rcPage(pInfo->m_rectDraw);
- CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
- // Set the page map mode to use GridCtrl units, and setup margin
- pDC->SetMapMode(MM_ANISOTROPIC);
- pDC->SetWindowExt(m_LogicalPageSize);
- pDC->SetViewportExt(m_PaperSize);
- pDC->SetWindowOrg(-LEFT_MARGIN*m_CharSize.cx, 0);
- // Header
- pInfo->m_rectDraw.top = 0;
- pInfo->m_rectDraw.left = 0;
- pInfo->m_rectDraw.right = m_LogicalPageSize.cx - (LEFT_MARGIN+RIGHT_MARGIN)*m_CharSize.cx;
- pInfo->m_rectDraw.bottom = HEADER_HEIGHT*m_CharSize.cy;
- PrintHeader(pDC, pInfo);
- pDC->OffsetWindowOrg(0, -HEADER_HEIGHT*m_CharSize.cy);
- // Gap between header and column headings
- pDC->OffsetWindowOrg(0, -GAP*m_CharSize.cy);
- // Print the column headings
- pInfo->m_rectDraw.bottom = GetFixedRowHeight();
- PrintColumnHeadings(pDC, pInfo);
- pDC->OffsetWindowOrg(0, -GetFixedRowHeight());
- // We need to find out which row to start printing for this page.
- int nTotalRowHeight = 0;
- UINT nNumPages = 1;
- int nCurrPrintRow = GetFixedRowCount();
- while (nCurrPrintRow < GetRowCount() && nNumPages < pInfo->m_nCurPage)
- {
- nTotalRowHeight += GetRowHeight(nCurrPrintRow);
- if (nTotalRowHeight > m_nPageHeight) {
- nNumPages++;
- if (nNumPages == pInfo->m_nCurPage) break;
- nTotalRowHeight = GetRowHeight(nCurrPrintRow);
- }
- nCurrPrintRow++;
- }
- if (nCurrPrintRow >= GetRowCount()) return;
- // Draw as many rows as will fit on the printed page.
- // Clip the printed page so that there is no partially shown
- // row at the bottom of the page (the same row which will be fully
- // shown at the top of the next page).
- BOOL bFirstPrintedRow = TRUE;
- CRect rect;
- rect.bottom = -1;
- while (nCurrPrintRow < GetRowCount())
- {
- rect.top = rect.bottom+1;
- rect.bottom = rect.top + GetRowHeight(nCurrPrintRow) - 1;
- if (rect.bottom > m_nPageHeight) break; // Gone past end of page
- rect.right = -1;
- for (int col = 0; col < GetColumnCount(); col++)
- {
- rect.left = rect.right+1;
- rect.right = rect.left + GetColumnWidth(col) - 1;
- DrawCell(pDC, nCurrPrintRow, col, rect);
- if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
- {
- int Overlap = (col == 0)? 0:1;
- pDC->MoveTo(rect.left-Overlap, rect.bottom);
- pDC->LineTo(rect.right, rect.bottom);
- if (nCurrPrintRow == 0) {
- pDC->MoveTo(rect.left-Overlap, rect.top);
- pDC->LineTo(rect.right, rect.top);
- }
- }
- if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
- {
- int Overlap = (bFirstPrintedRow)? 0:1;
- pDC->MoveTo(rect.right, rect.top-Overlap);
- pDC->LineTo(rect.right, rect.bottom);
- if (col == 0) {
- pDC->MoveTo(rect.left, rect.top-Overlap);
- pDC->LineTo(rect.left, rect.bottom);
- }
- }
- }
- nCurrPrintRow++;
- bFirstPrintedRow = FALSE;
- }
- // Footer
- pInfo->m_rectDraw.bottom = FOOTER_HEIGHT*m_CharSize.cy;
- pDC->SetWindowOrg(-LEFT_MARGIN*m_CharSize.cx, -m_LogicalPageSize.cy + FOOTER_HEIGHT*m_CharSize.cy);
- PrintFooter(pDC, pInfo);
- // SetWindowOrg back for next page
- pDC->SetWindowOrg(0,0);
- pDC->SelectObject(pOldFont);
- }
- void CGridCtrl::PrintColumnHeadings(CDC *pDC, CPrintInfo* /*pInfo*/)
- {
- CFont *pOldFont = pDC->SelectObject(&m_PrinterFont);
- CRect rect;
- rect.bottom = -1;
- for (int row = 0; row < GetFixedRowCount(); row++)
- {
- rect.top = rect.bottom+1;
- rect.bottom = rect.top + GetRowHeight(row) - 1;
- rect.right = -1;
- for (int col = 0; col < GetColumnCount(); col++)
- {
- rect.left = rect.right+1;
- rect.right = rect.left + GetColumnWidth(col) - 1;
- DrawFixedCell(pDC, row, col, rect);
- if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_HORZ)
- {
- int Overlap = (col == 0)? 0:1;
- pDC->MoveTo(rect.left-Overlap, rect.bottom);
- pDC->LineTo(rect.right, rect.bottom);
- if (row == 0) {
- pDC->MoveTo(rect.left-Overlap, rect.top);
- pDC->LineTo(rect.right, rect.top);
- }
- }
- if (m_nGridLines == GVL_BOTH || m_nGridLines == GVL_VERT)
- {
- int Overlap = (row == 0)? 0:1;
- pDC->MoveTo(rect.right, rect.top-Overlap);
- pDC->LineTo(rect.right, rect.bottom);
- if (col == 0) {
- pDC->MoveTo(rect.left, rect.top-Overlap);
- pDC->LineTo(rect.left, rect.bottom);
- }
- }
- }
- }
- pDC->SelectObject(pOldFont);
- }
- void CGridCtrl::PrintHeader(CDC *pDC, CPrintInfo *pInfo)
- {
- CRect rc(pInfo->m_rectDraw);
- CString strHeaderString;
- CFont BoldFont;
- LOGFONT lf;
- //create bold font for header and footer
- VERIFY(m_PrinterFont.GetLogFont(&lf));
- lf.lfWeight = FW_BOLD;
- VERIFY(BoldFont.CreateFontIndirect(&lf));
-
- CFont *pNormalFont = pDC->SelectObject(&BoldFont);
- int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
- // print App title on top right margin
- strHeaderString.LoadString(AFX_IDS_APP_TITLE);
- pDC->DrawText(strHeaderString, &rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
- // print parent window title in the centre (Gert Rijs)
- CWnd *pParentWnd = GetParent();
- while (pParentWnd)
- {
- pParentWnd->GetWindowText(strHeaderString);
- if (strHeaderString.GetLength()) // can happen if it is a CView, CChildFrm has the title
- break;
- pParentWnd = pParentWnd->GetParent();
- }
- pDC->DrawText(strHeaderString, &rc, DT_CENTER | DT_SINGLELINE | DT_NOPREFIX | DT_VCENTER);
- pDC->SetBkMode(nPrevBkMode);
- pDC->SelectObject(pNormalFont);
- BoldFont.DeleteObject();
- pDC->SelectStockObject(BLACK_PEN);
- pDC->MoveTo(rc.left, rc.bottom);
- pDC->LineTo(rc.right, rc.bottom);
- }
- //print footer with a line and date, and page number
- void CGridCtrl::PrintFooter(CDC *pDC, CPrintInfo *pInfo)
- {
- CRect rc(pInfo->m_rectDraw);
- CFont BoldFont;
- LOGFONT lf;
- //draw line
- pDC->MoveTo(rc.left, rc.top);
- pDC->LineTo(rc.right, rc.top);
- //create bold font for header and footer
- m_PrinterFont.GetLogFont(&lf);
- lf.lfWeight = FW_BOLD;
- BoldFont.CreateFontIndirect(&lf);
- CFont *pNormalFont = pDC->SelectObject(&BoldFont);
- int nPrevBkMode = pDC->SetBkMode(TRANSPARENT);
- // draw page number
- CString sTemp ;
- rc.OffsetRect(0, m_CharSize.cy/2);
- sTemp.Format(_T("Page %d of %d"), pInfo->m_nCurPage, pInfo->GetMaxPage());
- pDC->DrawText(sTemp,-1,rc, DT_LEFT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
- CTime t = CTime::GetCurrentTime();
- sTemp = t.Format(_T("%c"));
- pDC->DrawText(sTemp,-1,rc, DT_RIGHT | DT_SINGLELINE | DT_NOPREFIX | DT_NOCLIP | DT_VCENTER);
- pDC->SetBkMode(nPrevBkMode);
- pDC->SelectObject(pNormalFont);
- BoldFont.DeleteObject();
- }
- void CGridCtrl::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
- {
- m_PrinterFont.DeleteObject();
- }
- #endif // !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
- #ifndef _WIN32_WCE
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl persistance
- BOOL CGridCtrl::Save(LPCTSTR filename)
- {
- CStdioFile File;
- CFileException ex;
- if (!File.Open(filename, CFile::modeWrite | CFile::modeCreate| CFile::typeText, &ex)) {
- ex.ReportError();
- return FALSE;
- }
- TRY {
- int nNumColumns = GetColumnCount();
- for (int i = 0; i < nNumColumns; i++) {
- File.WriteString(GetItemText(0,i));
- File.WriteString((i==(nNumColumns-1))? _T("\n"):_T(","));
- }
- for (i = 0; i < GetRowCount(); i++) {
- for (int j = 0; j < nNumColumns; j++) {
- File.WriteString(GetItemText(i,j));
- File.WriteString((j==(nNumColumns-1))? _T("\n"):_T(","));
- }
- }
- File.Close();
- }
- CATCH (CFileException, e) {
- AfxMessageBox(_T("Unable to save grid list"));
- e->Delete();
- return FALSE;
- }
- END_CATCH
- return TRUE;
- }
- BOOL CGridCtrl::Load(LPCTSTR filename)
- {
- TCHAR *token, *end;
- TCHAR buffer[1024];
- CStdioFile File;
- CFileException ex;
- if (!File.Open(filename, CFile::modeRead | CFile::typeText)) {
- ex.ReportError();
- return FALSE;
- }
- DeleteAllItems();
- TRY {
- // Read Header off file
- File.ReadString(buffer, 1024);
- // Get first token
- for (token=buffer, end=buffer;
- *end && (*end != _T(',')) && (*end != _T('\n')); end++);
- if ((*end == _T('\0')) && (token == end)) token = NULL;
- *end = _T('\0');
- while (token)
- {
- InsertColumn(token);
-
- // Get next token
- for (token=++end; *end && (*end != _T(',')) && (*end != _T('\n'));
- end++);
- if ((*end == _T('\0')) && (token == end)) token = NULL;
- *end = _T('\0');
- }
- // Read in rest of data
- int nItem = 0;
- while (File.ReadString(buffer, 1024)) {
- // Get first token
- for (token=buffer, end=buffer;
- *end && (*end != _T(',')) && (*end != _T('\n')); end++);
- if ((*end == _T('\0')) && (token == end)) token = NULL;
- *end = _T('\0');
- int nSubItem = 0;
- while (token) {
- if (!nSubItem)
- InsertRow(token);
- else
- SetItemText(nItem, nSubItem, token);
- // Get next token
- for (token=++end; *end && (*end != _T(',')) && (*end != _T('\n'));
- end++);
- if ((*end == _T('\0')) && (token == end)) token = NULL;
- *end = _T('\0');
- nSubItem++;
- }
- nItem++;
- }
- AutoSizeColumns();
- File.Close();
- }
- CATCH (CFileException, e) {
- AfxMessageBox(_T("Unable to load grid data"));
- e->Delete();
- return FALSE;
- }
- END_CATCH
- return TRUE;
- }
- #endif
- /////////////////////////////////////////////////////////////////////////////
- // CGridCtrl overrideables
- #ifndef GRIDCONTROL_NO_DRAGDROP
- // This is no longer needed since I've changed to OLE drag and drop - but it's
- // still cool code. :)
- CImageList* CGridCtrl::CreateDragImage(CPoint *pHotSpot)
- {
- CDC* pDC = GetDC();
- if (!pDC) return NULL;
- CRect rect;
- CCellID cell = GetFocusCell();
- if (!GetCellRect(cell.row, cell.col, rect)) return NULL;
- // Translate coordinate system
- rect.BottomRight() = CPoint(rect.Width(), rect.Height());
- rect.TopLeft() = CPoint(0,0);
- *pHotSpot = rect.BottomRight();
- // Create a new imagelist (the caller of this function has responsibility
- // for deleting this list)
- CImageList* pList = new CImageList;
- if (!pList || !pList->Create(rect.Width(), rect.Height(), ILC_MASK, 1,1))
- {
- if (pList) delete pList;
- return NULL;
- }
- // Create mem DC and bitmap
- CDC MemDC;
- CBitmap bm;
- MemDC.CreateCompatibleDC(pDC);
- bm.CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
- CBitmap* pOldBitmap = MemDC.SelectObject(&bm);
- MemDC.SetWindowOrg(0,0);
- // Draw cell onto bitmap in memDC
- DrawCell(&MemDC, cell.row, cell.col, rect, TRUE);
- // Clean up
- MemDC.SelectObject(pOldBitmap);
- ReleaseDC(pDC);
- // Add the bitmap we just drew to the image list.
- pList->Add(&bm, GetTextBkColor());
- bm.DeleteObject();
- return pList;
- }
- #endif
- void CGridCtrl::OnFixedRowClick(CCellID& cell)
- {
- if (!IsValid(cell))
- return;
- if (m_bListMode)
- {
- if (!m_bSortOnClick)
- return;
- CWaitCursor waiter;
- if (cell.col == m_SortColumn)
- m_bAscending = !m_bAscending;
- else
- {
- m_bAscending = TRUE;
- m_SortColumn = cell.col;
- }
- SortTextItems(m_SortColumn, m_bAscending);
- Invalidate();
- }
- else if (cell.col < GetFixedColumnCount())
- {
- m_MouseMode = MOUSE_SELECT_ALL;
- OnSelecting(cell);
- }
- else
- {
- m_MouseMode = MOUSE_SELECT_COL;
- OnSelecting(cell);
- }
- }
- void CGridCtrl::OnFixedColumnClick(CCellID& cell)
- {
- if (!IsValid(cell))
- return;
- // if (m_bListMode && (GetItemState(cell.row, m_nFixedCols) & GVNI_SELECTED))
- // {
- // OnEditCell(cell.row, cell.col, VK_LBUTTON);
- // return;
- // }
- if (cell.row < GetFixedRowCount())
- {
- m_MouseMode = MOUSE_SELECT_ALL;
- OnSelecting(cell);
- }
- else
- {
- m_MouseMode = MOUSE_SELECT_ROW;
- OnSelecting(cell);
- }
- }
- // Gets the extent of the text pointed to by str (no CDC needed)
- // By default this uses the selected font (which is a bigger font)
- CSize CGridCtrl::GetTextExtent(LPCTSTR str, BOOL bUseSelectedFont /* = TRUE */)
- {
- CDC* pDC = GetDC();
- if (!pDC) return CSize(0,0);
- CFont *pOldFont, font;
- if (bUseSelectedFont)
- {
- LOGFONT lf;
- memcpy(&lf, &m_Logfont, sizeof(LOGFONT));
- lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
-
- font.CreateFontIndirect(&lf);
-
- pOldFont = pDC->SelectObject(&font);
- }
- else
- pOldFont = pDC->SelectObject(&m_Font);
- CSize size = pDC->GetTextExtent(str);
- pDC->SelectObject(pOldFont);
- ReleaseDC(pDC);
- return size + CSize(2*m_nMargin, 2*m_nMargin);
- }
- CSize CGridCtrl::GetCellExtent(int nRow, int nCol, CDC* pDC)
- {
- LOGFONT *pLF = GetItemFont(nRow, nCol);
-
- // use selected font since it's thicker
- LOGFONT lf;
- memcpy(&lf, pLF, sizeof(LOGFONT));
-
- if (nRow < m_nFixedRows || nCol < m_nFixedCols)
- lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
-
- CFont font;
- font.CreateFontIndirect(&lf);
-
- CFont* pOldFont = pDC->SelectObject(&font);
- CSize size = pDC->GetTextExtent(GetItemText(nRow, nCol));
- pDC->SelectObject(pOldFont);
- size += CSize(4*m_nMargin, 2*m_nMargin);
- CSize ImageSize(0,0);
- if (m_pImageList) {
- int nImage = GetItemImage(nRow, nCol);
- if (nImage >= 0) {
- IMAGEINFO Info;
- if (m_pImageList->GetImageInfo(nImage, &Info))
- ImageSize = CSize(Info.rcImage.right-Info.rcImage.left+1,
- Info.rcImage.bottom-Info.rcImage.top+1);
- }
- }
-
- return CSize(size.cx + ImageSize.cx, max(size.cy, ImageSize.cy));
- }
- BOOL CGridCtrl::DrawFixedCell(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBk)
- {
- if (!m_bAllowDraw)
- return FALSE;
- GV_ITEM Item;
- Item.mask = GVIF_TEXT | GVIF_FORMAT | GVIF_IMAGE | GVIF_BKCLR | GVIF_FGCLR;
- Item.row = nRow;
- Item.col = nCol;
- if (!GetItem(&Item))
- return FALSE;
- // Force redraw of background if custom colour
- //if (Item.crBkClr != CLR_DEFAULT)
- bEraseBk = TRUE;
- if (bEraseBk
- #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
- && !pDC->IsPrinting()
- #endif
- )
- {
- CBrush brush((Item.crBkClr == CLR_DEFAULT)? GetFixedBkColor() : Item.crBkClr);
- pDC->FillRect(rect, &brush);
- }
- pDC->SetTextColor((Item.crFgClr == CLR_DEFAULT)? GetFixedTextColor() : Item.crFgClr);
-
- int nSavedDC = pDC->SaveDC();
-
- // Create the appropriate font and select into DC
- LOGFONT *pLF = GetItemFont(nRow, nCol);
- CCellID FocusCell = GetFocusCell();
- // if (IsCellFixed(nRow, nCol) && (FocusCell.row == nRow || FocusCell.col == nCol))
- //{
- if (FocusCell.row == nRow || FocusCell.col == nCol)
- {
- static LOGFONT lf;
- memcpy(&lf, pLF, sizeof(LOGFONT));
- lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
- pLF = &lf;
- }
-
- CFont Font;
- Font.CreateFontIndirect(pLF);
- pDC->SelectObject(&Font);
- if (IsValid(FocusCell) && (FocusCell.row == nRow || FocusCell.col == nCol))
- {
- rect.right++; rect.bottom++;
- pDC->DrawEdge(rect, BDR_SUNKENINNER /*EDGE_RAISED*/, BF_RECT);
- rect.DeflateRect(1,1);
- }
- else
- {
- CPen lightpen(PS_SOLID, 1, ::GetSysColor(COLOR_3DHIGHLIGHT)),
- darkpen(PS_SOLID, 1, ::GetSysColor(COLOR_3DDKSHADOW)),
- *pOldPen = pDC->GetCurrentPen();
-
- pDC->SelectObject(&lightpen);
- pDC->MoveTo(rect.right, rect.top);
- pDC->LineTo(rect.left, rect.top);
- pDC->LineTo(rect.left, rect.bottom);
- pDC->SelectObject(&darkpen);
- pDC->MoveTo(rect.right, rect.top);
- pDC->LineTo(rect.right, rect.bottom);
- pDC->LineTo(rect.left, rect.bottom);
- pDC->SelectObject(pOldPen);
- rect.DeflateRect(1,1);
- }
- pDC->SetBkMode(TRANSPARENT);
- rect.DeflateRect(m_nMargin, 0);
- if (m_pImageList && Item.iImage >= 0)
- {
- IMAGEINFO Info;
- if (m_pImageList->GetImageInfo(Item.iImage, &Info))
- {
- //CRgn rgn;
- //rgn.CreateRectRgnIndirect(rect);
- //pDC->SelectClipRgn(&rgn);
- //rgn.DeleteObject();
-
- int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
- m_pImageList->Draw(pDC, Item.iImage, rect.TopLeft(), ILD_NORMAL);
- rect.left += nImageWidth+m_nMargin;
- }
- }
- DrawText(pDC->m_hDC, Item.szText, -1, rect, Item.nFormat);
- pDC->RestoreDC(nSavedDC);
- Font.DeleteObject();
- return TRUE;
- }
- BOOL CGridCtrl::DrawCell(CDC* pDC, int nRow, int nCol, CRect rect, BOOL bEraseBk)
- {
- if (!m_bAllowDraw)
- return FALSE;
- GV_ITEM Item;
- Item.mask = GVIF_TEXT | GVIF_FORMAT | GVIF_STATE | GVIF_IMAGE | GVIF_BKCLR | GVIF_FGCLR;
- Item.row = nRow;
- Item.col = nCol;
- if (!GetItem(&Item))
- return FALSE;
- COLORREF TextBkClr = (Item.crBkClr == CLR_DEFAULT)? GetTextBkColor() : Item.crBkClr;
- COLORREF TextClr = (Item.crFgClr == CLR_DEFAULT)? GetTextColor() : Item.crFgClr;
- // Force redraw of background if custom colour
- //if (Item.crBkClr != CLR_DEFAULT)
- bEraseBk = TRUE;
- int nSavedDC = pDC->SaveDC();
- pDC->SetBkMode(TRANSPARENT);
- if (Item.state & GVIS_FOCUSED
- #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
- && !pDC->IsPrinting()
- #endif
- )
- {
- rect.right++; rect.bottom++; // FillRect doesn't draw RHS or bottom
- if (bEraseBk)
- {
- CBrush brush(TextBkClr);
- pDC->FillRect(rect, &brush);
- }
- rect.right--; rect.bottom--;
- pDC->SelectStockObject(BLACK_PEN);
- pDC->SelectStockObject(NULL_BRUSH);
- pDC->Rectangle(rect);
- pDC->SetTextColor(TextClr);
- rect.DeflateRect(1,1);
- }
- else if (Item.state & GVIS_SELECTED
- #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
- && !pDC->IsPrinting()
- #endif
- )
- {
- rect.right++; rect.bottom++; // FillRect doesn't draw RHS or bottom
- pDC->FillSolidRect(rect, ::GetSysColor(COLOR_HIGHLIGHT));
- rect.right--; rect.bottom--;
- pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));
- } else {
- rect.right++; rect.bottom++; // FillRect doesn't draw RHS or bottom
- if (bEraseBk)
- {
- CBrush brush(TextBkClr);
- pDC->FillRect(rect, &brush);
- }
- rect.right--; rect.bottom--;
- pDC->SetTextColor(TextClr);
- }
- if (Item.state & GVIS_DROPHILITED
- #if !defined(_WIN32_WCE_NO_PRINTING) && !defined(GRIDCONTROL_NO_PRINTING)
- && !pDC->IsPrinting()
- #endif
- )
- {
- pDC->SelectStockObject(BLACK_PEN);
- pDC->SelectStockObject(NULL_BRUSH);
- pDC->Rectangle(rect);
- }
- // Create the appropriate font and select into DC
- LOGFONT *pLF = GetItemFont(nRow, nCol);
- //CCellID FocusCell = GetFocusCell();
- //if (IsCellFixed(nRow, nCol) && (FocusCell.row == nRow || FocusCell.col == nCol))
- //{
- // static LOGFONT lf;
- // memcpy(&lf, pLF, sizeof(LOGFONT));
- // lf.lfWeight = SELECTED_CELL_FONT_WEIGHT;
- // pLF = &lf;
- //}
-
- CFont Font;
- Font.CreateFontIndirect(pLF);
- pDC->SelectObject(&Font);
- rect.DeflateRect(m_nMargin, 0);
- if (m_pImageList && Item.iImage >= 0)
- {
- IMAGEINFO Info;
- if (m_pImageList->GetImageInfo(Item.iImage, &Info))
- {
- //CRgn rgn;
- //rgn.CreateRectRgnIndirect(rect);
- //pDC->SelectClipRgn(&rgn);
- //rgn.DeleteObject();
- int nImageWidth = Info.rcImage.right-Info.rcImage.left+1;
- m_pImageList->Draw(pDC, Item.iImage, rect.TopLeft(), ILD_NORMAL);
- rect.left += nImageWidth+m_nMargin;
- }
- }
- DrawText(pDC->m_hDC, Item.szText, -1, rect, Item.nFormat);
- pDC->RestoreDC(nSavedDC);
- Font.DeleteObject();
- return TRUE;
- }
- void CGridCtrl::OnEditCell(int nRow, int nCol, UINT nChar)
- {
- EnsureVisible(nRow, nCol);
- CCellID cell(nRow, nCol);
- if (!IsValid(cell) || !IsCellEditable(nRow, nCol) || !IsCellVisible(nRow, nCol))
- return;
- CRect rect;
- if (!GetCellRect(cell, rect)) return;
- SendMessageToParent(nRow, nCol, GVN_BEGINLABELEDIT);
- GV_ITEM Item;
- Item.mask = GVIF_TEXT | GVIF_FORMAT;
- Item.row = nRow;
- Item.col = nCol;
- if (!GetItem(&Item)) return;
- DWORD dwStyle = ES_LEFT;
- if (Item.nFormat & DT_RIGHT) dwStyle = ES_RIGHT;
- else if (Item.nFormat & DT_CENTER) dwStyle = ES_CENTER;
- CreateInPlaceEditControl(rect, dwStyle, IDC_INPLACE_CONTROL,
- nRow, nCol, Item.szText, nChar);
- }
- void CGridCtrl::CreateInPlaceEditControl(CRect& rect, DWORD dwStyle, UINT nID,
- int nRow, int nCol,
- LPCTSTR szText, int nChar)
- {
- // InPlaceEdit auto-deletes itself
- new CInPlaceEdit(this, rect, dwStyle, nID, nRow, nCol, szText, nChar);
- }
- void CGridCtrl::OnEndEditCell(int nRow, int nCol, CString str)
- {
- CString strCurrent = GetItemText(nRow,nCol);
- if (strCurrent != str)
- {
- SetModified(TRUE, nRow, nCol);
- SetItemText(nRow, nCol, str);
- }
- }
- CString CGridCtrl::GetItemText(int nRow, int nCol)
- {
- if (nRow < 0 || nRow >= m_nRows || nCol < 0 || nCol >= m_nCols) return "";
- CGridCell* pCell = GetCell(nRow, nCol);
- ASSERT(pCell);
- if (!pCell) return "";
- return pCell->szText;
- }
|