gtkgadget.bmx 142 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406
  1. ' Copyright (c) 2006-2020 Bruce A Henderson
  2. '
  3. ' Permission is hereby granted, free of charge, to any person obtaining a copy
  4. ' of this software and associated documentation files (the "Software"), to deal
  5. ' in the Software without restriction, including without limitation the rights
  6. ' to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. ' copies of the Software, and to permit persons to whom the Software is
  8. ' furnished to do so, subject to the following conditions:
  9. '
  10. ' The above copyright notice and this permission notice shall be included in
  11. ' all copies or substantial portions of the Software.
  12. '
  13. ' THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. ' IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. ' FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. ' AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. ' LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. ' OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. ' THE SOFTWARE.
  20. '
  21. SuperStrict
  22. Import "gtkcommon.bmx"
  23. Type TGTKGadget Extends TGadget
  24. Field iclass:Int
  25. ' usually the pointer to the gtk widget
  26. Field handle:Byte Ptr
  27. Field menubar:Byte Ptr
  28. Field menu:Byte Ptr
  29. ' reference to this gadgets' font (if we've ever set it programmatically)
  30. Field _font:TGuiFont
  31. ' a map to hold connection handler ids... sometimes we need to disconnect the little buggers.
  32. Field connectionMap:TMap = New TMap
  33. ' a unique identifier for this gadget
  34. Field accelMapId:String
  35. Field accelString:String
  36. Field hasAccel:Int
  37. Field initialSizing:Int = False
  38. Field mySetVisible:Int = True
  39. Field visible:Int = False
  40. ' the class id of this gadget in MaxGUI terms.
  41. Field maxguiClass:Int
  42. Method Init(GadgetClass:Int, _x:Int, _y:Int, _w:Int, _h:Int, _style:Int)
  43. SetRect(_x,_y,_w,_h)
  44. iclass = GadgetClass
  45. kids = New TList
  46. style = _style
  47. End Method
  48. Method addConnection(name:String, id:Int)
  49. connectionMap.Insert(name, TGTKInteger.Set(id))
  50. End Method
  51. Function Destroy(data:Byte Ptr, closure:Byte Ptr)
  52. 'Print "Destroy Handler"
  53. End Function
  54. Function Create:TGTKGadget(GadgetClass:Int, x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int, mgclass:Int)
  55. Local gadget:TGTKGadget
  56. Select GadgetClass
  57. Case GTK_WINDOW
  58. gadget = TGTKWindow.CreateWindow(x, y ,w , h, label, group, style)
  59. Case GTK_BUTTON
  60. gadget = TGTKButtonPush.CreateButton(x, y ,w , h, label, group, style)
  61. Case GTK_RADIOBUTTON
  62. gadget = TGTKButtonRadio.CreateButton(x, y ,w , h, label, group, style)
  63. Case GTK_CHECKBUTTON
  64. gadget = TGTKButtonCheckbox.CreateButton(x, y ,w , h, label, group, style)
  65. Case GTK_LABEL
  66. gadget = TGTKLabel.CreateLabel(x, y ,w , h, label, group, style)
  67. Case GTK_MENUITEM
  68. gadget = TGTKMenuItem.CreateMenuItem(label, style, group)
  69. Case GTK_TEXTFIELD
  70. gadget = TGTKTextField.CreateTextField(x, y ,w , h, label, group, style)
  71. Case GTK_HTMLVIEW
  72. If gtk3maxgui_htmlview Then
  73. gadget = gtk3maxgui_htmlview.CreateHTMLView(x, y ,w , h, label, group, style)
  74. Else
  75. Throw "No HTMLView specified. You need To Import one! " + ..
  76. " Import Gtk.gtk3webkitgtk"
  77. End If
  78. Case GTK_TABBER
  79. gadget = TGTKTabber.CreateTabber(x, y ,w , h, label, group, style)
  80. Case GTK_PANEL
  81. gadget = TGTKPanel.CreatePanel(x, y ,w , h, label, group, style)
  82. Case GTK_COMBOBOX
  83. gadget = TGTKComboBox.CreateComboBox(x, y ,w , h, label, group, style)
  84. Case GTK_PROGRESSBAR
  85. gadget = TGTKProgressBar.CreateProgressBar(x, y ,w , h, label, group, style)
  86. Case GTK_STEPPER
  87. gadget = TGTKStepper.CreateStepper(x, y ,w , h, label, group, style)
  88. Case GTK_SCROLLBAR
  89. gadget = TGTKScrollBar.CreateScrollBar(x, y ,w , h, label, group, style)
  90. Case GTK_TRACKBAR
  91. gadget = TGTKTrackBar.CreateTrackBar(x, y ,w , h, label, group, style)
  92. Case GTK_TEXTAREA
  93. ' no custom text area? use the default
  94. If Not gtk3maxgui_textarea Then
  95. gtk3maxgui_textarea = New TGTKDefaultTextAreaDriver
  96. End If
  97. gadget = gtk3maxgui_textarea.CreateTextArea(x, y ,w , h, label, group, style)
  98. Case GTK_TOOLBAR
  99. gadget = TGTKToolbar.CreateToolBar(x, y ,w , h, label, group, style)
  100. Case GTK_LISTBOX
  101. gadget = TGTKListbox.CreateListBox(x, y ,w , h, label, group, style)
  102. Case GTK_TREEVIEW
  103. gadget = TGTKTreeView.CreateTreeView(x, y ,w , h, label, group, style)
  104. Case GTK_CANVAS
  105. gadget = TGTKCanvas.CreateCanvas(x, y ,w , h, label, group, style)
  106. End Select
  107. ' map the new gadget - so we can find it later if required
  108. If gadget Then
  109. GadgetMap.Insert(gadget.handle, gadget)
  110. End If
  111. If group Then
  112. gadget._SetParent group
  113. End If
  114. gadget.SetShape x,y,w,h
  115. ' set the maxgui class type
  116. gadget.maxguiClass = mgclass
  117. Return gadget
  118. End Function
  119. Method Free:Int()
  120. Local gadget:TGTKGadget
  121. Local rkids:TList
  122. rkids=kids.Reversed()
  123. For gadget = EachIn rkids
  124. gadget.Free()
  125. Next
  126. gadget = TGTKGadget(parent)
  127. If gadget Then
  128. gadget.kids.remove Self
  129. End If
  130. ' remove reference from global reference map
  131. If handle Then
  132. GadgetMap.Remove(handle)
  133. handle = Null
  134. End If
  135. connectionMap.Clear()
  136. End Method
  137. Rem
  138. bbdoc: Show or hide the gadget.
  139. End Rem
  140. Method SetShow:Int(truefalse:Int)
  141. visible = truefalse
  142. mySetVisible = visible
  143. If truefalse Then
  144. gtk_widget_show(handle)
  145. Else
  146. gtk_widget_hide(handle)
  147. EndIf
  148. UpdateChildVisibility()
  149. End Method
  150. Method UpdateChildVisibility()
  151. For Local gadget:TGTKGadget = EachIn kids
  152. If Not visible Then
  153. gadget.visible = False
  154. Else
  155. gadget.visible = gadget.mySetVisible
  156. End If
  157. gadget.UpdateChildVisibility()
  158. Next
  159. End Method
  160. ' checks text for mnemonics
  161. Method processText:String(txt:String)
  162. ' convert underscores to doubles
  163. txt = txt.Replace("_", "__")
  164. txt = txt.Replace("&&", "$^^$")
  165. txt = txt.Replace("&", "_")
  166. txt = txt.Replace("$^^$", "&")
  167. Return txt
  168. End Method
  169. Method setAccelEntry(keycode:Int, modifier:Int)
  170. Local accelKey:Int
  171. Local modKey:Int
  172. If accelString And hasAccel Then
  173. Local accelPtr:Byte Ptr = accelString.ToUTF8String()
  174. gtk_accelerator_parse(accelPtr, Varptr accelKey, Varptr modKey)
  175. MemFree(accelPtr)
  176. If accelKey <> 0 Then
  177. gtk_widget_remove_accelerator(handle, getWindow().accelGroup, accelKey, modKey)
  178. hasAccel = False
  179. End If
  180. End If
  181. ' enabling accelerator?
  182. If keycode Then
  183. accelString = TGTKKeyMap.accelToString(keycode, modifier)
  184. Local accelPtr:Byte Ptr = accelString.ToUTF8String()
  185. gtk_accelerator_parse(accelPtr, Varptr accelKey, Varptr modKey)
  186. MemFree(accelPtr)
  187. gtk_widget_add_accelerator(handle, "activate", getWindow().accelGroup, accelKey, modKey, GTK_ACCEL_VISIBLE)
  188. hasAccel = True
  189. End If
  190. End Method
  191. Method setAccelMapId(id:String)
  192. accelMapId = id.Replace("&", "")
  193. End Method
  194. ' returns the widgets window
  195. Method getWindow:TGTKWindow()
  196. If Not TGTKWindow(Self) Then
  197. If TGTKGadget(parent) Then
  198. Return TGTKGadget(parent).getWindow()
  199. Else
  200. Return Null
  201. End If
  202. End If
  203. Return TGTKWindow(Self)
  204. End Method
  205. Rem
  206. bbdoc: Callback for focus lost.
  207. End Rem
  208. Function OnFocusLost:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  209. PostGuiEvent(EVENT_GADGETLOSTFOCUS, TGadget(obj))
  210. End Function
  211. Rem
  212. bbdoc: Set the gadget tooltip.
  213. End Rem
  214. Method setToolTip:Int(tip:String)
  215. If tip And tip.length > 0 Then
  216. Local tipPtr:Byte Ptr = tip.ToUTF8String()
  217. gtk_widget_set_tooltip_text(handle, tipPtr)
  218. MemFree(tipPtr)
  219. Else
  220. gtk_widget_set_has_tooltip(handle, False)
  221. End If
  222. End Method
  223. Rem
  224. bbdoc: Perform an activation command on the gadget.
  225. End Rem
  226. Method Activate:Int(cmd:Int)
  227. Select cmd
  228. Case ACTIVATE_FOCUS
  229. gtk_widget_grab_focus(handle)
  230. Case ACTIVATE_FORWARD
  231. Case ACTIVATE_BACK
  232. Case ACTIVATE_REDRAW
  233. redraw()
  234. PostGuiEvent(EVENT_GADGETPAINT, Self)
  235. End Select
  236. End Method
  237. Method redraw()
  238. gtk_widget_queue_draw(handle)
  239. End Method
  240. Rem
  241. bbdoc: Return the gadget's client width.
  242. End Rem
  243. Method ClientWidth:Int()
  244. If initialSizing Then
  245. ?bmxng
  246. Local minReq:GtkRequisition
  247. Local natReq:GtkRequisition
  248. ?Not bmxng
  249. Local minReq:GtkRequisition = New GtkRequisition
  250. Local natReq:GtkRequisition = New GtkRequisition
  251. ?
  252. gtk_widget_get_preferred_size(handle, minReq, natReq)
  253. Return natReq.width
  254. End If
  255. Return width
  256. End Method
  257. Rem
  258. bbdoc: Return the gadget's client height.
  259. End Rem
  260. Method ClientHeight:Int()
  261. If initialSizing Then
  262. ?bmxng
  263. Local minReq:GtkRequisition
  264. Local natReq:GtkRequisition
  265. ?Not bmxng
  266. Local minReq:GtkRequisition = New GtkRequisition
  267. Local natReq:GtkRequisition = New GtkRequisition
  268. ?
  269. gtk_widget_get_preferred_size(handle, minReq, natReq)
  270. Return natReq.height
  271. End If
  272. Return height
  273. End Method
  274. Method Rethink:Int()
  275. If handle
  276. gtk_layout_move(TGTKContainer(parent).container, handle, Max(xpos,0), Max(ypos,0))
  277. gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
  278. End If
  279. End Method
  280. Rem
  281. bbdoc: Return the gadget state.
  282. End Rem
  283. Method State:Int()
  284. Local flags:Int
  285. Local _state:Int = gtk_widget_get_state_flags(handle)
  286. Select _state
  287. Case GTK_STATE_FLAG_INSENSITIVE
  288. flags:| STATE_DISABLED
  289. Case GTK_STATE_FLAG_SELECTED
  290. flags:| STATE_SELECTED
  291. Case GTK_STATE_FLAG_ACTIVE
  292. flags:| STATE_ACTIVE
  293. End Select
  294. If Not gtk_widget_get_visible(handle) Then
  295. flags:| STATE_HIDDEN
  296. End If
  297. Return flags
  298. End Method
  299. End Type
  300. Rem
  301. bbdoc: The Desktop.
  302. End Rem
  303. Type TGTKDesktop Extends TGTKGadget
  304. Function CreateDesktop:TGTKDesktop()
  305. Local this:TGTKDesktop = New TGTKDesktop
  306. this.initDesktop()
  307. Return this
  308. End Function
  309. Method initDesktop()
  310. iclass = GTK_DESKTOP
  311. handle = gdk_screen_get_default()
  312. SetArea(0, 0, gdk_screen_get_width(handle), gdk_screen_get_height(handle))
  313. End Method
  314. Method Rethink:Int()
  315. End Method
  316. Rem
  317. bbdoc: Returns the desktop width.
  318. End Rem
  319. Method ClientWidth:Int()
  320. Return width
  321. End Method
  322. Rem
  323. bbdoc: Returns the desktop height.
  324. End Rem
  325. Method ClientHeight:Int()
  326. Return height
  327. End Method
  328. Rem
  329. bbdoc: Returns the desktop depth.
  330. End Rem
  331. Method GetDepth:Int()
  332. Local visual:Byte Ptr = gdk_screen_get_system_visual(handle)
  333. Return gdk_visual_get_depth(visual)
  334. End Method
  335. Rem
  336. bbdoc: Returns the desktop hertz.
  337. End Rem
  338. Method GetHertz:Int()
  339. Return bmx_gtk3_gtkdesktop_gethertz()
  340. End Method
  341. Rem
  342. bbdoc: Returns the desktop scale factor that maps from window coordiantes to the actual device pixels.
  343. about: On traditional systems this is 1, but on very high density outputs this can be a higher value (often 2).
  344. End Rem
  345. Method ScaleFactor:Int()
  346. Return gdk_screen_get_monitor_scale_factor(handle, 0)
  347. End Method
  348. End Type
  349. Rem
  350. bbdoc: This type handles "internal" widget containers for "Container" gadgets.
  351. End Rem
  352. Type TGTKContainer Extends TGTKGadget
  353. ' a multi-row container
  354. Field box:Byte Ptr
  355. ' the "Fixed" container that we place gadgets onto
  356. Field container:Byte Ptr
  357. ' dont need to free this, as removing radio buttons from it will free itself when empty
  358. Field radioGroup:Byte Ptr
  359. ' initialize the container stuff
  360. Method Init(GadgetClass:Int, x:Int, y:Int, w:Int, h:Int, style:Int)
  361. Super.init(GadgetClass, x, y, w, h, style)
  362. End Method
  363. Method ClientWidth:Int()
  364. Return width
  365. End Method
  366. Method ClientHeight:Int()
  367. Return height
  368. End Method
  369. End Type
  370. Rem
  371. bbdoc: A Window
  372. End Rem
  373. Type TGTKWindow Extends TGTKContainer
  374. Field statusbar:Byte Ptr
  375. Field sblabels:Byte Ptr[]
  376. Field toolbar:TGTKToolbar
  377. Field accelGroup:Byte Ptr
  378. Field oldCW:Int
  379. Field oldCH:Int
  380. Field _maximized:Int
  381. Field _minimized:Int
  382. Field ignoreMoveEvent:Int
  383. Field ignoreSizeEvent:Int
  384. Function CreateWindow:TGTKWindow(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  385. Local this:TGTKWindow = New TGTKWindow
  386. this.initWindow(x, y, w, h, label, group, style)
  387. gtkWindows.addLast(this)
  388. Return this
  389. End Function
  390. Method initWindow(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  391. If group And TGTKDesktop(group)
  392. group = Null
  393. End If
  394. ' should only be a window parent!!
  395. If group Then
  396. Assert TGTKWindow(group), "group not TGTKWindow!"
  397. End If
  398. handle = gtk_window_new(GTK_WINDOW_TOPLEVEL)
  399. Init(GTK_WINDOW, x, y, w, h, style)
  400. ' container BEGIN
  401. box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)
  402. gtk_widget_show(box)
  403. If style & WINDOW_MENU Then
  404. menubar = gtk_menu_bar_new()
  405. gtk_box_pack_start(box, menubar, False, True, 0)
  406. gtk_widget_show(menubar)
  407. End If
  408. container = gtk_layout_new(Null, Null)
  409. gtk_widget_show(container)
  410. gtk_box_pack_start(box, container, True, True, 0)
  411. ' container END
  412. If style & WINDOW_STATUS Then
  413. createStatusbar()
  414. SetStatusText("")
  415. EndIf
  416. If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
  417. LocalizeGadget(Self, label)
  418. Else
  419. SetText(label)
  420. EndIf
  421. gtk_window_move(handle, x, y)
  422. gtk_window_set_default_size(handle, w, calcHeight(h))
  423. gtk_window_set_decorated(handle, (style & WINDOW_TITLEBAR))
  424. gtk_window_set_resizable(handle, (style & WINDOW_RESIZABLE))
  425. If style & WINDOW_TOOL Then
  426. gtk_window_set_type_hint(handle, GDK_WINDOW_TYPE_HINT_UTILITY)
  427. End If
  428. gtk_container_add(handle, box)
  429. ' some funky window setting up...
  430. ' It's all rather fiddly, but it appears to work.
  431. ?bmxng
  432. Local geom:GdkGeometry
  433. ?Not bmxng
  434. Local geom:GdkGeometry = New GdkGeometry
  435. ?
  436. 'DebugStop
  437. Local hints:Int = 0
  438. If style & WINDOW_RESIZABLE Then
  439. hints:| GDK_HINT_USER_SIZE
  440. geom.minWidth = 16
  441. geom.minHeight = 16
  442. hints:| GDK_HINT_RESIZE_INC
  443. geom.widthInc = 1
  444. geom.heightInc = 1
  445. Else
  446. geom.minWidth = w
  447. geom.minHeight = calcHeight(h)
  448. End If
  449. geom.maxWidth = -1
  450. geom.maxHeight = -1
  451. If Not (style & WINDOW_CLIENTCOORDS) Then
  452. geom.baseWidth = w
  453. geom.baseHeight = calcHeight(h)
  454. Else
  455. geom.baseWidth = -1
  456. geom.baseHeight = -1
  457. End If
  458. gtk_window_set_geometry_hints(handle, box, geom, GDK_HINT_POS | GDK_HINT_MIN_SIZE | ..
  459. GDK_HINT_BASE_SIZE | GDK_HINT_USER_POS | hints)
  460. If Not(style & WINDOW_RESIZABLE) Then
  461. gtk_widget_set_size_request(handle, w, calcHeight(h))
  462. End If
  463. ' connect this window with its parent
  464. If group And (style & WINDOW_CHILD) Then
  465. gtk_window_set_transient_for(handle, TGTKWindow(group).handle)
  466. End If
  467. Rem
  468. A Window produces the following events:
  469. EVENT_WINDOWMOVE Window has been moved
  470. EVENT_WINDOWSIZE Window has been resized
  471. EVENT_WINDOWCLOSE Window close icon clicked
  472. EVENT_WINDOWACTIVATE Window activated
  473. EVENT_WINDOWACCEPT Drag and Drop operation was attempted
  474. End Rem
  475. ' move
  476. addConnection("configure-event", g_signal_cb3(handle, "configure-event", OnWindowMoveSize, Self, Destroy, 0))
  477. ' size
  478. addConnection("check-resize", g_signal_cb2(handle, "check-resize", OnWindowSize, Self, Destroy, 0))
  479. ' close
  480. addConnection("delete-event", g_signal_cb3_ret(handle, "delete-event", OnWindowClose, Self, Destroy, 0))
  481. ' activate
  482. addConnection("focus-in-event", g_signal_cb3(handle, "focus-in-event", OnWindowActivate, Self, Destroy, 0))
  483. addConnection("focus-out-event", g_signal_cb3_ret(handle, "focus-out-event", OnWindowDeactivate, Self, Destroy, 0))
  484. ' accept
  485. 'g_signal_cb3(handle, "XXXXXX", WindowAccept, Self, Destroy, 0)
  486. ' minimize / maximize
  487. addConnection("window-state-event", g_signal_cb3_ret(handle, "window-state-event", OnWindowStateChange, Self, Destroy, 0))
  488. If style & WINDOW_ACCEPTFILES Then
  489. 'Local entries:Byte Ptr
  490. gtk_drag_dest_set(handle, GTK_DEST_DEFAULT_ALL, Null, 0, GDK_ACTION_COPY)
  491. gtk_drag_dest_add_uri_targets(handle)
  492. addConnection("drag-drop", g_signal_cb8(handle, "drag-data-received", OnDragDrop, Self, Destroy, 0))
  493. End If
  494. ' used for tabbers - ensure they are redrawn properly when required
  495. 'g_signal_cb7(container, "draw-background", OnDraw, Self, Destroy, 0)
  496. accelGroup = gtk_accel_group_new()
  497. gtk_window_add_accel_group(handle, accelGroup)
  498. setAccelMapId(label)
  499. If ~style & WINDOW_HIDDEN
  500. Setshow(True)
  501. Else
  502. SetShow(False)
  503. End If
  504. End Method
  505. Method calcHeight:Int(requestedHeight:Int)
  506. If Not (style & WINDOW_CLIENTCOORDS) Then
  507. Return requestedHeight
  508. Else
  509. ?bmxng
  510. Local minReq:GtkRequisition
  511. Local natReq:GtkRequisition
  512. ?Not bmxng
  513. Local minReq:GtkRequisition = New GtkRequisition
  514. Local natReq:GtkRequisition = New GtkRequisition
  515. ?
  516. If statusbar Then
  517. gtk_widget_get_preferred_size(statusbar, minReq, natReq)
  518. requestedHeight:+ natReq.height
  519. End If
  520. If menubar Then
  521. gtk_widget_get_preferred_size(menubar, minReq, natReq)
  522. requestedHeight:+ natReq.height
  523. End If
  524. Return requestedHeight
  525. End If
  526. End Method
  527. Method deCalcHeight:Int(actualHeight:Int)
  528. If Not (style & WINDOW_CLIENTCOORDS) Then
  529. Return actualHeight
  530. Else
  531. ?bmxng
  532. Local minReq:GtkRequisition
  533. Local natReq:GtkRequisition
  534. ?Not bmxng
  535. Local minReq:GtkRequisition = New GtkRequisition
  536. Local natReq:GtkRequisition = New GtkRequisition
  537. ?
  538. If statusbar Then
  539. gtk_widget_get_preferred_size(statusbar, minReq, natReq)
  540. actualHeight:- natReq.height
  541. End If
  542. If menubar Then
  543. gtk_widget_get_preferred_size(statusbar, minReq, natReq)
  544. actualHeight:- natReq.height
  545. End If
  546. Return actualHeight
  547. End If
  548. End Method
  549. Rem
  550. bbdoc: Callback for window size / move
  551. End Rem
  552. Function OnWindowMoveSize(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  553. Local x:Int, y:Int, w:Int, h:Int
  554. bmx_gtk3maxgui_gdkeventconfigure(event, Varptr x, Varptr y, Varptr w, Varptr h)
  555. Local win:TGTKWindow = TGTKWindow(obj)
  556. If win Then
  557. Local change:Int = False
  558. h = win.deCalcHeight(h)
  559. ' Has the window actually changed size/position?
  560. If win.width <> w Or win.height <> h Then
  561. change = True
  562. If Not win.ignoreSizeEvent Then
  563. PostGuiEvent(EVENT_WINDOWSIZE, TGadget(obj),,,w,h)
  564. End If
  565. End If
  566. gtk_window_get_position(win.handle, Varptr x, Varptr y)
  567. If win.xpos <> x Or win.ypos <> y Then
  568. change = True
  569. If Not win.ignoreMoveEvent Then
  570. PostGuiEvent(EVENT_WINDOWMOVE, TGadget(obj),,,x,y)
  571. End If
  572. End If
  573. If win.ClientHeight() <> win.oldCH Or win.ClientWidth() <> win.oldCW Then
  574. win.oldCH = win.ClientHeight()
  575. win.oldCW = win.ClientWidth()
  576. change = True
  577. End If
  578. ' something has changed.. we need to update ourself and tell the children.
  579. If change Then
  580. win.setRect(x, y, w, h)
  581. win.layoutkids()
  582. End If
  583. win.ignoreMoveEvent = False
  584. win.ignoreSizeEvent = False
  585. End If
  586. End Function
  587. Method Rethink:Int()
  588. If style & WINDOW_RESIZABLE Then
  589. gtk_window_resize(handle, width, calcHeight(height))
  590. Else
  591. gtk_window_set_default_size(handle, width, calcHeight(height))
  592. End If
  593. layoutkids() ' we need to do this so the children know we've really changed.
  594. End Method
  595. Rem
  596. bbdoc: Callback for window size.
  597. about: This event doesn't actually trigger a max size event, but we use it to adjust the client
  598. size.
  599. End Rem
  600. Function OnWindowSize(widget:Byte Ptr, obj:Object)
  601. Local win:TGTKWindow = TGTKWindow(obj)
  602. If win Then
  603. If win.ClientHeight() <> win.oldCH Or win.ClientWidth() <> win.oldCW Then
  604. win.oldCH = win.ClientHeight()
  605. win.oldCW = win.ClientWidth()
  606. TGTKContainer(obj).rethink()
  607. End If
  608. End If
  609. End Function
  610. Rem
  611. bbdoc: Callback for window state change.
  612. End Rem
  613. Function OnWindowStateChange:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  614. Local statemask:Int
  615. bmx_gtk3maxgui_gdkeventwindowstate(event, Varptr statemask)
  616. Local win:TGTKWindow = TGTKWindow(obj)
  617. If win Then
  618. If statemask & GDK_WINDOW_STATE_ICONIFIED Then
  619. win._minimized = Not win._minimized
  620. End If
  621. If statemask & GDK_WINDOW_STATE_MAXIMIZED Then
  622. win._maximized = Not win._maximized
  623. ' when maximized, we can't be minimized... so clear it
  624. If win._maximized Then
  625. win._minimized = False
  626. End If
  627. End If
  628. End If
  629. End Function
  630. Rem
  631. bbdoc: Callback for window close
  632. End Rem
  633. Function OnWindowClose:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  634. PostGuiEvent(EVENT_WINDOWCLOSE, TGadget(obj))
  635. Return True ' we don't want it to close - that's a user decision :-p
  636. End Function
  637. Rem
  638. bbdoc: Callback for window activate
  639. End Rem
  640. Function OnWindowActivate(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  641. PostGuiEvent(EVENT_WINDOWACTIVATE, TGadget(obj))
  642. End Function
  643. Rem
  644. bbdoc: Callback for window deactivate
  645. about: Not used, but might come in handy at some point...
  646. End Rem
  647. Function OnWindowDeactivate:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  648. ' We catch this but don't act on it...
  649. Return False
  650. End Function
  651. Function OnDragDrop(widget:Byte Ptr, context:Byte Ptr, x:Int, y:Int, data:Byte Ptr, info:Int, time:Int, obj:Object)
  652. Local uris:String[] = bmx_gtk3_selection_data_get_uris(data)
  653. If uris Then
  654. For Local uri:String = EachIn uris
  655. PostGuiEvent EVENT_WINDOWACCEPT,TGadget(obj),0,0,x,y,uri.Replace("file://", "")
  656. Next
  657. End If
  658. End Function
  659. Method SetShape:Int(x:Int,y:Int,w:Int,h:Int)
  660. If x <> xpos Or y <> ypos Then
  661. ignoreMoveEvent = True
  662. End If
  663. If w <> width Or h <> height Then
  664. ignoreSizeEvent = True
  665. End If
  666. Super.SetShape(Max(x, 0), Max(y, 0), w, h)
  667. 'actually move/resize
  668. 'using the ignore* saves from backupping old position
  669. 'and sizes before calling "SetShape()"
  670. If ignoreMoveEvent Then
  671. gtk_window_move(handle, x, y)
  672. End If
  673. If ignoreSizeEvent Then
  674. gtk_window_resize(handle, w, h)
  675. End If
  676. End Method
  677. Rem
  678. bbdoc: Set the window status text
  679. End Rem
  680. Method SetStatusText:Int(text:String)
  681. If statusbar Then
  682. Local t:Int, m0:String, m1:String, m2:String
  683. m0 = text
  684. t = m0.find("~t")
  685. If t <> -1 Then
  686. m1 = m0[t+1..]
  687. m0 = m0[..t]
  688. End If
  689. t = m1.find("~t")
  690. If t <> -1 Then
  691. m2 = m1[t+1..]
  692. m1 = m1[..t]
  693. End If
  694. Local mb0:Byte Ptr = m0.ToUTF8String()
  695. Local mb1:Byte Ptr = m1.ToUTF8String()
  696. Local mb2:Byte Ptr = m2.ToUTF8String()
  697. gtk_label_set_text(sblabels[0], mb0)
  698. gtk_label_set_text(sblabels[1], mb1)
  699. gtk_label_set_text(sblabels[2], mb2)
  700. MemFree(mb2)
  701. MemFree(mb1)
  702. MemFree(mb0)
  703. If m0.length = 0 And m1.length = 0 And m2.length = 0 Then
  704. gtk_widget_show(sblabels[0])
  705. gtk_widget_hide(sblabels[1])
  706. gtk_widget_hide(sblabels[2])
  707. Else
  708. If m0.length > 0 Then
  709. gtk_widget_show(sblabels[0])
  710. Else
  711. gtk_widget_hide(sblabels[0])
  712. End If
  713. If m1.length > 0 Then
  714. gtk_widget_show(sblabels[1])
  715. Else
  716. gtk_widget_hide(sblabels[1])
  717. End If
  718. If m2.length > 0 Then
  719. gtk_widget_show(sblabels[2])
  720. Else
  721. gtk_widget_hide(sblabels[2])
  722. End If
  723. End If
  724. End If
  725. End Method
  726. Method GetMenu:TGadget()
  727. Return Self
  728. End Method
  729. Method createStatusbar()
  730. ' our "statusbar" is actually a horizontal box...
  731. statusbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 0)
  732. gtk_widget_show(statusbar)
  733. sblabels = New Byte Ptr[3]
  734. For Local i:Int = 0 Until 3
  735. Local sblabel:Byte Ptr = gtk_label_new("")
  736. sblabels[i] = sblabel
  737. If i = 0 Then
  738. gtk_misc_set_alignment(sblabel, 0, 0.5)
  739. 'gtk_label_set_yalign(sblabel, 0.5) ' 3.16
  740. Else If i = 2 Then
  741. gtk_misc_set_alignment(sblabel, 1, 0.5)
  742. 'gtk_label_set_xalign(sblabel, 1) ' 3.16
  743. 'gtk_label_set_yalign(sblabel, 0.5) ' 3.16
  744. End If
  745. gtk_box_pack_start(statusbar, sblabel, True, True, 0)
  746. Next
  747. ' add to the window!
  748. gtk_box_pack_start(box, statusbar, False, True, 0)
  749. End Method
  750. Method addToolbar(_toolbar:TGTKToolbar)
  751. If toolbar <> Null Then
  752. toolbar.free()
  753. End If
  754. toolbar = _toolbar
  755. ' add to the list
  756. gtk_box_pack_start(box, toolbar.handle, False, False, 0)
  757. ' we need to move this to the correct place (usually under the menu)
  758. If menubar Then
  759. gtk_box_reorder_child(box, toolbar.handle, 1)
  760. Else
  761. gtk_box_reorder_child(box, toolbar.handle, 0)
  762. End If
  763. End Method
  764. Method ClientHeight:Int()
  765. ?bmxng
  766. Local allocation:GtkAllocation
  767. ?Not bmxng
  768. Local allocation:GtkAllocation = New GtkAllocation
  769. ?
  770. gtk_widget_get_allocation(container, allocation)
  771. Local h:Int = allocation.height
  772. If h <= 8 Then
  773. h = height
  774. ?bmxng
  775. Local minReq:GtkRequisition
  776. Local natReq:GtkRequisition
  777. ?Not bmxng
  778. Local minReq:GtkRequisition = New GtkRequisition
  779. Local natReq:GtkRequisition = New GtkRequisition
  780. ?
  781. If statusbar Then
  782. gtk_widget_get_preferred_size(statusbar, minReq, natReq)
  783. h:- natReq.height
  784. End If
  785. If menubar Then
  786. gtk_widget_get_preferred_size(menubar, minReq, natReq)
  787. h:- natReq.height
  788. End If
  789. End If
  790. If toolbar Then
  791. h:- toolbar.height
  792. End If
  793. Return h
  794. End Method
  795. Method ClientWidth:Int()
  796. ?bmxng
  797. Local allocation:GtkAllocation
  798. ?Not bmxng
  799. Local allocation:GtkAllocation = New GtkAllocation
  800. ?
  801. gtk_widget_get_allocation(handle, allocation)
  802. Local w:Int = allocation.width
  803. If w <= 8 Then
  804. w = width
  805. End If
  806. Return w
  807. End Method
  808. Rem
  809. bbdoc: Pop up a popup menu
  810. End Rem
  811. Method PopupMenu:Int(menu:TGadget,extra:Object=Null)
  812. If TGTKMenuItem(menu) Then
  813. If TGTKMenuItem(menu).popupMenu Then
  814. TGTKMenuItem(menu).popupExtra = extra
  815. gtk_menu_popup(TGTKMenuItem(menu).popupMenu, Null, Null, Null, Null, 0, gtk_get_current_event_time())
  816. End If
  817. End If
  818. End Method
  819. Method free:Int() Override
  820. Super.Free()
  821. If handle
  822. gtk_widget_destroy(handle)
  823. EndIf
  824. handle = Null
  825. gtkWindows.remove(Self)
  826. End Method
  827. Method Activate:Int(cmd:Int)
  828. Super.Activate(cmd)
  829. If Not visible Return 0
  830. Select cmd
  831. Case ACTIVATE_MAXIMIZE
  832. gtk_window_maximize(handle)
  833. Case ACTIVATE_MINIMIZE
  834. gtk_window_iconify(handle)
  835. Case ACTIVATE_RESTORE
  836. ' since we need to remember if we are maximized while being minimized
  837. ' we check for minimized first...
  838. If _minimized Then
  839. gtk_window_deiconify(handle)
  840. Else If _maximized Then
  841. gtk_window_unmaximize(handle)
  842. End If
  843. Case ACTIVATE_FOCUS
  844. gtk_window_present(handle)
  845. End Select
  846. End Method
  847. Method SetMinimumSize:Int(w:Int, h:Int)
  848. ?bmxng
  849. Local geom:GdkGeometry
  850. ?Not bmxng
  851. Local geom:GdkGeometry = New GdkGeometry
  852. ?
  853. gtk_window_set_geometry_hints(handle, Null, geom, GDK_HINT_MIN_SIZE)
  854. End Method
  855. Rem
  856. bbdoc: Sets the window icon with the specified pixmap.
  857. End Rem
  858. Method setIcon(pix:TPixmap)
  859. If pix <> Null Then
  860. Local pixmap:TPixmap = pix.convert( PF_RGBA8888 )
  861. Local icon:Byte Ptr = gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
  862. pixmap.width, pixmap.height, pixmap.Pitch, Null, Null)
  863. gtk_window_set_icon(handle, icon)
  864. End If
  865. End Method
  866. Rem
  867. bbdoc: Returns the window state.
  868. End Rem
  869. Method State:Int()
  870. Local flags:Int = Super.state()
  871. ' Note: you can be maximized and minimized at the same time, so that when
  872. ' we un-maximize (de-conify) it goes back to maximized.
  873. ' not sure if we should set them both in this instance. "Not" at the moment...
  874. If _minimized Then
  875. flags:| STATE_MINIMIZED
  876. Else If _maximized Then
  877. flags:| STATE_MAXIMIZED
  878. End If
  879. Return flags
  880. End Method
  881. Method SetText:Int(text:String)
  882. Local textPtr:Byte Ptr = text.ToUTF8String()
  883. gtk_window_set_title(handle, textPtr)
  884. MemFree(textPtr)
  885. End Method
  886. Method GetText:String()
  887. Return String.FromUTF8String(gtk_window_get_title(handle))
  888. End Method
  889. Method toString:String()
  890. Return "TGTKWindow"
  891. End Method
  892. End Type
  893. Rem
  894. bbdoc: A menu item.
  895. End Rem
  896. Type TGTKMenuItem Extends TGTKGadget
  897. Field popupMenu:Byte Ptr
  898. Field tag:Int = 0
  899. Field ignoreSelection:Int
  900. Field isCheckable:Int
  901. Field hasMnemonic:Int
  902. Field isSeparator:Int
  903. Field checked:Int
  904. Field text:String
  905. Field index:Int
  906. Field isStockItem:Int
  907. Global popupExtra:Object
  908. ' we use these to remember keycode and modifier just in case we need to make this
  909. ' menu item a check-type - in which case we delete and create a new one.
  910. Field myKeycode:Int
  911. Field myModifier:Int
  912. Field windowAccelGroup:Byte Ptr
  913. Field pixmap:TPixmap
  914. Field imagePixbuf:Byte Ptr
  915. Field image:Byte Ptr
  916. Function CreateMenuItem:TGTKMenuItem(label:String, tag:Int, parent:TGadget)
  917. Local this:TGTKMenuItem = New TGTKMenuItem
  918. this.initMenu(label, tag, parent)
  919. Return this
  920. End Function
  921. Method initMenu(_label:String, _tag:Int, _parent:TGadget)
  922. iclass = GTK_MENUITEM
  923. tag = _tag
  924. Local originalLabel:String = _label
  925. If TGTKWindow(_parent) Then
  926. windowAccelGroup = TGTKWindow(_parent).accelGroup
  927. Else If TGTKMenuItem(_parent)
  928. windowAccelGroup = TGTKMenuItem(_parent).windowAccelGroup
  929. Else
  930. 'Throw "menu item has no valid parent"
  931. ' A popupmenu... perhaps?
  932. windowAccelGroup = Null
  933. End If
  934. ' localisation
  935. If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
  936. MapInsert maxgui_driver._mapLocalized, Self, [_label,""]
  937. _label = LocalizeString(_label)
  938. End If
  939. setAccelMapId(_label)
  940. ' this is our menu item / text
  941. If _label = Null Or _label.length = 0 Then
  942. ' a separator
  943. handle = gtk_separator_menu_item_new()
  944. isSeparator = True
  945. Else
  946. ' convert underscores to doubles
  947. '_label = _label.replace("_", "__")
  948. ' a normal menu item
  949. ' Does it have a
  950. Local p:Int = _label.find("&")
  951. _label = processText(_label)
  952. Local _labelPtr:Byte Ptr = _label.ToUTF8String()
  953. ' does this label have a mnemonic?
  954. If p >= 0 Then
  955. '_label = _label.replace("&", "_")
  956. hasMnemonic = True
  957. handle = gtk_menu_item_new_with_mnemonic(_labelPtr)
  958. Else
  959. handle = gtk_menu_item_new_with_label(_labelPtr)
  960. End If
  961. MemFree(_labelPtr)
  962. End If
  963. text = _label
  964. ' let's hope that at least the parent is set!!
  965. If _parent Then
  966. parent = _parent
  967. If TGTKWindow(parent) Then
  968. Assert TGTKWindow(parent).menubar, "Cannot add menu to window created without WINDOW_MENU"
  969. ' add a new menu for the menubar
  970. ' Note : we never show this!! (on purpose)
  971. menu = gtk_menu_new()
  972. ' attach the menu text to the menu
  973. gtk_menu_item_set_submenu(handle, menu)
  974. ' add the menu to the menubar
  975. ' Need to make sure we have a menubar to add it to...
  976. ' In debug mode we'll have failed the above assertion already.
  977. If TGTKWindow(parent).menubar Then
  978. gtk_menu_shell_append(TGTKWindow(parent).menubar, handle)
  979. End If
  980. Else If TGTKMenuItem(parent) Then
  981. If TGTKMenuItem(parent).popupMenu Then
  982. gtk_container_add(TGTKMenuItem(parent).popupMenu, handle)
  983. Else
  984. ' we may need to create a sub menu to hold this!
  985. If Not TGTKMenuItem(parent).menu Then
  986. TGTKMenuItem(parent).menu = gtk_menu_new()
  987. ' attach the menu text to the menu
  988. gtk_menu_item_set_submenu(TGTKMenuItem(parent).handle, TGTKMenuItem(parent).menu)
  989. End If
  990. gtk_menu_shell_append(TGTKMenuItem(parent).menu, handle)
  991. End If
  992. ' we need to know our position in the menu
  993. index = parent.kids.count()
  994. End If
  995. gtk_widget_show(handle)
  996. ' Add an activate signal and store ourself in the menu data
  997. If Not TGTKWindow(parent) And Not isSeparator Then
  998. addConnection("activate", g_signal_cb2_ret(handle, "activate", MenuSelected, Self, Destroy, 0))
  999. g_object_set_data(handle, "_maxmenu", Self)
  1000. End If
  1001. Else ' popupmenu...
  1002. popupMenu = gtk_menu_new()
  1003. ' don't add OUR menu item to the list, as it is only a place holder.
  1004. 'gtk_container_add(popupMenu, handle)
  1005. gtk_widget_show(handle)
  1006. End If
  1007. End Method
  1008. Method SetHotKey:Int(keycode:Int, modifier:Int)
  1009. myKeycode = keycode
  1010. myModifier = modifier
  1011. setAccelEntry(keycode, modifier)
  1012. ' override F10 menu access?
  1013. If keycode = KEY_F10 And modifier = 0 Then
  1014. Local settings:Byte Ptr = gtk_settings_get_default()
  1015. gtk_settings_set_string_property(settings, "gtk-menu-bar-accel", "<alt>F10", AppFile)
  1016. End If
  1017. End Method
  1018. Rem
  1019. bbdoc: Callback function for selecting a menu option.
  1020. about: Triggers a menu action event.<br/>
  1021. NOTE - We have to ignore "obj" because it is not reliable
  1022. End Rem
  1023. Function MenuSelected:Int(widget:Byte Ptr, obj:Object)
  1024. Local _menu:TGTKMenuItem = g_object_get_menudata(widget, "_maxmenu")
  1025. Assert _menu, "Menu data is missing... !!!!"
  1026. ' If this isn't a submenu root (one which has sub menus)
  1027. ' then we can post the event
  1028. If Not _menu.menu And Not _menu.ignoreSelection Then
  1029. PostGuiEvent(EVENT_MENUACTION, _menu, _menu.tag,,,,_menu.popupextra)
  1030. If _menu.popupExtra Then
  1031. _menu.popupExtra = Null
  1032. End If
  1033. End If
  1034. ' We need to keep the "checked" flag uptodate...
  1035. If _menu.isCheckable Then
  1036. _menu.checked = gtk_check_menu_item_get_active(widget)
  1037. End If
  1038. _menu.ignoreSelection = False
  1039. Return True
  1040. End Function
  1041. Method SetSelected:Int(bool:Int)
  1042. ' Don't do anything if we are already set...
  1043. If (checked = bool) And isCheckable Then
  1044. Return 0
  1045. End If
  1046. ignoreSelection = True
  1047. ' if it's not checkable yet, we need to make it so
  1048. If Not isCheckable And Not isSeparator And menu = Null Then
  1049. ' remove the current menu
  1050. If handle Then
  1051. gtk_widget_destroy(handle)
  1052. hasAccel = False
  1053. End If
  1054. Local textPtr:Byte Ptr = text.ToUtf8String()
  1055. If hasMnemonic Then
  1056. handle = gtk_check_menu_item_new_with_mnemonic(textPtr)
  1057. Else
  1058. handle = gtk_check_menu_item_new_with_label(textPtr)
  1059. End If
  1060. MemFree(textPtr)
  1061. gtk_widget_show(handle)
  1062. ' if we originally gave this a keycode / modifier, we need to re-establish it.
  1063. If myKeycode <> 0 Then
  1064. SetHotKey(myKeycode, myModifier)
  1065. End If
  1066. If TGTKWindow(parent) Then
  1067. ' Only insert if menubar exists tho...
  1068. If TGTKWindow(parent).menubar Then
  1069. gtk_menu_shell_insert(TGTKWindow(parent).menubar, handle, index)
  1070. End If
  1071. Else If TGTKMenuItem(parent) Then
  1072. If TGTKMenuItem(parent).menu Then
  1073. gtk_menu_shell_insert(TGTKMenuItem(parent).menu, handle, index)
  1074. End If
  1075. EndIf
  1076. ' we need to catch toggles!
  1077. addConnection("toggled", g_signal_cb2_ret(handle, "toggled", MenuSelected, Self, Destroy, 0))
  1078. g_object_set_data(handle, "_maxmenu", Self)
  1079. isCheckable = True
  1080. ' If we are not setting it checked it won't generate a toggle event...
  1081. If Not bool Then
  1082. ignoreSelection = False
  1083. End If
  1084. End If
  1085. checked = bool
  1086. gtk_check_menu_item_set_active(handle, checked)
  1087. End Method
  1088. Rem
  1089. bbdoc: Returns menu state - checked or unchecked
  1090. End Rem
  1091. Method State:Int()
  1092. Local _state:Int = Super.State()
  1093. If isCheckable Then
  1094. If gtk_check_menu_item_get_active(handle) Then
  1095. _state :| STATE_SELECTED
  1096. End If
  1097. End If
  1098. Return _state
  1099. End Method
  1100. Rem
  1101. bbdoc: Returns the menu text
  1102. End Rem
  1103. Method GetText:String()
  1104. If Not isSeparator Then
  1105. Return String.FromUTF8String(gtk_label_get_text(gtk_bin_get_child(handle)))
  1106. End If
  1107. Return ""
  1108. End Method
  1109. Rem
  1110. bbdoc: Sets the menu text
  1111. End Rem
  1112. Method SetText:Int(label:String)
  1113. If Not isSeparator Then
  1114. If label = Null Then
  1115. label = ""
  1116. End If
  1117. text = processText(label)
  1118. Local labelPtr:Byte Ptr = text.ToUTF8String()
  1119. If label.find("&") >= 0 Then
  1120. gtk_label_set_text_with_mnemonic(gtk_bin_get_child(handle), labelPtr)
  1121. Else
  1122. gtk_label_set_text(gtk_bin_get_child(handle), labelPtr)
  1123. End If
  1124. MemFree(labelPtr)
  1125. End If
  1126. End Method
  1127. Method free:Int() Override
  1128. Local _handle:Byte Ptr = handle
  1129. Super.Free()
  1130. If _handle
  1131. gtk_widget_destroy(_handle)
  1132. End If
  1133. menu = Null
  1134. If pixmap Then
  1135. pixmap = Null
  1136. End If
  1137. If image Then
  1138. ' g_object_unref(image) ' oops.. TODO: we might need this still.
  1139. image = Null
  1140. End If
  1141. If imagePixbuf Then
  1142. g_object_unref(imagePixbuf)
  1143. imagePixbuf = Null
  1144. End If
  1145. End Method
  1146. Method rethink:Int()
  1147. End Method
  1148. Method DoLayout:Int()
  1149. End Method
  1150. Method SetPixmap:Int(pix:TPixmap, flags:Int)
  1151. If Not isSeparator Then
  1152. If pix Then
  1153. If PixmapFormat(pix) <> PF_RGBA8888 And PixmapFormat(pix) <> PF_BGRA8888 Then
  1154. pixmap = pix.convert( PF_RGBA8888 )
  1155. Else
  1156. pixmap = pix
  1157. End If
  1158. If imagePixbuf Then
  1159. g_object_unref(imagePixbuf)
  1160. End If
  1161. imagePixbuf = gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
  1162. pixmap.width, pixmap.height, pixmap.Pitch, Null, Null)
  1163. If Not image Then
  1164. image = gtk_image_new()
  1165. End If
  1166. gtk_image_set_from_pixbuf(image, imagePixbuf)
  1167. Else
  1168. If pixmap Then
  1169. gtk_image_clear(image)
  1170. pixmap = Null
  1171. End If
  1172. End If
  1173. If image Then
  1174. ' TODO
  1175. 'gtk_image_menu_item_set_image(handle, image)
  1176. End If
  1177. End If
  1178. End Method
  1179. Method toString:String()
  1180. Return "TGTKMenuItem : " + text + " : " + Super.ToString()
  1181. End Method
  1182. Method SetEnabled:Int(bool:Int)
  1183. gtk_widget_set_sensitive(handle, bool)
  1184. End Method
  1185. End Type
  1186. Type TGTKIconStrip Extends TIconStrip
  1187. Field images:Byte Ptr[]
  1188. Field names:String[]
  1189. Function IsNotBlank:Int(pixmap:TPixmap)
  1190. Local w:Int = pixmap.width
  1191. Local h:Int = pixmap.height
  1192. Local c:Int = pixmap.ReadPixel(0,0)
  1193. For Local x:Int = 0 Until h
  1194. For Local y:Int = 0 Until h
  1195. If pixmap.ReadPixel(x,y) <> c Then
  1196. Return True
  1197. End If
  1198. Next
  1199. Next
  1200. End Function
  1201. Function Create:TGTKIconStrip(source:Object)
  1202. Local baseName:String = MilliSecs()
  1203. Local pix:TPixmap = TPixmap(source)
  1204. If Not pix Then
  1205. pix = LoadPixmap(source)
  1206. If Not pix Then
  1207. Return Null
  1208. End If
  1209. End If
  1210. Local n:Int = pix.width/pix.height
  1211. If n = 0 Then
  1212. Return Null
  1213. End If
  1214. Local pixmap:TPixmap = pix.convert( PF_RGBA8888 )
  1215. Local icons:TGTKIconStrip = New TGTKIconStrip
  1216. icons.pixmap=pixmap
  1217. icons.count=n
  1218. icons.images=New Byte Ptr[n]
  1219. icons.names = New String[n]
  1220. Local h:Int = pixmap.height
  1221. Local w:Int = h
  1222. For Local x:Int = 0 Until n
  1223. Local winpix:TPixmap = pixmap.Window(x*w,0,w,pixmap.height)
  1224. If IsNotBlank(winpix) Then
  1225. icons.images[x]= gdk_pixbuf_new_from_data(winpix.pixels, GDK_COLORSPACE_RGB, True, 8, ..
  1226. w, h, pixmap.Pitch, Null, Null)
  1227. Local name:String = baseName + "_" + x
  1228. icons.names[x] = name
  1229. gtk_icon_theme_add_builtin_icon(name, h, icons.images[x])
  1230. End If
  1231. Next
  1232. Return icons
  1233. End Function
  1234. End Type
  1235. Rem
  1236. bbdoc: Base type for button gadgets.
  1237. End Rem
  1238. Type TGTKButton Extends TGTKGadget
  1239. Field hotkey:THotKey
  1240. Field ignoreButtonClick:Int
  1241. Method makeButton(label:String) Abstract
  1242. Method initButton(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  1243. Init(iclass, x, y, w, h, style)
  1244. parent = group
  1245. ' localisation
  1246. If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
  1247. MapInsert maxgui_driver._mapLocalized, Self, [label,""]
  1248. label = LocalizeString(label)
  1249. End If
  1250. makeButton(label)
  1251. setAccelMapId(label)
  1252. gtk_layout_put(TGTKContainer(parent).container, handle, x, y)
  1253. gtk_widget_set_size_request(handle, w, Max(h,0))
  1254. sensitivity:| SENSITIZE_MOUSE
  1255. ' Set as default ?
  1256. If style = BUTTON_OK Then
  1257. gtk_widget_grab_default(handle)
  1258. End If
  1259. setShow(True)
  1260. ' button clicked handler
  1261. addConnection("clicked", g_signal_cb2(handle, "clicked", OnButtonClicked, Self, Destroy, 0))
  1262. ' catch right-mouse buttons
  1263. addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
  1264. addConnection("enter-notify-event", g_signal_cb3_ret(handle, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
  1265. addConnection("leave-notify-event", g_signal_cb3_ret(handle, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
  1266. End Method
  1267. Rem
  1268. bbdoc: Callback for button click.
  1269. End Rem
  1270. Function OnButtonClicked(widget:Byte Ptr, obj:Object)
  1271. If Not TGTKButton(obj).ignoreButtonClick Then
  1272. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), ButtonState(TGadget(obj)))
  1273. End If
  1274. TGTKButton(obj).ignoreButtonClick = False
  1275. End Function
  1276. Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  1277. Local x:Double, y:Double, button:Int
  1278. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  1279. If button = 3 Then ' right mouse button
  1280. PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,Int(x),Int(y))
  1281. Return True
  1282. End If
  1283. Return False
  1284. End Function
  1285. Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  1286. If TGTKGadget(obj).visible Then
  1287. PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
  1288. End If
  1289. Return False
  1290. End Function
  1291. Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  1292. If TGTKGadget(obj).visible Then
  1293. PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
  1294. End If
  1295. Return False
  1296. End Function
  1297. Rem
  1298. bbdoc: Sets the button text.
  1299. End Rem
  1300. Method SetText:Int(text:String)
  1301. text = processText(text)
  1302. Local textPtr:Byte Ptr = text.ToUTF8String()
  1303. gtk_button_set_label(handle, textPtr)
  1304. MemFree(textPtr)
  1305. gtk_button_set_use_underline(handle, True)
  1306. End Method
  1307. Rem
  1308. bbdoc: Returns the button text.
  1309. End Rem
  1310. Method GetText:String()
  1311. Return String.FromUTF8String(gtk_button_get_label(handle))
  1312. End Method
  1313. Rem
  1314. bbdoc: Sets the button text color.
  1315. End Rem
  1316. Method SetTextColor:Int(r:Int, g:Int, b:Int)
  1317. Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
  1318. Local buttonLabel:Byte Ptr = gtk_bin_get_child(handle)
  1319. gtk_widget_override_color(buttonLabel, GTK_STATE_FLAG_NORMAL, color)
  1320. gtk_widget_override_color(buttonLabel, GTK_STATE_FLAG_ACTIVE, color)
  1321. gtk_widget_override_color(buttonLabel, GTK_STATE_FLAG_PRELIGHT, color)
  1322. End Method
  1323. Method free:Int() Override
  1324. Super.Free()
  1325. If handle
  1326. gtk_widget_destroy(handle)
  1327. EndIf
  1328. handle = Null
  1329. End Method
  1330. Rem
  1331. bbdoc: Sets a hot key for the button.
  1332. End Rem
  1333. Method SetHotKey:Int(keycode:Int, modifier:Int)
  1334. setAccelEntry(keycode, modifier)
  1335. End Method
  1336. Method toString:String()
  1337. Return "TGTKButton"
  1338. End Method
  1339. End Type
  1340. Rem
  1341. bbdoc: A push button
  1342. End Rem
  1343. Type TGTKButtonPush Extends TGTKButton
  1344. Function CreateButton:TGTKButtonPush(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  1345. Local this:TGTKButtonPush = New TGTKButtonPush
  1346. this.initButton(x, y, w, h, label, group, style)
  1347. Return this
  1348. End Function
  1349. Method makeButton(label:String)
  1350. label = processText(label)
  1351. Local labelPtr:Byte Ptr = label.ToUTF8String()
  1352. handle = gtk_button_new_with_label(labelPtr)
  1353. MemFree(labelPtr)
  1354. gtk_button_set_use_underline(handle, True)
  1355. ' enable "default" gadget functionality
  1356. g_object_set_int(handle, "can-default", True)
  1357. End Method
  1358. Method SetText:Int(text:String)
  1359. text = processText(text)
  1360. Local textPtr:Byte Ptr = text.ToUTF8String()
  1361. gtk_button_set_label(handle, textPtr)
  1362. MemFree(textPtr)
  1363. gtk_button_set_use_underline(handle, True)
  1364. End Method
  1365. Method SetPixmap:Int(pix:TPixmap, flags:Int = 0)
  1366. If pix Then
  1367. Local pixmap:TPixmap
  1368. If pix.format <> PF_RGBA8888 Then
  1369. pixmap = pix.convert( PF_RGBA8888 )
  1370. Else
  1371. pixmap = pix
  1372. End If
  1373. Local image:Byte Ptr = gtk_image_new_from_pixbuf(gdk_pixbuf_new_from_data(pixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
  1374. pixmap.width, pixmap.height, pixmap.Pitch, Null, Null))
  1375. If image Then
  1376. gtk_button_set_image(handle, image)
  1377. gtk_button_set_image_position(handle, GTK_POS_LEFT)
  1378. End If
  1379. End If
  1380. End Method
  1381. Method toString:String()
  1382. Return "TGTKButtonPush"
  1383. End Method
  1384. End Type
  1385. Rem
  1386. bbdoc: A button which has a toggle-type usage (radio / checkbox)
  1387. End Rem
  1388. Type TGTKToggleButton Extends TGTKButton
  1389. Field isSelected:Int
  1390. Method SetSelected:Int(bool:Int)
  1391. If bool <> gtk_toggle_button_get_active(handle) Then
  1392. ignoreButtonClick = True
  1393. End If
  1394. gtk_toggle_button_set_active(handle, bool)
  1395. isSelected = bool
  1396. End Method
  1397. Method State:Int()
  1398. Local flags:Int = Super.State()
  1399. If gtk_toggle_button_get_active(handle) Then
  1400. flags:|STATE_SELECTED
  1401. End If
  1402. Return flags
  1403. End Method
  1404. Rem
  1405. bbdoc: Callback for button click.
  1406. End Rem
  1407. Function OnButtonClicked(widget:Byte Ptr, obj:Object)
  1408. If Not TGTKButton(obj).ignoreButtonClick Then
  1409. If TGTKToggleButton(obj).isSelected <> gtk_toggle_button_get_active(widget)
  1410. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), ButtonState(TGadget(obj)))
  1411. End If
  1412. TGTKToggleButton(obj).isSelected = gtk_toggle_button_get_active(widget)
  1413. End If
  1414. TGTKButton(obj).ignoreButtonClick = False
  1415. End Function
  1416. Method disableEvents()
  1417. End Method
  1418. Method enableEvents()
  1419. End Method
  1420. End Type
  1421. Rem
  1422. bbdoc: A radio button.
  1423. End Rem
  1424. Type TGTKButtonRadio Extends TGTKToggleButton
  1425. Function CreateButton:TGTKButtonRadio(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  1426. Local this:TGTKButtonRadio = New TGTKButtonRadio
  1427. this.initButton(x, y, w, h, label, group, style)
  1428. Return this
  1429. End Function
  1430. Method makeButton(label:String)
  1431. Local _group:Byte Ptr = TGTKContainer(parent).radioGroup
  1432. label = processText(label)
  1433. Local labelPtr:Byte Ptr = label.ToUTF8String()
  1434. If _group = Null Then
  1435. handle = gtk_radio_button_new_with_label(Null, labelPtr)
  1436. gtk_toggle_button_set_active(handle, True)
  1437. isSelected = True
  1438. Else
  1439. handle = gtk_radio_button_new_with_label(_group, labelPtr)
  1440. End If
  1441. MemFree(labelPtr)
  1442. ' update the radiogroup, ready for a new radio button...
  1443. TGTKContainer(parent).radioGroup = gtk_radio_button_get_group(handle)
  1444. gtk_button_set_use_underline(handle, True)
  1445. If style & BUTTON_PUSH Then
  1446. gtk_toggle_button_set_mode(handle, False)
  1447. End If
  1448. End Method
  1449. Method SetSelected:Int(bool:Int)
  1450. disableEvents()
  1451. gtk_toggle_button_set_active(handle, bool)
  1452. enableEvents()
  1453. isSelected = bool
  1454. End Method
  1455. Function OnButtonClicked(widget:Byte Ptr, obj:Object)
  1456. TGTKToggleButton(obj).isSelected = gtk_toggle_button_get_active(widget)
  1457. If TGTKToggleButton(obj).isSelected Then
  1458. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), ButtonState(TGadget(obj)))
  1459. End If
  1460. TGTKButton(obj).ignoreButtonClick = False
  1461. End Function
  1462. Method disableEvents()
  1463. For Local gadget:TGTKButtonRadio = EachIn parent.kids
  1464. Local id:TGTKInteger = TGTKInteger(gadget.connectionMap.ValueForKey("clicked"))
  1465. If id Then
  1466. g_signal_handler_disconnect(gadget.handle, id.value)
  1467. End If
  1468. Next
  1469. End Method
  1470. Method enableEvents()
  1471. For Local gadget:TGTKButtonRadio = EachIn parent.kids
  1472. gadget.addConnection("clicked", g_signal_cb2(gadget.handle, "clicked", OnButtonClicked, gadget, Destroy, 0))
  1473. Next
  1474. End Method
  1475. Method toString:String()
  1476. Return "TGTKButtonRadio"
  1477. End Method
  1478. End Type
  1479. Rem
  1480. bbdoc: A checkbox button
  1481. End Rem
  1482. Type TGTKButtonCheckbox Extends TGTKToggleButton
  1483. Function CreateButton:TGTKButtonCheckbox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  1484. Local this:TGTKButtonCheckbox = New TGTKButtonCheckbox
  1485. this.initButton(x, y, w, h, label, group, style)
  1486. Return this
  1487. End Function
  1488. Method makeButton(label:String)
  1489. label = processText(label)
  1490. Local labelPtr:Byte Ptr = label.ToUTF8String()
  1491. handle = gtk_check_button_new_with_label(labelPtr)
  1492. MemFree(labelPtr)
  1493. gtk_button_set_use_underline(handle, True)
  1494. If style & BUTTON_PUSH Then
  1495. gtk_toggle_button_set_mode(handle, False)
  1496. End If
  1497. End Method
  1498. Method toString:String()
  1499. Return "TGTKButtonCheckbox"
  1500. End Method
  1501. End Type
  1502. Rem
  1503. bbdoc: A label.
  1504. End Rem
  1505. Type TGTKLabel Extends TGTKGadget
  1506. ' surrounding frame widget, if any
  1507. Field frame:Byte Ptr
  1508. Field hasFrame:Int
  1509. Field isSeparator:Int
  1510. Field ebox:Byte Ptr
  1511. Function CreateLabel:TGTKLabel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  1512. Local this:TGTKLabel = New TGTKLabel
  1513. this.initLabel(x, y, w, h, label, group, style)
  1514. Return this
  1515. End Function
  1516. Method initLabel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  1517. Init(GTK_LABEL, x, y, w, h, style)
  1518. If style & LABEL_FRAME And style & LABEL_SUNKENFRAME Then
  1519. isSeparator = True
  1520. End If
  1521. If Not isSeparator Then
  1522. Local labelPtr:Byte Ptr = label.ToUTF8String()
  1523. handle = gtk_label_new(labelPtr)
  1524. MemFree(labelPtr)
  1525. If style & LABEL_RIGHT Then
  1526. gtk_misc_set_alignment(handle, 1, 0.5)
  1527. Else If style & LABEL_CENTER Then
  1528. gtk_misc_set_alignment(handle, 0.5, 0.5)
  1529. Else
  1530. gtk_misc_set_alignment(handle, 0, 0.5)
  1531. End If
  1532. sensitivity:| SENSITIZE_MOUSE
  1533. ' since a Label can't accept events, we wrap it inside an event box which can
  1534. ebox = gtk_event_box_new()
  1535. gtk_event_box_set_visible_window(ebox, False)
  1536. gtk_widget_add_events(ebox, GDK_BUTTON_PRESS_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
  1537. addConnection("enter-notify-event", g_signal_cb3_ret(ebox, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
  1538. addConnection("leave-notify-event", g_signal_cb3_ret(ebox, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
  1539. addConnection("button-press-event", g_signal_cb3_ret(ebox, "button-press-event", OnMouseDown, Self, Destroy, 0))
  1540. ' show the box
  1541. gtk_widget_show(ebox)
  1542. ' add the label to the eventbox
  1543. gtk_container_add(ebox, handle)
  1544. If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
  1545. LocalizeGadget(Self, label)
  1546. Else
  1547. SetText(label)
  1548. EndIf
  1549. End If
  1550. ' Should we add a frame?
  1551. If style & LABEL_FRAME Or style & LABEL_SUNKENFRAME Then
  1552. hasFrame = True
  1553. If isSeparator Then
  1554. If w < h Then
  1555. frame = gtk_separator_new(GTK_ORIENTATION_VERTICAL)
  1556. Else
  1557. frame = gtk_separator_new(GTK_ORIENTATION_HORIZONTAL)
  1558. End If
  1559. handle = frame
  1560. Else
  1561. frame = gtk_frame_new(Null)
  1562. If style & LABEL_FRAME Then
  1563. gtk_frame_set_shadow_type(frame, GTK_SHADOW_ETCHED_IN)
  1564. Else
  1565. gtk_frame_set_shadow_type(frame, GTK_SHADOW_IN)
  1566. End If
  1567. gtk_container_add(frame, ebox)
  1568. End If
  1569. gtk_layout_put(TGTKContainer(group).container, frame, x, y)
  1570. gtk_widget_set_size_request(frame, w, Max(h,0))
  1571. Else
  1572. gtk_layout_put(TGTKContainer(group).container, ebox, x, y)
  1573. gtk_widget_set_size_request(handle, w, Max(h,0))
  1574. End If
  1575. setShow(True)
  1576. End Method
  1577. Rem
  1578. bbdoc: Show or Hide the label
  1579. End Rem
  1580. Method SetShow:Int(truefalse:Int)
  1581. visible = truefalse
  1582. mySetVisible = visible
  1583. If hasFrame Then
  1584. If truefalse Then
  1585. gtk_widget_show(frame)
  1586. Else
  1587. gtk_widget_hide(frame)
  1588. EndIf
  1589. End If
  1590. If Not isSeparator Then
  1591. If truefalse Then
  1592. gtk_widget_show(handle)
  1593. gtk_widget_show(ebox)
  1594. Else
  1595. gtk_widget_hide(ebox)
  1596. EndIf
  1597. End If
  1598. End Method
  1599. Method SetText:Int(text:String)
  1600. If Not isSeparator Then
  1601. Local textPtr:Byte Ptr = text.ToUtf8String()
  1602. gtk_label_set_text(handle, textPtr)
  1603. MemFree(textPtr)
  1604. End If
  1605. End Method
  1606. Method GetText:String()
  1607. If Not isSeparator Then
  1608. Return String.FromUTF8String(gtk_label_get_text(handle))
  1609. End If
  1610. Return Null
  1611. End Method
  1612. Method free:Int() Override
  1613. Super.Free()
  1614. If frame
  1615. gtk_widget_destroy(frame)
  1616. Else
  1617. If ebox Then
  1618. gtk_widget_destroy(ebox)
  1619. End If
  1620. EndIf
  1621. handle = Null
  1622. frame = Null
  1623. ebox = Null
  1624. End Method
  1625. Method setToolTip:Int(tip:String)
  1626. If Not isSeparator Then
  1627. If tip And tip.length > 0 Then
  1628. Local tipPtr:Byte Ptr = tip.ToUTF8String()
  1629. gtk_widget_set_tooltip_text(ebox, tipPtr)
  1630. MemFree(tipPtr)
  1631. Else
  1632. gtk_widget_set_has_tooltip(ebox, False)
  1633. End If
  1634. Else
  1635. If tip And tip.length > 0 Then
  1636. Local tipPtr:Byte Ptr = tip.ToUTF8String()
  1637. gtk_widget_set_tooltip_text(handle, tipPtr)
  1638. MemFree(tipPtr)
  1639. Else
  1640. gtk_widget_set_has_tooltip(handle, False)
  1641. End If
  1642. End If
  1643. End Method
  1644. Method Rethink:Int()
  1645. If frame Then
  1646. gtk_layout_move(TGTKContainer(parent).container, frame, Max(xpos, 0), Max(ypos, 0))
  1647. gtk_widget_set_size_request(frame, Max(width,0), Max(height,0))
  1648. Else If handle Then
  1649. gtk_layout_move(TGTKContainer(parent).container, ebox, Max(xpos, 0), Max(ypos, 0))
  1650. gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
  1651. End If
  1652. End Method
  1653. Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  1654. If TGTKGadget(obj).visible Then
  1655. PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
  1656. End If
  1657. Return False
  1658. End Function
  1659. Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  1660. If TGTKGadget(obj).visible Then
  1661. PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
  1662. End If
  1663. Return False
  1664. End Function
  1665. Rem
  1666. bbdoc: Callback For mouse button press.
  1667. End Rem
  1668. Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  1669. Local x:Double, y:Double, button:Int
  1670. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  1671. If button = 3 Then ' right mouse button
  1672. PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,Int(x),Int(y))
  1673. Else ' other mouse buttons
  1674. If button = 2 Then
  1675. button = 3
  1676. End If
  1677. PostGuiEvent(EVENT_MOUSEDOWN, TGadget(obj),button,,Int(x),Int(y))
  1678. End If
  1679. Return True
  1680. End Function
  1681. Rem
  1682. bbdoc: Sets the label text color.
  1683. End Rem
  1684. Method SetTextColor:Int(r:Int, g:Int, b:Int)
  1685. Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
  1686. gtk_widget_override_color(handle, GTK_STATE_FLAG_NORMAL, color)
  1687. End Method
  1688. Method toString:String()
  1689. Return "TGTKLabel"
  1690. End Method
  1691. End Type
  1692. Rem
  1693. bbdoc: Base type for editable gadgets (textfield / textarea).
  1694. End Rem
  1695. Type TGTKEditable Extends TGTKGadget
  1696. Field ignoreTextChange:Int
  1697. Method Activate:Int(cmd:Int)
  1698. Super.Activate(cmd)
  1699. End Method
  1700. Function OnTextChanged(widget:Byte Ptr, obj:Object)
  1701. If Not TGTKEditable(obj).ignoreTextChange Then
  1702. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj))
  1703. End If
  1704. If TGTKEditable(obj).ignoreTextChange Then
  1705. TGTKEditable(obj).ignoreTextChange:-1
  1706. End If
  1707. End Function
  1708. ' key handler stuff - filtering etc
  1709. Function OnKeyDown:Int(widget:Byte Ptr, gdkEvent:Byte Ptr, obj:Object)
  1710. Local source:TGTKEditable = TGTKEditable(obj)
  1711. ' only if we are using a filter...
  1712. If source And source.eventfilter <> Null Then
  1713. Local _key:Int, _mods:Int
  1714. bmx_gtk3maxgui_gdkeventkey(gdkEvent, Varptr _key, Varptr _mods)
  1715. Local key:Int = TGTKKeyMap.mapBack(_key)
  1716. Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
  1717. Local event:TEvent=HotKeyEvent( key,mods, Null )
  1718. If event Then
  1719. event.emit()
  1720. Return True
  1721. EndIf
  1722. event = CreateEvent(EVENT_KEYDOWN, source, key, mods)
  1723. If Not source.eventfilter(event, source.context) Then
  1724. Return True
  1725. End If
  1726. Local char:Int = gdk_keyval_to_unicode(_key)
  1727. ' we sometimes get 0 from this function when key is valid... so set it to key just so that it has a value.
  1728. If char = 0 And key <> 0 Then
  1729. char = key
  1730. End If
  1731. event = CreateEvent(EVENT_KEYCHAR, source, char, mods)
  1732. If Not source.eventfilter(event, source.context) Then
  1733. Return True
  1734. End If
  1735. EndIf
  1736. Return False
  1737. End Function
  1738. End Type
  1739. Rem
  1740. bbdoc: A Text field.
  1741. End Rem
  1742. Type TGTKTextField Extends TGTKEditable
  1743. Field isPassword:Int
  1744. Function CreateTextField:TGTKTextField(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  1745. Local this:TGTKTextField = New TGTKTextField
  1746. this.initTextField(x, y, w, h, label, group, style)
  1747. Return this
  1748. End Function
  1749. Method initTextField(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  1750. handle = gtk_entry_new()
  1751. Init(GTK_TEXTFIELD, x, y, w, h, style)
  1752. If style Then
  1753. isPassword = True
  1754. gtk_entry_set_visibility(handle, False)
  1755. End If
  1756. ' causes the default gadget to be activated when Enter is pressed inside this Text Field.
  1757. g_object_set_int(handle, "activates-default", True)
  1758. setShow(True)
  1759. gtk_layout_put(TGTKContainer(group).container, handle, x, y)
  1760. gtk_widget_set_size_request(handle, w, Max(h,0))
  1761. ' add callbacks
  1762. addConnection("changed", g_signal_cb2(handle, "changed", OnTextChanged, Self, Destroy, 0))
  1763. addConnection("key-press-event", g_signal_cb3_ret(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
  1764. addConnection("focus-out-event", g_signal_cb3_ret(handle, "focus-out-event", OnFocusLost, Self, Destroy, 0))
  1765. ' catch right-mouse buttons
  1766. addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
  1767. End Method
  1768. Rem
  1769. bbdoc: Returns the textfield text.
  1770. End Rem
  1771. Method GetText:String()
  1772. Return String.FromUTF8String(gtk_entry_get_text(handle))
  1773. End Method
  1774. Rem
  1775. bbdoc: Sets the textfield text.
  1776. End Rem
  1777. Method SetText:Int(txt:String)
  1778. If txt = Null
  1779. txt = ""
  1780. End If
  1781. ' when set to blank, it raises 2 change events?
  1782. If txt = "" And GetText() <> "" Then
  1783. ignoreTextChange:+1
  1784. End If
  1785. If txt <> GetText() Then
  1786. ignoreTextChange:+1
  1787. End If
  1788. Local txtPtr:Byte Ptr = txt.ToUTF8String()
  1789. gtk_entry_set_text(handle, txtPtr)
  1790. MemFree(txtPtr)
  1791. End Method
  1792. Method free:Int() Override
  1793. Super.Free()
  1794. If handle
  1795. gtk_widget_destroy(handle)
  1796. EndIf
  1797. handle = Null
  1798. End Method
  1799. Method Activate:Int(cmd:Int)
  1800. Super.Activate(cmd)
  1801. Select cmd
  1802. Case ACTIVATE_CUT
  1803. gtk_editable_cut_clipboard(handle)
  1804. Case ACTIVATE_COPY
  1805. gtk_editable_copy_clipboard(handle)
  1806. Case ACTIVATE_PASTE
  1807. gtk_editable_paste_clipboard(handle)
  1808. End Select
  1809. End Method
  1810. Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  1811. Local x:Double, y:Double, button:Int
  1812. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  1813. If button = 3 Then ' right mouse button
  1814. PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,Int(x),Int(y))
  1815. Return True
  1816. End If
  1817. Return False
  1818. End Function
  1819. Method toString:String()
  1820. Return "TGTKTextField"
  1821. End Method
  1822. End Type
  1823. Rem
  1824. bbdoc: A base for list gadgets.
  1825. End Rem
  1826. Type TGTKList Extends TGTKGadget
  1827. Field icons:TGTKIconStrip
  1828. Field _store:Byte Ptr
  1829. Field _selection:Byte Ptr
  1830. ' sometimes we need to ignore events because we made them ourselves - rather than the user selecting
  1831. ' something.
  1832. Field ignoreListChangeEvent:Int
  1833. Method SetIconStrip:Int(iconstrip:TIconStrip)
  1834. icons = TGTKIconStrip(iconstrip)
  1835. End Method
  1836. Method populateListRow(index:Int, text:String, tip:String, icon:Int, iter:Byte Ptr)
  1837. ' need to put the string in a GValue for placing into the list
  1838. Local _value:Byte Ptr = bmx_gtk3_gvalue_new(G_TYPE_STRING)
  1839. 'g_value_init(_value, G_TYPE_STRING)
  1840. Local textPtr:Byte Ptr = text.ToUTF8String()
  1841. g_value_set_string(_value, textPtr)
  1842. MemFree(textPtr)
  1843. ' set the row value
  1844. If TGTKListbox(Self) Or TGTKComboBox(Self) Then
  1845. gtk_list_store_set_value(_store, iter, 1, _value)
  1846. Else
  1847. gtk_tree_store_set_value(_store, iter, 1, _value)
  1848. End If
  1849. ' tidy up !
  1850. g_value_unset(_value)
  1851. Local image:Byte Ptr
  1852. If icons And icon>=0 Then
  1853. image = icons.images[icon]
  1854. End If
  1855. If image Then
  1856. ' Insert the appropriate icon
  1857. g_value_init(_value, gdk_pixbuf_get_type())
  1858. g_value_set_object(_value, image)
  1859. ' set the row value
  1860. If TGTKListbox(Self) Or TGTKComboBox(Self) Then
  1861. gtk_list_store_set_value(_store, iter, 0, _value)
  1862. Else
  1863. gtk_tree_store_set_value(_store, iter, 0, _value)
  1864. End If
  1865. ' tidy up !
  1866. g_value_unset(_value)
  1867. Else
  1868. ' clear out an icon if one is present in this entry
  1869. g_value_init(_value, gdk_pixbuf_get_type())
  1870. g_value_set_object(_value, Null)
  1871. ' set the row value
  1872. If TGTKListbox(Self) Or TGTKComboBox(Self) Then
  1873. gtk_list_store_set_value(_store, iter, 0, _value)
  1874. Else
  1875. gtk_tree_store_set_value(_store, iter, 0, _value)
  1876. End If
  1877. ' tidy up !
  1878. g_value_unset(_value)
  1879. End If
  1880. bmx_gtk3_gvalue_free(_value)
  1881. End Method
  1882. Method initColumns()
  1883. ' add a column to the list :
  1884. Local col:Byte Ptr = gtk_tree_view_column_new()
  1885. ' pack column into list
  1886. gtk_tree_view_append_column(handle, col)
  1887. Local pixRenderer:Byte Ptr = gtk_cell_renderer_pixbuf_new()
  1888. Local textRenderer:Byte Ptr = gtk_cell_renderer_text_new()
  1889. ' pack cell renderers into column
  1890. gtk_tree_view_column_pack_start(col, pixRenderer, False)
  1891. gtk_tree_view_column_pack_end(col, textRenderer, True)
  1892. gtk_tree_view_column_add_attribute(col, pixRenderer, "pixbuf", 0)
  1893. gtk_tree_view_column_add_attribute(col, textRenderer, "text", 1)
  1894. End Method
  1895. Function OnSelectionChanged(_sel:Byte Ptr, obj:Object) Abstract
  1896. End Type
  1897. Rem
  1898. bbdoc: A combo box
  1899. End Rem
  1900. Type TGTKComboBox Extends TGTKList
  1901. Field isEditable:Int
  1902. Function CreateComboBox:TGTKComboBox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  1903. Local this:TGTKComboBox = New TGTKComboBox
  1904. this.initComboBox(x, y, w, h, label, group, style)
  1905. Return this
  1906. End Function
  1907. Method initComboBox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  1908. If style = COMBOBOX_EDITABLE Then
  1909. isEditable = True
  1910. handle = gtk_combo_box_new_with_entry()
  1911. Else
  1912. handle = gtk_combo_box_new()
  1913. End If
  1914. Init(GTK_COMBOBOX, x, y, w, h, style)
  1915. ' Create a list store of pixbuf and string (the two displayable columns)
  1916. _store = gtk_list_store_new(2, gdk_pixbuf_get_type(), G_TYPE_STRING)
  1917. gtk_combo_box_set_model(handle, _store)
  1918. ' for editable, we need to tell it which column contains the text part
  1919. If isEditable Then
  1920. gtk_combo_box_set_entry_text_column(handle, 1)
  1921. End If
  1922. initColumns()
  1923. setShow(True)
  1924. gtk_layout_put(TGTKContainer(group).container, handle, x, y)
  1925. gtk_widget_set_size_request(handle, w, Max(h,0))
  1926. addConnection("changed", g_signal_cb2(handle, "changed", OnSelectionChanged, Self, Destroy, 0))
  1927. ' catch right-mouse buttons
  1928. addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
  1929. End Method
  1930. Method initColumns()
  1931. gtk_cell_layout_clear(handle)
  1932. Local pixRenderer:Byte Ptr = gtk_cell_renderer_pixbuf_new()
  1933. Local textRenderer:Byte Ptr = gtk_cell_renderer_text_new()
  1934. ' pack cell renderers into layout
  1935. gtk_cell_layout_pack_start(handle, pixRenderer, False)
  1936. gtk_cell_layout_pack_end(handle, textRenderer, True)
  1937. gtk_cell_layout_add_attribute(handle, pixRenderer, "pixbuf", 0)
  1938. gtk_cell_layout_add_attribute(handle, textRenderer, "text", 1)
  1939. End Method
  1940. Rem
  1941. bbdoc: Callback for selection change.
  1942. End Rem
  1943. Function OnSelectionChanged(widget:Byte Ptr, obj:Object)
  1944. Local row:Int = TGTKComboBox(obj).SelectedItem()
  1945. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), row,,,,TGadget(obj).ItemExtra(row))
  1946. End Function
  1947. Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  1948. Local x:Double, y:Double, button:Int
  1949. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  1950. If button = 3 Then ' right mouse button
  1951. Local treePath:Byte Ptr
  1952. Local row:Int = TGTKComboBox(obj).SelectedItem()
  1953. If row >= 0 Then
  1954. PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,Int(x),Int(y),TGTKList(obj).items[row].extra)
  1955. Else
  1956. PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,Int(x),Int(y))
  1957. End If
  1958. Return True
  1959. End If
  1960. Return False
  1961. End Function
  1962. Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
  1963. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  1964. gtk_list_store_insert(_store, iter, index)
  1965. populateListRow(index, text, tip, icon, iter)
  1966. bmx_gtk3_gtktreeiter_free(iter)
  1967. End Method
  1968. Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
  1969. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  1970. Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
  1971. If found Then
  1972. populateListRow(index, text, tip, icon, iter)
  1973. End If
  1974. bmx_gtk3_gtktreeiter_free(iter)
  1975. End Method
  1976. Method SelectedItem:Int()
  1977. Return gtk_combo_box_get_active(handle)
  1978. End Method
  1979. Method SetListItemState:Int(index:Int ,state:Int)
  1980. If state & STATE_SELECTED Then
  1981. gtk_combo_box_set_active(handle, index)
  1982. End If
  1983. End Method
  1984. Method ClearListItems:Int()
  1985. gtk_list_store_clear(_store)
  1986. End Method
  1987. Method RemoveListItem:Int(index:Int)
  1988. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  1989. Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
  1990. If found Then
  1991. gtk_list_store_remove(_store, iter)
  1992. End If
  1993. bmx_gtk3_gtktreeiter_free(iter)
  1994. End Method
  1995. Method ItemText:String(index:Int)
  1996. If index < 0 Or index >= items.length Then
  1997. Return GetText()
  1998. End If
  1999. Return items[index].text
  2000. End Method
  2001. Method GetText:String()
  2002. Local st:String
  2003. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  2004. Local found:Int = gtk_combo_box_get_active_iter(handle, iter)
  2005. If found Then
  2006. Local _value:Byte Ptr = bmx_gtk3_gvalue_new(G_TYPE_STRING)
  2007. gtk_tree_model_get_value(_store, iter, 0, _value)
  2008. st = String.FromUTF8String(g_value_get_string(_value))
  2009. ' tidy up !
  2010. g_value_unset(_value)
  2011. bmx_gtk3_gvalue_free(_value)
  2012. End If
  2013. Return st
  2014. End Method
  2015. Method free:Int() Override
  2016. Super.Free()
  2017. If handle
  2018. gtk_widget_destroy(handle)
  2019. EndIf
  2020. handle = Null
  2021. End Method
  2022. Method toString:String()
  2023. Return "TGTKComboBox"
  2024. End Method
  2025. End Type
  2026. Rem
  2027. bbdoc: A scrollable list.
  2028. End Rem
  2029. Type TGTKListWithScrollWindow Extends TGTKList
  2030. Field scrollWindow:Byte Ptr
  2031. Method Init(GadgetClass:Int, x:Int, y:Int, w:Int, h:Int, style:Int)
  2032. Super.init(iclass, x, y, w, h, style)
  2033. handle = gtk_tree_view_new()
  2034. gtk_tree_view_set_headers_visible(handle, False)
  2035. ' a reference to the selection object
  2036. _selection = gtk_tree_view_get_selection(handle)
  2037. ' currently we only support SINGLE row selection
  2038. gtk_tree_selection_set_mode(_selection, GTK_SELECTION_SINGLE)
  2039. scrollWindow = gtk_scrolled_window_new(Null, Null)
  2040. ' set container resize mode
  2041. gtk_container_set_resize_mode(scrollWindow, GTK_RESIZE_QUEUE)
  2042. ' set scrollbar policy
  2043. gtk_scrolled_window_set_policy(scrollWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC)
  2044. ' show
  2045. gtk_widget_show(scrollWindow)
  2046. ' add the html view to the scroll view
  2047. gtk_container_add(scrollWindow, handle)
  2048. ' add callback
  2049. addConnection("changed", g_signal_cb2(_selection, "changed", OnSelectionChanged, Self, Destroy, 0))
  2050. ' catch right-mouse buttons
  2051. addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
  2052. End Method
  2053. Method SetShow:Int(truefalse:Int)
  2054. visible = truefalse
  2055. mySetVisible = visible
  2056. If truefalse Then
  2057. gtk_widget_show(scrollWindow)
  2058. gtk_widget_show(handle)
  2059. Else
  2060. gtk_widget_hide(scrollWindow)
  2061. gtk_widget_hide(handle)
  2062. EndIf
  2063. UpdateChildVisibility()
  2064. End Method
  2065. Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  2066. End Function
  2067. End Type
  2068. Rem
  2069. bbdoc: List box
  2070. End Rem
  2071. Type TGTKListbox Extends TGTKListWithScrollWindow
  2072. Field currentSelection:Int = -1
  2073. Function CreateListBox:TGTKListbox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2074. Local this:TGTKListbox = New TGTKListbox
  2075. this.initListBox(x, y, w, h, label, group, style)
  2076. Return this
  2077. End Function
  2078. Method initListBox(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2079. Init(GTK_LISTBOX, x, y, w, h, style)
  2080. ' had intended using GTK_TYPE_PIXBUF here but it's a different value every time!?!
  2081. _store = gtk_list_store_new(2, gdk_pixbuf_get_type(), G_TYPE_STRING)
  2082. initColumns()
  2083. gtk_tree_view_set_model(handle, _store)
  2084. ' remove *our* reference to the store... when the list is destroyed this will be too
  2085. g_object_unref(_store)
  2086. addConnection("row-activated", g_signal_cb4(handle, "row-activated", OnRowActivated, Self, Destroy, 0))
  2087. SetShow(True)
  2088. gtk_layout_put(TGTKContainer(group).container, scrollwindow, x, y)
  2089. gtk_widget_set_size_request(handle, w, Max(h,0))
  2090. End Method
  2091. Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, extra:Object)
  2092. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  2093. gtk_list_store_insert(_store, iter, index)
  2094. populateListRow(index, text, tip, icon, iter)
  2095. bmx_gtk3_gtktreeiter_free(iter)
  2096. End Method
  2097. Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
  2098. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  2099. Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
  2100. If found Then
  2101. populateListRow(index, text, tip, icon, iter)
  2102. End If
  2103. bmx_gtk3_gtktreeiter_free(iter)
  2104. End Method
  2105. Rem
  2106. bbdoc: Removes an item from the list at the given index
  2107. End Rem
  2108. Method RemoveListItem:Int(index:Int)
  2109. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  2110. Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
  2111. If found Then
  2112. If gtk_tree_selection_iter_is_selected(_selection, iter) Then
  2113. ignoreListChangeEvent = True
  2114. End If
  2115. gtk_list_store_remove(_store, iter)
  2116. End If
  2117. bmx_gtk3_gtktreeiter_free(iter)
  2118. End Method
  2119. Method SetListItemState:Int(index:Int, state:Int)
  2120. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  2121. Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
  2122. If found Then
  2123. If state & STATE_SELECTED Then
  2124. ignoreListChangeEvent = True
  2125. gtk_tree_selection_select_iter(_selection, iter)
  2126. Else
  2127. If gtk_tree_selection_iter_is_selected(_selection, iter) Then
  2128. ignoreListChangeEvent = True
  2129. End If
  2130. gtk_tree_selection_unselect_iter(_selection, iter)
  2131. End If
  2132. End If
  2133. bmx_gtk3_gtktreeiter_free(iter)
  2134. End Method
  2135. Method ListItemState:Int(index:Int)
  2136. Local state:Int = 0
  2137. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  2138. Local found:Int = gtk_tree_model_iter_nth_child(_store, iter, Null, index)
  2139. If found Then
  2140. If gtk_tree_selection_iter_is_selected(_selection, iter) Then
  2141. state:| STATE_SELECTED
  2142. End If
  2143. End If
  2144. bmx_gtk3_gtktreeiter_free(iter)
  2145. Return state
  2146. End Method
  2147. Function OnSelectionChanged(_sel:Byte Ptr, obj:Object)
  2148. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  2149. Local row:Int = -1
  2150. Local selected:Int = gtk_tree_selection_get_selected(_sel, Null, iter)
  2151. If selected Then
  2152. Local path:Byte Ptr = gtk_tree_model_get_string_from_iter(TGTKList(obj)._store, iter)
  2153. row = String.fromCString(path).toInt()
  2154. g_free(path)
  2155. End If
  2156. If TGTKListbox(obj).currentSelection <> row Then
  2157. TGTKListbox(obj).currentSelection = row
  2158. If Not TGTKList(obj).ignoreListChangeEvent Then
  2159. PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj), row,,,,TGadget(obj).ItemExtra(row))
  2160. End If
  2161. End If
  2162. TGTKList(obj).ignoreListChangeEvent = False
  2163. bmx_gtk3_gtktreeiter_free(iter)
  2164. End Function
  2165. Rem
  2166. bbdoc: Callback for listbox activation (double-click).
  2167. End Rem
  2168. Function OnRowActivated(widget:Byte Ptr, treePath:Byte Ptr, treeviewColumn:Byte Ptr, obj:Object)
  2169. Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
  2170. Local row:Int
  2171. If p <> Null Then
  2172. row = String.fromCString(p).toInt()
  2173. End If
  2174. ' clean up mem
  2175. g_free(p)
  2176. If row >= 0 Then
  2177. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj),row ,,,,TGTKList(obj).items[row].extra)
  2178. Else
  2179. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), row)
  2180. End If
  2181. End Function
  2182. Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  2183. Local x:Double, y:Double, button:Int
  2184. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  2185. If button = 3 Then ' right mouse button
  2186. Local treePath:Byte Ptr
  2187. Local row:Int = -1
  2188. ' Get tree path For row that was clicked
  2189. If gtk_tree_view_get_path_at_pos(widget, Int(x), Int(y), Varptr treePath, Null, Null, Null) Then
  2190. Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
  2191. If p <> Null Then
  2192. row = String.fromCString(p).toInt()
  2193. End If
  2194. ' clean up mem
  2195. g_free(p)
  2196. gtk_tree_path_free(treePath)
  2197. End If
  2198. If row >= 0 Then
  2199. PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,Int(x),Int(y),TGTKList(obj).items[row].extra)
  2200. Else
  2201. PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),row,,Int(x),Int(y))
  2202. End If
  2203. Return True
  2204. End If
  2205. Return False
  2206. End Function
  2207. Method ClearListItems:Int()
  2208. If gtk_tree_selection_get_selected(_selection, Null, Null) Then
  2209. ignoreListChangeEvent = True
  2210. End If
  2211. gtk_list_store_clear(_store)
  2212. End Method
  2213. Method rethink:Int()
  2214. If handle Then
  2215. gtk_layout_move(TGTKContainer(parent).container, scrollwindow, Max(xpos, 0), Max(ypos, 0))
  2216. gtk_widget_set_size_request(scrollwindow, Max(width,0), Max(height,0))
  2217. End If
  2218. End Method
  2219. Method free:Int() Override
  2220. Super.free()
  2221. ' destroying the widget should destroy the handle (list) too.
  2222. If scrollWindow Then
  2223. gtk_widget_destroy(scrollWindow)
  2224. End If
  2225. scrollWindow = Null
  2226. handle = Null
  2227. End Method
  2228. Method toString:String()
  2229. Return "TGTKListbox"
  2230. End Method
  2231. End Type
  2232. Rem
  2233. bbdoc: A node in the tree view.
  2234. End Rem
  2235. Type TGTKTreeViewNode Extends TGTKListWithScrollWindow
  2236. ' is this node the root node?
  2237. Field isRoot:Int
  2238. ' internal representation of node position in the tree
  2239. Field _path:String
  2240. ' direct access to the node in the tree
  2241. Field myIter:Byte Ptr
  2242. ' icon to display for this node
  2243. Field _icon:Int
  2244. ' flag to prevent non-user events from firing
  2245. Field ignoreExpand:Int
  2246. Field ignoreCollapse:Int
  2247. ' text of this node
  2248. Field _text:String
  2249. Function _createNode:TGTKTreeViewNode(parent:TGTKTreeViewNode, index:Int)
  2250. Local this:TGTKTreeViewNode = New TGTKTreeViewNode
  2251. this.kids = New TEList
  2252. this.handle = parent.handle
  2253. this._store = parent._store
  2254. this._selection = parent._selection
  2255. this.parent = parent
  2256. this.icons = parent.icons
  2257. this.myIter = bmx_gtk3_gtktreeiter_new()
  2258. this.refreshPath(index)
  2259. Return this
  2260. End Function
  2261. Method refreshPath(index:Int)
  2262. Assert myIter, "Null Iterator!"
  2263. If parent Then
  2264. _path = TGTKTreeViewNode(parent)._path
  2265. If TGTKTreeViewNode(parent)._path.length > 0 Then
  2266. _path:+ ":"
  2267. End If
  2268. Else
  2269. _path = ""
  2270. End If
  2271. _path:+ index
  2272. gtk_tree_model_get_iter_from_string(_store, myIter, _path)
  2273. End Method
  2274. Method refreshChildPaths()
  2275. Local i:Int = 0
  2276. For Local child:TGTKTreeViewNode = EachIn kids
  2277. child.refreshPath(i)
  2278. child.refreshChildPaths()
  2279. i:+ 1
  2280. Next
  2281. End Method
  2282. Function OnSelectionChanged(_sel:Byte Ptr, obj:Object)
  2283. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  2284. Local node:TGTKTreeViewNode = Null
  2285. Local selected:Int = gtk_tree_selection_get_selected(_sel, Null, iter)
  2286. If selected Then
  2287. Local p:Byte Ptr = gtk_tree_model_get_string_from_iter(TGTKList(obj)._store, iter)
  2288. node = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
  2289. g_free(p)
  2290. End If
  2291. If Not TGTKList(obj).ignoreListChangeEvent Then
  2292. PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj),,,,,node)
  2293. End If
  2294. TGTKList(obj).ignoreListChangeEvent = False
  2295. bmx_gtk3_gtktreeiter_free(iter)
  2296. End Function
  2297. Rem
  2298. bbdoc: Returns the root node for this tree
  2299. End Rem
  2300. Method RootNode:TGadget()
  2301. If Not isRoot Then
  2302. Return parent.RootNode()
  2303. End If
  2304. Return Self
  2305. End Method
  2306. Rem
  2307. bbdoc: Inserts a new node as a child at the specified index.
  2308. End Rem
  2309. Method InsertNode:TGadget(index:Int, text:String, icon:Int)
  2310. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  2311. Local childNode:TGTKTreeViewNode
  2312. ' create a new row in the tree
  2313. If isRoot Then
  2314. If index < 0 Then
  2315. gtk_tree_store_append(_store, iter, Null)
  2316. Else
  2317. gtk_tree_store_insert(_store, iter, Null, index)
  2318. End If
  2319. Else
  2320. If index < 0 Then
  2321. gtk_tree_store_append(_store, iter, myIter)
  2322. Else
  2323. gtk_tree_store_insert(_store, iter, myIter, index)
  2324. End If
  2325. End If
  2326. ' add the text / icon to the tree
  2327. populateListRow(index, text, Null, icon, iter)
  2328. ' add the child to the parent kids
  2329. If index < 0 Or index = CountKids() Then
  2330. childNode = TGTKTreeViewNode._createNode(Self, CountKids())
  2331. childNode._text = text
  2332. kids.addLast(childNode)
  2333. Else
  2334. childNode = TGTKTreeViewNode._createNode(Self, index)
  2335. childNode._text = text
  2336. TEList(kids).insertElementAt(childNode, index)
  2337. refreshChildPaths()
  2338. End If
  2339. childNode._icon = icon
  2340. If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
  2341. LocalizeGadget(childNode, text)
  2342. Else
  2343. childNode.SetText(text)
  2344. EndIf
  2345. bmx_gtk3_gtktreeiter_free(iter)
  2346. Return childNode
  2347. End Method
  2348. Rem
  2349. bbdoc: Changes the tree node text and icon
  2350. End Rem
  2351. Method ModifyNode:Int(text:String, icon:Int)
  2352. ' not allowed to modify the root node... quietly ignore the request.
  2353. If isRoot Then
  2354. Return 0
  2355. End If
  2356. _text = text
  2357. populateListRow(-1, text, Null, icon, myIter)
  2358. End Method
  2359. Rem
  2360. bbdoc: Returns the currently selected tree node or null if none selected
  2361. End Rem
  2362. Method SelectedNode:TGadget()
  2363. Local iter:Byte Ptr = bmx_gtk3_gtktreeiter_new()
  2364. If gtk_tree_selection_get_selected(_selection, Null, iter) Then
  2365. Local path:Byte Ptr = gtk_tree_model_get_path(_store, iter)
  2366. Local p:Byte Ptr = gtk_tree_path_to_string(path)
  2367. Local node:TGTKTreeViewNode = findNodeFromPath(String.FromCString(p))
  2368. g_free(p)
  2369. gtk_tree_path_free(path)
  2370. bmx_gtk3_gtktreeiter_free(iter)
  2371. Return node
  2372. End If
  2373. bmx_gtk3_gtktreeiter_free(iter)
  2374. Return Null
  2375. End Method
  2376. Rem
  2377. bbdoc: Returns the number of child nodes
  2378. End Rem
  2379. Method CountKids:Int()
  2380. Return kids.count()
  2381. End Method
  2382. Method free:Int() Override
  2383. Super.free()
  2384. If isRoot Then
  2385. If scrollWindow Then
  2386. gtk_widget_destroy(scrollWindow)
  2387. End If
  2388. scrollWindow = Null
  2389. handle = Null
  2390. Else
  2391. ' this should always be true... if not, we really want to throw an assertion.
  2392. ' Assert myIter, "Trying to Free() a node twice?"
  2393. If myIter Then
  2394. gtk_tree_store_remove(_store, myIter)
  2395. bmx_gtk3_gtktreeiter_free(myIter)
  2396. myIter = Null
  2397. If parent Then
  2398. TGTKTreeViewNode(parent).refreshChildPaths()
  2399. End If
  2400. End If
  2401. End If
  2402. End Method
  2403. ' search always begins from the tree root, so we only need to look through the
  2404. ' children.. ie. downwards
  2405. ' TODO : make this more efficient... we should be able to use the path to skip
  2406. ' searching of child nodes of nodes not in our path
  2407. Method findNodeFromPath:TGTKTreeViewNode(lookup:String)
  2408. If lookup = _path Then
  2409. Return Self
  2410. End If
  2411. Local i:Int = 0
  2412. For Local child:TGTKTreeViewNode = EachIn kids
  2413. Local node:TGTKTreeViewNode = child.findNodeFromPath(lookup)
  2414. If node Then
  2415. Return node
  2416. End If
  2417. Next
  2418. Return Null
  2419. End Method
  2420. Method Activate:Int(command:Int)
  2421. Super.Activate(command)
  2422. Select command
  2423. Case ACTIVATE_EXPAND
  2424. If _path <> Null And _path.length > 0 Then
  2425. ignoreExpand = True
  2426. ' get the tree view
  2427. Local _root:TGTKTreeViewNode = TGTKTreeViewNode(RootNode())
  2428. ' get this node path
  2429. Local path:Byte Ptr = gtk_tree_path_new_from_string(_path)
  2430. ' expand the node
  2431. gtk_tree_view_expand_row(_root.handle, path, False)
  2432. ' free stuff
  2433. gtk_tree_path_free(path)
  2434. End If
  2435. Case ACTIVATE_COLLAPSE
  2436. If _path <> Null And _path.length > 0 Then
  2437. ignoreCollapse = True
  2438. ' get the tree view
  2439. Local _root:TGTKTreeViewNode = TGTKTreeViewNode(RootNode())
  2440. ' get this node path
  2441. Local path:Byte Ptr = gtk_tree_path_new_from_string(_path)
  2442. ' expand the node
  2443. gtk_tree_view_collapse_row(_root.handle, path)
  2444. ' free stuff
  2445. gtk_tree_path_free(path)
  2446. End If
  2447. Case ACTIVATE_SELECT
  2448. If _path <> Null And _path.length > 0 Then
  2449. ' the tree view should ignore this selection...
  2450. TGTKTreeViewNode(RootNode()).ignoreListChangeEvent = True
  2451. ' get this node path
  2452. Local path:Byte Ptr = gtk_tree_path_new_from_string(_path)
  2453. ' set the new selection
  2454. gtk_tree_selection_select_path(_selection, path)
  2455. ' free stuff
  2456. gtk_tree_path_free(path)
  2457. End If
  2458. End Select
  2459. End Method
  2460. Rem
  2461. bbdoc: Returns the text for this node.
  2462. End Rem
  2463. Method GetText:String()
  2464. Return _text
  2465. End Method
  2466. Rem
  2467. bbdoc: Sets the text for this node.
  2468. End Rem
  2469. Method SetText:Int(text:String)
  2470. ModifyNode(text, _icon)
  2471. End Method
  2472. Method toString:String()
  2473. Return "TGTKTreeViewNode : " + _text + " : " + Super.ToString()
  2474. End Method
  2475. End Type
  2476. Rem
  2477. bbdoc: A tree view.
  2478. End Rem
  2479. Type TGTKTreeView Extends TGTKTreeViewNode
  2480. Function CreateTreeView:TGTKTreeView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2481. Local this:TGTKTreeView = New TGTKTreeView
  2482. this.initTreeView(x, y, w, h, label, group, style)
  2483. Return this
  2484. End Function
  2485. Method initTreeView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2486. Init(GTK_TREEVIEW, x, y, w, h, style)
  2487. ignoreListChangeEvent = True
  2488. kids = New TEList
  2489. ' create the tree store
  2490. _store = gtk_tree_store_new(2, gdk_pixbuf_get_type(), G_TYPE_STRING)
  2491. ' set up the column contents
  2492. initColumns()
  2493. ' attach store to the view
  2494. gtk_tree_view_set_model(handle, _store)
  2495. ' remove *our* reference to the store... when the tree is destroyed this will be too
  2496. g_object_unref(_store)
  2497. SetShow(True)
  2498. gtk_layout_put(TGTKContainer(group).container, scrollwindow, x, y)
  2499. gtk_widget_set_size_request(handle, w, Max(h,0))
  2500. addConnection("row-activated", g_signal_cb4(handle, "row-activated", OnRowActivated, Self, Destroy, 0))
  2501. addConnection("row-expanded", g_signal_cb4(handle, "row-expanded", OnRowExpanded, Self, Destroy, 0))
  2502. addConnection("row-collapsed", g_signal_cb4(handle, "row-collapsed", OnRowCollapsed, Self, Destroy, 0))
  2503. isRoot = True
  2504. End Method
  2505. Rem
  2506. bbdoc: Callback For tree-view node activation (Double-click).
  2507. End Rem
  2508. Function OnRowActivated(widget:Byte Ptr, treePath:Byte Ptr, treeviewColumn:Byte Ptr, obj:Object)
  2509. Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
  2510. Local node:TGTKTreeViewNode = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
  2511. ' clean up mem
  2512. g_free(p)
  2513. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj),,,,,node)
  2514. End Function
  2515. Rem
  2516. bbdoc: Callback for tree-view node expand.
  2517. End Rem
  2518. Function OnRowExpanded(widget:Byte Ptr, treeIter:Byte Ptr, treePath:Byte Ptr, obj:Object)
  2519. Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
  2520. Local node:TGTKTreeViewNode = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
  2521. ' clean up mem
  2522. g_free(p)
  2523. If Not node.ignoreExpand Then
  2524. PostGuiEvent(EVENT_GADGETOPEN, TGadget(obj),,,,,node)
  2525. End If
  2526. node.ignoreExpand = False
  2527. End Function
  2528. Rem
  2529. bbdoc: Callback for tree-view node collapse.
  2530. End Rem
  2531. Function OnRowCollapsed(widget:Byte Ptr, treeIter:Byte Ptr, treePath:Byte Ptr, obj:Object)
  2532. Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
  2533. Local node:TGTKTreeViewNode = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
  2534. ' clean up mem
  2535. g_free(p)
  2536. If Not node.ignoreCollapse Then
  2537. PostGuiEvent(EVENT_GADGETCLOSE, TGadget(obj),,,,,node)
  2538. End If
  2539. node.ignoreCollapse = False
  2540. End Function
  2541. Rem
  2542. bbdoc: Callback for mouse right-click
  2543. End Rem
  2544. Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  2545. Local x:Double, y:Double, button:Int
  2546. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  2547. If button = 3 Then ' right mouse button
  2548. Local node:TGTKTreeViewNode
  2549. Local treePath:Byte Ptr
  2550. ' Get tree path For row that was clicked
  2551. If gtk_tree_view_get_path_at_pos(widget, Int(x), Int(y), Varptr treePath, Null, Null, Null) Then
  2552. Local p:Byte Ptr = gtk_tree_path_to_string(treePath)
  2553. node = TGTKTreeViewNode(obj).findNodeFromPath(String.FromCString(p))
  2554. ' clean up mem
  2555. g_free(p)
  2556. gtk_tree_path_free(treePath)
  2557. End If
  2558. PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,Int(x),Int(y),node)
  2559. Return True
  2560. End If
  2561. Return False
  2562. End Function
  2563. ' overriden - does nothing!!
  2564. Method LayoutKids:Int()
  2565. End Method
  2566. Method rethink:Int()
  2567. If handle Then
  2568. gtk_layout_move(TGTKContainer(parent).container, scrollwindow, Max(xpos, 0), Max(ypos, 0))
  2569. gtk_widget_set_size_request(scrollwindow, Max(width,0), Max(height,0))
  2570. End If
  2571. End Method
  2572. Method toString:String()
  2573. Return "TGTKTreeView"
  2574. End Method
  2575. End Type
  2576. Rem
  2577. bbdoc: A base-type for handling slider / range gadgets - ScrollBar and TrackBar
  2578. End Rem
  2579. Type TGTKRange Extends TGTKGadget
  2580. Field currentValue:Int
  2581. Field rangeMin:Int
  2582. Field rangeMax:Int
  2583. Rem
  2584. bbdoc: Sets the slider range.
  2585. End Rem
  2586. Method SetRange:Int(visible:Int, total:Int)
  2587. rangeMin = Min(visible, total)
  2588. rangeMax = Max(visible, total)
  2589. gtk_range_set_range(handle, rangeMin, rangeMax)
  2590. End Method
  2591. Rem
  2592. bbdoc: Sets the value on the slider.
  2593. End Rem
  2594. Method SetProp:Int(value:Int)
  2595. currentValue = value
  2596. gtk_range_set_value(handle, value)
  2597. End Method
  2598. Rem
  2599. bbdoc: Returns the current slider value.
  2600. End Rem
  2601. Method GetProp:Int()
  2602. Return gtk_range_get_value(handle)
  2603. End Method
  2604. Rem
  2605. bbdoc: Callback for user changing of a slider.
  2606. about: Tries to keep the value within the desired range.
  2607. End Rem
  2608. Function OnChangeValue:Int(widget:Byte Ptr, scrolltype:Int, value:Double, obj:Object)
  2609. Local v:Int = Max(Min(value, TGTKRange(obj).rangeMax), TGTKRange(obj).rangeMin)
  2610. If v <> TGTKRange(obj).currentValue Then
  2611. TGTKRange(obj).currentValue = v
  2612. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), v)
  2613. End If
  2614. Return False
  2615. End Function
  2616. Method free:Int() Override
  2617. Super.Free()
  2618. If handle
  2619. gtk_widget_destroy(handle)
  2620. EndIf
  2621. handle = Null
  2622. End Method
  2623. Method toString:String()
  2624. Return "TGTKRange"
  2625. End Method
  2626. End Type
  2627. Rem
  2628. bbdoc: A scrollbar
  2629. End Rem
  2630. Type TGTKScrollBar Extends TGTKRange
  2631. Field thumbSize:Int
  2632. Field Range:Int
  2633. Field pageSize:Int
  2634. Function CreateScrollBar:TGTKScrollBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2635. Local this:TGTKScrollBar = New TGTKScrollBar
  2636. this.initScrollBar(x, y, w, h, label, group, style)
  2637. Return this
  2638. End Function
  2639. Method initScrollBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2640. If style & SLIDER_VERTICAL Then
  2641. handle = gtk_scrollbar_new(GTK_ORIENTATION_VERTICAL, Null)
  2642. Else
  2643. handle = gtk_scrollbar_new(GTK_ORIENTATION_HORIZONTAL, Null)
  2644. End If
  2645. Init(GTK_SCROLLBAR, x, y, w, h, style)
  2646. ' set the default range
  2647. SetRange(1, 10)
  2648. setShow(True)
  2649. addConnection("change-value", g_signal_cb4a(handle, "change-value", OnChangeValue, Self, Destroy, 0))
  2650. gtk_layout_put(TGTKContainer(group).container, handle, x, y)
  2651. gtk_widget_set_size_request(handle, w, Max(h,0))
  2652. gtk_range_set_round_digits(handle, 0)
  2653. End Method
  2654. Rem
  2655. bbdoc: Overrides the default...
  2656. End Rem
  2657. Method SetRange:Int(small:Int, big:Int)
  2658. Range = big - small
  2659. pageSize = small
  2660. If small <> 0 Then
  2661. thumbSize = big/small
  2662. thumbSize = range / thumbSize
  2663. Else
  2664. thumbSize = 1
  2665. End If
  2666. If Range = 0 Then
  2667. Range = 1
  2668. thumbSize = 1
  2669. End If
  2670. gtk_adjustment_set_page_size(gtk_range_get_adjustment(handle), thumbSize)
  2671. gtk_range_set_increments(handle, 1, pageSize)
  2672. gtk_range_set_range(handle, 0, Range)
  2673. gtk_range_set_value(handle, GetProp())
  2674. End Method
  2675. Function OnChangeValue:Int(widget:Byte Ptr, scrolltype:Int, value:Double, obj:Object)
  2676. Local v:Int = Min(TGTKScrollBar(obj).range, Max(value, 0))
  2677. If v <> TGTKRange(obj).currentValue Then
  2678. TGTKRange(obj).currentValue = v
  2679. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), v)
  2680. End If
  2681. Return False
  2682. End Function
  2683. Method toString:String()
  2684. Return "TGTKScrollBar"
  2685. End Method
  2686. End Type
  2687. Rem
  2688. bbdoc: A trackbar
  2689. End Rem
  2690. Type TGTKTrackBar Extends TGTKRange
  2691. Function CreateTrackBar:TGTKTrackBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2692. Local this:TGTKTrackBar = New TGTKTrackBar
  2693. this.initTrackBar(x, y, w, h, label, group, style)
  2694. Return this
  2695. End Function
  2696. Method initTrackBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2697. If style & SLIDER_VERTICAL Then
  2698. handle = gtk_scale_new_with_range(GTK_ORIENTATION_VERTICAL, 1, 10, 1)
  2699. Else
  2700. handle = gtk_scale_new_with_range(GTK_ORIENTATION_HORIZONTAL, 1, 10, 1)
  2701. End If
  2702. Init(GTK_TRACKBAR, x, y, w, h, style)
  2703. ' set the default range
  2704. SetRange(1,10)
  2705. gtk_scale_set_draw_value(handle, False)
  2706. setShow(True)
  2707. addConnection("change-value", g_signal_cb4a(handle, "change-value", OnChangeValue, Self, Destroy, 0))
  2708. gtk_layout_put(TGTKContainer(group).container, handle, x, y)
  2709. gtk_widget_set_size_request(handle, w, Max(h,0))
  2710. End Method
  2711. Method toString:String()
  2712. Return "TGTKTrackBar"
  2713. End Method
  2714. End Type
  2715. Type TGTKStepper Extends TGTKGadget
  2716. Function CreateStepper:TGTKStepper(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2717. Local this:TGTKStepper = New TGTKStepper
  2718. this.initStepper(x, y, w, h, label, group, style)
  2719. Return this
  2720. End Function
  2721. Method initStepper(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2722. handle = gtk_spin_button_new_with_range(1, 100, 1)
  2723. Init(GTK_STEPPER, x, y, w, h, style)
  2724. ' init range..
  2725. SetRange(1,100)
  2726. gtk_spin_button_set_increments(handle, 1, 10)
  2727. setShow(True)
  2728. addConnection("change-value", g_signal_cb3a_ret(handle, "change-value", OnChangeValue, Self, Destroy, 0))
  2729. gtk_layout_put(TGTKContainer(group).container, handle, x, y)
  2730. gtk_widget_set_size_request(handle, w, Max(h,0))
  2731. End Method
  2732. Rem
  2733. bbdoc: Sets the value on the slider.
  2734. End Rem
  2735. Method SetProp:Int(value:Int)
  2736. 'currentValue = value
  2737. gtk_spin_button_set_value(handle, value)
  2738. End Method
  2739. Rem
  2740. bbdoc: Returns the current slider value.
  2741. End Rem
  2742. Method GetProp:Int()
  2743. Return gtk_spin_button_get_value(handle)
  2744. End Method
  2745. Rem
  2746. bbdoc: Sets the slider range.
  2747. End Rem
  2748. Method SetRange:Int(visible:Int, total:Int)
  2749. Local rangeMin:Int = Min(visible, total)
  2750. Local rangeMax:Int = Max(visible, total)
  2751. gtk_spin_button_set_range(handle, rangeMin, rangeMax)
  2752. End Method
  2753. Function OnChangeValue:Int(widget:Byte Ptr, scrolltype:Int, obj:Object)
  2754. Local v:Int = gtk_spin_button_get_value(widget)
  2755. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), v)
  2756. Return False
  2757. End Function
  2758. Method toString:String()
  2759. Return "TGTKStepper"
  2760. End Method
  2761. End Type
  2762. Rem
  2763. bbdoc: A progress bar
  2764. about: Interestingly, although we can find out the current value, MaxGUI doesn't support it...
  2765. End Rem
  2766. Type TGTKProgressBar Extends TGTKGadget
  2767. Field ebox:Byte Ptr
  2768. Function CreateProgressBar:TGTKProgressBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2769. Local this:TGTKProgressBar = New TGTKProgressBar
  2770. this.initProgressBar(x, y, w, h, label, group, style)
  2771. Return this
  2772. End Function
  2773. Method initProgressBar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2774. handle = gtk_progress_bar_new()
  2775. Init(GTK_PROGRESSBAR, x, y, w, h, style)
  2776. ' required for tooltips functionality
  2777. gtk_widget_add_events(handle, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
  2778. setShow(True)
  2779. gtk_layout_put(TGTKContainer(group).container, handle, x, y)
  2780. gtk_widget_set_size_request(handle, w, Max(h,0))
  2781. End Method
  2782. Rem
  2783. bbdoc: Set the value of the progress bar.
  2784. End Rem
  2785. Method SetValue:Int(value:Float)
  2786. value = Min(Max(0, value), 1.0)
  2787. gtk_progress_bar_set_fraction(handle, value)
  2788. End Method
  2789. Rem
  2790. bbdoc: Get the current value of the progress bar
  2791. End Rem
  2792. Method GetValue:Float()
  2793. Return gtk_progress_bar_get_fraction(handle)
  2794. End Method
  2795. Method free:Int() Override
  2796. Super.Free()
  2797. If handle
  2798. gtk_widget_destroy(handle)
  2799. EndIf
  2800. handle = Null
  2801. End Method
  2802. Method toString:String()
  2803. Return "TGTKProgressBar"
  2804. End Method
  2805. End Type
  2806. Rem
  2807. bbdoc: A Toolbar
  2808. End Rem
  2809. Type TGTKToolbar Extends TGTKGadget
  2810. Field icons:TGTKIconStrip
  2811. Field toolitems:Byte Ptr[]
  2812. Function CreateToolBar:TGTKToolbar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2813. Local this:TGTKToolbar = New TGTKToolbar
  2814. this.initToolbar(x, y, w, h, label, group, style)
  2815. Return this
  2816. End Function
  2817. Method initToolbar(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2818. handle = gtk_toolbar_new()
  2819. Init(GTK_TOOLBAR, x, y, w, h, style)
  2820. If TGTKWindow(group) Then
  2821. TGTKWindow(group).addToolbar(Self)
  2822. End If
  2823. ' show icons only
  2824. gtk_toolbar_set_style(handle, GTK_TOOLBAR_ICONS)
  2825. gtk_widget_show(handle)
  2826. End Method
  2827. Method SetIconStrip:Int(iconstrip:TIconStrip)
  2828. icons = TGTKIconStrip(iconstrip)
  2829. End Method
  2830. Rem
  2831. bbdoc: Inserts an item at the specified index.
  2832. End Rem
  2833. Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, extra:Object)
  2834. Local image:Byte Ptr
  2835. If icons And icon>=0 Then
  2836. image = icons.images[icon]
  2837. End If
  2838. toolitems = toolitems[..toolitems.length+1]
  2839. For Local i:Int = toolitems.length - 2 To index Step -1
  2840. toolitems[i + 1] = toolitems[i]
  2841. Next
  2842. If image Then
  2843. Local imageWidget:Byte Ptr = gtk_image_new_from_pixbuf(image)
  2844. gtk_widget_show(imageWidget)
  2845. Local textPtr:Byte Ptr = text.ToUTF8String()
  2846. If items[index].flags = GADGETITEM_TOGGLE Then
  2847. toolitems[index] = gtk_toggle_tool_button_new()
  2848. gtk_tool_button_set_label(toolitems[index], textPtr)
  2849. gtk_tool_button_set_icon_name(toolitems[index], icons.names[icon])
  2850. addConnection("toggled", g_signal_cb2(toolitems[index], "toggled", OnToolItemToggled, Self, Destroy, 0))
  2851. Else
  2852. toolitems[index] = gtk_tool_button_new(Null, textPtr)
  2853. gtk_tool_button_set_label(toolitems[index], textPtr)
  2854. gtk_tool_button_set_icon_name(toolitems[index], icons.names[icon])
  2855. addConnection("clicked", g_signal_cb2(toolitems[index], "clicked", OnToolItemClicked, Self, Destroy, 0))
  2856. End If
  2857. MemFree(textPtr)
  2858. ' Add a tooltip
  2859. SetToolTipIndex(index, tip)
  2860. Else
  2861. ' no image? Then this is a separator!
  2862. toolitems[index] = gtk_separator_tool_item_new()
  2863. End If
  2864. gtk_widget_show(toolitems[index])
  2865. gtk_toolbar_insert(handle, toolitems[index], index)
  2866. End Method
  2867. Function OnToolItemToggled(widget:Byte Ptr, obj:Object)
  2868. Local index:Int = gtk_toolbar_get_item_index(TGTKToolbar(obj).handle, widget)
  2869. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), index, gtk_toggle_tool_button_get_active(widget))
  2870. End Function
  2871. Function OnToolItemClicked(widget:Byte Ptr, obj:Object)
  2872. Local index:Int = gtk_toolbar_get_item_index(TGTKToolbar(obj).handle, widget)
  2873. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), index)
  2874. End Function
  2875. Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, extra:Object)
  2876. If toolitems[index] Then
  2877. gtk_container_remove(handle, toolitems[index])
  2878. For Local i:Int = index Until toolitems.length - 1
  2879. toolitems[i] = toolitems[i + 1]
  2880. Next
  2881. toolitems = toolitems[..toolitems.length - 1]
  2882. End If
  2883. InsertListItem(index, text, tip, icon, extra)
  2884. End Method
  2885. Method SetToolTipIndex:Int(index:Int, tip:String)
  2886. ' Add a tooltip
  2887. If tip And tip.length > 0 Then
  2888. Local tipPtr:Byte Ptr = tip.ToUTF8String()
  2889. gtk_tool_item_set_tooltip_text(toolitems[index], tipPtr)
  2890. MemFree(tipPtr)
  2891. Else
  2892. gtk_tool_item_set_tooltip_text(toolitems[index], Null)
  2893. End If
  2894. End Method
  2895. Method SetListItemState:Int(item:Int, state:Int)
  2896. If state & STATE_DISABLED Then
  2897. gtk_widget_set_sensitive(toolitems[item], False)
  2898. Else
  2899. gtk_widget_set_sensitive(toolitems[item], True)
  2900. End If
  2901. If items[item].flags = GADGETITEM_TOGGLE Then
  2902. If state & STATE_SELECTED Then
  2903. gtk_toggle_tool_button_set_active(toolitems[item], True)
  2904. Else
  2905. gtk_toggle_tool_button_set_active(toolitems[item], False)
  2906. End If
  2907. End If
  2908. gtk_widget_queue_draw(handle)
  2909. End Method
  2910. Method ListItemState:Int(index:Int)
  2911. Local state:Int = 0
  2912. If Not gtk_widget_is_sensitive(toolitems[index]) Then
  2913. state:| STATE_DISABLED
  2914. End If
  2915. If items[index].flags = GADGETITEM_TOGGLE Then
  2916. If gtk_toggle_tool_button_get_active(toolitems[index]) Then
  2917. state:| STATE_SELECTED
  2918. End If
  2919. End If
  2920. Return state
  2921. End Method
  2922. Method RemoveListItem:Int(index:Int)
  2923. If toolitems[index] Then
  2924. gtk_container_remove(handle, toolitems[index])
  2925. For Local i:Int = index Until toolitems.length - 1
  2926. toolitems[i] = toolitems[i + 1]
  2927. Next
  2928. toolitems = toolitems[..toolitems.length - 1]
  2929. End If
  2930. End Method
  2931. Method rethink:Int()
  2932. End Method
  2933. Method free:Int() Override
  2934. Super.Free()
  2935. If handle
  2936. gtk_widget_destroy(handle)
  2937. ' assuming that destroying the toolbar will destroy
  2938. For Local i:Int = 0 Until toolitems.length
  2939. toolitems[i] = Null
  2940. Next
  2941. EndIf
  2942. handle = Null
  2943. End Method
  2944. Method toString:String()
  2945. Return "TGTKToolbar"
  2946. End Method
  2947. End Type
  2948. Rem
  2949. bbdoc: A tabber.
  2950. End Rem
  2951. Type TGTKTabber Extends TGTKContainer
  2952. Field icons:TGTKIconStrip
  2953. Field images:Byte Ptr[]
  2954. Field labels:Byte Ptr[]
  2955. Field pages:Byte Ptr[]
  2956. Field ignoreChange:Int
  2957. Field currentIndex:Int = -1
  2958. Function CreateTabber:TGTKTabber(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2959. Local this:TGTKTabber = New TGTKTabber
  2960. this.initTabber(x, y, w, h, label, group, style)
  2961. Return this
  2962. End Function
  2963. Method initTabber(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  2964. handle = gtk_notebook_new()
  2965. Init(GTK_TABBER, x, y, w, h, style)
  2966. container = gtk_layout_new(Null, Null)
  2967. gtk_widget_show(container)
  2968. g_object_ref(container) ' hold an extra ref for our container
  2969. ' Scrollable tabs if there are too many to fit on the display
  2970. gtk_notebook_set_scrollable(handle, True)
  2971. gtk_widget_show(handle)
  2972. g_signal_tabchange(handle, "switch-page", OnTabChanged, Self, Destroy, 0)
  2973. gtk_layout_put(TGTKContainer(group).container, handle, x, y)
  2974. gtk_widget_set_size_request(handle, w, Max(h,0))
  2975. End Method
  2976. Function OnTabChanged(widget:Byte Ptr, page:Byte Ptr, index:Int, obj:Object)
  2977. If TGTKTabber(obj).currentIndex >= 0 Then
  2978. Local child:Byte Ptr = gtk_notebook_get_nth_page(TGTKTabber(obj).handle, TGTKTabber(obj).currentIndex)
  2979. TGTKTabber(obj).RemoveFromTab(child)
  2980. End If
  2981. If index >= 0 Then
  2982. TGTKTabber(obj).AddToTab(page)
  2983. End If
  2984. TGTKTabber(obj).currentIndex = index
  2985. If Not TGTKTabber(obj).ignoreChange Then
  2986. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj), index,,,,TGadget(obj).ItemExtra(index))
  2987. End If
  2988. TGTKTabber(obj).ignoreChange = False
  2989. End Function
  2990. Rem
  2991. bbdoc: Inserts a new tab
  2992. End Rem
  2993. Method InsertListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
  2994. ' don't create gui events when inserting new pages.
  2995. ignoreChange = True
  2996. Local image:Byte Ptr
  2997. If icons And icon>=0 Then
  2998. image = icons.images[icon]
  2999. End If
  3000. images = images[..images.length+1]
  3001. For Local i:Int = images.length - 2 To index Step -1
  3002. images[i + 1] = images[i]
  3003. Next
  3004. labels = labels[..labels.length+1]
  3005. For Local i:Int = labels.length - 2 To index Step -1
  3006. labels[i + 1] = labels[i]
  3007. Next
  3008. pages = pages[..pages.length+1]
  3009. For Local i:Int = pages.length - 2 To index Step -1
  3010. pages[i + 1] = pages[i]
  3011. Next
  3012. If image Then
  3013. images[index] = gtk_image_new_from_pixbuf(image)
  3014. gtk_widget_show(images[index])
  3015. Else
  3016. images[index] = gtk_image_new()
  3017. End If
  3018. ' since a Label can't accept events, we wrap it inside an event box which can
  3019. Local box:Byte Ptr = gtk_event_box_new()
  3020. gtk_event_box_set_visible_window(box, False)
  3021. gtk_widget_add_events(box, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
  3022. ' show the box
  3023. gtk_widget_show(box)
  3024. ' create a display label for the tab
  3025. Local textPtr:Byte Ptr = text.ToUTF8String()
  3026. labels[index] = gtk_label_new(textPtr)
  3027. MemFree(textPtr)
  3028. gtk_widget_show(labels[index])
  3029. ' create a horizontal box to place the image/label combo
  3030. Local hbox:Byte Ptr = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 4)
  3031. gtk_widget_show(hbox)
  3032. ' add widgets to the hbox
  3033. gtk_box_pack_start(hbox, images[index], False, False, 0)
  3034. gtk_box_pack_start(hbox, labels[index], False, False, 0)
  3035. ' add the hbox to the eventbox
  3036. gtk_container_add(box, hbox)
  3037. ' create a child to hold our container.
  3038. Local child:Byte Ptr = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0)
  3039. pages[index] = child
  3040. gtk_widget_show(child)
  3041. gtk_notebook_insert_page(handle, child, box, index)
  3042. ' Add a tooltip to the event box
  3043. SetToolTipIndex(index, tip, box)
  3044. End Method
  3045. Method SetListItem:Int(index:Int, text:String, tip:String, icon:Int, tag:Object)
  3046. Local child:Byte Ptr = gtk_notebook_get_nth_page(handle, index)
  3047. ' get the event box to which we set tooltips
  3048. Local box:Byte Ptr = gtk_notebook_get_tab_label(handle, child)
  3049. ' is there an image to show?
  3050. Local image:Byte Ptr
  3051. If icons And icon>=0 Then
  3052. image = icons.images[icon]
  3053. End If
  3054. If Not image Then
  3055. ' hide image if none
  3056. gtk_widget_hide(images[index])
  3057. Else
  3058. ' set and display image
  3059. gtk_image_set_from_pixbuf(images[index], image)
  3060. gtk_widget_show(images[index])
  3061. End If
  3062. ' set new text
  3063. Local textPtr:Byte Ptr = text.ToUTF8String()
  3064. gtk_label_set_text(labels[index], textPtr)
  3065. MemFree(textPtr)
  3066. ' Add a tooltip to the event box
  3067. SetToolTipIndex(index, tip, box)
  3068. End Method
  3069. Method RemoveListItem:Int(index:Int)
  3070. Local arr:Byte Ptr[] = images
  3071. images = images[..images.length-1]
  3072. For Local i:Int = index To arr.length-2
  3073. images[i] = arr[i+1]
  3074. Next
  3075. arr = labels
  3076. labels = labels[..labels.length-1]
  3077. For Local i:Int = index To arr.length-2
  3078. labels[i] = arr[i+1]
  3079. Next
  3080. arr = pages
  3081. pages = pages[..pages.length-1]
  3082. For Local i:Int = index To arr.length-2
  3083. pages[i] = arr[i+1]
  3084. Next
  3085. ' remove from current tab if required
  3086. If gtk_notebook_get_current_page(handle) = index Then
  3087. Local child:Byte Ptr = gtk_notebook_get_nth_page(handle, index)
  3088. RemoveFromTab(child)
  3089. currentIndex = -1
  3090. Else If index < currentIndex Then
  3091. currentIndex :- 1
  3092. End If
  3093. gtk_notebook_remove_page(handle, index)
  3094. End Method
  3095. Method ListItemState:Int(index:Int)
  3096. Local state:Int = 0
  3097. If gtk_notebook_get_current_page(handle) = index Then
  3098. state:| STATE_SELECTED
  3099. End If
  3100. Return state
  3101. End Method
  3102. Method SetListItemState:Int(index:Int, state:Int)
  3103. If state & STATE_SELECTED Then
  3104. If gtk_notebook_get_current_page(handle) <> index Then
  3105. ignoreChange = True
  3106. ?bmxng
  3107. IWrappedSystemDriver(SystemDriver()).GetDriver().Poll()
  3108. ?Not bmxng
  3109. brl.System.Driver.Poll() ' update events
  3110. ?
  3111. gtk_notebook_set_current_page(handle, index)
  3112. End If
  3113. End If
  3114. End Method
  3115. Method ClientHeight:Int()
  3116. Local h:Int = height
  3117. If handle Then
  3118. ?bmxng
  3119. Local minReq:GtkRequisition
  3120. Local natReq:GtkRequisition
  3121. ?Not bmxng
  3122. Local minReq:GtkRequisition = New GtkRequisition
  3123. Local natReq:GtkRequisition = New GtkRequisition
  3124. ?
  3125. gtk_widget_get_preferred_size(handle, minReq, natReq)
  3126. h :- 34 ' FIXME : current hard-coded. Should be height of notebook less tab height and border.
  3127. End If
  3128. Return Max(0, h)
  3129. End Method
  3130. Method ClientWidth:Int()
  3131. Local w:Int = width
  3132. If handle Then
  3133. ?bmxng
  3134. Local minReq:GtkRequisition
  3135. Local natReq:GtkRequisition
  3136. ?Not bmxng
  3137. Local minReq:GtkRequisition = New GtkRequisition
  3138. Local natReq:GtkRequisition = New GtkRequisition
  3139. ?
  3140. gtk_widget_get_preferred_size(handle, minReq, natReq)
  3141. w:- 4 ' FIXME : current hard-coded. Should be width of notebook less borders.
  3142. End If
  3143. Return Max(0, w)
  3144. End Method
  3145. Method SetToolTipIndex:Int(index:Int, tip:String, label:Byte Ptr)
  3146. ' Add a tooltip
  3147. If tip And tip.length > 0 Then
  3148. Local tipPtr:Byte Ptr = tip.ToUTF8String()
  3149. gtk_widget_set_tooltip_text(label, tipPtr)
  3150. MemFree(tipPtr)
  3151. Else
  3152. gtk_widget_set_tooltip_text(label, Null)
  3153. End If
  3154. End Method
  3155. Method SetIconStrip:Int(iconstrip:TIconStrip)
  3156. icons = TGTKIconStrip(iconstrip)
  3157. End Method
  3158. Method free:Int() Override
  3159. Super.Free()
  3160. If container Then
  3161. gtk_widget_destroy(container)
  3162. container = Null
  3163. End If
  3164. handle = Null
  3165. images = Null
  3166. labels = Null
  3167. End Method
  3168. Method Rethink:Int()
  3169. If handle Then
  3170. gtk_layout_move(TGTKContainer(parent).container, handle, xpos, ypos)
  3171. gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
  3172. End If
  3173. End Method
  3174. Method toString:String()
  3175. Return "TGTKTabber"
  3176. End Method
  3177. Method RemoveFromTab(page:Byte Ptr)
  3178. If currentIndex >= 0 Then
  3179. g_object_ref(container)
  3180. gtk_container_remove(page, container)
  3181. End If
  3182. End Method
  3183. Method AddToTab(page:Byte Ptr)
  3184. gtk_box_pack_start(page, container, True, True, 0)
  3185. g_object_unref(container)
  3186. End Method
  3187. End Type
  3188. Rem
  3189. bbdoc: A Panel
  3190. End Rem
  3191. Type TGTKPanel Extends TGTKContainer
  3192. Field frame:Byte Ptr
  3193. Field hasFrame:Int
  3194. Field panelPixmap:TPixmap
  3195. Field panelPixbuf:Byte Ptr
  3196. Field pixmapMode:Int
  3197. Field drawPixbuf:Int
  3198. Field visualpixbuf:Byte Ptr
  3199. Field pbx:Int
  3200. Field pby:Int
  3201. Field pane:Int
  3202. Function CreatePanel:TGTKPanel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int, intoPane:Int = 0)
  3203. Local this:TGTKPanel = New TGTKPanel
  3204. this.initPanel(x, y, w, h, label, group, style, intoPane)
  3205. Return this
  3206. End Function
  3207. Method initPanel(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int, intoPane:Int)
  3208. handle = gtk_layout_new(Null, Null)
  3209. Init(GTK_PANEL, x, y, w, h, style)
  3210. container = handle
  3211. If style & PANEL_ACTIVE
  3212. sensitivity:| SENSITIZE_MOUSE | SENSITIZE_KEYS
  3213. End If
  3214. gtk_widget_add_events(handle, GDK_BUTTON_PRESS_MASK | ..
  3215. GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | ..
  3216. GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK)' | ..
  3217. ' GDK_POINTER_MOTION_HINT_MASK)
  3218. addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
  3219. addConnection("button-release-event", g_signal_cb3_ret(handle, "button-release-event", OnMouseUp, Self, Destroy, 0))
  3220. addConnection("enter-notify-event", g_signal_cb3_ret(handle, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
  3221. addConnection("leave-notify-event", g_signal_cb3_ret(handle, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
  3222. addConnection("motion-notify-event", g_signal_cb3_ret(handle, "motion-notify-event", OnMouseMove, Self, Destroy, 0))
  3223. addConnection("draw", g_signal_cb3_ret(handle, "draw", OnDraw, Self, Destroy, 0))
  3224. addConnection("scroll-event", g_signal_cb3(handle, "scroll-event", OnScroll, Self, Destroy, 0))
  3225. addConnection("key-press-event", g_signal_cb3_ret(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
  3226. addConnection("key-release-event", g_signal_cb3_ret(handle, "key-release-event", OnKeyUp, Self, Destroy, 0))
  3227. gtk_widget_show(handle)
  3228. ' Should we add a frame?
  3229. If style & PANEL_BORDER Or style & PANEL_GROUP Then
  3230. hasFrame = True
  3231. frame = gtk_frame_new(Null)
  3232. gtk_widget_show(frame)
  3233. ' set frame text
  3234. If (LocalizationMode() & LOCALIZATION_OVERRIDE) Then
  3235. LocalizeGadget(Self, label)
  3236. Else
  3237. SetText(label)
  3238. EndIf
  3239. gtk_container_add(frame, handle)
  3240. gtk_layout_put(TGTKContainer(group).container, frame, x, y)
  3241. gtk_widget_set_size_request(frame, w, Max(h,0))
  3242. Else
  3243. gtk_layout_put(TGTKContainer(group).container, handle, x, y)
  3244. gtk_widget_set_size_request(handle, w, Max(h,0))
  3245. End If
  3246. End Method
  3247. Rem
  3248. bbdoc: Callback for mouse button press.
  3249. End Rem
  3250. Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3251. If TGTKPanel(obj).style & PANEL_ACTIVE Then
  3252. Local x:Double, y:Double, button:Int
  3253. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  3254. If button = 3 Then
  3255. button = 2
  3256. Else If button = 2 Then
  3257. button = 3
  3258. End If
  3259. PostGuiEvent(EVENT_MOUSEDOWN, TGadget(obj),button,,Int(x),Int(y))
  3260. End If
  3261. Return True
  3262. End Function
  3263. Rem
  3264. bbdoc: Callback for mouse button release.
  3265. End Rem
  3266. Function OnMouseUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3267. If TGTKPanel(obj).style & PANEL_ACTIVE Then
  3268. Local x:Double, y:Double, button:Int
  3269. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  3270. If button = 3 Then
  3271. button = 2
  3272. Else If button = 2 Then
  3273. button = 3
  3274. End If
  3275. PostGuiEvent(EVENT_MOUSEUP, TGadget(obj),button,,Int(x),Int(y))
  3276. End If
  3277. Return True
  3278. End Function
  3279. Rem
  3280. bbdoc: Callback for mouse enter.
  3281. End Rem
  3282. Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3283. If TGTKPanel(obj).style & PANEL_ACTIVE Then
  3284. If TGTKGadget(obj).visible Then
  3285. PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
  3286. End If
  3287. End If
  3288. Return False
  3289. End Function
  3290. Rem
  3291. bbdoc: Callback for mouse leave.
  3292. End Rem
  3293. Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3294. If TGTKPanel(obj).style & PANEL_ACTIVE Then
  3295. If TGTKGadget(obj).visible Then
  3296. PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
  3297. End If
  3298. End If
  3299. Return False
  3300. End Function
  3301. Rem
  3302. bbdoc: Callback for mouse movement
  3303. End Rem
  3304. Function OnMouseMove:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3305. If TGTKPanel(obj).style & PANEL_ACTIVE Then
  3306. Local _x:Double, _y:Double, button:Int
  3307. bmx_gtk3maxgui_gdkeventmotion(event, Varptr _x, Varptr _y, Varptr button)
  3308. Local x:Int, y:Int
  3309. ' we actually ignore the coords returned by the event and get the
  3310. ' mouse coords relative to this widget's parent
  3311. gdk_window_get_device_position(gtk_widget_get_parent_window(widget), bmx_gtk3maxgui_gdkeventmotiondevice(event), x, y, button)
  3312. ' then we remove the stored coords from that value to get the TRUE coords.
  3313. x:- TGTKPanel(obj).xpos
  3314. y:- TGTKPanel(obj).ypos
  3315. If button & GDK_BUTTON1_MASK Then
  3316. button = 1
  3317. Else If button & GDK_BUTTON3_MASK Then
  3318. button = 2
  3319. Else If button & GDK_BUTTON2_MASK Then
  3320. button = 3
  3321. Else
  3322. button = 0
  3323. End If
  3324. PostGuiEvent(EVENT_MOUSEMOVE, TGadget(obj),button,,x,y)
  3325. End If
  3326. Return True
  3327. End Function
  3328. Function OnDraw:Int(widget:Byte Ptr, cairo:Byte Ptr, obj:Object)
  3329. Local panel:TGTKPanel = TGTKPanel(obj)
  3330. If panel Then
  3331. If panel.drawPixbuf And panel.visualpixbuf Then
  3332. gdk_cairo_set_source_pixbuf(cairo, panel.visualpixbuf, panel.pbx, panel.pby)
  3333. cairo_paint(cairo)
  3334. cairo_fill(cairo)
  3335. End If
  3336. End If
  3337. PostGuiEvent(EVENT_GADGETPAINT, TGadget(obj))
  3338. End Function
  3339. Rem
  3340. bbdoc: Callback for mouse scroll wheel
  3341. End Rem
  3342. Function OnScroll(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3343. If TGTKPanel(obj).style & PANEL_ACTIVE Then
  3344. Local x:Double, y:Double, direction:Int
  3345. bmx_gtk3maxgui_gdkeventscroll(event, Varptr x, Varptr y, Varptr direction)
  3346. If direction = GDK_SCROLL_UP Or direction = GDK_SCROLL_LEFT Then
  3347. PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),-1,,Int(x),Int(y))
  3348. Else
  3349. PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),1,,Int(x),Int(y))
  3350. End If
  3351. End If
  3352. End Function
  3353. Rem
  3354. bbdoc: Callback for key down
  3355. End Rem
  3356. Function OnKeyDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3357. If TGTKPanel(obj).style & PANEL_ACTIVE Then
  3358. Local _key:Int, _mods:Int
  3359. bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
  3360. Local key:Int = TGTKKeyMap.mapBack(_key)
  3361. Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
  3362. If Not gtk3SetKeyDown(key) Then
  3363. PostGuiEvent(EVENT_KEYDOWN, TGadget(obj), key, mods)
  3364. Else
  3365. PostGuiEvent(EVENT_KEYREPEAT, TGadget(obj), key, mods)
  3366. End If
  3367. Local char:Int = gdk_keyval_to_unicode(_key)
  3368. ' we sometimes get 0 from this function when key is valid... so set it to key just so that it has a value.
  3369. If char = 0 And key <> 0 Then
  3370. char = key
  3371. End If
  3372. PostGuiEvent(EVENT_KEYCHAR, TGadget(obj), char, mods)
  3373. Return True
  3374. End If
  3375. End Function
  3376. Rem
  3377. bbdoc: Callback for key up
  3378. End Rem
  3379. Function OnKeyUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3380. If TGTKPanel(obj).style & PANEL_ACTIVE Then
  3381. Local _key:Int, _mods:Int
  3382. bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
  3383. Local key:Int = TGTKKeyMap.mapBack(_key)
  3384. Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
  3385. gtk3SetKeyUp(key)
  3386. PostGuiEvent(EVENT_KEYUP, TGadget(obj), key, mods)
  3387. Return True
  3388. End If
  3389. End Function
  3390. Rem
  3391. bbdoc: Sets the text of a group panel.
  3392. End Rem
  3393. Method SetText:Int(text:String)
  3394. If style & PANEL_GROUP Then
  3395. If text = Null Or text.length = 0 Then
  3396. gtk_frame_set_label(frame, Null)
  3397. Else
  3398. Local textPtr:Byte Ptr = text.ToUTF8String()
  3399. gtk_frame_set_label(frame, textPtr)
  3400. MemFree(textPtr)
  3401. End If
  3402. End If
  3403. End Method
  3404. Rem
  3405. bbdoc: Shows or hides a panel
  3406. End Rem
  3407. Method SetShow:Int(truefalse:Int)
  3408. visible = truefalse
  3409. mySetVisible = visible
  3410. If truefalse Then
  3411. If frame Then
  3412. gtk_widget_show(frame)
  3413. Else
  3414. gtk_widget_show(handle)
  3415. End If
  3416. Else
  3417. If frame Then
  3418. gtk_widget_hide(frame)
  3419. Else
  3420. gtk_widget_hide(handle)
  3421. End If
  3422. EndIf
  3423. UpdateChildVisibility()
  3424. End Method
  3425. Method free:Int() Override
  3426. Super.Free()
  3427. If frame Then
  3428. gtk_widget_destroy(frame)
  3429. Else
  3430. If handle Then
  3431. gtk_widget_destroy(handle)
  3432. End If
  3433. End If
  3434. container = Null
  3435. handle = Null
  3436. frame = Null
  3437. If panelpixmap Then
  3438. panelpixmap = Null
  3439. End If
  3440. If panelPixbuf Then
  3441. g_object_unref(panelPixbuf)
  3442. panelPixbuf = Null
  3443. End If
  3444. End Method
  3445. Rem
  3446. bbdoc: Set the panel color.
  3447. End Rem
  3448. Method SetColor:Int(r:Int, g:Int, b:Int)
  3449. Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
  3450. gtk_widget_override_background_color(handle, GTK_STATE_FLAG_NORMAL, color)
  3451. End Method
  3452. Rem
  3453. bbdoc: Set the panel pixmap.
  3454. End Rem
  3455. Method SetPixmap:Int(pixmap:TPixmap, flags:Int)
  3456. pixmapMode = flags
  3457. If pixmap Then
  3458. If PixmapFormat(pixmap) <> PF_RGBA8888 And PixmapFormat(pixmap) <> PF_BGRA8888 Then
  3459. panelPixmap = pixmap.convert( PF_RGBA8888 )
  3460. Else
  3461. panelPixmap = pixmap
  3462. End If
  3463. If panelPixbuf Then
  3464. g_object_unref(panelPixbuf)
  3465. End If
  3466. panelPixbuf = gdk_pixbuf_new_from_data(panelPixmap.pixels, GDK_COLORSPACE_RGB, True, 8, ..
  3467. panelPixmap.width, panelPixmap.height, panelPixmap.Pitch, Null, Null)
  3468. Else
  3469. If panelPixmap Then
  3470. panelPixmap = Null
  3471. End If
  3472. End If
  3473. redraw()
  3474. End Method
  3475. Method rethink:Int()
  3476. If frame Then
  3477. gtk_layout_move(TGTKContainer(parent).container, frame, xpos, ypos)
  3478. gtk_widget_set_size_request(frame, Max(width,0), Max(height,0))
  3479. Else If handle Then
  3480. gtk_layout_move(TGTKContainer(parent).container, handle, xpos, ypos)
  3481. gtk_widget_set_size_request(handle, Max(width,0), Max(height,0))
  3482. End If
  3483. redraw()
  3484. End Method
  3485. Method redraw()
  3486. If Not panelPixmap Then
  3487. If panelPixbuf Then
  3488. g_object_unref(panelPixbuf)
  3489. panelPixbuf = Null
  3490. End If
  3491. If visualpixbuf Then
  3492. g_object_unref(visualpixbuf)
  3493. visualpixbuf = Null
  3494. ' make the panel redraw itself
  3495. gtk_widget_queue_draw(handle)
  3496. End If
  3497. End If
  3498. If panelPixbuf Then
  3499. If visualpixbuf Then
  3500. g_object_unref(visualpixbuf)
  3501. End If
  3502. Select pixmapMode & (PANELPIXMAP_TILE | PANELPIXMAP_CENTER | PANELPIXMAP_FIT | PANELPIXMAP_FIT2 | PANELPIXMAP_STRETCH)
  3503. Case PANELPIXMAP_TILE
  3504. pbx = 0
  3505. pby = 0
  3506. Local w:Float = width
  3507. Local h:Float = height
  3508. Local wfull:Int = w / panelPixmap.width
  3509. Local hfull:Int = h / panelPixmap.height
  3510. Local wpart:Int = w Mod panelPixmap.width
  3511. Local hpart:Int = h Mod panelPixmap.height
  3512. visualpixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, True, 8, Int(w), Int(h))
  3513. For Local x:Int = 0 Until wfull
  3514. For Local y:Int = 0 Until hfull
  3515. gdk_pixbuf_copy_area(panelPixbuf, 0, 0, panelPixmap.width, panelPixmap.height, visualpixbuf, x * panelPixmap.width, y * panelPixmap.height)
  3516. Next
  3517. If hpart > 0 Then
  3518. gdk_pixbuf_copy_area(panelPixbuf, 0, 0, panelPixmap.width, hpart, visualpixbuf, x * panelPixmap.width, hfull * panelPixmap.height)
  3519. End If
  3520. Next
  3521. If wpart > 0 Then
  3522. For Local y:Int = 0 Until hfull
  3523. gdk_pixbuf_copy_area(panelPixbuf, 0, 0, wpart, panelPixmap.height, visualpixbuf, wfull * panelPixmap.width, y * panelPixmap.height)
  3524. Next
  3525. If hpart > 0 Then
  3526. gdk_pixbuf_copy_area(panelPixbuf, 0, 0, wpart, hpart, visualpixbuf, wfull * panelPixmap.width, hfull * panelPixmap.height)
  3527. End If
  3528. End If
  3529. Case PANELPIXMAP_CENTER
  3530. visualpixbuf = gdk_pixbuf_copy(panelPixBuf)
  3531. pbx = width / 2 - panelPixmap.width / 2
  3532. pby = height / 2 - panelPixmap.height / 2
  3533. Case PANELPIXMAP_FIT
  3534. Local _w:Float = width / (panelPixmap.width * 1.0)
  3535. Local _h:Float = height / (panelPixmap.height * 1.0)
  3536. Local newWidth:Int = Min(_w, _h) * panelPixmap.width
  3537. Local newHeight:Int = Min(_w, _h) * panelPixmap.height
  3538. pbx = width / 2 - newWidth / 2
  3539. pby = height / 2 - newHeight / 2
  3540. visualpixbuf = gdk_pixbuf_scale_simple(panelPixbuf, newWidth, newHeight, GDK_INTERP_BILINEAR)
  3541. Case PANELPIXMAP_FIT2
  3542. Local _w:Float = width / (panelPixmap.width * 1.0)
  3543. Local _h:Float = height / (panelPixmap.height * 1.0)
  3544. Local newWidth:Int = Max(_w, _h) * panelPixmap.width
  3545. Local newHeight:Int = Max(_w, _h) * panelPixmap.height
  3546. pbx = width / 2 - newWidth / 2
  3547. pby = height / 2 - newHeight / 2
  3548. visualpixbuf = gdk_pixbuf_scale_simple(panelPixbuf, newWidth, newHeight, GDK_INTERP_BILINEAR)
  3549. Case PANELPIXMAP_STRETCH
  3550. pbx = 0
  3551. pby = 0
  3552. visualpixbuf = gdk_pixbuf_scale_simple(panelPixbuf, width, height, GDK_INTERP_BILINEAR)
  3553. End Select
  3554. If Not drawPixbuf Then
  3555. drawPixbuf = True
  3556. End If
  3557. End If
  3558. ' make sure the panel refreshes visually
  3559. Super.redraw()
  3560. End Method
  3561. Method Activate:Int(cmd:Int)
  3562. Select cmd
  3563. Case ACTIVATE_REDRAW
  3564. redraw()
  3565. Default
  3566. Super.Activate(cmd)
  3567. End Select
  3568. End Method
  3569. Method toString:String()
  3570. Return "TGTKPanel"
  3571. End Method
  3572. End Type
  3573. Rem
  3574. bbdoc: A canvas.
  3575. End Rem
  3576. Type TGTKCanvas Extends TGTKGadget
  3577. Field canvas:TGraphics
  3578. Field Mode:Long
  3579. Function CreateCanvas:TGTKCanvas(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  3580. Local this:TGTKCanvas = New TGTKCanvas
  3581. this.initCanvas(x, y, w, h, label, group, style)
  3582. Return this
  3583. End Function
  3584. Method initCanvas(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  3585. handle = gtk_drawing_area_new()
  3586. Init(GTK_CANVAS, x, y, w, h, style)
  3587. gtk_layout_put(TGTKContainer(group).container, handle, x, y)
  3588. gtk_widget_set_size_request(handle, w, Max(h,0))
  3589. sensitivity:| SENSITIZE_MOUSE | SENSITIZE_KEYS
  3590. ' we need to allow the drawing area to accept focus !
  3591. g_object_set_int(handle, "can-focus", True)
  3592. ' we need to handle our own redrawing...
  3593. 'gtk_widget_set_double_buffered(handle, False)
  3594. addConnection("draw", g_signal_cb3(handle, "draw", CanvasRedraw, Self, Destroy, 0))
  3595. gtk_widget_add_events(handle, GDK_BUTTON_PRESS_MASK | ..
  3596. GDK_BUTTON_RELEASE_MASK | GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK | ..
  3597. GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | GDK_POINTER_MOTION_MASK | GDK_SCROLL_MASK)' | ..
  3598. ' GDK_POINTER_MOTION_HINT_MASK)
  3599. addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
  3600. addConnection("button-release-event", g_signal_cb3_ret(handle, "button-release-event", OnMouseUp, Self, Destroy, 0))
  3601. addConnection("enter-notify-event", g_signal_cb3_ret(handle, "enter-notify-event", OnMouseEnter, Self, Destroy, 0))
  3602. addConnection("leave-notify-event", g_signal_cb3_ret(handle, "leave-notify-event", OnMouseLeave, Self, Destroy, 0))
  3603. addConnection("motion-notify-event", g_signal_cb3_ret(handle, "motion-notify-event", OnMouseMove, Self, Destroy, 0))
  3604. addConnection("scroll-event", g_signal_cb3(handle, "scroll-event", OnScroll, Self, Destroy, 0))
  3605. addConnection("key-press-event", g_signal_cb3_ret(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
  3606. addConnection("key-release-event", g_signal_cb3_ret(handle, "key-release-event", OnKeyUp, Self, Destroy, 0))
  3607. SetShow(True)
  3608. End Method
  3609. Function CanvasRedraw(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3610. PostGuiEvent(EVENT_GADGETPAINT, TGadget(obj))
  3611. End Function
  3612. Method AttachGraphics:TGraphics( flags:Long )
  3613. Mode = flags
  3614. End Method
  3615. Method CanvasGraphics:TGraphics()
  3616. If Not canvas Then
  3617. canvas = BRL.Graphics.AttachGraphics(gdk_x11_window_get_xid(gtk_widget_get_window(handle)), Mode)
  3618. End If
  3619. Return canvas
  3620. End Method
  3621. Method Activate:Int(cmd:Int)
  3622. If cmd <> ACTIVATE_REDRAW Then
  3623. Super.Activate(cmd)
  3624. End If
  3625. Select cmd
  3626. Case ACTIVATE_REDRAW
  3627. gtk_widget_queue_draw(handle)
  3628. End Select
  3629. End Method
  3630. Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3631. Local x:Double, y:Double, button:Int
  3632. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  3633. If button = 3 Then
  3634. button = 2
  3635. Else If button = 2 Then
  3636. button = 3
  3637. End If
  3638. PostGuiEvent(EVENT_MOUSEDOWN, TGadget(obj),button,,Int(x),Int(y))
  3639. Return True
  3640. End Function
  3641. Function OnScroll(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3642. Local x:Double, y:Double, direction:Int
  3643. bmx_gtk3maxgui_gdkeventscroll(event, Varptr x, Varptr y, Varptr direction)
  3644. If direction = GDK_SCROLL_UP Or direction = GDK_SCROLL_LEFT Then
  3645. PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),-1,,Int(x),Int(y))
  3646. Else
  3647. PostGuiEvent(EVENT_MOUSEWHEEL, TGadget(obj),1,,Int(x),Int(y))
  3648. End If
  3649. End Function
  3650. Function OnMouseUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3651. Local x:Double, y:Double, button:Int
  3652. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  3653. If button = 3 Then
  3654. button = 2
  3655. Else If button = 2 Then
  3656. button = 3
  3657. End If
  3658. PostGuiEvent(EVENT_MOUSEUP, TGadget(obj),button,,Int(x),Int(y))
  3659. Return True
  3660. End Function
  3661. Function OnMouseEnter:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3662. PostGuiEvent(EVENT_MOUSEENTER, TGadget(obj))
  3663. Return True
  3664. End Function
  3665. Function OnMouseLeave:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3666. PostGuiEvent(EVENT_MOUSELEAVE, TGadget(obj))
  3667. Return True
  3668. End Function
  3669. 'Rem
  3670. 'bbdoc: Callback for mouse movement
  3671. 'End Rem
  3672. Function OnMouseMove:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3673. Local x:Double, y:Double, button:Int
  3674. bmx_gtk3maxgui_gdkeventmotion(event, Varptr x, Varptr y, Varptr button)
  3675. If button & GDK_BUTTON1_MASK Then
  3676. button = 1
  3677. Else If button & GDK_BUTTON3_MASK Then
  3678. button = 2
  3679. Else If button & GDK_BUTTON2_MASK Then
  3680. button = 3
  3681. Else
  3682. button = 0
  3683. End If
  3684. PostGuiEvent(EVENT_MOUSEMOVE, TGadget(obj),button,,Int(x),Int(y))
  3685. Return True
  3686. End Function
  3687. Function OnKeyDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3688. Local _key:Int, _mods:Int
  3689. bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
  3690. Local key:Int = TGTKKeyMap.mapBack(_key)
  3691. Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
  3692. If Not gtk3SetKeyDown(key) Then
  3693. PostGuiEvent(EVENT_KEYDOWN, TGadget(obj), key, mods)
  3694. Else
  3695. PostGuiEvent(EVENT_KEYREPEAT, TGadget(obj), key, mods)
  3696. End If
  3697. Local char:Int = gdk_keyval_to_unicode(_key)
  3698. ' we sometimes get 0 from this function when key is valid... so set it to key just so that it has a value.
  3699. If char = 0 And key <> 0 Then
  3700. char = key
  3701. End If
  3702. PostGuiEvent(EVENT_KEYCHAR, TGadget(obj), char, mods)
  3703. Return True
  3704. End Function
  3705. Function OnKeyUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3706. Local _key:Int, _mods:Int
  3707. bmx_gtk3maxgui_gdkeventkey(event, Varptr _key, Varptr _mods)
  3708. Local key:Int = TGTKKeyMap.mapBack(_key)
  3709. Local mods:Int = TGTKKeyMap.mapModifierBack(_mods)
  3710. gtk3SetKeyUp(key)
  3711. PostGuiEvent(EVENT_KEYUP, TGadget(obj), key, mods)
  3712. Return True
  3713. End Function
  3714. Method free:Int()
  3715. Super.free()
  3716. If canvas
  3717. canvas.Close()
  3718. canvas = Null
  3719. End If
  3720. If handle
  3721. gtk_widget_destroy(handle)
  3722. EndIf
  3723. handle = Null
  3724. End Method
  3725. End Type
  3726. Rem
  3727. bbdoc: A text area.
  3728. End Rem
  3729. Type TGTKDefaultTextArea Extends TGTKTextArea
  3730. Field _tabsize:Int = 4
  3731. Field scrollWindow:Byte Ptr
  3732. Field _textBuffer:Byte Ptr
  3733. Field _textTagTable:Byte Ptr
  3734. Field _tabArray:Byte Ptr
  3735. Field ignoreChange:Int
  3736. Field fastUpdate:Int = False
  3737. 'Field _selStart:Int
  3738. 'Field _selEnd:Int
  3739. Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  3740. Local this:TGTKDefaultTextArea = New TGTKDefaultTextArea
  3741. this.initTextArea(x, y, w, h, label, group, style)
  3742. Return this
  3743. End Function
  3744. Method initTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  3745. _textBuffer = gtk_text_buffer_new(Null)
  3746. _textTagTable = gtk_text_buffer_get_tag_table(_textBuffer)
  3747. handle = gtk_text_view_new_with_buffer(_textBuffer)
  3748. gtk_widget_show(handle)
  3749. ' we need these events to allow tooltips to work
  3750. gtk_widget_add_events(handle, GDK_ENTER_NOTIFY_MASK | GDK_LEAVE_NOTIFY_MASK)
  3751. ' use word-wrapping ?
  3752. If style & TEXTAREA_WORDWRAP Then
  3753. gtk_text_view_set_wrap_mode(handle, GTK_WRAP_WORD_CHAR)
  3754. End If
  3755. ' a read-only textarea ?
  3756. If style & TEXTAREA_READONLY Then
  3757. gtk_text_view_set_editable(handle, False)
  3758. End If
  3759. Init(GTK_TEXTFIELD, x, y, w, h, style)
  3760. ' scrollbars for the textarea...
  3761. scrollWindow = gtk_scrolled_window_new(Null, Null)
  3762. ' set container resize mode
  3763. gtk_container_set_resize_mode(scrollWindow, GTK_RESIZE_QUEUE)
  3764. ' set scrollbar policy
  3765. gtk_scrolled_window_set_policy(scrollWindow, GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC)
  3766. ' show
  3767. gtk_widget_show(scrollWindow)
  3768. ' add the text area to the scroll window
  3769. gtk_container_add(scrollWindow, handle)
  3770. addConnection("changed", g_signal_cb2(_textBuffer, "changed", OnTextChanged, Self, Destroy, 0))
  3771. addConnection("move-cursor", g_signal_cb5(handle, "move-cursor", OnCursorMoved, Self, Destroy, 0))
  3772. addConnection("button-press-event", g_signal_cb3_ret(handle, "button-press-event", OnMouseDown, Self, Destroy, 0))
  3773. addConnection("button-release-event", g_signal_cb3_ret(handle, "button-release-event", OnMouseUp, Self, Destroy, 0))
  3774. addConnection("key-press-event", g_signal_cb3_ret(handle, "key-press-event", OnKeyDown, Self, Destroy, 0))
  3775. addConnection("focus-out-event", g_signal_cb3_ret(handle, "focus-out-event", OnFocusLost, Self, Destroy, 0))
  3776. 'g_signal_cb3(handle, "visibility-notify-event", OnVisibilityChange, Self, Destroy, 0)
  3777. gtk_layout_put(TGTKContainer(group).container, scrollwindow, x, y)
  3778. gtk_widget_set_size_request(handle, w, Max(h,0))
  3779. End Method
  3780. Rem
  3781. bbdoc: Callback for text change
  3782. End Rem
  3783. Function OnTextChanged(widget:Byte Ptr, obj:Object)
  3784. If Not TGTKDefaultTextArea(obj).ignoreChange Then
  3785. PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
  3786. PostGuiEvent(EVENT_GADGETACTION, TGadget(obj))
  3787. End If
  3788. TGTKDefaultTextArea(obj).ignoreChange = False
  3789. End Function
  3790. Rem
  3791. bbdoc: Callback for text-cursor movement
  3792. End Rem
  3793. Function OnCursorMoved(widget:Byte Ptr, _Step:Int, count:Int, extend_selection:Int, obj:Object)
  3794. PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
  3795. End Function
  3796. Rem
  3797. bbdoc: Callback for mouse button press
  3798. End Rem
  3799. Function OnMouseDown:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3800. Local x:Double, y:Double, button:Int
  3801. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  3802. If button = 3 Then ' right mouse button
  3803. ' ignore this... see MouseUp for menu event!
  3804. Return True
  3805. End If
  3806. PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
  3807. End Function
  3808. Rem
  3809. bbdoc: Callback for mouse button release
  3810. End Rem
  3811. Function OnMouseUp:Int(widget:Byte Ptr, event:Byte Ptr, obj:Object)
  3812. Local x:Double, y:Double, button:Int
  3813. bmx_gtk3maxgui_gdkeventbutton(event, Varptr x, Varptr y, Varptr button)
  3814. If button = 3 Then ' right mouse button
  3815. PostGuiEvent(EVENT_GADGETMENU, TGadget(obj),,,Int(x),Int(y))
  3816. Return True
  3817. End If
  3818. PostGuiEvent(EVENT_GADGETSELECT, TGadget(obj))
  3819. End Function
  3820. Rem
  3821. bbdoc: Adds text to the end of the text.
  3822. End Rem
  3823. Method AddText:Int(text:String)
  3824. Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
  3825. ' get the end of the text
  3826. gtk_text_buffer_get_end_iter(_textBuffer, _end)
  3827. ignoreChange = True
  3828. Local textPtr:Byte Ptr = text.ToUTF8String()
  3829. gtk_text_buffer_insert(_textBuffer, _end, textPtr, -1)
  3830. MemFree(textPtr)
  3831. gtk_text_buffer_get_end_iter(_textBuffer, _end)
  3832. ?bmxng
  3833. IWrappedSystemDriver(SystemDriver()).GetDriver().Poll()
  3834. ?Not bmxng
  3835. brl.System.Driver.Poll() ' update events, before scrolling to the end...
  3836. ?
  3837. gtk_text_view_scroll_to_iter(handle, _end, 0, False, 0, 0)
  3838. bmx_gtk3_gtktextiter_free(_end)
  3839. End Method
  3840. Rem
  3841. bbdoc: Returns the text For the specified location
  3842. End Rem
  3843. Method AreaText:String(pos:Int, length:Int, units:Int)
  3844. Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
  3845. Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
  3846. If units = TEXTAREA_LINES Then
  3847. gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
  3848. gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
  3849. Else ' must be TEXTAREA_CHARS
  3850. gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
  3851. gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
  3852. End If
  3853. Local s:Byte Ptr = gtk_text_buffer_get_text(_textBuffer, _start, _end, False)
  3854. Local st:String = String.FromUTF8String(s)
  3855. g_free(s)
  3856. bmx_gtk3_gtktextiter_free(_start)
  3857. bmx_gtk3_gtktextiter_free(_end)
  3858. Return st
  3859. End Method
  3860. Rem
  3861. bbdoc: Returns either the number of characters or number of rows.
  3862. End Rem
  3863. Method AreaLen:Int(units:Int)
  3864. If units = TEXTAREA_LINES Then
  3865. Return gtk_text_buffer_get_line_count(_textBuffer)
  3866. Else
  3867. Return gtk_text_buffer_get_char_count(_textBuffer)
  3868. End If
  3869. End Method
  3870. Rem
  3871. bbdoc: Returns the current cursor position value, in characters or lines
  3872. End Rem
  3873. Method GetCursorPos:Int(units:Int)
  3874. Local pos:Int = 0
  3875. Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
  3876. Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
  3877. ' Since the cursor position might be at the end of selected text, we get the selection
  3878. ' bounds and get the *start* location. If there is no selection, start and end will be the same
  3879. gtk_text_buffer_get_selection_bounds(_textBuffer, _start, _end)
  3880. If units = TEXTAREA_LINES Then
  3881. pos = gtk_text_iter_get_line(_start)
  3882. Else ' must be TEXTAREA_CHARS
  3883. pos = gtk_text_iter_get_offset(_start)
  3884. End If
  3885. bmx_gtk3_gtktextiter_free(_start)
  3886. bmx_gtk3_gtktextiter_free(_end)
  3887. Return pos
  3888. End Method
  3889. Rem
  3890. bbdoc: Set the text area visibility.
  3891. End Rem
  3892. Method SetShow:Int(truefalse:Int)
  3893. visible = truefalse
  3894. mySetVisible = visible
  3895. If truefalse Then
  3896. gtk_widget_show(handle)
  3897. gtk_widget_show(scrollWindow)
  3898. Else
  3899. gtk_widget_hide(scrollWindow)
  3900. EndIf
  3901. End Method
  3902. Rem
  3903. bbdoc: Set the text area font.
  3904. End Rem
  3905. Method SetFont:Int(font:TGuiFont)
  3906. Super.SetFont(font)
  3907. ' we need to reset the tabs, as it is lost when font is changed.
  3908. SetTabs(_tabsize)
  3909. End Method
  3910. Rem
  3911. bbdoc: Sets the text buffer text
  3912. End Rem
  3913. Method SetText:Int(text:String)
  3914. ignoreChange = True
  3915. Local textPtr:Byte Ptr = text.ToUTF8String()
  3916. gtk_text_buffer_set_text(_textBuffer, textPtr, -1)
  3917. MemFree(textPtr)
  3918. ' move the cursor to the start
  3919. Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
  3920. gtk_text_buffer_get_iter_at_line(_textBuffer, _start, 0)
  3921. gtk_text_buffer_place_cursor(_textBuffer, _start)
  3922. gtk_text_view_scroll_mark_onscreen(handle, gtk_text_buffer_get_insert(_textBuffer))', 0, False, 0, 0.1)
  3923. bmx_gtk3_gtktextiter_free(_start)
  3924. End Method
  3925. Rem
  3926. bbdoc: Set the text area selection
  3927. End Rem
  3928. Method SetSelection:Int(pos:Int, length:Int, units:Int)
  3929. Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
  3930. Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
  3931. If units = TEXTAREA_LINES Then
  3932. gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
  3933. gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
  3934. Else ' must be TEXTAREA_CHARS
  3935. gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
  3936. gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
  3937. End If
  3938. gtk_text_buffer_place_cursor(_textBuffer, _start)
  3939. gtk_text_view_scroll_mark_onscreen(handle, gtk_text_buffer_get_insert(_textBuffer))
  3940. gtk_text_buffer_select_range(_textBuffer, _start, _end)
  3941. PostGuiEvent(EVENT_GADGETSELECT, Self)
  3942. ' scroll to the start of the selection
  3943. ' NOTE: setting param4 to False causes it to scroll only as much as required to show the start
  3944. ' Set to True to cause it to always display at the same point on the visible area.
  3945. gtk_text_view_scroll_to_iter(handle, _start, 0, False, 0, 0.1)
  3946. bmx_gtk3_gtktextiter_free(_start)
  3947. bmx_gtk3_gtktextiter_free(_end)
  3948. End Method
  3949. Rem
  3950. bbdoc: Returns the size of the current selection, in characters or lines.
  3951. End Rem
  3952. Method GetSelectionLength:Int(units:Int)
  3953. Local length:Int = 0
  3954. Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
  3955. Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
  3956. Local hasSelection:Int = gtk_text_buffer_get_selection_bounds(_textBuffer, _start, _end)
  3957. If hasSelection Then
  3958. If units = TEXTAREA_LINES Then
  3959. gtk_text_iter_backward_char(_end)
  3960. length = (gtk_text_iter_get_line(_end) - gtk_text_iter_get_line(_start)) + 1
  3961. Else ' must be TEXTAREA_CHARS
  3962. length = gtk_text_iter_get_offset(_end) - gtk_text_iter_get_offset(_start)
  3963. End If
  3964. End If
  3965. bmx_gtk3_gtktextiter_free(_start)
  3966. bmx_gtk3_gtktextiter_free(_end)
  3967. Return length
  3968. End Method
  3969. Rem
  3970. bbdoc: Sets the style of part of the text area
  3971. about: @flags are any mix of TEXTFORMAT_BOLD, TEXTFORMAT_ITALIC, TEXTFORMAT_UNDERLINE and TEXTFORMAT_STRIKETHROUGH.<br/>
  3972. We utilise the buffers' tag table to cache tags that we reuse - based on the attributes.
  3973. This way we only create one for each different style we actually use in the buffer.<br/>
  3974. Note: "fastUpdate" flag enables or disables the use of gtk_text_buffer_remove_all_tags which strips
  3975. old tags from the area before applying the new one.<br/>
  3976. Ideally, you would first remove tags before applying new ones, but since removal is slow, the following
  3977. method can work well :
  3978. <pre>
  3979. setFastUpdate(false)
  3980. SetStyle on whole intended area to "normal" style
  3981. setFastUpdate(true)
  3982. iterate thru tokens applying styles..
  3983. </pre>
  3984. End Rem
  3985. Method SetStyle:Int(r:Int, g:Int, b:Int, flags:Int, pos:Int, length:Int, units:Int)
  3986. ' Build a style string
  3987. Local s:Int = r Shl 24 | g Shl 16 | b Shl 8 | (flags & $ff)
  3988. Local styleText:String = String(s)
  3989. ' Does this one already exist?
  3990. Local _textTag:Byte Ptr = gtk_text_tag_table_lookup(_textTagTable, styleText)
  3991. ' nope... so we need to create it
  3992. If _textTag = Null Then
  3993. Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
  3994. '
  3995. Local _style:Int = PANGO_STYLE_NORMAL
  3996. If flags & TEXTFORMAT_ITALIC Then
  3997. _style = PANGO_STYLE_ITALIC
  3998. End If
  3999. Local _weight:Int = PANGO_WEIGHT_NORMAL
  4000. If flags & TEXTFORMAT_BOLD Then
  4001. _weight = PANGO_WEIGHT_BOLD
  4002. End If
  4003. Local _under:Int = PANGO_UNDERLINE_NONE
  4004. If flags & TEXTFORMAT_UNDERLINE Then
  4005. _under = PANGO_UNDERLINE_SINGLE
  4006. End If
  4007. Local _strike:Int = False
  4008. If flags & TEXTFORMAT_STRIKETHROUGH Then
  4009. _strike = True
  4010. End If
  4011. ' create and setup the tag
  4012. _textTag = bmx_gtk3_set_text_tag_style(_textBuffer, styleText, color, _style, _weight, _under, _strike)
  4013. End If
  4014. applyStyle(pos, length, units, _textTag)
  4015. End Method
  4016. Method applyStyle(pos:Int, length:Int, units:Int, _textTag:Byte Ptr)
  4017. ' set up start and end points
  4018. Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
  4019. Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
  4020. If units = TEXTAREA_LINES Then
  4021. gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
  4022. gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
  4023. Else ' must be TEXTAREA_CHARS
  4024. gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
  4025. gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
  4026. End If
  4027. ' remove any existing tags in the range first - otherwise they'll just pile up
  4028. ' NOTE : except that this is REALLY slow....
  4029. If Not fastUpdate Then
  4030. gtk_text_buffer_remove_all_tags(_textBuffer, _start, _end)
  4031. End If
  4032. ' apply the tag to the range
  4033. gtk_text_buffer_apply_tag(_textBuffer, _textTag, _start, _end)
  4034. bmx_gtk3_gtktextiter_free(_start)
  4035. bmx_gtk3_gtktextiter_free(_end)
  4036. End Method
  4037. Method SetBGStyle(r:Int, g:Int, b:Int, pos:Int, length:Int, units:Int)
  4038. ' Build a style string
  4039. Local styleText:String = r + "_" + g + "_" + b + "_bg"
  4040. ' Does this one already exist?
  4041. Local _textTag:Byte Ptr = gtk_text_tag_table_lookup(_textTagTable, styleText)
  4042. ' nope... so we need to create it
  4043. If _textTag = Null Then
  4044. Local color:GdkRGBA = New GdkRGBA(r / 255.0, g / 255.0, b / 255.0)
  4045. ' create and setup the tag
  4046. _textTag = bmx_gtk3_set_text_bg_tag(_textBuffer, styleText, color)
  4047. End If
  4048. applyStyle(pos, length, units, _textTag)
  4049. End Method
  4050. Method ReplaceText:Int(pos:Int, length:Int, text:String, units:Int)
  4051. If length = TEXTAREA_ALL Then
  4052. SetText(text)
  4053. Else
  4054. ' set up start and end points
  4055. Local _start:Byte Ptr = bmx_gtk3_gtktextiter_new()
  4056. Local _end:Byte Ptr = bmx_gtk3_gtktextiter_new()
  4057. If units = TEXTAREA_LINES Then
  4058. gtk_text_buffer_get_iter_at_line(_textBuffer, _start, pos)
  4059. gtk_text_buffer_get_iter_at_line(_textBuffer, _end, pos + length)
  4060. Else ' must be TEXTAREA_CHARS
  4061. gtk_text_buffer_get_iter_at_offset(_textBuffer, _start, pos)
  4062. gtk_text_buffer_get_iter_at_offset(_textBuffer, _end, pos + length)
  4063. End If
  4064. ' remove the specified range
  4065. gtk_text_buffer_delete(_textBuffer, _start, _end)
  4066. ' insert new text
  4067. Local textPtr:Byte Ptr = text.ToUTF8String()
  4068. gtk_text_buffer_insert(_textBuffer, _start, textPtr, -1)
  4069. MemFree(textPtr)
  4070. bmx_gtk3_gtktextiter_free(_start)
  4071. bmx_gtk3_gtktextiter_free(_end)
  4072. End If
  4073. End Method
  4074. Rem
  4075. bbdoc: Locks the text area.
  4076. End Rem
  4077. Method LockText:Int()
  4078. gtk_text_view_set_editable(handle, False)
  4079. End Method
  4080. Rem
  4081. bbdoc: Unlocks the text area
  4082. End Rem
  4083. Method UnlockText:Int()
  4084. gtk_text_view_set_editable(handle, True)
  4085. End Method
  4086. Rem
  4087. bbdoc:
  4088. End Rem
  4089. Method SetTabs:Int(tabs:Int)
  4090. ' cache the current size
  4091. _tabsize = tabs
  4092. ' get the current tab array - returns Null if default 8-space setting
  4093. _tabArray = gtk_text_view_get_tabs(handle)
  4094. If _tabArray <> Null Then
  4095. pango_tab_array_free(_tabArray)
  4096. End If
  4097. Local tabmul:Int = 8 * 1024
  4098. If _font <> Null Then
  4099. tabmul = _font.size * 1024
  4100. End If
  4101. _tabArray = pango_tab_array_new_with_positions(1, False, PANGO_TAB_LEFT, tabs * tabmul)
  4102. gtk_text_view_set_tabs(handle, _tabArray)
  4103. End Method
  4104. Method CharAt:Int(line:Int)
  4105. Local _iter:Byte Ptr = bmx_gtk3_gtktextiter_new()
  4106. gtk_text_buffer_get_iter_at_line(_textBuffer, _iter, line)
  4107. Local ret:Int = gtk_text_iter_get_offset(_iter)
  4108. bmx_gtk3_gtktextiter_free(_iter)
  4109. Return ret
  4110. End Method
  4111. Method LineAt:Int(index:Int)
  4112. Local _iter:Byte Ptr = bmx_gtk3_gtktextiter_new()
  4113. gtk_text_buffer_get_iter_at_offset(_textBuffer, _iter, index)
  4114. Local ret:Int = gtk_text_iter_get_line(_iter)
  4115. bmx_gtk3_gtktextiter_free(_iter)
  4116. Return ret
  4117. End Method
  4118. Method free:Int() Override
  4119. Super.Free()
  4120. If scrollWindow Then
  4121. gtk_widget_destroy(scrollWindow)
  4122. EndIf
  4123. handle = Null
  4124. scrollWindow = Null
  4125. End Method
  4126. Method Activate:Int(cmd:Int)
  4127. Super.Activate(cmd)
  4128. Select cmd
  4129. Case ACTIVATE_CUT
  4130. Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
  4131. gtk_text_buffer_cut_clipboard(_textBuffer, clipboard, True)
  4132. Case ACTIVATE_COPY
  4133. Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
  4134. gtk_text_buffer_copy_clipboard(_textBuffer, clipboard)
  4135. Case ACTIVATE_PASTE
  4136. Local clipboard:Byte Ptr = gtk_clipboard_get(gdk_atom_intern("CLIPBOARD", True))
  4137. gtk_text_buffer_paste_clipboard(_textBuffer, clipboard, Null, True)
  4138. End Select
  4139. End Method
  4140. Rem
  4141. bbdoc: Enable to allow *fast* formatting.
  4142. about: When enabled, highlighting will not be removed before being applied, and since
  4143. tags are ordered, some highlight may not appear on top of others.
  4144. End Rem
  4145. Method setFastUpdate(bool:Int)
  4146. fastUpdate = bool
  4147. End Method
  4148. Method Rethink:Int()
  4149. If handle Then
  4150. gtk_layout_move(TGTKContainer(parent).container, scrollWindow, Max(xpos, 0), Max(ypos, 0))
  4151. gtk_widget_set_size_request(scrollWindow, Max(width,0), Max(height,0))
  4152. End If
  4153. End Method
  4154. End Type
  4155. Rem
  4156. bbdoc: A base type for html view gadgets.
  4157. about: Implementations are in seperate modules.<br/>
  4158. See bah.gtkwebmozilla and bah.gtkwebgtkhtml mods.
  4159. End Rem
  4160. Type TGTKHTMLView Extends TGTKGadget
  4161. Function CreateHTMLView:TGTKHTMLView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
  4162. Method Stop() Abstract
  4163. Method SetText:Int(url:String) Abstract
  4164. Method GetText:String() Abstract
  4165. End Type
  4166. Type TGTKWebDriver
  4167. Function CreateHTMLView:TGTKHTMLView(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
  4168. End Type
  4169. Global gtk3maxgui_htmlview:TGTKWebDriver
  4170. Rem
  4171. bbdoc: A base type for text area gadgets.
  4172. about: Implementations are in seperate modules, except for the default TGTKDefaultTextArea
  4173. End Rem
  4174. Type TGTKTextArea Extends TGTKEditable
  4175. Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
  4176. End Type
  4177. Type TGTKTextAreaDriver
  4178. Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int) Abstract
  4179. End Type
  4180. ' default text area driver
  4181. Type TGTKDefaultTextAreaDriver Extends TGTKTextAreaDriver
  4182. Function CreateTextArea:TGTKTextArea(x:Int, y:Int, w:Int, h:Int, label:String, group:TGadget, style:Int)
  4183. Return TGTKDefaultTextArea.CreateTextArea(x, y, w, h, label, group, style)
  4184. End Function
  4185. End Type
  4186. Global gtk3maxgui_textarea:TGTKTextAreaDriver
  4187. Extern
  4188. Function g_object_get_menudata:TGTKMenuItem(handle:Byte Ptr, name:Byte Ptr) = "g_object_get_data"
  4189. End Extern