gtkgadget.bmx 142 KB

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