12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946 |
- /*
- Open Tracker License
- Terms and Conditions
- Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
- Permission is hereby granted, free of charge, to any person obtaining a copy of
- this software and associated documentation files (the "Software"), to deal in
- the Software without restriction, including without limitation the rights to
- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- of the Software, and to permit persons to whom the Software is furnished to do
- so, subject to the following conditions:
- The above copyright notice and this permission notice applies to all licensees
- and shall be included in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
- AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- Except as contained in this notice, the name of Be Incorporated shall not be
- used in advertising or otherwise to promote the sale, use or other dealings in
- this Software without prior written authorization from Be Incorporated.
- Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
- of Be Incorporated in the United States and other countries. Other brand product
- names are registered trademarks or trademarks of their respective holders.
- All rights reserved.
- */
- /*******************************************************************************
- /
- / File: ColumnListView.cpp
- /
- / Description: Experimental multi-column list view.
- /
- / Copyright 2000+, Be Incorporated, All Rights Reserved
- / By Jeff Bush
- /
- *******************************************************************************/
- #include "ColumnListView.h"
- #include <typeinfo>
- #include <stdio.h>
- #include <stdlib.h>
- #include <Application.h>
- #include <Bitmap.h>
- #include <ControlLook.h>
- #include <Cursor.h>
- #include <Debug.h>
- #include <GraphicsDefs.h>
- #include <LayoutUtils.h>
- #include <MenuItem.h>
- #include <PopUpMenu.h>
- #include <Region.h>
- #include <ScrollBar.h>
- #include <String.h>
- #include <SupportDefs.h>
- #include <Window.h>
- #include "ObjectListPrivate.h"
- #include "ColorTools.h"
- #include "ObjectList.h"
- #define DOUBLE_BUFFERED_COLUMN_RESIZE 1
- #define SMART_REDRAW 1
- #define DRAG_TITLE_OUTLINE 1
- #define CONSTRAIN_CLIPPING_REGION 1
- #define LOWER_SCROLLBAR 0
- namespace BPrivate {
- static const unsigned char kDownSortArrow8x8[] = {
- 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff
- };
- static const unsigned char kUpSortArrow8x8[] = {
- 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff
- };
- static const unsigned char kDownSortArrow8x8Invert[] = {
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff
- };
- static const unsigned char kUpSortArrow8x8Invert[] = {
- 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0x1f, 0x1f, 0x1f, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
- };
- static const float kTintedLineTint = 1.04;
- static const float kTitleHeight = 16.0;
- static const float kLatchWidth = 15.0;
- static const rgb_color kColor[B_COLOR_TOTAL] =
- {
- {255, 255, 255, 255}, // B_COLOR_BACKGROUND
- { 0, 0, 0, 255}, // B_COLOR_TEXT
- {148, 148, 148, 255}, // B_COLOR_ROW_DIVIDER
- {190, 190, 190, 255}, // B_COLOR_SELECTION
- { 0, 0, 0, 255}, // B_COLOR_SELECTION_TEXT
- {200, 200, 200, 255}, // B_COLOR_NON_FOCUS_SELECTION
- {180, 180, 180, 180}, // B_COLOR_EDIT_BACKGROUND
- { 0, 0, 0, 255}, // B_COLOR_EDIT_TEXT
- {215, 215, 215, 255}, // B_COLOR_HEADER_BACKGROUND
- { 0, 0, 0, 255}, // B_COLOR_HEADER_TEXT
- { 0, 0, 0, 255}, // B_COLOR_SEPARATOR_LINE
- { 0, 0, 0, 255}, // B_COLOR_SEPARATOR_BORDER
- };
- static const int32 kMaxDepth = 1024;
- static const float kLeftMargin = kLatchWidth;
- static const float kRightMargin = 8;
- static const float kOutlineLevelIndent = kLatchWidth;
- static const float kColumnResizeAreaWidth = 10.0;
- static const float kRowDragSensitivity = 5.0;
- static const float kDoubleClickMoveSensitivity = 4.0;
- static const float kSortIndicatorWidth = 9.0;
- static const float kDropHighlightLineHeight = 2.0;
- static const uint32 kToggleColumn = 'BTCL';
- class BRowContainer : public BObjectList<BRow>
- {
- };
- class TitleView : public BView {
- typedef BView _inherited;
- public:
- TitleView(BRect frame, OutlineView* outlineView,
- BList* visibleColumns, BList* sortColumns,
- BColumnListView* masterView,
- uint32 resizingMode);
- virtual ~TitleView();
- void ColumnAdded(BColumn* column);
- void ColumnResized(BColumn* column, float oldWidth);
- void SetColumnVisible(BColumn* column, bool visible);
- virtual void Draw(BRect updateRect);
- virtual void ScrollTo(BPoint where);
- virtual void MessageReceived(BMessage* message);
- virtual void MouseDown(BPoint where);
- virtual void MouseMoved(BPoint where, uint32 transit,
- const BMessage* dragMessage);
- virtual void MouseUp(BPoint where);
- virtual void FrameResized(float width, float height);
- void MoveColumn(BColumn* column, int32 index);
- void SetColumnFlags(column_flags flags);
- void SetEditMode(bool state)
- { fEditMode = state; }
- float MarginWidth() const;
- private:
- void GetTitleRect(BColumn* column, BRect* _rect);
- int32 FindColumn(BPoint where, float* _leftEdge);
- void FixScrollBar(bool scrollToFit);
- void DragSelectedColumn(BPoint where);
- void ResizeSelectedColumn(BPoint where,
- bool preferred = false);
- void ComputeDragBoundries(BColumn* column,
- BPoint where);
- void DrawTitle(BView* view, BRect frame,
- BColumn* column, bool depressed);
- float _VirtualWidth() const;
- OutlineView* fOutlineView;
- BList* fColumns;
- BList* fSortColumns;
- // float fColumnsWidth;
- BRect fVisibleRect;
- #if DOUBLE_BUFFERED_COLUMN_RESIZE
- BBitmap* fDrawBuffer;
- BView* fDrawBufferView;
- #endif
- enum {
- INACTIVE,
- RESIZING_COLUMN,
- PRESSING_COLUMN,
- DRAG_COLUMN_INSIDE_TITLE,
- DRAG_COLUMN_OUTSIDE_TITLE
- } fCurrentState;
- BPopUpMenu* fColumnPop;
- BColumnListView* fMasterView;
- bool fEditMode;
- int32 fColumnFlags;
- // State information for resizing/dragging
- BColumn* fSelectedColumn;
- BRect fSelectedColumnRect;
- bool fResizingFirstColumn;
- BPoint fClickPoint; // offset within cell
- float fLeftDragBoundry;
- float fRightDragBoundry;
- BPoint fCurrentDragPosition;
- BBitmap* fUpSortArrow;
- BBitmap* fDownSortArrow;
- BCursor* fResizeCursor;
- BCursor* fMinResizeCursor;
- BCursor* fMaxResizeCursor;
- BCursor* fColumnMoveCursor;
- };
- class OutlineView : public BView {
- typedef BView _inherited;
- public:
- OutlineView(BRect, BList* visibleColumns,
- BList* sortColumns,
- BColumnListView* listView);
- virtual ~OutlineView();
- virtual void Draw(BRect);
- const BRect& VisibleRect() const;
- void RedrawColumn(BColumn* column, float leftEdge,
- bool isFirstColumn);
- void StartSorting();
- float GetColumnPreferredWidth(BColumn* column);
- void AddRow(BRow*, int32 index, BRow* TheRow);
- BRow* CurrentSelection(BRow* lastSelected) const;
- void ToggleFocusRowSelection(bool selectRange);
- void ToggleFocusRowOpen();
- void ChangeFocusRow(bool up, bool updateSelection,
- bool addToCurrentSelection);
- void MoveFocusToVisibleRect();
- void ExpandOrCollapse(BRow* parent, bool expand);
- void RemoveRow(BRow*);
- BRowContainer* RowList();
- void UpdateRow(BRow*);
- bool FindParent(BRow* row, BRow** _parent,
- bool* _isVisible);
- int32 IndexOf(BRow* row);
- void Deselect(BRow*);
- void AddToSelection(BRow*);
- void DeselectAll();
- BRow* FocusRow() const;
- void SetFocusRow(BRow* row, bool select);
- BRow* FindRow(float ypos, int32* _indent,
- float* _top);
- bool FindRect(const BRow* row, BRect* _rect);
- void ScrollTo(const BRow* row);
- void Clear();
- void SetSelectionMode(list_view_type type);
- list_view_type SelectionMode() const;
- void SetMouseTrackingEnabled(bool);
- void FixScrollBar(bool scrollToFit);
- void SetEditMode(bool state)
- { fEditMode = state; }
- virtual void FrameResized(float width, float height);
- virtual void ScrollTo(BPoint where);
- virtual void MouseDown(BPoint where);
- virtual void MouseMoved(BPoint where, uint32 transit,
- const BMessage* dragMessage);
- virtual void MouseUp(BPoint where);
- virtual void MessageReceived(BMessage* message);
- private:
- bool SortList(BRowContainer* list, bool isVisible);
- static int32 DeepSortThreadEntry(void* outlineView);
- void DeepSort();
- void SelectRange(BRow* start, BRow* end);
- int32 CompareRows(BRow* row1, BRow* row2);
- void AddSorted(BRowContainer* list, BRow* row);
- void RecursiveDeleteRows(BRowContainer* list,
- bool owner);
- void InvalidateCachedPositions();
- bool FindVisibleRect(BRow* row, BRect* _rect);
- BList* fColumns;
- BList* fSortColumns;
- float fItemsHeight;
- BRowContainer fRows;
- BRect fVisibleRect;
- #if DOUBLE_BUFFERED_COLUMN_RESIZE
- BBitmap* fDrawBuffer;
- BView* fDrawBufferView;
- #endif
- BRow* fFocusRow;
- BRect fFocusRowRect;
- BRow* fRollOverRow;
- BRow fSelectionListDummyHead;
- BRow* fLastSelectedItem;
- BRow* fFirstSelectedItem;
- thread_id fSortThread;
- int32 fNumSorted;
- bool fSortCancelled;
- enum CurrentState {
- INACTIVE,
- LATCH_CLICKED,
- ROW_CLICKED,
- DRAGGING_ROWS
- };
- CurrentState fCurrentState;
- BColumnListView* fMasterView;
- list_view_type fSelectionMode;
- bool fTrackMouse;
- BField* fCurrentField;
- BRow* fCurrentRow;
- BColumn* fCurrentColumn;
- bool fMouseDown;
- BRect fFieldRect;
- int32 fCurrentCode;
- bool fEditMode;
- // State information for mouse/keyboard interaction
- BPoint fClickPoint;
- bool fDragging;
- int32 fClickCount;
- BRow* fTargetRow;
- float fTargetRowTop;
- BRect fLatchRect;
- float fDropHighlightY;
- friend class RecursiveOutlineIterator;
- };
- class RecursiveOutlineIterator {
- public:
- RecursiveOutlineIterator(
- BRowContainer* container,
- bool openBranchesOnly = true);
- BRow* CurrentRow() const;
- int32 CurrentLevel() const;
- void GoToNext();
- private:
- struct {
- BRowContainer* fRowSet;
- int32 fIndex;
- int32 fDepth;
- } fStack[kMaxDepth];
- int32 fStackIndex;
- BRowContainer* fCurrentList;
- int32 fCurrentListIndex;
- int32 fCurrentListDepth;
- bool fOpenBranchesOnly;
- };
- } // namespace BPrivate
- using namespace BPrivate;
- BField::BField()
- {
- }
- BField::~BField()
- {
- }
- // #pragma mark -
- void
- BColumn::MouseMoved(BColumnListView* /*parent*/, BRow* /*row*/,
- BField* /*field*/, BRect /*field_rect*/, BPoint/*point*/,
- uint32 /*buttons*/, int32 /*code*/)
- {
- }
- void
- BColumn::MouseDown(BColumnListView* /*parent*/, BRow* /*row*/,
- BField* /*field*/, BRect /*field_rect*/, BPoint /*point*/,
- uint32 /*buttons*/)
- {
- }
- void
- BColumn::MouseUp(BColumnListView* /*parent*/, BRow* /*row*/, BField* /*field*/)
- {
- }
- // #pragma mark -
- BRow::BRow(float height)
- :
- fChildList(NULL),
- fIsExpanded(false),
- fHeight(height),
- fNextSelected(NULL),
- fPrevSelected(NULL),
- fParent(NULL),
- fList(NULL)
- {
- }
- BRow::~BRow()
- {
- while (true) {
- BField* field = (BField*) fFields.RemoveItem((int32)0);
- if (field == 0)
- break;
- delete field;
- }
- }
- bool
- BRow::HasLatch() const
- {
- return fChildList != 0;
- }
- int32
- BRow::CountFields() const
- {
- return fFields.CountItems();
- }
- BField*
- BRow::GetField(int32 index)
- {
- return (BField*)fFields.ItemAt(index);
- }
- const BField*
- BRow::GetField(int32 index) const
- {
- return (const BField*)fFields.ItemAt(index);
- }
- void
- BRow::SetField(BField* field, int32 logicalFieldIndex)
- {
- if (fFields.ItemAt(logicalFieldIndex) != 0)
- delete (BField*)fFields.RemoveItem(logicalFieldIndex);
- if (NULL != fList) {
- ValidateField(field, logicalFieldIndex);
- BRect inv;
- fList->GetRowRect(this, &inv);
- fList->Invalidate(inv);
- }
- fFields.AddItem(field, logicalFieldIndex);
- }
- float
- BRow::Height() const
- {
- return fHeight;
- }
- bool
- BRow::IsExpanded() const
- {
- return fIsExpanded;
- }
- bool
- BRow::IsSelected() const
- {
- return fPrevSelected != NULL;
- }
- void
- BRow::ValidateFields() const
- {
- for (int32 i = 0; i < CountFields(); i++)
- ValidateField(GetField(i), i);
- }
- void
- BRow::ValidateField(const BField* field, int32 logicalFieldIndex) const
- {
- // The Fields may be moved by the user, but the logicalFieldIndexes
- // do not change, so we need to map them over when checking the
- // Field types.
- BColumn* col = NULL;
- int32 items = fList->CountColumns();
- for (int32 i = 0 ; i < items; ++i) {
- col = fList->ColumnAt(i);
- if( col->LogicalFieldNum() == logicalFieldIndex )
- break;
- }
- if (NULL == col) {
- BString dbmessage("\n\n\tThe parent BColumnListView does not have "
- "\n\ta BColumn at the logical field index ");
- dbmessage << logicalFieldIndex << ".\n\n";
- printf(dbmessage.String());
- } else {
- if (!col->AcceptsField(field)) {
- BString dbmessage("\n\n\tThe BColumn of type ");
- dbmessage << typeid(*col).name() << "\n\tat logical field index "
- << logicalFieldIndex << "\n\tdoes not support the "
- "field type "
- << typeid(*field).name() << ".\n\n";
- debugger(dbmessage.String());
- }
- }
- }
- // #pragma mark -
- BColumn::BColumn(float width, float minWidth, float maxWidth, alignment align)
- :
- fWidth(width),
- fMinWidth(minWidth),
- fMaxWidth(maxWidth),
- fVisible(true),
- fList(0),
- fShowHeading(true),
- fAlignment(align)
- {
- }
- BColumn::~BColumn()
- {
- }
- float
- BColumn::Width() const
- {
- return fWidth;
- }
- void
- BColumn::SetWidth(float width)
- {
- fWidth = width;
- }
- float
- BColumn::MinWidth() const
- {
- return fMinWidth;
- }
- float
- BColumn::MaxWidth() const
- {
- return fMaxWidth;
- }
- void
- BColumn::DrawTitle(BRect, BView*)
- {
- }
- void
- BColumn::DrawField(BField*, BRect, BView*)
- {
- }
- int
- BColumn::CompareFields(BField*, BField*)
- {
- return 0;
- }
- void
- BColumn::GetColumnName(BString* into) const
- {
- *into = "(Unnamed)";
- }
- float
- BColumn::GetPreferredWidth(BField* field, BView* parent) const
- {
- return fWidth;
- }
- bool
- BColumn::IsVisible() const
- {
- return fVisible;
- }
- void
- BColumn::SetVisible(bool visible)
- {
- if (fList && (fVisible != visible))
- fList->SetColumnVisible(this, visible);
- }
- bool
- BColumn::ShowHeading() const
- {
- return fShowHeading;
- }
- void
- BColumn::SetShowHeading(bool state)
- {
- fShowHeading = state;
- }
- alignment
- BColumn::Alignment() const
- {
- return fAlignment;
- }
- void
- BColumn::SetAlignment(alignment align)
- {
- fAlignment = align;
- }
- bool
- BColumn::WantsEvents() const
- {
- return fWantsEvents;
- }
- void
- BColumn::SetWantsEvents(bool state)
- {
- fWantsEvents = state;
- }
- int32
- BColumn::LogicalFieldNum() const
- {
- return fFieldID;
- }
- bool
- BColumn::AcceptsField(const BField*) const
- {
- return true;
- }
- // #pragma mark -
- BColumnListView::BColumnListView(BRect rect, const char* name,
- uint32 resizingMode, uint32 flags, border_style border,
- bool showHorizontalScrollbar)
- :
- BView(rect, name, resizingMode,
- flags | B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE),
- fStatusView(NULL),
- fSelectionMessage(NULL),
- fSortingEnabled(true),
- fLatchWidth(kLatchWidth),
- fBorderStyle(border),
- fShowingHorizontalScrollBar(showHorizontalScrollbar)
- {
- _Init();
- }
- BColumnListView::BColumnListView(const char* name, uint32 flags,
- border_style border, bool showHorizontalScrollbar)
- :
- BView(name, flags | B_WILL_DRAW | B_FRAME_EVENTS | B_FULL_UPDATE_ON_RESIZE),
- fStatusView(NULL),
- fSelectionMessage(NULL),
- fSortingEnabled(true),
- fLatchWidth(kLatchWidth),
- fBorderStyle(border),
- fShowingHorizontalScrollBar(showHorizontalScrollbar)
- {
- _Init();
- }
- BColumnListView::~BColumnListView()
- {
- while (BColumn* column = (BColumn*)fColumns.RemoveItem((int32)0))
- delete column;
- }
- bool
- BColumnListView::InitiateDrag(BPoint, bool)
- {
- return false;
- }
- void
- BColumnListView::MessageDropped(BMessage*, BPoint)
- {
- }
- void
- BColumnListView::ExpandOrCollapse(BRow* row, bool Open)
- {
- fOutlineView->ExpandOrCollapse(row, Open);
- }
- status_t
- BColumnListView::Invoke(BMessage* message)
- {
- if (message == 0)
- message = Message();
- return BInvoker::Invoke(message);
- }
- void
- BColumnListView::ItemInvoked()
- {
- Invoke();
- }
- void
- BColumnListView::SetInvocationMessage(BMessage* message)
- {
- SetMessage(message);
- }
- BMessage*
- BColumnListView::InvocationMessage() const
- {
- return Message();
- }
- uint32
- BColumnListView::InvocationCommand() const
- {
- return Command();
- }
- BRow*
- BColumnListView::FocusRow() const
- {
- return fOutlineView->FocusRow();
- }
- void
- BColumnListView::SetFocusRow(int32 Index, bool Select)
- {
- SetFocusRow(RowAt(Index), Select);
- }
- void
- BColumnListView::SetFocusRow(BRow* row, bool Select)
- {
- fOutlineView->SetFocusRow(row, Select);
- }
- void
- BColumnListView::SetMouseTrackingEnabled(bool Enabled)
- {
- fOutlineView->SetMouseTrackingEnabled(Enabled);
- }
- list_view_type
- BColumnListView::SelectionMode() const
- {
- return fOutlineView->SelectionMode();
- }
- void
- BColumnListView::Deselect(BRow* row)
- {
- fOutlineView->Deselect(row);
- }
- void
- BColumnListView::AddToSelection(BRow* row)
- {
- fOutlineView->AddToSelection(row);
- }
- void
- BColumnListView::DeselectAll()
- {
- fOutlineView->DeselectAll();
- }
- BRow*
- BColumnListView::CurrentSelection(BRow* lastSelected) const
- {
- return fOutlineView->CurrentSelection(lastSelected);
- }
- void
- BColumnListView::SelectionChanged()
- {
- if (fSelectionMessage)
- Invoke(fSelectionMessage);
- }
- void
- BColumnListView::SetSelectionMessage(BMessage* message)
- {
- if (fSelectionMessage == message)
- return;
- delete fSelectionMessage;
- fSelectionMessage = message;
- }
- BMessage*
- BColumnListView::SelectionMessage()
- {
- return fSelectionMessage;
- }
- uint32
- BColumnListView::SelectionCommand() const
- {
- if (fSelectionMessage)
- return fSelectionMessage->what;
- return 0;
- }
- void
- BColumnListView::SetSelectionMode(list_view_type mode)
- {
- fOutlineView->SetSelectionMode(mode);
- }
- void
- BColumnListView::SetSortingEnabled(bool enabled)
- {
- fSortingEnabled = enabled;
- fSortColumns.MakeEmpty();
- fTitleView->Invalidate(); // Erase sort indicators
- }
- bool
- BColumnListView::SortingEnabled() const
- {
- return fSortingEnabled;
- }
- void
- BColumnListView::SetSortColumn(BColumn* column, bool add, bool ascending)
- {
- if (!SortingEnabled())
- return;
- if (!add)
- fSortColumns.MakeEmpty();
- if (!fSortColumns.HasItem(column))
- fSortColumns.AddItem(column);
- column->fSortAscending = ascending;
- fTitleView->Invalidate();
- fOutlineView->StartSorting();
- }
- void
- BColumnListView::ClearSortColumns()
- {
- fSortColumns.MakeEmpty();
- fTitleView->Invalidate(); // Erase sort indicators
- }
- void
- BColumnListView::AddStatusView(BView* view)
- {
- BRect bounds = Bounds();
- float width = view->Bounds().Width();
- if (width > bounds.Width() / 2)
- width = bounds.Width() / 2;
- fStatusView = view;
- Window()->BeginViewTransaction();
- fHorizontalScrollBar->ResizeBy(-(width + 1), 0);
- fHorizontalScrollBar->MoveBy((width + 1), 0);
- AddChild(view);
- BRect viewRect(bounds);
- viewRect.right = width;
- viewRect.top = viewRect.bottom - B_H_SCROLL_BAR_HEIGHT;
- if (fBorderStyle == B_PLAIN_BORDER)
- viewRect.OffsetBy(1, -1);
- else if (fBorderStyle == B_FANCY_BORDER)
- viewRect.OffsetBy(2, -2);
- view->SetResizingMode(B_FOLLOW_LEFT | B_FOLLOW_BOTTOM);
- view->ResizeTo(viewRect.Width(), viewRect.Height());
- view->MoveTo(viewRect.left, viewRect.top);
- Window()->EndViewTransaction();
- }
- BView*
- BColumnListView::RemoveStatusView()
- {
- if (fStatusView) {
- float width = fStatusView->Bounds().Width();
- Window()->BeginViewTransaction();
- fStatusView->RemoveSelf();
- fHorizontalScrollBar->MoveBy(-width, 0);
- fHorizontalScrollBar->ResizeBy(width, 0);
- Window()->EndViewTransaction();
- }
- BView* view = fStatusView;
- fStatusView = 0;
- return view;
- }
- void
- BColumnListView::AddColumn(BColumn* column, int32 logicalFieldIndex)
- {
- ASSERT(column != NULL);
- column->fList = this;
- column->fFieldID = logicalFieldIndex;
- // sanity check. If there is already a field with this ID, remove it.
- for (int32 index = 0; index < fColumns.CountItems(); index++) {
- BColumn* existingColumn = (BColumn*) fColumns.ItemAt(index);
- if (existingColumn && existingColumn->fFieldID == logicalFieldIndex) {
- RemoveColumn(existingColumn);
- break;
- }
- }
- if (column->Width() < column->MinWidth())
- column->SetWidth(column->MinWidth());
- else if (column->Width() > column->MaxWidth())
- column->SetWidth(column->MaxWidth());
- fColumns.AddItem((void*) column);
- fTitleView->ColumnAdded(column);
- }
- void
- BColumnListView::MoveColumn(BColumn* column, int32 index)
- {
- ASSERT(column != NULL);
- fTitleView->MoveColumn(column, index);
- }
- void
- BColumnListView::RemoveColumn(BColumn* column)
- {
- if (fColumns.HasItem(column)) {
- SetColumnVisible(column, false);
- if (Window() != NULL)
- Window()->UpdateIfNeeded();
- fColumns.RemoveItem(column);
- }
- }
- int32
- BColumnListView::CountColumns() const
- {
- return fColumns.CountItems();
- }
- BColumn*
- BColumnListView::ColumnAt(int32 field) const
- {
- return (BColumn*) fColumns.ItemAt(field);
- }
- BColumn*
- BColumnListView::ColumnAt(BPoint point) const
- {
- float left = MAX(kLeftMargin, LatchWidth());
- for (int i = 0; BColumn* column = (BColumn*)fColumns.ItemAt(i); i++) {
- if (!column->IsVisible())
- continue;
- float right = left + column->Width();
- if (point.x >= left && point.x <= right)
- return column;
- left = right + 1;
- }
- return NULL;
- }
- void
- BColumnListView::SetColumnVisible(BColumn* column, bool visible)
- {
- fTitleView->SetColumnVisible(column, visible);
- }
- void
- BColumnListView::SetColumnVisible(int32 index, bool isVisible)
- {
- BColumn* column = ColumnAt(index);
- if (column)
- column->SetVisible(isVisible);
- }
- bool
- BColumnListView::IsColumnVisible(int32 index) const
- {
- BColumn* column = ColumnAt(index);
- if (column)
- return column->IsVisible();
- return false;
- }
- void
- BColumnListView::SetColumnFlags(column_flags flags)
- {
- fTitleView->SetColumnFlags(flags);
- }
- void
- BColumnListView::ResizeColumnToPreferred(int32 index)
- {
- BColumn* column = ColumnAt(index);
- if (column == NULL)
- return;
- // get the preferred column width
- float width = fOutlineView->GetColumnPreferredWidth(column);
- // set it
- float oldWidth = column->Width();
- column->SetWidth(width);
- fTitleView->ColumnResized(column, oldWidth);
- fOutlineView->Invalidate();
- }
- void
- BColumnListView::ResizeAllColumnsToPreferred()
- {
- int32 count = CountColumns();
- for (int32 i = 0; i < count; i++)
- ResizeColumnToPreferred(i);
- }
- const BRow*
- BColumnListView::RowAt(int32 Index, BRow* parentRow) const
- {
- if (parentRow == 0)
- return fOutlineView->RowList()->ItemAt(Index);
- return parentRow->fChildList ? parentRow->fChildList->ItemAt(Index) : NULL;
- }
- BRow*
- BColumnListView::RowAt(int32 Index, BRow* parentRow)
- {
- if (parentRow == 0)
- return fOutlineView->RowList()->ItemAt(Index);
- return parentRow->fChildList ? parentRow->fChildList->ItemAt(Index) : 0;
- }
- const BRow*
- BColumnListView::RowAt(BPoint point) const
- {
- float top;
- int32 indent;
- return fOutlineView->FindRow(point.y, &indent, &top);
- }
- BRow*
- BColumnListView::RowAt(BPoint point)
- {
- float top;
- int32 indent;
- return fOutlineView->FindRow(point.y, &indent, &top);
- }
- bool
- BColumnListView::GetRowRect(const BRow* row, BRect* outRect) const
- {
- return fOutlineView->FindRect(row, outRect);
- }
- bool
- BColumnListView::FindParent(BRow* row, BRow** _parent, bool* _isVisible) const
- {
- return fOutlineView->FindParent(row, _parent, _isVisible);
- }
- int32
- BColumnListView::IndexOf(BRow* row)
- {
- return fOutlineView->IndexOf(row);
- }
- int32
- BColumnListView::CountRows(BRow* parentRow) const
- {
- if (parentRow == 0)
- return fOutlineView->RowList()->CountItems();
- if (parentRow->fChildList)
- return parentRow->fChildList->CountItems();
- else
- return 0;
- }
- void
- BColumnListView::AddRow(BRow* row, BRow* parentRow)
- {
- AddRow(row, -1, parentRow);
- }
- void
- BColumnListView::AddRow(BRow* row, int32 index, BRow* parentRow)
- {
- row->fChildList = 0;
- row->fList = this;
- row->ValidateFields();
- fOutlineView->AddRow(row, index, parentRow);
- }
- void
- BColumnListView::RemoveRow(BRow* row)
- {
- fOutlineView->RemoveRow(row);
- row->fList = NULL;
- }
- void
- BColumnListView::UpdateRow(BRow* row)
- {
- fOutlineView->UpdateRow(row);
- }
- bool
- BColumnListView::SwapRows(int32 index1, int32 index2, BRow* parentRow1,
- BRow* parentRow2)
- {
- BRow* row1 = NULL;
- BRow* row2 = NULL;
- BRowContainer* container1 = NULL;
- BRowContainer* container2 = NULL;
- if (parentRow1 == NULL)
- container1 = fOutlineView->RowList();
- else
- container1 = parentRow1->fChildList;
- if (container1 == NULL)
- return false;
- if (parentRow2 == NULL)
- container2 = fOutlineView->RowList();
- else
- container2 = parentRow1->fChildList;
- if (container2 == NULL)
- return false;
- row1 = container1->ItemAt(index1);
- if (row1 == NULL)
- return false;
- row2 = container2->ItemAt(index2);
- if (row2 == NULL)
- return false;
- container1->ReplaceItem(index2, row1);
- container2->ReplaceItem(index1, row2);
- BRect rect1;
- BRect rect2;
- BRect rect;
- fOutlineView->FindRect(row1, &rect1);
- fOutlineView->FindRect(row2, &rect2);
- rect = rect1 | rect2;
- fOutlineView->Invalidate(rect);
- return true;
- }
- void
- BColumnListView::ScrollTo(const BRow* row)
- {
- fOutlineView->ScrollTo(row);
- }
- void
- BColumnListView::ScrollTo(BPoint point)
- {
- fOutlineView->ScrollTo(point);
- }
- void
- BColumnListView::Clear()
- {
- fOutlineView->Clear();
- }
- void
- BColumnListView::SetFont(const BFont* font, uint32 mask)
- {
- // This method is deprecated.
- fOutlineView->SetFont(font, mask);
- fTitleView->SetFont(font, mask);
- }
- void
- BColumnListView::SetFont(ColumnListViewFont font_num, const BFont* font,
- uint32 mask)
- {
- switch (font_num) {
- case B_FONT_ROW:
- fOutlineView->SetFont(font, mask);
- break;
- case B_FONT_HEADER:
- fTitleView->SetFont(font, mask);
- break;
- default:
- ASSERT(false);
- break;
- }
- }
- void
- BColumnListView::GetFont(ColumnListViewFont font_num, BFont* font) const
- {
- switch (font_num) {
- case B_FONT_ROW:
- fOutlineView->GetFont(font);
- break;
- case B_FONT_HEADER:
- fTitleView->GetFont(font);
- break;
- default:
- ASSERT(false);
- break;
- }
- }
- void
- BColumnListView::SetColor(ColumnListViewColor color_num, const rgb_color color)
- {
- if ((int)color_num < 0) {
- ASSERT(false);
- color_num = (ColumnListViewColor) 0;
- }
- if ((int)color_num >= (int)B_COLOR_TOTAL) {
- ASSERT(false);
- color_num = (ColumnListViewColor) (B_COLOR_TOTAL - 1);
- }
- fColorList[color_num] = color;
- }
- rgb_color
- BColumnListView::Color(ColumnListViewColor color_num) const
- {
- if ((int)color_num < 0) {
- ASSERT(false);
- color_num = (ColumnListViewColor) 0;
- }
- if ((int)color_num >= (int)B_COLOR_TOTAL) {
- ASSERT(false);
- color_num = (ColumnListViewColor) (B_COLOR_TOTAL - 1);
- }
- return fColorList[color_num];
- }
- void
- BColumnListView::SetHighColor(rgb_color color)
- {
- BView::SetHighColor(color);
- // fOutlineView->Invalidate(); // Redraw things with the new color
- // Note that this will currently cause
- // an infinite loop, refreshing over and over.
- // A better solution is needed.
- }
- void
- BColumnListView::SetSelectionColor(rgb_color color)
- {
- fColorList[B_COLOR_SELECTION] = color;
- }
- void
- BColumnListView::SetBackgroundColor(rgb_color color)
- {
- fColorList[B_COLOR_BACKGROUND] = color;
- fOutlineView->Invalidate(); // Repaint with new color
- }
- void
- BColumnListView::SetEditColor(rgb_color color)
- {
- fColorList[B_COLOR_EDIT_BACKGROUND] = color;
- }
- const rgb_color
- BColumnListView::SelectionColor() const
- {
- return fColorList[B_COLOR_SELECTION];
- }
- const rgb_color
- BColumnListView::BackgroundColor() const
- {
- return fColorList[B_COLOR_BACKGROUND];
- }
- const rgb_color
- BColumnListView::EditColor() const
- {
- return fColorList[B_COLOR_EDIT_BACKGROUND];
- }
- BPoint
- BColumnListView::SuggestTextPosition(const BRow* row,
- const BColumn* inColumn) const
- {
- BRect rect;
- GetRowRect(row, &rect);
- if (inColumn) {
- float leftEdge = MAX(kLeftMargin, LatchWidth());
- for (int index = 0; index < fColumns.CountItems(); index++) {
- BColumn* column = (BColumn*) fColumns.ItemAt(index);
- if (!column->IsVisible())
- continue;
- if (column == inColumn) {
- rect.left = leftEdge;
- rect.right = rect.left + column->Width();
- break;
- }
- leftEdge += column->Width() + 1;
- }
- }
- font_height fh;
- fOutlineView->GetFontHeight(&fh);
- float baseline = floor(rect.top + fh.ascent
- + (rect.Height()+1-(fh.ascent+fh.descent))/2);
- return BPoint(rect.left + 8, baseline);
- }
- void
- BColumnListView::SetLatchWidth(float width)
- {
- fLatchWidth = width;
- Invalidate();
- }
- float
- BColumnListView::LatchWidth() const
- {
- return fLatchWidth;
- }
- void
- BColumnListView::DrawLatch(BView* view, BRect rect, LatchType position, BRow*)
- {
- const int32 rectInset = 4;
- view->SetHighColor(0, 0, 0);
- // Make Square
- int32 sideLen = rect.IntegerWidth();
- if (sideLen > rect.IntegerHeight())
- sideLen = rect.IntegerHeight();
- // Make Center
- int32 halfWidth = rect.IntegerWidth() / 2;
- int32 halfHeight = rect.IntegerHeight() / 2;
- int32 halfSide = sideLen / 2;
- float left = rect.left + halfWidth - halfSide;
- float top = rect.top + halfHeight - halfSide;
- BRect itemRect(left, top, left + sideLen, top + sideLen);
- // Why it is a pixel high? I don't know.
- itemRect.OffsetBy(0, -1);
- itemRect.InsetBy(rectInset, rectInset);
- // Make it an odd number of pixels wide, the latch looks better this way
- if ((itemRect.IntegerWidth() % 2) == 1) {
- itemRect.right += 1;
- itemRect.bottom += 1;
- }
- switch (position) {
- case B_OPEN_LATCH:
- view->StrokeRect(itemRect);
- view->StrokeLine(
- BPoint(itemRect.left + 2,
- (itemRect.top + itemRect.bottom) / 2),
- BPoint(itemRect.right - 2,
- (itemRect.top + itemRect.bottom) / 2));
- break;
- case B_PRESSED_LATCH:
- view->StrokeRect(itemRect);
- view->StrokeLine(
- BPoint(itemRect.left + 2,
- (itemRect.top + itemRect.bottom) / 2),
- BPoint(itemRect.right - 2,
- (itemRect.top + itemRect.bottom) / 2));
- view->StrokeLine(
- BPoint((itemRect.left + itemRect.right) / 2,
- itemRect.top + 2),
- BPoint((itemRect.left + itemRect.right) / 2,
- itemRect.bottom - 2));
- view->InvertRect(itemRect);
- break;
- case B_CLOSED_LATCH:
- view->StrokeRect(itemRect);
- view->StrokeLine(
- BPoint(itemRect.left + 2,
- (itemRect.top + itemRect.bottom) / 2),
- BPoint(itemRect.right - 2,
- (itemRect.top + itemRect.bottom) / 2));
- view->StrokeLine(
- BPoint((itemRect.left + itemRect.right) / 2,
- itemRect.top + 2),
- BPoint((itemRect.left + itemRect.right) / 2,
- itemRect.bottom - 2));
- break;
- case B_NO_LATCH:
- // No drawing
- break;
- }
- }
- void
- BColumnListView::MakeFocus(bool isFocus)
- {
- if (fBorderStyle != B_NO_BORDER) {
- // Redraw focus marks around view
- Invalidate();
- fHorizontalScrollBar->SetBorderHighlighted(isFocus);
- fVerticalScrollBar->SetBorderHighlighted(isFocus);
- }
- BView::MakeFocus(isFocus);
- }
- void
- BColumnListView::MessageReceived(BMessage* message)
- {
- // Propagate mouse wheel messages down to child, so that it can
- // scroll. Note we have done so, so we don't go into infinite
- // recursion if this comes back up here.
- if (message->what == B_MOUSE_WHEEL_CHANGED) {
- bool handled;
- if (message->FindBool("be:clvhandled", &handled) != B_OK) {
- message->AddBool("be:clvhandled", true);
- fOutlineView->MessageReceived(message);
- return;
- }
- }
- BView::MessageReceived(message);
- }
- void
- BColumnListView::KeyDown(const char* bytes, int32 numBytes)
- {
- char c = bytes[0];
- switch (c) {
- case B_RIGHT_ARROW:
- case B_LEFT_ARROW:
- {
- float minVal, maxVal;
- fHorizontalScrollBar->GetRange(&minVal, &maxVal);
- float smallStep, largeStep;
- fHorizontalScrollBar->GetSteps(&smallStep, &largeStep);
- float oldVal = fHorizontalScrollBar->Value();
- float newVal = oldVal;
- if (c == B_LEFT_ARROW)
- newVal -= smallStep;
- else if (c == B_RIGHT_ARROW)
- newVal += smallStep;
- if (newVal < minVal)
- newVal = minVal;
- else if (newVal > maxVal)
- newVal = maxVal;
- fHorizontalScrollBar->SetValue(newVal);
- break;
- }
- case B_DOWN_ARROW:
- fOutlineView->ChangeFocusRow(false,
- (modifiers() & B_CONTROL_KEY) == 0,
- (modifiers() & B_SHIFT_KEY) != 0);
- break;
- case B_UP_ARROW:
- fOutlineView->ChangeFocusRow(true,
- (modifiers() & B_CONTROL_KEY) == 0,
- (modifiers() & B_SHIFT_KEY) != 0);
- break;
- case B_PAGE_UP:
- case B_PAGE_DOWN:
- {
- float minValue, maxValue;
- fVerticalScrollBar->GetRange(&minValue, &maxValue);
- float smallStep, largeStep;
- fVerticalScrollBar->GetSteps(&smallStep, &largeStep);
- float currentValue = fVerticalScrollBar->Value();
- float newValue = currentValue;
- if (c == B_PAGE_UP)
- newValue -= largeStep;
- else
- newValue += largeStep;
- if (newValue > maxValue)
- newValue = maxValue;
- else if (newValue < minValue)
- newValue = minValue;
- fVerticalScrollBar->SetValue(newValue);
- // Option + pgup or pgdn scrolls and changes the selection.
- if (modifiers() & B_OPTION_KEY)
- fOutlineView->MoveFocusToVisibleRect();
- break;
- }
- case B_ENTER:
- Invoke();
- break;
- case B_SPACE:
- fOutlineView->ToggleFocusRowSelection(
- (modifiers() & B_SHIFT_KEY) != 0);
- break;
- case '+':
- fOutlineView->ToggleFocusRowOpen();
- break;
- default:
- BView::KeyDown(bytes, numBytes);
- }
- }
- void
- BColumnListView::AttachedToWindow()
- {
- if (!Messenger().IsValid())
- SetTarget(Window());
- if (SortingEnabled()) fOutlineView->StartSorting();
- }
- void
- BColumnListView::WindowActivated(bool active)
- {
- fOutlineView->Invalidate();
- // Focus and selection appearance changes with focus
- Invalidate(); // Redraw focus marks around view
- BView::WindowActivated(active);
- }
- void
- BColumnListView::Draw(BRect updateRect)
- {
- BRect rect = Bounds();
- if (be_control_look != NULL) {
- uint32 flags = 0;
- if (IsFocus() && Window()->IsActive())
- flags |= BControlLook::B_FOCUSED;
- rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
- BRect verticalScrollBarFrame;
- if (!fVerticalScrollBar->IsHidden())
- verticalScrollBarFrame = fVerticalScrollBar->Frame();
- BRect horizontalScrollBarFrame;
- if (!fHorizontalScrollBar->IsHidden())
- horizontalScrollBarFrame = fHorizontalScrollBar->Frame();
- if (fBorderStyle == B_NO_BORDER) {
- // We still draw the left/top border, but not focused.
- // The scrollbars cannot be displayed without frame and
- // it looks bad to have no frame only along the left/top
- // side.
- rgb_color borderColor = tint_color(base, B_DARKEN_2_TINT);
- SetHighColor(borderColor);
- StrokeLine(BPoint(rect.left, rect.bottom),
- BPoint(rect.left, rect.top));
- StrokeLine(BPoint(rect.left + 1, rect.top),
- BPoint(rect.right, rect.top));
- }
- be_control_look->DrawScrollViewFrame(this, rect, updateRect,
- verticalScrollBarFrame, horizontalScrollBarFrame,
- base, fBorderStyle, flags);
- return;
- }
- BRect cornerRect(rect.right - B_V_SCROLL_BAR_WIDTH,
- rect.bottom - B_H_SCROLL_BAR_HEIGHT, rect.right, rect.bottom);
- if (fBorderStyle == B_PLAIN_BORDER) {
- BView::SetHighColor(0, 0, 0);
- StrokeRect(rect);
- cornerRect.OffsetBy(-1, -1);
- } else if (fBorderStyle == B_FANCY_BORDER) {
- bool isFocus = IsFocus() && Window()->IsActive();
- if (isFocus) {
- // TODO: Need to find focus color programatically
- BView::SetHighColor(0, 0, 190);
- } else
- BView::SetHighColor(255, 255, 255);
- StrokeRect(rect);
- if (!isFocus)
- BView::SetHighColor(184, 184, 184);
- else
- BView::SetHighColor(152, 152, 152);
- rect.InsetBy(1,1);
- StrokeRect(rect);
- cornerRect.OffsetBy(-2, -2);
- }
- BView::SetHighColor(ui_color(B_PANEL_BACKGROUND_COLOR));
- // fills lower right rect between scroll bars
- FillRect(cornerRect);
- }
- void
- BColumnListView::SaveState(BMessage* msg)
- {
- msg->MakeEmpty();
- for (int32 i = 0; BColumn* col = (BColumn*)fColumns.ItemAt(i); i++) {
- msg->AddInt32("ID",col->fFieldID);
- msg->AddFloat("width", col->fWidth);
- msg->AddBool("visible", col->fVisible);
- }
- msg->AddBool("sortingenabled", fSortingEnabled);
- if (fSortingEnabled) {
- for (int32 i = 0; BColumn* col = (BColumn*)fSortColumns.ItemAt(i);
- i++) {
- msg->AddInt32("sortID", col->fFieldID);
- msg->AddBool("sortascending", col->fSortAscending);
- }
- }
- }
- void
- BColumnListView::LoadState(BMessage* msg)
- {
- int32 id;
- for (int i = 0; msg->FindInt32("ID", i, &id) == B_OK; i++) {
- for (int j = 0; BColumn* column = (BColumn*)fColumns.ItemAt(j); j++) {
- if (column->fFieldID == id) {
- // move this column to position 'i' and set its attributes
- MoveColumn(column, i);
- float width;
- if (msg->FindFloat("width", i, &width) == B_OK)
- column->SetWidth(width);
- bool visible;
- if (msg->FindBool("visible", i, &visible) == B_OK)
- column->SetVisible(visible);
- }
- }
- }
- bool b;
- if (msg->FindBool("sortingenabled", &b) == B_OK) {
- SetSortingEnabled(b);
- for (int k = 0; msg->FindInt32("sortID", k, &id) == B_OK; k++) {
- for (int j = 0; BColumn* column = (BColumn*)fColumns.ItemAt(j);
- j++) {
- if (column->fFieldID == id) {
- // add this column to the sort list
- bool value;
- if (msg->FindBool("sortascending", k, &value) == B_OK)
- SetSortColumn(column, true, value);
- }
- }
- }
- }
- }
- void
- BColumnListView::SetEditMode(bool state)
- {
- fOutlineView->SetEditMode(state);
- fTitleView->SetEditMode(state);
- }
- void
- BColumnListView::Refresh()
- {
- if (LockLooper()) {
- Invalidate();
- fOutlineView->FixScrollBar (true);
- fOutlineView->Invalidate();
- Window()->UpdateIfNeeded();
- UnlockLooper();
- }
- }
- BSize
- BColumnListView::MinSize()
- {
- BSize size;
- size.width = 100;
- size.height = kTitleHeight + 4 * B_H_SCROLL_BAR_HEIGHT;
- if (!fHorizontalScrollBar->IsHidden())
- size.height += fHorizontalScrollBar->Frame().Height() + 1;
- // TODO: Take border size into account
- return BLayoutUtils::ComposeSize(ExplicitMinSize(), size);
- }
- BSize
- BColumnListView::PreferredSize()
- {
- BSize size = MinSize();
- size.height += ceilf(be_plain_font->Size()) * 20;
- // return MinSize().width if there are no columns.
- int32 count = CountColumns();
- if (count > 0) {
- BRect titleRect;
- BRect outlineRect;
- BRect vScrollBarRect;
- BRect hScrollBarRect;
- _GetChildViewRects(Bounds(), titleRect, outlineRect, vScrollBarRect,
- hScrollBarRect);
- // Start with the extra width for border and scrollbars etc.
- size.width = titleRect.left - Bounds().left;
- size.width += Bounds().right - titleRect.right;
- // If we want all columns to be visible at their preferred width,
- // we also need to add the extra margin width that the TitleView
- // uses to compute its _VirtualWidth() for the horizontal scroll bar.
- size.width += fTitleView->MarginWidth();
- for (int32 i = 0; i < count; i++) {
- BColumn* column = ColumnAt(i);
- if (column != NULL)
- size.width += fOutlineView->GetColumnPreferredWidth(column);
- }
- }
- return BLayoutUtils::ComposeSize(ExplicitPreferredSize(), size);
- }
- BSize
- BColumnListView::MaxSize()
- {
- BSize size(B_SIZE_UNLIMITED, B_SIZE_UNLIMITED);
- return BLayoutUtils::ComposeSize(ExplicitMaxSize(), size);
- }
- void
- BColumnListView::LayoutInvalidated(bool descendants)
- {
- }
- void
- BColumnListView::DoLayout()
- {
- if (!(Flags() & B_SUPPORTS_LAYOUT))
- return;
- BRect titleRect;
- BRect outlineRect;
- BRect vScrollBarRect;
- BRect hScrollBarRect;
- _GetChildViewRects(Bounds(), titleRect, outlineRect, vScrollBarRect,
- hScrollBarRect);
- fTitleView->MoveTo(titleRect.LeftTop());
- fTitleView->ResizeTo(titleRect.Width(), titleRect.Height());
- fOutlineView->MoveTo(outlineRect.LeftTop());
- fOutlineView->ResizeTo(outlineRect.Width(), outlineRect.Height());
- fVerticalScrollBar->MoveTo(vScrollBarRect.LeftTop());
- fVerticalScrollBar->ResizeTo(vScrollBarRect.Width(),
- vScrollBarRect.Height());
- fHorizontalScrollBar->MoveTo(hScrollBarRect.LeftTop());
- fHorizontalScrollBar->ResizeTo(hScrollBarRect.Width(),
- hScrollBarRect.Height());
- fOutlineView->FixScrollBar(true);
- }
- void
- BColumnListView::_Init()
- {
- SetViewColor(B_TRANSPARENT_32_BIT);
- BRect bounds(Bounds());
- if (bounds.Width() <= 0)
- bounds.right = 100;
- if (bounds.Height() <= 0)
- bounds.bottom = 100;
- for (int i = 0; i < (int)B_COLOR_TOTAL; i++)
- fColorList[i] = kColor[i];
- BRect titleRect;
- BRect outlineRect;
- BRect vScrollBarRect;
- BRect hScrollBarRect;
- _GetChildViewRects(bounds, titleRect, outlineRect, vScrollBarRect,
- hScrollBarRect);
- fOutlineView = new OutlineView(outlineRect, &fColumns, &fSortColumns, this);
- AddChild(fOutlineView);
- fTitleView = new TitleView(titleRect, fOutlineView, &fColumns,
- &fSortColumns, this, B_FOLLOW_LEFT_RIGHT | B_FOLLOW_TOP);
- AddChild(fTitleView);
- fVerticalScrollBar = new BScrollBar(vScrollBarRect, "vertical_scroll_bar",
- fOutlineView, 0.0, bounds.Height(), B_VERTICAL);
- AddChild(fVerticalScrollBar);
- fHorizontalScrollBar = new BScrollBar(hScrollBarRect,
- "horizontal_scroll_bar", fTitleView, 0.0, bounds.Width(), B_HORIZONTAL);
- AddChild(fHorizontalScrollBar);
- if (!fShowingHorizontalScrollBar)
- fHorizontalScrollBar->Hide();
- fOutlineView->FixScrollBar(true);
- }
- void
- BColumnListView::_GetChildViewRects(const BRect& bounds, BRect& titleRect,
- BRect& outlineRect, BRect& vScrollBarRect, BRect& hScrollBarRect)
- {
- titleRect = bounds;
- titleRect.bottom = titleRect.top + kTitleHeight;
- #if !LOWER_SCROLLBAR
- titleRect.right -= B_V_SCROLL_BAR_WIDTH;
- #endif
- outlineRect = bounds;
- outlineRect.top = titleRect.bottom + 1.0;
- outlineRect.right -= B_V_SCROLL_BAR_WIDTH;
- if (fShowingHorizontalScrollBar)
- outlineRect.bottom -= B_H_SCROLL_BAR_HEIGHT;
- vScrollBarRect = bounds;
- #if LOWER_SCROLLBAR
- vScrollBarRect.top += kTitleHeight;
- #endif
- vScrollBarRect.left = vScrollBarRect.right - B_V_SCROLL_BAR_WIDTH;
- if (fShowingHorizontalScrollBar)
- vScrollBarRect.bottom -= B_H_SCROLL_BAR_HEIGHT;
- hScrollBarRect = bounds;
- hScrollBarRect.top = hScrollBarRect.bottom - B_H_SCROLL_BAR_HEIGHT;
- hScrollBarRect.right -= B_V_SCROLL_BAR_WIDTH;
- // Adjust stuff so the border will fit.
- if (fBorderStyle == B_PLAIN_BORDER || fBorderStyle == B_NO_BORDER) {
- titleRect.InsetBy(1, 0);
- titleRect.OffsetBy(0, 1);
- outlineRect.InsetBy(1, 1);
- } else if (fBorderStyle == B_FANCY_BORDER) {
- titleRect.InsetBy(2, 0);
- titleRect.OffsetBy(0, 2);
- outlineRect.InsetBy(2, 2);
- vScrollBarRect.OffsetBy(-1, 0);
- #if LOWER_SCROLLBAR
- vScrollBarRect.top += 2;
- vScrollBarRect.bottom -= 1;
- #else
- vScrollBarRect.InsetBy(0, 1);
- #endif
- hScrollBarRect.OffsetBy(0, -1);
- hScrollBarRect.InsetBy(1, 0);
- }
- }
- // #pragma mark -
- TitleView::TitleView(BRect rect, OutlineView* horizontalSlave,
- BList* visibleColumns, BList* sortColumns, BColumnListView* listView,
- uint32 resizingMode)
- :
- BView(rect, "title_view", resizingMode, B_WILL_DRAW | B_FRAME_EVENTS),
- fOutlineView(horizontalSlave),
- fColumns(visibleColumns),
- fSortColumns(sortColumns),
- // fColumnsWidth(0),
- fVisibleRect(rect.OffsetToCopy(0, 0)),
- fCurrentState(INACTIVE),
- fColumnPop(NULL),
- fMasterView(listView),
- fEditMode(false),
- fColumnFlags(B_ALLOW_COLUMN_MOVE | B_ALLOW_COLUMN_RESIZE
- | B_ALLOW_COLUMN_POPUP | B_ALLOW_COLUMN_REMOVE)
- {
- SetViewColor(B_TRANSPARENT_COLOR);
- #if DOUBLE_BUFFERED_COLUMN_RESIZE
- // xxx this needs to be smart about the size of the backbuffer.
- BRect doubleBufferRect(0, 0, 600, 35);
- fDrawBuffer = new BBitmap(doubleBufferRect, B_RGB32, true);
- fDrawBufferView = new BView(doubleBufferRect, "double_buffer_view",
- B_FOLLOW_ALL_SIDES, 0);
- fDrawBuffer->Lock();
- fDrawBuffer->AddChild(fDrawBufferView);
- fDrawBuffer->Unlock();
- #endif
- fUpSortArrow = new BBitmap(BRect(0, 0, 7, 7), B_CMAP8);
- fDownSortArrow = new BBitmap(BRect(0, 0, 7, 7), B_CMAP8);
- fUpSortArrow->SetBits((const void*) kUpSortArrow8x8, 64, 0, B_CMAP8);
- fDownSortArrow->SetBits((const void*) kDownSortArrow8x8, 64, 0, B_CMAP8);
- fResizeCursor = new BCursor(B_CURSOR_ID_RESIZE_EAST_WEST);
- fMinResizeCursor = new BCursor(B_CURSOR_ID_RESIZE_EAST);
- fMaxResizeCursor = new BCursor(B_CURSOR_ID_RESIZE_WEST);
- fColumnMoveCursor = new BCursor(B_CURSOR_ID_MOVE);
- FixScrollBar(true);
- }
- TitleView::~TitleView()
- {
- delete fColumnPop;
- fColumnPop = NULL;
- #if DOUBLE_BUFFERED_COLUMN_RESIZE
- delete fDrawBuffer;
- #endif
- delete fUpSortArrow;
- delete fDownSortArrow;
- delete fResizeCursor;
- delete fMaxResizeCursor;
- delete fMinResizeCursor;
- delete fColumnMoveCursor;
- }
- void
- TitleView::ColumnAdded(BColumn* column)
- {
- // fColumnsWidth += column->Width();
- FixScrollBar(false);
- Invalidate();
- }
- void
- TitleView::ColumnResized(BColumn* column, float oldWidth)
- {
- // fColumnsWidth += column->Width() - oldWidth;
- FixScrollBar(false);
- Invalidate();
- }
- void
- TitleView::SetColumnVisible(BColumn* column, bool visible)
- {
- if (column->fVisible == visible)
- return;
- // If setting it visible, do this first so we can find its position
- // to invalidate. If hiding it, do it last.
- if (visible)
- column->fVisible = visible;
- BRect titleInvalid;
- GetTitleRect(column, &titleInvalid);
- // Now really set the visibility
- column->fVisible = visible;
- // if (visible)
- // fColumnsWidth += column->Width();
- // else
- // fColumnsWidth -= column->Width();
- BRect outlineInvalid(fOutlineView->VisibleRect());
- outlineInvalid.left = titleInvalid.left;
- titleInvalid.right = outlineInvalid.right;
- Invalidate(titleInvalid);
- fOutlineView->Invalidate(outlineInvalid);
- }
- void
- TitleView::GetTitleRect(BColumn* findColumn, BRect* _rect)
- {
- float leftEdge = MAX(kLeftMargin, fMasterView->LatchWidth());
- int32 numColumns = fColumns->CountItems();
- for (int index = 0; index < numColumns; index++) {
- BColumn* column = (BColumn*) fColumns->ItemAt(index);
- if (!column->IsVisible())
- continue;
- if (column == findColumn) {
- _rect->Set(leftEdge, 0, leftEdge + column->Width(),
- fVisibleRect.bottom);
- return;
- }
- leftEdge += column->Width() + 1;
- }
- TRESPASS();
- }
- int32
- TitleView::FindColumn(BPoint position, float* _leftEdge)
- {
- float leftEdge = MAX(kLeftMargin, fMasterView->LatchWidth());
- int32 numColumns = fColumns->CountItems();
- for (int index = 0; index < numColumns; index++) {
- BColumn* column = (BColumn*) fColumns->ItemAt(index);
- if (!column->IsVisible())
- continue;
- if (leftEdge > position.x)
- break;
- if (position.x >= leftEdge
- && position.x <= leftEdge + column->Width()) {
- *_leftEdge = leftEdge;
- return index;
- }
- leftEdge += column->Width() + 1;
- }
- return 0;
- }
- void
- TitleView::FixScrollBar(bool scrollToFit)
- {
- BScrollBar* hScrollBar = ScrollBar(B_HORIZONTAL);
- if (hScrollBar == NULL)
- return;
- float virtualWidth = _VirtualWidth();
- if (virtualWidth > fVisibleRect.Width()) {
- hScrollBar->SetProportion(fVisibleRect.Width() / virtualWidth);
- // Perform the little trick if the user is scrolled over too far.
- // See OutlineView::FixScrollBar for a more in depth explanation
- float maxScrollBarValue = virtualWidth - fVisibleRect.Width();
- if (scrollToFit || hScrollBar->Value() <= maxScrollBarValue) {
- hScrollBar->SetRange(0.0, maxScrollBarValue);
- hScrollBar->SetSteps(50, fVisibleRect.Width());
- }
- } else if (hScrollBar->Value() == 0.0) {
- // disable scroll bar.
- hScrollBar->SetRange(0.0, 0.0);
- }
- }
- void
- TitleView::DragSelectedColumn(BPoint position)
- {
- float invalidLeft = fSelectedColumnRect.left;
- float invalidRight = fSelectedColumnRect.right;
- float leftEdge;
- int32 columnIndex = FindColumn(position, &leftEdge);
- fSelectedColumnRect.OffsetTo(leftEdge, 0);
- MoveColumn(fSelectedColumn, columnIndex);
- fSelectedColumn->fVisible = true;
- ComputeDragBoundries(fSelectedColumn, position);
- // Redraw the new column position
- GetTitleRect(fSelectedColumn, &fSelectedColumnRect);
- invalidLeft = MIN(fSelectedColumnRect.left, invalidLeft);
- invalidRight = MAX(fSelectedColumnRect.right, invalidRight);
- Invalidate(BRect(invalidLeft, 0, invalidRight, fVisibleRect.bottom));
- fOutlineView->Invalidate(BRect(invalidLeft, 0, invalidRight,
- fOutlineView->VisibleRect().bottom));
- DrawTitle(this, fSelectedColumnRect, fSelectedColumn, true);
- }
- void
- TitleView::MoveColumn(BColumn* column, int32 index)
- {
- fColumns->RemoveItem((void*) column);
- if (-1 == index) {
- // Re-add the column at the end of the list.
- fColumns->AddItem((void*) column);
- } else {
- fColumns->AddItem((void*) column, index);
- }
- }
- void
- TitleView::SetColumnFlags(column_flags flags)
- {
- fColumnFlags = flags;
- }
- float
- TitleView::MarginWidth() const
- {
- return MAX(kLeftMargin, fMasterView->LatchWidth()) + kRightMargin;
- }
- void
- TitleView::ResizeSelectedColumn(BPoint position, bool preferred)
- {
- float minWidth = fSelectedColumn->MinWidth();
- float maxWidth = fSelectedColumn->MaxWidth();
- float oldWidth = fSelectedColumn->Width();
- float originalEdge = fSelectedColumnRect.left + oldWidth;
- if (preferred) {
- float width = fOutlineView->GetColumnPreferredWidth(fSelectedColumn);
- fSelectedColumn->SetWidth(width);
- } else if (position.x > fSelectedColumnRect.left + maxWidth)
- fSelectedColumn->SetWidth(maxWidth);
- else if (position.x < fSelectedColumnRect.left + minWidth)
- fSelectedColumn->SetWidth(minWidth);
- else
- fSelectedColumn->SetWidth(position.x - fSelectedColumnRect.left - 1);
- float dX = fSelectedColumnRect.left + fSelectedColumn->Width()
- - originalEdge;
- if (dX != 0) {
- float columnHeight = fVisibleRect.Height();
- BRect originalRect(originalEdge, 0, 1000000.0, columnHeight);
- BRect movedRect(originalRect);
- movedRect.OffsetBy(dX, 0);
- // Update the size of the title column
- BRect sourceRect(0, 0, fSelectedColumn->Width(), columnHeight);
- BRect destRect(sourceRect);
- destRect.OffsetBy(fSelectedColumnRect.left, 0);
- #if DOUBLE_BUFFERED_COLUMN_RESIZE
- fDrawBuffer->Lock();
- DrawTitle(fDrawBufferView, sourceRect, fSelectedColumn, false);
- fDrawBufferView->Sync();
- fDrawBuffer->Unlock();
- CopyBits(originalRect, movedRect);
- DrawBitmap(fDrawBuffer, sourceRect, destRect);
- #else
- CopyBits(originalRect, movedRect);
- DrawTitle(this, destRect, fSelectedColumn, false);
- #endif
- // Update the body view
- BRect slaveSize = fOutlineView->VisibleRect();
- BRect slaveSource(originalRect);
- slaveSource.bottom = slaveSize.bottom;
- BRect slaveDest(movedRect);
- slaveDest.bottom = slaveSize.bottom;
- fOutlineView->CopyBits(slaveSource, slaveDest);
- fOutlineView->RedrawColumn(fSelectedColumn, fSelectedColumnRect.left,
- fResizingFirstColumn);
- // fColumnsWidth += dX;
- // Update the cursor
- if (fSelectedColumn->Width() == minWidth)
- SetViewCursor(fMinResizeCursor, true);
- else if (fSelectedColumn->Width() == maxWidth)
- SetViewCursor(fMaxResizeCursor, true);
- else
- SetViewCursor(fResizeCursor, true);
- ColumnResized(fSelectedColumn, oldWidth);
- }
- }
- void
- TitleView::ComputeDragBoundries(BColumn* findColumn, BPoint)
- {
- float previousColumnLeftEdge = -1000000.0;
- float nextColumnRightEdge = 1000000.0;
- bool foundColumn = false;
- float leftEdge = MAX(kLeftMargin, fMasterView->LatchWidth());
- int32 numColumns = fColumns->CountItems();
- for (int index = 0; index < numColumns; index++) {
- BColumn* column = (BColumn*) fColumns->ItemAt(index);
- if (!column->IsVisible())
- continue;
- if (column == findColumn) {
- foundColumn = true;
- continue;
- }
- if (foundColumn) {
- nextColumnRightEdge = leftEdge + column->Width();
- break;
- } else
- previousColumnLeftEdge = leftEdge;
- leftEdge += column->Width() + 1;
- }
- float rightEdge = leftEdge + findColumn->Width();
- fLeftDragBoundry = MIN(previousColumnLeftEdge + findColumn->Width(),
- leftEdge);
- fRightDragBoundry = MAX(nextColumnRightEdge, rightEdge);
- }
- void
- TitleView::DrawTitle(BView* view, BRect rect, BColumn* column, bool depressed)
- {
- BRect drawRect;
- rgb_color borderColor = mix_color(
- fMasterView->Color(B_COLOR_HEADER_BACKGROUND),
- make_color(0, 0, 0), 128);
- rgb_color backgroundColor;
- rgb_color bevelHigh;
- rgb_color bevelLow;
- // Want exterior borders to overlap.
- if (be_control_look == NULL) {
- rect.right += 1;
- drawRect = rect;
- drawRect.InsetBy(2, 2);
- if (depressed) {
- backgroundColor = mix_color(
- fMasterView->Color(B_COLOR_HEADER_BACKGROUND),
- make_color(0, 0, 0), 64);
- bevelHigh = mix_color(backgroundColor, make_color(0, 0, 0), 64);
- bevelLow = mix_color(backgroundColor, make_color(255, 255, 255),
- 128);
- drawRect.left++;
- drawRect.top++;
- } else {
- backgroundColor = fMasterView->Color(B_COLOR_HEADER_BACKGROUND);
- bevelHigh = mix_color(backgroundColor, make_color(255, 255, 255),
- 192);
- bevelLow = mix_color(backgroundColor, make_color(0, 0, 0), 64);
- drawRect.bottom--;
- drawRect.right--;
- }
- } else {
- drawRect = rect;
- }
- font_height fh;
- GetFontHeight(&fh);
- float baseline = floor(drawRect.top + fh.ascent
- + (drawRect.Height() + 1 - (fh.ascent + fh.descent)) / 2);
- if (be_control_look != NULL) {
- BRect bgRect = rect;
- rgb_color base = ui_color(B_PANEL_BACKGROUND_COLOR);
- view->SetHighColor(tint_color(base, B_DARKEN_2_TINT));
- view->StrokeLine(bgRect.LeftBottom(), bgRect.RightBottom());
- bgRect.bottom--;
- bgRect.right--;
- if (depressed)
- base = tint_color(base, B_DARKEN_1_TINT);
- be_control_look->DrawButtonBackground(view, bgRect, rect, base, 0,
- BControlLook::B_TOP_BORDER | BControlLook::B_BOTTOM_BORDER);
- view->SetHighColor(tint_color(ui_color(B_PANEL_BACKGROUND_COLOR),
- B_DARKEN_2_TINT));
- view->StrokeLine(rect.RightTop(), rect.RightBottom());
- } else {
- view->SetHighColor(borderColor);
- view->StrokeRect(rect);
- view->BeginLineArray(4);
- view->AddLine(BPoint(rect.left + 1, rect.top + 1),
- BPoint(rect.right - 1, rect.top + 1), bevelHigh);
- view->AddLine(BPoint(rect.left + 1, rect.top + 1),
- BPoint(rect.left + 1, rect.bottom - 1), bevelHigh);
- view->AddLine(BPoint(rect.right - 1, rect.top + 1),
- BPoint(rect.right - 1, rect.bottom - 1), bevelLow);
- view->AddLine(BPoint(rect.left + 2, rect.bottom-1),
- BPoint(rect.right - 1, rect.bottom - 1), bevelLow);
- view->EndLineArray();
- view->SetHighColor(backgroundColor);
- view->SetLowColor(backgroundColor);
- view->FillRect(rect.InsetByCopy(2, 2));
- }
- // If no column given, nothing else to draw.
- if (!column)
- return;
- view->SetHighColor(fMasterView->Color(B_COLOR_HEADER_TEXT));
- BFont font;
- GetFont(&font);
- view->SetFont(&font);
- int sortIndex = fSortColumns->IndexOf(column);
- if (sortIndex >= 0) {
- // Draw sort notation.
- BPoint upperLeft(drawRect.right - kSortIndicatorWidth, baseline);
- if (fSortColumns->CountItems() > 1) {
- char str[256];
- sprintf(str, "%d", sortIndex + 1);
- const float w = view->StringWidth(str);
- upperLeft.x -= w;
- view->SetDrawingMode(B_OP_COPY);
- view->MovePenTo(BPoint(upperLeft.x + kSortIndicatorWidth,
- baseline));
- view->DrawString(str);
- }
- float bmh = fDownSortArrow->Bounds().Height()+1;
- view->SetDrawingMode(B_OP_OVER);
- if (column->fSortAscending) {
- BPoint leftTop(upperLeft.x, drawRect.top + (drawRect.IntegerHeight()
- - fDownSortArrow->Bounds().IntegerHeight()) / 2);
- view->DrawBitmapAsync(fDownSortArrow, leftTop);
- } else {
- BPoint leftTop(upperLeft.x, drawRect.top + (drawRect.IntegerHeight()
- - fUpSortArrow->Bounds().IntegerHeight()) / 2);
- view->DrawBitmapAsync(fUpSortArrow, leftTop);
- }
- upperLeft.y = baseline - bmh + floor((fh.ascent + fh.descent - bmh) / 2);
- if (upperLeft.y < drawRect.top)
- upperLeft.y = drawRect.top;
- // Adjust title stuff for sort indicator
- drawRect.right = upperLeft.x - 2;
- }
- if (drawRect.right > drawRect.left) {
- #if CONSTRAIN_CLIPPING_REGION
- BRegion clipRegion(drawRect);
- view->PushState();
- view->ConstrainClippingRegion(&clipRegion);
- #endif
- view->MovePenTo(BPoint(drawRect.left + 8, baseline));
- view->SetDrawingMode(B_OP_OVER);
- view->SetHighColor(fMasterView->Color(B_COLOR_HEADER_TEXT));
- column->DrawTitle(drawRect, view);
- #if CONSTRAIN_CLIPPING_REGION
- view->PopState();
- #endif
- }
- }
- float
- TitleView::_VirtualWidth() const
- {
- float width = MarginWidth();
- int32 count = fColumns->CountItems();
- for (int32 i = 0; i < count; i++) {
- BColumn* column = reinterpret_cast<BColumn*>(fColumns->ItemAt(i));
- width += column->Width();
- }
- return width;
- }
- void
- TitleView::Draw(BRect invalidRect)
- {
- float columnLeftEdge = MAX(kLeftMargin, fMasterView->LatchWidth());
- for (int32 columnIndex = 0; columnIndex < fColumns->CountItems();
- columnIndex++) {
- BColumn* column = (BColumn*) fColumns->ItemAt(columnIndex);
- if (!column->IsVisible())
- continue;
- if (columnLeftEdge > invalidRect.right)
- break;
- if (columnLeftEdge + column->Width() >= invalidRect.left) {
- BRect titleRect(columnLeftEdge, 0,
- columnLeftEdge + column->Width(), fVisibleRect.Height());
- DrawTitle(this, titleRect, column,
- (fCurrentState == DRAG_COLUMN_INSIDE_TITLE
- && fSelectedColumn == column));
- }
- columnLeftEdge += column->Width() + 1;
- }
- // Bevels for right title margin
- if (columnLeftEdge <= invalidRect.right) {
- BRect titleRect(columnLeftEdge, 0, Bounds().right + 2,
- fVisibleRect.Height());
- DrawTitle(this, titleRect, NULL, false);
- }
- // Bevels for left title margin
- if (invalidRect.left < MAX(kLeftMargin, fMasterView->LatchWidth())) {
- BRect titleRect(0, 0, MAX(kLeftMargin, fMasterView->LatchWidth()) - 1,
- fVisibleRect.Height());
- DrawTitle(this, titleRect, NULL, false);
- }
- #if DRAG_TITLE_OUTLINE
- // (Internal) Column Drag Indicator
- if (fCurrentState == DRAG_COLUMN_INSIDE_TITLE) {
- BRect dragRect(fSelectedColumnRect);
- dragRect.OffsetTo(fCurrentDragPosition.x - fClickPoint.x, 0);
- if (dragRect.Intersects(invalidRect)) {
- SetHighColor(0, 0, 255);
- StrokeRect(dragRect);
- }
- }
- #endif
- }
- void
- TitleView::ScrollTo(BPoint position)
- {
- fOutlineView->ScrollBy(position.x - fVisibleRect.left, 0);
- fVisibleRect.OffsetTo(position.x, position.y);
- // Perform the little trick if the user is scrolled over too far.
- // See OutlineView::ScrollTo for a more in depth explanation
- float maxScrollBarValue = _VirtualWidth() - fVisibleRect.Width();
- BScrollBar* hScrollBar = ScrollBar(B_HORIZONTAL);
- float min, max;
- hScrollBar->GetRange(&min, &max);
- if (max != maxScrollBarValue && position.x > maxScrollBarValue)
- FixScrollBar(true);
- _inherited::ScrollTo(position);
- }
- void
- TitleView::MessageReceived(BMessage* message)
- {
- if (message->what == kToggleColumn) {
- int32 num;
- if (message->FindInt32("be:field_num", &num) == B_OK) {
- for (int index = 0; index < fColumns->CountItems(); index++) {
- BColumn* column = (BColumn*) fColumns->ItemAt(index);
- if (!column)
- continue;
- if (column->LogicalFieldNum() == num)
- column->SetVisible(!column->IsVisible());
- }
- }
- return;
- } else {
- BView::MessageReceived(message);
- }
- }
- void
- TitleView::MouseDown(BPoint position)
- {
- if(fEditMode)
- return;
- int32 buttons = 1;
- Window()->CurrentMessage()->FindInt32("buttons", &buttons);
- if (buttons == B_SECONDARY_MOUSE_BUTTON
- && (fColumnFlags & B_ALLOW_COLUMN_POPUP)) {
- // Right mouse button -- bring up menu to show/hide columns.
- if (!fColumnPop) fColumnPop = new BPopUpMenu("Columns", false, false);
- fColumnPop->RemoveItems(0, fColumnPop->CountItems(), true);
- BMessenger me(this);
- for (int index = 0; index < fColumns->CountItems(); index++) {
- BColumn* column = (BColumn*) fColumns->ItemAt(index);
- if (!column) continue;
- BString name;
- column->GetColumnName(&name);
- BMessage* msg = new BMessage(kToggleColumn);
- msg->AddInt32("be:field_num", column->LogicalFieldNum());
- BMenuItem* it = new BMenuItem(name.String(), msg);
- it->SetMarked(column->IsVisible());
- it->SetTarget(me);
- fColumnPop->AddItem(it);
- }
- BPoint screenPosition = ConvertToScreen(position);
- BRect sticky(screenPosition, screenPosition);
- sticky.InsetBy(-5, -5);
- fColumnPop->Go(ConvertToScreen(position), true, false, sticky, true);
- return;
- }
- fResizingFirstColumn = true;
- float leftEdge = MAX(kLeftMargin, fMasterView->LatchWidth());
- for (int index = 0; index < fColumns->CountItems(); index++) {
- BColumn* column = (BColumn*) fColumns->ItemAt(index);
- if (!column->IsVisible())
- continue;
- if (leftEdge > position.x + kColumnResizeAreaWidth / 2)
- break;
- // Check for resizing a column
- float rightEdge = leftEdge + column->Width();
- if (column->ShowHeading()) {
- if (position.x > rightEdge - kColumnResizeAreaWidth / 2
- && position.x < rightEdge + kColumnResizeAreaWidth / 2
- && column->MaxWidth() > column->MinWidth()
- && (fColumnFlags & B_ALLOW_COLUMN_RESIZE)) {
- int32 clicks = 0;
- Window()->CurrentMessage()->FindInt32("clicks", &clicks);
- if (clicks == 2) {
- ResizeSelectedColumn(position, true);
- fCurrentState = INACTIVE;
- break;
- }
- fCurrentState = RESIZING_COLUMN;
- fSelectedColumn = column;
- fSelectedColumnRect.Set(leftEdge, 0, rightEdge,
- fVisibleRect.Height());
- fClickPoint = BPoint(position.x - rightEdge - 1,
- position.y - fSelectedColumnRect.top);
- SetMouseEventMask(B_POINTER_EVENTS,
- B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
- break;
- }
- fResizingFirstColumn = false;
- // Check for clicking on a column.
- if (position.x > leftEdge && position.x < rightEdge) {
- fCurrentState = PRESSING_COLUMN;
- fSelectedColumn = column;
- fSelectedColumnRect.Set(leftEdge, 0, rightEdge,
- fVisibleRect.Height());
- DrawTitle(this, fSelectedColumnRect, fSelectedColumn, true);
- fClickPoint = BPoint(position.x - fSelectedColumnRect.left,
- position.y - fSelectedColumnRect.top);
- SetMouseEventMask(B_POINTER_EVENTS,
- B_LOCK_WINDOW_FOCUS | B_NO_POINTER_HISTORY);
- break;
- }
- }
- leftEdge = rightEdge + 1;
- }
- }
- void
- TitleView::MouseMoved(BPoint position, uint32 transit,
- const BMessage* dragMessage)
- {
- if (fEditMode)
- return;
- // Handle column manipulation
- switch (fCurrentState) {
- case RESIZING_COLUMN:
- ResizeSelectedColumn(position - BPoint(fClickPoint.x, 0));
- break;
- case PRESSING_COLUMN: {
- if (abs((int32)(position.x - (fClickPoint.x
- + fSelectedColumnRect.left))) > kColumnResizeAreaWidth
- || abs((int32)(position.y - (fClickPoint.y
- + fSelectedColumnRect.top))) > kColumnResizeAreaWidth) {
- // User has moved the mouse more than the tolerable amount,
- // initiate a drag.
- if (transit == B_INSIDE_VIEW || transit == B_ENTERED_VIEW) {
- if(fColumnFlags & B_ALLOW_COLUMN_MOVE) {
- fCurrentState = DRAG_COLUMN_INSIDE_TITLE;
- ComputeDragBoundries(fSelectedColumn, position);
- SetViewCursor(fColumnMoveCursor, true);
- #if DRAG_TITLE_OUTLINE
- BRect invalidRect(fSelectedColumnRect);
- invalidRect.OffsetTo(position.x - fClickPoint.x, 0);
- fCurrentDragPosition = position;
- Invalidate(invalidRect);
- #endif
- }
- } else {
- if(fColumnFlags & B_ALLOW_COLUMN_REMOVE) {
- // Dragged outside view
- fCurrentState = DRAG_COLUMN_OUTSIDE_TITLE;
- fSelectedColumn->SetVisible(false);
- BRect dragRect(fSelectedColumnRect);
- // There is a race condition where the mouse may have
- // moved by the time we get to handle this message.
- // If the user drags a column very quickly, this
- // results in the annoying bug where the cursor is
- // outside of the rectangle that is being dragged
- // around. Call GetMouse with the checkQueue flag set
- // to false so we can get the most recent position of
- // the mouse. This minimizes this problem (although
- // it is currently not possible to completely eliminate
- // it).
- uint32 buttons;
- GetMouse(&position, &buttons, false);
- dragRect.OffsetTo(position.x - fClickPoint.x,
- position.y - dragRect.Height() / 2);
- BeginRectTracking(dragRect, B_TRACK_WHOLE_RECT);
- }
- }
- }
- break;
- }
- case DRAG_COLUMN_INSIDE_TITLE: {
- if (transit == B_EXITED_VIEW
- && (fColumnFlags & B_ALLOW_COLUMN_REMOVE)) {
- // Dragged outside view
- fCurrentState = DRAG_COLUMN_OUTSIDE_TITLE;
- fSelectedColumn->SetVisible(false);
- BRect dragRect(fSelectedColumnRect);
- // See explanation above.
- uint32 buttons;
- GetMouse(&position, &buttons, false);
- dragRect.OffsetTo(position.x - fClickPoint.x,
- position.y - fClickPoint.y);
- BeginRectTracking(dragRect, B_TRACK_WHOLE_RECT);
- } else if (position.x < fLeftDragBoundry
- || position.x > fRightDragBoundry) {
- DragSelectedColumn(position - BPoint(fClickPoint.x, 0));
- }
- #if DRAG_TITLE_OUTLINE
- // Set up the invalid rect to include the rect for the previous
- // position of the drag rect, as well as the new one.
- BRect invalidRect(fSelectedColumnRect);
- invalidRect.OffsetTo(fCurrentDragPosition.x - fClickPoint.x, 0);
- if (position.x < fCurrentDragPosition.x)
- invalidRect.left -= fCurrentDragPosition.x - position.x;
- else
- invalidRect.right += position.x - fCurrentDragPosition.x;
- fCurrentDragPosition = position;
- Invalidate(invalidRect);
- #endif
- break;
- }
- case DRAG_COLUMN_OUTSIDE_TITLE:
- if (transit == B_ENTERED_VIEW) {
- // Drag back into view
- EndRectTracking();
- fCurrentState = DRAG_COLUMN_INSIDE_TITLE;
- fSelectedColumn->SetVisible(true);
- DragSelectedColumn(position - BPoint(fClickPoint.x, 0));
- }
- break;
- case INACTIVE:
- // Check for cursor changes if we are over the resize area for
- // a column.
- BColumn* resizeColumn = 0;
- float leftEdge = MAX(kLeftMargin, fMasterView->LatchWidth());
- for (int index = 0; index < fColumns->CountItems(); index++) {
- BColumn* column = (BColumn*) fColumns->ItemAt(index);
- if (!column->IsVisible())
- continue;
- if (leftEdge > position.x + kColumnResizeAreaWidth / 2)
- break;
- float rightEdge = leftEdge + column->Width();
- if (position.x > rightEdge - kColumnResizeAreaWidth / 2
- && position.x < rightEdge + kColumnResizeAreaWidth / 2
- && column->MaxWidth() > column->MinWidth()) {
- resizeColumn = column;
- break;
- }
- leftEdge = rightEdge + 1;
- }
- // Update the cursor
- if (resizeColumn) {
- if (resizeColumn->Width() == resizeColumn->MinWidth())
- SetViewCursor(fMinResizeCursor, true);
- else if (resizeColumn->Width() == resizeColumn->MaxWidth())
- SetViewCursor(fMaxResizeCursor, true);
- else
- SetViewCursor(fResizeCursor, true);
- } else
- SetViewCursor(B_CURSOR_SYSTEM_DEFAULT, true);
- break;
- }
- }
- void
- TitleView::MouseUp(BPoint position)
- {
- if (fEditMode)
- return;
- switch (fCurrentState) {
- case RESIZING_COLUMN:
- ResizeSelectedColumn(position - BPoint(fClickPoint.x, 0));
- fCurrentState = INACTIVE;
- FixScrollBar(false);
- break;
- case PRESSING_COLUMN: {
- if (fMasterView->SortingEnabled()) {
- if (fSortColumns->HasItem(fSelectedColumn)) {
- if ((modifiers() & B_CONTROL_KEY) == 0
- && fSortColumns->CountItems() > 1) {
- fSortColumns->MakeEmpty();
- fSortColumns->AddItem(fSelectedColumn);
- }
- fSelectedColumn->fSortAscending
- = !fSelectedColumn->fSortAscending;
- } else {
- if ((modifiers() & B_CONTROL_KEY) == 0)
- fSortColumns->MakeEmpty();
- fSortColumns->AddItem(fSelectedColumn);
- fSelectedColumn->fSortAscending = true;
- }
- fOutlineView->StartSorting();
- }
- fCurrentState = INACTIVE;
- Invalidate();
- break;
- }
- case DRAG_COLUMN_INSIDE_TITLE:
- fCurrentState = INACTIVE;
- #if DRAG_TITLE_OUTLINE
- Invalidate(); // xxx Can make this smaller
- #else
- Invalidate(fSelectedColumnRect);
- #endif
- SetViewCursor(B_CURSOR_SYSTEM_DEFAULT, true);
- break;
- case DRAG_COLUMN_OUTSIDE_TITLE:
- fCurrentState = INACTIVE;
- EndRectTracking();
- SetViewCursor(B_CURSOR_SYSTEM_DEFAULT, true);
- break;
- default:
- ;
- }
- }
- void
- TitleView::FrameResized(float width, float height)
- {
- fVisibleRect.right = fVisibleRect.left + width;
- fVisibleRect.bottom = fVisibleRect.top + height;
- FixScrollBar(true);
- }
- // #pragma mark -
- OutlineView::OutlineView(BRect rect, BList* visibleColumns, BList* sortColumns,
- BColumnListView* listView)
- :
- BView(rect, "outline_view", B_FOLLOW_ALL_SIDES,
- B_WILL_DRAW | B_FRAME_EVENTS),
- fColumns(visibleColumns),
- fSortColumns(sortColumns),
- fItemsHeight(0.0),
- fVisibleRect(rect.OffsetToCopy(0, 0)),
- fFocusRow(0),
- fRollOverRow(0),
- fLastSelectedItem(0),
- fFirstSelectedItem(0),
- fSortThread(B_BAD_THREAD_ID),
- fCurrentState(INACTIVE),
- fMasterView(listView),
- fSelectionMode(B_MULTIPLE_SELECTION_LIST),
- fTrackMouse(false),
- fCurrentField(0),
- fCurrentRow(0),
- fCurrentColumn(0),
- fMouseDown(false),
- fCurrentCode(B_OUTSIDE_VIEW),
- fEditMode(false),
- fDragging(false),
- fClickCount(0),
- fDropHighlightY(-1)
- {
- SetViewColor(B_TRANSPARENT_COLOR);
- #if DOUBLE_BUFFERED_COLUMN_RESIZE
- // TODO: This needs to be smart about the size of the buffer.
- // Also, the buffer can be shared with the title's buffer.
- BRect doubleBufferRect(0, 0, 600, 35);
- fDrawBuffer = new BBitmap(doubleBufferRect, B_RGB32, true);
- fDrawBufferView = new BView(doubleBufferRect, "double_buffer_view",
- B_FOLLOW_ALL_SIDES, 0);
- fDrawBuffer->Lock();
- fDrawBuffer->AddChild(fDrawBufferView);
- fDrawBuffer->Unlock();
- #endif
- FixScrollBar(true);
- fSelectionListDummyHead.fNextSelected = &fSelectionListDummyHead;
- fSelectionListDummyHead.fPrevSelected = &fSelectionListDummyHead;
- }
- OutlineView::~OutlineView()
- {
- #if DOUBLE_BUFFERED_COLUMN_RESIZE
- delete fDrawBuffer;
- #endif
- Clear();
- }
- void
- OutlineView::Clear()
- {
- DeselectAll();
- // Make sure selection list doesn't point to deleted rows!
- RecursiveDeleteRows(&fRows, false);
- fItemsHeight = 0.0;
- FixScrollBar(true);
- Invalidate();
- }
- void
- OutlineView::SetSelectionMode(list_view_type mode)
- {
- DeselectAll();
- fSelectionMode = mode;
- }
- list_view_type
- OutlineView::SelectionMode() const
- {
- return fSelectionMode;
- }
- void
- OutlineView::Deselect(BRow* row)
- {
- if (row == NULL)
- return;
- if (row->fNextSelected != 0) {
- row->fNextSelected->fPrevSelected = row->fPrevSelected;
- row->fPrevSelected->fNextSelected = row->fNextSelected;
- row->fNextSelected = 0;
- row->fPrevSelected = 0;
- Invalidate();
- }
- }
- void
- OutlineView::AddToSelection(BRow* row)
- {
- if (row == NULL)
- return;
- if (row->fNextSelected == 0) {
- if (fSelectionMode == B_SINGLE_SELECTION_LIST)
- DeselectAll();
- row->fNextSelected = fSelectionListDummyHead.fNextSelected;
- row->fPrevSelected = &fSelectionListDummyHead;
- row->fNextSelected->fPrevSelected = row;
- row->fPrevSelected->fNextSelected = row;
- BRect invalidRect;
- if (FindVisibleRect(row, &invalidRect))
- Invalidate(invalidRect);
- }
- }
- void
- OutlineView::RecursiveDeleteRows(BRowContainer* list, bool isOwner)
- {
- if (list == NULL)
- return;
- while (true) {
- BRow* row = list->RemoveItemAt(0L);
- if (row == 0)
- break;
- if (row->fChildList)
- RecursiveDeleteRows(row->fChildList, true);
- delete row;
- }
- if (isOwner)
- delete list;
- }
- void
- OutlineView::RedrawColumn(BColumn* column, float leftEdge, bool isFirstColumn)
- {
- // TODO: Remove code duplication (private function which takes a view
- // pointer, pass "this" in non-double buffered mode)!
- // Watch out for sourceRect versus destRect though!
- if (!column)
- return;
- font_height fh;
- GetFontHeight(&fh);
- float line = 0.0;
- bool tintedLine = true;
- for (RecursiveOutlineIterator iterator(&fRows); iterator.CurrentRow();
- line += iterator.CurrentRow()->Height() + 1, iterator.GoToNext()) {
- BRow* row = iterator.CurrentRow();
- float rowHeight = row->Height();
- if (line > fVisibleRect.bottom)
- break;
- tintedLine = !tintedLine;
- if (line + rowHeight >= fVisibleRect.top) {
- #if DOUBLE_BUFFERED_COLUMN_RESIZE
- BRect sourceRect(0, 0, column->Width(), rowHeight);
- #endif
- BRect destRect(leftEdge, line, leftEdge + column->Width(),
- line + rowHeight);
- rgb_color highColor;
- rgb_color lowColor;
- if (row->fNextSelected != 0) {
- if (fEditMode) {
- highColor = fMasterView->Color(B_COLOR_EDIT_BACKGROUND);
- lowColor = fMasterView->Color(B_COLOR_EDIT_BACKGROUND);
- } else {
- highColor = fMasterView->Color(B_COLOR_SELECTION);
- lowColor = fMasterView->Color(B_COLOR_SELECTION);
- }
- } else {
- highColor = fMasterView->Color(B_COLOR_BACKGROUND);
- lowColor = fMasterView->Color(B_COLOR_BACKGROUND);
- }
- if (tintedLine)
- lowColor = tint_color(lowColor, kTintedLineTint);
- #if DOUBLE_BUFFERED_COLUMN_RESIZE
- fDrawBuffer->Lock();
- fDrawBufferView->SetHighColor(highColor);
- fDrawBufferView->SetLowColor(lowColor);
- BFont font;
- GetFont(&font);
- fDrawBufferView->SetFont(&font);
- fDrawBufferView->FillRect(sourceRect, B_SOLID_LOW);
- if (isFirstColumn) {
- // If this is the first column, double buffer drawing the latch
- // too.
- destRect.left += iterator.CurrentLevel() * kOutlineLevelIndent
- - fMasterView->LatchWidth();
- sourceRect.left += iterator.CurrentLevel() * kOutlineLevelIndent
- - fMasterView->LatchWidth();
- LatchType pos = B_NO_LATCH;
- if (row->HasLatch())
- pos = row->fIsExpanded ? B_OPEN_LATCH : B_CLOSED_LATCH;
- BRect latchRect(sourceRect);
- latchRect.right = latchRect.left + fMasterView->LatchWidth();
- fMasterView->DrawLatch(fDrawBufferView, latchRect, pos, row);
- }
- BField* field = row->GetField(column->fFieldID);
- if (field) {
- BRect fieldRect(sourceRect);
- if (isFirstColumn)
- fieldRect.left += fMasterView->LatchWidth();
- #if CONSTRAIN_CLIPPING_REGION
- BRegion clipRegion(fieldRect);
- fDrawBufferView->PushState();
- fDrawBufferView->ConstrainClippingRegion(&clipRegion);
- #endif
- fDrawBufferView->SetHighColor(fMasterView->Color(
- row->fNextSelected ? B_COLOR_SELECTION_TEXT
- : B_COLOR_TEXT));
- float baseline = floor(fieldRect.top + fh.ascent
- + (fieldRect.Height() + 1 - (fh.ascent+fh.descent)) / 2);
- fDrawBufferView->MovePenTo(fieldRect.left + 8, baseline);
- column->DrawField(field, fieldRect, fDrawBufferView);
- #if CONSTRAIN_CLIPPING_REGION
- fDrawBufferView->PopState();
- #endif
- }
- if (fFocusRow == row && !fEditMode && fMasterView->IsFocus()
- && Window()->IsActive()) {
- fDrawBufferView->SetHighColor(fMasterView->Color(
- B_COLOR_ROW_DIVIDER));
- fDrawBufferView->StrokeRect(BRect(-1, sourceRect.top,
- 10000.0, sourceRect.bottom));
- }
- fDrawBufferView->Sync();
- fDrawBuffer->Unlock();
- SetDrawingMode(B_OP_COPY);
- DrawBitmap(fDrawBuffer, sourceRect, destRect);
- #else
- SetHighColor(highColor);
- SetLowColor(lowColor);
- FillRect(destRect, B_SOLID_LOW);
- BField* field = row->GetField(column->fFieldID);
- if (field) {
- #if CONSTRAIN_CLIPPING_REGION
- BRegion clipRegion(destRect);
- PushState();
- ConstrainClippingRegion(&clipRegion);
- #endif
- SetHighColor(fMasterView->Color(row->fNextSelected
- ? B_COLOR_SELECTION_TEXT : B_COLOR_TEXT));
- float baseline = floor(destRect.top + fh.ascent
- + (destRect.Height() + 1 - (fh.ascent + fh.descent)) / 2);
- MovePenTo(destRect.left + 8, baseline);
- column->DrawField(field, destRect, this);
- #if CONSTRAIN_CLIPPING_REGION
- PopState();
- #endif
- }
- if (fFocusRow == row && !fEditMode && fMasterView->IsFocus()
- && Window()->IsActive()) {
- SetHighColor(fMasterView->Color(B_COLOR_ROW_DIVIDER));
- StrokeRect(BRect(0, destRect.top, 10000.0, destRect.bottom));
- }
- #endif
- }
- }
- }
- void
- OutlineView::Draw(BRect invalidBounds)
- {
- #if SMART_REDRAW
- BRegion invalidRegion;
- GetClippingRegion(&invalidRegion);
- #endif
- font_height fh;
- GetFontHeight(&fh);
- float line = 0.0;
- bool tintedLine = true;
- int32 numColumns = fColumns->CountItems();
- for (RecursiveOutlineIterator iterator(&fRows); iterator.CurrentRow();
- iterator.GoToNext()) {
- BRow* row = iterator.CurrentRow();
- if (line > invalidBounds.bottom)
- break;
- tintedLine = !tintedLine;
- float rowHeight = row->Height();
- if (line >= invalidBounds.top - rowHeight) {
- bool isFirstColumn = true;
- float fieldLeftEdge = MAX(kLeftMargin, fMasterView->LatchWidth());
- // setup background color
- rgb_color lowColor;
- if (row->fNextSelected != 0) {
- if (Window()->IsActive()) {
- if (fEditMode)
- lowColor = fMasterView->Color(B_COLOR_EDIT_BACKGROUND);
- else
- lowColor = fMasterView->Color(B_COLOR_SELECTION);
- }
- else
- lowColor = fMasterView->Color(B_COLOR_NON_FOCUS_SELECTION);
- } else
- lowColor = fMasterView->Color(B_COLOR_BACKGROUND);
- if (tintedLine)
- lowColor = tint_color(lowColor, kTintedLineTint);
- for (int columnIndex = 0; columnIndex < numColumns; columnIndex++) {
- BColumn* column = (BColumn*) fColumns->ItemAt(columnIndex);
- if (!column->IsVisible())
- continue;
- if (!isFirstColumn && fieldLeftEdge > invalidBounds.right)
- break;
- if (fieldLeftEdge + column->Width() >= invalidBounds.left) {
- BRect fullRect(fieldLeftEdge, line,
- fieldLeftEdge + column->Width(), line + rowHeight);
- bool clippedFirstColumn = false;
- // This happens when a column is indented past the
- // beginning of the next column.
- SetHighColor(lowColor);
- BRect destRect(fullRect);
- if (isFirstColumn) {
- fullRect.left -= fMasterView->LatchWidth();
- destRect.left += iterator.CurrentLevel()
- * kOutlineLevelIndent;
- if (destRect.left >= destRect.right) {
- // clipped
- FillRect(BRect(0, line, fieldLeftEdge
- + column->Width(), line + rowHeight));
- clippedFirstColumn = true;
- }
- FillRect(BRect(0, line, MAX(kLeftMargin,
- fMasterView->LatchWidth()), line + row->Height()));
- }
- #if SMART_REDRAW
- if (!clippedFirstColumn
- && invalidRegion.Intersects(fullRect)) {
- #else
- if (!clippedFirstColumn) {
- #endif
- FillRect(fullRect); // Using color set above
- // Draw the latch widget if it has one.
- if (isFirstColumn) {
- if (row == fTargetRow
- && fCurrentState == LATCH_CLICKED) {
- // Note that this only occurs if the user is
- // holding down a latch while items are added
- // in the background.
- BPoint pos;
- uint32 buttons;
- GetMouse(&pos, &buttons);
- if (fLatchRect.Contains(pos)) {
- fMasterView->DrawLatch(this, fLatchRect,
- B_PRESSED_LATCH, fTargetRow);
- } else {
- fMasterView->DrawLatch(this, fLatchRect,
- row->fIsExpanded ? B_OPEN_LATCH
- : B_CLOSED_LATCH, fTargetRow);
- }
- } else {
- LatchType pos = B_NO_LATCH;
- if (row->HasLatch())
- pos = row->fIsExpanded ? B_OPEN_LATCH
- : B_CLOSED_LATCH;
- fMasterView->DrawLatch(this,
- BRect(destRect.left
- - fMasterView->LatchWidth(),
- destRect.top, destRect.left,
- destRect.bottom), pos, row);
- }
- }
- SetHighColor(fMasterView->HighColor());
- // The master view just holds the high color for us.
- SetLowColor(lowColor);
- BField* field = row->GetField(column->fFieldID);
- if (field) {
- #if CONSTRAIN_CLIPPING_REGION
- BRegion clipRegion(destRect);
- PushState();
- ConstrainClippingRegion(&clipRegion);
- #endif
- SetHighColor(fMasterView->Color(
- row->fNextSelected ? B_COLOR_SELECTION_TEXT
- : B_COLOR_TEXT));
- float baseline = floor(destRect.top + fh.ascent
- + (destRect.Height() + 1
- - (fh.ascent+fh.descent)) / 2);
- MovePenTo(destRect.left + 8, baseline);
- column->DrawField(field, destRect, this);
- #if CONSTRAIN_CLIPPING_REGION
- PopState();
- #endif
- }
- }
- }
- isFirstColumn = false;
- fieldLeftEdge += column->Width() + 1;
- }
- if (fieldLeftEdge <= invalidBounds.right) {
- SetHighColor(lowColor);
- FillRect(BRect(fieldLeftEdge, line, invalidBounds.right,
- line + rowHeight));
- }
- }
- // indicate the keyboard focus row
- if (fFocusRow == row && !fEditMode && fMasterView->IsFocus()
- && Window()->IsActive()) {
- SetHighColor(fMasterView->Color(B_COLOR_ROW_DIVIDER));
- StrokeRect(BRect(0, line, 10000.0, line + rowHeight));
- }
- line += rowHeight + 1;
- }
- if (line <= invalidBounds.bottom) {
- // fill background below last item
- SetHighColor(fMasterView->Color(B_COLOR_BACKGROUND));
- FillRect(BRect(invalidBounds.left, line, invalidBounds.right,
- invalidBounds.bottom));
- }
- // Draw the drop target line
- if (fDropHighlightY != -1) {
- InvertRect(BRect(0, fDropHighlightY - kDropHighlightLineHeight / 2,
- 1000000, fDropHighlightY + kDropHighlightLineHeight / 2));
- }
- }
- BRow*
- OutlineView::FindRow(float ypos, int32* _rowIndent, float* _top)
- {
- if (_rowIndent && _top) {
- float line = 0.0;
- for (RecursiveOutlineIterator iterator(&fRows); iterator.CurrentRow();
- iterator.GoToNext()) {
- BRow* row = iterator.CurrentRow();
- if (line > ypos)
- break;
- float rowHeight = row->Height();
- if (ypos <= line + rowHeight) {
- *_top = line;
- *_rowIndent = iterator.CurrentLevel();
- return row;
- }
- line += rowHeight + 1;
- }
- }
- return NULL;
- }
- void OutlineView::SetMouseTrackingEnabled(bool enabled)
- {
- fTrackMouse = enabled;
- if (!enabled && fDropHighlightY != -1) {
- // Erase the old target line
- InvertRect(BRect(0, fDropHighlightY - kDropHighlightLineHeight / 2,
- 1000000, fDropHighlightY + kDropHighlightLineHeight / 2));
- fDropHighlightY = -1;
- }
- }
- //
- // Note that this interaction is not totally safe. If items are added to
- // the list in the background, the widget rect will be incorrect, possibly
- // resulting in drawing glitches. The code that adds items needs to be a little smarter
- // about invalidating state.
- //
- void
- OutlineView::MouseDown(BPoint position)
- {
- if (!fEditMode)
- fMasterView->MakeFocus(true);
- // Check to see if the user is clicking on a widget to open a section
- // of the list.
- bool reset_click_count = false;
- int32 indent;
- float rowTop;
- BRow* row = FindRow(position.y, &indent, &rowTop);
- if (row != NULL) {
- // Update fCurrentField
- bool handle_field = false;
- BField* new_field = 0;
- BRow* new_row = 0;
- BColumn* new_column = 0;
- BRect new_rect;
- if (position.y >= 0) {
- if (position.x >= 0) {
- float x = 0;
- for (int32 c = 0; c < fMasterView->CountColumns(); c++) {
- new_column = fMasterView->ColumnAt(c);
- if (!new_column->IsVisible())
- continue;
- if ((MAX(kLeftMargin, fMasterView->LatchWidth()) + x)
- + new_column->Width() >= position.x) {
- if (new_column->WantsEvents()) {
- new_field = row->GetField(c);
- new_row = row;
- FindRect(new_row,&new_rect);
- new_rect.left = MAX(kLeftMargin,
- fMasterView->LatchWidth()) + x;
- new_rect.right = new_rect.left
- + new_column->Width() - 1;
- handle_field = true;
- }
- break;
- }
- x += new_column->Width();
- }
- }
- }
- // Handle mouse down
- if (handle_field) {
- fMouseDown = true;
- fFieldRect = new_rect;
- fCurrentColumn = new_column;
- fCurrentRow = new_row;
- fCurrentField = new_field;
- fCurrentCode = B_INSIDE_VIEW;
- BMessage* message = Window()->CurrentMessage();
- int32 buttons = 1;
- message->FindInt32("buttons", &buttons);
- fCurrentColumn->MouseDown(fMasterView, fCurrentRow,
- fCurrentField, fFieldRect, position, buttons);
- }
- if (!fEditMode) {
- fTargetRow = row;
- fTargetRowTop = rowTop;
- FindVisibleRect(fFocusRow, &fFocusRowRect);
- float leftWidgetBoundry = indent * kOutlineLevelIndent
- + MAX(kLeftMargin, fMasterView->LatchWidth())
- - fMasterView->LatchWidth();
- fLatchRect.Set(leftWidgetBoundry, rowTop, leftWidgetBoundry
- + fMasterView->LatchWidth(), rowTop + row->Height());
- if (fLatchRect.Contains(position) && row->HasLatch()) {
- fCurrentState = LATCH_CLICKED;
- if (fTargetRow->fNextSelected != 0)
- SetHighColor(fMasterView->Color(B_COLOR_SELECTION));
- else
- SetHighColor(fMasterView->Color(B_COLOR_BACKGROUND));
- FillRect(fLatchRect);
- if (fLatchRect.Contains(position)) {
- fMasterView->DrawLatch(this, fLatchRect, B_PRESSED_LATCH,
- row);
- } else {
- fMasterView->DrawLatch(this, fLatchRect,
- fTargetRow->fIsExpanded ? B_OPEN_LATCH
- : B_CLOSED_LATCH, row);
- }
- } else {
- Invalidate(fFocusRowRect);
- fFocusRow = fTargetRow;
- FindVisibleRect(fFocusRow, &fFocusRowRect);
- ASSERT(fTargetRow != 0);
- if ((modifiers() & B_CONTROL_KEY) == 0)
- DeselectAll();
- if ((modifiers() & B_SHIFT_KEY) != 0 && fFirstSelectedItem != 0
- && fSelectionMode == B_MULTIPLE_SELECTION_LIST) {
- SelectRange(fFirstSelectedItem, fTargetRow);
- }
- else {
- if (fTargetRow->fNextSelected != 0) {
- // Unselect row
- fTargetRow->fNextSelected->fPrevSelected
- = fTargetRow->fPrevSelected;
- fTargetRow->fPrevSelected->fNextSelected
- = fTargetRow->fNextSelected;
- fTargetRow->fPrevSelected = 0;
- fTargetRow->fNextSelected = 0;
- fFirstSelectedItem = NULL;
- } else {
- // Select row
- if (fSelectionMode == B_SINGLE_SELECTION_LIST)
- DeselectAll();
- fTargetRow->fNextSelected
- = fSelectionListDummyHead.fNextSelected;
- fTargetRow->fPrevSelected
- = &fSelectionListDummyHead;
- fTargetRow->fNextSelected->fPrevSelected = fTargetRow;
- fTargetRow->fPrevSelected->fNextSelected = fTargetRow;
- fFirstSelectedItem = fTargetRow;
- }
- Invalidate(BRect(fVisibleRect.left, fTargetRowTop,
- fVisibleRect.right,
- fTargetRowTop + fTargetRow->Height()));
- }
- fCurrentState = ROW_CLICKED;
- if (fLastSelectedItem != fTargetRow)
- reset_click_count = true;
- fLastSelectedItem = fTargetRow;
- fMasterView->SelectionChanged();
- }
- }
- SetMouseEventMask(B_POINTER_EVENTS, B_LOCK_WINDOW_FOCUS |
- B_NO_POINTER_HISTORY);
- } else if (fFocusRow != 0) {
- // User clicked in open space, unhighlight focus row.
- FindVisibleRect(fFocusRow, &fFocusRowRect);
- fFocusRow = 0;
- Invalidate(fFocusRowRect);
- }
- // We stash the click counts here because the 'clicks' field
- // is not in the CurrentMessage() when MouseUp is called... ;(
- if (reset_click_count)
- fClickCount = 1;
- else
- Window()->CurrentMessage()->FindInt32("clicks", &fClickCount);
- fClickPoint = position;
- }
- void
- OutlineView::MouseMoved(BPoint position, uint32 /*transit*/,
- const BMessage* /*dragMessage*/)
- {
- if (!fMouseDown) {
- // Update fCurrentField
- bool handle_field = false;
- BField* new_field = 0;
- BRow* new_row = 0;
- BColumn* new_column = 0;
- BRect new_rect(0,0,0,0);
- if (position.y >=0 ) {
- float top;
- int32 indent;
- BRow* row = FindRow(position.y, &indent, &top);
- if (row && position.x >=0 ) {
- float x=0;
- for (int32 c=0;c<fMasterView->CountColumns();c++) {
- new_column = fMasterView->ColumnAt(c);
- if (!new_column->IsVisible())
- continue;
- if ((MAX(kLeftMargin,
- fMasterView->LatchWidth()) + x) + new_column->Width()
- > position.x) {
- if(new_column->WantsEvents()) {
- new_field = row->GetField(c);
- new_row = row;
- FindRect(new_row,&new_rect);
- new_rect.left = MAX(kLeftMargin,
- fMasterView->LatchWidth()) + x;
- new_rect.right = new_rect.left
- + new_column->Width() - 1;
- handle_field = true;
- }
- break;
- }
- x += new_column->Width();
- }
- }
- }
- // Handle mouse moved
- if (handle_field) {
- if (new_field != fCurrentField) {
- if (fCurrentField) {
- fCurrentColumn->MouseMoved(fMasterView, fCurrentRow,
- fCurrentField, fFieldRect, position, 0,
- fCurrentCode = B_EXITED_VIEW);
- }
- fCurrentColumn = new_column;
- fCurrentRow = new_row;
- fCurrentField = new_field;
- fFieldRect = new_rect;
- if (fCurrentField) {
- fCurrentColumn->MouseMoved(fMasterView, fCurrentRow,
- fCurrentField, fFieldRect, position, 0,
- fCurrentCode = B_ENTERED_VIEW);
- }
- } else {
- if (fCurrentField) {
- fCurrentColumn->MouseMoved(fMasterView, fCurrentRow,
- fCurrentField, fFieldRect, position, 0,
- fCurrentCode = B_INSIDE_VIEW);
- }
- }
- } else {
- if (fCurrentField) {
- fCurrentColumn->MouseMoved(fMasterView, fCurrentRow,
- fCurrentField, fFieldRect, position, 0,
- fCurrentCode = B_EXITED_VIEW);
- fCurrentField = 0;
- fCurrentColumn = 0;
- fCurrentRow = 0;
- }
- }
- } else {
- if (fCurrentField) {
- if (fFieldRect.Contains(position)) {
- if (fCurrentCode == B_OUTSIDE_VIEW
- || fCurrentCode == B_EXITED_VIEW) {
- fCurrentColumn->MouseMoved(fMasterView, fCurrentRow,
- fCurrentField, fFieldRect, position, 1,
- fCurrentCode = B_ENTERED_VIEW);
- } else {
- fCurrentColumn->MouseMoved(fMasterView, fCurrentRow,
- fCurrentField, fFieldRect, position, 1,
- fCurrentCode = B_INSIDE_VIEW);
- }
- } else {
- if (fCurrentCode == B_INSIDE_VIEW
- || fCurrentCode == B_ENTERED_VIEW) {
- fCurrentColumn->MouseMoved(fMasterView, fCurrentRow,
- fCurrentField, fFieldRect, position, 1,
- fCurrentCode = B_EXITED_VIEW);
- } else {
- fCurrentColumn->MouseMoved(fMasterView, fCurrentRow,
- fCurrentField, fFieldRect, position, 1,
- fCurrentCode = B_OUTSIDE_VIEW);
- }
- }
- }
- }
- if (!fEditMode) {
- switch (fCurrentState) {
- case LATCH_CLICKED:
- if (fTargetRow->fNextSelected != 0)
- SetHighColor(fMasterView->Color(B_COLOR_SELECTION));
- else
- SetHighColor(fMasterView->Color(B_COLOR_BACKGROUND));
- FillRect(fLatchRect);
- if (fLatchRect.Contains(position)) {
- fMasterView->DrawLatch(this, fLatchRect, B_PRESSED_LATCH,
- fTargetRow);
- } else {
- fMasterView->DrawLatch(this, fLatchRect,
- fTargetRow->fIsExpanded ? B_OPEN_LATCH : B_CLOSED_LATCH,
- fTargetRow);
- }
- break;
- case ROW_CLICKED:
- if (abs((int)(position.x - fClickPoint.x)) > kRowDragSensitivity
- || abs((int)(position.y - fClickPoint.y))
- > kRowDragSensitivity) {
- fCurrentState = DRAGGING_ROWS;
- fMasterView->InitiateDrag(fClickPoint,
- fTargetRow->fNextSelected != 0);
- }
- break;
- case DRAGGING_ROWS:
- #if 0
- // falls through...
- #else
- if (fTrackMouse /*&& message*/) {
- if (fVisibleRect.Contains(position)) {
- float top;
- int32 indent;
- BRow* target = FindRow(position.y, &indent, &top);
- if (target)
- SetFocusRow(target, true);
- }
- }
- break;
- #endif
- default: {
- if (fTrackMouse /*&& message*/) {
- // Draw a highlight line...
- if (fVisibleRect.Contains(position)) {
- float top;
- int32 indent;
- BRow* target = FindRow(position.y, &indent, &top);
- if (target == fRollOverRow)
- break;
- if (fRollOverRow) {
- BRect rect;
- FindRect(fRollOverRow, &rect);
- Invalidate(rect);
- }
- fRollOverRow = target;
- #if 0
- SetFocusRow(fRollOverRow,false);
- #else
- PushState();
- SetDrawingMode(B_OP_BLEND);
- SetHighColor(255, 255, 255, 255);
- BRect rect;
- FindRect(fRollOverRow, &rect);
- rect.bottom -= 1.0;
- FillRect(rect);
- PopState();
- #endif
- } else {
- if (fRollOverRow) {
- BRect rect;
- FindRect(fRollOverRow, &rect);
- Invalidate(rect);
- fRollOverRow = NULL;
- }
- }
- }
- }
- }
- }
- }
- void
- OutlineView::MouseUp(BPoint position)
- {
- if (fCurrentField) {
- fCurrentColumn->MouseUp(fMasterView, fCurrentRow, fCurrentField);
- fMouseDown = false;
- }
- if (fEditMode)
- return;
- switch (fCurrentState) {
- case LATCH_CLICKED:
- if (fLatchRect.Contains(position)) {
- fMasterView->ExpandOrCollapse(fTargetRow,
- !fTargetRow->fIsExpanded);
- }
- Invalidate(fLatchRect);
- fCurrentState = INACTIVE;
- break;
- case ROW_CLICKED:
- if (fClickCount > 1
- && abs((int)fClickPoint.x - (int)position.x)
- < kDoubleClickMoveSensitivity
- && abs((int)fClickPoint.y - (int)position.y)
- < kDoubleClickMoveSensitivity) {
- fMasterView->ItemInvoked();
- }
- fCurrentState = INACTIVE;
- break;
- case DRAGGING_ROWS:
- fCurrentState = INACTIVE;
- // Falls through
- default:
- if (fDropHighlightY != -1) {
- InvertRect(BRect(0,
- fDropHighlightY - kDropHighlightLineHeight / 2,
- 1000000, fDropHighlightY + kDropHighlightLineHeight / 2));
- // Erase the old target line
- fDropHighlightY = -1;
- }
- }
- }
- void
- OutlineView::MessageReceived(BMessage* message)
- {
- if (message->WasDropped()) {
- fMasterView->MessageDropped(message,
- ConvertFromScreen(message->DropPoint()));
- } else {
- BView::MessageReceived(message);
- }
- }
- void
- OutlineView::ChangeFocusRow(bool up, bool updateSelection,
- bool addToCurrentSelection)
- {
- int32 indent;
- float top;
- float newRowPos = 0;
- float verticalScroll = 0;
- if (fFocusRow) {
- // A row currently has the focus, get information about it
- newRowPos = fFocusRowRect.top + (up ? -4 : fFocusRow->Height() + 4);
- if (newRowPos < fVisibleRect.top + 20)
- verticalScroll = newRowPos - 20;
- else if (newRowPos > fVisibleRect.bottom - 20)
- verticalScroll = newRowPos - fVisibleRect.Height() + 20;
- } else
- newRowPos = fVisibleRect.top + 2;
- // no row is currently focused, set this to the top of the window
- // so we will select the first visible item in the list.
- BRow* newRow = FindRow(newRowPos, &indent, &top);
- if (newRow) {
- if (fFocusRow) {
- fFocusRowRect.right = 10000;
- Invalidate(fFocusRowRect);
- }
- fFocusRow = newRow;
- fFocusRowRect.top = top;
- fFocusRowRect.left = 0;
- fFocusRowRect.right = 10000;
- fFocusRowRect.bottom = fFocusRowRect.top + fFocusRow->Height();
- Invalidate(fFocusRowRect);
- if (updateSelection) {
- if (!addToCurrentSelection
- || fSelectionMode == B_SINGLE_SELECTION_LIST) {
- DeselectAll();
- }
- if (fFocusRow->fNextSelected == 0) {
- fFocusRow->fNextSelected
- = fSelectionListDummyHead.fNextSelected;
- fFocusRow->fPrevSelected = &fSelectionListDummyHead;
- fFocusRow->fNextSelected->fPrevSelected = fFocusRow;
- fFocusRow->fPrevSelected->fNextSelected = fFocusRow;
- }
- fLastSelectedItem = fFocusRow;
- }
- } else
- Invalidate(fFocusRowRect);
- if (verticalScroll != 0) {
- BScrollBar* vScrollBar = ScrollBar(B_VERTICAL);
- float min, max;
- vScrollBar->GetRange(&min, &max);
- if (verticalScroll < min)
- verticalScroll = min;
- else if (verticalScroll > max)
- verticalScroll = max;
- vScrollBar->SetValue(verticalScroll);
- }
- if (newRow && updateSelection)
- fMasterView->SelectionChanged();
- }
- void
- OutlineView::MoveFocusToVisibleRect()
- {
- fFocusRow = 0;
- ChangeFocusRow(true, true, false);
- }
- BRow*
- OutlineView::CurrentSelection(BRow* lastSelected) const
- {
- BRow* row;
- if (lastSelected == 0)
- row = fSelectionListDummyHead.fNextSelected;
- else
- row = lastSelected->fNextSelected;
- if (row == &fSelectionListDummyHead)
- row = 0;
- return row;
- }
- void
- OutlineView::ToggleFocusRowSelection(bool selectRange)
- {
- if (fFocusRow == 0)
- return;
- if (selectRange && fSelectionMode == B_MULTIPLE_SELECTION_LIST)
- SelectRange(fLastSelectedItem, fFocusRow);
- else {
- if (fFocusRow->fNextSelected != 0) {
- // Unselect row
- fFocusRow->fNextSelected->fPrevSelected = fFocusRow->fPrevSelected;
- fFocusRow->fPrevSelected->fNextSelected = fFocusRow->fNextSelected;
- fFocusRow->fPrevSelected = 0;
- fFocusRow->fNextSelected = 0;
- } else {
- // Select row
- if (fSelectionMode == B_SINGLE_SELECTION_LIST)
- DeselectAll();
- fFocusRow->fNextSelected = fSelectionListDummyHead.fNextSelected;
- fFocusRow->fPrevSelected = &fSelectionListDummyHead;
- fFocusRow->fNextSelected->fPrevSelected = fFocusRow;
- fFocusRow->fPrevSelected->fNextSelected = fFocusRow;
- }
- }
- fLastSelectedItem = fFocusRow;
- fMasterView->SelectionChanged();
- Invalidate(fFocusRowRect);
- }
- void
- OutlineView::ToggleFocusRowOpen()
- {
- if (fFocusRow)
- fMasterView->ExpandOrCollapse(fFocusRow, !fFocusRow->fIsExpanded);
- }
- void
- OutlineView::ExpandOrCollapse(BRow* parentRow, bool expand)
- {
- // TODO: Could use CopyBits here to speed things up.
- if (parentRow == NULL)
- return;
- if (parentRow->fIsExpanded == expand)
- return;
- parentRow->fIsExpanded = expand;
- BRect parentRect;
- if (FindRect(parentRow, &parentRect)) {
- // Determine my new height
- float subTreeHeight = 0.0;
- if (parentRow->fIsExpanded)
- for (RecursiveOutlineIterator iterator(parentRow->fChildList);
- iterator.CurrentRow();
- iterator.GoToNext()
- )
- {
- subTreeHeight += iterator.CurrentRow()->Height()+1;
- }
- else
- for (RecursiveOutlineIterator iterator(parentRow->fChildList);
- iterator.CurrentRow();
- iterator.GoToNext()
- )
- {
- subTreeHeight -= iterator.CurrentRow()->Height()+1;
- }
- fItemsHeight += subTreeHeight;
- // Adjust focus row if necessary.
- if (FindRect(fFocusRow, &fFocusRowRect) == false) {
- // focus row is in a subtree that has collapsed,
- // move it up to the parent.
- fFocusRow = parentRow;
- FindRect(fFocusRow, &fFocusRowRect);
- }
- Invalidate(BRect(0, parentRect.top, fVisibleRect.right,
- fVisibleRect.bottom));
- FixScrollBar(false);
- }
- }
- void
- OutlineView::RemoveRow(BRow* row)
- {
- if (row == NULL)
- return;
- BRow* parentRow;
- bool parentIsVisible;
- FindParent(row, &parentRow, &parentIsVisible);
- // NOTE: This could be a root row without a parent, in which case
- // it is always visible, though.
- // Adjust height for the visible sub-tree that is going to be removed.
- float subTreeHeight = 0.0f;
- if (parentIsVisible && (parentRow == NULL || parentRow->fIsExpanded)) {
- // The row itself is visible at least.
- subTreeHeight = row->Height() + 1;
- if (row->fIsExpanded) {
- // Adjust for the height of visible sub-items as well.
- // (By default, the iterator follows open branches only.)
- for (RecursiveOutlineIterator iterator(row->fChildList);
- iterator.CurrentRow(); iterator.GoToNext())
- subTreeHeight += iterator.CurrentRow()->Height() + 1;
- }
- BRect invalid;
- if (FindRect(row, &invalid)) {
- invalid.bottom = Bounds().bottom;
- if (invalid.IsValid())
- Invalidate(invalid);
- }
- }
- fItemsHeight -= subTreeHeight;
- FixScrollBar(false);
- int32 indent = 0;
- float top = 0.0;
- if (FindRow(fVisibleRect.top, &indent, &top) == NULL && ScrollBar(B_VERTICAL) != NULL) {
- // after removing this row, no rows are actually visible any more,
- // force a scroll to make them visible again
- if (fItemsHeight > fVisibleRect.Height())
- ScrollBy(0.0, fItemsHeight - fVisibleRect.Height() - Bounds().top);
- else
- ScrollBy(0.0, -Bounds().top);
- }
- if (parentRow != NULL) {
- parentRow->fChildList->RemoveItem(row);
- if (parentRow->fChildList->CountItems() == 0) {
- delete parentRow->fChildList;
- parentRow->fChildList = 0;
- // It was the last child row of the parent, which also means the
- // latch disappears.
- BRect parentRowRect;
- if (parentIsVisible && FindRect(parentRow, &parentRowRect))
- Invalidate(parentRowRect);
- }
- } else
- fRows.RemoveItem(row);
- // Adjust focus row if necessary.
- if (fFocusRow && !FindRect(fFocusRow, &fFocusRowRect)) {
- // focus row is in a subtree that is gone, move it up to the parent.
- fFocusRow = parentRow;
- if (fFocusRow)
- FindRect(fFocusRow, &fFocusRowRect);
- }
- // Remove this from the selection if necessary
- if (row->fNextSelected != 0) {
- row->fNextSelected->fPrevSelected = row->fPrevSelected;
- row->fPrevSelected->fNextSelected = row->fNextSelected;
- row->fPrevSelected = 0;
- row->fNextSelected = 0;
- fMasterView->SelectionChanged();
- }
- fCurrentColumn = 0;
- fCurrentRow = 0;
- fCurrentField = 0;
- }
- BRowContainer*
- OutlineView::RowList()
- {
- return &fRows;
- }
- void
- OutlineView::UpdateRow(BRow* row)
- {
- if (row) {
- // Determine if this row has changed its sort order
- BRow* parentRow = NULL;
- bool parentIsVisible = false;
- FindParent(row, &parentRow, &parentIsVisible);
- BRowContainer* list = (parentRow == NULL) ? &fRows : parentRow->fChildList;
- if(list) {
- int32 rowIndex = list->IndexOf(row);
- ASSERT(rowIndex >= 0);
- ASSERT(list->ItemAt(rowIndex) == row);
- bool rowMoved = false;
- if (rowIndex > 0 && CompareRows(list->ItemAt(rowIndex - 1), row) > 0)
- rowMoved = true;
- if (rowIndex < list->CountItems() - 1 && CompareRows(list->ItemAt(rowIndex + 1),
- row) < 0)
- rowMoved = true;
- if (rowMoved) {
- // Sort location of this row has changed.
- // Remove and re-add in the right spot
- SortList(list, parentIsVisible && (parentRow == NULL || parentRow->fIsExpanded));
- } else if (parentIsVisible && (parentRow == NULL || parentRow->fIsExpanded)) {
- BRect invalidRect;
- if (FindVisibleRect(row, &invalidRect))
- Invalidate(invalidRect);
- }
- }
- }
- }
- void
- OutlineView::AddRow(BRow* row, int32 Index, BRow* parentRow)
- {
- if (!row)
- return;
- row->fParent = parentRow;
- if (fMasterView->SortingEnabled() && !fSortColumns->IsEmpty()) {
- // Ignore index here.
- if (parentRow) {
- if (parentRow->fChildList == NULL)
- parentRow->fChildList = new BRowContainer;
- AddSorted(parentRow->fChildList, row);
- } else
- AddSorted(&fRows, row);
- } else {
- // Note, a -1 index implies add to end if sorting is not enabled
- if (parentRow) {
- if (parentRow->fChildList == 0)
- parentRow->fChildList = new BRowContainer;
- if (Index < 0 || Index > parentRow->fChildList->CountItems())
- parentRow->fChildList->AddItem(row);
- else
- parentRow->fChildList->AddItem(row, Index);
- } else {
- if (Index < 0 || Index >= fRows.CountItems())
- fRows.AddItem(row);
- else
- fRows.AddItem(row, Index);
- }
- }
- if (parentRow == 0 || parentRow->fIsExpanded)
- fItemsHeight += row->Height() + 1;
- FixScrollBar(false);
- BRect newRowRect;
- bool newRowIsInOpenBranch = FindRect(row, &newRowRect);
- if (fFocusRow && fFocusRowRect.top > newRowRect.bottom) {
- // The focus row has moved.
- Invalidate(fFocusRowRect);
- FindRect(fFocusRow, &fFocusRowRect);
- Invalidate(fFocusRowRect);
- }
- if (newRowIsInOpenBranch) {
- if (fCurrentState == INACTIVE) {
- if (newRowRect.bottom < fVisibleRect.top) {
- // The new row is totally above the current viewport, move
- // everything down and redraw the first line.
- BRect source(fVisibleRect);
- BRect dest(fVisibleRect);
- source.bottom -= row->Height() + 1;
- dest.top += row->Height() + 1;
- CopyBits(source, dest);
- Invalidate(BRect(fVisibleRect.left, fVisibleRect.top, fVisibleRect.right,
- fVisibleRect.top + newRowRect.Height()));
- } else if (newRowRect.top < fVisibleRect.bottom) {
- // New item is somewhere in the current region. Scroll everything
- // beneath it down and invalidate just the new row rect.
- BRect source(fVisibleRect.left, newRowRect.top, fVisibleRect.right,
- fVisibleRect.bottom - newRowRect.Height());
- BRect dest(source);
- dest.OffsetBy(0, newRowRect.Height() + 1);
- CopyBits(source, dest);
- Invalidate(newRowRect);
- } // otherwise, this is below the currently visible region
- } else {
- // Adding the item may have caused the item that the user is currently
- // selected to move. This would cause annoying drawing and interaction
- // bugs, as the position of that item is cached. If this happens, resize
- // the scroll bar, then scroll back so the selected item is in view.
- BRect targetRect;
- if (FindRect(fTargetRow, &targetRect)) {
- float delta = targetRect.top - fTargetRowTop;
- if (delta != 0) {
- // This causes a jump because ScrollBy will copy a chunk of the view.
- // Since the actual contents of the view have been offset, we don't
- // want this, we just want to change the virtual origin of the window.
- // Constrain the clipping region so everything is clipped out so no
- // copy occurs.
- //
- // xxx this currently doesn't work if the scroll bars aren't enabled.
- // everything will still move anyway. A minor annoyance.
- BRegion emptyRegion;
- ConstrainClippingRegion(&emptyRegion);
- PushState();
- ScrollBy(0, delta);
- PopState();
- ConstrainClippingRegion(NULL);
- fTargetRowTop += delta;
- fClickPoint.y += delta;
- fLatchRect.OffsetBy(0, delta);
- }
- }
- }
- }
- // If the parent was previously childless, it will need to have a latch
- // drawn.
- BRect parentRect;
- if (parentRow && parentRow->fChildList->CountItems() == 1
- && FindVisibleRect(parentRow, &parentRect))
- Invalidate(parentRect);
- }
- void
- OutlineView::FixScrollBar(bool scrollToFit)
- {
- BScrollBar* vScrollBar = ScrollBar(B_VERTICAL);
- if (vScrollBar) {
- if (fItemsHeight > fVisibleRect.Height()) {
- float maxScrollBarValue = fItemsHeight - fVisibleRect.Height();
- vScrollBar->SetProportion(fVisibleRect.Height() / fItemsHeight);
- // If the user is scrolled down too far when making the range smaller, the list
- // will jump suddenly, which is undesirable. In this case, don't fix the scroll
- // bar here. In ScrollTo, it checks to see if this has occured, and will
- // fix the scroll bars sneakily if the user has scrolled up far enough.
- if (scrollToFit || vScrollBar->Value() <= maxScrollBarValue) {
- vScrollBar->SetRange(0.0, maxScrollBarValue);
- vScrollBar->SetSteps(20.0, fVisibleRect.Height());
- }
- } else if (vScrollBar->Value() == 0.0 || fItemsHeight == 0.0)
- vScrollBar->SetRange(0.0, 0.0); // disable scroll bar.
- }
- }
- void
- OutlineView::AddSorted(BRowContainer* list, BRow* row)
- {
- if (list && row) {
- // Find general vicinity with binary search.
- int32 lower = 0;
- int32 upper = list->CountItems()-1;
- while( lower < upper ) {
- int32 middle = lower + (upper-lower+1)/2;
- int32 cmp = CompareRows(row, list->ItemAt(middle));
- if( cmp < 0 ) upper = middle-1;
- else if( cmp > 0 ) lower = middle+1;
- else lower = upper = middle;
- }
- // At this point, 'upper' and 'lower' at the last found item.
- // Arbitrarily use 'upper' and determine the final insertion
- // point -- either before or after this item.
- if( upper < 0 ) upper = 0;
- else if( upper < list->CountItems() ) {
- if( CompareRows(row, list->ItemAt(upper)) > 0 ) upper++;
- }
- if (upper >= list->CountItems())
- list->AddItem(row); // Adding to end.
- else
- list->AddItem(row, upper); // Insert
- }
- }
- int32
- OutlineView::CompareRows(BRow* row1, BRow* row2)
- {
- int32 itemCount (fSortColumns->CountItems());
- if (row1 && row2) {
- for (int32 index = 0; index < itemCount; index++) {
- BColumn* column = (BColumn*) fSortColumns->ItemAt(index);
- int comp = 0;
- BField* field1 = (BField*) row1->GetField(column->fFieldID);
- BField* field2 = (BField*) row2->GetField(column->fFieldID);
- if (field1 && field2)
- comp = column->CompareFields(field1, field2);
- if (!column->fSortAscending)
- comp = -comp;
- if (comp != 0)
- return comp;
- }
- }
- return 0;
- }
- void
- OutlineView::FrameResized(float width, float height)
- {
- fVisibleRect.right = fVisibleRect.left + width;
- fVisibleRect.bottom = fVisibleRect.top + height;
- FixScrollBar(true);
- _inherited::FrameResized(width, height);
- }
- void
- OutlineView::ScrollTo(BPoint position)
- {
- fVisibleRect.OffsetTo(position.x, position.y);
- // In FixScrollBar, we might not have been able to change the size of
- // the scroll bar because the user was scrolled down too far. Take
- // this opportunity to sneak it in if we can.
- BScrollBar* vScrollBar = ScrollBar(B_VERTICAL);
- float maxScrollBarValue = fItemsHeight - fVisibleRect.Height();
- float min, max;
- vScrollBar->GetRange(&min, &max);
- if (max != maxScrollBarValue && position.y > maxScrollBarValue)
- FixScrollBar(true);
- _inherited::ScrollTo(position);
- }
- const BRect&
- OutlineView::VisibleRect() const
- {
- return fVisibleRect;
- }
- bool
- OutlineView::FindVisibleRect(BRow* row, BRect* _rect)
- {
- if (row && _rect) {
- float line = 0.0;
- for (RecursiveOutlineIterator iterator(&fRows); iterator.CurrentRow();
- iterator.GoToNext()) {
- if (line > fVisibleRect.bottom)
- break;
- if (iterator.CurrentRow() == row) {
- _rect->Set(fVisibleRect.left, line, fVisibleRect.right,
- line + row->Height());
- return true;
- }
- line += iterator.CurrentRow()->Height() + 1;
- }
- }
- return false;
- }
- bool
- OutlineView::FindRect(const BRow* row, BRect* _rect)
- {
- float line = 0.0;
- for (RecursiveOutlineIterator iterator(&fRows); iterator.CurrentRow();
- iterator.GoToNext()) {
- if (iterator.CurrentRow() == row) {
- _rect->Set(fVisibleRect.left, line, fVisibleRect.right,
- line + row->Height());
- return true;
- }
- line += iterator.CurrentRow()->Height() + 1;
- }
- return false;
- }
- void
- OutlineView::ScrollTo(const BRow* row)
- {
- BRect rect;
- if (FindRect(row, &rect)) {
- BRect bounds = Bounds();
- if (rect.top < bounds.top)
- ScrollTo(BPoint(bounds.left, rect.top));
- else if (rect.bottom > bounds.bottom)
- ScrollBy(0, rect.bottom - bounds.bottom);
- }
- }
- void
- OutlineView::DeselectAll()
- {
- // Invalidate all selected rows
- float line = 0.0;
- for (RecursiveOutlineIterator iterator(&fRows); iterator.CurrentRow();
- iterator.GoToNext()) {
- if (line > fVisibleRect.bottom)
- break;
- BRow* row = iterator.CurrentRow();
- if (line + row->Height() > fVisibleRect.top) {
- if (row->fNextSelected != 0)
- Invalidate(BRect(fVisibleRect.left, line, fVisibleRect.right,
- line + row->Height()));
- }
- line += row->Height() + 1;
- }
- // Set items not selected
- while (fSelectionListDummyHead.fNextSelected != &fSelectionListDummyHead) {
- BRow* row = fSelectionListDummyHead.fNextSelected;
- row->fNextSelected->fPrevSelected = row->fPrevSelected;
- row->fPrevSelected->fNextSelected = row->fNextSelected;
- row->fNextSelected = 0;
- row->fPrevSelected = 0;
- }
- }
- BRow*
- OutlineView::FocusRow() const
- {
- return fFocusRow;
- }
- void
- OutlineView::SetFocusRow(BRow* row, bool Select)
- {
- if (row) {
- if (Select)
- AddToSelection(row);
- if (fFocusRow == row)
- return;
- Invalidate(fFocusRowRect); // invalidate previous
- fTargetRow = fFocusRow = row;
- FindVisibleRect(fFocusRow, &fFocusRowRect);
- Invalidate(fFocusRowRect); // invalidate current
- fFocusRowRect.right = 10000;
- fMasterView->SelectionChanged();
- }
- }
- bool
- OutlineView::SortList(BRowContainer* list, bool isVisible)
- {
- if (list) {
- // Shellsort
- BRow** items
- = (BRow**) BObjectList<BRow>::Private(list).AsBList()->Items();
- int32 numItems = list->CountItems();
- int h;
- for (h = 1; h < numItems / 9; h = 3 * h + 1)
- ;
- for (;h > 0; h /= 3) {
- for (int step = h; step < numItems; step++) {
- BRow* temp = items[step];
- int i;
- for (i = step - h; i >= 0; i -= h) {
- if (CompareRows(temp, items[i]) < 0)
- items[i + h] = items[i];
- else
- break;
- }
- items[i + h] = temp;
- }
- }
- if (isVisible) {
- Invalidate();
- InvalidateCachedPositions();
- int lockCount = Window()->CountLocks();
- for (int i = 0; i < lockCount; i++)
- Window()->Unlock();
- while (lockCount--)
- if (!Window()->Lock())
- return false; // Window is gone...
- }
- }
- return true;
- }
- int32
- OutlineView::DeepSortThreadEntry(void* _outlineView)
- {
- ((OutlineView*) _outlineView)->DeepSort();
- return 0;
- }
- void
- OutlineView::DeepSort()
- {
- struct stack_entry {
- bool isVisible;
- BRowContainer* list;
- int32 listIndex;
- } stack[kMaxDepth];
- int32 stackTop = 0;
- stack[stackTop].list = &fRows;
- stack[stackTop].isVisible = true;
- stack[stackTop].listIndex = 0;
- fNumSorted = 0;
- if (Window()->Lock() == false)
- return;
- bool doneSorting = false;
- while (!doneSorting && !fSortCancelled) {
- stack_entry* currentEntry = &stack[stackTop];
- // xxx Can make the invalidate area smaller by finding the rect for the
- // parent item and using that as the top of the invalid rect.
- bool haveLock = SortList(currentEntry->list, currentEntry->isVisible);
- if (!haveLock)
- return ; // window is gone.
- // Fix focus rect.
- InvalidateCachedPositions();
- if (fCurrentState != INACTIVE)
- fCurrentState = INACTIVE; // sorry...
- // next list.
- bool foundNextList = false;
- while (!foundNextList && !fSortCancelled) {
- for (int32 index = currentEntry->listIndex; index < currentEntry->list->CountItems();
- index++) {
- BRow* parentRow = currentEntry->list->ItemAt(index);
- BRowContainer* childList = parentRow->fChildList;
- if (childList != 0) {
- currentEntry->listIndex = index + 1;
- stackTop++;
- ASSERT(stackTop < kMaxDepth);
- stack[stackTop].listIndex = 0;
- stack[stackTop].list = childList;
- stack[stackTop].isVisible = (currentEntry->isVisible && parentRow->fIsExpanded);
- foundNextList = true;
- break;
- }
- }
- if (!foundNextList) {
- // back up
- if (--stackTop < 0) {
- doneSorting = true;
- break;
- }
- currentEntry = &stack[stackTop];
- }
- }
- }
- Window()->Unlock();
- }
- void
- OutlineView::StartSorting()
- {
- // If this view is not yet attached to a window, don't start a sort thread!
- if (Window() == NULL)
- return;
- if (fSortThread != B_BAD_THREAD_ID) {
- thread_info tinfo;
- if (get_thread_info(fSortThread, &tinfo) == B_OK) {
- // Unlock window so this won't deadlock (sort thread is probably
- // waiting to lock window).
- int lockCount = Window()->CountLocks();
- for (int i = 0; i < lockCount; i++)
- Window()->Unlock();
- fSortCancelled = true;
- int32 status;
- wait_for_thread(fSortThread, &status);
- while (lockCount--)
- if (!Window()->Lock())
- return ; // Window is gone...
- }
- }
- fSortCancelled = false;
- fSortThread = spawn_thread(DeepSortThreadEntry, "sort_thread", B_NORMAL_PRIORITY, this);
- resume_thread(fSortThread);
- }
- void
- OutlineView::SelectRange(BRow* start, BRow* end)
- {
- if (!start || !end)
- return;
- if (start == end) // start is always selected when this is called
- return;
- RecursiveOutlineIterator iterator(&fRows, false);
- while (iterator.CurrentRow() != 0) {
- if (iterator.CurrentRow() == end) {
- // reverse selection, swap to fix special case
- BRow* temp = start;
- start = end;
- end = temp;
- break;
- } else if (iterator.CurrentRow() == start)
- break;
- iterator.GoToNext();
- }
- while (true) {
- BRow* row = iterator.CurrentRow();
- if (row) {
- if (row->fNextSelected == 0) {
- row->fNextSelected = fSelectionListDummyHead.fNextSelected;
- row->fPrevSelected = &fSelectionListDummyHead;
- row->fNextSelected->fPrevSelected = row;
- row->fPrevSelected->fNextSelected = row;
- }
- } else
- break;
- if (row == end)
- break;
- iterator.GoToNext();
- }
- Invalidate(); // xxx make invalidation smaller
- }
- bool
- OutlineView::FindParent(BRow* row, BRow** outParent, bool* outParentIsVisible)
- {
- bool result = false;
- if (row != NULL && outParent != NULL) {
- *outParent = row->fParent;
- if (outParentIsVisible != NULL) {
- // Walk up the parent chain to determine if this row is visible
- *outParentIsVisible = true;
- for (BRow* currentRow = row->fParent; currentRow != NULL;
- currentRow = currentRow->fParent) {
- if (!currentRow->fIsExpanded) {
- *outParentIsVisible = false;
- break;
- }
- }
- }
- result = *outParent != NULL;
- }
- return result;
- }
- int32
- OutlineView::IndexOf(BRow* row)
- {
- if (row) {
- if (row->fParent == 0)
- return fRows.IndexOf(row);
- ASSERT(row->fParent->fChildList);
- return row->fParent->fChildList->IndexOf(row);
- }
- return B_ERROR;
- }
- void
- OutlineView::InvalidateCachedPositions()
- {
- if (fFocusRow)
- FindRect(fFocusRow, &fFocusRowRect);
- }
- float
- OutlineView::GetColumnPreferredWidth(BColumn* column)
- {
- float preferred = 0.0;
- for (RecursiveOutlineIterator iterator(&fRows); BRow* row =
- iterator.CurrentRow(); iterator.GoToNext()) {
- BField* field = row->GetField(column->fFieldID);
- if (field) {
- float width = column->GetPreferredWidth(field, this)
- + iterator.CurrentLevel() * kOutlineLevelIndent;
- preferred = max_c(preferred, width);
- }
- }
- BString name;
- column->GetColumnName(&name);
- preferred = max_c(preferred, StringWidth(name));
- // Constrain to preferred width. This makes the method do a little
- // more than asked, but it's for convenience.
- if (preferred < column->MinWidth())
- preferred = column->MinWidth();
- else if (preferred > column->MaxWidth())
- preferred = column->MaxWidth();
- return preferred;
- }
- // #pragma mark -
- RecursiveOutlineIterator::RecursiveOutlineIterator(BRowContainer* list,
- bool openBranchesOnly)
- :
- fStackIndex(0),
- fCurrentListIndex(0),
- fCurrentListDepth(0),
- fOpenBranchesOnly(openBranchesOnly)
- {
- if (list == 0 || list->CountItems() == 0)
- fCurrentList = 0;
- else
- fCurrentList = list;
- }
- BRow*
- RecursiveOutlineIterator::CurrentRow() const
- {
- if (fCurrentList == 0)
- return 0;
- return fCurrentList->ItemAt(fCurrentListIndex);
- }
- void
- RecursiveOutlineIterator::GoToNext()
- {
- if (fCurrentList == 0)
- return;
- if (fCurrentListIndex < 0 || fCurrentListIndex >= fCurrentList->CountItems()) {
- fCurrentList = 0;
- return;
- }
- BRow* currentRow = fCurrentList->ItemAt(fCurrentListIndex);
- if(currentRow) {
- if (currentRow->fChildList && (currentRow->fIsExpanded || !fOpenBranchesOnly)
- && currentRow->fChildList->CountItems() > 0) {
- // Visit child.
- // Put current list on the stack if it needs to be revisited.
- if (fCurrentListIndex < fCurrentList->CountItems() - 1) {
- fStack[fStackIndex].fRowSet = fCurrentList;
- fStack[fStackIndex].fIndex = fCurrentListIndex + 1;
- fStack[fStackIndex].fDepth = fCurrentListDepth;
- fStackIndex++;
- }
- fCurrentList = currentRow->fChildList;
- fCurrentListIndex = 0;
- fCurrentListDepth++;
- } else if (fCurrentListIndex < fCurrentList->CountItems() - 1)
- fCurrentListIndex++; // next item in current list
- else if (--fStackIndex >= 0) {
- fCurrentList = fStack[fStackIndex].fRowSet;
- fCurrentListIndex = fStack[fStackIndex].fIndex;
- fCurrentListDepth = fStack[fStackIndex].fDepth;
- } else
- fCurrentList = 0;
- }
- }
- int32
- RecursiveOutlineIterator::CurrentLevel() const
- {
- return fCurrentListDepth;
- }
|