main.c 331 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390
  1. /*
  2. * Copyright 2021
  3. *
  4. * This program is free software: you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation, either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  16. *
  17. * These are the four essential freedoms with GNU GPL software:
  18. * 1: freedom to run the program, for any purpose
  19. * 2: freedom to study how the program works, and change it to make it do what you wish
  20. * 3: freedom to redistribute copies to help your Free Software friends
  21. * 4: freedom to distribute copies of your modified versions to your Free Software friends
  22. * , ,
  23. * / \
  24. * ((__-^^-,-^^-__))
  25. * `-_---' `---_-'
  26. * `--|o` 'o|--'
  27. * \ ` /
  28. * ): :(
  29. * :o_o:
  30. * "-"
  31. *
  32. * SPDX-License-Identifier: GPL-3.0+
  33. * License-Filename: LICENSE
  34. */
  35. #ifdef __cplusplus
  36. #error "you are clowns said Linus"
  37. #endif
  38. #ifdef WIN32
  39. #error "Sorry, install GNU / Linux GPL Free software see fsf.org or debian.org"
  40. #endif
  41. /*
  42. * The layout theory is described in this book
  43. * Graph Drawing And Applications For Software And Knowledge Engineers
  44. * ISBN10 9810248792 or ISBN13 9789810248796
  45. * Kozo Sugiyama, World Scientific Publishing Co Pte Ltd
  46. * K. Sugiyama, S. Tagawa and M. Toda, "Methods for Visual Understanding of
  47. * Hierarchical Systems". IEEE Transactions on Systems, Man and Cybernetics
  48. * 11(2):109-125, 1981.
  49. */
  50. #include "config.h"
  51. /* for a qt5 gui it is only needed to create a main.cpp instead of using main.c and link the rest of the code
  52. * or rewrite for nappgui because that is also good and does not add extra overhead
  53. * and nappgui can be compiled for linux gtk-3, windos and mac os-x
  54. * some parts of nappgui are c++ and that is not c
  55. */
  56. /* needed to get basename() from string.h
  57. * #define _GNU_SOURCE
  58. * basename() changed in g_path_get_basename()
  59. */
  60. /* needed to get M_PI definition from math.h
  61. * #define _GNU_SOURCE
  62. * replaced with #define M_PI below after math.h
  63. */
  64. /* needed to get the proto for strdup() in string.h
  65. * now strdup changed into calloc() and strcpy()
  66. * #define _POSIX_C_SOURCE 200809L
  67. */
  68. #include <stdio.h>
  69. #include <stdlib.h>
  70. #include <string.h>
  71. #include <errno.h>
  72. #include <math.h>
  73. #include <zlib.h>
  74. #ifdef HAVE_UNISTD_H
  75. #include <unistd.h> /* should have sync() */
  76. #endif
  77. /* math.h should have set this */
  78. #ifndef M_PI
  79. #define M_PI 3.141592
  80. #endif
  81. #include <gtk/gtk.h>
  82. #include <gdk/gdkkeysyms.h>
  83. #include <cairo.h>
  84. #include <cairo-svg.h>
  85. /* this should be the way check for glib version */
  86. #if GLIB_CHECK_VERSION (2,30,0)
  87. #ifdef WIN32
  88. #else
  89. #include <glib-unix.h>
  90. #endif
  91. #endif
  92. /* check for gtk versions */
  93. #if GTK_CHECK_VERSION (4,0,0)
  94. #elif GTK_CHECK_VERSION (3,0,0)
  95. #elif GTK_CHECK_VERSION (3,2,0)
  96. #elif GTK_CHECK_VERSION (3,4,0)
  97. #elif GTK_CHECK_VERSION (3,6,0)
  98. #elif GTK_CHECK_VERSION (3,8,0)
  99. #elif GTK_CHECK_VERSION (3,12,0)
  100. #elif GTK_CHECK_VERSION (3,14,0)
  101. #elif GTK_CHECK_VERSION (2,0,0)
  102. #elif GTK_CHECK_VERSION (1,0,0)
  103. #else
  104. /* assume gtk-2 */
  105. #endif
  106. #include "splay-tree.h"
  107. #include "main.h"
  108. #include "hier.h"
  109. #include "uniqnode.h"
  110. #include "uniqstr.h"
  111. #include "uniqgraph.h"
  112. #include "bubbling.h"
  113. #include "sugi.h"
  114. #include "pos.h"
  115. #include "posz.h"
  116. #include "gml_scanner.h"
  117. #include "gml_parser.h"
  118. #include "dpif.h"
  119. #include "dot.tab.h"
  120. #include "vcg.h"
  121. #include "jgf.h"
  122. #include "bgv.h"
  123. #include "dpmem.h"
  124. /* todo the pango font routines can be improved */
  125. /*
  126. * a GTK font pattern. These have the syntax
  127. * fontname [properties] [fontsize]
  128. *
  129. * where fontname is the family name,
  130. * properties is a list of property values separated by spaces,
  131. * and fontsize is the point size.
  132. * The properties that you may specify for GTK font patterns are as follows:
  133. * Slant properties: ‘Italic’ or ‘Oblique’. If omitted, the default (roman) slant is implied.
  134. * Weight properties: ‘Bold’, ‘Book’, ‘Light’, ‘Medium’, ‘Semi-bold’, or ‘Ultra-light’. If omitted, ‘Medium’ weight is implied.
  135. * Width properties: ‘Semi-Condensed’ or ‘Condensed’. If omitted, a default width is used.
  136. * Here are some examples of GTK font patterns:
  137. * Monospace 12
  138. * Monospace Bold Italic 12
  139. */
  140. #if 0 /* this does not work yet for windows, todo */
  141. #ifdef WIN32
  142. /* pango on wine has issues with font options, so use only a font name */
  143. /* name of font to use, example "Sans" */
  144. #define DEFAULT_FONTNAME "sans"
  145. /* name of slant to use, example "Italic", "Oblique" or "Roman" */
  146. #define DEFAULT_FONTSLANT " "
  147. /* name of weight to use, example "Bold", "Book", "Light", "Medium", "Semi-bold", "Ultra-light" */
  148. #define DEFAULT_FONTWEIGHT " "
  149. /* name of condensed to use, example "Semi-Condensed", "Condensed" */
  150. #define DEFAULT_FONTCONDENSED " "
  151. /* font size to use, example "10", "18", "20" etc. */
  152. #define DEFAULT_FONTSIZE "14"
  153. #define DEFAULT_FONTSIZE_INT 14
  154. #endif
  155. #endif
  156. /* Linux defaults */
  157. /* name of font to use, example "Sans" */
  158. #define DEFAULT_FONTNAME "sans"
  159. /* name of slant to use, example "Italic", "Oblique" or "Roman" */
  160. #define DEFAULT_FONTSLANT "roman"
  161. /* name of weight to use, example "Bold", "Book", "Light", "Medium", "Semi-bold", "Ultra-light" */
  162. #define DEFAULT_FONTWEIGHT "light"
  163. /* name of condensed to use, example "Semi-Condensed", "Condensed" */
  164. #define DEFAULT_FONTCONDENSED "condensed"
  165. /* font size to use, example "10", "18", "20" etc. */
  166. #define DEFAULT_FONTSIZE "12"
  167. #define DEFAULT_FONTSIZE_INT 12
  168. /* edge line thickness double value for example 0.5, 1.0, 1.5 */
  169. #define DEFAULT_EDGE_THICKNESS 1.0
  170. /* pixels in padding for gtk_box_pack try values 0, 1, 5, 20 */
  171. #define PACKPADDING 0
  172. /* window initial (x,y) size in pixels */
  173. #define TOP_LEVEL_WINDOW_XSIZE 800
  174. #define TOP_LEVEL_WINDOW_YSIZE 650
  175. /* probed once to check if pango lib support markup overline="single" attribute */
  176. static int pango_overline = -1;
  177. /* last open/save dir */
  178. static char *lastopendir = NULL;
  179. static char *lastsavedir = NULL;
  180. /* main argv[0] */
  181. static char *argv0 = NULL;
  182. /* debug output to stdout */
  183. static int option_gdebug = 0; /* 0,1,2 */
  184. /* draw edgelines as soft splines */
  185. static int option_splines = 1;
  186. /* exposed size of draw area */
  187. static int drawing_area_xsize = 0;
  188. static int drawing_area_ysize = 0;
  189. /* set if there is data to draw */
  190. static int validdata = 0;
  191. /* r/g/b of drawing alt color "grey82" */
  192. static int altr = 0xd1;
  193. static int altg = 0xd1;
  194. static int altb = 0xd1;
  195. /* zoom scaling factor changed by zoom slider */
  196. static double zfactor = 1.0;
  197. /* x offset changed by x slider */
  198. static int vxmin = 0;
  199. /* y offset changed by y slider */
  200. static int vymin = 0;
  201. /* top level window also used in maingtk2.c */
  202. static GtkWidget *mainwindow1 = (GtkWidget *) 0;
  203. /* where to draw */
  204. static GtkWidget *drawingarea1 = (GtkWidget *) 0;
  205. /* popup level window also used in maingtk2.c */
  206. static GtkWidget *popupwindow1 = (GtkWidget *) 0;
  207. /* position mode button */
  208. static GtkWidget *posbutton = (GtkWidget *) 0;
  209. /* edge labels */
  210. static GtkWidget *elabel1 = (GtkWidget *) 0;
  211. /* status line gtk buffers */
  212. static GtkTextBuffer *entry1buffer = NULL;
  213. static char charentry1buffer[80];
  214. /* old mouse (x,y) left button clicked used for dragging drawing */
  215. static int mouse_oldx = 0;
  216. static int mouse_oldy = 0;
  217. /* if set, draw dummy nodes */
  218. static int option_drawdummy = 0;
  219. /* gtk-0 can be re-compiled as mini-gtk also for freedos */
  220. #if (GTK_HAVE_API_VERSION_0 == 1)
  221. #warning "gtk-0 not implemented"
  222. #endif
  223. /* gtk-1 re-compile failed and looks to have 64bits issues */
  224. #if (GTK_HAVE_API_VERSION_1 == 1)
  225. #warning "gtk-1 not implemented"
  226. #endif
  227. /* sliders */
  228. #if (GTK_HAVE_API_VERSION_2 == 1)
  229. static GtkObject *adjvscale1 = NULL; /* left vertical zoom slider */
  230. static GtkObject *adjvscale2 = NULL;
  231. static GtkObject *adjhscale1 = NULL;
  232. #endif
  233. #if (GTK_HAVE_API_VERSION_3 == 1)
  234. static GtkAdjustment *adjvscale1 = NULL; /* left vertical zoom slider */
  235. static GtkAdjustment *adjvscale2 = NULL;
  236. static GtkAdjustment *adjhscale1 = NULL;
  237. #endif
  238. #if (GTK_HAVE_API_VERSION_4 == 1)
  239. static GtkAdjustment *adjvscale1 = NULL; /* left vertical zoom slider */
  240. static GtkAdjustment *adjvscale2 = NULL;
  241. static GtkAdjustment *adjhscale1 = NULL;
  242. #endif
  243. /* forward decl. */
  244. static void do_clear_all(int mode);
  245. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  246. static void top_level_window_main_quit(void);
  247. static void on_top_level_window_open1_activate(GtkMenuItem * menuitem, gpointer user_data);
  248. static void on_top_level_window_open2_activate(GtkMenuItem * menuitem, gpointer user_data);
  249. static void on_top_level_window_open3_activate(GtkMenuItem * menuitem, gpointer user_data);
  250. static void on_top_level_window_open4_activate(GtkMenuItem * menuitem, gpointer user_data);
  251. static void on_top_level_window_open5_activate(GtkMenuItem * menuitem, gpointer user_data);
  252. static void on_top_level_window_svg1_activate(GtkMenuItem * menuitem, gpointer user_data);
  253. static void on_top_level_window_dia1_activate(GtkMenuItem * menuitem, gpointer user_data);
  254. static void on_top_level_window_jgf1_activate(GtkMenuItem * menuitem, gpointer user_data);
  255. static void on_top_level_window_quit1_activate(GtkMenuItem * menuitem, gpointer user_data);
  256. static void on_top_level_window_fullscreen1_activate(GtkMenuItem * menuitem, gpointer user_data);
  257. static void on_top_level_window_unfullscreen1_activate(GtkMenuItem * menuitem, gpointer user_data);
  258. #ifdef WIN32
  259. /* product activation for windows */
  260. static void on_top_level_window_activate1_activate(GtkMenuItem * menuitem, gpointer user_data);
  261. #endif
  262. #endif
  263. static void xspin_changed(GtkWidget * widget, gpointer spinbutton);
  264. static void yspin_changed(GtkWidget * widget, gpointer spinbutton);
  265. static void pos_changed(GtkWidget * widget, gpointer spinbutton);
  266. static void bary_changed(GtkWidget * widget, gpointer spinbutton);
  267. static void rank_changed(GtkWidget * widget, gpointer spinbutton);
  268. static void check1_toggle(GtkWidget * widget, gpointer window);
  269. static void dummy1_toggle(GtkWidget * widget, gpointer window);
  270. static void elabel1_toggle(GtkWidget * widget, gpointer window);
  271. static void label1_toggle(GtkWidget * widget, gpointer window);
  272. static void nnames1_toggle(GtkWidget * widget, gpointer window);
  273. static void popup1_toggle(GtkWidget * widget, gpointer window);
  274. static void mirrory1_toggle(GtkWidget * widget, gpointer window);
  275. static void on_top_level_window_drawingarea1_expose_event_edges(cairo_t * crp);
  276. static void on_top_level_window_drawingarea1_expose_event_nodes_record_r(cairo_t * crp, struct gml_node
  277. *node, struct gml_rl
  278. *info);
  279. static void on_top_level_window_drawingarea1_expose_event_nodes_record(cairo_t * crp, struct gml_node
  280. *node);
  281. static void on_top_level_window_drawingarea1_expose_event_nodes_html(cairo_t * crp, struct gml_node
  282. *node);
  283. static void on_top_level_window_drawingarea1_expose_event_nodes(cairo_t * crp);
  284. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  285. static void show_about(GtkWidget * widget, gpointer data);
  286. #endif
  287. /* show about with ok button */
  288. static void show_about_bare(void);
  289. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  290. /* left slider */
  291. static void on_vscale1_changed(GtkAdjustment * adj);
  292. /* right slider */
  293. static void on_vscale2_changed(GtkAdjustment * adj);
  294. /* bottom slider */
  295. static void on_hscale1_changed(GtkAdjustment * adj);
  296. #endif
  297. #if (GTK_HAVE_API_VERSION_4 == 1)
  298. /* left slider */
  299. static void on_vscale1_changed(GtkAdjustment * adj, gpointer data);
  300. /* right slider */
  301. static void on_vscale2_changed(GtkAdjustment * adj, gpointer data);
  302. /* bottom slider */
  303. static void on_hscale1_changed(GtkAdjustment * adj, gpointer data);
  304. #endif
  305. #if GTK_HAVE_API_VERSION_2 == 1
  306. /* redraw drawing area */
  307. static gboolean on_top_level_window_drawingarea1_expose_event(GtkWidget * widget, GdkEventExpose * event, gpointer user_data);
  308. #endif
  309. #if GTK_HAVE_API_VERSION_3 == 1
  310. /* redraw drawing area */
  311. static gboolean on_top_level_window_drawingarea1_draw_event(GtkWidget * widget, cairo_t * crdraw, gpointer user_data);
  312. #endif
  313. #if GTK_HAVE_API_VERSION_2 == 1
  314. /* redraw drawing area */
  315. static gboolean popuparea1_expose_event(GtkWidget * widget, GdkEventExpose * event, gpointer user_data);
  316. #endif
  317. #if GTK_HAVE_API_VERSION_3 == 1
  318. /* redraw drawing area */
  319. static gboolean popuparea1_draw_event(GtkWidget * widget, cairo_t * crdraw, gpointer user_data);
  320. #endif
  321. /* fit drawing in window */
  322. static void dofit(void);
  323. static void do_layout_all(struct gml_graph *g);
  324. static void do_relayout_all(struct gml_graph *g);
  325. static void finalxy(struct gml_graph *g);
  326. static struct gml_p *static_maingtk_textsizes1sz(struct gml_rl *info);
  327. static void static_maingtk_textsizes1rl(struct gml_rl *info);
  328. static void static_maingtk_textsizes1eq(struct gml_rl *info);
  329. static void static_maingtk_textsizes2rl(struct gml_rl *info, int count, int xoff, int yoff, int bbx, int bby);
  330. static void static_maingtk_textsizes1n(struct gml_node *node);
  331. static void static_maingtk_textsizes(void);
  332. static void update_status_text(char *text);
  333. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  334. static gboolean on_mouse_clicked(GtkWidget * widget, GdkEventButton * event, gpointer user_data);
  335. static gboolean on_motion_notify_event(GtkWidget * widget, GdkEventMotion * event);
  336. #endif
  337. #if (GTK_HAVE_API_VERSION_4 == 1)
  338. static void on_motion_notify_event(GtkEventControllerMotion * controller, double x, double y, GtkWidget * widget);
  339. #endif
  340. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  341. static void sliders_default(void)
  342. {
  343. zfactor = 1.0;
  344. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale1), 50);
  345. vxmin = 0;
  346. vymin = 0;
  347. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale2), 0);
  348. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjhscale1), 0);
  349. return;
  350. }
  351. #endif
  352. #if (GTK_HAVE_API_VERSION_4 == 1)
  353. static void sliders_default(void)
  354. {
  355. zfactor = 1.0;
  356. vxmin = 0;
  357. vymin = 0;
  358. return;
  359. }
  360. #endif
  361. static int initialfiles(int argc, char *argv[])
  362. {
  363. char *s = NULL;
  364. char *fnam = NULL;
  365. gzFile fgv = (gzFile) 0;
  366. gzFile fgml = (gzFile) 0;
  367. gzFile fvcg = (gzFile) 0;
  368. /* check for optinal gml file on commandline
  369. * on commandline file.gml.gz is supported
  370. * but not dot.gz or vcg.gz
  371. */
  372. if (argc > 1) {
  373. fnam = argv[1];
  374. if ((*fnam) != '-') {
  375. /* find the last '.'
  376. * if (strcmp(s, ".gz") == 0)
  377. * then it is gzipped, but need to know the part before
  378. */
  379. s = strrchr(fnam, '.');
  380. if (s) {
  381. /*
  382. * switch between dot or gml or vcg parser
  383. * gcc generates vcg file with file extention .ci
  384. */
  385. if ((strcmp(s, ".vcg") == 0) || (strcmp(s, ".ci") == 0)) {
  386. /* assume this is a gcc vcg file */
  387. fvcg = gzopen(fnam, "r");
  388. if (fvcg) {
  389. /* type of graph data 0=gml 1=dot 2=vcg */
  390. graphtype = 2;
  391. /* create root graph */
  392. create_maingraph();
  393. /* parse the data */
  394. if (vcgparse(maingraph, fvcg, fnam, argv0)) {
  395. /* parse error */
  396. if (strlen(parsermessage) == 0) {
  397. strcpy(parsermessage, "no parser message");
  398. }
  399. printf("%s\n", parsermessage);
  400. fflush(stdout);
  401. gzclose(fvcg);
  402. /* data is invalid at this point */
  403. validdata = 0;
  404. } else {
  405. /* check for empty graph here */
  406. if (maingraph->rawnodelist) {
  407. /* update status text */
  408. update_status_text("Wait ... Calculating Layout");
  409. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  410. while (gtk_events_pending()) {
  411. gtk_main_iteration();
  412. /* this updates the status text */
  413. }
  414. #endif
  415. do_layout_all(maingraph);
  416. /* update status text */
  417. update_status_text(NULL);
  418. /* set sliders to defaults */
  419. sliders_default();
  420. drawing_area_xsize = TOP_LEVEL_WINDOW_XSIZE;
  421. drawing_area_ysize = TOP_LEVEL_WINDOW_YSIZE;
  422. /* fit drawing in window */
  423. dofit();
  424. validdata = 1;
  425. } else {
  426. /* update status text */
  427. update_status_text("Empty graph ... No Nodes");
  428. validdata = 0;
  429. }
  430. }
  431. gzclose(fvcg);
  432. } else {
  433. printf("%s(): cannot open `%s' file for reading\n", __func__, fnam);
  434. fflush(stdout);
  435. }
  436. /* end of vcg file at start */
  437. } else if ((strcmp(s, ".dot") == 0) || (strcmp(s, ".gv") == 0)) {
  438. /* assume this is a dot file */
  439. fgv = gzopen(fnam, "r");
  440. if (fgv) {
  441. /* type of graph data 0=gml 1=dot 2=vcg */
  442. graphtype = 1;
  443. /* create root graph */
  444. create_maingraph();
  445. /* parse the data */
  446. if (dotparse(maingraph, fgv, fnam, argv0)) {
  447. /* parse error */
  448. if (strlen(parsermessage) == 0) {
  449. strcpy(parsermessage, "no parser message");
  450. }
  451. printf("%s\n", parsermessage);
  452. fflush(stdout);
  453. gzclose(fgv);
  454. /* data is invalid at this point */
  455. validdata = 0;
  456. } else {
  457. /* check for empty graph here */
  458. if (maingraph->rawnodelist) {
  459. /* update status text */
  460. update_status_text("Wait ... Calculating Layout");
  461. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  462. while (gtk_events_pending()) {
  463. gtk_main_iteration();
  464. /* this updates the status text */
  465. }
  466. #endif
  467. do_layout_all(maingraph);
  468. /* update status text */
  469. update_status_text(NULL);
  470. /* set sliders to defaults */
  471. sliders_default();
  472. drawing_area_xsize = TOP_LEVEL_WINDOW_XSIZE;
  473. drawing_area_ysize = TOP_LEVEL_WINDOW_YSIZE;
  474. /* fit drawing in window */
  475. dofit();
  476. validdata = 1;
  477. } else {
  478. /* update status text */
  479. update_status_text("Empty graph ... No Nodes");
  480. validdata = 0;
  481. }
  482. }
  483. gzclose(fgv);
  484. } else {
  485. printf("%s(): cannot open `%s' file for reading\n", __func__, fnam);
  486. fflush(stdout);
  487. }
  488. /* end of dot file at start */
  489. } else {
  490. /* assume gml file */
  491. fgml = gzopen(fnam, "r");
  492. if (fgml) {
  493. /* type of graph data 0=gml 1=dot 2=vcg */
  494. graphtype = 0;
  495. /* create root graph */
  496. create_maingraph();
  497. /* parse the gml data */
  498. if (gmlparse(maingraph, fgml, fnam, argv0)) {
  499. /* parse error */
  500. if (strlen(parsermessage) == 0) {
  501. strcpy(parsermessage, "no parser message");
  502. }
  503. printf("%s\n", parsermessage);
  504. fflush(stdout);
  505. gzclose(fgml);
  506. /* data is invalid at this point */
  507. validdata = 0;
  508. } else {
  509. /* check for empty graph here */
  510. if (maingraph->rawnodelist) {
  511. /* update status text */
  512. update_status_text("Wait ... Calculating Layout");
  513. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  514. while (gtk_events_pending()) {
  515. gtk_main_iteration();
  516. /* this updates the status text */
  517. }
  518. #endif
  519. do_layout_all(maingraph);
  520. /* update status text */
  521. update_status_text(NULL);
  522. /* set sliders to defaults */
  523. sliders_default();
  524. drawing_area_xsize = TOP_LEVEL_WINDOW_XSIZE;
  525. drawing_area_ysize = TOP_LEVEL_WINDOW_YSIZE;
  526. /* fit drawing in window */
  527. dofit();
  528. validdata = 1;
  529. } else {
  530. /* update status text */
  531. update_status_text("Empty graph ... No Nodes");
  532. validdata = 0;
  533. }
  534. }
  535. gzclose(fgml);
  536. } else {
  537. printf("%s(): cannot open `%s' file for reading\n", __func__, fnam);
  538. fflush(stdout);
  539. }
  540. /* end of gml file at start */
  541. }
  542. }
  543. }
  544. }
  545. return (0);
  546. }
  547. #if (GTK_HAVE_API_VERSION_4 == 1)
  548. static void set_current_folder(GtkFileChooser * chooser, const char *name);
  549. static void fullscreen_changed(GSimpleAction * action, GVariant * value, gpointer win);
  550. static void on_top_level_window_quit1_activate(GSimpleAction * action, GVariant * paramter, gpointer user_data);
  551. /* open dot decl. */
  552. static void open1_activated(GSimpleAction * action, GVariant * parameter, gpointer app);
  553. /* open gml */
  554. static void open2_activated(GSimpleAction * action, GVariant * parameter, gpointer app);
  555. /* open vcg */
  556. static void open3_activated(GSimpleAction * action, GVariant * parameter, gpointer app);
  557. /* open jgf */
  558. static void open4_activated(GSimpleAction * action, GVariant * parameter, gpointer app);
  559. /* open bgv */
  560. static void open5_activated(GSimpleAction * action, GVariant * parameter, gpointer app);
  561. /* save svg */
  562. static void save1_activated(GSimpleAction * action, GVariant * parameter, gpointer app);
  563. /* save dia xml */
  564. static void save2_activated(GSimpleAction * action, GVariant * parameter, gpointer app);
  565. /* save json jgf data */
  566. static void save3_activated(GSimpleAction * action, GVariant * parameter, gpointer app);
  567. /* show about box with gtk lib info */
  568. static void about_activated(GSimpleAction * action, GVariant * parameter, gpointer app)
  569. {
  570. if (action) {
  571. }
  572. if (parameter) {
  573. }
  574. if (app) {
  575. }
  576. show_about_bare();
  577. return;
  578. }
  579. /* draw on screen */
  580. static void draw_function_for_gtk4(GtkDrawingArea * area, cairo_t * cr, int width, int height, gpointer user_data);
  581. /* draw on pupup window */
  582. static void popuparea1_draw_event_for_gtk4(GtkDrawingArea * area, cairo_t * crdraw, int width, int height, gpointer user_data);
  583. /* start the gtk-4 gui
  584. * this gui is manual crafted and does not depend on builder software or external files
  585. * then it should be more sure long term maintance is possible
  586. * it can be manual extended and is easier then expected
  587. */
  588. static int maingtk4_activate(GApplication * app, gpointer * user_data)
  589. {
  590. GtkWidget *vbox1 = NULL;
  591. GtkWidget *hbox1 = NULL;
  592. GtkWidget *vbox2 = NULL;
  593. GtkWidget *hbox2 = NULL;
  594. GtkWidget *vscale1 = NULL;
  595. GtkWidget *vscale2 = NULL;
  596. GtkWidget *hscale1 = NULL;
  597. GtkWidget *vbox3 = NULL;
  598. GtkWidget *hbox3 = NULL;
  599. GtkWidget *xspinlabel = NULL;
  600. GtkWidget *xspinbutton = NULL;
  601. GtkWidget *yspinlabel = NULL;
  602. GtkWidget *yspinbutton = NULL;
  603. GtkWidget *pos1 = NULL;
  604. /* GtkWidget *posbutton is global */
  605. GtkWidget *check1 = NULL;
  606. GtkWidget *dummy1 = NULL;
  607. GtkWidget *entry1 = NULL;
  608. GtkWidget *vbox4 = NULL;
  609. GtkWidget *hbox4 = NULL;
  610. GtkWidget *rank1 = NULL;
  611. GtkWidget *rankbutton = NULL;
  612. GtkWidget *barylabel = NULL;
  613. GtkWidget *barybutton = NULL;
  614. /* GtkWidget *elabel1 = NULL; is global */
  615. GtkWidget *label1 = NULL;
  616. GtkWidget *nnames1 = NULL;
  617. GtkWidget *popup1 = NULL;
  618. GtkWidget *mirrory1 = NULL;
  619. GtkEventController *controller = NULL;
  620. if (user_data) {
  621. }
  622. /* create main window */
  623. mainwindow1 = gtk_application_window_new(GTK_APPLICATION(app));
  624. /* use package string program name as set by configure in config.h */
  625. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  626. /* pre-set some size */
  627. gtk_window_set_default_size(GTK_WINDOW(mainwindow1), TOP_LEVEL_WINDOW_XSIZE, TOP_LEVEL_WINDOW_YSIZE);
  628. GSimpleAction *act_open1 = g_simple_action_new("open1", NULL);
  629. GSimpleAction *act_open2 = g_simple_action_new("open2", NULL);
  630. GSimpleAction *act_open3 = g_simple_action_new("open3", NULL);
  631. GSimpleAction *act_open4 = g_simple_action_new("open4", NULL);
  632. GSimpleAction *act_open5 = g_simple_action_new("open5", NULL);
  633. GSimpleAction *act_save1 = g_simple_action_new("save1", NULL);
  634. GSimpleAction *act_save2 = g_simple_action_new("save2", NULL);
  635. GSimpleAction *act_save3 = g_simple_action_new("save3", NULL);
  636. GSimpleAction *act_about = g_simple_action_new("about", NULL);
  637. GSimpleAction *act_fullscreen = g_simple_action_new_stateful("fullscreen", NULL, g_variant_new_boolean(FALSE));
  638. GSimpleAction *act_quit = g_simple_action_new("quit", NULL);
  639. GMenu *menubar = g_menu_new();
  640. GMenu *menu = g_menu_new();
  641. GMenu *section1 = g_menu_new();
  642. GMenuItem *menu_item_opendot = g_menu_item_new("Open dot", "win.open1");
  643. GMenuItem *menu_item_opengml = g_menu_item_new("Open gml", "win.open2");
  644. GMenuItem *menu_item_openvcg = g_menu_item_new("Open ci", "win.open3");
  645. GMenuItem *menu_item_openjgf = g_menu_item_new("Open jgf", "win.open4");
  646. GMenuItem *menu_item_openbgv = g_menu_item_new("Open bgv", "win.open5");
  647. GMenuItem *menu_item_savesvg = g_menu_item_new("Save svg", "win.save1");
  648. GMenuItem *menu_item_savedia = g_menu_item_new("Save dia", "win.save2");
  649. GMenuItem *menu_item_savejgf = g_menu_item_new("Save jgf", "win.save3");
  650. GMenuItem *menu_item_about = g_menu_item_new("About", "win.about");
  651. GMenuItem *menu_item_fullscreen = g_menu_item_new("Full Screen", "win.fullscreen");
  652. GMenuItem *menu_item_quit = g_menu_item_new("Quit", "app.quit");
  653. g_signal_connect(act_fullscreen, "change-state", G_CALLBACK(fullscreen_changed), mainwindow1);
  654. g_signal_connect(act_open1, "activate", G_CALLBACK(open1_activated), app); /* open dot */
  655. g_signal_connect(act_open2, "activate", G_CALLBACK(open2_activated), app); /* open gml */
  656. g_signal_connect(act_open3, "activate", G_CALLBACK(open3_activated), app); /* open vcg */
  657. g_signal_connect(act_open4, "activate", G_CALLBACK(open4_activated), app); /* open jgf */
  658. g_signal_connect(act_open5, "activate", G_CALLBACK(open5_activated), app); /* open bgv */
  659. g_signal_connect(act_save1, "activate", G_CALLBACK(save1_activated), app); /* save svg */
  660. g_signal_connect(act_save2, "activate", G_CALLBACK(save2_activated), app); /* save dia xml */
  661. g_signal_connect(act_save3, "activate", G_CALLBACK(save3_activated), app); /* save json jgf data */
  662. g_signal_connect(act_about, "activate", G_CALLBACK(about_activated), app);
  663. g_signal_connect(act_quit, "activate", G_CALLBACK(on_top_level_window_quit1_activate), app);
  664. g_action_map_add_action(G_ACTION_MAP(mainwindow1), G_ACTION(act_open1)); /* open dot */
  665. g_action_map_add_action(G_ACTION_MAP(mainwindow1), G_ACTION(act_open2)); /* open gml */
  666. g_action_map_add_action(G_ACTION_MAP(mainwindow1), G_ACTION(act_open3)); /* open vcg */
  667. g_action_map_add_action(G_ACTION_MAP(mainwindow1), G_ACTION(act_open4)); /* open jgf */
  668. g_action_map_add_action(G_ACTION_MAP(mainwindow1), G_ACTION(act_open5)); /* open bgv */
  669. g_action_map_add_action(G_ACTION_MAP(mainwindow1), G_ACTION(act_save1)); /* save svg */
  670. g_action_map_add_action(G_ACTION_MAP(mainwindow1), G_ACTION(act_save2)); /* save dia xml */
  671. g_action_map_add_action(G_ACTION_MAP(mainwindow1), G_ACTION(act_save3)); /* save json jgf data */
  672. g_action_map_add_action(G_ACTION_MAP(mainwindow1), G_ACTION(act_about));
  673. g_action_map_add_action(G_ACTION_MAP(mainwindow1), G_ACTION(act_fullscreen));
  674. g_action_map_add_action(G_ACTION_MAP(app), G_ACTION(act_quit));
  675. /* open graph data */
  676. g_menu_append_item(section1, menu_item_opendot);
  677. g_menu_append_item(section1, menu_item_opengml);
  678. g_menu_append_item(section1, menu_item_openvcg);
  679. g_menu_append_item(section1, menu_item_openjgf);
  680. g_menu_append_item(section1, menu_item_openbgv);
  681. /* save drawing */
  682. g_menu_append_item(section1, menu_item_savesvg);
  683. g_menu_append_item(section1, menu_item_savedia);
  684. g_menu_append_item(section1, menu_item_savejgf);
  685. /* others */
  686. g_menu_append_item(section1, menu_item_about);
  687. g_menu_append_item(section1, menu_item_fullscreen);
  688. g_menu_append_item(section1, menu_item_quit);
  689. g_object_unref(menu_item_about);
  690. g_object_unref(menu_item_fullscreen);
  691. g_object_unref(menu_item_savesvg);
  692. g_object_unref(menu_item_savedia);
  693. g_object_unref(menu_item_savejgf);
  694. g_object_unref(menu_item_opendot);
  695. g_object_unref(menu_item_opengml);
  696. g_object_unref(menu_item_openvcg);
  697. g_object_unref(menu_item_openjgf);
  698. g_object_unref(menu_item_openbgv);
  699. g_object_unref(menu_item_quit);
  700. g_menu_append_section(menu, NULL, G_MENU_MODEL(section1));
  701. g_menu_append_submenu(menubar, "File", G_MENU_MODEL(menu));
  702. gtk_application_set_menubar(GTK_APPLICATION(app), G_MENU_MODEL(menubar));
  703. gtk_application_window_set_show_menubar(GTK_APPLICATION_WINDOW(mainwindow1), TRUE);
  704. /* next vertical area for slider and drawing are */
  705. vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, /* spacing */ 0);
  706. gtk_widget_set_vexpand(vbox1, TRUE);
  707. gtk_window_set_child(GTK_WINDOW(mainwindow1), vbox1);
  708. hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, /* spacing */ 0);
  709. gtk_widget_set_hexpand(hbox1, TRUE);
  710. gtk_box_append(GTK_BOX(vbox1), hbox1);
  711. /*
  712. * in hbox1
  713. * left zoom slider
  714. * drawing area
  715. * right y slider
  716. * below x slider
  717. */
  718. /* add next area to the vbox1 */
  719. /* vertical slider in hbox1 for the zoom factor 50% is 1:1 */
  720. adjvscale1 = gtk_adjustment_new(50, 0, 100, 0, 0, 0);
  721. vscale1 = gtk_scale_new(GTK_ORIENTATION_VERTICAL, adjvscale1);
  722. /* stretch slider vertical */
  723. gtk_widget_set_vexpand(vscale1, TRUE);
  724. /* slider routine */
  725. g_signal_connect(G_OBJECT(adjvscale1), "value-changed", G_CALLBACK(on_vscale1_changed), NULL);
  726. gtk_box_append(GTK_BOX(hbox1), vscale1);
  727. /* where to draw in hbox1 */
  728. drawingarea1 = gtk_drawing_area_new();
  729. /* stretch maximal */
  730. gtk_widget_set_vexpand(drawingarea1, TRUE);
  731. gtk_widget_set_hexpand(drawingarea1, TRUE);
  732. /* add routines for drawing */
  733. gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(drawingarea1), draw_function_for_gtk4, NULL, NULL);
  734. gtk_box_append(GTK_BOX(hbox1), drawingarea1);
  735. /* add motion routine in the drawingarea */
  736. controller = gtk_event_controller_motion_new();
  737. g_signal_connect(G_OBJECT(controller), "motion", G_CALLBACK(on_motion_notify_event), NULL);
  738. gtk_widget_add_controller(GTK_WIDGET(drawingarea1), controller);
  739. /* at right vertical slider in hbox1 for the y position range 0...100% of full image size */
  740. adjvscale2 = gtk_adjustment_new(0, 0, 100, 0, 0, 0);
  741. vscale2 = gtk_scale_new(GTK_ORIENTATION_VERTICAL, adjvscale2);
  742. /* stretch slider vertical */
  743. gtk_widget_set_vexpand(vscale2, TRUE);
  744. /* add slider */
  745. g_signal_connect(G_OBJECT(adjvscale2), "value-changed", G_CALLBACK(on_vscale2_changed), NULL);
  746. gtk_box_append(GTK_BOX(hbox1), vscale2);
  747. /* next vertical area for horizontal slider */
  748. vbox2 = gtk_box_new(GTK_ORIENTATION_VERTICAL, /* spacing */ 0);
  749. gtk_widget_set_vexpand(vbox2, FALSE);
  750. gtk_box_append(GTK_BOX(vbox1), vbox2);
  751. hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, /* spacing */ 0);
  752. gtk_widget_set_hexpand(hbox2, TRUE);
  753. gtk_box_append(GTK_BOX(vbox2), hbox2);
  754. /* add horizontal slider */
  755. /* horizontal scroller 0..100% of drawing size */
  756. adjhscale1 = gtk_adjustment_new(0, 0, 100, 0, 0, 0);
  757. hscale1 = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, adjhscale1);
  758. /* stretch slider */
  759. gtk_widget_set_hexpand(hscale1, TRUE);
  760. /* slider routine */
  761. g_signal_connect(G_OBJECT(adjhscale1), "value-changed", G_CALLBACK(on_hscale1_changed), NULL);
  762. gtk_box_append(GTK_BOX(hbox2), hscale1);
  763. /* next vertical area for options */
  764. vbox3 = gtk_box_new(GTK_ORIENTATION_VERTICAL, /* spacing */ 0);
  765. gtk_widget_set_vexpand(vbox3, FALSE);
  766. gtk_box_append(GTK_BOX(vbox2), vbox3);
  767. hbox3 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, /* spacing */ 0);
  768. gtk_widget_set_hexpand(hbox3, TRUE);
  769. gtk_box_append(GTK_BOX(vbox3), hbox3);
  770. /* add the options below the horizontal slider */
  771. /* stretch drawing in x dir */
  772. xspinlabel = gtk_label_new("dx");
  773. gtk_widget_set_tooltip_text(xspinlabel, "stretch drawing in x-direction");
  774. gtk_box_append(GTK_BOX(hbox3), xspinlabel);
  775. xspinbutton = gtk_spin_button_new_with_range(0, 99, 1);
  776. gtk_spin_button_set_value(GTK_SPIN_BUTTON(xspinbutton), (double)xspacing);
  777. g_signal_connect(G_OBJECT(xspinbutton), "value_changed", G_CALLBACK(xspin_changed), NULL);
  778. gtk_box_append(GTK_BOX(hbox3), xspinbutton);
  779. /* stretch drawing in y dir */
  780. yspinlabel = gtk_label_new("dy");
  781. gtk_widget_set_tooltip_text(yspinlabel, "stretch drawing in y-direction");
  782. gtk_box_append(GTK_BOX(hbox3), yspinlabel);
  783. yspinbutton = gtk_spin_button_new_with_range(0, 99, 1);
  784. gtk_spin_button_set_value(GTK_SPIN_BUTTON(yspinbutton), (double)yspacing);
  785. g_signal_connect(G_OBJECT(yspinbutton), "value_changed", G_CALLBACK(yspin_changed), NULL);
  786. gtk_box_append(GTK_BOX(hbox3), yspinbutton);
  787. /* at every click, advance positioning mode, the type of node placament */
  788. pos1 = gtk_label_new("pos");
  789. gtk_widget_set_tooltip_text(pos1, "positioning mode");
  790. gtk_box_append(GTK_BOX(hbox3), pos1);
  791. posbutton = gtk_spin_button_new_with_range(1, 4, 1);
  792. gtk_spin_button_set_value(GTK_SPIN_BUTTON(posbutton), (double)postype);
  793. g_signal_connect(G_OBJECT(posbutton), "value_changed", G_CALLBACK(pos_changed), NULL);
  794. gtk_box_append(GTK_BOX(hbox3), posbutton);
  795. /* draw spline edges or normal */
  796. check1 = gtk_check_button_new_with_label("splines");
  797. /* */
  798. if (option_splines) {
  799. gtk_check_button_set_active(GTK_CHECK_BUTTON(check1), TRUE);
  800. } else {
  801. gtk_check_button_set_active(GTK_CHECK_BUTTON(check1), FALSE);
  802. }
  803. gtk_widget_set_tooltip_text(check1, "edge line splines");
  804. /* routine */
  805. g_signal_connect(G_OBJECT(check1), "toggled", G_CALLBACK(check1_toggle), NULL);
  806. gtk_box_append(GTK_BOX(hbox3), check1);
  807. dummy1 = gtk_check_button_new_with_label("dummy's");
  808. /* */
  809. if (option_drawdummy) {
  810. gtk_check_button_set_active(GTK_CHECK_BUTTON(dummy1), TRUE);
  811. } else {
  812. gtk_check_button_set_active(GTK_CHECK_BUTTON(dummy1), FALSE);
  813. }
  814. gtk_widget_set_tooltip_text(dummy1, "show dummy nodes");
  815. /* routine */
  816. g_signal_connect(G_OBJECT(dummy1), "toggled", G_CALLBACK(dummy1_toggle), NULL);
  817. gtk_box_append(GTK_BOX(hbox3), dummy1);
  818. /* area with a text message */
  819. entry1 = gtk_text_view_new();
  820. gtk_widget_set_hexpand(entry1, TRUE);
  821. entry1buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry1));
  822. gtk_text_buffer_set_text(entry1buffer, "GML4GTK is GNU GPL free software to copy, share and improve", -1);
  823. gtk_text_view_set_editable(GTK_TEXT_VIEW(entry1), FALSE);
  824. gtk_widget_set_tooltip_text(entry1, "status information");
  825. /* monospace font for the text messages and font can be changed */
  826. gtk_text_view_set_monospace(GTK_TEXT_VIEW(entry1), TRUE);
  827. /* todo add routines */
  828. gtk_box_append(GTK_BOX(hbox3), entry1);
  829. /* next vertical area for options */
  830. vbox4 = gtk_box_new(GTK_ORIENTATION_VERTICAL, /* spacing */ 0);
  831. gtk_widget_set_vexpand(vbox4, FALSE);
  832. gtk_box_append(GTK_BOX(vbox3), vbox4);
  833. hbox4 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, /* spacing */ 0);
  834. gtk_widget_set_hexpand(hbox4, TRUE);
  835. gtk_box_append(GTK_BOX(vbox4), hbox4);
  836. /* add the options below */
  837. /* the type of vertical levels node placement */
  838. rank1 = gtk_label_new("rank");
  839. gtk_widget_set_tooltip_text(rank1, "dfs/bfs/topological levels");
  840. gtk_box_append(GTK_BOX(hbox4), rank1);
  841. /* spin to change rank type note that in gtk2 it is a (GtkObject *) and in gtk3 a (GtkAdjustment *) */
  842. rankbutton = gtk_spin_button_new_with_range(1, 3, 1);
  843. gtk_spin_button_set_value(GTK_SPIN_BUTTON(rankbutton), (double)ranktype);
  844. g_signal_connect(G_OBJECT(rankbutton), "value_changed", G_CALLBACK(rank_changed), NULL);
  845. gtk_box_append(GTK_BOX(hbox4), rankbutton);
  846. /* the type of barycenter to reduce edge crossings */
  847. barylabel = gtk_label_new("bary");
  848. gtk_widget_set_tooltip_text(barylabel, "barycenter type");
  849. gtk_box_append(GTK_BOX(hbox4), barylabel);
  850. /* spin to change barycenter type note that in gtk2 it is a (GtkObject *) and in gtk3 a (GtkAdjustment *) */
  851. barybutton = gtk_spin_button_new_with_range(1, 5, 1);
  852. gtk_spin_button_set_value(GTK_SPIN_BUTTON(barybutton), (double)barytype);
  853. g_signal_connect(G_OBJECT(barybutton), "value_changed", G_CALLBACK(bary_changed), NULL);
  854. gtk_box_append(GTK_BOX(hbox4), barybutton);
  855. /* edgelabels on/off */
  856. elabel1 = gtk_check_button_new_with_label("elabel");
  857. /* */
  858. if (option_edgelabels) {
  859. gtk_check_button_set_active(GTK_CHECK_BUTTON(elabel1), TRUE);
  860. } else {
  861. gtk_check_button_set_active(GTK_CHECK_BUTTON(elabel1), FALSE);
  862. }
  863. gtk_widget_set_tooltip_text(elabel1, "edgelabels on/off");
  864. /* routine */
  865. g_signal_connect(G_OBJECT(elabel1), "toggled", G_CALLBACK(elabel1_toggle), NULL);
  866. gtk_box_append(GTK_BOX(hbox4), elabel1);
  867. /* labels on/off */
  868. label1 = gtk_check_button_new_with_label("labels");
  869. /* */
  870. if (option_labels) {
  871. gtk_check_button_set_active(GTK_CHECK_BUTTON(label1), TRUE);
  872. } else {
  873. gtk_check_button_set_active(GTK_CHECK_BUTTON(label1), FALSE);
  874. }
  875. gtk_widget_set_tooltip_text(label1, "labels on/off");
  876. /* routine */
  877. g_signal_connect(G_OBJECT(label1), "toggled", G_CALLBACK(label1_toggle), NULL);
  878. gtk_box_append(GTK_BOX(hbox4), label1);
  879. /* node names on/off */
  880. nnames1 = gtk_check_button_new_with_label("names");
  881. /* */
  882. if (option_nnames) {
  883. gtk_check_button_set_active(GTK_CHECK_BUTTON(nnames1), TRUE);
  884. } else {
  885. gtk_check_button_set_active(GTK_CHECK_BUTTON(nnames1), FALSE);
  886. }
  887. gtk_widget_set_tooltip_text(nnames1, "node names instead of labels");
  888. /* routine */
  889. g_signal_connect(G_OBJECT(nnames1), "toggled", G_CALLBACK(nnames1_toggle), NULL);
  890. gtk_box_append(GTK_BOX(hbox4), nnames1);
  891. /* popup labels on/off */
  892. popup1 = gtk_check_button_new_with_label("popup");
  893. /* */
  894. if (option_popup) {
  895. gtk_check_button_set_active(GTK_CHECK_BUTTON(popup1), TRUE);
  896. } else {
  897. gtk_check_button_set_active(GTK_CHECK_BUTTON(popup1), FALSE);
  898. }
  899. gtk_widget_set_tooltip_text(popup1, "popup labels on/off");
  900. /* routine */
  901. g_signal_connect(G_OBJECT(popup1), "toggled", G_CALLBACK(popup1_toggle), NULL);
  902. gtk_box_append(GTK_BOX(hbox4), popup1);
  903. /* mirror y on/off */
  904. mirrory1 = gtk_check_button_new_with_label("mirror");
  905. /* */
  906. if (option_mirrory) {
  907. gtk_check_button_set_active(GTK_CHECK_BUTTON(mirrory1), TRUE);
  908. } else {
  909. gtk_check_button_set_active(GTK_CHECK_BUTTON(mirrory1), FALSE);
  910. }
  911. gtk_widget_set_tooltip_text(mirrory1, "mirror drawing in y direction");
  912. /* routine */
  913. g_signal_connect(G_OBJECT(mirrory1), "toggled", G_CALLBACK(mirrory1_toggle), NULL);
  914. gtk_box_append(GTK_BOX(hbox4), mirrory1);
  915. gtk_window_present(GTK_WINDOW(mainwindow1));
  916. return (0);
  917. }
  918. #endif
  919. #if (GTK_HAVE_API_VERSION_2 == 1 || GTK_HAVE_API_VERSION_3 == 1)
  920. int maingtk23(void)
  921. {
  922. GtkWidget *vbox1;
  923. GtkWidget *menubar1;
  924. GtkWidget *menuitem1;
  925. GtkWidget *menuitem1_menu;
  926. GtkWidget *open1; /* open gml file */
  927. GtkWidget *open2; /* open dot file */
  928. GtkWidget *open3; /* open vcg file */
  929. GtkWidget *open4; /* open jgf file */
  930. GtkWidget *open5; /* open bgv file */
  931. GtkWidget *svg1;
  932. GtkWidget *dia1;
  933. GtkWidget *jgf1;
  934. GtkWidget *about1;
  935. GtkWidget *quit1;
  936. GtkWidget *hbox1;
  937. GtkWidget *hbox2;
  938. GtkWidget *vscale1;
  939. GtkWidget *vscale2;
  940. GtkWidget *hscale1;
  941. GtkWidget *hbox3;
  942. GtkWidget *xspinlabel;
  943. GtkAdjustment *xspinadjustment;
  944. GtkWidget *xspinbutton;
  945. GtkWidget *yspinlabel;
  946. GtkAdjustment *yspinadjustment;
  947. GtkWidget *yspinbutton;
  948. GtkWidget *pos1;
  949. GtkAdjustment *posadjustment;
  950. GtkWidget *check1;
  951. GtkWidget *dummy1;
  952. GtkWidget *rank1;
  953. GtkAdjustment *rankadjustment;
  954. GtkWidget *rankbutton;
  955. GtkWidget *entry1;
  956. GtkWidget *barylabel;
  957. GtkAdjustment *baryadjustment;
  958. GtkWidget *barybutton;
  959. /* GtkWidget *elabel1; is global */
  960. GtkWidget *label1;
  961. GtkWidget *nnames1;
  962. GtkWidget *popup1;
  963. GtkWidget *mirrory1;
  964. GtkWidget *menuitem2;
  965. GtkWidget *menuitem2_menu;
  966. GtkWidget *fullscreen1;
  967. GtkWidget *unfullscreen1;
  968. #ifdef WIN32
  969. GtkWidget *activate1;
  970. #endif
  971. /* top level outer window */
  972. mainwindow1 = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  973. /* make sure to exit oke. */
  974. g_signal_connect(G_OBJECT(mainwindow1), "destroy", G_CALLBACK(top_level_window_main_quit), NULL);
  975. #if (GTK_HAVE_API_VERSION_2 == 1)
  976. /* needed for the cairo drawing */
  977. gtk_widget_set_app_paintable(mainwindow1, TRUE);
  978. #endif
  979. #if (GTK_HAVE_API_VERSION_3 == 1)
  980. /* set_app_paintable() here causes trouble with the gtk+-3 gui */
  981. #endif
  982. /* use package string program name as set by configure in config.h */
  983. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  984. /* pre-set some size */
  985. gtk_window_set_default_size(GTK_WINDOW(mainwindow1), TOP_LEVEL_WINDOW_XSIZE, TOP_LEVEL_WINDOW_YSIZE);
  986. /* --- */
  987. /* vbox1 is a menu bar */
  988. #if (GTK_HAVE_API_VERSION_2 == 1)
  989. vbox1 = gtk_vbox_new( /* homogeneous */ FALSE, /* spacing */ 0);
  990. #endif
  991. #if (GTK_HAVE_API_VERSION_3 == 1)
  992. vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, /* spacing */ 0);
  993. #endif
  994. gtk_container_add(GTK_CONTAINER(mainwindow1), vbox1);
  995. /* --- */
  996. /* menu bar in vbox1 */
  997. menubar1 = gtk_menu_bar_new();
  998. gtk_box_pack_start( /* box */ GTK_BOX(vbox1), /* child */ menubar1,
  999. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1000. PACKPADDING);
  1001. /* --- */
  1002. /* menu items in menu bar in vbox1 */
  1003. menuitem1 = gtk_menu_item_new_with_mnemonic("File");
  1004. gtk_container_add(GTK_CONTAINER(menubar1), menuitem1);
  1005. /* --- */
  1006. /* 'file' sub menu in menu items in menu bar in vbox1 */
  1007. menuitem1_menu = gtk_menu_new();
  1008. gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem1), menuitem1_menu);
  1009. /* --- */
  1010. /* 'open' in 'file' sub menu in menu items in menu bar in vbox1 */
  1011. open2 = gtk_menu_item_new_with_mnemonic("Open DOT graph");
  1012. gtk_container_add(GTK_CONTAINER(menuitem1_menu), open2);
  1013. /* run this routine when selected 'open' in 'file' menu */
  1014. g_signal_connect(G_OBJECT(open2), "activate", G_CALLBACK(on_top_level_window_open2_activate), NULL);
  1015. /* 'open' in 'file' sub menu in menu items in menu bar in vbox1 */
  1016. open1 = gtk_menu_item_new_with_mnemonic("Open GML graph");
  1017. gtk_container_add(GTK_CONTAINER(menuitem1_menu), open1);
  1018. /* run this routine when selected 'open' in 'file' menu */
  1019. g_signal_connect(G_OBJECT(open1), "activate", G_CALLBACK(on_top_level_window_open1_activate), NULL);
  1020. /* 'open' in 'file' sub menu in menu items in menu bar in vbox1 */
  1021. open3 = gtk_menu_item_new_with_mnemonic("Open CI graph");
  1022. gtk_container_add(GTK_CONTAINER(menuitem1_menu), open3);
  1023. /* run this routine when selected 'open' in 'file' menu */
  1024. g_signal_connect(G_OBJECT(open3), "activate", G_CALLBACK(on_top_level_window_open3_activate), NULL);
  1025. /* 'open' in 'file' sub menu in menu items in menu bar in vbox1 */
  1026. open4 = gtk_menu_item_new_with_mnemonic("Open JGF graph");
  1027. gtk_container_add(GTK_CONTAINER(menuitem1_menu), open4);
  1028. /* run this routine when selected 'open' in 'file' menu */
  1029. g_signal_connect(G_OBJECT(open4), "activate", G_CALLBACK(on_top_level_window_open4_activate), NULL);
  1030. /* 'open' in 'file' sub menu in menu items in menu bar in vbox1 */
  1031. open5 = gtk_menu_item_new_with_mnemonic("Open BGV graph");
  1032. gtk_container_add(GTK_CONTAINER(menuitem1_menu), open5);
  1033. /* run this routine when selected 'open' in 'file' menu */
  1034. g_signal_connect(G_OBJECT(open5), "activate", G_CALLBACK(on_top_level_window_open5_activate), NULL);
  1035. svg1 = gtk_menu_item_new_with_mnemonic("Save as SVG");
  1036. gtk_container_add(GTK_CONTAINER(menuitem1_menu), svg1);
  1037. /* run this routine when selected 'svg' in 'file' menu */
  1038. g_signal_connect(G_OBJECT(svg1), "activate", G_CALLBACK(on_top_level_window_svg1_activate), NULL);
  1039. dia1 = gtk_menu_item_new_with_mnemonic("Save as DIA");
  1040. gtk_container_add(GTK_CONTAINER(menuitem1_menu), dia1);
  1041. /* run this routine when selected 'dia' in 'file' menu */
  1042. g_signal_connect(G_OBJECT(dia1), "activate", G_CALLBACK(on_top_level_window_dia1_activate), NULL);
  1043. jgf1 = gtk_menu_item_new_with_mnemonic("Save as JGF");
  1044. gtk_container_add(GTK_CONTAINER(menuitem1_menu), jgf1);
  1045. /* run this routine when selected 'jgf' in 'file' menu */
  1046. g_signal_connect(G_OBJECT(jgf1), "activate", G_CALLBACK(on_top_level_window_jgf1_activate), NULL);
  1047. /* 'about' in 'file' sub menu in menu items in menu bar in vbox1 */
  1048. about1 = gtk_menu_item_new_with_mnemonic("About");
  1049. gtk_container_add(GTK_CONTAINER(menuitem1_menu), about1);
  1050. /* run this routine when selected 'about' in 'file' menu */
  1051. g_signal_connect(G_OBJECT(about1), "activate", G_CALLBACK(show_about), NULL);
  1052. #ifdef WIN32
  1053. /* 'activate' in 'file' sub menu in menu items in menu bar in vbox1 */
  1054. activate1 = gtk_menu_item_new_with_mnemonic("Activate");
  1055. gtk_container_add(GTK_CONTAINER(menuitem1_menu), activate1);
  1056. /* run this routine when selected 'activate' in 'file' menu */
  1057. g_signal_connect(G_OBJECT(activate1), "activate", G_CALLBACK(on_top_level_window_activate1_activate), NULL);
  1058. #endif
  1059. /* 'quit' in 'file' sub menu in menu items in menu bar in vbox1 */
  1060. quit1 = gtk_menu_item_new_with_mnemonic("Quit");
  1061. gtk_container_add(GTK_CONTAINER(menuitem1_menu), quit1);
  1062. /* run this routine when selected 'quit' in 'file' menu */
  1063. g_signal_connect(G_OBJECT(quit1), "activate", G_CALLBACK(on_top_level_window_quit1_activate), NULL);
  1064. /* --- */
  1065. /* menu items in menu bar in vbox1 */
  1066. menuitem2 = gtk_menu_item_new_with_mnemonic("Fullscreen");
  1067. gtk_container_add(GTK_CONTAINER(menubar1), menuitem2);
  1068. /* 'fullscreen' sub menu in menu items in menu bar in vbox1 */
  1069. menuitem2_menu = gtk_menu_new();
  1070. gtk_menu_item_set_submenu(GTK_MENU_ITEM(menuitem2), menuitem2_menu);
  1071. /* 'fullscreen->fullscreen' in 'fullscreen' sub menu in menu items in menu bar in vbox1 */
  1072. fullscreen1 = gtk_menu_item_new_with_mnemonic("Fullscreen");
  1073. gtk_container_add(GTK_CONTAINER(menuitem2_menu), fullscreen1);
  1074. /* run this routine when selected 'fullscreen->fullscreen in 'fullscreen' menu */
  1075. g_signal_connect(G_OBJECT(fullscreen1), "activate", G_CALLBACK(on_top_level_window_fullscreen1_activate), NULL);
  1076. /* 'fullscreen->normal' in 'fullscreen' sub menu in menu items in menu bar in vbox1 */
  1077. unfullscreen1 = gtk_menu_item_new_with_mnemonic("Normal");
  1078. gtk_container_add(GTK_CONTAINER(menuitem2_menu), unfullscreen1);
  1079. /* run this routine when selected 'fullscreen->normal' in 'fullscreen' menu */
  1080. g_signal_connect(G_OBJECT(unfullscreen1), "activate", G_CALLBACK(on_top_level_window_unfullscreen1_activate), NULL);
  1081. /* -- */
  1082. /*
  1083. * in hbox1
  1084. * left zoom slider
  1085. * drawing area
  1086. * right y slider
  1087. * below x slider
  1088. */
  1089. /* add next area to the vbox1 */
  1090. #if (GTK_HAVE_API_VERSION_2 == 1)
  1091. hbox1 = gtk_hbox_new( /* homogeneous */ FALSE, /* spacing */ 0);
  1092. gtk_box_pack_start( /* box */ GTK_BOX(vbox1), /* child */ hbox1,
  1093. /* expand */ TRUE, /* fill */ TRUE, /* padding */
  1094. PACKPADDING);
  1095. #endif
  1096. #if (GTK_HAVE_API_VERSION_3 == 1)
  1097. hbox1 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, /* spacing */ 0);
  1098. gtk_box_pack_start( /* box */ GTK_BOX(vbox1), /* child */ hbox1,
  1099. /* expand */ TRUE, /* fill */ TRUE, /* padding */
  1100. PACKPADDING);
  1101. #endif
  1102. /* vertical slider in hbox1 for the zoom factor 50% is 1:1 */
  1103. adjvscale1 = gtk_adjustment_new(50, 0, 100, 0, 0, 0);
  1104. #if (GTK_HAVE_API_VERSION_2 == 1)
  1105. vscale1 = gtk_vscale_new(GTK_ADJUSTMENT(adjvscale1));
  1106. g_signal_connect(G_OBJECT(adjvscale1), "value_changed", GTK_SIGNAL_FUNC(on_vscale1_changed), NULL);
  1107. gtk_box_pack_start( /* box */ GTK_BOX(hbox1), /* child */ vscale1,
  1108. /* expand */ FALSE, /* fill */ TRUE, /* padding */
  1109. PACKPADDING);
  1110. gtk_scale_set_draw_value(GTK_SCALE(vscale1), FALSE);
  1111. #endif
  1112. #if (GTK_HAVE_API_VERSION_3 == 1)
  1113. vscale1 = gtk_scale_new(GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT(adjvscale1));
  1114. g_signal_connect(G_OBJECT(adjvscale1), "value_changed", G_CALLBACK(on_vscale1_changed), NULL);
  1115. gtk_box_pack_start( /* box */ GTK_BOX(hbox1), /* child */ vscale1,
  1116. /* expand */ FALSE, /* fill */ TRUE, /* padding */
  1117. PACKPADDING);
  1118. gtk_scale_set_draw_value(GTK_SCALE(vscale1), FALSE);
  1119. #endif
  1120. /* where to draw in hbox1 */
  1121. drawingarea1 = gtk_drawing_area_new();
  1122. gtk_box_pack_start( /* box */ GTK_BOX(hbox1), /* child */ drawingarea1,
  1123. /* expand */ TRUE, /* fill */ TRUE, /* padding */
  1124. PACKPADDING);
  1125. #if (GTK_HAVE_API_VERSION_2 == 1)
  1126. g_signal_connect(G_OBJECT(drawingarea1), "expose_event", G_CALLBACK(on_top_level_window_drawingarea1_expose_event), NULL);
  1127. #endif
  1128. #if (GTK_HAVE_API_VERSION_3 == 1)
  1129. g_signal_connect(G_OBJECT(drawingarea1), "draw", G_CALLBACK(on_top_level_window_drawingarea1_draw_event), NULL);
  1130. #endif
  1131. /* mouse buttons */
  1132. g_signal_connect(G_OBJECT(drawingarea1), "button-press-event", G_CALLBACK(on_mouse_clicked), NULL);
  1133. g_signal_connect(G_OBJECT(drawingarea1), "motion_notify_event", G_CALLBACK(on_motion_notify_event), NULL);
  1134. /* get button press events to above callback() routines
  1135. * get button 1 press events
  1136. * get mouse pointer movement events
  1137. */
  1138. gtk_widget_set_events((drawingarea1), (GDK_BUTTON_PRESS_MASK | GDK_BUTTON1_MOTION_MASK | GDK_POINTER_MOTION_MASK));
  1139. /* vertical slider in hbox1 for the y position range 0...100% of full image size */
  1140. adjvscale2 = gtk_adjustment_new(0, 0, 100, 0, 0, 0);
  1141. #if (GTK_HAVE_API_VERSION_2 == 1)
  1142. vscale2 = gtk_vscale_new(GTK_ADJUSTMENT(adjvscale2));
  1143. g_signal_connect(G_OBJECT(adjvscale2), "value_changed", GTK_SIGNAL_FUNC(on_vscale2_changed), NULL);
  1144. gtk_box_pack_start( /* box */ GTK_BOX(hbox1), /* child */ vscale2,
  1145. /* expand */ FALSE, /* fill */ TRUE, /* padding */
  1146. PACKPADDING);
  1147. gtk_scale_set_draw_value(GTK_SCALE(vscale2), FALSE);
  1148. #endif
  1149. #if (GTK_HAVE_API_VERSION_3 == 1)
  1150. vscale2 = gtk_scale_new(GTK_ORIENTATION_VERTICAL, GTK_ADJUSTMENT(adjvscale2));
  1151. g_signal_connect(G_OBJECT(adjvscale2), "value_changed", G_CALLBACK(on_vscale2_changed), NULL);
  1152. gtk_box_pack_start( /* box */ GTK_BOX(hbox1), /* child */ vscale2,
  1153. /* expand */ FALSE, /* fill */ TRUE, /* padding */
  1154. PACKPADDING);
  1155. gtk_scale_set_draw_value(GTK_SCALE(vscale2), FALSE);
  1156. #endif
  1157. /* horizontal scroller 0..100% of drawing size */
  1158. adjhscale1 = gtk_adjustment_new(0, 0, 100, 0, 0, 0);
  1159. #if (GTK_HAVE_API_VERSION_2 == 1)
  1160. hscale1 = gtk_hscale_new(GTK_ADJUSTMENT(adjhscale1));
  1161. g_signal_connect(G_OBJECT(adjhscale1), "value_changed", GTK_SIGNAL_FUNC(on_hscale1_changed), NULL);
  1162. gtk_box_pack_start( /* box */ GTK_BOX(vbox1), /* child */ hscale1,
  1163. /* expand */ FALSE, /* fill */ TRUE, /* padding */
  1164. PACKPADDING);
  1165. gtk_scale_set_draw_value(GTK_SCALE(hscale1), FALSE);
  1166. #endif
  1167. #if (GTK_HAVE_API_VERSION_3 == 1)
  1168. hscale1 = gtk_scale_new(GTK_ORIENTATION_HORIZONTAL, GTK_ADJUSTMENT(adjhscale1));
  1169. g_signal_connect(G_OBJECT(adjhscale1), "value_changed", G_CALLBACK(on_hscale1_changed), NULL);
  1170. gtk_box_pack_start( /* box */ GTK_BOX(vbox1), /* child */ hscale1,
  1171. /* expand */ FALSE, /* fill */ TRUE, /* padding */
  1172. PACKPADDING);
  1173. gtk_scale_set_draw_value(GTK_SCALE(hscale1), FALSE);
  1174. #endif
  1175. /* --- */
  1176. /* add next area to the vbox1 */
  1177. #if (GTK_HAVE_API_VERSION_2 == 1)
  1178. hbox2 = gtk_hbox_new( /* homogeneous */ FALSE, /* spacing */ 0);
  1179. gtk_box_pack_start( /* box */ GTK_BOX(vbox1), /* child */ hbox2,
  1180. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1181. PACKPADDING);
  1182. #endif
  1183. #if (GTK_HAVE_API_VERSION_3 == 1)
  1184. hbox2 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, /* spacing */ 0);
  1185. gtk_box_pack_start( /* box */ GTK_BOX(vbox1), /* child */ hbox2,
  1186. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1187. PACKPADDING);
  1188. #endif
  1189. /* --- */
  1190. xspinlabel = gtk_label_new("dx");
  1191. gtk_box_pack_start( /* box */ GTK_BOX(hbox2), /* child */ xspinlabel,
  1192. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1193. PACKPADDING);
  1194. gtk_widget_set_tooltip_text(xspinlabel, "stretch drawing in x-direction");
  1195. gtk_widget_show(xspinlabel);
  1196. /* spin to change drawing spread factor. note that in gtk2 it is a (GtkObject *) and in gtk3 a (GtkAdjustment *) */
  1197. xspinadjustment = (GtkAdjustment *) gtk_adjustment_new(xspacing /* initial value */ ,
  1198. 0 /* minimum value */ ,
  1199. 99 /* maximum value */ ,
  1200. 1 /* step increment */ ,
  1201. 1 /* page increment */ ,
  1202. 0 /* page size now *must* be zero */
  1203. );
  1204. xspinbutton = gtk_spin_button_new(xspinadjustment, 1 /* climb rate */ ,
  1205. 0 /* digits achter de comma */ );
  1206. gtk_box_pack_start( /* box */ GTK_BOX(hbox2), /* child */ xspinbutton,
  1207. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1208. PACKPADDING);
  1209. g_signal_connect(G_OBJECT(xspinadjustment), "value-changed", G_CALLBACK(xspin_changed), (gpointer) xspinbutton);
  1210. yspinlabel = gtk_label_new("dy");
  1211. gtk_box_pack_start( /* box */ GTK_BOX(hbox2), /* child */ yspinlabel,
  1212. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1213. PACKPADDING);
  1214. gtk_widget_set_tooltip_text(yspinlabel, "stretch drawing in y-direction");
  1215. /* spin to change drawing spread factor. note that in gtk2 it is a (GtkObject *) and in gtk3 a (GtkAdjustment *) */
  1216. yspinadjustment = (GtkAdjustment *) gtk_adjustment_new(yspacing /* initial value */ ,
  1217. 0 /* minimum value */ ,
  1218. 99 /* maximum value */ ,
  1219. 1 /* step increment */ ,
  1220. 1 /* page increment */ ,
  1221. 0 /* page size now *must* be zero */
  1222. );
  1223. yspinbutton = gtk_spin_button_new(yspinadjustment, 1 /* climb rate */ ,
  1224. 0 /* digits achter de comma */ );
  1225. gtk_box_pack_start( /* box */ GTK_BOX(hbox2), /* child */ yspinbutton,
  1226. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1227. PACKPADDING);
  1228. gtk_widget_set_tooltip_text(yspinbutton, "stretch y-direction");
  1229. g_signal_connect(G_OBJECT(yspinadjustment), "value-changed", G_CALLBACK(yspin_changed), (gpointer) yspinbutton);
  1230. /* at every click, advance positioning mode */
  1231. pos1 = gtk_label_new("pos");
  1232. gtk_box_pack_start( /* box */ GTK_BOX(hbox2), /* child */ pos1,
  1233. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1234. PACKPADDING);
  1235. gtk_widget_set_tooltip_text(pos1, "positioning mode");
  1236. posadjustment = (GtkAdjustment *) gtk_adjustment_new(postype /* initial value */ ,
  1237. 1 /* minimum value */ ,
  1238. 4 /* maximum value */ ,
  1239. 1 /* step increment */ ,
  1240. 1 /* page increment */ ,
  1241. 0 /* page size now *must* be zero */
  1242. );
  1243. posbutton = gtk_spin_button_new(posadjustment, 1 /* climb rate */ ,
  1244. 0 /* digits achter de comma */ );
  1245. gtk_box_pack_start( /* box */ GTK_BOX(hbox2), /* child */ posbutton,
  1246. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1247. PACKPADDING);
  1248. g_signal_connect(G_OBJECT(posadjustment), "value-changed", G_CALLBACK(pos_changed), (gpointer) posbutton);
  1249. /* draw spline edges or normal */
  1250. check1 = gtk_check_button_new_with_label("splines");
  1251. gtk_box_pack_start( /* box */ GTK_BOX(hbox2), /* child */ check1,
  1252. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1253. PACKPADDING);
  1254. /* */
  1255. if (option_splines) {
  1256. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check1), TRUE);
  1257. } else {
  1258. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(check1), FALSE);
  1259. }
  1260. /* the window arg is not used */
  1261. g_signal_connect(G_OBJECT(check1), "clicked", G_CALLBACK(check1_toggle), (gpointer) mainwindow1);
  1262. gtk_widget_set_tooltip_text(check1, "edge line splines");
  1263. /* draw dummy nodes */
  1264. dummy1 = gtk_check_button_new_with_label("dummy's");
  1265. gtk_box_pack_start( /* box */ GTK_BOX(hbox2), /* child */ dummy1,
  1266. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1267. PACKPADDING);
  1268. /* */
  1269. if (option_drawdummy) {
  1270. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dummy1), TRUE);
  1271. } else {
  1272. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(dummy1), FALSE);
  1273. }
  1274. /* the window arg is not used */
  1275. g_signal_connect(G_OBJECT(dummy1), "clicked", G_CALLBACK(dummy1_toggle), (gpointer) mainwindow1);
  1276. gtk_widget_set_tooltip_text(dummy1, "show dummy nodes");
  1277. /* */
  1278. entry1 = gtk_text_view_new();
  1279. entry1buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(entry1));
  1280. gtk_text_buffer_set_text(entry1buffer, "GML4GTK is free software to copy, share and improve", -1);
  1281. gtk_text_view_set_editable(GTK_TEXT_VIEW(entry1), FALSE);
  1282. gtk_box_pack_start( /* box */ GTK_BOX(hbox2), /* child */ entry1,
  1283. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1284. PACKPADDING);
  1285. gtk_widget_set_tooltip_text(entry1, "status information");
  1286. /*
  1287. * next line with toggle buttons
  1288. */
  1289. /* add next area to the vbox1 */
  1290. #if (GTK_HAVE_API_VERSION_2 == 1)
  1291. hbox3 = gtk_hbox_new( /* homogeneous */ FALSE, /* spacing */ 0);
  1292. gtk_box_pack_start( /* box */ GTK_BOX(vbox1), /* child */ hbox3,
  1293. /* expand */ FALSE, /* fill */ TRUE, /* padding */
  1294. PACKPADDING);
  1295. #endif
  1296. #if (GTK_HAVE_API_VERSION_3 == 1)
  1297. hbox3 = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, /* spacing */ 0);
  1298. gtk_box_pack_start( /* box */ GTK_BOX(vbox1), /* child */ hbox3,
  1299. /* expand */ FALSE, /* fill */ TRUE, /* padding */
  1300. PACKPADDING);
  1301. #endif
  1302. /* level placement */
  1303. rank1 = gtk_label_new("rank");
  1304. gtk_box_pack_start( /* box */ GTK_BOX(hbox3), /* child */ rank1,
  1305. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1306. PACKPADDING);
  1307. gtk_widget_set_tooltip_text(rank1, "dfs/bfs/topological levels");
  1308. /* spin to change rank type note that in gtk2 it is a (GtkObject *) and in gtk3 a (GtkAdjustment *) */
  1309. rankadjustment = (GtkAdjustment *) gtk_adjustment_new(ranktype /* initial value */ ,
  1310. 1 /* minimum value */ ,
  1311. 3 /* maximum value */ ,
  1312. 1 /* step increment */ ,
  1313. 1 /* page increment */ ,
  1314. 0 /* page size now *must* be zero */
  1315. );
  1316. rankbutton = gtk_spin_button_new(rankadjustment, 1 /* climb rate */ ,
  1317. 0 /* digits achter de comma */ );
  1318. gtk_box_pack_start( /* box */ GTK_BOX(hbox3), /* child */ rankbutton,
  1319. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1320. PACKPADDING);
  1321. g_signal_connect(G_OBJECT(rankadjustment), "value-changed", G_CALLBACK(rank_changed), (gpointer) rankbutton);
  1322. /* barycenter */
  1323. barylabel = gtk_label_new("bary");
  1324. gtk_box_pack_start( /* box */ GTK_BOX(hbox3), /* child */ barylabel,
  1325. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1326. PACKPADDING);
  1327. gtk_widget_set_tooltip_text(barylabel, "barycenter type");
  1328. /* spin to change barycenter type note that in gtk2 it is a (GtkObject *) and in gtk3 a (GtkAdjustment *) */
  1329. baryadjustment = (GtkAdjustment *) gtk_adjustment_new(barytype /* initial value */ ,
  1330. 1 /* minimum value */ ,
  1331. 5 /* maximum value */ ,
  1332. 1 /* step increment */ ,
  1333. 1 /* page increment */ ,
  1334. 0 /* page size now *must* be zero */
  1335. );
  1336. barybutton = gtk_spin_button_new(baryadjustment, 1 /* climb rate */ ,
  1337. 0 /* digits achter de comma */ );
  1338. gtk_box_pack_start( /* box */ GTK_BOX(hbox3), /* child */ barybutton,
  1339. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1340. PACKPADDING);
  1341. g_signal_connect(G_OBJECT(baryadjustment), "value-changed", G_CALLBACK(bary_changed), (gpointer) barybutton);
  1342. /* edgelabels on/off */
  1343. elabel1 = gtk_check_button_new_with_label("elabel");
  1344. gtk_box_pack_start( /* box */ GTK_BOX(hbox3), /* child */ elabel1,
  1345. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1346. PACKPADDING);
  1347. /* */
  1348. if (option_edgelabels) {
  1349. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(elabel1), TRUE);
  1350. } else {
  1351. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(elabel1), FALSE);
  1352. }
  1353. g_signal_connect(G_OBJECT(elabel1), "clicked", G_CALLBACK(elabel1_toggle), (gpointer) mainwindow1);
  1354. gtk_widget_set_tooltip_text(elabel1, "edgelabels on/off");
  1355. /* labels on/off */
  1356. label1 = gtk_check_button_new_with_label("labels");
  1357. gtk_box_pack_start( /* box */ GTK_BOX(hbox3), /* child */ label1,
  1358. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1359. PACKPADDING);
  1360. /* */
  1361. if (option_labels) {
  1362. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(label1), TRUE);
  1363. } else {
  1364. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(label1), FALSE);
  1365. }
  1366. g_signal_connect(G_OBJECT(label1), "clicked", G_CALLBACK(label1_toggle), (gpointer) mainwindow1);
  1367. gtk_widget_set_tooltip_text(label1, "labels on/off");
  1368. /* node names on/off */
  1369. nnames1 = gtk_check_button_new_with_label("names");
  1370. gtk_box_pack_start( /* box */ GTK_BOX(hbox3), /* child */ nnames1,
  1371. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1372. PACKPADDING);
  1373. /* */
  1374. if (option_nnames) {
  1375. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(nnames1), TRUE);
  1376. } else {
  1377. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(nnames1), FALSE);
  1378. }
  1379. g_signal_connect(G_OBJECT(nnames1), "clicked", G_CALLBACK(nnames1_toggle), (gpointer) mainwindow1);
  1380. gtk_widget_set_tooltip_text(nnames1, "node names instead of labels");
  1381. /* popup labels on/off */
  1382. popup1 = gtk_check_button_new_with_label("popup");
  1383. gtk_box_pack_start( /* box */ GTK_BOX(hbox3), /* child */ popup1,
  1384. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1385. PACKPADDING);
  1386. /* */
  1387. if (option_popup) {
  1388. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(popup1), TRUE);
  1389. } else {
  1390. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(popup1), FALSE);
  1391. }
  1392. g_signal_connect(G_OBJECT(popup1), "clicked", G_CALLBACK(popup1_toggle), (gpointer) mainwindow1);
  1393. gtk_widget_set_tooltip_text(popup1, "popup labels on/off");
  1394. /* mirror y on/off */
  1395. mirrory1 = gtk_check_button_new_with_label("mirror");
  1396. gtk_box_pack_start( /* box */ GTK_BOX(hbox3), /* child */ mirrory1,
  1397. /* expand */ FALSE, /* fill */ FALSE, /* padding */
  1398. PACKPADDING);
  1399. /* */
  1400. if (option_mirrory) {
  1401. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mirrory1), TRUE);
  1402. } else {
  1403. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(mirrory1), FALSE);
  1404. }
  1405. g_signal_connect(G_OBJECT(mirrory1), "clicked", G_CALLBACK(mirrory1_toggle), (gpointer) mainwindow1);
  1406. gtk_widget_set_tooltip_text(mirrory1, "mirror drawing in y direction");
  1407. /*
  1408. * here additional gtk elements
  1409. */
  1410. /* put on screen */
  1411. gtk_widget_show_all(mainwindow1);
  1412. return (0);
  1413. }
  1414. #endif
  1415. int main(int argc, char *argv[])
  1416. {
  1417. int ret = 0;
  1418. char *s = NULL;
  1419. /* check options */
  1420. if (argc > 1) {
  1421. for (ret = 1; ret < argc; ret++) {
  1422. if (strcmp(argv[ret], "--version") == 0) {
  1423. /* print version in config.h set by configure.ac and exit */
  1424. printf("%s\n", PACKAGE_STRING);
  1425. return (0);
  1426. } else if (strcmp(argv[ret], "--debug") == 0) {
  1427. /* set debug flag */
  1428. yydebug = 1;
  1429. printf("%s(): turned on yydebug\n", __func__);
  1430. } else {
  1431. /* add option check here */
  1432. }
  1433. }
  1434. }
  1435. /* */
  1436. dp_meminit();
  1437. /* the program name is saved and also can be gml4gtk4d for debug putput */
  1438. argv0 = argv[0];
  1439. #if (GTK_HAVE_API_VERSION_4 == 1)
  1440. /* check the used cairo version at runtime */
  1441. if (cairo_version() < CAIRO_VERSION_ENCODE(1, 17, 4)) {
  1442. /* there is an issue */
  1443. printf("%s(): need at least cairo lib version 1.17.4 and expect blurry text\n", __func__);
  1444. }
  1445. #endif
  1446. /* get the home dir */
  1447. s = getenv("HOME");
  1448. if (s) {
  1449. lastopendir = dp_calloc(1, (strlen(s) + 1));
  1450. strcpy(lastopendir, s);
  1451. lastsavedir = dp_calloc(1, (strlen(s) + 1));
  1452. strcpy(lastsavedir, s);
  1453. } else {
  1454. /* there is no home dir set in env */
  1455. lastopendir = NULL;
  1456. lastsavedir = NULL;
  1457. }
  1458. /* this is depreciated
  1459. * g_type_init();
  1460. * g_thread_init(NULL);
  1461. */
  1462. #if !GLIB_CHECK_VERSION (2, 36, 0)
  1463. /* for GDBus */
  1464. g_type_init();
  1465. #endif
  1466. #if (GTK_HAVE_API_VERSION_0 == 1)
  1467. ret = 0;
  1468. #endif
  1469. #if (GTK_HAVE_API_VERSION_1 == 1)
  1470. ret = 0;
  1471. #endif
  1472. #if (GTK_HAVE_API_VERSION_2 == 1 || GTK_HAVE_API_VERSION_3 == 1)
  1473. /*
  1474. * gtk_init (&argc, &argv); in gkt2, gtk3 and gtk_init() in gtk4
  1475. *
  1476. * calls the function gtk_init(gint *argc, gchar ***argv) which will be called in all GTK applications.
  1477. * This sets up a few things for us such as the default visual and color map and then proceeds to call
  1478. * gdk_init(gint *argc, gchar ***argv). This function initializes the library for use, sets up default
  1479. * signal handlers, and checks the arguments passed to your application on the command line,
  1480. * looking for one of the following:
  1481. *
  1482. * * --gtk-module
  1483. * * --g-fatal-warnings
  1484. * * --gtk-debug
  1485. * * --gtk-no-debug
  1486. * * --gdk-debug
  1487. * * --gdk-no-debug
  1488. * * --display
  1489. * * --sync
  1490. * * --no-xshm
  1491. * * --name
  1492. * * --class
  1493. *
  1494. * It removes these from the argument list, leaving anything it does not recognize for your application
  1495. * to parse or ignore. This creates a set of standard arguments accepted by all GTK applications.
  1496. *
  1497. */
  1498. /* do gtk init, gtk will grab the gtk specific options on command line */
  1499. /* gtk 2, 3 */
  1500. {
  1501. if (yydebug) {
  1502. gtk_test_init(&argc, &argv);
  1503. gtk_test_register_all_types();
  1504. /* add here g_test_add_func() */
  1505. #if (GTK_HAVE_API_VERSION_2 == 1)
  1506. /* only in gtk2 */
  1507. gdk_window_set_debug_updates(TRUE);
  1508. #endif
  1509. /* this does not work:
  1510. * #include "gtkdebug.h"
  1511. * gtk_set_debug_flags(0xffffffff);
  1512. */
  1513. } else {
  1514. gtk_init(&argc, &argv);
  1515. }
  1516. }
  1517. ret = maingtk23();
  1518. if (ret) {
  1519. }
  1520. initialfiles(argc, argv);
  1521. if (ret) {
  1522. }
  1523. /* run the gui */
  1524. gtk_main();
  1525. #endif
  1526. #if (GTK_HAVE_API_VERSION_4 == 1)
  1527. {
  1528. GtkApplication *app = NULL;
  1529. /* gtk4 has no args */
  1530. if (yydebug) {
  1531. (void)gtk_test_init(&argc, &argv);
  1532. gtk_test_register_all_types();
  1533. } else {
  1534. (void)gtk_init();
  1535. }
  1536. app = gtk_application_new("www.graphviewer.nl", G_APPLICATION_FLAGS_NONE);
  1537. g_signal_connect(G_OBJECT(app), "activate", G_CALLBACK(maingtk4_activate), NULL);
  1538. ret = g_application_run(G_APPLICATION(app), argc, argv);
  1539. g_object_unref(app);
  1540. if (ret) {
  1541. }
  1542. initialfiles(argc, argv);
  1543. }
  1544. #endif
  1545. /* clear all graph data */
  1546. do_clear_all(0);
  1547. if (lastopendir) {
  1548. lastopendir = dp_free(lastopendir);
  1549. if (lastopendir) {
  1550. }
  1551. }
  1552. if (lastsavedir) {
  1553. lastsavedir = dp_free(lastsavedir);
  1554. if (lastsavedir) {
  1555. }
  1556. }
  1557. /* optional memory check report when compiled with -DMEMCHECK */
  1558. dp_memreport();
  1559. return (ret);
  1560. }
  1561. /* scale pos to zvalue */
  1562. static int doscaleit(int val)
  1563. {
  1564. int ret = 0;
  1565. double x = 0.0;
  1566. x = (double)val;
  1567. x = x * zfactor;
  1568. x = round(x);
  1569. ret = (int)x;
  1570. return (ret);
  1571. }
  1572. /* check if a node at mouse pointer position */
  1573. static struct gml_node *is_node_at_xy(int x, int y)
  1574. {
  1575. struct gml_node *found = NULL;
  1576. struct gml_nlist *nl = NULL;
  1577. int x0 = 0;
  1578. int y0 = 0;
  1579. int xs = 0;
  1580. int ys = 0;
  1581. /* first parameters check */
  1582. if (x < 0) {
  1583. return (NULL);
  1584. }
  1585. if (y < 0) {
  1586. return (NULL);
  1587. }
  1588. if (x > drawing_area_xsize) {
  1589. return (NULL);
  1590. }
  1591. if (y > drawing_area_ysize) {
  1592. return (NULL);
  1593. }
  1594. nl = maingraph->nodelist;
  1595. while (nl) {
  1596. /* skip dummy nodes */
  1597. if (nl->node->dummy == 1) {
  1598. nl = nl->next;
  1599. continue;
  1600. }
  1601. /* skip edgelabel nodes */
  1602. if (nl->node->elabel) {
  1603. nl = nl->next;
  1604. continue;
  1605. }
  1606. /* this is a real node and calc screen coords */
  1607. x0 = doscaleit(nl->node->finx - vxmin);
  1608. y0 = doscaleit(nl->node->finy - vymin);
  1609. xs = doscaleit(nl->node->bbx);
  1610. ys = doscaleit(nl->node->bby);
  1611. /* check if on-screen */
  1612. if (x0 < 0 && (x0 + xs) < 0) {
  1613. nl = nl->next;
  1614. continue;
  1615. }
  1616. if (y0 < 0 && (y0 + ys) < 0) {
  1617. nl = nl->next;
  1618. continue;
  1619. }
  1620. if (x0 > drawing_area_xsize) {
  1621. nl = nl->next;
  1622. continue;
  1623. }
  1624. if (y0 > drawing_area_ysize) {
  1625. nl = nl->next;
  1626. continue;
  1627. }
  1628. /* node is on-screen and check wit mouse pointer */
  1629. if ((x > x0 && x < (x0 + xs)) && (y > y0 && y < (y0 + ys))) {
  1630. found = nl->node;
  1631. break;
  1632. }
  1633. /* try other node in drawing */
  1634. nl = nl->next;
  1635. }
  1636. return (found);
  1637. }
  1638. /* make sure there is no popup windows */
  1639. static void no_popup(void)
  1640. {
  1641. if (popupwindow1) {
  1642. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  1643. gtk_widget_destroy(popupwindow1);
  1644. #endif
  1645. #if (GTK_HAVE_API_VERSION_4 == 1)
  1646. gtk_window_destroy(GTK_WINDOW(popupwindow1));
  1647. #endif
  1648. popupwindow1 = NULL;
  1649. }
  1650. return;
  1651. }
  1652. /* popup the node label text, vars are checked */
  1653. static void popup_nodelabel(struct gml_node *n, cairo_t * crp, int xsize, int ysize)
  1654. {
  1655. int cr = 0;
  1656. int cg = 0;
  1657. int cb = 0;
  1658. int xo = 0;
  1659. int yo = 0;
  1660. PangoLayout *layout = NULL;
  1661. PangoFontDescription *desc = NULL;
  1662. char buf[128];
  1663. char *s = NULL;
  1664. /* name of font to use, example "Sans" */
  1665. const char *default_fontname = DEFAULT_FONTNAME;
  1666. /* name of slant to use, example "Italic", "Oblique", "Roman" */
  1667. const char *default_fontslant = DEFAULT_FONTSLANT;
  1668. /* name of weight to use, example "Bold", "Book", "Light", "Medium", "Semi-bold", "Ultra-light" */
  1669. const char *default_fontweight = DEFAULT_FONTWEIGHT;
  1670. /* name of condensed to use, example "Semi-Condensed", "Condensed" */
  1671. const char *default_fontcondensed = DEFAULT_FONTCONDENSED;
  1672. /* font size to use, example "10", "18", "20" etc. */
  1673. const char *default_fontsize = DEFAULT_FONTSIZE;
  1674. /* fillcolor of node white default or color */
  1675. cr = (n->ncolor & 0x00ff0000) >> 16;
  1676. cg = (n->ncolor & 0x0000ff00) >> 8;
  1677. cb = (n->ncolor & 0x000000ff);
  1678. cairo_set_source_rgb(crp, cr / 255.0, cg / 255.0, cb / 255.0);
  1679. cairo_rectangle(crp, 0, 0, xsize, ysize);
  1680. cairo_fill(crp);
  1681. cairo_stroke(crp);
  1682. /* bordercolor of node black default or color */
  1683. cr = (n->nbcolor & 0x00ff0000) >> 16;
  1684. cg = (n->nbcolor & 0x0000ff00) >> 8;
  1685. cb = (n->nbcolor & 0x000000ff);
  1686. cairo_set_source_rgb(crp, cr / 255.0, cg / 255.0, cb / 255.0);
  1687. cairo_rectangle(crp, 0, 0, xsize, ysize);
  1688. cairo_stroke(crp);
  1689. if (n->hlabel) {
  1690. /* html label */
  1691. on_top_level_window_drawingarea1_expose_event_nodes_html(crp, n);
  1692. } else if (n->rlabel) {
  1693. /* record label */
  1694. /* draw record label */
  1695. on_top_level_window_drawingarea1_expose_event_nodes_record(crp, n);
  1696. } else {
  1697. /* fontcolor of node black default or color */
  1698. cr = (n->fontcolor & 0x00ff0000) >> 16;
  1699. cg = (n->fontcolor & 0x0000ff00) >> 8;
  1700. cb = (n->fontcolor & 0x000000ff);
  1701. /* draw in text color of node */
  1702. cairo_set_source_rgb(crp, cr / 255.0, cg / 255.0, cb / 255.0);
  1703. xo = 2;
  1704. yo = 2;
  1705. /* set start position of text */
  1706. cairo_move_to(crp, n->finx - vxmin + xo, n->finy - vymin + yo);
  1707. layout = pango_cairo_create_layout(crp);
  1708. /* set the text to draw which is 0 terminated */
  1709. pango_layout_set_text(layout, n->nlabel, -1);
  1710. /* set font parameters */
  1711. /* create the fontname description */
  1712. memset(buf, 0, (size_t)128);
  1713. default_fontname = DEFAULT_FONTNAME;
  1714. /* check if node has a specified font slant */
  1715. default_fontslant = DEFAULT_FONTSLANT;
  1716. /* check if node has a specified font weight */
  1717. default_fontweight = DEFAULT_FONTWEIGHT;
  1718. /* check if node has a specified font size */
  1719. default_fontsize = DEFAULT_FONTSIZE;
  1720. /* create the font name string */
  1721. snprintf(buf, (128 - 1), "%s %s %s %s %s", default_fontname,
  1722. default_fontslant, default_fontweight, default_fontcondensed, default_fontsize);
  1723. /* copy string buffer */
  1724. s = uniqstr(buf);
  1725. /* */
  1726. desc = pango_font_description_from_string(s);
  1727. /* */
  1728. pango_layout_set_font_description(layout, desc);
  1729. /* */
  1730. pango_font_description_free(desc);
  1731. /* */
  1732. pango_cairo_update_layout(crp, layout);
  1733. /* draw the text */
  1734. pango_cairo_show_layout(crp, layout);
  1735. /* */
  1736. cairo_stroke(crp);
  1737. g_object_unref(G_OBJECT(layout));
  1738. }
  1739. return;
  1740. }
  1741. #if (GTK_HAVE_API_VERSION_2 == 1)
  1742. /* redraw drawing area */
  1743. static gboolean popuparea1_expose_event(GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
  1744. {
  1745. struct gml_node *n = NULL;
  1746. cairo_t *crp = NULL;
  1747. gint w = 0; /* xsize of drawing area */
  1748. gint h = 0; /* ysize of drawing area */
  1749. double zfactor_saved = 0.0;
  1750. int vxmin_saved = 0;
  1751. int vymin_saved = 0;
  1752. if (popupwindow1 == NULL) {
  1753. /* shouldnothappen */
  1754. return (FALSE);
  1755. }
  1756. if (widget) {
  1757. }
  1758. if (event == NULL) {
  1759. return (FALSE);
  1760. }
  1761. /* the user data has the node to draw */
  1762. n = (struct gml_node *)user_data;
  1763. /* get cairo drawing context */
  1764. crp = gdk_cairo_create(event->window);
  1765. if (crp == NULL) {
  1766. /* shouldnothappen */
  1767. return (FALSE);
  1768. }
  1769. /* how large drawing area is */
  1770. (void)gdk_drawable_get_size(event->window, &w, &h);
  1771. if (option_gdebug > 1 || 0) {
  1772. printf("%s(): drawing area size is (%d,%d) node=%p nlabel=\"%s\"\n", __func__, w, h, (void *)n, n->nlabel);
  1773. fflush(stdout);
  1774. }
  1775. if (n == NULL) {
  1776. /* shouldnothappen */
  1777. return (FALSE);
  1778. }
  1779. /* save mainwindow settings */
  1780. zfactor_saved = zfactor;
  1781. vxmin_saved = vxmin;
  1782. vymin_saved = vymin;
  1783. /* draw node label text at 1:1 100% scale */
  1784. zfactor = 1.0;
  1785. vxmin = n->finx;
  1786. vymin = n->finy;
  1787. cairo_scale(crp, zfactor, zfactor);
  1788. /* popup the node label text */
  1789. popup_nodelabel(n, crp, w, h);
  1790. /* restore mainwindow settings */
  1791. zfactor = zfactor_saved;
  1792. vxmin = vxmin_saved;
  1793. vymin = vymin_saved;
  1794. return (FALSE);
  1795. }
  1796. #endif
  1797. #if (GTK_HAVE_API_VERSION_4 == 1)
  1798. /* draw in the popup window the label text */
  1799. static void popuparea1_draw_event_for_gtk4(GtkDrawingArea * area, cairo_t * crdraw, int width, int height, gpointer user_data)
  1800. {
  1801. struct gml_node *n = NULL;
  1802. double zfactor_saved = 0.0;
  1803. int vxmin_saved = 0;
  1804. int vymin_saved = 0;
  1805. if (area) {
  1806. }
  1807. if (popupwindow1 == NULL) {
  1808. /* shouldnothappen */
  1809. return;
  1810. }
  1811. /* the user data has the node to draw */
  1812. n = (struct gml_node *)user_data;
  1813. if (n == NULL) {
  1814. /* shouldnothappen */
  1815. return;
  1816. }
  1817. /* save mainwindow settings */
  1818. zfactor_saved = zfactor;
  1819. vxmin_saved = vxmin;
  1820. vymin_saved = vymin;
  1821. /* draw node label text at 1:1 100% scale */
  1822. zfactor = 1.0;
  1823. vxmin = n->finx;
  1824. vymin = n->finy;
  1825. cairo_scale(crdraw, zfactor, zfactor);
  1826. /* popup the node label text */
  1827. popup_nodelabel(n, crdraw, width, height);
  1828. /* restore mainwindow settings */
  1829. zfactor = zfactor_saved;
  1830. vxmin = vxmin_saved;
  1831. vymin = vymin_saved;
  1832. return;
  1833. }
  1834. #endif
  1835. #if (GTK_HAVE_API_VERSION_3 == 1)
  1836. /* redraw drawing area */
  1837. static gboolean popuparea1_draw_event(GtkWidget * widget, cairo_t * crdraw, gpointer user_data)
  1838. {
  1839. struct gml_node *n = NULL;
  1840. gint w = 0; /* xsize of drawing area */
  1841. gint h = 0; /* ysize of drawing area */
  1842. cairo_t *crp = NULL;
  1843. double zfactor_saved = 0.0;
  1844. int vxmin_saved = 0;
  1845. int vymin_saved = 0;
  1846. if (popupwindow1 == NULL) {
  1847. /* shouldnothappen */
  1848. return (FALSE);
  1849. }
  1850. if (widget) {
  1851. }
  1852. /* the user data has the node to draw */
  1853. n = (struct gml_node *)user_data;
  1854. if (n == NULL) {
  1855. /* shouldnothappen */
  1856. return (FALSE);
  1857. }
  1858. /* this is a workaround for issue in cairo-lib 1.14.0 with gtk3,
  1859. * cairo.c cairo_destroy() line 305 assert(), (with gtk2 no problem) */
  1860. crp = cairo_reference(crdraw);
  1861. if (crp == NULL) {
  1862. /* shouldnothappen */
  1863. return (FALSE);
  1864. }
  1865. /* how large drawing area is */
  1866. w = gtk_widget_get_allocated_width(popupwindow1);
  1867. h = gtk_widget_get_allocated_height(popupwindow1);
  1868. if (option_gdebug > 1 || 0) {
  1869. printf("%s(): drawing area size is (%d,%d) node %p\n", __func__, w, h, (void *)n);
  1870. fflush(stdout);
  1871. }
  1872. /* save mainwindow settings */
  1873. zfactor_saved = zfactor;
  1874. vxmin_saved = vxmin;
  1875. vymin_saved = vymin;
  1876. /* draw node label text at 1:1 100% scale */
  1877. zfactor = 1.0;
  1878. vxmin = n->finx;
  1879. vymin = n->finy;
  1880. cairo_scale(crp, zfactor, zfactor);
  1881. /* popup the node label text */
  1882. popup_nodelabel(n, crp, w, h);
  1883. /* restore mainwindow settings */
  1884. zfactor = zfactor_saved;
  1885. vxmin = vxmin_saved;
  1886. vymin = vymin_saved;
  1887. return (FALSE);
  1888. }
  1889. #endif
  1890. #if (GTK_HAVE_API_VERSION_4 == 1)
  1891. /* popup window with node label text, (x,y) current mouse pointer */
  1892. static void do_popup(struct gml_node *n, int x, int y)
  1893. {
  1894. int pop = 1;
  1895. GtkWidget *vbox1 = NULL;
  1896. GtkWidget *popuparea1 = (GtkWidget *) 0;
  1897. if (yydebug || 0) {
  1898. printf("%s(): popup window for node at (%d,%d) node ptr %p\n", __func__, x, y, (void *)n);
  1899. }
  1900. /* if there is alreay a popup, keep it that way */
  1901. if (popupwindow1) {
  1902. return;
  1903. }
  1904. /* fresh window */
  1905. popupwindow1 = gtk_window_new();
  1906. /* make sure to exit oke. */
  1907. g_signal_connect(G_OBJECT(popupwindow1), "destroy", G_CALLBACK(no_popup), NULL);
  1908. /* set some title */
  1909. gtk_window_set_title(GTK_WINDOW(popupwindow1), " ");
  1910. /* pre-set size of full sized label text */
  1911. gtk_window_set_default_size(GTK_WINDOW(popupwindow1), (n->fbbx + 5) /* XSIZE */ ,
  1912. n->fbby + 5 /* YSIZE */ );
  1913. /* decorate the window otherwise it will not show up
  1914. * this is a window manager issue and not gtk
  1915. * set to true or false
  1916. */
  1917. gtk_window_set_decorated(GTK_WINDOW(popupwindow1), FALSE);
  1918. /* next vertical area for slider and drawing are */
  1919. vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, /* spacing */ 0);
  1920. gtk_widget_set_hexpand(vbox1, TRUE);
  1921. gtk_widget_set_vexpand(vbox1, TRUE);
  1922. gtk_window_set_child(GTK_WINDOW(popupwindow1), vbox1);
  1923. /* where to draw in box */
  1924. popuparea1 = gtk_drawing_area_new();
  1925. /* stretch maximal */
  1926. gtk_widget_set_vexpand(popuparea1, TRUE);
  1927. gtk_widget_set_hexpand(popuparea1, TRUE);
  1928. /* add routine for drawing with supplied current node in user data */
  1929. gtk_drawing_area_set_draw_func(GTK_DRAWING_AREA(popuparea1), /* function */ popuparea1_draw_event_for_gtk4, /* user_data */
  1930. (gpointer) n, /* destroy */ NULL);
  1931. gtk_box_append(GTK_BOX(vbox1), popuparea1);
  1932. if (pop) {
  1933. /* optional move the popup window here next to the node as in the gtk-3 sourcecode */
  1934. /* the position of the created popup window is determined by the windowmanager */
  1935. }
  1936. gtk_window_present(GTK_WINDOW(popupwindow1));
  1937. return;
  1938. }
  1939. #endif
  1940. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  1941. /* popup window with node label text, (x,y) current mouse pointer */
  1942. static void do_popup(struct gml_node *n, int x, int y)
  1943. {
  1944. GdkWindow *window = NULL;
  1945. GtkWidget *vbox1 = (GtkWidget *) 0;
  1946. GtkWidget *popuparea1 = (GtkWidget *) 0;
  1947. int xx = 0;
  1948. int yy = 0;
  1949. int pop = 1;
  1950. /* if there is alreay a popup, keep it that way */
  1951. if (popupwindow1) {
  1952. return;
  1953. }
  1954. /* top level outer window
  1955. * can also be GTK_WINDOW_POPUP but then window is
  1956. * not managed by window manager
  1957. * with POPUP the popup window is at (0,0) on the screen
  1958. * with TOPLEVEL the window can be at mouse position
  1959. * instead of next to mouse position
  1960. *the positioning of the popup window can be optimized
  1961. */
  1962. if (pop) {
  1963. popupwindow1 = gtk_window_new(GTK_WINDOW_POPUP /* or GTK_WINDOW_TOPLEVEL */ );
  1964. } else {
  1965. popupwindow1 = gtk_window_new( /* GTK_WINDOW_POPUP or */ GTK_WINDOW_TOPLEVEL);
  1966. }
  1967. /* make sure to exit oke. */
  1968. g_signal_connect(G_OBJECT(popupwindow1), "destroy", G_CALLBACK(no_popup), NULL);
  1969. /* needed for the cairo drawing */
  1970. #if (GTK_HAVE_API_VERSION_2 == 1)
  1971. /* only for gtk-2, not for gtk-3 */
  1972. gtk_widget_set_app_paintable(popupwindow1, TRUE);
  1973. #endif
  1974. /* set some title */
  1975. gtk_window_set_title(GTK_WINDOW(popupwindow1), "label");
  1976. /* pre-set size of full sized label text */
  1977. gtk_window_set_default_size(GTK_WINDOW(popupwindow1), (n->fbbx + 5) /* XSIZE */ ,
  1978. n->fbby + 5 /* YSIZE */ );
  1979. /* decorate the window */
  1980. gtk_window_set_decorated(GTK_WINDOW(popupwindow1), FALSE);
  1981. /* vbox1 */
  1982. #if (GTK_HAVE_API_VERSION_2 == 1)
  1983. vbox1 = gtk_vbox_new( /* homogeneous */ FALSE, /* spacing */ 0);
  1984. gtk_widget_show(vbox1);
  1985. gtk_container_add(GTK_CONTAINER(popupwindow1), vbox1);
  1986. #endif
  1987. #if (GTK_HAVE_API_VERSION_3 == 1)
  1988. vbox1 = gtk_box_new(GTK_ORIENTATION_VERTICAL, /* spacing */ 0);
  1989. gtk_widget_show(vbox1);
  1990. gtk_container_add(GTK_CONTAINER(popupwindow1), vbox1);
  1991. #endif
  1992. #if (GTK_HAVE_API_VERSION_4 == 1)
  1993. /* todo add gtk-4 support */
  1994. #endif
  1995. /* where to draw in hbox1 */
  1996. popuparea1 = gtk_drawing_area_new();
  1997. gtk_box_pack_start( /* box */ GTK_BOX(vbox1), /* child */ popuparea1,
  1998. /* expand */ TRUE, /* fill */ TRUE, /* padding */
  1999. PACKPADDING);
  2000. gtk_widget_show(popuparea1);
  2001. #if (GTK_HAVE_API_VERSION_2 == 1)
  2002. g_signal_connect(G_OBJECT(popuparea1), "expose_event", G_CALLBACK(popuparea1_expose_event), (gpointer) n);
  2003. #endif
  2004. #if (GTK_HAVE_API_VERSION_3 == 1)
  2005. g_signal_connect(G_OBJECT(popuparea1), "draw", G_CALLBACK(popuparea1_draw_event), (gpointer) n);
  2006. #endif
  2007. /* the label text drawing is in the expose/draw event */
  2008. if (pop) {
  2009. /* get position of window drawarea where mouse is */
  2010. window = gtk_widget_get_window(drawingarea1);
  2011. gdk_window_get_origin(window, &xx, &yy);
  2012. /* move popup right at node */
  2013. gtk_window_move(GTK_WINDOW(popupwindow1), xx + x + 15, yy + y + 0);
  2014. }
  2015. gtk_widget_show(popupwindow1);
  2016. return;
  2017. }
  2018. #endif
  2019. #if (GTK_HAVE_API_VERSION_4 == 1)
  2020. /* movement of mouse on the drawing area */
  2021. static void on_motion_notify_event(GtkEventControllerMotion * controller, double doublex, double doubley, GtkWidget * widget)
  2022. {
  2023. int x = 0;
  2024. int y = 0;
  2025. int pressed = 0;
  2026. int idx = 0;
  2027. int idy = 0;
  2028. double gdelta = 0.0;
  2029. double gsld = 0.0;
  2030. double val = 0.0;
  2031. int ival = 0;
  2032. double dhw = 0.0;
  2033. double dx = 0.0;
  2034. double dy = 0.0;
  2035. double hw = 0.0;
  2036. double hh = 0.0;
  2037. GdkModifierType state = 0;
  2038. struct gml_node *n = NULL;
  2039. if (widget) {
  2040. }
  2041. /* check if there is node data to draw */
  2042. if (validdata == 0) {
  2043. /* make sure there is no popup windows */
  2044. no_popup();
  2045. return;
  2046. }
  2047. /* get the button 1 pressed status */
  2048. state = gtk_event_controller_get_current_event_state(GTK_EVENT_CONTROLLER(controller));
  2049. if ((state & GDK_BUTTON1_MASK) != 0) {
  2050. pressed = 1;
  2051. } else {
  2052. pressed = 0;
  2053. }
  2054. /* get (x,y) */
  2055. x = (int)doublex;
  2056. y = (int)doubley;
  2057. if (yydebug || 0) {
  2058. printf("%s(): at (%d,%d) left button pressed is %d\n", __func__, x, y, pressed);
  2059. }
  2060. fflush(stdout);
  2061. /* if button left pressed move the drawing (x,y) offset */
  2062. if (pressed) {
  2063. idx = (mouse_oldx - x);
  2064. idy = (mouse_oldy - y);
  2065. if (option_gdebug || 0) {
  2066. printf("%s(): mouse is at (%d,%d) delta is (%d,%d)\n", __func__, x, y, idx, idy);
  2067. }
  2068. if ((idx == 0) && (idy == 0)) {
  2069. /* no change needed */
  2070. return;
  2071. }
  2072. if (idx != 0) {
  2073. hw = (double)(x);
  2074. dx = (double)(mouse_oldx + vxmin) / zfactor;
  2075. dhw = ((double)(hw + vxmin) / zfactor);
  2076. gdelta = dx - dhw;
  2077. vxmin = vxmin + (int)gdelta;
  2078. if (vxmin < 0) {
  2079. vxmin = 0;
  2080. }
  2081. if (vxmin > maxx) {
  2082. vxmin = maxx;
  2083. }
  2084. /* */
  2085. gsld = (gdelta / maxx);
  2086. gsld = (gsld * 100);
  2087. val = gtk_adjustment_get_value(GTK_ADJUSTMENT(adjhscale1));
  2088. ival = (int)val;
  2089. ival = ival + (int)gsld;
  2090. if (ival < 0) {
  2091. ival = 0;
  2092. }
  2093. if (ival > 100) {
  2094. ival = 100;
  2095. }
  2096. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjhscale1), ival);
  2097. }
  2098. if (idy != 0) {
  2099. hh = (double)(y);
  2100. dy = (double)(mouse_oldy + vymin) / zfactor;
  2101. dhw = (hh + vymin) / zfactor;
  2102. gdelta = dy - dhw;
  2103. vymin = vymin + (int)gdelta;
  2104. if (vymin < 0) {
  2105. vymin = 0;
  2106. }
  2107. if (vymin > maxy) {
  2108. vymin = maxy;
  2109. }
  2110. /* */
  2111. gsld = (gdelta / maxy);
  2112. gsld = (gsld * 100);
  2113. val = gtk_adjustment_get_value(GTK_ADJUSTMENT(adjvscale2));
  2114. ival = (int)val;
  2115. ival = ival + (int)gsld;
  2116. if (ival < 0) {
  2117. ival = 0;
  2118. }
  2119. if (ival > 100) {
  2120. ival = 100;
  2121. }
  2122. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale2), ival);
  2123. }
  2124. /* save */
  2125. mouse_oldx = x;
  2126. mouse_oldy = y;
  2127. /* only redraw needed */
  2128. gtk_widget_queue_draw(drawingarea1);
  2129. }
  2130. /* show popup window with node label text if option is set */
  2131. if (option_popup) {
  2132. /* only if there is no popup */
  2133. /* check if node is at mouse location */
  2134. n = is_node_at_xy(x, y);
  2135. if (n) {
  2136. if (yydebug || 0) {
  2137. printf("%s(): found node at cursor\n", __func__);
  2138. }
  2139. /* node text must have a size */
  2140. if ((n->fbbx > 10) && (n->fbby > 10)) {
  2141. /* popup window with node label text */
  2142. do_popup(n, x, y);
  2143. }
  2144. } else {
  2145. /* make sure there is no popup windows */
  2146. no_popup();
  2147. }
  2148. } else {
  2149. /* make sure there is no popup windows */
  2150. no_popup();
  2151. }
  2152. return;
  2153. }
  2154. #endif
  2155. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  2156. /* dragging drawing when left button 1 is held down */
  2157. static gboolean on_motion_notify_event(GtkWidget * widget, GdkEventMotion * event)
  2158. {
  2159. int x = 0;
  2160. int y = 0;
  2161. int idx = 0;
  2162. int idy = 0;
  2163. double gdelta = 0.0;
  2164. double gsld = 0.0;
  2165. double val = 0.0;
  2166. int ival = 0;
  2167. double dhw = 0.0;
  2168. double dx = 0.0;
  2169. double dy = 0.0;
  2170. double hw = 0.0;
  2171. double hh = 0.0;
  2172. GdkModifierType state = 0;
  2173. struct gml_node *n = NULL;
  2174. /* check if there is node data to draw */
  2175. if (validdata == 0) {
  2176. /* make sure there is no popup windows */
  2177. no_popup();
  2178. return (TRUE);
  2179. }
  2180. if (event == NULL) {
  2181. /* shouldnothappen */
  2182. }
  2183. /* where mouse click is on window and mouse status */
  2184. #if (GTK_HAVE_API_VERSION_2 == 1)
  2185. gdk_window_get_pointer(widget->window, &x, &y, &state);
  2186. #endif
  2187. #if (GTK_HAVE_API_VERSION_3 == 1)
  2188. if (event) {
  2189. gdk_window_get_device_position(gtk_widget_get_window(widget), event->device, &x, &y, &state);
  2190. } else {
  2191. /* shouldnothappen */
  2192. state = 0;
  2193. x = 0;
  2194. y = 0;
  2195. }
  2196. #endif
  2197. if ((state & GDK_BUTTON1_MASK) != 0) {
  2198. idx = (mouse_oldx - x);
  2199. idy = (mouse_oldy - y);
  2200. if (option_gdebug || 0) {
  2201. printf("%s(): mouse is at (%d,%d) delta is (%d,%d)\n", __func__, x, y, idx, idy);
  2202. fflush(stdout);
  2203. }
  2204. if ((idx == 0) && (idy == 0)) {
  2205. return (TRUE);
  2206. }
  2207. if (idx != 0) {
  2208. hw = (double)(x);
  2209. dx = (double)(mouse_oldx + vxmin) / zfactor;
  2210. dhw = ((double)(hw + vxmin) / zfactor);
  2211. gdelta = dx - dhw;
  2212. vxmin = vxmin + (int)gdelta;
  2213. if (vxmin < 0) {
  2214. vxmin = 0;
  2215. }
  2216. if (vxmin > maxx) {
  2217. vxmin = maxx;
  2218. }
  2219. /* */
  2220. gsld = (gdelta / maxx);
  2221. gsld = (gsld * 100);
  2222. val = gtk_adjustment_get_value(GTK_ADJUSTMENT(adjhscale1));
  2223. ival = (int)val;
  2224. ival = ival + (int)gsld;
  2225. if (ival < 0) {
  2226. ival = 0;
  2227. }
  2228. if (ival > 100) {
  2229. ival = 100;
  2230. }
  2231. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjhscale1), ival);
  2232. }
  2233. if (idy != 0) {
  2234. hh = (double)(y);
  2235. dy = (double)(mouse_oldy + vymin) / zfactor;
  2236. dhw = (hh + vymin) / zfactor;
  2237. gdelta = dy - dhw;
  2238. vymin = vymin + (int)gdelta;
  2239. if (vymin < 0) {
  2240. vymin = 0;
  2241. }
  2242. if (vymin > maxy) {
  2243. vymin = maxy;
  2244. }
  2245. /* */
  2246. gsld = (gdelta / maxy);
  2247. gsld = (gsld * 100);
  2248. val = gtk_adjustment_get_value(GTK_ADJUSTMENT(adjvscale2));
  2249. ival = (int)val;
  2250. ival = ival + (int)gsld;
  2251. if (ival < 0) {
  2252. ival = 0;
  2253. }
  2254. if (ival > 100) {
  2255. ival = 100;
  2256. }
  2257. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale2), ival);
  2258. }
  2259. /* save */
  2260. mouse_oldx = x;
  2261. mouse_oldy = y;
  2262. /* only redraw needed */
  2263. gtk_widget_queue_draw(drawingarea1);
  2264. }
  2265. /* show popup window with node label text if option is set */
  2266. if (option_popup) {
  2267. /* only if there is no popup */
  2268. /* check if node is at mouse location */
  2269. n = is_node_at_xy(x, y);
  2270. if (n) {
  2271. /* node text must have a size */
  2272. if ((n->fbbx > 10) && (n->fbby > 10)) {
  2273. /* popup window with node label text */
  2274. do_popup(n, x, y);
  2275. }
  2276. } else {
  2277. /* make sure there is no popup windows */
  2278. no_popup();
  2279. }
  2280. } else {
  2281. /* make sure there is no popup windows */
  2282. no_popup();
  2283. }
  2284. return (TRUE);
  2285. }
  2286. #endif
  2287. /* mouse click on drawing area
  2288. *
  2289. * guint event->type has this info
  2290. * enum GdkEventType
  2291. * {
  2292. * .
  2293. * GDK_BUTTON_PRESS = 4, (single click)
  2294. * GDK_2BUTTON_PRESS = 5, (double click)
  2295. * GDK_3BUTTON_PRESS = 6, (triple click)
  2296. * GDK_BUTTON_RELEASE = 7, (released)
  2297. * ...
  2298. * };
  2299. * which button is clicked is in guint event->button;
  2300. * the button which was pressed or released, numbered from 1 to 5.
  2301. * Normally button 1 is the left mouse button,
  2302. * 2 is the middle button, and 3 is the right button.
  2303. * On 2-button mice, the middle button can often be simulated
  2304. * by pressing both mouse buttons together.
  2305. * for dragging the mouse (x,y) is saved.
  2306. */
  2307. #if (GTK_HAVE_API_VERSION_4 == 1)
  2308. /* on_mouse_clicked is handled in motion notify */
  2309. #endif
  2310. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  2311. static gboolean on_mouse_clicked(GtkWidget * widget, GdkEventButton * event, gpointer user_data)
  2312. {
  2313. int eventbutton = 0;
  2314. double dx = 0.0;
  2315. double dy = 0.0;
  2316. int nx = 0;
  2317. int ny = 0;
  2318. int ex = 0;
  2319. int ey = 0;
  2320. if (widget) {
  2321. }
  2322. if (user_data) {
  2323. }
  2324. /* check if there is node data to draw */
  2325. if (validdata == 0) {
  2326. return (TRUE);
  2327. }
  2328. /* get where clicked in the drawing */
  2329. ex = (event->x);
  2330. ey = (event->y);
  2331. dx = ((double)ex / zfactor);
  2332. dy = ((double)ey / zfactor);
  2333. nx = ((int)dx) + vxmin;
  2334. ny = ((int)dy) + vymin;
  2335. if (nx) {
  2336. }
  2337. if (ny) {
  2338. }
  2339. /* check the buttons */
  2340. eventbutton = (int)(event->button);
  2341. /* check the buttons after modification */
  2342. if (eventbutton == 1) {
  2343. /* left button drag drawing using motion_notify_event */
  2344. mouse_oldx = ex;
  2345. mouse_oldy = ey;
  2346. return (TRUE);
  2347. }
  2348. if (eventbutton == 2) {
  2349. /* middle button clicked */
  2350. return (TRUE);
  2351. }
  2352. if (eventbutton == 3) {
  2353. /* right button clicked */
  2354. return (TRUE);
  2355. }
  2356. if (eventbutton == 4) {
  2357. /* button 4 clicked */
  2358. return (TRUE);
  2359. }
  2360. if (eventbutton == 5) {
  2361. /* button 5 clicked */
  2362. return (TRUE);
  2363. }
  2364. if (eventbutton == 6) {
  2365. return TRUE;
  2366. }
  2367. if (eventbutton == 7) {
  2368. return TRUE;
  2369. }
  2370. if (eventbutton == 8) {
  2371. /* lower side button */
  2372. return TRUE;
  2373. }
  2374. if (eventbutton == 9) {
  2375. /* upper side button */
  2376. return TRUE;
  2377. }
  2378. /* unknown button */
  2379. return TRUE;
  2380. }
  2381. #endif
  2382. /* debug print layout of one cluster */
  2383. static void do_layout_all_rprint(struct gml_graph *g)
  2384. {
  2385. struct gml_nlist *lnl = NULL;
  2386. char *s = NULL;
  2387. lnl = g->nodelist;
  2388. while (lnl) {
  2389. s = "";
  2390. if (lnl->node->dummy) {
  2391. s = "dummynode";
  2392. }
  2393. if (lnl->node->elabel) {
  2394. s = "edgelabel";
  2395. }
  2396. printf("%s(): node %d is at (%d,%d) %s\n", __func__, lnl->node->nr, lnl->node->relx, lnl->node->rely, s);
  2397. lnl = lnl->next;
  2398. }
  2399. return;
  2400. }
  2401. /* incremental layout */
  2402. static void do_layout_all_r(struct gml_graph *g)
  2403. {
  2404. struct gml_glist *gl = NULL;
  2405. if (g == NULL) {
  2406. return;
  2407. }
  2408. gl = g->subglist;
  2409. while (gl) {
  2410. do_layout_all_r(gl->sg);
  2411. gl = gl->next;
  2412. }
  2413. /* skip the subgraphs */
  2414. if (g->type != SG_CLUSTER) {
  2415. return;
  2416. }
  2417. printf("%s(): calculation layout of cluster `%s' `%s'\n", __func__, g->graphname, g->label);
  2418. /* this are the incremental layout stages */
  2419. /* re-organize nodelist */
  2420. reorg(g);
  2421. /* change cycles in the graph */
  2422. uncycle(g);
  2423. /* re-organize nodelist */
  2424. reorg(g);
  2425. /* determine startnodes */
  2426. if (1) { /* old */
  2427. startnodes(g);
  2428. }
  2429. /* longest path algorithm */
  2430. longestpath(g);
  2431. /* set y level of all nodes */
  2432. ylevels(g);
  2433. /* try to find shorter edges */
  2434. shorteredges(g);
  2435. /* change edge directions downwards */
  2436. edgesdownwards(g, 1);
  2437. /* check length of edges */
  2438. edgelen(g);
  2439. /* doublespace the vertical levels */
  2440. doublespacey(g);
  2441. /* split edges with label into node->label->node */
  2442. edgelabels(g, 0);
  2443. /* after edge label nodes are created:
  2444. * calculate (x,y) size of text area
  2445. */
  2446. static_maingtk_textsizes();
  2447. /* split longer edges */
  2448. splitedges(g, /* before bary */ 0);
  2449. /* create level node count data */
  2450. nodecounts(g);
  2451. /* determine startnodes */
  2452. if (0) {
  2453. startnodes(g);
  2454. }
  2455. /* run barycenter using defaults (0,0) or a value */
  2456. barycenter(g, 0, 0);
  2457. /* force postype */
  2458. postype = 1;
  2459. /* set the value for the new pos type */
  2460. gtk_spin_button_set_value((GtkSpinButton *) posbutton, postype);
  2461. improve_positions(g);
  2462. /* add final() edgeconn() posz() */
  2463. /* print results */
  2464. if (yydebug || 0) {
  2465. do_layout_all_rprint(g);
  2466. }
  2467. return;
  2468. }
  2469. /* run all stages of the layout
  2470. * todo pos_changed() should be able to call this
  2471. * with only updating positionings and no barycenter etc.
  2472. */
  2473. static void do_layout_all(struct gml_graph *g)
  2474. {
  2475. struct gml_glist *gl = NULL;
  2476. int modus = 0; /* barycenter layout mode 1 0 */
  2477. /* sync() is on GNU/Linux, maybe not on others */
  2478. #ifdef HAVE_SYNC
  2479. #ifdef sync
  2480. /* sync() found */
  2481. #else
  2482. /* gcc-12 analyzer says issue here */
  2483. /* sync() still not found. manual added now. */
  2484. extern void sync(void);
  2485. #endif
  2486. /* maybe safer on Linux to sync() now because next may need much extra memory */
  2487. sync();
  2488. #endif
  2489. /* this is also valid c
  2490. * int c=0;
  2491. * int javascript=0;
  2492. * if (c --> javascript) c++;
  2493. */
  2494. if (incrlayout /* 0 */ && maingraph->tnclusters) {
  2495. /* todo fixup for modus */
  2496. printf("%s(): doing incremental layout for %d clusters\n", __func__, maingraph->tnclusters);
  2497. /* prepare */
  2498. prepincr(g);
  2499. /* set edges with labels */
  2500. prepel(g);
  2501. /* recursively layout the clusters */
  2502. gl = maingraph->subglist;
  2503. while (gl) {
  2504. do_layout_all_r(gl->sg);
  2505. gl = gl->next;
  2506. }
  2507. } else {
  2508. /* this are the regular layout stages */
  2509. /* prepare */
  2510. prep(g);
  2511. /* set edges with labels */
  2512. prepel(g);
  2513. /* re-organize nodelist */
  2514. reorg(g);
  2515. /* change cycles in the graph */
  2516. uncycle(g);
  2517. /* re-organize nodelist */
  2518. reorg(g);
  2519. /* determine startnodes */
  2520. if (modus == 0 || 1) {
  2521. startnodes(g);
  2522. }
  2523. /* find longest path */
  2524. longestpath(g);
  2525. /* set y level of all nodes */
  2526. ylevels(g);
  2527. /* try to find shorter edges */
  2528. shorteredges(g);
  2529. /* change edge directions downwards */
  2530. edgesdownwards(g, 1);
  2531. /* mark same edges */
  2532. checksame(g);
  2533. if (modus == 1) {
  2534. /* split same edges */
  2535. splitsame(g);
  2536. }
  2537. /* check length of edges */
  2538. edgelen(g);
  2539. if (modus == 0) {
  2540. /* doublespace the vertical levels */
  2541. doublespacey(g);
  2542. /* split edges with label into node->label->node */
  2543. edgelabels(g, 0);
  2544. }
  2545. /* after edge label nodes are created:
  2546. * calculate (x,y) size of text area
  2547. */
  2548. static_maingtk_textsizes();
  2549. if (modus == 0) {
  2550. /* split longer edges */
  2551. splitedges(g, /* before bary */ 0);
  2552. }
  2553. /* create level node count data */
  2554. nodecounts(g);
  2555. /* run barycenter using defaults (0,0) or a value */
  2556. barycenter(g, 100, 100);
  2557. if (modus == 1) {
  2558. /* doublespace the vertical levels */
  2559. doublespaceyafter(g);
  2560. /* split longer edges */
  2561. splitedgesafter(g);
  2562. /* create level node count data */
  2563. nodecountsafter(g);
  2564. }
  2565. /* update startnodes */
  2566. startnodesafter(g);
  2567. /* final */
  2568. finalafter(g);
  2569. /* run priority algorithm */
  2570. improve_positions(g);
  2571. /* final (x,y) positioning of nodes/edges */
  2572. /* todo draw errors with dummy node routing */
  2573. /* todo works with node names and gcc data but not with irregular larger labels */
  2574. finalxy(g);
  2575. /* calculate edge connections */
  2576. /* XXXX tofix this can fail */
  2577. edgeconnections(g);
  2578. /* update sub parts of drawing */
  2579. positionz(g);
  2580. }
  2581. return;
  2582. }
  2583. /* run all stages of the layout */
  2584. static void do_relayout_all(struct gml_graph *g)
  2585. {
  2586. /* also possible to re-layout only 1 specific subgraph */
  2587. if (g) {
  2588. }
  2589. do_clear_all( /* keep raw data */ 1);
  2590. do_layout_all(maingraph);
  2591. fflush(stdout);
  2592. /* set sliders to defaults */
  2593. sliders_default();
  2594. /* fit drawing in window */
  2595. dofit();
  2596. validdata = 1;
  2597. /* update status text */
  2598. update_status_text(NULL);
  2599. return;
  2600. }
  2601. /* clear all memory used by the graph data
  2602. * if mode==0 clear all data
  2603. * if mode==1 keep some data
  2604. * used in a re-layout
  2605. */
  2606. static void do_clear_all(int mode)
  2607. {
  2608. /* no draw data */
  2609. validdata = 0;
  2610. if (mode == 0) {
  2611. /* clear db with strings */
  2612. clear_uniqstr();
  2613. /* clear db with nodes */
  2614. clear_uniqnode(NULL);
  2615. /* clear db with graph pointers */
  2616. clear_uniqgraph(NULL);
  2617. }
  2618. /* clear db with nodes */
  2619. clear_uniqnode2(NULL);
  2620. if (maingraph) {
  2621. /* clear optional record label and html of node */
  2622. if (mode == 0) {
  2623. /* clear all data */
  2624. clear_rlabel_r(maingraph);
  2625. clear_hlabel_r(maingraph);
  2626. }
  2627. /* clear number of edges between level n and n+1 */
  2628. clear_nume_r(maingraph);
  2629. /* clear number of nodes at level */
  2630. clear_nnl_r(maingraph);
  2631. /* clear arrays in/out edges */
  2632. clear_ioedges_r(maingraph);
  2633. /* clear count of crossing edges at level */
  2634. clear_numce_r(maingraph);
  2635. /* clear self-edges list */
  2636. clear_selfedgesnodelist_r(maingraph);
  2637. /* clear single nodes list */
  2638. clear_singlenodelist_r(maingraph);
  2639. /* clear startnodes array */
  2640. clear_startnodes_r(maingraph);
  2641. /* clear nodes list and its data
  2642. * if mode<>0 then keep record label data
  2643. * that will be re-used at doing re-layout
  2644. * if mode==0 clear the rlabel data
  2645. */
  2646. clear_nodelist_r(maingraph, mode);
  2647. /* clear edges list */
  2648. clear_edgelist_r(maingraph);
  2649. /* clear bubbling algorithm */
  2650. clear_bubbling(maingraph);
  2651. if (mode == 0) {
  2652. /* clear optional edge label data */
  2653. clear_edgelabeldata(maingraph);
  2654. /* clear subgraphs and optional summary node */
  2655. clear_sg(maingraph);
  2656. /* clear input nodes */
  2657. clear_rawnodelist(maingraph);
  2658. /* clear input edges */
  2659. clear_rawedgelist(maingraph);
  2660. /* clear main graph structure */
  2661. maingraph = dp_free(maingraph);
  2662. if (maingraph) {
  2663. }
  2664. }
  2665. }
  2666. return;
  2667. }
  2668. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  2669. /* finally stop the gui */
  2670. static void top_level_window_main_quit(void)
  2671. {
  2672. do_clear_all(0);
  2673. if (lastopendir) {
  2674. lastopendir = dp_free(lastopendir);
  2675. if (lastopendir) {
  2676. }
  2677. }
  2678. if (lastsavedir) {
  2679. lastsavedir = dp_free(lastsavedir);
  2680. if (lastsavedir) {
  2681. }
  2682. }
  2683. /* run the gtk internal routine to stop gtk_main() which is a for(){} loop */
  2684. gtk_main_quit();
  2685. return;
  2686. }
  2687. #endif
  2688. #if (GTK_HAVE_API_VERSION_4 == 1)
  2689. static void fullscreen_changed(GSimpleAction * action, GVariant * value, gpointer win)
  2690. {
  2691. if (g_variant_get_boolean(value)) {
  2692. gtk_window_maximize(GTK_WINDOW(win));
  2693. } else {
  2694. gtk_window_unmaximize(GTK_WINDOW(win));
  2695. }
  2696. g_simple_action_set_state(action, value);
  2697. return;
  2698. }
  2699. #endif
  2700. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  2701. /* use full screen */
  2702. static void on_top_level_window_fullscreen1_activate(GtkMenuItem * menuitem, gpointer user_data)
  2703. {
  2704. if (menuitem) {
  2705. }
  2706. if (user_data) {
  2707. }
  2708. gtk_window_fullscreen(GTK_WINDOW(mainwindow1));
  2709. return;
  2710. }
  2711. #endif
  2712. #if (GTK_HAVE_API_VERSION_4 == 1)
  2713. #endif
  2714. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  2715. /* use screen in a window */
  2716. static void on_top_level_window_unfullscreen1_activate(GtkMenuItem * menuitem, gpointer user_data)
  2717. {
  2718. if (menuitem) {
  2719. }
  2720. if (user_data) {
  2721. }
  2722. gtk_window_unfullscreen(GTK_WINDOW(mainwindow1));
  2723. return;
  2724. }
  2725. #endif
  2726. /* for windos activate product message */
  2727. #ifdef WIN32
  2728. #if (GTK_HAVE_API_VERSION_4 == 1)
  2729. #endif
  2730. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  2731. /* for the windows version */
  2732. static void on_top_level_window_activate1_activate(GtkMenuItem * menuitem, gpointer user_data)
  2733. {
  2734. GtkWidget *edialog = NULL;
  2735. char *message = "GNU GPL Free GNU/Linux software can just be used without limitations.\n"
  2736. "There is no need for product activation or a product key.\n"
  2737. "This program does not have telemetry using internet.\n"
  2738. "This program does not create or change files on your computer.\n"
  2739. "This program does not use cookies or run javascript.\n"
  2740. "This program is free to copy, share or improve with source code.\n";
  2741. if (menuitem) {
  2742. }
  2743. if (user_data) {
  2744. }
  2745. edialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  2746. GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", message);
  2747. gtk_widget_show(edialog);
  2748. gtk_dialog_run(GTK_DIALOG(edialog));
  2749. gtk_widget_destroy(edialog);
  2750. return;
  2751. }
  2752. #endif
  2753. #endif
  2754. #if (GTK_HAVE_API_VERSION_4 == 1)
  2755. /* parse the file */
  2756. static void open2_response_cb_fn(char *inputfilename, char *binputfilename)
  2757. {
  2758. gzFile f; /* the zipped file stream */
  2759. GtkWidget *dialog = NULL;
  2760. /* binputfilename is the short filename and should not be numm */
  2761. /* open file to parse */
  2762. errno = 0;
  2763. /* open zipped or unzipped file as file stream */
  2764. f = gzopen(inputfilename, "rb");
  2765. if (f == NULL || 0) {
  2766. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  2767. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  2768. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Cannot open file %s", inputfilename);
  2769. gtk_widget_show(dialog);
  2770. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  2771. /* data is unchanged, so keep validdata status */
  2772. return;
  2773. }
  2774. /* type of graph data 0=gml 1=dot 2=vcg */
  2775. graphtype = 1;
  2776. do_clear_all(0);
  2777. /* background r/g/b of drawing */
  2778. bgcr = 0xff;
  2779. bgcg = 0xff;
  2780. bgcb = 0xff;
  2781. /* create root graph */
  2782. create_maingraph();
  2783. /* parse the dot data */
  2784. if (gmlparse(maingraph, f, inputfilename, argv0)) {
  2785. /* parse error */
  2786. if (strlen(parsermessage) == 0) {
  2787. strcpy(parsermessage, "no parser message");
  2788. }
  2789. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  2790. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  2791. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", parsermessage);
  2792. gtk_widget_show(dialog);
  2793. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  2794. fflush(stdout);
  2795. gzclose(f);
  2796. /* data is invalid at this point */
  2797. validdata = 0;
  2798. do_clear_all(0);
  2799. /* use package string program name as set by configure in config.h */
  2800. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  2801. /* re draw screen */
  2802. gtk_widget_queue_draw(drawingarea1);
  2803. return;
  2804. }
  2805. fflush(stdout);
  2806. gzclose(f);
  2807. /* set the basename of file as window title /tmp/foo.dot has window title foo.dot */
  2808. if (binputfilename) {
  2809. gtk_window_set_title(GTK_WINDOW(mainwindow1), binputfilename);
  2810. } else {
  2811. gtk_window_set_title(GTK_WINDOW(mainwindow1), inputfilename);
  2812. }
  2813. /* check for empty graph here */
  2814. if (maingraph->rawnodelist) {
  2815. printf("%s(): calculating layout of file %s\n", __func__, inputfilename);
  2816. fflush(stdout);
  2817. /* update status text */
  2818. update_status_text("Wait ... Calculating Layout");
  2819. do_layout_all(maingraph);
  2820. fflush(stdout);
  2821. /* update status text */
  2822. update_status_text(NULL);
  2823. /* set sliders to defaults */
  2824. /* fit drawing in window */
  2825. dofit();
  2826. validdata = 1;
  2827. } else {
  2828. /* update status text */
  2829. update_status_text("Empty graph ... No Nodes");
  2830. validdata = 0;
  2831. }
  2832. return;
  2833. }
  2834. /* run dialog and set bool done to TRUE if ready */
  2835. static void open2_response_cb(GtkDialog * dialog, int response_id, gpointer data)
  2836. {
  2837. gboolean *done = data; /* bool to set is passed on at call */
  2838. GListModel *files = NULL;
  2839. guint i = 0;
  2840. guint n = 0;
  2841. GFile *file = NULL;
  2842. GFile *folder = NULL;
  2843. char *uri = NULL;
  2844. char *file_chooser_dir = NULL;
  2845. char *inputfilename = NULL;
  2846. char *file_chooser_filename = NULL;
  2847. char *bname = NULL;
  2848. if (response_id == GTK_RESPONSE_OK) {
  2849. /* scan the list with selected files */
  2850. files = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog));
  2851. n = g_list_model_get_n_items(files);
  2852. if (yydebug || 0) {
  2853. g_print("%s(): selected %d files\n", __func__, n);
  2854. }
  2855. for (i = 0; i < n; i++) {
  2856. file = g_list_model_get_item(files, i);
  2857. uri = g_file_get_uri(file);
  2858. /* option here
  2859. * the uri is like file:///bin/true
  2860. * this allows for network uri
  2861. * as https://graphviewer.nl/data/example.dot
  2862. */
  2863. if (uri == NULL) {
  2864. g_print("%s(): file %d has nil name\n", __func__, i);
  2865. } else {
  2866. if (strlen(uri) == 0) {
  2867. g_print("%s(): file %d has empty name \"\"\n", __func__, i);
  2868. } else {
  2869. if (i != 0) {
  2870. g_print("%s(): skipped file %d with name %s\n", __func__, i, uri);
  2871. } else {
  2872. /* this is the first file to read
  2873. * uri is file:///bin/foo
  2874. * g_file_get_parse_name(file) is /bin/foo
  2875. * g_file_get_basename(file) is foo
  2876. * g_file_get_path(file) is /bin/foo
  2877. */
  2878. /* update directory of chosen file */
  2879. folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
  2880. if (folder) {
  2881. file_chooser_dir = g_file_get_parse_name(folder);
  2882. if (file_chooser_dir) {
  2883. if (lastopendir) {
  2884. lastopendir = dp_free(lastopendir);
  2885. if (lastopendir) {
  2886. }
  2887. }
  2888. lastopendir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  2889. strcpy(lastopendir, file_chooser_dir);
  2890. g_free(file_chooser_dir);
  2891. file_chooser_dir = NULL;
  2892. }
  2893. g_object_unref(folder);
  2894. }
  2895. /* copy filename */
  2896. file_chooser_filename = g_file_get_parse_name(file);
  2897. if (file_chooser_filename) {
  2898. if (strlen(file_chooser_filename)) {
  2899. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  2900. strcpy(inputfilename, file_chooser_filename);
  2901. } else {
  2902. g_print("%s(): empty filename\n", __func__);
  2903. }
  2904. bname = g_file_get_basename(file);
  2905. /* read and parse the file */
  2906. open2_response_cb_fn(file_chooser_filename, bname);
  2907. if (bname) {
  2908. g_free(bname);
  2909. bname = NULL;
  2910. };
  2911. /* there could have been a parse error */
  2912. g_free(file_chooser_filename);
  2913. file_chooser_filename = NULL;
  2914. }
  2915. /* print the derived filenames */
  2916. if (yydebug || 0) {
  2917. g_print("%s(): %s %s %s %s %s\n", __func__, g_file_get_parse_name(file),
  2918. g_file_get_basename(file), uri, g_file_get_path(file), g_file_get_parse_name(folder));
  2919. }
  2920. }
  2921. }
  2922. g_free(uri);
  2923. uri = NULL;
  2924. }
  2925. g_object_unref(file);
  2926. }
  2927. g_object_unref(files);
  2928. } else {
  2929. /* no file selected */
  2930. if (yydebug || 0) {
  2931. g_print("%s(): open dialog was closed\n", __func__);
  2932. }
  2933. }
  2934. /* inicate this dialog is finished in passed on var */
  2935. *done = TRUE;
  2936. g_main_context_wakeup(NULL);
  2937. return;
  2938. }
  2939. /* open dot file */
  2940. static void open2_activated(GSimpleAction * action, GVariant * parameter, gpointer user_data)
  2941. {
  2942. gboolean multiple = FALSE; /* if TRUE multiple files can be selected as extended feature */
  2943. GtkWidget *dialog = NULL;
  2944. GtkFileFilter *filter = NULL;
  2945. gboolean done = FALSE; /* indicator dialog is finished */
  2946. if (action) {
  2947. }
  2948. if (parameter) {
  2949. }
  2950. if (user_data) {
  2951. }
  2952. /* see the testcase in gtk-4 testfilechooser.c */
  2953. dialog = g_object_new(GTK_TYPE_FILE_CHOOSER_DIALOG, "action", GTK_FILE_CHOOSER_ACTION_OPEN, "select-multiple", multiple, NULL);
  2954. gtk_window_set_title(GTK_WINDOW(dialog), "Open gml graph file");
  2955. gtk_dialog_add_buttons(GTK_DIALOG(dialog), ("_Cancel"), GTK_RESPONSE_CANCEL, ("_Open"), GTK_RESPONSE_OK, NULL);
  2956. gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
  2957. /* the callback will set bool done to TRUE if ready */
  2958. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(open2_response_cb), (gpointer) & done);
  2959. /* Filters */
  2960. filter = gtk_file_filter_new();
  2961. gtk_file_filter_set_name(filter, "All Files");
  2962. gtk_file_filter_add_pattern(filter, "*");
  2963. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  2964. filter = gtk_file_filter_new();
  2965. gtk_file_filter_set_name(filter, "gml");
  2966. gtk_file_filter_add_pattern(filter, "*.gml");
  2967. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  2968. /* this are the gzipped graph files */
  2969. filter = gtk_file_filter_new();
  2970. gtk_file_filter_set_name(filter, "gml.gz");
  2971. gtk_file_filter_add_pattern(filter, "*.gml.gz");
  2972. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  2973. if (lastopendir) {
  2974. set_current_folder(GTK_FILE_CHOOSER(dialog), lastopendir);
  2975. }
  2976. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  2977. gtk_widget_show(dialog);
  2978. /* run dialog and wait until it is ready */
  2979. while (done == FALSE) {
  2980. g_main_context_iteration(NULL, TRUE);
  2981. }
  2982. gtk_window_destroy(GTK_WINDOW(dialog));
  2983. return;
  2984. }
  2985. #endif
  2986. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  2987. /* 'open' in 'file' menu activated - sub menu in menu items in menu bar in vbox1 */
  2988. static void on_top_level_window_open1_activate(GtkMenuItem * menuitem, gpointer user_data)
  2989. {
  2990. GtkWidget *edialog = (GtkWidget *) 0;
  2991. GtkWidget *pdialog = (GtkWidget *) 0;
  2992. GtkWidget *dialog = (GtkWidget *) 0;
  2993. char *file_chooser_filename = (char *)0;
  2994. char *file_chooser_dir = (char *)0;
  2995. GtkFileChooser *chooser = NULL;
  2996. char *inputfilename = (char *)0;
  2997. char *baseinputfilename = (char *)0;
  2998. char *baseinputfilename2 = (char *)0;
  2999. gzFile fgml = (gzFile) 0;
  3000. char *bname = NULL;
  3001. int cnt = 0;
  3002. if (menuitem) {
  3003. }
  3004. if (user_data) {
  3005. }
  3006. #if (GTK_HAVE_API_VERSION_2 == 1)
  3007. /* see gimp source code howto */
  3008. dialog = gtk_file_chooser_dialog_new("Select GML Graph File", 0, /* parent_window */
  3009. GTK_FILE_CHOOSER_ACTION_OPEN,
  3010. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
  3011. #endif
  3012. #if (GTK_HAVE_API_VERSION_3 == 1)
  3013. /* see gimp source code howto */
  3014. dialog = gtk_file_chooser_dialog_new("Select GML Graph File", GTK_WINDOW(mainwindow1) /* parent_window */
  3015. ,
  3016. GTK_FILE_CHOOSER_ACTION_OPEN,
  3017. "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
  3018. #endif
  3019. chooser = GTK_FILE_CHOOSER(dialog);
  3020. /* use same dir if opened in earlier dir */
  3021. if (lastopendir) {
  3022. gtk_file_chooser_set_current_folder(chooser, lastopendir);
  3023. }
  3024. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  3025. /* run the window to select a input file */
  3026. if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
  3027. /* open button */
  3028. file_chooser_filename = (char *)gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
  3029. file_chooser_dir = (char *)gtk_file_chooser_get_current_folder(chooser);
  3030. } else {
  3031. /* cancel button */
  3032. (void)gtk_widget_destroy(dialog);
  3033. return;
  3034. }
  3035. /* */
  3036. (void)gtk_widget_destroy(dialog);
  3037. /* update last-used-dir */
  3038. if (file_chooser_dir) {
  3039. if (lastopendir) {
  3040. lastopendir = dp_free(lastopendir);
  3041. if (lastopendir) {
  3042. }
  3043. }
  3044. lastopendir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  3045. strcpy(lastopendir, file_chooser_dir);
  3046. /* not dp_free() because gtk allocated */
  3047. g_free(file_chooser_dir);
  3048. }
  3049. /* copy the input filename from gtk */
  3050. if (file_chooser_filename) {
  3051. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  3052. strcpy(inputfilename, file_chooser_filename);
  3053. /* not dp_free() because gtk allocated */
  3054. g_free(file_chooser_filename);
  3055. } else {
  3056. return;
  3057. }
  3058. /* set filename in window */
  3059. bname = g_path_get_basename(inputfilename);
  3060. baseinputfilename2 = dp_calloc(1, (strlen(bname) + 1));
  3061. strcpy(baseinputfilename2, bname);
  3062. /* not dp_free() because gtk allocated */
  3063. g_free(bname);
  3064. /* open file to parse */
  3065. errno = 0;
  3066. fgml = gzopen(inputfilename, "r");
  3067. if (fgml == (gzFile) 0 || 0) {
  3068. edialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  3069. GTK_DIALOG_DESTROY_WITH_PARENT,
  3070. GTK_MESSAGE_ERROR,
  3071. GTK_BUTTONS_CLOSE,
  3072. "Cannot open file %s for reading (%s)", inputfilename, g_strerror(errno));
  3073. gtk_dialog_run(GTK_DIALOG(edialog));
  3074. gtk_widget_destroy(edialog);
  3075. if (inputfilename) {
  3076. inputfilename = dp_free(inputfilename);
  3077. if (inputfilename) {
  3078. }
  3079. }
  3080. baseinputfilename2 = dp_free(baseinputfilename2);
  3081. if (baseinputfilename2) {
  3082. }
  3083. /* data is unchanged, so keep validdata status */
  3084. return;
  3085. }
  3086. /* type of graph data 0=gml 1=dot 2=vcg */
  3087. graphtype = 0;
  3088. do_clear_all(0);
  3089. /* background r/g/b of drawing */
  3090. bgcr = 0xff;
  3091. bgcg = 0xff;
  3092. bgcb = 0xff;
  3093. /* create root graph */
  3094. create_maingraph();
  3095. /* parse the gml data
  3096. * the next line is a bug not detected by the source code checker software
  3097. * if (gmlparse(maingraph, fgml, baseinputfilename2) > 0 && 0 < gmlparse(maingraph, fgml, baseinputfilename2))
  3098. * such kind of bugs do happen and can have big impact on the functionality
  3099. */
  3100. if (gmlparse(maingraph, fgml, baseinputfilename2, argv0) != 0) {
  3101. /* parse error */
  3102. if (strlen(parsermessage) == 0) {
  3103. strcpy(parsermessage, "no parser message");
  3104. }
  3105. pdialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  3106. GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", parsermessage);
  3107. gtk_dialog_run(GTK_DIALOG(pdialog));
  3108. gtk_widget_destroy(pdialog);
  3109. inputfilename = dp_free(inputfilename);
  3110. if (inputfilename) {
  3111. }
  3112. baseinputfilename2 = dp_free(baseinputfilename2);
  3113. if (baseinputfilename2) {
  3114. }
  3115. gzclose(fgml);
  3116. /* data is invalid at this point */
  3117. validdata = 0;
  3118. do_clear_all(0);
  3119. /* use package string program name as set by configure in config.h */
  3120. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  3121. /* re draw screen */
  3122. gtk_widget_queue_draw(drawingarea1);
  3123. return;
  3124. }
  3125. gzclose(fgml);
  3126. bname = g_path_get_basename(inputfilename);
  3127. baseinputfilename = uniqstr(bname);
  3128. /* not dp_free because gtk allocated */
  3129. g_free(bname);
  3130. gtk_window_set_title(GTK_WINDOW(mainwindow1), baseinputfilename);
  3131. /* check for empty graph here */
  3132. if (maingraph->rawnodelist) {
  3133. printf("%s(): calculating layout of file %s\n", __func__, baseinputfilename2);
  3134. fflush(stdout);
  3135. /* update status text */
  3136. update_status_text("Wait ... Calculating Layout");
  3137. #if (GTK_HAVE_API_VERSION_4 == 1)
  3138. #endif
  3139. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  3140. cnt = 1000;
  3141. while (gtk_events_pending()) {
  3142. cnt--;
  3143. if (cnt > 0) {
  3144. gtk_main_iteration();
  3145. /* this updates the status text */
  3146. }
  3147. }
  3148. #endif
  3149. do_layout_all(maingraph);
  3150. fflush(stdout);
  3151. /* update status text */
  3152. update_status_text(NULL);
  3153. while (gtk_main_iteration()) {
  3154. /* this should update the status text */ ;
  3155. }
  3156. /* set sliders to defaults */
  3157. zfactor = 1.0;
  3158. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale1), 50);
  3159. vxmin = 0;
  3160. vymin = 0;
  3161. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale2), 0);
  3162. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjhscale1), 0);
  3163. /* filename is not saved */
  3164. inputfilename = dp_free(inputfilename);
  3165. if (inputfilename) {
  3166. }
  3167. baseinputfilename2 = dp_free(baseinputfilename2);
  3168. if (baseinputfilename2) {
  3169. }
  3170. /* fit drawing in window */
  3171. dofit();
  3172. validdata = 1;
  3173. } else {
  3174. /* filename is not saved */
  3175. inputfilename = dp_free(inputfilename);
  3176. if (inputfilename) {
  3177. }
  3178. baseinputfilename2 = dp_free(baseinputfilename2);
  3179. if (baseinputfilename2) {
  3180. }
  3181. /* update status text */
  3182. update_status_text("Empty graph ... No Nodes");
  3183. validdata = 0;
  3184. }
  3185. /* re draw screen */
  3186. gtk_widget_queue_draw(drawingarea1);
  3187. return;
  3188. }
  3189. #endif
  3190. #if (GTK_HAVE_API_VERSION_4 == 1)
  3191. /* parse the file */
  3192. static void open5_response_cb_fn(char *inputfilename, char *binputfilename)
  3193. {
  3194. gzFile f; /* the zipped file stream */
  3195. GtkWidget *dialog = NULL;
  3196. /* binputfilename is the short filename and should not be numm */
  3197. /* open file to parse */
  3198. errno = 0;
  3199. /* open zipped or unzipped file as file stream */
  3200. f = gzopen(inputfilename, "rb");
  3201. if (f == NULL || 0) {
  3202. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  3203. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  3204. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Cannot open file %s", inputfilename);
  3205. gtk_widget_show(dialog);
  3206. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  3207. /* data is unchanged, so keep validdata status */
  3208. return;
  3209. }
  3210. /* type of graph data 0=gml 1=dot 2=vcg */
  3211. graphtype = 1;
  3212. do_clear_all(0);
  3213. /* background r/g/b of drawing */
  3214. bgcr = 0xff;
  3215. bgcg = 0xff;
  3216. bgcb = 0xff;
  3217. /* create root graph */
  3218. create_maingraph();
  3219. /* parse the jgf data */
  3220. if (bgvparse(maingraph, f, inputfilename, argv0)) {
  3221. /* parse error */
  3222. if (strlen(parsermessage) == 0) {
  3223. strcpy(parsermessage, "no parser message");
  3224. }
  3225. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  3226. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  3227. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", parsermessage);
  3228. gtk_widget_show(dialog);
  3229. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  3230. fflush(stdout);
  3231. gzclose(f);
  3232. /* data is invalid at this point */
  3233. validdata = 0;
  3234. do_clear_all(0);
  3235. /* use package string program name as set by configure in config.h */
  3236. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  3237. /* re draw screen */
  3238. gtk_widget_queue_draw(drawingarea1);
  3239. return;
  3240. }
  3241. fflush(stdout);
  3242. gzclose(f);
  3243. /* set the basename of file as window title /tmp/foo.dot has window title foo.dot */
  3244. if (binputfilename) {
  3245. gtk_window_set_title(GTK_WINDOW(mainwindow1), binputfilename);
  3246. } else {
  3247. gtk_window_set_title(GTK_WINDOW(mainwindow1), inputfilename);
  3248. }
  3249. /* check for empty graph here */
  3250. if (maingraph->rawnodelist) {
  3251. printf("%s(): calculating layout of file %s\n", __func__, inputfilename);
  3252. fflush(stdout);
  3253. /* update status text */
  3254. update_status_text("Wait ... Calculating Layout");
  3255. do_layout_all(maingraph);
  3256. fflush(stdout);
  3257. /* update status text */
  3258. update_status_text(NULL);
  3259. /* set sliders to defaults */
  3260. /* fit drawing in window */
  3261. dofit();
  3262. validdata = 1;
  3263. } else {
  3264. /* update status text */
  3265. update_status_text("Empty graph ... No Nodes");
  3266. validdata = 0;
  3267. }
  3268. return;
  3269. }
  3270. /* run dialog and set bool done to TRUE if ready */
  3271. static void open5_response_cb(GtkDialog * dialog, int response_id, gpointer data)
  3272. {
  3273. gboolean *done = data; /* bool to set is passed on at call */
  3274. GListModel *files = NULL;
  3275. guint i = 0;
  3276. guint n = 0;
  3277. GFile *file = NULL;
  3278. GFile *folder = NULL;
  3279. char *uri = NULL;
  3280. char *file_chooser_dir = NULL;
  3281. char *inputfilename = NULL;
  3282. char *file_chooser_filename = NULL;
  3283. char *bname = NULL;
  3284. if (response_id == GTK_RESPONSE_OK) {
  3285. /* scan the list with selected files */
  3286. files = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog));
  3287. n = g_list_model_get_n_items(files);
  3288. if (yydebug || 0) {
  3289. g_print("%s(): selected %d files\n", __func__, n);
  3290. }
  3291. for (i = 0; i < n; i++) {
  3292. file = g_list_model_get_item(files, i);
  3293. uri = g_file_get_uri(file);
  3294. /* option here
  3295. * the uri is like file:///bin/true
  3296. * this allows for network uri
  3297. * as https://graphviewer.nl/data/example.dot
  3298. */
  3299. if (uri == NULL) {
  3300. g_print("%s(): file %d has nil name\n", __func__, i);
  3301. } else {
  3302. if (strlen(uri) == 0) {
  3303. g_print("%s(): file %d has empty name \"\"\n", __func__, i);
  3304. } else {
  3305. if (i != 0) {
  3306. g_print("%s(): skipped file %d with name %s\n", __func__, i, uri);
  3307. } else {
  3308. /* this is the first file to read
  3309. * uri is file:///bin/foo
  3310. * g_file_get_parse_name(file) is /bin/foo
  3311. * g_file_get_basename(file) is foo
  3312. * g_file_get_path(file) is /bin/foo
  3313. */
  3314. /* update directory of chosen file */
  3315. folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
  3316. if (folder) {
  3317. file_chooser_dir = g_file_get_parse_name(folder);
  3318. if (file_chooser_dir) {
  3319. if (lastopendir) {
  3320. lastopendir = dp_free(lastopendir);
  3321. if (lastopendir) {
  3322. }
  3323. }
  3324. lastopendir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  3325. strcpy(lastopendir, file_chooser_dir);
  3326. g_free(file_chooser_dir);
  3327. file_chooser_dir = NULL;
  3328. }
  3329. g_object_unref(folder);
  3330. }
  3331. /* copy filename */
  3332. file_chooser_filename = g_file_get_parse_name(file);
  3333. if (file_chooser_filename) {
  3334. if (strlen(file_chooser_filename)) {
  3335. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  3336. strcpy(inputfilename, file_chooser_filename);
  3337. } else {
  3338. g_print("%s(): empty filename\n", __func__);
  3339. }
  3340. bname = g_file_get_basename(file);
  3341. /* read and parse the file */
  3342. open5_response_cb_fn(file_chooser_filename, bname);
  3343. if (bname) {
  3344. g_free(bname);
  3345. bname = NULL;
  3346. };
  3347. /* there could have been a parse error */
  3348. g_free(file_chooser_filename);
  3349. file_chooser_filename = NULL;
  3350. }
  3351. /* print the derived filenames */
  3352. if (yydebug || 0) {
  3353. g_print("%s(): %s %s %s %s %s\n", __func__, g_file_get_parse_name(file),
  3354. g_file_get_basename(file), uri, g_file_get_path(file), g_file_get_parse_name(folder));
  3355. }
  3356. }
  3357. }
  3358. g_free(uri);
  3359. uri = NULL;
  3360. }
  3361. g_object_unref(file);
  3362. }
  3363. g_object_unref(files);
  3364. } else {
  3365. /* no file selected */
  3366. if (yydebug || 0) {
  3367. g_print("%s(): open dialog was closed\n", __func__);
  3368. }
  3369. }
  3370. /* inicate this dialog is finished in passed on var */
  3371. *done = TRUE;
  3372. g_main_context_wakeup(NULL);
  3373. return;
  3374. }
  3375. /* open bgv file */
  3376. static void open5_activated(GSimpleAction * action, GVariant * parameter, gpointer user_data)
  3377. {
  3378. gboolean multiple = FALSE; /* if TRUE multiple files can be selected as extended feature */
  3379. GtkWidget *dialog = NULL;
  3380. GtkFileFilter *filter = NULL;
  3381. gboolean done = FALSE; /* indicator dialog is finished */
  3382. if (action) {
  3383. }
  3384. if (parameter) {
  3385. }
  3386. if (user_data) {
  3387. }
  3388. /* see the testcase in gtk-4 testfilechooser.c */
  3389. dialog = g_object_new(GTK_TYPE_FILE_CHOOSER_DIALOG, "action", GTK_FILE_CHOOSER_ACTION_OPEN, "select-multiple", multiple, NULL);
  3390. gtk_window_set_title(GTK_WINDOW(dialog), "Open bgv graph file");
  3391. gtk_dialog_add_buttons(GTK_DIALOG(dialog), ("_Cancel"), GTK_RESPONSE_CANCEL, ("_Open"), GTK_RESPONSE_OK, NULL);
  3392. gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
  3393. /* the callback will set bool done to TRUE if ready */
  3394. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(open5_response_cb), (gpointer) & done);
  3395. /* Filters */
  3396. filter = gtk_file_filter_new();
  3397. gtk_file_filter_set_name(filter, "All Files");
  3398. gtk_file_filter_add_pattern(filter, "*");
  3399. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  3400. filter = gtk_file_filter_new();
  3401. gtk_file_filter_set_name(filter, "bgv");
  3402. gtk_file_filter_add_pattern(filter, "*.bgv");
  3403. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  3404. /* this are the gzipped graph files */
  3405. filter = gtk_file_filter_new();
  3406. gtk_file_filter_set_name(filter, "bgv.gz");
  3407. gtk_file_filter_add_pattern(filter, "*.bgv.gz");
  3408. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  3409. if (lastopendir) {
  3410. set_current_folder(GTK_FILE_CHOOSER(dialog), lastopendir);
  3411. }
  3412. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  3413. gtk_widget_show(dialog);
  3414. /* run dialog and wait until it is ready */
  3415. while (done == FALSE) {
  3416. g_main_context_iteration(NULL, TRUE);
  3417. }
  3418. gtk_window_destroy(GTK_WINDOW(dialog));
  3419. return;
  3420. }
  3421. #endif
  3422. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  3423. /* 'open' in 'file' menu activated - sub menu in menu items in menu bar in vbox1 */
  3424. static void on_top_level_window_open5_activate(GtkMenuItem * menuitem, gpointer user_data)
  3425. {
  3426. GtkWidget *edialog = (GtkWidget *) 0;
  3427. GtkWidget *pdialog = (GtkWidget *) 0;
  3428. GtkWidget *dialog = (GtkWidget *) 0;
  3429. char *file_chooser_filename = (char *)0;
  3430. char *file_chooser_dir = (char *)0;
  3431. GtkFileChooser *chooser = NULL;
  3432. char *inputfilename = (char *)0;
  3433. char *baseinputfilename = (char *)0;
  3434. char *baseinputfilename2 = (char *)0;
  3435. gzFile f = NULL;
  3436. char *bname = NULL;
  3437. int cnt = 0;
  3438. if (menuitem) {
  3439. }
  3440. if (user_data) {
  3441. }
  3442. #if (GTK_HAVE_API_VERSION_2 == 1)
  3443. /* see gimp source code howto */
  3444. dialog = gtk_file_chooser_dialog_new("Select BGV Graph File", 0, /* parent_window */
  3445. GTK_FILE_CHOOSER_ACTION_OPEN,
  3446. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
  3447. #endif
  3448. #if (GTK_HAVE_API_VERSION_3 == 1)
  3449. /* see gimp source code howto */
  3450. dialog = gtk_file_chooser_dialog_new("Select BGV Graph File", GTK_WINDOW(mainwindow1) /* parent_window */
  3451. ,
  3452. GTK_FILE_CHOOSER_ACTION_OPEN,
  3453. "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
  3454. #endif
  3455. chooser = GTK_FILE_CHOOSER(dialog);
  3456. /* use same dir if opened in earlier dir */
  3457. if (lastopendir) {
  3458. gtk_file_chooser_set_current_folder(chooser, lastopendir);
  3459. }
  3460. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  3461. /* run the window to select a input file */
  3462. if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
  3463. /* open button */
  3464. file_chooser_filename = (char *)gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
  3465. file_chooser_dir = (char *)gtk_file_chooser_get_current_folder(chooser);
  3466. } else {
  3467. /* cancel button */
  3468. (void)gtk_widget_destroy(dialog);
  3469. return;
  3470. }
  3471. /* */
  3472. (void)gtk_widget_destroy(dialog);
  3473. /* update last-used-dir */
  3474. if (file_chooser_dir) {
  3475. if (lastopendir) {
  3476. lastopendir = dp_free(lastopendir);
  3477. if (lastopendir) {
  3478. }
  3479. }
  3480. lastopendir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  3481. strcpy(lastopendir, file_chooser_dir);
  3482. /* not dp_free() because gtk allocated */
  3483. g_free(file_chooser_dir);
  3484. }
  3485. /* copy the input filename from gtk */
  3486. if (file_chooser_filename) {
  3487. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  3488. strcpy(inputfilename, file_chooser_filename);
  3489. /* not dp_free() because gtk allocated */
  3490. g_free(file_chooser_filename);
  3491. } else {
  3492. return;
  3493. }
  3494. /* set filename in window */
  3495. bname = g_path_get_basename(inputfilename);
  3496. baseinputfilename2 = dp_calloc(1, (strlen(bname) + 1));
  3497. strcpy(baseinputfilename2, bname);
  3498. /* not dp_free() because gtk allocated */
  3499. g_free(bname);
  3500. /* open file to parse */
  3501. errno = 0;
  3502. f = gzopen(inputfilename, "rb");
  3503. if (f == NULL) {
  3504. edialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  3505. GTK_DIALOG_DESTROY_WITH_PARENT,
  3506. GTK_MESSAGE_ERROR,
  3507. GTK_BUTTONS_CLOSE,
  3508. "Cannot open file %s for reading (%s)", inputfilename, g_strerror(errno));
  3509. gtk_dialog_run(GTK_DIALOG(edialog));
  3510. gtk_widget_destroy(edialog);
  3511. inputfilename = dp_free(inputfilename);
  3512. if (inputfilename) {
  3513. }
  3514. baseinputfilename2 = dp_free(baseinputfilename2);
  3515. if (baseinputfilename2) {
  3516. }
  3517. /* data is unchanged, so keep validdata status */
  3518. return;
  3519. }
  3520. /* type of graph data 0=gml 1=dot 2=vcg */
  3521. graphtype = 1;
  3522. do_clear_all(0);
  3523. /* background r/g/b of drawing */
  3524. bgcr = 0xff;
  3525. bgcg = 0xff;
  3526. bgcb = 0xff;
  3527. /* create root graph */
  3528. create_maingraph();
  3529. /* parse the bgv data */
  3530. if (bgvparse(maingraph, f, baseinputfilename2, argv0)) {
  3531. /* parse error */
  3532. if (strlen(parsermessage) == 0) {
  3533. strcpy(parsermessage, "no parser message");
  3534. }
  3535. pdialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  3536. GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", parsermessage);
  3537. gtk_dialog_run(GTK_DIALOG(pdialog));
  3538. gtk_widget_destroy(pdialog);
  3539. inputfilename = dp_free(inputfilename);
  3540. if (inputfilename) {
  3541. }
  3542. baseinputfilename2 = dp_free(baseinputfilename2);
  3543. if (baseinputfilename2) {
  3544. }
  3545. fflush(stdout);
  3546. gzclose(f);
  3547. /* data is invalid at this point */
  3548. validdata = 0;
  3549. do_clear_all(0);
  3550. /* use package string program name as set by configure in config.h */
  3551. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  3552. /* re draw screen */
  3553. gtk_widget_queue_draw(drawingarea1);
  3554. return;
  3555. }
  3556. gzclose(f);
  3557. bname = g_path_get_basename(inputfilename);
  3558. baseinputfilename = uniqstr(bname);
  3559. /* not dp_free() because gtk allocated */
  3560. g_free(bname);
  3561. gtk_window_set_title(GTK_WINDOW(mainwindow1), baseinputfilename);
  3562. /* check for empty graph here */
  3563. if (maingraph->rawnodelist) {
  3564. printf("%s(): calculating layout of file %s\n", __func__, baseinputfilename2);
  3565. fflush(stdout);
  3566. /* update status text */
  3567. update_status_text("Wait ... Calculating Layout");
  3568. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  3569. cnt = 1000;
  3570. while (gtk_events_pending()) {
  3571. cnt--;
  3572. if (cnt > 0) {
  3573. gtk_main_iteration();
  3574. /* this updates the status text */
  3575. }
  3576. }
  3577. #endif
  3578. do_layout_all(maingraph);
  3579. fflush(stdout);
  3580. /* update status text */
  3581. update_status_text(NULL);
  3582. cnt = 1000;
  3583. while (gtk_main_iteration()) {
  3584. cnt--;
  3585. if (cnt > 0) {
  3586. /* this should update the status text */ ;
  3587. }
  3588. }
  3589. /* set sliders to defaults */
  3590. zfactor = 1.0;
  3591. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale1), 50);
  3592. vxmin = 0;
  3593. vymin = 0;
  3594. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale2), 0);
  3595. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjhscale1), 0);
  3596. /* filename is not saved */
  3597. inputfilename = dp_free(inputfilename);
  3598. if (inputfilename) {
  3599. }
  3600. baseinputfilename2 = dp_free(baseinputfilename2);
  3601. if (baseinputfilename2) {
  3602. }
  3603. /* fit drawing in window */
  3604. dofit();
  3605. validdata = 1;
  3606. } else {
  3607. /* filename is not saved */
  3608. inputfilename = dp_free(inputfilename);
  3609. if (inputfilename) {
  3610. }
  3611. baseinputfilename2 = dp_free(baseinputfilename2);
  3612. if (baseinputfilename2) {
  3613. }
  3614. /* update status text */
  3615. update_status_text("Empty graph ... No Nodes");
  3616. validdata = 0;
  3617. }
  3618. /* re draw screen */
  3619. gtk_widget_queue_draw(drawingarea1);
  3620. return;
  3621. }
  3622. #endif
  3623. #if (GTK_HAVE_API_VERSION_4 == 1)
  3624. /* set directory for file chooser */
  3625. static void set_current_folder(GtkFileChooser * chooser, const char *name)
  3626. {
  3627. GtkWidget *dialog;
  3628. GFile *file = g_file_new_for_path(name);
  3629. if (file) {
  3630. if (gtk_file_chooser_set_current_folder(chooser, file, NULL) == FALSE) {
  3631. dialog = gtk_message_dialog_new(GTK_WINDOW(chooser),
  3632. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  3633. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Could not set the folder to %s", name);
  3634. gtk_widget_show(dialog);
  3635. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  3636. }
  3637. g_object_unref(file);
  3638. }
  3639. return;
  3640. }
  3641. /* parse the file */
  3642. static void open1_response_cb_fn(char *inputfilename, char *binputfilename)
  3643. {
  3644. gzFile f; /* the zipped file stream */
  3645. GtkWidget *dialog = NULL;
  3646. /* binputfilename is the short filename and should not be numm */
  3647. /* open file to parse */
  3648. errno = 0;
  3649. /* open zipped or unzipped file as file stream */
  3650. f = gzopen(inputfilename, "rb");
  3651. if (f == NULL || 0) {
  3652. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  3653. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  3654. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Cannot open file %s", inputfilename);
  3655. gtk_widget_show(dialog);
  3656. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  3657. /* data is unchanged, so keep validdata status */
  3658. return;
  3659. }
  3660. /* type of graph data 0=gml 1=dot 2=vcg */
  3661. graphtype = 1;
  3662. do_clear_all(0);
  3663. /* background r/g/b of drawing */
  3664. bgcr = 0xff;
  3665. bgcg = 0xff;
  3666. bgcb = 0xff;
  3667. /* create root graph */
  3668. create_maingraph();
  3669. /* parse the dot data */
  3670. if (dotparse(maingraph, f, inputfilename, argv0)) {
  3671. /* parse error */
  3672. if (strlen(parsermessage) == 0) {
  3673. strcpy(parsermessage, "no parser message");
  3674. }
  3675. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  3676. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  3677. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", parsermessage);
  3678. gtk_widget_show(dialog);
  3679. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  3680. fflush(stdout);
  3681. gzclose(f);
  3682. /* data is invalid at this point */
  3683. validdata = 0;
  3684. do_clear_all(0);
  3685. /* use package string program name as set by configure in config.h */
  3686. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  3687. /* re draw screen */
  3688. gtk_widget_queue_draw(drawingarea1);
  3689. return;
  3690. }
  3691. fflush(stdout);
  3692. gzclose(f);
  3693. /* set the basename of file as window title /tmp/foo.dot has window title foo.dot */
  3694. if (binputfilename) {
  3695. gtk_window_set_title(GTK_WINDOW(mainwindow1), binputfilename);
  3696. } else {
  3697. gtk_window_set_title(GTK_WINDOW(mainwindow1), inputfilename);
  3698. }
  3699. /* check for empty graph here */
  3700. if (maingraph->rawnodelist) {
  3701. printf("%s(): calculating layout of file %s\n", __func__, inputfilename);
  3702. fflush(stdout);
  3703. /* update status text */
  3704. update_status_text("Wait ... Calculating Layout");
  3705. do_layout_all(maingraph);
  3706. fflush(stdout);
  3707. /* update status text */
  3708. update_status_text(NULL);
  3709. /* set sliders to defaults */
  3710. /* fit drawing in window */
  3711. dofit();
  3712. validdata = 1;
  3713. } else {
  3714. /* update status text */
  3715. update_status_text("Empty graph ... No Nodes");
  3716. validdata = 0;
  3717. }
  3718. return;
  3719. }
  3720. /* run dialog and set bool done to TRUE if ready */
  3721. static void open1_response_cb(GtkDialog * dialog, int response_id, gpointer data)
  3722. {
  3723. gboolean *done = data; /* bool to set is passed on at call */
  3724. GListModel *files = NULL;
  3725. guint i = 0;
  3726. guint n = 0;
  3727. GFile *file = NULL;
  3728. GFile *folder = NULL;
  3729. char *uri = NULL;
  3730. char *file_chooser_dir = NULL;
  3731. char *inputfilename = NULL;
  3732. char *file_chooser_filename = NULL;
  3733. char *bname = NULL;
  3734. if (response_id == GTK_RESPONSE_OK) {
  3735. /* scan the list with selected files */
  3736. files = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog));
  3737. n = g_list_model_get_n_items(files);
  3738. if (yydebug || 0) {
  3739. g_print("%s(): selected %d files\n", __func__, n);
  3740. }
  3741. for (i = 0; i < n; i++) {
  3742. file = g_list_model_get_item(files, i);
  3743. uri = g_file_get_uri(file);
  3744. /* option here
  3745. * the uri is like file:///bin/true
  3746. * this allows for network uri
  3747. * as https://graphviewer.nl/data/example.dot
  3748. */
  3749. if (uri == NULL) {
  3750. g_print("%s(): file %d has nil name\n", __func__, i);
  3751. } else {
  3752. if (strlen(uri) == 0) {
  3753. g_print("%s(): file %d has empty name \"\"\n", __func__, i);
  3754. } else {
  3755. if (i != 0) {
  3756. g_print("%s(): skipped file %d with name %s\n", __func__, i, uri);
  3757. } else {
  3758. /* this is the first file to read
  3759. * uri is file:///bin/foo
  3760. * g_file_get_parse_name(file) is /bin/foo
  3761. * g_file_get_basename(file) is foo
  3762. * g_file_get_path(file) is /bin/foo
  3763. */
  3764. /* update directory of chosen file */
  3765. folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
  3766. if (folder) {
  3767. file_chooser_dir = g_file_get_parse_name(folder);
  3768. if (file_chooser_dir) {
  3769. if (lastopendir) {
  3770. lastopendir = dp_free(lastopendir);
  3771. if (lastopendir) {
  3772. }
  3773. }
  3774. lastopendir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  3775. strcpy(lastopendir, file_chooser_dir);
  3776. g_free(file_chooser_dir);
  3777. file_chooser_dir = NULL;
  3778. }
  3779. g_object_unref(folder);
  3780. }
  3781. /* copy filename */
  3782. file_chooser_filename = g_file_get_parse_name(file);
  3783. if (file_chooser_filename) {
  3784. if (strlen(file_chooser_filename)) {
  3785. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  3786. strcpy(inputfilename, file_chooser_filename);
  3787. } else {
  3788. g_print("%s(): empty filename\n", __func__);
  3789. }
  3790. bname = g_file_get_basename(file);
  3791. /* read and parse the file */
  3792. open1_response_cb_fn(file_chooser_filename, bname);
  3793. if (bname) {
  3794. g_free(bname);
  3795. bname = NULL;
  3796. };
  3797. /* there could have been a parse error */
  3798. g_free(file_chooser_filename);
  3799. file_chooser_filename = NULL;
  3800. }
  3801. /* print the derived filenames */
  3802. if (yydebug || 0) {
  3803. g_print("%s(): %s %s %s %s %s\n", __func__, g_file_get_parse_name(file),
  3804. g_file_get_basename(file), uri, g_file_get_path(file), g_file_get_parse_name(folder));
  3805. }
  3806. }
  3807. }
  3808. g_free(uri);
  3809. uri = NULL;
  3810. }
  3811. g_object_unref(file);
  3812. }
  3813. g_object_unref(files);
  3814. } else {
  3815. /* no file selected */
  3816. if (yydebug || 0) {
  3817. g_print("%s(): open dialog was closed\n", __func__);
  3818. }
  3819. }
  3820. /* inicate this dialog is finished in passed on var */
  3821. *done = TRUE;
  3822. g_main_context_wakeup(NULL);
  3823. return;
  3824. }
  3825. /* open dot file */
  3826. static void open1_activated(GSimpleAction * action, GVariant * parameter, gpointer user_data)
  3827. {
  3828. gboolean multiple = FALSE; /* if TRUE multiple files can be selected as extended feature */
  3829. GtkWidget *dialog = NULL;
  3830. GtkFileFilter *filter = NULL;
  3831. gboolean done = FALSE; /* indicator dialog is finished */
  3832. if (action) {
  3833. }
  3834. if (parameter) {
  3835. }
  3836. if (user_data) {
  3837. }
  3838. /* see the testcase in gtk-4 testfilechooser.c */
  3839. dialog = g_object_new(GTK_TYPE_FILE_CHOOSER_DIALOG, "action", GTK_FILE_CHOOSER_ACTION_OPEN, "select-multiple", multiple, NULL);
  3840. gtk_window_set_title(GTK_WINDOW(dialog), "Open dot graph file");
  3841. gtk_dialog_add_buttons(GTK_DIALOG(dialog), ("_Cancel"), GTK_RESPONSE_CANCEL, ("_Open"), GTK_RESPONSE_OK, NULL);
  3842. gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
  3843. /* the callback will set bool done to TRUE if ready */
  3844. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(open1_response_cb), (gpointer) & done);
  3845. /* Filters */
  3846. filter = gtk_file_filter_new();
  3847. gtk_file_filter_set_name(filter, "All Files");
  3848. gtk_file_filter_add_pattern(filter, "*");
  3849. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  3850. filter = gtk_file_filter_new();
  3851. gtk_file_filter_set_name(filter, "dot");
  3852. gtk_file_filter_add_pattern(filter, "*.dot");
  3853. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  3854. filter = gtk_file_filter_new();
  3855. gtk_file_filter_set_name(filter, "gv");
  3856. gtk_file_filter_add_pattern(filter, "*.gv");
  3857. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  3858. /* this are the gzipped graph files */
  3859. filter = gtk_file_filter_new();
  3860. gtk_file_filter_set_name(filter, "dot.gz");
  3861. gtk_file_filter_add_pattern(filter, "*.dot.gz");
  3862. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  3863. filter = gtk_file_filter_new();
  3864. gtk_file_filter_set_name(filter, "gv.gz");
  3865. gtk_file_filter_add_pattern(filter, "*.gv.gz");
  3866. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  3867. if (lastopendir) {
  3868. set_current_folder(GTK_FILE_CHOOSER(dialog), lastopendir);
  3869. }
  3870. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  3871. gtk_widget_show(dialog);
  3872. /* run dialog and wait until it is ready */
  3873. while (done == FALSE) {
  3874. g_main_context_iteration(NULL, TRUE);
  3875. }
  3876. gtk_window_destroy(GTK_WINDOW(dialog));
  3877. return;
  3878. }
  3879. #endif
  3880. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  3881. /* 'open' in 'file' menu activated - sub menu in menu items in menu bar in vbox1 */
  3882. static void on_top_level_window_open2_activate(GtkMenuItem * menuitem, gpointer user_data)
  3883. {
  3884. GtkWidget *edialog = (GtkWidget *) 0;
  3885. GtkWidget *pdialog = (GtkWidget *) 0;
  3886. GtkWidget *dialog = (GtkWidget *) 0;
  3887. char *file_chooser_filename = (char *)0;
  3888. char *file_chooser_dir = (char *)0;
  3889. GtkFileChooser *chooser = NULL;
  3890. char *inputfilename = (char *)0;
  3891. char *baseinputfilename = (char *)0;
  3892. char *baseinputfilename2 = (char *)0;
  3893. gzFile f = NULL;
  3894. char *bname = NULL;
  3895. int cnt = 0;
  3896. if (menuitem) {
  3897. }
  3898. if (user_data) {
  3899. }
  3900. #if (GTK_HAVE_API_VERSION_2 == 1)
  3901. /* see gimp source code howto */
  3902. dialog = gtk_file_chooser_dialog_new("Select DOT Graph File", 0, /* parent_window */
  3903. GTK_FILE_CHOOSER_ACTION_OPEN,
  3904. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
  3905. #endif
  3906. #if (GTK_HAVE_API_VERSION_3 == 1)
  3907. /* see gimp source code howto */
  3908. dialog = gtk_file_chooser_dialog_new("Select DOT Graph File", GTK_WINDOW(mainwindow1) /* parent_window */
  3909. ,
  3910. GTK_FILE_CHOOSER_ACTION_OPEN,
  3911. "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
  3912. #endif
  3913. chooser = GTK_FILE_CHOOSER(dialog);
  3914. /* use same dir if opened in earlier dir */
  3915. if (lastopendir) {
  3916. gtk_file_chooser_set_current_folder(chooser, lastopendir);
  3917. }
  3918. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  3919. /* run the window to select a input file */
  3920. if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
  3921. /* open button */
  3922. file_chooser_filename = (char *)gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
  3923. file_chooser_dir = (char *)gtk_file_chooser_get_current_folder(chooser);
  3924. } else {
  3925. /* cancel button */
  3926. (void)gtk_widget_destroy(dialog);
  3927. return;
  3928. }
  3929. /* */
  3930. (void)gtk_widget_destroy(dialog);
  3931. /* update last-used-dir */
  3932. if (file_chooser_dir) {
  3933. if (lastopendir) {
  3934. lastopendir = dp_free(lastopendir);
  3935. if (lastopendir) {
  3936. }
  3937. }
  3938. lastopendir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  3939. strcpy(lastopendir, file_chooser_dir);
  3940. /* not dp_free() because gtk allocated */
  3941. g_free(file_chooser_dir);
  3942. }
  3943. /* copy the input filename from gtk */
  3944. if (file_chooser_filename) {
  3945. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  3946. strcpy(inputfilename, file_chooser_filename);
  3947. /* not dp_free() because gtk allocated */
  3948. g_free(file_chooser_filename);
  3949. } else {
  3950. return;
  3951. }
  3952. /* set filename in window */
  3953. bname = g_path_get_basename(inputfilename);
  3954. baseinputfilename2 = dp_calloc(1, (strlen(bname) + 1));
  3955. strcpy(baseinputfilename2, bname);
  3956. /* not dp_free() because gtk allocated */
  3957. g_free(bname);
  3958. /* open file to parse */
  3959. errno = 0;
  3960. f = gzopen(inputfilename, "rb");
  3961. if (f == NULL) {
  3962. edialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  3963. GTK_DIALOG_DESTROY_WITH_PARENT,
  3964. GTK_MESSAGE_ERROR,
  3965. GTK_BUTTONS_CLOSE,
  3966. "Cannot open file %s for reading (%s)", inputfilename, g_strerror(errno));
  3967. gtk_dialog_run(GTK_DIALOG(edialog));
  3968. gtk_widget_destroy(edialog);
  3969. inputfilename = dp_free(inputfilename);
  3970. if (inputfilename) {
  3971. }
  3972. baseinputfilename2 = dp_free(baseinputfilename2);
  3973. if (baseinputfilename2) {
  3974. }
  3975. /* data is unchanged, so keep validdata status */
  3976. return;
  3977. }
  3978. /* type of graph data 0=gml 1=dot 2=vcg */
  3979. graphtype = 1;
  3980. do_clear_all(0);
  3981. /* background r/g/b of drawing */
  3982. bgcr = 0xff;
  3983. bgcg = 0xff;
  3984. bgcb = 0xff;
  3985. /* create root graph */
  3986. create_maingraph();
  3987. /* parse the dot data */
  3988. if (dotparse(maingraph, f, baseinputfilename2, argv0)) {
  3989. /* parse error */
  3990. if (strlen(parsermessage) == 0) {
  3991. strcpy(parsermessage, "no parser message");
  3992. }
  3993. pdialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  3994. GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", parsermessage);
  3995. gtk_dialog_run(GTK_DIALOG(pdialog));
  3996. gtk_widget_destroy(pdialog);
  3997. inputfilename = dp_free(inputfilename);
  3998. if (inputfilename) {
  3999. }
  4000. baseinputfilename2 = dp_free(baseinputfilename2);
  4001. if (baseinputfilename2) {
  4002. }
  4003. fflush(stdout);
  4004. gzclose(f);
  4005. /* data is invalid at this point */
  4006. validdata = 0;
  4007. do_clear_all(0);
  4008. /* use package string program name as set by configure in config.h */
  4009. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  4010. /* re draw screen */
  4011. gtk_widget_queue_draw(drawingarea1);
  4012. return;
  4013. }
  4014. gzclose(f);
  4015. bname = g_path_get_basename(inputfilename);
  4016. baseinputfilename = uniqstr(bname);
  4017. /* not dp_free() because gtk allocated */
  4018. g_free(bname);
  4019. gtk_window_set_title(GTK_WINDOW(mainwindow1), baseinputfilename);
  4020. /* check for empty graph here */
  4021. if (maingraph->rawnodelist) {
  4022. printf("%s(): calculating layout of file %s\n", __func__, baseinputfilename2);
  4023. fflush(stdout);
  4024. /* update status text */
  4025. update_status_text("Wait ... Calculating Layout");
  4026. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  4027. cnt = 1000;
  4028. while (gtk_events_pending()) {
  4029. cnt--;
  4030. if (cnt > 0) {
  4031. gtk_main_iteration();
  4032. /* this updates the status text */
  4033. }
  4034. }
  4035. #endif
  4036. do_layout_all(maingraph);
  4037. fflush(stdout);
  4038. /* update status text */
  4039. update_status_text(NULL);
  4040. cnt = 1000;
  4041. while (gtk_main_iteration()) {
  4042. cnt--;
  4043. if (cnt > 0) {
  4044. /* this should update the status text */ ;
  4045. }
  4046. }
  4047. /* set sliders to defaults */
  4048. zfactor = 1.0;
  4049. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale1), 50);
  4050. vxmin = 0;
  4051. vymin = 0;
  4052. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale2), 0);
  4053. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjhscale1), 0);
  4054. /* filename is not saved */
  4055. inputfilename = dp_free(inputfilename);
  4056. if (inputfilename) {
  4057. }
  4058. baseinputfilename2 = dp_free(baseinputfilename2);
  4059. if (baseinputfilename2) {
  4060. }
  4061. /* fit drawing in window */
  4062. dofit();
  4063. validdata = 1;
  4064. } else {
  4065. /* filename is not saved */
  4066. inputfilename = dp_free(inputfilename);
  4067. if (inputfilename) {
  4068. }
  4069. baseinputfilename2 = dp_free(baseinputfilename2);
  4070. if (baseinputfilename2) {
  4071. }
  4072. /* update status text */
  4073. update_status_text("Empty graph ... No Nodes");
  4074. validdata = 0;
  4075. }
  4076. /* re draw screen */
  4077. gtk_widget_queue_draw(drawingarea1);
  4078. return;
  4079. }
  4080. #endif
  4081. #if (GTK_HAVE_API_VERSION_4 == 1)
  4082. /* parse the file */
  4083. static void open3_response_cb_fn(char *inputfilename, char *binputfilename)
  4084. {
  4085. gzFile f; /* the zipped file stream */
  4086. GtkWidget *dialog = NULL;
  4087. /* binputfilename is the short filename and should not be numm */
  4088. /* open file to parse */
  4089. errno = 0;
  4090. /* open zipped or unzipped file as file stream */
  4091. f = gzopen(inputfilename, "rb");
  4092. if (f == NULL || 0) {
  4093. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  4094. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  4095. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Cannot open file %s", inputfilename);
  4096. gtk_widget_show(dialog);
  4097. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  4098. /* data is unchanged, so keep validdata status */
  4099. return;
  4100. }
  4101. /* type of graph data 0=gml 1=dot 2=vcg */
  4102. graphtype = 1;
  4103. do_clear_all(0);
  4104. /* background r/g/b of drawing */
  4105. bgcr = 0xff;
  4106. bgcg = 0xff;
  4107. bgcb = 0xff;
  4108. /* create root graph */
  4109. create_maingraph();
  4110. /* parse the dot data */
  4111. if (vcgparse(maingraph, f, inputfilename, argv0)) {
  4112. /* parse error */
  4113. if (strlen(parsermessage) == 0) {
  4114. strcpy(parsermessage, "no parser message");
  4115. }
  4116. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  4117. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  4118. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", parsermessage);
  4119. gtk_widget_show(dialog);
  4120. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  4121. fflush(stdout);
  4122. gzclose(f);
  4123. /* data is invalid at this point */
  4124. validdata = 0;
  4125. do_clear_all(0);
  4126. /* use package string program name as set by configure in config.h */
  4127. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  4128. /* re draw screen */
  4129. gtk_widget_queue_draw(drawingarea1);
  4130. return;
  4131. }
  4132. fflush(stdout);
  4133. gzclose(f);
  4134. /* set the basename of file as window title /tmp/foo.dot has window title foo.dot */
  4135. if (binputfilename) {
  4136. gtk_window_set_title(GTK_WINDOW(mainwindow1), binputfilename);
  4137. } else {
  4138. gtk_window_set_title(GTK_WINDOW(mainwindow1), inputfilename);
  4139. }
  4140. /* check for empty graph here */
  4141. if (maingraph->rawnodelist) {
  4142. printf("%s(): calculating layout of file %s\n", __func__, inputfilename);
  4143. fflush(stdout);
  4144. /* update status text */
  4145. update_status_text("Wait ... Calculating Layout");
  4146. do_layout_all(maingraph);
  4147. fflush(stdout);
  4148. /* update status text */
  4149. update_status_text(NULL);
  4150. /* set sliders to defaults */
  4151. /* fit drawing in window */
  4152. dofit();
  4153. validdata = 1;
  4154. } else {
  4155. /* update status text */
  4156. update_status_text("Empty graph ... No Nodes");
  4157. validdata = 0;
  4158. }
  4159. return;
  4160. }
  4161. /* run dialog and set bool done to TRUE if ready */
  4162. static void open3_response_cb(GtkDialog * dialog, int response_id, gpointer data)
  4163. {
  4164. gboolean *done = data; /* bool to set is passed on at call */
  4165. GListModel *files = NULL;
  4166. guint i = 0;
  4167. guint n = 0;
  4168. GFile *file = NULL;
  4169. GFile *folder = NULL;
  4170. char *uri = NULL;
  4171. char *file_chooser_dir = NULL;
  4172. char *inputfilename = NULL;
  4173. char *file_chooser_filename = NULL;
  4174. char *bname = NULL;
  4175. if (response_id == GTK_RESPONSE_OK) {
  4176. /* scan the list with selected files */
  4177. files = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog));
  4178. n = g_list_model_get_n_items(files);
  4179. if (yydebug || 0) {
  4180. g_print("%s(): selected %d files\n", __func__, n);
  4181. }
  4182. for (i = 0; i < n; i++) {
  4183. file = g_list_model_get_item(files, i);
  4184. uri = g_file_get_uri(file);
  4185. /* option here
  4186. * the uri is like file:///bin/true
  4187. * this allows for network uri
  4188. * as https://graphviewer.nl/data/example.dot
  4189. */
  4190. if (uri == NULL) {
  4191. g_print("%s(): file %d has nil name\n", __func__, i);
  4192. } else {
  4193. if (strlen(uri) == 0) {
  4194. g_print("%s(): file %d has empty name \"\"\n", __func__, i);
  4195. } else {
  4196. if (i != 0) {
  4197. g_print("%s(): skipped file %d with name %s\n", __func__, i, uri);
  4198. } else {
  4199. /* this is the first file to read
  4200. * uri is file:///bin/foo
  4201. * g_file_get_parse_name(file) is /bin/foo
  4202. * g_file_get_basename(file) is foo
  4203. * g_file_get_path(file) is /bin/foo
  4204. */
  4205. /* update directory of chosen file */
  4206. folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
  4207. if (folder) {
  4208. file_chooser_dir = g_file_get_parse_name(folder);
  4209. if (file_chooser_dir) {
  4210. if (lastopendir) {
  4211. lastopendir = dp_free(lastopendir);
  4212. if (lastopendir) {
  4213. }
  4214. }
  4215. lastopendir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  4216. strcpy(lastopendir, file_chooser_dir);
  4217. g_free(file_chooser_dir);
  4218. file_chooser_dir = NULL;
  4219. }
  4220. g_object_unref(folder);
  4221. }
  4222. /* copy filename */
  4223. file_chooser_filename = g_file_get_parse_name(file);
  4224. if (file_chooser_filename) {
  4225. if (strlen(file_chooser_filename)) {
  4226. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  4227. strcpy(inputfilename, file_chooser_filename);
  4228. } else {
  4229. g_print("%s(): empty filename\n", __func__);
  4230. }
  4231. bname = g_file_get_basename(file);
  4232. /* read and parse the file */
  4233. open3_response_cb_fn(file_chooser_filename, bname);
  4234. if (bname) {
  4235. g_free(bname);
  4236. bname = NULL;
  4237. };
  4238. /* there could have been a parse error */
  4239. g_free(file_chooser_filename);
  4240. file_chooser_filename = NULL;
  4241. }
  4242. /* print the derived filenames */
  4243. if (yydebug || 0) {
  4244. g_print("%s(): %s %s %s %s %s\n", __func__, g_file_get_parse_name(file),
  4245. g_file_get_basename(file), uri, g_file_get_path(file), g_file_get_parse_name(folder));
  4246. }
  4247. }
  4248. }
  4249. g_free(uri);
  4250. uri = NULL;
  4251. }
  4252. g_object_unref(file);
  4253. }
  4254. g_object_unref(files);
  4255. } else {
  4256. /* no file selected */
  4257. if (yydebug || 0) {
  4258. g_print("%s(): open dialog was closed\n", __func__);
  4259. }
  4260. }
  4261. /* inicate this dialog is finished in passed on var */
  4262. *done = TRUE;
  4263. g_main_context_wakeup(NULL);
  4264. return;
  4265. }
  4266. /* open vcg file */
  4267. static void open3_activated(GSimpleAction * action, GVariant * parameter, gpointer user_data)
  4268. {
  4269. gboolean multiple = FALSE; /* if TRUE multiple files can be selected as extended feature */
  4270. GtkWidget *dialog = NULL;
  4271. GtkFileFilter *filter = NULL;
  4272. gboolean done = FALSE; /* indicator dialog is finished */
  4273. if (action) {
  4274. }
  4275. if (parameter) {
  4276. }
  4277. if (user_data) {
  4278. }
  4279. /* see the testcase in gtk-4 testfilechooser.c */
  4280. dialog = g_object_new(GTK_TYPE_FILE_CHOOSER_DIALOG, "action", GTK_FILE_CHOOSER_ACTION_OPEN, "select-multiple", multiple, NULL);
  4281. gtk_window_set_title(GTK_WINDOW(dialog), "Open ci graph file");
  4282. gtk_dialog_add_buttons(GTK_DIALOG(dialog), ("_Cancel"), GTK_RESPONSE_CANCEL, ("_Open"), GTK_RESPONSE_OK, NULL);
  4283. gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
  4284. /* the callback will set bool done to TRUE if ready */
  4285. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(open3_response_cb), (gpointer) & done);
  4286. /* Filters */
  4287. filter = gtk_file_filter_new();
  4288. gtk_file_filter_set_name(filter, "All Files");
  4289. gtk_file_filter_add_pattern(filter, "*");
  4290. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  4291. filter = gtk_file_filter_new();
  4292. gtk_file_filter_set_name(filter, "vcg");
  4293. gtk_file_filter_add_pattern(filter, "*.vcg");
  4294. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  4295. filter = gtk_file_filter_new();
  4296. gtk_file_filter_set_name(filter, "ci");
  4297. gtk_file_filter_add_pattern(filter, "*.ci");
  4298. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  4299. /* this are the gzipped graph files */
  4300. filter = gtk_file_filter_new();
  4301. gtk_file_filter_set_name(filter, "vcg.gz");
  4302. gtk_file_filter_add_pattern(filter, "*.vcg.gz");
  4303. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  4304. if (lastopendir) {
  4305. set_current_folder(GTK_FILE_CHOOSER(dialog), lastopendir);
  4306. }
  4307. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  4308. gtk_widget_show(dialog);
  4309. /* run dialog and wait until it is ready */
  4310. while (done == FALSE) {
  4311. g_main_context_iteration(NULL, TRUE);
  4312. }
  4313. gtk_window_destroy(GTK_WINDOW(dialog));
  4314. return;
  4315. }
  4316. #endif
  4317. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  4318. /* 'open' in 'file' menu activated - sub menu in menu items in menu bar in vbox1 */
  4319. static void on_top_level_window_open3_activate(GtkMenuItem * menuitem, gpointer user_data)
  4320. {
  4321. GtkWidget *edialog = (GtkWidget *) 0;
  4322. GtkWidget *pdialog = (GtkWidget *) 0;
  4323. GtkWidget *dialog = (GtkWidget *) 0;
  4324. char *file_chooser_filename = (char *)0;
  4325. char *file_chooser_dir = (char *)0;
  4326. GtkFileChooser *chooser = NULL;
  4327. char *inputfilename = (char *)0;
  4328. char *baseinputfilename = (char *)0;
  4329. char *baseinputfilename2 = (char *)0;
  4330. gzFile fvcg = (gzFile) 0;
  4331. char *bname = NULL;
  4332. if (menuitem) {
  4333. }
  4334. if (user_data) {
  4335. }
  4336. #if (GTK_HAVE_API_VERSION_2 == 1)
  4337. /* see gimp source code howto */
  4338. dialog = gtk_file_chooser_dialog_new("Select CI Graph File", 0, /* parent_window */
  4339. GTK_FILE_CHOOSER_ACTION_OPEN,
  4340. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
  4341. #endif
  4342. #if (GTK_HAVE_API_VERSION_3 == 1)
  4343. /* see gimp source code howto */
  4344. dialog = gtk_file_chooser_dialog_new("Select CI Graph File", GTK_WINDOW(mainwindow1) /* parent_window */
  4345. ,
  4346. GTK_FILE_CHOOSER_ACTION_OPEN,
  4347. "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
  4348. #endif
  4349. chooser = GTK_FILE_CHOOSER(dialog);
  4350. /* use same dir if opened in earlier dir */
  4351. if (lastopendir) {
  4352. gtk_file_chooser_set_current_folder(chooser, lastopendir);
  4353. }
  4354. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  4355. /* run the window to select a input file */
  4356. if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
  4357. /* open button */
  4358. file_chooser_filename = (char *)gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
  4359. file_chooser_dir = (char *)gtk_file_chooser_get_current_folder(chooser);
  4360. } else {
  4361. /* cancel button */
  4362. (void)gtk_widget_destroy(dialog);
  4363. return;
  4364. }
  4365. /* */
  4366. (void)gtk_widget_destroy(dialog);
  4367. /* update last-used-dir */
  4368. if (file_chooser_dir) {
  4369. if (lastopendir) {
  4370. lastopendir = dp_free(lastopendir);
  4371. if (lastopendir) {
  4372. }
  4373. }
  4374. lastopendir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  4375. strcpy(lastopendir, file_chooser_dir);
  4376. /* not dp_free() because gtk allocated */
  4377. g_free(file_chooser_dir);
  4378. }
  4379. /* copy the input filename from gtk */
  4380. if (file_chooser_filename) {
  4381. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  4382. strcpy(inputfilename, file_chooser_filename);
  4383. /* not dp_free() because gtk allocated */
  4384. g_free(file_chooser_filename);
  4385. } else {
  4386. return;
  4387. }
  4388. /* set filename in window */
  4389. bname = g_path_get_basename(inputfilename);
  4390. baseinputfilename2 = dp_calloc(1, (strlen(bname) + 1));
  4391. strcpy(baseinputfilename2, bname);
  4392. /* not dp_free() because gtk allocated */
  4393. g_free(bname);
  4394. /* open file to parse */
  4395. errno = 0;
  4396. fvcg = gzopen(inputfilename, "r");
  4397. if (fvcg == (gzFile) 0) {
  4398. edialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  4399. GTK_DIALOG_DESTROY_WITH_PARENT,
  4400. GTK_MESSAGE_ERROR,
  4401. GTK_BUTTONS_CLOSE,
  4402. "Cannot open file %s for reading (%s)", inputfilename, g_strerror(errno));
  4403. gtk_dialog_run(GTK_DIALOG(edialog));
  4404. gtk_widget_destroy(edialog);
  4405. baseinputfilename2 = dp_free(baseinputfilename2);
  4406. if (baseinputfilename2) {
  4407. }
  4408. inputfilename = dp_free(inputfilename);
  4409. if (inputfilename) {
  4410. }
  4411. /* data is unchanged, so keep validdata status */
  4412. return;
  4413. }
  4414. /* type of graph data 0=gml 1=dot 2=vcg */
  4415. graphtype = 2;
  4416. do_clear_all(0);
  4417. /* background r/g/b of drawing */
  4418. bgcr = 0xff;
  4419. bgcg = 0xff;
  4420. bgcb = 0xff;
  4421. /* create root graph */
  4422. create_maingraph();
  4423. /* parse the vcg data */
  4424. if (vcgparse(maingraph, fvcg, baseinputfilename2, argv0)) {
  4425. /* parse error */
  4426. if (strlen(parsermessage) == 0) {
  4427. strcpy(parsermessage, "no parser message");
  4428. }
  4429. pdialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  4430. GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", parsermessage);
  4431. gtk_dialog_run(GTK_DIALOG(pdialog));
  4432. gtk_widget_destroy(pdialog);
  4433. inputfilename = dp_free(inputfilename);
  4434. if (inputfilename) {
  4435. }
  4436. baseinputfilename2 = dp_free(baseinputfilename2);
  4437. if (baseinputfilename2) {
  4438. }
  4439. fflush(stdout);
  4440. gzclose(fvcg);
  4441. /* data is invalid at this point */
  4442. validdata = 0;
  4443. do_clear_all(0);
  4444. /* use package string program name as set by configure in config.h */
  4445. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  4446. /* re draw screen */
  4447. gtk_widget_queue_draw(drawingarea1);
  4448. return;
  4449. }
  4450. gzclose(fvcg);
  4451. bname = g_path_get_basename(inputfilename);
  4452. baseinputfilename = uniqstr(bname);
  4453. /* not dp_free because gtk allocated */
  4454. g_free(bname);
  4455. gtk_window_set_title(GTK_WINDOW(mainwindow1), baseinputfilename);
  4456. /* check for empty graph here */
  4457. if (maingraph->rawnodelist) {
  4458. printf("%s(): calculating layout of file %s\n", __func__, baseinputfilename2);
  4459. fflush(stdout);
  4460. /* update status text */
  4461. update_status_text("Wait ... Calculating Layout");
  4462. while (gtk_events_pending()) {
  4463. gtk_main_iteration();
  4464. /* this updates the status text */
  4465. }
  4466. do_layout_all(maingraph);
  4467. fflush(stdout);
  4468. /* update status text */
  4469. update_status_text(NULL);
  4470. while (gtk_main_iteration()) {
  4471. /* this should update the status text */ ;
  4472. }
  4473. /* set sliders to defaults */
  4474. zfactor = 1.0;
  4475. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale1), 50);
  4476. vxmin = 0;
  4477. vymin = 0;
  4478. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale2), 0);
  4479. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjhscale1), 0);
  4480. /* filename is not saved */
  4481. inputfilename = dp_free(inputfilename);
  4482. if (inputfilename) {
  4483. }
  4484. baseinputfilename2 = dp_free(baseinputfilename2);
  4485. if (baseinputfilename2) {
  4486. }
  4487. /* fit drawing in window */
  4488. dofit();
  4489. validdata = 1;
  4490. } else {
  4491. /* filename is not saved */
  4492. inputfilename = dp_free(inputfilename);
  4493. if (inputfilename) {
  4494. }
  4495. baseinputfilename2 = dp_free(baseinputfilename2);
  4496. if (baseinputfilename2) {
  4497. }
  4498. /* update status text */
  4499. update_status_text("Empty graph ... No Nodes");
  4500. validdata = 0;
  4501. }
  4502. /* re draw screen */
  4503. gtk_widget_queue_draw(drawingarea1);
  4504. return;
  4505. }
  4506. #endif
  4507. #if (GTK_HAVE_API_VERSION_4 == 1)
  4508. /* parse the file */
  4509. static void open4_response_cb_fn(char *inputfilename, char *binputfilename)
  4510. {
  4511. gzFile f; /* the zipped file stream */
  4512. GtkWidget *dialog = NULL;
  4513. /* binputfilename is the short filename and should not be numm */
  4514. /* open file to parse */
  4515. errno = 0;
  4516. /* open zipped or unzipped file as file stream */
  4517. f = gzopen(inputfilename, "rb");
  4518. if (f == NULL || 0) {
  4519. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  4520. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  4521. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Cannot open file %s", inputfilename);
  4522. gtk_widget_show(dialog);
  4523. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  4524. /* data is unchanged, so keep validdata status */
  4525. return;
  4526. }
  4527. /* type of graph data 0=gml 1=dot 2=vcg */
  4528. graphtype = 1;
  4529. do_clear_all(0);
  4530. /* background r/g/b of drawing */
  4531. bgcr = 0xff;
  4532. bgcg = 0xff;
  4533. bgcb = 0xff;
  4534. /* create root graph */
  4535. create_maingraph();
  4536. /* parse the jgf data */
  4537. if (jgfparse(maingraph, f, inputfilename, argv0)) {
  4538. /* parse error */
  4539. if (strlen(parsermessage) == 0) {
  4540. strcpy(parsermessage, "no parser message");
  4541. }
  4542. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  4543. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  4544. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", parsermessage);
  4545. gtk_widget_show(dialog);
  4546. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  4547. fflush(stdout);
  4548. gzclose(f);
  4549. /* data is invalid at this point */
  4550. validdata = 0;
  4551. do_clear_all(0);
  4552. /* use package string program name as set by configure in config.h */
  4553. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  4554. /* re draw screen */
  4555. gtk_widget_queue_draw(drawingarea1);
  4556. return;
  4557. }
  4558. fflush(stdout);
  4559. gzclose(f);
  4560. /* set the basename of file as window title /tmp/foo.dot has window title foo.dot */
  4561. if (binputfilename) {
  4562. gtk_window_set_title(GTK_WINDOW(mainwindow1), binputfilename);
  4563. } else {
  4564. gtk_window_set_title(GTK_WINDOW(mainwindow1), inputfilename);
  4565. }
  4566. /* check for empty graph here */
  4567. if (maingraph->rawnodelist) {
  4568. printf("%s(): calculating layout of file %s\n", __func__, inputfilename);
  4569. fflush(stdout);
  4570. /* update status text */
  4571. update_status_text("Wait ... Calculating Layout");
  4572. do_layout_all(maingraph);
  4573. fflush(stdout);
  4574. /* update status text */
  4575. update_status_text(NULL);
  4576. /* set sliders to defaults */
  4577. /* fit drawing in window */
  4578. dofit();
  4579. validdata = 1;
  4580. } else {
  4581. /* update status text */
  4582. update_status_text("Empty graph ... No Nodes");
  4583. validdata = 0;
  4584. }
  4585. return;
  4586. }
  4587. /* run dialog and set bool done to TRUE if ready */
  4588. static void open4_response_cb(GtkDialog * dialog, int response_id, gpointer data)
  4589. {
  4590. gboolean *done = data; /* bool to set is passed on at call */
  4591. GListModel *files = NULL;
  4592. guint i = 0;
  4593. guint n = 0;
  4594. GFile *file = NULL;
  4595. GFile *folder = NULL;
  4596. char *uri = NULL;
  4597. char *file_chooser_dir = NULL;
  4598. char *inputfilename = NULL;
  4599. char *file_chooser_filename = NULL;
  4600. char *bname = NULL;
  4601. if (response_id == GTK_RESPONSE_OK) {
  4602. /* scan the list with selected files */
  4603. files = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog));
  4604. n = g_list_model_get_n_items(files);
  4605. if (yydebug || 0) {
  4606. g_print("%s(): selected %d files\n", __func__, n);
  4607. }
  4608. for (i = 0; i < n; i++) {
  4609. file = g_list_model_get_item(files, i);
  4610. uri = g_file_get_uri(file);
  4611. /* option here
  4612. * the uri is like file:///bin/true
  4613. * this allows for network uri
  4614. * as https://graphviewer.nl/data/example.dot
  4615. */
  4616. if (uri == NULL) {
  4617. g_print("%s(): file %d has nil name\n", __func__, i);
  4618. } else {
  4619. if (strlen(uri) == 0) {
  4620. g_print("%s(): file %d has empty name \"\"\n", __func__, i);
  4621. } else {
  4622. if (i != 0) {
  4623. g_print("%s(): skipped file %d with name %s\n", __func__, i, uri);
  4624. } else {
  4625. /* this is the first file to read
  4626. * uri is file:///bin/foo
  4627. * g_file_get_parse_name(file) is /bin/foo
  4628. * g_file_get_basename(file) is foo
  4629. * g_file_get_path(file) is /bin/foo
  4630. */
  4631. /* update directory of chosen file */
  4632. folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
  4633. if (folder) {
  4634. file_chooser_dir = g_file_get_parse_name(folder);
  4635. if (file_chooser_dir) {
  4636. if (lastopendir) {
  4637. lastopendir = dp_free(lastopendir);
  4638. if (lastopendir) {
  4639. }
  4640. }
  4641. lastopendir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  4642. strcpy(lastopendir, file_chooser_dir);
  4643. g_free(file_chooser_dir);
  4644. file_chooser_dir = NULL;
  4645. }
  4646. g_object_unref(folder);
  4647. }
  4648. /* copy filename */
  4649. file_chooser_filename = g_file_get_parse_name(file);
  4650. if (file_chooser_filename) {
  4651. if (strlen(file_chooser_filename)) {
  4652. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  4653. strcpy(inputfilename, file_chooser_filename);
  4654. } else {
  4655. g_print("%s(): empty filename\n", __func__);
  4656. }
  4657. bname = g_file_get_basename(file);
  4658. /* read and parse the file */
  4659. open4_response_cb_fn(file_chooser_filename, bname);
  4660. if (bname) {
  4661. g_free(bname);
  4662. bname = NULL;
  4663. };
  4664. /* there could have been a parse error */
  4665. g_free(file_chooser_filename);
  4666. file_chooser_filename = NULL;
  4667. }
  4668. /* print the derived filenames */
  4669. if (yydebug || 0) {
  4670. g_print("%s(): %s %s %s %s %s\n", __func__, g_file_get_parse_name(file),
  4671. g_file_get_basename(file), uri, g_file_get_path(file), g_file_get_parse_name(folder));
  4672. }
  4673. }
  4674. }
  4675. g_free(uri);
  4676. uri = NULL;
  4677. }
  4678. g_object_unref(file);
  4679. }
  4680. g_object_unref(files);
  4681. } else {
  4682. /* no file selected */
  4683. if (yydebug || 0) {
  4684. g_print("%s(): open dialog was closed\n", __func__);
  4685. }
  4686. }
  4687. /* inicate this dialog is finished in passed on var */
  4688. *done = TRUE;
  4689. g_main_context_wakeup(NULL);
  4690. return;
  4691. }
  4692. /* open jgf file */
  4693. static void open4_activated(GSimpleAction * action, GVariant * parameter, gpointer user_data)
  4694. {
  4695. gboolean multiple = FALSE; /* if TRUE multiple files can be selected as extended feature */
  4696. GtkWidget *dialog = NULL;
  4697. GtkFileFilter *filter = NULL;
  4698. gboolean done = FALSE; /* indicator dialog is finished */
  4699. if (action) {
  4700. }
  4701. if (parameter) {
  4702. }
  4703. if (user_data) {
  4704. }
  4705. /* see the testcase in gtk-4 testfilechooser.c */
  4706. dialog = g_object_new(GTK_TYPE_FILE_CHOOSER_DIALOG, "action", GTK_FILE_CHOOSER_ACTION_OPEN, "select-multiple", multiple, NULL);
  4707. gtk_window_set_title(GTK_WINDOW(dialog), "Open jgf graph file");
  4708. gtk_dialog_add_buttons(GTK_DIALOG(dialog), ("_Cancel"), GTK_RESPONSE_CANCEL, ("_Open"), GTK_RESPONSE_OK, NULL);
  4709. gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
  4710. /* the callback will set bool done to TRUE if ready */
  4711. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(open4_response_cb), (gpointer) & done);
  4712. /* Filters */
  4713. filter = gtk_file_filter_new();
  4714. gtk_file_filter_set_name(filter, "All Files");
  4715. gtk_file_filter_add_pattern(filter, "*");
  4716. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  4717. filter = gtk_file_filter_new();
  4718. gtk_file_filter_set_name(filter, "jgf");
  4719. gtk_file_filter_add_pattern(filter, "*.jgf");
  4720. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  4721. /* this are the gzipped graph files */
  4722. filter = gtk_file_filter_new();
  4723. gtk_file_filter_set_name(filter, "jgf.gz");
  4724. gtk_file_filter_add_pattern(filter, "*.jgf.gz");
  4725. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  4726. if (lastopendir) {
  4727. set_current_folder(GTK_FILE_CHOOSER(dialog), lastopendir);
  4728. }
  4729. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  4730. gtk_widget_show(dialog);
  4731. /* run dialog and wait until it is ready */
  4732. while (done == FALSE) {
  4733. g_main_context_iteration(NULL, TRUE);
  4734. }
  4735. gtk_window_destroy(GTK_WINDOW(dialog));
  4736. return;
  4737. }
  4738. #endif
  4739. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  4740. /* 'open' in 'file' menu activated - sub menu in menu items in menu bar in vbox1 */
  4741. static void on_top_level_window_open4_activate(GtkMenuItem * menuitem, gpointer user_data)
  4742. {
  4743. GtkWidget *edialog = (GtkWidget *) 0;
  4744. GtkWidget *pdialog = (GtkWidget *) 0;
  4745. GtkWidget *dialog = (GtkWidget *) 0;
  4746. char *file_chooser_filename = (char *)0;
  4747. char *file_chooser_dir = (char *)0;
  4748. GtkFileChooser *chooser = NULL;
  4749. char *inputfilename = (char *)0;
  4750. char *baseinputfilename = (char *)0;
  4751. char *baseinputfilename2 = (char *)0;
  4752. gzFile f = NULL;
  4753. char *bname = NULL;
  4754. if (menuitem) {
  4755. }
  4756. if (user_data) {
  4757. }
  4758. #if (GTK_HAVE_API_VERSION_2 == 1)
  4759. /* see gimp source code howto */
  4760. dialog = gtk_file_chooser_dialog_new("Select JGF Graph File", 0, /* parent_window */
  4761. GTK_FILE_CHOOSER_ACTION_OPEN,
  4762. GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT, NULL);
  4763. #endif
  4764. #if (GTK_HAVE_API_VERSION_3 == 1)
  4765. /* see gimp source code howto */
  4766. dialog = gtk_file_chooser_dialog_new("Select JGF Graph File", GTK_WINDOW(mainwindow1) /* parent_window */
  4767. ,
  4768. GTK_FILE_CHOOSER_ACTION_OPEN,
  4769. "Cancel", GTK_RESPONSE_CANCEL, "Open", GTK_RESPONSE_ACCEPT, NULL);
  4770. #endif
  4771. chooser = GTK_FILE_CHOOSER(dialog);
  4772. /* use same dir if opened in earlier dir */
  4773. if (lastopendir) {
  4774. gtk_file_chooser_set_current_folder(chooser, lastopendir);
  4775. }
  4776. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  4777. /* run the window to select a input file */
  4778. if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
  4779. /* open button */
  4780. file_chooser_filename = (char *)gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
  4781. file_chooser_dir = (char *)gtk_file_chooser_get_current_folder(chooser);
  4782. } else {
  4783. /* cancel button */
  4784. (void)gtk_widget_destroy(dialog);
  4785. return;
  4786. }
  4787. /* */
  4788. (void)gtk_widget_destroy(dialog);
  4789. /* update last-used-dir */
  4790. if (file_chooser_dir) {
  4791. if (lastopendir) {
  4792. lastopendir = dp_free(lastopendir);
  4793. if (lastopendir) {
  4794. }
  4795. }
  4796. lastopendir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  4797. strcpy(lastopendir, file_chooser_dir);
  4798. /* not dp_free() because gtk allocated */
  4799. g_free(file_chooser_dir);
  4800. }
  4801. /* copy the input filename from gtk */
  4802. if (file_chooser_filename) {
  4803. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  4804. strcpy(inputfilename, file_chooser_filename);
  4805. /* node dp_free() because gtk allocated */
  4806. g_free(file_chooser_filename);
  4807. } else {
  4808. return;
  4809. }
  4810. /* set filename in window */
  4811. bname = g_path_get_basename(inputfilename);
  4812. baseinputfilename2 = dp_calloc(1, (strlen(bname) + 1));
  4813. strcpy(baseinputfilename2, bname);
  4814. /* not dp_free() because gtk allocated */
  4815. g_free(bname);
  4816. /* open file to parse */
  4817. errno = 0;
  4818. f = gzopen(inputfilename, "rb");
  4819. if (f == NULL) {
  4820. edialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  4821. GTK_DIALOG_DESTROY_WITH_PARENT,
  4822. GTK_MESSAGE_ERROR,
  4823. GTK_BUTTONS_CLOSE,
  4824. "Cannot open file %s for reading (%s)", inputfilename, g_strerror(errno));
  4825. gtk_dialog_run(GTK_DIALOG(edialog));
  4826. gtk_widget_destroy(edialog);
  4827. inputfilename = dp_free(inputfilename);
  4828. if (inputfilename) {
  4829. }
  4830. baseinputfilename2 = dp_free(baseinputfilename2);
  4831. if (baseinputfilename2) {
  4832. }
  4833. /* data is unchanged, so keep validdata status */
  4834. return;
  4835. }
  4836. /* type of graph data 0=gml 1=dot 2=vcg 3=jgf */
  4837. graphtype = 3;
  4838. do_clear_all(0);
  4839. /* background r/g/b of drawing */
  4840. bgcr = 0xff;
  4841. bgcg = 0xff;
  4842. bgcb = 0xff;
  4843. /* create root graph */
  4844. create_maingraph();
  4845. /* parse the vcg data */
  4846. if (jgfparse(maingraph, f, baseinputfilename2, argv0)) {
  4847. /* parse error */
  4848. if (strlen(parsermessage) == 0) {
  4849. strcpy(parsermessage, "no parser message");
  4850. }
  4851. pdialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  4852. GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", parsermessage);
  4853. gtk_dialog_run(GTK_DIALOG(pdialog));
  4854. gtk_widget_destroy(pdialog);
  4855. inputfilename = dp_free(inputfilename);
  4856. if (inputfilename) {
  4857. }
  4858. baseinputfilename2 = dp_free(baseinputfilename2);
  4859. if (baseinputfilename2) {
  4860. }
  4861. fflush(stdout);
  4862. gzclose(f);
  4863. /* data is invalid at this point */
  4864. validdata = 0;
  4865. do_clear_all(0);
  4866. /* use package string program name as set by configure in config.h */
  4867. gtk_window_set_title(GTK_WINDOW(mainwindow1), PACKAGE_STRING);
  4868. /* re draw screen */
  4869. gtk_widget_queue_draw(drawingarea1);
  4870. return;
  4871. }
  4872. gzclose(f);
  4873. bname = g_path_get_basename(inputfilename);
  4874. baseinputfilename = uniqstr(bname);
  4875. /* not dp_free() because gtk allocated */
  4876. g_free(bname);
  4877. gtk_window_set_title(GTK_WINDOW(mainwindow1), baseinputfilename);
  4878. /* check for empty graph here */
  4879. if (maingraph->rawnodelist) {
  4880. printf("%s(): calculating layout of file %s\n", __func__, baseinputfilename2);
  4881. fflush(stdout);
  4882. /* update status text */
  4883. update_status_text("Wait ... Calculating Layout");
  4884. while (gtk_events_pending()) {
  4885. gtk_main_iteration();
  4886. /* this updates the status text */
  4887. }
  4888. do_layout_all(maingraph);
  4889. fflush(stdout);
  4890. /* update status text */
  4891. update_status_text(NULL);
  4892. while (gtk_main_iteration()) {
  4893. /* this should update the status text */ ;
  4894. }
  4895. /* set sliders to defaults */
  4896. zfactor = 1.0;
  4897. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale1), 50);
  4898. vxmin = 0;
  4899. vymin = 0;
  4900. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale2), 0);
  4901. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjhscale1), 0);
  4902. /* fit drawing in window */
  4903. dofit();
  4904. validdata = 1;
  4905. } else {
  4906. /* update status text */
  4907. update_status_text("Empty graph ... No Nodes");
  4908. validdata = 0;
  4909. }
  4910. inputfilename = dp_free(inputfilename);
  4911. if (inputfilename) {
  4912. }
  4913. baseinputfilename2 = dp_free(baseinputfilename2);
  4914. if (baseinputfilename2) {
  4915. }
  4916. /* re draw screen */
  4917. gtk_widget_queue_draw(drawingarea1);
  4918. return;
  4919. }
  4920. #endif
  4921. #if (GTK_HAVE_API_VERSION_4 == 1)
  4922. /* generate the file */
  4923. static void save1_response_cb_fn(char *svgfilename, char *binputfilename)
  4924. {
  4925. int mymaxx = 0;
  4926. int mymaxy = 0;
  4927. int saved_vxmin = 0;
  4928. int saved_vymin = 0;
  4929. FILE *fstream = NULL;
  4930. GtkWidget *dialog = NULL;
  4931. cairo_surface_t *surface = NULL;
  4932. cairo_t *crp = NULL;
  4933. if (binputfilename) {
  4934. }
  4935. errno = 0;
  4936. fstream = fopen(svgfilename, "wb");
  4937. /* check if open */
  4938. if (fstream == NULL) {
  4939. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  4940. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  4941. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Cannot open file %s", svgfilename);
  4942. gtk_widget_show(GTK_WIDGET(dialog));
  4943. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  4944. return;
  4945. }
  4946. /* write the svg image data */
  4947. /* save current gui settings */
  4948. saved_vxmin = vxmin;
  4949. saved_vymin = vymin;
  4950. /* output whole drawing with a small border, then edge line at end is in drawing */
  4951. vxmin = 0;
  4952. vymin = 0;
  4953. mymaxx = (int)((maxx + xspacing) * /* 1.0 */ zfactor);
  4954. mymaxy = (int)((maxy + yspacing) * /* 1.0 */ zfactor);
  4955. surface = cairo_svg_surface_create(svgfilename, mymaxx, mymaxy);
  4956. /* */
  4957. crp = cairo_create(surface);
  4958. /* fill drawing background with background color */
  4959. cairo_set_source_rgb(crp, bgcr / 255.0, bgcg / 255.0, bgcb / 255.0);
  4960. /* select whole drawing to fill wth background color */
  4961. cairo_rectangle(crp, 0, 0, mymaxx, mymaxy);
  4962. cairo_fill(crp);
  4963. /* use zoom slider drawing scale */
  4964. cairo_scale(crp, /*1.0 */ zfactor, /*1.0 */ zfactor);
  4965. on_top_level_window_drawingarea1_expose_event_edges(crp);
  4966. on_top_level_window_drawingarea1_expose_event_nodes(crp);
  4967. cairo_destroy(crp);
  4968. cairo_surface_destroy(surface);
  4969. /* restore screen (x,y) min */
  4970. vxmin = saved_vxmin;
  4971. vymin = saved_vymin;
  4972. fclose(fstream);
  4973. return;
  4974. }
  4975. /* run dialog and set bool done to TRUE if ready */
  4976. static void save1_response_cb(GtkDialog * dialog, int response_id, gpointer data)
  4977. {
  4978. gboolean *done = data; /* bool to set is passed on at call */
  4979. GListModel *files = NULL;
  4980. guint i = 0;
  4981. guint n = 0;
  4982. GFile *file = NULL;
  4983. GFile *folder = NULL;
  4984. char *uri = NULL;
  4985. char *file_chooser_dir = NULL;
  4986. char *inputfilename = NULL;
  4987. char *file_chooser_filename = NULL;
  4988. char *bbbname = NULL;
  4989. /* this allows to select multiple files at once and generate all output files with same data */
  4990. /* the uri allow to save to url as on used the internet */
  4991. if (response_id == GTK_RESPONSE_OK && 1 /* for testing */ ) {
  4992. /* scan the list with selected files */
  4993. files = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog));
  4994. n = g_list_model_get_n_items(files);
  4995. /* this causes crash only at save at the free */
  4996. for (i = 0; i < n; i++) {
  4997. file = g_list_model_get_item(files, i);
  4998. uri = g_file_get_uri(file);
  4999. /* option here
  5000. * the uri is like file:///bin/true
  5001. * this allows for network uri
  5002. * as https://graphviewer.nl/data/example.dot
  5003. */
  5004. if (uri == NULL) {
  5005. g_print("%s(): file %d has nil name\n", __func__, i);
  5006. } else {
  5007. if (strlen(uri) == 0) {
  5008. g_print("%s(): file %d has empty name \"\"\n", __func__, i);
  5009. } else {
  5010. if (i != 0) {
  5011. g_print("%s(): skipped file %d with name %s\n", __func__, i, uri);
  5012. } else {
  5013. if (yydebug || 0) {
  5014. g_print("%s(): selected file %d with name %s\n", __func__, i, uri);
  5015. }
  5016. /* this is the first file to read
  5017. * uri is file:///bin/foo
  5018. * g_file_get_parse_name(file) is /bin/foo
  5019. * g_file_get_basename(file) is foo
  5020. * g_file_get_path(file) is /bin/foo
  5021. */
  5022. /* update directory of chosen file */
  5023. folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
  5024. if (folder) {
  5025. file_chooser_dir = g_file_get_parse_name(folder);
  5026. if (file_chooser_dir) {
  5027. if (lastsavedir) {
  5028. lastsavedir = dp_free(lastsavedir);
  5029. if (lastsavedir) {
  5030. }
  5031. }
  5032. lastsavedir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  5033. strcpy(lastsavedir, file_chooser_dir);
  5034. g_free(file_chooser_dir);
  5035. file_chooser_dir = NULL;
  5036. }
  5037. g_object_unref(folder);
  5038. }
  5039. /* copy filename */
  5040. file_chooser_filename = g_file_get_parse_name(file);
  5041. if (file_chooser_filename) {
  5042. if (strlen(file_chooser_filename)) {
  5043. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  5044. strcpy(inputfilename, file_chooser_filename);
  5045. bbbname = g_file_get_basename(file);
  5046. /* write the file */
  5047. save1_response_cb_fn(file_chooser_filename, bbbname);
  5048. if (bbbname) {
  5049. g_free(bbbname);
  5050. bbbname = NULL;
  5051. }
  5052. } else {
  5053. g_print("%s(): empty filename\n", __func__);
  5054. }
  5055. /* there could have been a error */
  5056. g_free(file_chooser_filename);
  5057. file_chooser_filename = NULL;
  5058. }
  5059. /* print the derived filenames */
  5060. if (yydebug || 0) {
  5061. g_print("%s(): %s %s %s %s %s\n", __func__, g_file_get_parse_name(file),
  5062. g_file_get_basename(file), uri, g_file_get_path(file), g_file_get_parse_name(folder));
  5063. }
  5064. }
  5065. }
  5066. g_free(uri);
  5067. uri = NULL;
  5068. }
  5069. g_object_unref(file);
  5070. }
  5071. g_object_unref(files);
  5072. } else {
  5073. /* no file selected */
  5074. if (yydebug || 0) {
  5075. g_print("%s(): save dialog was closed\n", __func__);
  5076. }
  5077. }
  5078. /* inicate this dialog is finished in passed on var */
  5079. *done = TRUE;
  5080. g_main_context_wakeup(NULL);
  5081. return;
  5082. }
  5083. /* save svg */
  5084. static void save1_activated(GSimpleAction * action, GVariant * parameter, gpointer user_data)
  5085. {
  5086. gboolean multiple = FALSE; /* if TRUE multiple files can be selected as extended feature */
  5087. GtkWidget *dialog = NULL;
  5088. GtkFileFilter *filter = NULL;
  5089. gboolean done = FALSE; /* indicator dialog is finished */
  5090. if (action) {
  5091. }
  5092. if (parameter) {
  5093. }
  5094. if (user_data) {
  5095. }
  5096. /* nothing todo if there is no layout */
  5097. if (validdata == 0) {
  5098. return;
  5099. }
  5100. /* see the testcase in gtk-4 testfilechooser.c */
  5101. dialog = g_object_new(GTK_TYPE_FILE_CHOOSER_DIALOG, "action", GTK_FILE_CHOOSER_ACTION_SAVE, "select-multiple", multiple, NULL);
  5102. gtk_window_set_title(GTK_WINDOW(dialog), "Save svg file");
  5103. gtk_dialog_add_buttons(GTK_DIALOG(dialog), ("_Cancel"), GTK_RESPONSE_CANCEL, ("_Save"), GTK_RESPONSE_OK, NULL);
  5104. gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
  5105. /* the callback will set bool done to TRUE if ready */
  5106. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(save1_response_cb), (gpointer) & done);
  5107. /* Filters */
  5108. filter = gtk_file_filter_new();
  5109. gtk_file_filter_set_name(filter, "All Files");
  5110. gtk_file_filter_add_pattern(filter, "*");
  5111. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  5112. filter = gtk_file_filter_new();
  5113. gtk_file_filter_set_name(filter, "svg");
  5114. gtk_file_filter_add_pattern(filter, "*.svg");
  5115. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  5116. if (lastsavedir) {
  5117. set_current_folder(GTK_FILE_CHOOSER(dialog), lastsavedir);
  5118. }
  5119. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  5120. gtk_widget_show(dialog);
  5121. /* run dialog and wait until it is ready */
  5122. while (done == FALSE) {
  5123. g_main_context_iteration(NULL, TRUE);
  5124. }
  5125. gtk_window_destroy(GTK_WINDOW(dialog));
  5126. dialog = NULL;
  5127. return;
  5128. }
  5129. #endif
  5130. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  5131. /* save as gtk svg */
  5132. static void on_top_level_window_svg1_activate(GtkMenuItem * menuitem, gpointer user_data)
  5133. {
  5134. GtkWidget *dialog = (GtkWidget *) 0;
  5135. GtkWidget *edialog = (GtkWidget *) 0;
  5136. char *file_chooser_filename = (char *)0;
  5137. char *file_chooser_dir = (char *)0;
  5138. GtkFileChooser *chooser = NULL;
  5139. GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  5140. gint res = 0;
  5141. char *svgfilename = NULL;
  5142. FILE *fstream = NULL;
  5143. int mymaxx = 0;
  5144. int mymaxy = 0;
  5145. int saved_vxmin = 0;
  5146. int saved_vymin = 0;
  5147. cairo_surface_t *surface = NULL;
  5148. cairo_t *crp = NULL;
  5149. /* nothing todo if there is no layout */
  5150. if (validdata == 0) {
  5151. return;
  5152. }
  5153. if (menuitem) {
  5154. }
  5155. if (user_data) {
  5156. }
  5157. dialog = gtk_file_chooser_dialog_new("Save As SVG Image",
  5158. /* parent_window */ NULL,
  5159. action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  5160. chooser = GTK_FILE_CHOOSER(dialog);
  5161. /* change to last used dir if any */
  5162. if (lastsavedir) {
  5163. gtk_file_chooser_set_current_folder(chooser, lastsavedir);
  5164. }
  5165. /* ask to override existing */
  5166. gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE);
  5167. /* get the filename */
  5168. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  5169. res = gtk_dialog_run(GTK_DIALOG(dialog));
  5170. if (res == GTK_RESPONSE_ACCEPT) {
  5171. file_chooser_filename = gtk_file_chooser_get_filename(chooser);
  5172. file_chooser_dir = gtk_file_chooser_get_current_folder(chooser);
  5173. } else {
  5174. /* cancel button */
  5175. (void)gtk_widget_destroy(dialog);
  5176. return;
  5177. }
  5178. /* update last-used-dir */
  5179. if (file_chooser_dir) {
  5180. if (lastsavedir) {
  5181. lastsavedir = dp_free(lastsavedir);
  5182. if (lastsavedir) {
  5183. }
  5184. }
  5185. lastsavedir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  5186. strcpy(lastsavedir, file_chooser_dir);
  5187. /* not dp_free() because gtk allocated */
  5188. g_free(file_chooser_dir);
  5189. }
  5190. /* */
  5191. (void)gtk_widget_destroy(dialog);
  5192. /* */
  5193. if (file_chooser_filename) {
  5194. svgfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  5195. strcpy(svgfilename, file_chooser_filename);
  5196. /* not dp_free() because gtk allocated */
  5197. g_free(file_chooser_filename);
  5198. } else {
  5199. /* no filename */
  5200. return;
  5201. }
  5202. errno = 0;
  5203. fstream = fopen(svgfilename, "wb");
  5204. /* check if open */
  5205. if (fstream == NULL) {
  5206. edialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  5207. GTK_DIALOG_DESTROY_WITH_PARENT,
  5208. GTK_MESSAGE_ERROR,
  5209. GTK_BUTTONS_CLOSE, "Cannot open file %s for writing (%s)", svgfilename, g_strerror(errno));
  5210. gtk_dialog_run(GTK_DIALOG(edialog));
  5211. gtk_widget_destroy(edialog);
  5212. svgfilename = dp_free(svgfilename);
  5213. if (svgfilename) {
  5214. }
  5215. return;
  5216. }
  5217. /* write the svg image data */
  5218. /* save current gui settings */
  5219. saved_vxmin = vxmin;
  5220. saved_vymin = vymin;
  5221. /* output whole drawing with a small border, then edge line at end is in drawing */
  5222. vxmin = 0;
  5223. vymin = 0;
  5224. mymaxx = (int)((maxx + xspacing) * /* 1.0 */ zfactor);
  5225. mymaxy = (int)((maxy + yspacing) * /* 1.0 */ zfactor);
  5226. surface = cairo_svg_surface_create(svgfilename, mymaxx, mymaxy);
  5227. /* */
  5228. crp = cairo_create(surface);
  5229. /* fill drawing background with background color */
  5230. cairo_set_source_rgb(crp, bgcr / 255.0, bgcg / 255.0, bgcb / 255.0);
  5231. /* select whole drawing to fill wth background color */
  5232. cairo_rectangle(crp, 0, 0, mymaxx, mymaxy);
  5233. cairo_fill(crp);
  5234. /* use zoom slider drawing scale */
  5235. cairo_scale(crp, /*1.0 */ zfactor, /*1.0 */ zfactor);
  5236. on_top_level_window_drawingarea1_expose_event_edges(crp);
  5237. on_top_level_window_drawingarea1_expose_event_nodes(crp);
  5238. cairo_destroy(crp);
  5239. cairo_surface_destroy(surface);
  5240. /* restore screen (x,y) min */
  5241. vxmin = saved_vxmin;
  5242. vymin = saved_vymin;
  5243. fclose(fstream);
  5244. svgfilename = dp_free(svgfilename);
  5245. if (svgfilename) {
  5246. }
  5247. return;
  5248. }
  5249. #endif
  5250. #if (GTK_HAVE_API_VERSION_4 == 1)
  5251. /* generate the file */
  5252. static void save2_response_cb_fn(char *diafilename, char *binputfilename)
  5253. {
  5254. FILE *fstream = NULL;
  5255. GtkWidget *dialog = NULL;
  5256. if (binputfilename) {
  5257. }
  5258. errno = 0;
  5259. fstream = fopen(diafilename, "wb");
  5260. /* check if open */
  5261. if (fstream == NULL) {
  5262. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  5263. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  5264. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Cannot open file %s", diafilename);
  5265. gtk_widget_show(dialog);
  5266. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  5267. return;
  5268. }
  5269. /* write the dia diagram */
  5270. graph2dia(maingraph, fstream);
  5271. fclose(fstream);
  5272. return;
  5273. }
  5274. /* run dialog and set bool done to TRUE if ready */
  5275. static void save2_response_cb(GtkDialog * dialog, int response_id, gpointer data)
  5276. {
  5277. gboolean *done = data; /* bool to set is passed on at call */
  5278. GListModel *files = NULL;
  5279. guint i = 0;
  5280. guint n = 0;
  5281. GFile *file = NULL;
  5282. GFile *folder = NULL;
  5283. char *uri = NULL;
  5284. char *file_chooser_dir = NULL;
  5285. char *inputfilename = NULL;
  5286. char *file_chooser_filename = NULL;
  5287. char *bbbname = NULL;
  5288. /* this allows to select multiple files at once and generate all output files with same data */
  5289. /* the uri allow to save to url as on used the internet */
  5290. if (response_id == GTK_RESPONSE_OK && 1 /* for testing */ ) {
  5291. /* scan the list with selected files */
  5292. files = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog));
  5293. n = g_list_model_get_n_items(files);
  5294. /* this causes crash only at save at the free */
  5295. for (i = 0; i < n; i++) {
  5296. file = g_list_model_get_item(files, i);
  5297. uri = g_file_get_uri(file);
  5298. /* option here
  5299. * the uri is like file:///bin/true
  5300. * this allows for network uri
  5301. * as https://graphviewer.nl/data/example.dot
  5302. */
  5303. if (uri == NULL) {
  5304. g_print("%s(): file %d has nil name\n", __func__, i);
  5305. } else {
  5306. if (strlen(uri) == 0) {
  5307. g_print("%s(): file %d has empty name \"\"\n", __func__, i);
  5308. } else {
  5309. if (i != 0) {
  5310. g_print("%s(): skipped file %d with name %s\n", __func__, i, uri);
  5311. } else {
  5312. if (yydebug || 0) {
  5313. g_print("%s(): selected file %d with name %s\n", __func__, i, uri);
  5314. }
  5315. /* this is the first file to read
  5316. * uri is file:///bin/foo
  5317. * g_file_get_parse_name(file) is /bin/foo
  5318. * g_file_get_basename(file) is foo
  5319. * g_file_get_path(file) is /bin/foo
  5320. */
  5321. /* update directory of chosen file */
  5322. folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
  5323. if (folder) {
  5324. file_chooser_dir = g_file_get_parse_name(folder);
  5325. if (file_chooser_dir) {
  5326. if (lastsavedir) {
  5327. lastsavedir = dp_free(lastsavedir);
  5328. if (lastsavedir) {
  5329. }
  5330. }
  5331. lastsavedir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  5332. strcpy(lastsavedir, file_chooser_dir);
  5333. g_free(file_chooser_dir);
  5334. file_chooser_dir = NULL;
  5335. }
  5336. g_object_unref(folder);
  5337. }
  5338. /* copy filename */
  5339. file_chooser_filename = g_file_get_parse_name(file);
  5340. if (file_chooser_filename) {
  5341. if (strlen(file_chooser_filename)) {
  5342. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  5343. strcpy(inputfilename, file_chooser_filename);
  5344. bbbname = g_file_get_basename(file);
  5345. /* write the file */
  5346. save2_response_cb_fn(file_chooser_filename, bbbname);
  5347. if (bbbname) {
  5348. g_free(bbbname);
  5349. bbbname = NULL;
  5350. }
  5351. } else {
  5352. g_print("%s(): empty filename\n", __func__);
  5353. }
  5354. /* there could have been a error */
  5355. g_free(file_chooser_filename);
  5356. file_chooser_filename = NULL;
  5357. }
  5358. /* print the derived filenames */
  5359. if (yydebug || 0) {
  5360. g_print("%s(): %s %s %s %s %s\n", __func__, g_file_get_parse_name(file),
  5361. g_file_get_basename(file), uri, g_file_get_path(file), g_file_get_parse_name(folder));
  5362. }
  5363. }
  5364. }
  5365. g_free(uri);
  5366. uri = NULL;
  5367. }
  5368. g_object_unref(file);
  5369. }
  5370. g_object_unref(files);
  5371. } else {
  5372. /* no file selected */
  5373. if (yydebug || 0) {
  5374. g_print("%s(): save dialog was closed\n", __func__);
  5375. }
  5376. }
  5377. /* inicate this dialog is finished in passed on var */
  5378. *done = TRUE;
  5379. g_main_context_wakeup(NULL);
  5380. return;
  5381. }
  5382. /* save dia xml */
  5383. static void save2_activated(GSimpleAction * action, GVariant * parameter, gpointer user_data)
  5384. {
  5385. gboolean multiple = FALSE; /* if TRUE multiple files can be selected as extended feature */
  5386. GtkWidget *dialog = NULL;
  5387. GtkFileFilter *filter = NULL;
  5388. gboolean done = FALSE; /* indicator dialog is finished */
  5389. if (action) {
  5390. }
  5391. if (parameter) {
  5392. }
  5393. if (user_data) {
  5394. }
  5395. /* nothing todo if there is no layout */
  5396. if (validdata == 0) {
  5397. return;
  5398. }
  5399. /* see the testcase in gtk-4 testfilechooser.c */
  5400. dialog = g_object_new(GTK_TYPE_FILE_CHOOSER_DIALOG, "action", GTK_FILE_CHOOSER_ACTION_SAVE, "select-multiple", multiple, NULL);
  5401. gtk_window_set_title(GTK_WINDOW(dialog), "Save dia xml file");
  5402. gtk_dialog_add_buttons(GTK_DIALOG(dialog), ("_Cancel"), GTK_RESPONSE_CANCEL, ("_Save"), GTK_RESPONSE_OK, NULL);
  5403. gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
  5404. /* the callback will set bool done to TRUE if ready */
  5405. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(save2_response_cb), (gpointer) & done);
  5406. /* Filters */
  5407. filter = gtk_file_filter_new();
  5408. gtk_file_filter_set_name(filter, "All Files");
  5409. gtk_file_filter_add_pattern(filter, "*");
  5410. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  5411. filter = gtk_file_filter_new();
  5412. gtk_file_filter_set_name(filter, "dia");
  5413. gtk_file_filter_add_pattern(filter, "*.dia");
  5414. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  5415. if (lastsavedir) {
  5416. set_current_folder(GTK_FILE_CHOOSER(dialog), lastsavedir);
  5417. }
  5418. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  5419. gtk_widget_show(dialog);
  5420. /* run dialog and wait until it is ready */
  5421. while (done == FALSE) {
  5422. g_main_context_iteration(NULL, TRUE);
  5423. }
  5424. gtk_window_destroy(GTK_WINDOW(dialog));
  5425. dialog = NULL;
  5426. return;
  5427. }
  5428. #endif
  5429. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  5430. /* save as dia xml diagram */
  5431. static void on_top_level_window_dia1_activate(GtkMenuItem * menuitem, gpointer user_data)
  5432. {
  5433. GtkWidget *dialog = (GtkWidget *) 0;
  5434. GtkWidget *edialog = (GtkWidget *) 0;
  5435. char *file_chooser_filename = (char *)0;
  5436. char *file_chooser_dir = (char *)0;
  5437. GtkFileChooser *chooser = NULL;
  5438. GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  5439. gint res = 0;
  5440. char *diafilename = NULL;
  5441. FILE *fstream = NULL;
  5442. if (validdata == 0) {
  5443. return;
  5444. }
  5445. if (menuitem) {
  5446. }
  5447. if (user_data) {
  5448. }
  5449. dialog = gtk_file_chooser_dialog_new("Save As DIA diagram",
  5450. /* parent_window */ NULL,
  5451. action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  5452. chooser = GTK_FILE_CHOOSER(dialog);
  5453. /* change to last used dir if any */
  5454. if (lastsavedir) {
  5455. gtk_file_chooser_set_current_folder(chooser, lastsavedir);
  5456. }
  5457. /* ask to override existing */
  5458. gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE);
  5459. /* get the filename */
  5460. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  5461. res = gtk_dialog_run(GTK_DIALOG(dialog));
  5462. if (res == GTK_RESPONSE_ACCEPT) {
  5463. file_chooser_filename = gtk_file_chooser_get_filename(chooser);
  5464. file_chooser_dir = gtk_file_chooser_get_current_folder(chooser);
  5465. } else {
  5466. /* cancel button */
  5467. (void)gtk_widget_destroy(dialog);
  5468. return;
  5469. }
  5470. /* update last-used-dir */
  5471. if (file_chooser_dir) {
  5472. if (lastsavedir) {
  5473. lastsavedir = dp_free(lastsavedir);
  5474. if (lastsavedir) {
  5475. }
  5476. }
  5477. lastsavedir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  5478. strcpy(lastsavedir, file_chooser_dir);
  5479. /* not dp_free() because gtk allocated */
  5480. g_free(file_chooser_dir);
  5481. }
  5482. /* */
  5483. (void)gtk_widget_destroy(dialog);
  5484. /* */
  5485. if (file_chooser_filename) {
  5486. diafilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  5487. strcpy(diafilename, file_chooser_filename);
  5488. /* not dp_free() because gtk allocated */
  5489. g_free(file_chooser_filename);
  5490. } else {
  5491. /* no filename */
  5492. return;
  5493. }
  5494. errno = 0;
  5495. fstream = fopen(diafilename, "wb");
  5496. /* check if open */
  5497. if (fstream == NULL) {
  5498. edialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  5499. GTK_DIALOG_DESTROY_WITH_PARENT,
  5500. GTK_MESSAGE_ERROR,
  5501. GTK_BUTTONS_CLOSE, "Cannot open file %s for writing (%s)", diafilename, g_strerror(errno));
  5502. gtk_dialog_run(GTK_DIALOG(edialog));
  5503. gtk_widget_destroy(edialog);
  5504. diafilename = dp_free(diafilename);
  5505. if (diafilename) {
  5506. }
  5507. return;
  5508. }
  5509. /* write the dia diagram */
  5510. graph2dia(maingraph, fstream);
  5511. fclose(fstream);
  5512. diafilename = dp_free(diafilename);
  5513. if (diafilename) {
  5514. }
  5515. return;
  5516. }
  5517. #endif
  5518. /* save as jgf json diagram json jgf version 2.1
  5519. {
  5520. "$schema": "http://json-schema.org/draft-07/schema#",
  5521. "$id": "http://jsongraphformat.info/v2.1/json-graph-schema.json",
  5522. "title": "JSON Graph Schema",
  5523. "oneOf": [
  5524. {
  5525. "type": "object",
  5526. "properties": {
  5527. "graph": { "$ref": "#/definitions/graph" }
  5528. },
  5529. "additionalProperties": false,
  5530. "required": [
  5531. "graph"
  5532. ]
  5533. },
  5534. {
  5535. "type": "object",
  5536. "properties": {
  5537. "graphs": {
  5538. "type": "array",
  5539. "items": { "$ref": "#/definitions/graph" }
  5540. }
  5541. },
  5542. "additionalProperties": false
  5543. }
  5544. ],
  5545. "definitions": {
  5546. "graph": {
  5547. "oneOf": [
  5548. {
  5549. "type": "object",
  5550. "additionalProperties": false,
  5551. "properties": {
  5552. "id": { "type": "string" },
  5553. "label": { "type": "string" },
  5554. "directed": { "type": [ "boolean" ], "default": true },
  5555. "type": { "type": "string" },
  5556. "metadata": { "type": [ "object" ] },
  5557. "nodes": {
  5558. "type": "object",
  5559. "additionalProperties": { "$ref": "#/definitions/node" }
  5560. },
  5561. "edges": {
  5562. "type": [ "array" ],
  5563. "items": { "$ref": "#/definitions/edge" }
  5564. }
  5565. }
  5566. },
  5567. {
  5568. "type": "object",
  5569. "additionalProperties": false,
  5570. "properties": {
  5571. "id": { "type": "string" },
  5572. "label": { "type": "string" },
  5573. "directed": { "type": [ "boolean" ], "default": true },
  5574. "type": { "type": "string" },
  5575. "metadata": { "type": [ "object" ] },
  5576. "nodes": {
  5577. "type": "object",
  5578. "additionalProperties": { "$ref": "#/definitions/node" }
  5579. },
  5580. "hyperedges": {
  5581. "type": [ "array" ],
  5582. "items": { "$ref": "#/definitions/directedhyperedge" }
  5583. }
  5584. }
  5585. },
  5586. {
  5587. "type": "object",
  5588. "additionalProperties": false,
  5589. "properties": {
  5590. "id": { "type": "string" },
  5591. "label": { "type": "string" },
  5592. "directed": { "type": [ "boolean" ], "enum": [false] },
  5593. "type": { "type": "string" },
  5594. "metadata": { "type": [ "object" ] },
  5595. "nodes": {
  5596. "type": "object",
  5597. "additionalProperties": { "$ref": "#/definitions/node" }
  5598. },
  5599. "hyperedges": {
  5600. "type": [ "array" ],
  5601. "items": { "$ref": "#/definitions/undirectedhyperedge" }
  5602. }
  5603. },
  5604. "required": [ "directed" ]
  5605. }
  5606. ]
  5607. },
  5608. "node": {
  5609. "type": "object",
  5610. "properties": {
  5611. "label": { "type": "string" },
  5612. "metadata": { "type": "object" },
  5613. "additionalProperties": false
  5614. }
  5615. },
  5616. "edge": {
  5617. "type": "object",
  5618. "additionalProperties": false,
  5619. "properties": {
  5620. "id": { "type": "string" },
  5621. "source": { "type": "string" },
  5622. "target": { "type": "string" },
  5623. "relation": { "type": "string" },
  5624. "directed": { "type": [ "boolean" ], "default": true },
  5625. "label": { "type": "string" },
  5626. "metadata": { "type": [ "object" ] }
  5627. },
  5628. "required": [ "source", "target" ]
  5629. },
  5630. "directedhyperedge": {
  5631. "type": "object",
  5632. "additionalProperties": false,
  5633. "properties": {
  5634. "id": { "type": "string" },
  5635. "source": { "type": "array", "items": { "type": "string" } },
  5636. "target": { "type": "array", "items": { "type": "string" } },
  5637. "relation": { "type": "string" },
  5638. "label": { "type": "string" },
  5639. "metadata": { "type": [ "object" ] }
  5640. },
  5641. "required": [ "source", "target" ]
  5642. },
  5643. "undirectedhyperedge": {
  5644. "type": "object",
  5645. "additionalProperties": false,
  5646. "properties": {
  5647. "id": { "type": "string" },
  5648. "nodes": { "type": "array", "items": { "type": "string" } },
  5649. "relation": { "type": "string" },
  5650. "label": { "type": "string" },
  5651. "metadata": { "type": [ "object" ] }
  5652. },
  5653. "required": [ "nodes" ]
  5654. }
  5655. }
  5656. }
  5657. */
  5658. #if (GTK_HAVE_API_VERSION_4 == 1)
  5659. /* generate the file */
  5660. static void save3_response_cb_fn(char *jgffilename, char *binputfilename)
  5661. {
  5662. FILE *fstream = NULL;
  5663. GtkWidget *dialog = NULL;
  5664. if (binputfilename) {
  5665. }
  5666. errno = 0;
  5667. fstream = fopen(jgffilename, "wb");
  5668. /* check if open */
  5669. if (fstream == NULL) {
  5670. dialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  5671. GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
  5672. GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "Cannot open file %s", jgffilename);
  5673. gtk_widget_show(dialog);
  5674. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(gtk_window_destroy), NULL);
  5675. return;
  5676. }
  5677. /* write the jgf json */
  5678. graph2jgf(maingraph, fstream);
  5679. fclose(fstream);
  5680. return;
  5681. }
  5682. /* run dialog and set bool done to TRUE if ready */
  5683. static void save3_response_cb(GtkDialog * dialog, int response_id, gpointer data)
  5684. {
  5685. gboolean *done = data; /* bool to set is passed on at call */
  5686. GListModel *files = NULL;
  5687. guint i = 0;
  5688. guint n = 0;
  5689. GFile *file = NULL;
  5690. GFile *folder = NULL;
  5691. char *uri = NULL;
  5692. char *file_chooser_dir = NULL;
  5693. char *inputfilename = NULL;
  5694. char *file_chooser_filename = NULL;
  5695. char *bbbname = NULL;
  5696. /* this allows to select multiple files at once and generate all output files with same data */
  5697. /* the uri allow to save to url as on used the internet */
  5698. if (response_id == GTK_RESPONSE_OK && 1 /* for testing */ ) {
  5699. /* scan the list with selected files */
  5700. files = gtk_file_chooser_get_files(GTK_FILE_CHOOSER(dialog));
  5701. n = g_list_model_get_n_items(files);
  5702. /* this causes crash only at save at the free */
  5703. for (i = 0; i < n; i++) {
  5704. file = g_list_model_get_item(files, i);
  5705. uri = g_file_get_uri(file);
  5706. /* option here
  5707. * the uri is like file:///bin/true
  5708. * this allows for network uri
  5709. * as https://graphviewer.nl/data/example.dot
  5710. */
  5711. if (uri == NULL) {
  5712. g_print("%s(): file %d has nil name\n", __func__, i);
  5713. } else {
  5714. if (strlen(uri) == 0) {
  5715. g_print("%s(): file %d has empty name \"\"\n", __func__, i);
  5716. } else {
  5717. if (i != 0) {
  5718. g_print("%s(): skipped file %d with name %s\n", __func__, i, uri);
  5719. } else {
  5720. if (yydebug || 0) {
  5721. g_print("%s(): selected file %d with name %s\n", __func__, i, uri);
  5722. }
  5723. /* this is the first file to read
  5724. * uri is file:///bin/foo
  5725. * g_file_get_parse_name(file) is /bin/foo
  5726. * g_file_get_basename(file) is foo
  5727. * g_file_get_path(file) is /bin/foo
  5728. */
  5729. /* update directory of chosen file */
  5730. folder = gtk_file_chooser_get_current_folder(GTK_FILE_CHOOSER(dialog));
  5731. if (folder) {
  5732. file_chooser_dir = g_file_get_parse_name(folder);
  5733. if (file_chooser_dir) {
  5734. if (lastsavedir) {
  5735. lastsavedir = dp_free(lastsavedir);
  5736. if (lastsavedir) {
  5737. }
  5738. }
  5739. lastsavedir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  5740. strcpy(lastsavedir, file_chooser_dir);
  5741. g_free(file_chooser_dir);
  5742. file_chooser_dir = NULL;
  5743. }
  5744. g_object_unref(folder);
  5745. }
  5746. /* copy filename */
  5747. file_chooser_filename = g_file_get_parse_name(file);
  5748. if (file_chooser_filename) {
  5749. if (strlen(file_chooser_filename)) {
  5750. inputfilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  5751. strcpy(inputfilename, file_chooser_filename);
  5752. bbbname = g_file_get_basename(file);
  5753. /* write the file */
  5754. save3_response_cb_fn(file_chooser_filename, bbbname);
  5755. if (bbbname) {
  5756. g_free(bbbname);
  5757. bbbname = NULL;
  5758. }
  5759. } else {
  5760. g_print("%s(): empty filename\n", __func__);
  5761. }
  5762. /* there could have been a error */
  5763. g_free(file_chooser_filename);
  5764. file_chooser_filename = NULL;
  5765. }
  5766. /* print the derived filenames */
  5767. if (yydebug || 0) {
  5768. g_print("%s(): %s %s %s %s %s\n", __func__, g_file_get_parse_name(file),
  5769. g_file_get_basename(file), uri, g_file_get_path(file), g_file_get_parse_name(folder));
  5770. }
  5771. }
  5772. }
  5773. g_free(uri);
  5774. uri = NULL;
  5775. }
  5776. g_object_unref(file);
  5777. }
  5778. g_object_unref(files);
  5779. } else {
  5780. /* no file selected */
  5781. if (yydebug || 0) {
  5782. g_print("%s(): save dialog was closed\n", __func__);
  5783. }
  5784. }
  5785. /* inicate this dialog is finished in passed on var */
  5786. *done = TRUE;
  5787. g_main_context_wakeup(NULL);
  5788. return;
  5789. }
  5790. /* save json jgf */
  5791. static void save3_activated(GSimpleAction * action, GVariant * parameter, gpointer user_data)
  5792. {
  5793. gboolean multiple = FALSE; /* if TRUE multiple files can be selected as extended feature */
  5794. GtkWidget *dialog = NULL;
  5795. GtkFileFilter *filter = NULL;
  5796. gboolean done = FALSE; /* indicator dialog is finished */
  5797. if (action) {
  5798. }
  5799. if (parameter) {
  5800. }
  5801. if (user_data) {
  5802. }
  5803. /* nothing todo if there is no layout */
  5804. if (validdata == 0) {
  5805. return;
  5806. }
  5807. /* see the testcase in gtk-4 testfilechooser.c */
  5808. dialog = g_object_new(GTK_TYPE_FILE_CHOOSER_DIALOG, "action", GTK_FILE_CHOOSER_ACTION_SAVE, "select-multiple", multiple, NULL);
  5809. gtk_window_set_title(GTK_WINDOW(dialog), "Save json jgf file");
  5810. gtk_dialog_add_buttons(GTK_DIALOG(dialog), ("_Cancel"), GTK_RESPONSE_CANCEL, ("_Save"), GTK_RESPONSE_OK, NULL);
  5811. gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK);
  5812. /* the callback will set bool done to TRUE if ready */
  5813. g_signal_connect(G_OBJECT(dialog), "response", G_CALLBACK(save3_response_cb), (gpointer) & done);
  5814. /* Filters */
  5815. filter = gtk_file_filter_new();
  5816. gtk_file_filter_set_name(filter, "All Files");
  5817. gtk_file_filter_add_pattern(filter, "*");
  5818. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  5819. filter = gtk_file_filter_new();
  5820. gtk_file_filter_set_name(filter, "jgf");
  5821. gtk_file_filter_add_pattern(filter, "*.jgf");
  5822. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  5823. filter = gtk_file_filter_new();
  5824. gtk_file_filter_set_name(filter, "json");
  5825. gtk_file_filter_add_pattern(filter, "*.json");
  5826. gtk_file_chooser_add_filter(GTK_FILE_CHOOSER(dialog), filter);
  5827. if (lastsavedir) {
  5828. set_current_folder(GTK_FILE_CHOOSER(dialog), lastsavedir);
  5829. }
  5830. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  5831. gtk_widget_show(dialog);
  5832. /* run dialog and wait until it is ready */
  5833. while (done == FALSE) {
  5834. g_main_context_iteration(NULL, TRUE);
  5835. }
  5836. gtk_window_destroy(GTK_WINDOW(dialog));
  5837. dialog = NULL;
  5838. return;
  5839. }
  5840. #endif
  5841. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  5842. static void on_top_level_window_jgf1_activate(GtkMenuItem * menuitem, gpointer user_data)
  5843. {
  5844. GtkWidget *dialog = (GtkWidget *) 0;
  5845. GtkWidget *edialog = (GtkWidget *) 0;
  5846. char *file_chooser_filename = (char *)0;
  5847. char *file_chooser_dir = (char *)0;
  5848. GtkFileChooser *chooser = NULL;
  5849. GtkFileChooserAction action = GTK_FILE_CHOOSER_ACTION_SAVE;
  5850. gint res = 0;
  5851. char *jgffilename = NULL;
  5852. FILE *fstream = NULL;
  5853. if (validdata == 0) {
  5854. return;
  5855. }
  5856. if (menuitem) {
  5857. }
  5858. if (user_data) {
  5859. }
  5860. dialog = gtk_file_chooser_dialog_new("Save As JGF json",
  5861. /* parent_window */ NULL,
  5862. action, "_Cancel", GTK_RESPONSE_CANCEL, "_Save", GTK_RESPONSE_ACCEPT, NULL);
  5863. chooser = GTK_FILE_CHOOSER(dialog);
  5864. /* change to last used dir if any */
  5865. if (lastsavedir) {
  5866. gtk_file_chooser_set_current_folder(chooser, lastsavedir);
  5867. }
  5868. /* ask to override existing */
  5869. gtk_file_chooser_set_do_overwrite_confirmation(chooser, TRUE);
  5870. /* get the filename */
  5871. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  5872. res = gtk_dialog_run(GTK_DIALOG(dialog));
  5873. if (res == GTK_RESPONSE_ACCEPT) {
  5874. file_chooser_filename = gtk_file_chooser_get_filename(chooser);
  5875. file_chooser_dir = gtk_file_chooser_get_current_folder(chooser);
  5876. } else {
  5877. /* cancel button */
  5878. (void)gtk_widget_destroy(dialog);
  5879. return;
  5880. }
  5881. /* update last-used-dir */
  5882. if (file_chooser_dir) {
  5883. if (lastsavedir) {
  5884. lastsavedir = dp_free(lastsavedir);
  5885. if (lastsavedir) {
  5886. }
  5887. }
  5888. lastsavedir = dp_calloc(1, (strlen(file_chooser_dir) + 1));
  5889. strcpy(lastsavedir, file_chooser_dir);
  5890. /* not dp_free() because gtk allocated */
  5891. g_free(file_chooser_dir);
  5892. }
  5893. /* */
  5894. (void)gtk_widget_destroy(dialog);
  5895. /* */
  5896. if (file_chooser_filename) {
  5897. jgffilename = dp_calloc(1, (strlen(file_chooser_filename) + 1));
  5898. strcpy(jgffilename, file_chooser_filename);
  5899. /* not dp_free() because gtk allocated */
  5900. g_free(file_chooser_filename);
  5901. } else {
  5902. /* no filename */
  5903. return;
  5904. }
  5905. errno = 0;
  5906. fstream = fopen(jgffilename, "wb");
  5907. /* check if open */
  5908. if (fstream == NULL) {
  5909. edialog = gtk_message_dialog_new(GTK_WINDOW(mainwindow1),
  5910. GTK_DIALOG_DESTROY_WITH_PARENT,
  5911. GTK_MESSAGE_ERROR,
  5912. GTK_BUTTONS_CLOSE, "Cannot open file %s for writing (%s)", jgffilename, g_strerror(errno));
  5913. gtk_dialog_run(GTK_DIALOG(edialog));
  5914. gtk_widget_destroy(edialog);
  5915. jgffilename = dp_free(jgffilename);
  5916. if (jgffilename) {
  5917. }
  5918. return;
  5919. }
  5920. /* write the jgf json */
  5921. graph2jgf(maingraph, fstream);
  5922. fclose(fstream);
  5923. jgffilename = dp_free(jgffilename);
  5924. if (jgffilename) {
  5925. }
  5926. return;
  5927. }
  5928. #endif
  5929. #if (GTK_HAVE_API_VERSION_4 == 1)
  5930. static void on_top_level_window_quit1_activate(GSimpleAction * action, GVariant * parameter, gpointer user_data)
  5931. {
  5932. if (action) {
  5933. }
  5934. if (parameter) {
  5935. }
  5936. do_clear_all(0);
  5937. if (lastopendir) {
  5938. lastopendir = dp_free(lastopendir);
  5939. if (lastopendir) {
  5940. }
  5941. }
  5942. if (lastsavedir) {
  5943. lastsavedir = dp_free(lastsavedir);
  5944. if (lastsavedir) {
  5945. }
  5946. }
  5947. g_application_quit(G_APPLICATION(user_data));
  5948. /* never reached */
  5949. return;
  5950. }
  5951. #endif
  5952. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  5953. /* 'quit' in 'file' menu activated - sub menu in menu items in menu bar in vbox1 */
  5954. static void on_top_level_window_quit1_activate(GtkMenuItem * menuitem, gpointer user_data)
  5955. {
  5956. if (menuitem) {
  5957. }
  5958. if (user_data) {
  5959. }
  5960. top_level_window_main_quit();
  5961. return;
  5962. }
  5963. #endif
  5964. #if (GTK_HAVE_API_VERSION_4 == 1)
  5965. /* left slider zoom scale */
  5966. static void on_vscale1_changed(GtkAdjustment * adj, gpointer data)
  5967. {
  5968. gdouble val0 = 0.0;
  5969. int val1 = 0;
  5970. if (data) {
  5971. }
  5972. /* check if there is node data to draw */
  5973. if (validdata == 0) {
  5974. return;
  5975. }
  5976. val0 = gtk_adjustment_get_value(adj);
  5977. val1 = (int)val0;
  5978. zfactor = exp((double)(3 * (val1 - 50)) / (double)50);
  5979. if (option_gdebug > 1 || 0) {
  5980. printf("%s(): zoomslider=%d zoomfactor=%f\n", __func__, val1, zfactor);
  5981. fflush(stdout);
  5982. }
  5983. /* do a re-draw */
  5984. gtk_widget_queue_draw(drawingarea1);
  5985. return;
  5986. }
  5987. #endif
  5988. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  5989. /* left slider zoom factor */
  5990. static void on_vscale1_changed(GtkAdjustment * adj)
  5991. {
  5992. gdouble val0 = 0.0;
  5993. int val1 = 0;
  5994. if (adj) {
  5995. }
  5996. /* check if there is node data to draw */
  5997. if (validdata == 0) {
  5998. return;
  5999. }
  6000. val0 = gtk_adjustment_get_value(adj);
  6001. val1 = (int)val0;
  6002. zfactor = exp((double)(3 * (val1 - 50)) / (double)50);
  6003. if (option_gdebug > 1) {
  6004. printf("%s(): zoomslider=%d zoomfactor=%f\n", __func__, val1, zfactor);
  6005. fflush(stdout);
  6006. }
  6007. /* do a re-draw */
  6008. gtk_widget_queue_draw(drawingarea1);
  6009. return;
  6010. }
  6011. #endif
  6012. #if (GTK_HAVE_API_VERSION_4 == 1)
  6013. /* right slider y offset 0...100% */
  6014. static void on_vscale2_changed(GtkAdjustment * adj, gpointer data)
  6015. {
  6016. gdouble val = 0.0;
  6017. if (data) {
  6018. }
  6019. /* check if there is node data to draw */
  6020. if (validdata == 0) {
  6021. return;
  6022. }
  6023. val = gtk_adjustment_get_value(adj);
  6024. vymin = (int)((val * maxy) / 100);
  6025. if (option_gdebug > 1) {
  6026. printf("%s(): yslider=%d vymin=%d (maxy=%d)\n", __func__, (int)val, vymin, maxy);
  6027. fflush(stdout);
  6028. }
  6029. /* do a re-draw */
  6030. gtk_widget_queue_draw(drawingarea1);
  6031. return;
  6032. }
  6033. #endif
  6034. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  6035. /* right slider y offset 0...100% */
  6036. static void on_vscale2_changed(GtkAdjustment * adj)
  6037. {
  6038. gdouble val = 0.0;
  6039. if (adj) {
  6040. }
  6041. /* check if there is node data to draw */
  6042. if (validdata == 0) {
  6043. return;
  6044. }
  6045. val = gtk_adjustment_get_value(adj);
  6046. vymin = (int)((val * maxy) / 100);
  6047. if (option_gdebug > 1) {
  6048. printf("%s(): yslider=%d vymin=%d (maxy=%d)\n", __func__, (int)val, vymin, maxy);
  6049. fflush(stdout);
  6050. }
  6051. /* do a re-draw */
  6052. gtk_widget_queue_draw(drawingarea1);
  6053. return;
  6054. }
  6055. #endif
  6056. #if (GTK_HAVE_API_VERSION_4 == 1)
  6057. /* bottom slider x offset 0...100% */
  6058. static void on_hscale1_changed(GtkAdjustment * adj, gpointer data)
  6059. {
  6060. gdouble val = 0.0;
  6061. if (data) {
  6062. }
  6063. /* check if there is node data to draw */
  6064. if (validdata == 0) {
  6065. return;
  6066. }
  6067. val = gtk_adjustment_get_value(adj);
  6068. vxmin = (int)((val * maxx) / 100);
  6069. if (option_gdebug > 1) {
  6070. printf("%s(): xslider=%d vxmin=%d (maxx=%d)\n", __func__, (int)val, vxmin, maxx);
  6071. fflush(stdout);
  6072. }
  6073. /* do a re-draw */
  6074. gtk_widget_queue_draw(drawingarea1);
  6075. return;
  6076. }
  6077. #endif
  6078. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  6079. /* bottom slider x offset 0...100% */
  6080. static void on_hscale1_changed(GtkAdjustment * adj)
  6081. {
  6082. gdouble val = 0.0;
  6083. if (adj) {
  6084. }
  6085. /* check if there is node data to draw */
  6086. if (validdata == 0) {
  6087. return;
  6088. }
  6089. val = gtk_adjustment_get_value(adj);
  6090. vxmin = (int)((val * maxx) / 100);
  6091. if (option_gdebug > 1) {
  6092. printf("%s(): xslider=%d vxmin=%d (maxx=%d)\n", __func__, (int)val, vxmin, maxx);
  6093. fflush(stdout);
  6094. }
  6095. /* do a re-draw */
  6096. gtk_widget_queue_draw(drawingarea1);
  6097. return;
  6098. }
  6099. #endif
  6100. /* draw arrow, option to allow multiple arrow types todo
  6101. * arrow comes from (start_x,start_y) to (end_x,end_y)
  6102. * size is optional, if zero a default size is used
  6103. */
  6104. static void drarrow(cairo_t * crp, int start_x, int start_y, int end_x, int end_y, double size)
  6105. {
  6106. double angle = 0.0;
  6107. double arrow_lenght = 8.0;
  6108. double arrow_degrees = ( /* degrees */ 30 * (M_PI / 180));
  6109. double x1 = 0.0;
  6110. double y1 = 0.0;
  6111. double x2 = 0.0;
  6112. double y2 = 0.0;
  6113. if (yydebug || 0) {
  6114. printf("%s(): arrow at (%d,%d) coming from (%d,%d) size %f\n", __func__, end_x, end_y, start_x, start_y, size);
  6115. }
  6116. /* if size is specified, use it, otherwise use default size */ if (size == 0) {
  6117. arrow_lenght = 8.0;
  6118. } else {
  6119. arrow_lenght = size;
  6120. }
  6121. /* gtk has a gtk_render_arrow() function as alternative to use here */
  6122. angle = atan2(end_y - start_y, end_x - start_x) + M_PI;
  6123. x1 = end_x + arrow_lenght * cos(angle - arrow_degrees);
  6124. y1 = end_y + arrow_lenght * sin(angle - arrow_degrees);
  6125. x2 = end_x + arrow_lenght * cos(angle + arrow_degrees);
  6126. y2 = end_y + arrow_lenght * sin(angle + arrow_degrees);
  6127. /* set start position of arrow part 1 */
  6128. cairo_move_to(crp, end_x, end_y);
  6129. cairo_line_to(crp, x1, y1);
  6130. /* set start position of arrow part 2 */
  6131. cairo_move_to(crp, end_x, end_y);
  6132. cairo_line_to(crp, x2, y2);
  6133. /* make a triangle */
  6134. cairo_line_to(crp, x1, y1);
  6135. return;
  6136. }
  6137. /* */
  6138. static void on_top_level_window_drawingarea1_expose_event_nodes_record_r(cairo_t * crp, struct gml_node
  6139. *node, struct gml_rl
  6140. *info)
  6141. {
  6142. int i = 0;
  6143. int x0 = 0;
  6144. int y0 = 0;
  6145. int r = 0;
  6146. int b = 0;
  6147. int g = 0;
  6148. int xxo = 0;
  6149. int yyo = 0;
  6150. int szx = 0;
  6151. int szy = 0;
  6152. PangoLayout *layout = NULL;
  6153. PangoFontDescription *desc = NULL;
  6154. char buf[128];
  6155. char *s = NULL;
  6156. /* name of font to use, example "Sans" */
  6157. const char *default_fontname = DEFAULT_FONTNAME;
  6158. /* name of slant to use, example "Italic", "Oblique", "Roman" */
  6159. const char *default_fontslant = DEFAULT_FONTSLANT;
  6160. /* name of weight to use, example "Bold", "Book", "Light", "Medium", "Semi-bold", "Ultra-light" */
  6161. const char *default_fontweight = DEFAULT_FONTWEIGHT;
  6162. /* name of condensed to use, example "Semi-Condensed", "Condensed" */
  6163. const char *default_fontcondensed = DEFAULT_FONTCONDENSED;
  6164. /* font size to use, example "10", "18", "20" etc. */
  6165. const char *default_fontsize = DEFAULT_FONTSIZE;
  6166. x0 = node->finx - vxmin;
  6167. y0 = node->finy - vymin;
  6168. if (info->hd == 0) {
  6169. /* not-has-data */
  6170. for (i = 0; i < info->nparts; i++) {
  6171. on_top_level_window_drawingarea1_expose_event_nodes_record_r(crp, node, info->parts[i]);
  6172. }
  6173. } else {
  6174. /* has-data */
  6175. /* black outline color */
  6176. r = 0;
  6177. g = 0;
  6178. b = 0;
  6179. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  6180. szx = info->bbx;
  6181. szy = info->bby;
  6182. if (info->dir == 0) {
  6183. if (info->xstep) {
  6184. szx = info->xstep;
  6185. } else {
  6186. szx = info->bbx;
  6187. }
  6188. } else {
  6189. if (info->ystep) {
  6190. szy = info->ystep;
  6191. } else {
  6192. szy = info->bby;
  6193. }
  6194. }
  6195. /* this is the box to put the part of the text in */
  6196. cairo_rectangle(crp, x0 + info->xoff, y0 + info->yoff, szx, szy);
  6197. if (yydebug || 0) {
  6198. printf("%s(): rect at (%d,%d) size (%d,%d) for \"%s\"\n", __func__,
  6199. x0 + info->xoff, y0 + info->yoff, szx, szy, info->ulabel);
  6200. }
  6201. cairo_stroke(crp);
  6202. /* fontcolor of node black default or color */
  6203. r = (node->fontcolor & 0x00ff0000) >> 16;
  6204. g = (node->fontcolor & 0x0000ff00) >> 8;
  6205. b = (node->fontcolor & 0x000000ff);
  6206. /* draw in text fontcolor of node */
  6207. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  6208. /* start text inside rectangle */
  6209. xxo = 2;
  6210. yyo = 2;
  6211. /* set start position of text */
  6212. cairo_move_to(crp, x0 + info->xoff + xxo, y0 + info->yoff + yyo);
  6213. layout = pango_cairo_create_layout(crp);
  6214. /* set the text to draw which is 0 terminated */
  6215. pango_layout_set_text(layout, info->ulabel, -1);
  6216. /* set font parameters */
  6217. /* create the fontname description */
  6218. memset(buf, 0, (size_t)128);
  6219. default_fontname = DEFAULT_FONTNAME;
  6220. /* check if node has a specified font slant */
  6221. default_fontslant = DEFAULT_FONTSLANT;
  6222. /* check if node has a specified font weight */
  6223. default_fontweight = DEFAULT_FONTWEIGHT;
  6224. /* check if node has a specified font size */
  6225. default_fontsize = DEFAULT_FONTSIZE;
  6226. /* create the font name string */
  6227. snprintf(buf, (128 - 1), "%s %s %s %s %s", default_fontname,
  6228. default_fontslant, default_fontweight, default_fontcondensed, default_fontsize);
  6229. /* copy string buffer */
  6230. s = uniqstr(buf);
  6231. /* */
  6232. desc = pango_font_description_from_string(s);
  6233. /* */
  6234. pango_layout_set_font_description(layout, desc);
  6235. /* */
  6236. pango_font_description_free(desc);
  6237. /* */
  6238. pango_cairo_update_layout(crp, layout);
  6239. /* draw the text */
  6240. pango_cairo_show_layout(crp, layout);
  6241. /* */
  6242. cairo_stroke(crp);
  6243. g_object_unref(G_OBJECT(layout));
  6244. }
  6245. return;
  6246. }
  6247. /* record node drawing */
  6248. static void on_top_level_window_drawingarea1_expose_event_nodes_record(cairo_t * crp, struct gml_node
  6249. *node)
  6250. {
  6251. on_top_level_window_drawingarea1_expose_event_nodes_record_r(crp, node, node->rlabel);
  6252. return;
  6253. }
  6254. /* html 1 item node drawing */ static void on_top_level_window_drawingarea1_expose_event_nodes_html1item(cairo_t * crp, struct gml_node
  6255. *node,
  6256. struct gml_hitem *item,
  6257. int xplus, int yplus)
  6258. {
  6259. PangoLayout *layout = NULL;
  6260. PangoFontDescription *desc = NULL;
  6261. char buf[128];
  6262. int x0 = 0;
  6263. int y0 = 0;
  6264. int r = 0;
  6265. int b = 0;
  6266. int g = 0;
  6267. int fontcolor = 0;
  6268. int bgcolor = 0;
  6269. int bgr = 0;
  6270. int bgb = 0;
  6271. int bgg = 0;
  6272. int xxo = 0;
  6273. int yyo = 0;
  6274. char *s = NULL;
  6275. char *fontstr = NULL;
  6276. PangoAttrList *pattrs = NULL;
  6277. GError *errorpos = NULL;
  6278. int status = 0;
  6279. char *ptext = NULL;
  6280. char *em = NULL;
  6281. char *fnam = NULL;
  6282. char *fslant = NULL;
  6283. char *fweight = NULL;
  6284. char *ful = NULL;
  6285. char *fol = NULL;
  6286. char spans[128];
  6287. char spane[64];
  6288. char *fsubs = NULL;
  6289. char *fsube = NULL;
  6290. char *fsups = NULL;
  6291. char *fsupe = NULL;
  6292. char *fstr = NULL;
  6293. int fsize = 0;
  6294. int flen = 0;
  6295. if (item == NULL) {
  6296. /* shouldnothappen */
  6297. return;
  6298. }
  6299. if (item->text == NULL) {
  6300. /* shouldnothappen */
  6301. return;
  6302. }
  6303. if (strlen(item->text) == 0) {
  6304. /* shouldnothappen */
  6305. return;
  6306. }
  6307. /* start positions */
  6308. x0 = node->finx - vxmin;
  6309. y0 = node->finy - vymin;
  6310. x0 = x0 + xplus;
  6311. y0 = y0 + yplus;
  6312. if (yydebug || 0) {
  6313. printf("%s(): text %s at (%d,%d)\n", __func__, item->text, xplus, yplus);
  6314. }
  6315. layout = pango_cairo_create_layout(crp);
  6316. /* background color */
  6317. if (item->ncolor < 0) {
  6318. /* shouldnothappen */
  6319. bgcolor = 0x00ffff;
  6320. } else {
  6321. bgcolor = item->ncolor;
  6322. }
  6323. /* backgroundcolor of node white default or color */
  6324. bgr = (bgcolor & 0x00ff0000) >> 16;
  6325. bgg = (bgcolor & 0x0000ff00) >> 8;
  6326. bgb = (bgcolor & 0x000000ff);
  6327. if (item->fontcolor < 0) {
  6328. /* shouldnothappen */
  6329. fontcolor = 0; /* black */
  6330. } else {
  6331. fontcolor = item->fontcolor;
  6332. }
  6333. /* fontcolor of node black default or color */
  6334. r = (fontcolor & 0x00ff0000) >> 16;
  6335. g = (fontcolor & 0x0000ff00) >> 8;
  6336. b = (fontcolor & 0x000000ff);
  6337. /* re-use pango font format string */
  6338. if (item->fontstr) {
  6339. fontstr = item->fontstr;
  6340. } else {
  6341. /* create new string */
  6342. if (item->fontname) {
  6343. fnam = item->fontname;
  6344. } else {
  6345. fnam = DEFAULT_FONTNAME;
  6346. }
  6347. if (item->fontslant) {
  6348. fslant = item->fontslant;
  6349. } else {
  6350. fslant = DEFAULT_FONTSLANT;
  6351. }
  6352. if (item->bitflags.i) {
  6353. fslant = "italic";
  6354. }
  6355. if (item->fontweight) {
  6356. fweight = item->fontweight;
  6357. } else {
  6358. fweight = DEFAULT_FONTWEIGHT;
  6359. }
  6360. if (item->bitflags.b) {
  6361. fweight = "bold";
  6362. }
  6363. if (item->bitflags.u || 0) {
  6364. ful = " underline=\"single\"";
  6365. /* also option to set underline color */
  6366. } else {
  6367. ful = "";
  6368. }
  6369. /* also option to set overline color */
  6370. if (item->bitflags.o || 0) {
  6371. if (pango_overline < 0) {
  6372. /* probe pango lib for support at runtime */
  6373. status = pango_parse_markup("<span overline=\"single\">text</span>", -1, 0, &pattrs, &ptext, NULL, &errorpos);
  6374. if (status == 0) {
  6375. printf("%s(): overline <o> in html string is not supported with current pango library\n", __func__);
  6376. pango_overline = 0;
  6377. } else {
  6378. /* supported */
  6379. pango_overline = 1;
  6380. }
  6381. }
  6382. /* it depends on pango version if overline s allowed, if not then no text */
  6383. if (pango_overline) {
  6384. fol = " overline=\"single\"";
  6385. } else {
  6386. fol = "";
  6387. }
  6388. } else {
  6389. fol = "";
  6390. }
  6391. if (item->bitflags.s || 0) {
  6392. fstr = " strikethrough=\"true\"";
  6393. } else {
  6394. fstr = "";
  6395. }
  6396. if (item->fontsize < 0) {
  6397. fsize = DEFAULT_FONTSIZE_INT;
  6398. } else {
  6399. fsize = item->fontsize;
  6400. }
  6401. /* sub and superscript */
  6402. if (item->bitflags.sub || 0) {
  6403. fsubs = "<sub>";
  6404. fsube = "</sub>";
  6405. } else {
  6406. fsubs = "";
  6407. fsube = "";
  6408. }
  6409. if (item->bitflags.sup || 0) {
  6410. fsups = "<sup>";
  6411. fsupe = "</sup>";
  6412. } else {
  6413. fsups = "";
  6414. fsupe = "";
  6415. }
  6416. memset(spans, 0, (size_t)128);
  6417. /* start of format string */
  6418. snprintf(spans, (128 - 1), "<span foreground=\"#%02x%02x%02x\" background=\"#%02x%02x%02x\"%s%s%s>%s%s", r, g, b,
  6419. bgr, bgg, bgb, ful, fstr, fol, fsups, fsubs);
  6420. /* end of format string */
  6421. memset(spane, 0, (size_t)64);
  6422. snprintf(spane, (size_t)(64 - 1), "%s%s</span>", fsube, fsupe);
  6423. flen = strlen(spans) + strlen(spane) + strlen(item->otext) + 1;
  6424. fontstr = dp_calloc(1, flen);
  6425. /* create new full format string */
  6426. strcpy(fontstr, spans);
  6427. strcat(fontstr, item->otext);
  6428. strcat(fontstr, spane);
  6429. /* save for re-use */
  6430. item->fontstr = uniqstr(fontstr);
  6431. fontstr = dp_free(fontstr);
  6432. if (fontstr) {
  6433. }
  6434. fontstr = item->fontstr;
  6435. }
  6436. status = pango_parse_markup(fontstr, -1, 0, &pattrs, &ptext, NULL, &errorpos);
  6437. if (status == 0) {
  6438. if (errorpos) {
  6439. em = errorpos->message;
  6440. } else {
  6441. em = "";
  6442. }
  6443. printf("%s(): pango_parse_markup() of '%s' has error status %d \"%s\"\n", __func__, fontstr, status, em);
  6444. pattrs = NULL;
  6445. }
  6446. /* oke */
  6447. pango_layout_set_text(layout, item->text, -1);
  6448. pango_layout_set_attributes(layout, pattrs);
  6449. if (pango_layout_get_character_count(layout) == 0) {
  6450. /* shouldnothappen */
  6451. g_object_unref(G_OBJECT(layout));
  6452. return;
  6453. }
  6454. /* start text inside rectangle */
  6455. xxo = 1;
  6456. yyo = 1;
  6457. /* set start position of text */
  6458. cairo_move_to(crp, x0 + item->txoff + xxo, y0 + item->tyoff + yyo);
  6459. /* set font parameters */
  6460. /* create the fontname description or re-use */
  6461. if (item->fontdesc) {
  6462. s = item->fontdesc;
  6463. } else {
  6464. memset(buf, 0, (size_t)128);
  6465. /* create the font name string */
  6466. snprintf(buf, (size_t)(128 - 1), "%s %s %s %s %d", fnam, fslant, fweight, DEFAULT_FONTCONDENSED, fsize);
  6467. s = uniqstr(buf);
  6468. item->fontdesc = s;
  6469. }
  6470. /* */
  6471. desc = pango_font_description_from_string(s);
  6472. /* */
  6473. pango_layout_set_font_description(layout, desc);
  6474. /* */
  6475. pango_font_description_free(desc);
  6476. /* */
  6477. pango_cairo_update_layout(crp, layout);
  6478. /* draw the text */
  6479. pango_cairo_show_layout(crp, layout);
  6480. /* */
  6481. cairo_stroke(crp);
  6482. g_object_unref(G_OBJECT(layout));
  6483. return;
  6484. }
  6485. /* html items node drawing */
  6486. static void on_top_level_window_drawingarea1_expose_event_nodes_htmlitems(cairo_t * crp, struct gml_node
  6487. *node, struct gml_hilist *il, int xplus, int yplus)
  6488. {
  6489. struct gml_hitem *pitem = NULL;
  6490. struct gml_hilist *pi = NULL;
  6491. if (il == NULL) {
  6492. /* shouldnothappen */
  6493. return;
  6494. }
  6495. if (yydebug || 0) {
  6496. printf("%s(): node=\"%s\" xyplus=(%d,%d)\n", __func__, node->name, xplus, yplus);
  6497. }
  6498. /* scan the text elements */
  6499. pi = il;
  6500. while (pi) {
  6501. pitem = pi->items;
  6502. if (pitem) {
  6503. if (pi->items->bitflags.br) {
  6504. } else if (pi->items->bitflags.hr) {
  6505. } else if (pi->items->bitflags.vr) {
  6506. } else if (pi->items->bitflags.img) {
  6507. } else if (pi->items->bitflags.table) {
  6508. } else {
  6509. on_top_level_window_drawingarea1_expose_event_nodes_html1item(crp, node, pitem, xplus, yplus);
  6510. }
  6511. }
  6512. pi = pi->next;
  6513. }
  6514. return;
  6515. }
  6516. /* zzz */
  6517. /* html tables node drawing */
  6518. static void on_top_level_window_drawingarea1_expose_event_nodes_1htmltable(cairo_t * crp, struct gml_node
  6519. *node, struct gml_htlist *tlptr)
  6520. {
  6521. struct gml_tritemlist *trptr = NULL; /* list of <tr> items in this table */
  6522. struct gml_tditem *tdiptr = NULL;
  6523. struct gml_hilist *ilptr = NULL; /* list of text items */
  6524. struct gml_htlist *tlptrsub = NULL;
  6525. int yo = 0;
  6526. int xo = 0;
  6527. int nyo = 0;
  6528. int nxo = 0;
  6529. int itemrectanglecolor = 0; /* color of outline rectangle of item, 0 is black, #rrggbb */
  6530. int r = 0;
  6531. int g = 0;
  6532. int b = 0;
  6533. int tabxoff = 0;
  6534. int tabyoff = 0;
  6535. int tabxsize = 0;
  6536. int tabysize = 0;
  6537. int tabncols = 0;
  6538. int tabnrows = 0;
  6539. int trnumtd = 0;
  6540. int trysize = 0;
  6541. int tdxsize = 0;
  6542. int ytd = 0;
  6543. if (tlptr == NULL) {
  6544. printf("%s(): nil tlptr\n", __func__);
  6545. /* shouldnothappen */
  6546. return;
  6547. }
  6548. if (tlptr->titem == NULL) {
  6549. printf("%s(): nil titem\n", __func__);
  6550. /* shouldnothappen */
  6551. return;
  6552. }
  6553. /* scan the items in this <table> */
  6554. nxo = node->finx - vxmin;
  6555. nyo = node->finy - vymin;
  6556. /* (x,y) offset of <table> */
  6557. tabxoff = tlptr->titem->xoff;
  6558. tabyoff = tlptr->titem->yoff;
  6559. if (tabxoff) { /* todo */
  6560. }
  6561. if (tabyoff) { /* todo */
  6562. }
  6563. if (yydebug || 0) {
  6564. printf("%s(): <table> offset is (%d,%d)\n", __func__, tabxoff, tabyoff);
  6565. }
  6566. /* start draw at table offset */
  6567. /* xo = tabxoff; not used here */
  6568. yo = tabyoff;
  6569. /* (x,y) size of <table> */
  6570. tabxsize = tlptr->titem->txsize;
  6571. tabysize = tlptr->titem->tysize;
  6572. if (tabxsize) { /* todo */
  6573. }
  6574. if (tabysize) { /* todo */
  6575. }
  6576. /* (x,y) size of table in cols/rows */
  6577. tabncols = tlptr->titem->ncols;
  6578. tabnrows = tlptr->titem->nrows;
  6579. if (tabncols) { /* todo */
  6580. }
  6581. if (tabnrows) { /* todo */
  6582. }
  6583. /* */
  6584. if (tlptr->titem->tr) {
  6585. trptr = tlptr->titem->tr;
  6586. while (trptr) {
  6587. /* scan the <tr> items */
  6588. if (trptr->tritem) {
  6589. /* number of <td> items at this <tr> */
  6590. trnumtd = trptr->tritem->numtd;
  6591. if (trnumtd) { /* todo */
  6592. }
  6593. /* y size of this <tr> */
  6594. trysize = trptr->tritem->ysize;
  6595. /* */
  6596. tdiptr = trptr->tritem->tdi;
  6597. if (tdiptr) {
  6598. /* scan the <td> items */
  6599. xo = tabxoff;
  6600. while (tdiptr) {
  6601. /* x size of this <td> */
  6602. tdxsize = tdiptr->xsize;
  6603. if (tdxsize) { /* todo not used here */
  6604. }
  6605. /* there are dummy <td> with no item data in it, but color, size is set */
  6606. ilptr = tdiptr->il;
  6607. if (ilptr) {
  6608. ytd = 0;
  6609. while (ilptr) {
  6610. /* colored rectangle around item, option here. */
  6611. r = ((itemrectanglecolor & 0x00ff0000) >> 16);
  6612. g = ((itemrectanglecolor & 0x0000ff00) >> 8);
  6613. b = (itemrectanglecolor & 0x000000ff);
  6614. /* */
  6615. /* */
  6616. if (yydebug || 0) {
  6617. printf
  6618. ("%s(): <td> at (%d,%d) size (%d,%d) \"%s\"\n",
  6619. __func__, xo, yo + ytd, ilptr->items->txsize, ilptr->items->tysize, ilptr->items->text);
  6620. }
  6621. /* */
  6622. if (ilptr->items->bitflags.br) {
  6623. } else if (ilptr->items->bitflags.hr) {
  6624. } else if (ilptr->items->bitflags.vr) {
  6625. } else if (ilptr->items->bitflags.img) {
  6626. } else if (ilptr->items->bitflags.table) {
  6627. if (yydebug || 0) {
  6628. printf
  6629. ("%s(): table bit set todo xstep=%d xo=%d yo+ytd=%d\n",
  6630. __func__, tdiptr->xstep, xo, yo + ytd);
  6631. }
  6632. ilptr->items->table->xoff = xo;
  6633. ilptr->items->table->yoff = yo + ytd;
  6634. } else {
  6635. if (yydebug || 0) {
  6636. printf("%s(): items at (%d,%d)\n", __func__, xo, yo + ytd);
  6637. }
  6638. /* html items node drawing */
  6639. on_top_level_window_drawingarea1_expose_event_nodes_html1item(crp, node, ilptr->items,
  6640. /* int xplus */
  6641. xo,
  6642. /* int yplus */
  6643. yo + ytd);
  6644. }
  6645. ytd = ytd + ilptr->items->tysize;
  6646. ilptr = ilptr->next;
  6647. }
  6648. }
  6649. /* there can be dummy <td> */
  6650. /* test */
  6651. if (0) {
  6652. /* test only */
  6653. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  6654. cairo_rectangle(crp, xo + nxo, yo + nyo, tdxsize, trysize);
  6655. cairo_stroke(crp); /* ccx */
  6656. } else {
  6657. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  6658. cairo_rectangle(crp, xo + nxo, yo + nyo, tdiptr->xstep, tdiptr->ystep);
  6659. cairo_stroke(crp); /* ccx */
  6660. }
  6661. /* */
  6662. /* to next <td> */
  6663. xo = xo + 2;
  6664. xo = xo + tdiptr->xstep;
  6665. tdiptr = tdiptr->next;
  6666. }
  6667. /* end of <td> */
  6668. yo = yo + trysize;
  6669. }
  6670. }
  6671. trptr = trptr->next;
  6672. }
  6673. }
  6674. /* scan the sub <table> items in this <table> */
  6675. if (tlptr->titem->tl) {
  6676. tlptrsub = tlptr->titem->tl;
  6677. while (tlptrsub) {
  6678. on_top_level_window_drawingarea1_expose_event_nodes_1htmltable(crp, node, tlptrsub);
  6679. tlptrsub = tlptrsub->next;
  6680. }
  6681. }
  6682. return;
  6683. }
  6684. /* html tables node drawing */
  6685. static void on_top_level_window_drawingarea1_expose_event_nodes_htmltables(cairo_t * crp, struct gml_node
  6686. *node)
  6687. {
  6688. struct gml_htlist *tlptr = NULL;
  6689. if (node->hlabel->tl == NULL) {
  6690. /* shouldnothappen */
  6691. return;
  6692. }
  6693. /* */ tlptr = node->hlabel->tl;
  6694. while (tlptr) {
  6695. on_top_level_window_drawingarea1_expose_event_nodes_1htmltable(crp, node, tlptr);
  6696. tlptr = tlptr->next;
  6697. }
  6698. return;
  6699. }
  6700. /* html node drawing */
  6701. static void on_top_level_window_drawingarea1_expose_event_nodes_html(cairo_t * crp, struct gml_node
  6702. *node)
  6703. {
  6704. if (node->hlabel->mode == 0) {
  6705. /* items */
  6706. on_top_level_window_drawingarea1_expose_event_nodes_htmlitems(crp, node, node->hlabel->il, 0, 0);
  6707. } else {
  6708. /* tables */
  6709. on_top_level_window_drawingarea1_expose_event_nodes_htmltables(crp, node);
  6710. }
  6711. return;
  6712. }
  6713. /* draw all nodes z
  6714. zzz*/
  6715. static void on_top_level_window_drawingarea1_expose_event_nodes(cairo_t * crp)
  6716. {
  6717. int xo = 0;
  6718. int yo = 0;
  6719. double dfs = 0.0;
  6720. int fs = 0;
  6721. int r = 0;
  6722. int g = 0;
  6723. int b = 0;
  6724. PangoLayout *layout = NULL;
  6725. PangoFontDescription *desc = NULL;
  6726. char buf[128];
  6727. char *s = NULL;
  6728. /* name of font to use, example "Sans" */
  6729. const char *default_fontname = DEFAULT_FONTNAME;
  6730. /* name of slant to use, example "Italic", "Oblique", "Roman" */
  6731. const char *default_fontslant = DEFAULT_FONTSLANT;
  6732. /* name of weight to use, example "Bold", "Book", "Light", "Medium", "Semi-bold", "Ultra-light" */
  6733. const char *default_fontweight = DEFAULT_FONTWEIGHT;
  6734. /* name of condensed to use, example "Semi-Condensed", "Condensed" */
  6735. const char *default_fontcondensed = DEFAULT_FONTCONDENSED;
  6736. /* font size to use, example "10", "18", "20" etc. */
  6737. const char *default_fontsize = DEFAULT_FONTSIZE;
  6738. int x0 = 0;
  6739. int y0 = 0;
  6740. struct gml_nlist *nl = NULL;
  6741. nl = maingraph->nodelist;
  6742. while (nl) {
  6743. /* only draw real nodes here or draw edge-label */
  6744. if (nl->node->dummy == 0) {
  6745. x0 = nl->node->finx - vxmin;
  6746. y0 = nl->node->finy - vymin;
  6747. /* first draw circle is node has a selfedge */
  6748. if (nl->node->elabel == 0) {
  6749. if (nl->node->nselfedges) {
  6750. /* black or colored selfedge */
  6751. r = (nl->node->secolor & 0x00ff0000) >> 16;
  6752. g = ((nl->node->secolor & 0x0000ff00) >> 8);
  6753. b = (nl->node->secolor & 0x000000ff);
  6754. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  6755. /* draw the self-edge, whole circle */
  6756. cairo_arc(crp, x0 + nl->node->bbx - 3, y0 + nl->node->bby - 3, 6 /* radius */ ,
  6757. 0 /* 45 * (180 * M_PI) */ , 2 * M_PI);
  6758. /* opt. arrow, which is too big here todo. this looks not good */
  6759. if (0) {
  6760. drarrow(crp, x0 - 10, y0 + nl->node->bby - 6, x0, y0 + nl->node->bby - 6, 3);
  6761. }
  6762. cairo_stroke(crp);
  6763. }
  6764. }
  6765. /* fillcolor of node white default or color */
  6766. r = ((nl->node->ncolor & 0x00ff0000) >> 16);
  6767. g = ((nl->node->ncolor & 0x0000ff00) >> 8);
  6768. b = (nl->node->ncolor & 0x000000ff);
  6769. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  6770. cairo_rectangle(crp, x0, y0, nl->node->bbx, nl->node->bby);
  6771. cairo_fill(crp);
  6772. cairo_stroke(crp);
  6773. /* outline color black for node, edgelabel node has no outline */
  6774. if (nl->node->elabel == 0) {
  6775. /* bordercolor of node black default or color */
  6776. r = (nl->node->nbcolor & 0x00ff0000) >> 16;
  6777. g = (nl->node->nbcolor & 0x0000ff00) >> 8;
  6778. b = (nl->node->nbcolor & 0x000000ff);
  6779. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  6780. cairo_rectangle(crp, x0, y0, nl->node->bbx, nl->node->bby);
  6781. cairo_stroke(crp);
  6782. } else {
  6783. /* this is a edge label, no outline */
  6784. }
  6785. /* draw no text labels if labels==0 */
  6786. if (option_labels == 0) {
  6787. nl = nl->next;
  6788. continue;
  6789. }
  6790. /*
  6791. * now draw text of label as ususal or record style label
  6792. */
  6793. /* this below is not oke, todo to fix */
  6794. /* calculate the scaled font size */
  6795. dfs = (zfactor * atoi(default_fontsize));
  6796. /* somewhat rounded version */
  6797. fs = (int)dfs;
  6798. /* too small to draw readable text then skip the following text drawing area */
  6799. if (fs < 4) {
  6800. nl = nl->next;
  6801. continue;
  6802. }
  6803. if (yydebug || 0) {
  6804. printf("%s(): drawrh=%d\n", __func__, nl->node->drawrh);
  6805. }
  6806. if (nl->node->drawrh) {
  6807. /* draw regular text in node, or record label */
  6808. if (nl->node->hlabel) {
  6809. /* draw html label */
  6810. on_top_level_window_drawingarea1_expose_event_nodes_html(crp, nl->node);
  6811. } else if (nl->node->rlabel) {
  6812. /* draw record label */
  6813. on_top_level_window_drawingarea1_expose_event_nodes_record(crp, nl->node);
  6814. } else {
  6815. /* draw regular text */
  6816. /* fontcolor of node black default or color */
  6817. r = (nl->node->fontcolor & 0x00ff0000) >> 16;
  6818. g = (nl->node->fontcolor & 0x0000ff00) >> 8;
  6819. b = (nl->node->fontcolor & 0x000000ff);
  6820. /* draw in text color of node */
  6821. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  6822. xo = 2;
  6823. yo = 2;
  6824. /* set start position of text */
  6825. cairo_move_to(crp, nl->node->finx - vxmin + xo, nl->node->finy - vymin + yo);
  6826. layout = pango_cairo_create_layout(crp);
  6827. if (nl->node->nlabel == NULL) {
  6828. printf("%s(): nil nlabel\n", __func__);
  6829. /* shouldnothappen */
  6830. nl->node->nlabel = nl->node->name;
  6831. }
  6832. /* set the text to draw which is 0 terminated */
  6833. pango_layout_set_text(layout, nl->node->nlabel, -1);
  6834. /* set font parameters */
  6835. /* create the fontname description */
  6836. memset(buf, 0, (size_t)128);
  6837. default_fontname = DEFAULT_FONTNAME;
  6838. /* check if node has a specified font slant */
  6839. default_fontslant = DEFAULT_FONTSLANT;
  6840. /* check if node has a specified font weight */
  6841. default_fontweight = DEFAULT_FONTWEIGHT;
  6842. /* check if node has a specified font size */
  6843. default_fontsize = DEFAULT_FONTSIZE;
  6844. /* create the font name string */
  6845. snprintf(buf, (128 - 1), "%s %s %s %s %s", default_fontname,
  6846. default_fontslant, default_fontweight, default_fontcondensed, default_fontsize);
  6847. /* copy string buffer */
  6848. s = uniqstr(buf);
  6849. /* */
  6850. desc = pango_font_description_from_string(s);
  6851. /* */
  6852. pango_layout_set_font_description(layout, desc);
  6853. /* */
  6854. pango_font_description_free(desc);
  6855. /* */
  6856. pango_cairo_update_layout(crp, layout);
  6857. /* draw the text */
  6858. pango_cairo_show_layout(crp, layout);
  6859. /* */
  6860. cairo_stroke(crp);
  6861. g_object_unref(G_OBJECT(layout));
  6862. }
  6863. } else {
  6864. /* draw regular text */
  6865. /* fontcolor of node black default or color */
  6866. r = (nl->node->fontcolor & 0x00ff0000) >> 16;
  6867. g = (nl->node->fontcolor & 0x0000ff00) >> 8;
  6868. b = (nl->node->fontcolor & 0x000000ff);
  6869. /* draw in text color of node */
  6870. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  6871. xo = 2;
  6872. yo = 2;
  6873. /* set start position of text */
  6874. cairo_move_to(crp, nl->node->finx - vxmin + xo, nl->node->finy - vymin + yo);
  6875. layout = pango_cairo_create_layout(crp);
  6876. /* set the text to draw which is 0 terminated */
  6877. pango_layout_set_text(layout, nl->node->name, -1);
  6878. /* set font parameters */
  6879. /* create the fontname description */
  6880. memset(buf, 0, (size_t)128);
  6881. default_fontname = DEFAULT_FONTNAME;
  6882. /* check if node has a specified font slant */
  6883. default_fontslant = DEFAULT_FONTSLANT;
  6884. /* check if node has a specified font weight */
  6885. default_fontweight = DEFAULT_FONTWEIGHT;
  6886. /* check if node has a specified font size */
  6887. default_fontsize = DEFAULT_FONTSIZE;
  6888. /* create the font name string */
  6889. snprintf(buf, (128 - 1), "%s %s %s %s %s", default_fontname,
  6890. default_fontslant, default_fontweight, default_fontcondensed, default_fontsize);
  6891. /* copy string buffer */
  6892. s = uniqstr(buf);
  6893. /* */
  6894. desc = pango_font_description_from_string(s);
  6895. /* */
  6896. pango_layout_set_font_description(layout, desc);
  6897. /* */
  6898. pango_font_description_free(desc);
  6899. /* */
  6900. pango_cairo_update_layout(crp, layout);
  6901. /* draw the text */
  6902. pango_cairo_show_layout(crp, layout);
  6903. /* */
  6904. cairo_stroke(crp);
  6905. g_object_unref(G_OBJECT(layout));
  6906. }
  6907. }
  6908. nl = nl->next;
  6909. }
  6910. return;
  6911. }
  6912. /* real-to-dummy find edge conn. point */
  6913. static int r2d_finx(struct gml_edge *edge)
  6914. {
  6915. struct gml_node *sn = NULL;
  6916. struct gml_node *tn = NULL;
  6917. int ret = 0;
  6918. int i = 0;
  6919. sn = edge->from_node; /* from-node */
  6920. tn = edge->to_node; /* to-node */
  6921. if (tn) {
  6922. }
  6923. if (edge->vedge) {
  6924. ret = (sn->finx + (sn->bbx / 2));
  6925. return (ret);
  6926. }
  6927. if (sn->dx_oedges == 0) {
  6928. ret = (sn->finx + (sn->bbx / 2));
  6929. return (ret);
  6930. }
  6931. for (i = 0; i < sn->outdegree; i++) {
  6932. if (sn->oedges[i] == edge) {
  6933. break;
  6934. }
  6935. }
  6936. ret = (sn->finx + 5 + (i * sn->dx_oedges));
  6937. return (ret);
  6938. }
  6939. /* connection edge at real to-node */
  6940. static int d2r_tnx1(struct gml_edge *edge)
  6941. {
  6942. struct gml_node *sn = NULL;
  6943. struct gml_node *tn = NULL;
  6944. int ret = 0;
  6945. int i = 0;
  6946. sn = edge->from_node; /* from-node */
  6947. tn = edge->to_node; /* to-node */
  6948. if (sn) {
  6949. }
  6950. if (edge->vedge) {
  6951. ret = (tn->finx + (tn->bbx / 2));
  6952. return (ret);
  6953. }
  6954. if (tn->dx_iedges == 0) {
  6955. ret = (tn->finx + (tn->bbx / 2));
  6956. return (ret);
  6957. }
  6958. for (i = 0; i < tn->indegree; i++) {
  6959. if (tn->iedges[i] == edge) {
  6960. break;
  6961. }
  6962. }
  6963. ret = (tn->finx + 5 + (i * tn->dx_iedges));
  6964. return (ret);
  6965. }
  6966. /* nr. of pixels hor. edge goes downwards */
  6967. #define HEDGE_DY 10
  6968. /* draw dummy nodes in the drawing */
  6969. static void on_drawdummy(cairo_t * crp, int mode, int dx, int dy)
  6970. {
  6971. double radius = 3.0;
  6972. double x = (double)dx;
  6973. double y = (double)dy;
  6974. if (mode == 0) {
  6975. /* draw red filled rectangle size 5x5 pixels */
  6976. cairo_set_source_rgb(crp, 255 / 255.0, 0 / 255.0, 0 / 255.0);
  6977. cairo_rectangle(crp, x - 3, y - 3, 5, 5);
  6978. cairo_fill(crp);
  6979. } else if (mode == 1) {
  6980. /* draw orange circle not filled */
  6981. cairo_set_source_rgb(crp, 255 / 255.0, 140 / 255.0, 0 / 255.0);
  6982. /* 360 degree circle */
  6983. cairo_arc(crp, x, y, radius, 0.0, (double)(2 * M_PI));
  6984. } else if (mode == 2) {
  6985. /* draw fluor orange circle filled */
  6986. cairo_set_source_rgb(crp, 255 / 255.0, 191 / 255.0, 0 / 255.0);
  6987. /* 360 degree circle */
  6988. cairo_arc(crp, x, y, radius, 0.0, (double)(2 * M_PI));
  6989. cairo_fill(crp);
  6990. } else if (mode == 3) {
  6991. /* draw pale circle filled */
  6992. cairo_set_source_rgb(crp, 152 / 255.0, 251 / 255.0, 152 / 255.0);
  6993. /* 360 degree circle */
  6994. cairo_arc(crp, x, y, radius, 0.0, (double)(2 * M_PI));
  6995. cairo_fill(crp);
  6996. } else {
  6997. /* draw pink circle filled */
  6998. cairo_set_source_rgb(crp, 255 / 255.0, 105 / 255.0, 180 / 255.0);
  6999. /* 360 degree circle */
  7000. cairo_arc(crp, x, y, radius, 0.0, (double)(2 * M_PI));
  7001. cairo_fill(crp);
  7002. }
  7003. cairo_stroke(crp);
  7004. return;
  7005. }
  7006. /* draw all edges
  7007. * the barycenter gives node a relative (x,y) position in (x,y) and (relx,rely)
  7008. * the pos.c trnslates this in absolute (x,y) coordinates in (finx,finy)
  7009. * the virtual window top upper left corner is at (vxmin,vymin)
  7010. * the virtual window is moved using the sliders
  7011. * the zoom factor of the drawing is in (double) zfactor and used by cairo
  7012. * the node (x,y) size needed for the shape with the text is in (bbx,bby)
  7013. * the nodes are in vertical levels put in the middle of the level
  7014. * the top of the level of the node is in ly0
  7015. * the start of the top level of the node is in lx0
  7016. * the bottom of the level of the node is in ly1
  7017. * the start of the bottom level of the node is in lx2
  7018. * the dummy node has flag dummy set to 1
  7019. * the edge label node has flag elabel set to 1
  7020. * the horizontal edge has flag hedge set and must be routed differently
  7021. * the node has in nselfedges number of self edges at the node
  7022. * the drawing of self edges is extra part and creates other drawing problems
  7023. * the routing of edges is in graphviz really very complex
  7024. * this should also use a more complex solution for spline drawing
  7025. * the chaikin algorithm can be used to draw better spline edges
  7026. * this shuld be pre-calculated in the edge data also hor. edge routing to be added
  7027. */
  7028. static void on_top_level_window_drawingarea1_expose_event_edges(cairo_t * crp)
  7029. {
  7030. int r = 0;
  7031. int g = 0;
  7032. int b = 0;
  7033. int fnx1 = 0;
  7034. int fny1 = 0;
  7035. int tnx1 = 0;
  7036. int tny1 = 0;
  7037. struct gml_elist *el = NULL;
  7038. struct gml_edge *edge = NULL;
  7039. struct gml_node *sn = NULL;
  7040. struct gml_node *tn = NULL;
  7041. int ecolor = 0;
  7042. int dx15 = 0;
  7043. const double dashed[] = {
  7044. 14.0, 2.0 /* 6.0 */
  7045. };
  7046. int lendashed = sizeof(dashed) / sizeof(dashed[0]);
  7047. const double dotted[] = {
  7048. 1.0 /* 2.0, 6.0 */
  7049. };
  7050. int lendotted = sizeof(dotted) / sizeof(dotted[0]);
  7051. int px1 = 0;
  7052. int py1 = 0;
  7053. int px2 = 0;
  7054. int py2 = 0;
  7055. int test = 0; /* set to 1 for test */
  7056. el = maingraph->edgelist;
  7057. while (el) {
  7058. edge = el->edge;
  7059. sn = edge->from_node; /* from-node */
  7060. tn = edge->to_node; /* to-node */
  7061. ecolor = edge->ecolor; /* edge line color */
  7062. /* thickness of edge line */
  7063. cairo_set_line_width(crp, DEFAULT_EDGE_THICKNESS);
  7064. /* check edge line style */
  7065. if (edge->style == 1 /* ESTYLE_DASHED */ ) {
  7066. /* dashed edge line */
  7067. cairo_set_dash(crp, dashed, lendashed, 1);
  7068. } else if (edge->style == 2 /* ESTYLE_DOTTED */ ) {
  7069. /* dotted edge line */
  7070. cairo_set_dash(crp, dotted, lendotted, 0);
  7071. } else {
  7072. /* solid edge line */
  7073. cairo_set_dash(crp, dotted, 0, 0);
  7074. }
  7075. /* black or colored line */
  7076. r = (ecolor & 0x00ff0000) >> 16;
  7077. g = (ecolor & 0x0000ff00) >> 8;
  7078. b = (ecolor & 0x000000ff);
  7079. /* draw in line color of edge */
  7080. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7081. if (edge->hedge) {
  7082. /* horizontal edge has original endpoints */
  7083. /* center of from/to nodes */
  7084. fnx1 = (sn->finx + sn->bbx / 2) - vxmin;
  7085. tnx1 = (tn->finx + tn->bbx / 2) - vxmin;
  7086. if (tnx1 > fnx1) {
  7087. /* edge from left to right */
  7088. /* check if nodes are next to each other */
  7089. /* this should also check if to-node is a dummy or real node todo */
  7090. if ((sn->relx + 1) == tn->relx) {
  7091. /* printf ("direct-lr\n"); */
  7092. fnx1 = (sn->finx + sn->bbx) - vxmin;
  7093. fny1 = (sn->finy + sn->bby / 2) - vymin;
  7094. cairo_move_to(crp, fnx1, fny1);
  7095. cairo_line_to(crp, (tn->finx) - vxmin, (tn->finy + tn->bby / 2) - vymin);
  7096. /* add arrow */
  7097. if (edge->reversed == 0) {
  7098. drarrow(crp, fnx1, fny1, (tn->finx) - vxmin, (tn->finy + tn->bby / 2) - vymin, 0);
  7099. } else {
  7100. drarrow(crp, (tn->finx) - vxmin, (tn->finy + tn->bby / 2) - vymin, fnx1, fny1, 0);
  7101. }
  7102. } else {
  7103. /* distance length of hor. line / 5 */
  7104. dx15 = (tnx1 - fnx1) / 5;
  7105. /* optional draw hor. edges in a different color */
  7106. if (0) {
  7107. cairo_set_source_rgb(crp, 0 / 255.0, 0 / 255.0, 0xff / 255.0);
  7108. }
  7109. /* start line at center */
  7110. fnx1 = (sn->finx + sn->bbx / 2) - vxmin;
  7111. fny1 = (sn->finy + sn->bby) - vymin;
  7112. cairo_move_to(crp, fnx1, fny1);
  7113. if ((sn->finy + sn->bby) >= (tn->finy + tn->bby)) {
  7114. /* from node y is lower then target, put hor. line 10px lower */
  7115. cairo_line_to(crp, (fnx1 + dx15), ((sn->finy + sn->bby) + HEDGE_DY) - vymin);
  7116. cairo_line_to(crp, (fnx1 + dx15) + (3 * dx15), ((sn->finy + sn->bby) + HEDGE_DY) - vymin);
  7117. cairo_line_to(crp, (tn->finx + tn->bbx / 2) - vxmin, (tn->finy + tn->bby) - vymin);
  7118. /* add arrow */
  7119. if (edge->reversed == 0) {
  7120. drarrow(crp, (fnx1 + dx15) + (3 * dx15),
  7121. ((sn->finy + sn->bby) + HEDGE_DY) -
  7122. vymin, (tn->finx + tn->bbx / 2) - vxmin, (tn->finy + tn->bby) - vymin, 0);
  7123. } else {
  7124. if (0) { /*old */
  7125. drarrow(crp, (fnx1 + dx15), ((sn->finy + sn->bby) + HEDGE_DY) - vymin, fnx1, fny1, 0);
  7126. }
  7127. drarrow(crp,
  7128. (tn->finx + tn->bbx / 2) - vxmin,
  7129. (tn->finy + tn->bby) - vymin,
  7130. (fnx1 + dx15) + (3 * dx15), ((sn->finy + sn->bby) + HEDGE_DY) - vymin, 0);
  7131. }
  7132. } else {
  7133. /* from-node y is higher */
  7134. cairo_line_to(crp, (fnx1 + dx15), (tn->finy + tn->bby) + HEDGE_DY - vymin);
  7135. cairo_line_to(crp, (fnx1 + dx15) + (3 * dx15), ((tn->finy + tn->bby) + HEDGE_DY) - vymin);
  7136. cairo_line_to(crp, (tn->finx + tn->bbx / 2) - vxmin, (tn->finy + tn->bby) - vymin);
  7137. /* add arrow */
  7138. if (edge->reversed == 0) {
  7139. drarrow(crp, (fnx1 + dx15) + (3 * dx15),
  7140. ((tn->finy + tn->bby) + HEDGE_DY) -
  7141. vymin, (tn->finx + tn->bbx / 2) - vxmin, (tn->finy + tn->bby) - vymin, 0);
  7142. } else {
  7143. drarrow(crp, (fnx1 + dx15), (tn->finy + tn->bby) + HEDGE_DY - vymin, fnx1, fny1, 0);
  7144. }
  7145. }
  7146. }
  7147. } else {
  7148. /* edge from right to left fnx1>tnx1 */
  7149. if ((sn->relx) == (tn->relx + 1)) {
  7150. /* printf ("direct-rl\n"); */
  7151. cairo_move_to(crp, (sn->finx) - vxmin, (sn->finy + sn->bby / 2) - vymin);
  7152. cairo_line_to(crp, tn->finx + tn->bbx - vxmin, tn->finy + tn->bby / 2 - vymin);
  7153. /* add arrow */
  7154. if (edge->reversed == 0) {
  7155. drarrow(crp,
  7156. (sn->finx) - vxmin,
  7157. (sn->finy + sn->bby / 2) - vymin, tn->finx + tn->bbx - vxmin, tn->finy + tn->bby / 2 - vymin, 0);
  7158. } else {
  7159. drarrow(crp, tn->finx + tn->bbx - vxmin,
  7160. tn->finy + tn->bby / 2 - vymin, (sn->finx) - vxmin, (sn->finy + sn->bby / 2) - vymin, 0);
  7161. }
  7162. } else {
  7163. /* distance length of hor. line / 5 */
  7164. dx15 = (fnx1 - tnx1) / 5;
  7165. /* optional draw hor. edges in a different color */
  7166. if (0) {
  7167. cairo_set_source_rgb(crp, 0 / 255.0, 0 / 255.0, 0xff / 255.0);
  7168. }
  7169. /* start line at center */
  7170. fnx1 = (sn->finx + sn->bbx / 2) - vxmin;
  7171. fny1 = (sn->finy + sn->bby) - vymin;
  7172. cairo_move_to(crp, fnx1, fny1);
  7173. if ((sn->finy + sn->bby) >= (tn->finy + tn->bby)) {
  7174. /* from node y is lower then target, put hor. line 10px lower */
  7175. cairo_line_to(crp, (fnx1 - dx15), ((sn->finy + sn->bby) + HEDGE_DY) - vymin);
  7176. cairo_line_to(crp, (fnx1 - dx15) - (3 * dx15), ((sn->finy + sn->bby) + HEDGE_DY) - vymin);
  7177. cairo_line_to(crp, (tn->finx + tn->bbx / 2) - vxmin, (tn->finy + tn->bby) - vymin);
  7178. /* add arrow */
  7179. if (edge->reversed == 0) {
  7180. /* could be improved here todo */
  7181. drarrow(crp, (fnx1 - dx15) - (3 * dx15),
  7182. ((sn->finy + sn->bby) +
  7183. HEDGE_DY) - vymin, (tn->finx + tn->bbx / 2) - vxmin, (tn->finy + tn->bby) - vymin, 0);
  7184. } else {
  7185. drarrow(crp, (fnx1 - dx15), ((sn->finy + sn->bby) + HEDGE_DY) - vymin, fnx1, fny1, 0);
  7186. }
  7187. } else {
  7188. /* from-node y is higher */
  7189. cairo_line_to(crp, (fnx1 - dx15), (tn->finy + tn->bby) + HEDGE_DY - vymin);
  7190. cairo_line_to(crp, (fnx1 - dx15) - (3 * dx15), ((tn->finy + tn->bby) + HEDGE_DY) - vymin);
  7191. cairo_line_to(crp, (tn->finx + tn->bbx / 2) - vxmin, (tn->finy + tn->bby) - vymin);
  7192. /* add arrow */
  7193. if (edge->reversed == 0) {
  7194. /* this could be improved, todo */
  7195. drarrow(crp, (fnx1 - dx15) - (3 * dx15),
  7196. ((sn->finy + sn->bby) +
  7197. HEDGE_DY) - vymin, (tn->finx + tn->bbx / 2) - vxmin, (tn->finy + tn->bby) - vymin, 0);
  7198. } else {
  7199. drarrow(crp, (fnx1 - dx15), (tn->finy + tn->bby) + HEDGE_DY - vymin, fnx1, fny1, 0);
  7200. }
  7201. }
  7202. }
  7203. }
  7204. } else {
  7205. /* here if not a horizontal edge */
  7206. if (option_splines) {
  7207. /* drawing spline lines */
  7208. if (0) {
  7209. printf("%s(): edge `%s'->`%s' reversed=%d\n", __func__, sn->nlabel, tn->nlabel, edge->reversed);
  7210. }
  7211. if (sn->dummy == 0 && tn->dummy == 0) {
  7212. /* from real node to real node.
  7213. * real nodes are interleaved with dummy nodes
  7214. * this only does happen from real node to edge-label node
  7215. */
  7216. /* from point at bottom of node */
  7217. fnx1 = (sn->finx + sn->bbx / 2) - vxmin;
  7218. fny1 = (sn->finy + sn->bby) - vymin;
  7219. cairo_move_to(crp, (double)fnx1, (double)fny1);
  7220. /* to point at top of node */
  7221. tnx1 = (tn->finx + tn->bbx / 2) - vxmin;
  7222. tny1 = (tn->finy) - vymin;
  7223. cairo_line_to(crp, (double)tnx1, (double)tny1);
  7224. /* optional draw dummy node */
  7225. if (option_drawdummy) {
  7226. /* light baby pink */
  7227. cairo_set_source_rgb(crp, 245 / 255.0, 195 / 255.0, 194 / 255.0);
  7228. cairo_move_to(crp, (double)(fnx1 + 2), (double)fny1);
  7229. cairo_line_to(crp, (double)(tnx1 + 2), (double)tny1);
  7230. cairo_stroke(crp);
  7231. on_drawdummy(crp, 0 /* red rectangle */ , (double)fnx1, (double)fny1);
  7232. on_drawdummy(crp, 0 /* red rectangle */ , (double)tnx1, (double)tny1);
  7233. /* draw in line color of edge */
  7234. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7235. }
  7236. /* add arrow */
  7237. if (edge->reversed == 0) {
  7238. drarrow(crp, fnx1, fny1, tnx1, tny1, 0);
  7239. } else {
  7240. drarrow(crp, tnx1, tny1, fnx1, fny1, 0);
  7241. }
  7242. } else if (sn->dummy == 1 && tn->dummy == 0) {
  7243. /* from dummy node to real node */
  7244. fnx1 = sn->finx - vxmin;
  7245. fny1 = sn->finy - vymin;
  7246. tnx1 = d2r_tnx1(edge) - vxmin;
  7247. tny1 = tn->finy - vymin;
  7248. /* draw in line color of edge */
  7249. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7250. if (0) { /* straight lines */
  7251. cairo_move_to(crp, fnx1, fny1);
  7252. cairo_line_to(crp, fnx1, fny1 + (sn->bby / 2));
  7253. cairo_line_to(crp, tnx1, (tn->ly0 - vymin));
  7254. cairo_line_to(crp, tnx1, tny1);
  7255. } else {
  7256. /* temp fixed */
  7257. cairo_move_to(crp, (double)fnx1, (double)fny1);
  7258. px1 = fnx1;
  7259. py1 = fny1 + (sn->bby / 2);
  7260. px2 = tnx1;
  7261. py2 = (tn->ly0 - vymin);
  7262. cairo_curve_to(crp, (double)fnx1, (double)fny1, px1, py1, px2, py2);
  7263. cairo_line_to(crp, (double)tnx1, (double)tny1);
  7264. cairo_stroke(crp);
  7265. }
  7266. /* optional draw dummy node */
  7267. if (option_drawdummy) {
  7268. /* light red */
  7269. cairo_set_source_rgb(crp, 255 / 255.0, 204 / 255.0, 203 / 255.0);
  7270. /* +2 to put the colored line next to the original line */
  7271. cairo_move_to(crp, (double)(fnx1 + 2), (double)fny1);
  7272. cairo_line_to(crp, px1, py1);
  7273. cairo_line_to(crp, px2, py2);
  7274. cairo_line_to(crp, (double)(tnx1 + 2), (double)tny1);
  7275. cairo_stroke(crp);
  7276. on_drawdummy(crp, 0 /* red rectangle */ , (double)fnx1, (double)fny1);
  7277. on_drawdummy(crp, 0 /* red rectangle */ , (double)tnx1, (double)tny1);
  7278. on_drawdummy(crp, 1, px1, py1);
  7279. on_drawdummy(crp, 1, px2, py2);
  7280. /* draw in line color of edge */
  7281. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7282. }
  7283. /* add arrow */
  7284. if (edge->reversed == 0) {
  7285. drarrow(crp, fnx1, fny1, tnx1, tny1, 0);
  7286. } else {
  7287. /* no arrow */
  7288. }
  7289. cairo_stroke(crp);
  7290. } else if (sn->dummy == 0 && tn->dummy == 1) {
  7291. /* from real node to dummy node */
  7292. fnx1 = r2d_finx(edge) - vxmin;
  7293. fny1 = (sn->finy + sn->bby) - vymin;
  7294. tnx1 = tn->finx - vxmin;
  7295. tny1 = tn->finy - vymin;
  7296. /* draw in line color of edge */
  7297. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7298. /* optional draw dummy node */
  7299. if (option_drawdummy) {
  7300. cairo_set_source_rgb(crp, 255 / 255.0, 0 / 255.0, 0 / 255.0);
  7301. cairo_rectangle(crp, tnx1 - 1, tny1 - 1, 3, 3);
  7302. cairo_fill(crp);
  7303. /* draw in line color of edge */
  7304. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7305. }
  7306. if (0) { /* straight */
  7307. cairo_move_to(crp, fnx1, fny1);
  7308. cairo_line_to(crp, fnx1, (sn->ly1 - vymin));
  7309. cairo_line_to(crp, tnx1, tny1 - (tn->bby / 2));
  7310. cairo_line_to(crp, tnx1, tny1);
  7311. } else {
  7312. /* fixed */
  7313. cairo_move_to(crp, (double)fnx1, (double)fny1);
  7314. /* todo p1 p2 points */
  7315. px1 = fnx1;
  7316. py1 = (sn->ly1 - vymin);
  7317. px2 = tnx1;
  7318. py2 = tny1 - (tn->bby / 2);
  7319. cairo_curve_to(crp, px1, py1, px2, py2, (double)tnx1, (double)tny1);
  7320. cairo_stroke(crp);
  7321. }
  7322. /* optional draw dummy node */
  7323. if (option_drawdummy) {
  7324. /* peach puff light orange */
  7325. cairo_set_source_rgb(crp, 255 / 255.0, 218 / 255.0, 185 / 255.0);
  7326. cairo_move_to(crp, (double)(fnx1 + 2), (double)fny1);
  7327. cairo_line_to(crp, px1, py1);
  7328. cairo_line_to(crp, px2, py2);
  7329. cairo_line_to(crp, (double)(tnx1 + 2), (double)tny1);
  7330. cairo_stroke(crp);
  7331. on_drawdummy(crp, 0 /* red rectangle */ , (double)fnx1, (double)fny1);
  7332. on_drawdummy(crp, 0 /* red rectangle */ , (double)tnx1, (double)tny1);
  7333. on_drawdummy(crp, 2, px1, py1);
  7334. on_drawdummy(crp, 2, px2, py2);
  7335. /* draw in line color of edge */
  7336. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7337. }
  7338. /* add arrow */
  7339. if (edge->reversed == 0) {
  7340. /* no arrow */
  7341. } else {
  7342. drarrow(crp, tnx1, tny1, fnx1, fny1, 0);
  7343. }
  7344. cairo_stroke(crp);
  7345. } else {
  7346. /* from dummy node to dummy node */
  7347. fnx1 = sn->finx - vxmin;
  7348. fny1 = sn->finy - vymin;
  7349. tnx1 = tn->finx - vxmin;
  7350. tny1 = tn->finy - vymin;
  7351. /* draw in line color of edge */
  7352. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7353. if (test || 0) { /* straight */
  7354. cairo_move_to(crp, fnx1, fny1);
  7355. cairo_line_to(crp, fnx1, fny1 + (sn->bby / 2));
  7356. cairo_line_to(crp, tnx1, (tn->ly0 - vymin));
  7357. cairo_line_to(crp, tnx1, tny1 - (tn->bby / 2));
  7358. cairo_line_to(crp, tnx1, tny1);
  7359. } else {
  7360. cairo_move_to(crp, fnx1, fny1);
  7361. cairo_line_to(crp, fnx1, fny1 + (sn->bby / 2));
  7362. cairo_stroke(crp);
  7363. /* also possible px1 = (((fnx1 * 2) + tnx1) / 3); px2 = ((fnx1 + (tnx1 * 2)) / 3); */
  7364. cairo_move_to(crp, fnx1, fny1 + (sn->bby / 2));
  7365. cairo_curve_to(crp, tnx1, (tn->ly0 - vymin), tnx1, tny1 - (tn->bby / 2), tnx1, tny1);
  7366. px1 = tnx1;
  7367. py1 = (tn->ly0 - vymin);
  7368. px2 = tnx1;
  7369. py2 = tny1 - (tn->bby / 2);
  7370. cairo_stroke(crp);
  7371. }
  7372. /* optional draw dummy node */
  7373. if (option_drawdummy) {
  7374. /* light green */
  7375. cairo_set_source_rgb(crp, 173 / 255.0, 255 / 255.0, 47 / 255.0);
  7376. cairo_move_to(crp, (double)(fnx1 + 2), (double)fny1);
  7377. cairo_line_to(crp, (double)(fnx1 + 2), (double)(fny1 + (sn->bby / 2)));
  7378. cairo_line_to(crp, px1, py1);
  7379. cairo_line_to(crp, px2, py2);
  7380. cairo_line_to(crp, (double)(tnx1 + 2), (double)tny1);
  7381. cairo_stroke(crp);
  7382. on_drawdummy(crp, 0 /* red rectangle */ , (double)fnx1, (double)fny1);
  7383. on_drawdummy(crp, 0 /* red rectangle */ , (double)tnx1, (double)tny1);
  7384. on_drawdummy(crp, 3, px1, py1);
  7385. on_drawdummy(crp, 3, px2, py2);
  7386. /* draw in line color of edge */
  7387. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7388. }
  7389. /* no real nodes, no arrows, optional draw arrows at dummy nodes, see tuxsee */
  7390. }
  7391. } else {
  7392. /* drawing not-spline lines */
  7393. if (sn->dummy == 0 && tn->dummy == 0) {
  7394. /* from real node to real node.
  7395. * real nodes are interleaved with dummy nodes
  7396. * this does happen from real node to edge-label node
  7397. */
  7398. /* from real node to real node */
  7399. fnx1 = sn->finx + sn->bbx / 2 - vxmin;
  7400. fny1 = sn->finy + sn->bby - vymin;
  7401. cairo_move_to(crp, fnx1, fny1);
  7402. tnx1 = tn->finx + tn->bbx / 2 - vxmin;
  7403. tny1 = tn->finy - vymin;
  7404. cairo_line_to(crp, tnx1, tny1);
  7405. /* add arrow */
  7406. if (edge->reversed == 0) {
  7407. drarrow(crp, fnx1, fny1, tnx1, tny1, 0);
  7408. } else {
  7409. drarrow(crp, tnx1, tny1, fnx1, fny1, 0);
  7410. }
  7411. } else if (sn->dummy == 1 && tn->dummy == 0) {
  7412. /* from dummy node to real node */
  7413. fnx1 = sn->finx - vxmin;
  7414. fny1 = sn->finy - vymin;
  7415. tnx1 = d2r_tnx1(edge) - vxmin;
  7416. tny1 = tn->finy - vymin;
  7417. /* optional draw dummy node */
  7418. if (option_drawdummy) {
  7419. cairo_set_source_rgb(crp, 255 / 255.0, 0 / 255.0, 0 / 255.0);
  7420. cairo_rectangle(crp, fnx1 - 1, fny1 - 1, 3, 3);
  7421. cairo_fill(crp);
  7422. /* draw in line color of edge */
  7423. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7424. }
  7425. cairo_move_to(crp, fnx1, fny1);
  7426. cairo_line_to(crp, fnx1, fny1 + (sn->bby / 2));
  7427. cairo_line_to(crp, tnx1, (tn->ly0 - vymin));
  7428. cairo_line_to(crp, tnx1, tny1);
  7429. /* add arrow */
  7430. if (edge->reversed == 0) {
  7431. drarrow(crp, fnx1, fny1, tnx1, tny1, 0);
  7432. } else {
  7433. /* no arrow */
  7434. }
  7435. } else if (sn->dummy == 0 && tn->dummy == 1) {
  7436. /* from real node to dummy node */
  7437. fnx1 = r2d_finx(edge) - vxmin;
  7438. fny1 = (sn->finy + sn->bby) - vymin;
  7439. tnx1 = tn->finx - vxmin;
  7440. tny1 = tn->finy - vymin;
  7441. /* optional draw dummy node */
  7442. if (option_drawdummy) {
  7443. cairo_set_source_rgb(crp, 255 / 255.0, 0 / 255.0, 0 / 255.0);
  7444. cairo_rectangle(crp, tnx1 - 1, tny1 - 1, 3, 3);
  7445. cairo_fill(crp);
  7446. /* draw in line color of edge */
  7447. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7448. }
  7449. cairo_move_to(crp, fnx1, fny1);
  7450. cairo_line_to(crp, fnx1, (sn->ly1 - vymin));
  7451. cairo_line_to(crp, tnx1, tny1 - (tn->bby / 2));
  7452. cairo_line_to(crp, tnx1, tny1);
  7453. /* add arrow */
  7454. if (edge->reversed == 0) {
  7455. /* no arrow */
  7456. } else {
  7457. drarrow(crp, tnx1, tny1, fnx1, fny1, 0);
  7458. }
  7459. } else {
  7460. /* from dummy node to dummy node */
  7461. fnx1 = sn->finx - vxmin;
  7462. fny1 = sn->finy - vymin;
  7463. tnx1 = tn->finx - vxmin;
  7464. tny1 = tn->finy - vymin;
  7465. /* optional draw dummy node */
  7466. if (option_drawdummy) {
  7467. cairo_set_source_rgb(crp, 255 / 255.0, 0 / 255.0, 0 / 255.0);
  7468. cairo_rectangle(crp, fnx1 - 2, fny1 - 2, 5, 5);
  7469. cairo_fill(crp);
  7470. cairo_rectangle(crp, tnx1 - 2, tny1 - 2, 5, 5);
  7471. cairo_fill(crp);
  7472. /* draw in line color of edge */
  7473. cairo_set_source_rgb(crp, r / 255.0, g / 255.0, b / 255.0);
  7474. }
  7475. cairo_move_to(crp, fnx1, fny1);
  7476. cairo_line_to(crp, fnx1, fny1 + (sn->bby / 2));
  7477. cairo_line_to(crp, tnx1, (tn->ly0 - vymin));
  7478. cairo_line_to(crp, tnx1, tny1 - (tn->bby / 2));
  7479. cairo_line_to(crp, tnx1, tny1);
  7480. /* no arrow draw because there are no real nodes */
  7481. }
  7482. /* put the lines on screen */
  7483. cairo_stroke(crp);
  7484. }
  7485. }
  7486. cairo_stroke(crp);
  7487. el = el->next;
  7488. }
  7489. return;
  7490. }
  7491. #if (GTK_HAVE_API_VERSION_2 == 1)
  7492. /* redraw drawing area */
  7493. static gboolean on_top_level_window_drawingarea1_expose_event(GtkWidget * widget, GdkEventExpose * event, gpointer user_data)
  7494. {
  7495. cairo_t *crdraw = NULL;
  7496. gint w = 0; /* xsize of drawing area */
  7497. gint h = 0; /* ysize of drawing area */
  7498. int fit = 0;
  7499. if (widget) {
  7500. }
  7501. if (event == NULL) {
  7502. return (FALSE);
  7503. }
  7504. if (user_data) {
  7505. }
  7506. /* only at first expose */
  7507. if (drawing_area_xsize == 0 && drawing_area_ysize == 0) {
  7508. fit = 1;
  7509. } else {
  7510. fit = 0;
  7511. }
  7512. if (fit) {
  7513. }
  7514. /* get cairo drawing context */
  7515. crdraw = gdk_cairo_create(event->window);
  7516. /* how large drawing area is */
  7517. (void)gdk_drawable_get_size(event->window, &w, &h);
  7518. if (option_gdebug > 1 || 0) {
  7519. printf("%s(): drawing area size is (%d,%d)\n", __func__, w, h);
  7520. fflush(stdout);
  7521. }
  7522. /* save a copy of current size */
  7523. drawing_area_xsize = w;
  7524. drawing_area_ysize = h;
  7525. /* check if there is node data to draw */
  7526. if (validdata == 0) {
  7527. /* white fill drawing area */
  7528. cairo_set_source_rgb(crdraw, altr / 255.0, altg / 255.0, altb / 255.0);
  7529. cairo_rectangle(crdraw, 0, 0, w, h);
  7530. cairo_fill(crdraw);
  7531. cairo_stroke(crdraw);
  7532. cairo_destroy(crdraw);
  7533. /* no data */
  7534. return (FALSE);
  7535. }
  7536. cairo_set_source_rgb(crdraw, bgcr / 255.0, bgcg / 255.0, bgcb / 255.0);
  7537. /* select whole screen to fill with background color */
  7538. cairo_rectangle(crdraw, 0, 0, w, h);
  7539. cairo_fill(crdraw);
  7540. cairo_stroke(crdraw);
  7541. /* use zoom slider drawing scale */
  7542. cairo_scale(crdraw, zfactor, zfactor);
  7543. on_top_level_window_drawingarea1_expose_event_nodes(crdraw);
  7544. on_top_level_window_drawingarea1_expose_event_edges(crdraw);
  7545. /* ready drawing */
  7546. cairo_destroy(crdraw);
  7547. return (FALSE);
  7548. }
  7549. #endif
  7550. #if (GTK_HAVE_API_VERSION_4 == 1)
  7551. /* draw on screen */
  7552. static void draw_function_for_gtk4(GtkDrawingArea * area, cairo_t * crdraw, int width, int height, gpointer user_data)
  7553. {
  7554. if (area) {
  7555. }
  7556. if (user_data) {
  7557. }
  7558. if (option_gdebug > 1 || 0) {
  7559. printf("%s(): drawing area size is (%d,%d)\n", __func__, width, height);
  7560. fflush(stdout);
  7561. }
  7562. /* save a copy of current size */
  7563. drawing_area_xsize = width;
  7564. drawing_area_ysize = height;
  7565. /* check if there is node data to draw */
  7566. if (validdata == 0) {
  7567. /* fill drawing area with a light-grey color */
  7568. cairo_set_source_rgb(crdraw, altr / 255.0, altg / 255.0, altb / 255.0);
  7569. cairo_rectangle(crdraw, 0, 0, drawing_area_xsize, drawing_area_ysize);
  7570. cairo_fill(crdraw);
  7571. cairo_stroke(crdraw);
  7572. /* no cairo_destroy(crdraw); needed */
  7573. /* no data */
  7574. return;
  7575. }
  7576. /* set current background color parsed from graph data */
  7577. cairo_set_source_rgb(crdraw, bgcr / 255.0, bgcg / 255.0, bgcb / 255.0);
  7578. /* select whole screen to fill with background color */
  7579. cairo_rectangle(crdraw, 0, 0, drawing_area_xsize, drawing_area_ysize);
  7580. cairo_fill(crdraw);
  7581. cairo_stroke(crdraw);
  7582. /* use zoom slider drawing scale */
  7583. cairo_scale(crdraw, zfactor, zfactor);
  7584. on_top_level_window_drawingarea1_expose_event_nodes(crdraw);
  7585. on_top_level_window_drawingarea1_expose_event_edges(crdraw);
  7586. /* no cairo_destroy(crdraw); needed */
  7587. return;
  7588. }
  7589. #endif
  7590. #if (GTK_HAVE_API_VERSION_3 == 1)
  7591. /* redraw drawing area */
  7592. static gboolean on_top_level_window_drawingarea1_draw_event(GtkWidget * widget, cairo_t * crdraw, gpointer user_data)
  7593. {
  7594. gint w = 0; /* xsize of drawing area */
  7595. gint h = 0; /* ysize of drawing area */
  7596. cairo_t *crp = NULL;
  7597. if (widget) {
  7598. }
  7599. if (user_data) {
  7600. }
  7601. /* this is a workaround for issue in cairo-lib 1.14.0 with gtk3,
  7602. * cairo.c cairo_destroy() line 305 assert(), (with gtk2 no problem) */
  7603. crp = cairo_reference(crdraw);
  7604. /* how large drawing area is */
  7605. w = gtk_widget_get_allocated_width(drawingarea1);
  7606. h = gtk_widget_get_allocated_height(drawingarea1);
  7607. if (option_gdebug > 1) {
  7608. printf("%s(): drawing area size is (%d,%d)\n", __func__, w, h);
  7609. fflush(stdout);
  7610. }
  7611. /* save a copy of current size */
  7612. drawing_area_xsize = w;
  7613. drawing_area_ysize = h;
  7614. /* check if there is node data to draw */
  7615. if (validdata == 0) {
  7616. /* white fill drawing area */
  7617. cairo_set_source_rgb(crdraw, altr / 255.0, altg / 255.0, altb / 255.0);
  7618. cairo_rectangle(crdraw, 0, 0, w, h);
  7619. cairo_fill(crdraw);
  7620. cairo_stroke(crdraw);
  7621. cairo_destroy(crdraw);
  7622. /* no data */
  7623. return (FALSE);
  7624. }
  7625. cairo_set_source_rgb(crdraw, bgcr / 255.0, bgcg / 255.0, bgcb / 255.0);
  7626. /* select whole screen to fill with background color */
  7627. cairo_rectangle(crdraw, 0, 0, w, h);
  7628. cairo_fill(crdraw);
  7629. cairo_stroke(crdraw);
  7630. /* use zoom slider drawing scale */
  7631. cairo_scale(crdraw, zfactor, zfactor);
  7632. on_top_level_window_drawingarea1_expose_event_nodes(crdraw);
  7633. on_top_level_window_drawingarea1_expose_event_edges(crdraw);
  7634. cairo_destroy(crp);
  7635. return (FALSE);
  7636. }
  7637. #endif
  7638. /* update status text */
  7639. static void update_status_text(char *text)
  7640. {
  7641. /* update status text line */
  7642. memset(charentry1buffer, 0, (size_t)64);
  7643. /* */
  7644. if (text) {
  7645. snprintf(charentry1buffer, (size_t)(64 - 1), "%s", text);
  7646. if (option_gdebug > 1 || 0) {
  7647. printf("%s(): %s\n", __func__, text);
  7648. fflush(stdout);
  7649. }
  7650. } else {
  7651. if (maingraph) {
  7652. /* some info about the graph, based on parsed data */
  7653. snprintf(charentry1buffer, (64 - 1),
  7654. "%d nodes, %d edges, %d crossings, size (%d,%d)",
  7655. maingraph->tnnodes, maingraph->tnedges, maingraph->sugi_fcrossings, maxx, maxy);
  7656. } else {
  7657. snprintf(charentry1buffer, 64 - 1, "no message");
  7658. }
  7659. }
  7660. /* when running in console mode there is no entry1buffer */
  7661. if (entry1buffer) {
  7662. gtk_text_buffer_set_text(entry1buffer, charentry1buffer, -1);
  7663. /* it is visible in the gui */
  7664. /* only a re-draw needed */
  7665. gtk_widget_queue_draw(drawingarea1);
  7666. }
  7667. return;
  7668. }
  7669. /* */
  7670. void update_status_text_cross(char *text)
  7671. {
  7672. /* does not work as expected */
  7673. return;
  7674. update_status_text(text);
  7675. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7676. while (gtk_main_iteration()) {
  7677. /* this should update the status text */ ;
  7678. }
  7679. #endif
  7680. return;
  7681. }
  7682. /* checkbox 1 is 'splines' */
  7683. static void check1_toggle(GtkWidget * widget, gpointer arg)
  7684. {
  7685. gboolean status = FALSE;
  7686. if (widget) {
  7687. }
  7688. if (arg) {
  7689. }
  7690. /* toggle the splines option */
  7691. #if (GTK_HAVE_API_VERSION_4 == 1)
  7692. status = gtk_check_button_get_active(GTK_CHECK_BUTTON(widget));
  7693. #endif
  7694. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7695. status = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  7696. #endif
  7697. if (status == TRUE) {
  7698. option_splines = 1;
  7699. } else {
  7700. option_splines = 0;
  7701. }
  7702. /* only a re-draw needed */
  7703. gtk_widget_queue_draw(drawingarea1);
  7704. return;
  7705. }
  7706. /* checkbox 2 is 'dummy's' draw dummy nodes */
  7707. static void dummy1_toggle(GtkWidget * widget, gpointer window)
  7708. {
  7709. gboolean status = FALSE;
  7710. if (widget) {
  7711. }
  7712. if (window) {
  7713. }
  7714. /* toggle the splines option */
  7715. #if (GTK_HAVE_API_VERSION_4 == 1)
  7716. status = gtk_check_button_get_active(GTK_CHECK_BUTTON(widget));
  7717. #endif
  7718. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7719. status = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  7720. #endif
  7721. if (status == TRUE) {
  7722. option_drawdummy = 1;
  7723. } else {
  7724. option_drawdummy = 0;
  7725. }
  7726. /* only a re-draw needed */
  7727. gtk_widget_queue_draw(drawingarea1);
  7728. return;
  7729. }
  7730. /* checkbox 5 is switch edge labels */
  7731. static void elabel1_toggle(GtkWidget * widget, gpointer window)
  7732. {
  7733. gboolean status = FALSE;
  7734. if (widget) {
  7735. }
  7736. if (window) {
  7737. }
  7738. /* when no labels do not draw edge labels */
  7739. if (option_labels == 0) {
  7740. return;
  7741. }
  7742. #if (GTK_HAVE_API_VERSION_4 == 1)
  7743. status = gtk_check_button_get_active(GTK_CHECK_BUTTON(widget));
  7744. #endif
  7745. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7746. status = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  7747. #endif
  7748. /* toggle the splines option */
  7749. if (status == TRUE) {
  7750. option_edgelabels = 1;
  7751. } else {
  7752. option_edgelabels = 0;
  7753. }
  7754. /* nop if no data */
  7755. if (validdata == 0) {
  7756. return;
  7757. }
  7758. /* if no edgelabels, skip */
  7759. if (maingraph->tnedgelabels == 0) {
  7760. return;
  7761. }
  7762. /* do re-layout */
  7763. do_relayout_all(maingraph);
  7764. /* now a re-draw needed */
  7765. gtk_widget_queue_draw(drawingarea1);
  7766. return;
  7767. }
  7768. /* checkbox 6 is switch labels */
  7769. static void label1_toggle(GtkWidget * widget, gpointer window)
  7770. {
  7771. gboolean status = FALSE;
  7772. if (widget) {
  7773. }
  7774. if (window) {
  7775. }
  7776. #if (GTK_HAVE_API_VERSION_4 == 1)
  7777. status = gtk_check_button_get_active(GTK_CHECK_BUTTON(widget));
  7778. #endif
  7779. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7780. status = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  7781. #endif
  7782. /* toggle the splines option */
  7783. if (status == TRUE) {
  7784. option_labels = 1;
  7785. } else {
  7786. option_labels = 0;
  7787. }
  7788. /* nop if no data */
  7789. if (validdata == 0) {
  7790. return;
  7791. }
  7792. /* force edgelabels off */
  7793. option_edgelabels = 0;
  7794. #if (GTK_HAVE_API_VERSION_4 == 1)
  7795. gtk_check_button_set_active(GTK_CHECK_BUTTON(elabel1), FALSE);
  7796. #endif
  7797. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7798. gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(elabel1), FALSE);
  7799. #endif
  7800. /* do re-layout */
  7801. do_relayout_all(maingraph);
  7802. /* now a re-draw needed */
  7803. gtk_widget_queue_draw(drawingarea1);
  7804. return;
  7805. }
  7806. /* checkbox 7 is node names instead of labels */
  7807. static void nnames1_toggle(GtkWidget * widget, gpointer window)
  7808. {
  7809. gboolean status = FALSE;
  7810. if (widget) {
  7811. }
  7812. if (window) {
  7813. }
  7814. #if (GTK_HAVE_API_VERSION_4 == 1)
  7815. status = gtk_check_button_get_active(GTK_CHECK_BUTTON(widget));
  7816. #endif
  7817. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7818. status = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  7819. #endif
  7820. /* toggle the splines option */
  7821. if (status == TRUE) {
  7822. option_nnames = 1;
  7823. } else {
  7824. option_nnames = 0;
  7825. }
  7826. /* nop if no data */
  7827. if (validdata == 0) {
  7828. return;
  7829. }
  7830. /* do re-layout */
  7831. do_relayout_all(maingraph);
  7832. /* now a re-draw needed */
  7833. gtk_widget_queue_draw(drawingarea1);
  7834. return;
  7835. }
  7836. /* checkbox 8 is mirror in y direction */
  7837. static void mirrory1_toggle(GtkWidget * widget, gpointer window)
  7838. {
  7839. gboolean status = FALSE;
  7840. if (widget) {
  7841. }
  7842. if (window) {
  7843. }
  7844. #if (GTK_HAVE_API_VERSION_4 == 1)
  7845. status = gtk_check_button_get_active(GTK_CHECK_BUTTON(widget));
  7846. #endif
  7847. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7848. status = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  7849. #endif
  7850. /* toggle the splines option */
  7851. if (status == TRUE) {
  7852. option_mirrory = 1;
  7853. } else {
  7854. option_mirrory = 0;
  7855. }
  7856. /* nop if no data */
  7857. if (validdata == 0) {
  7858. return;
  7859. }
  7860. /* force postype */
  7861. postype = 1;
  7862. /* set the value for the new pos type */
  7863. gtk_spin_button_set_value((GtkSpinButton *) posbutton, postype);
  7864. /* do re-layout */
  7865. do_relayout_all(maingraph);
  7866. /* now a re-draw needed */
  7867. gtk_widget_queue_draw(drawingarea1);
  7868. return;
  7869. }
  7870. /* checkbox 7 is switch popup labels */
  7871. static void popup1_toggle(GtkWidget * widget, gpointer window)
  7872. {
  7873. gboolean status = FALSE;
  7874. if (widget) {
  7875. }
  7876. if (window) {
  7877. }
  7878. #if (GTK_HAVE_API_VERSION_4 == 1)
  7879. status = gtk_check_button_get_active(GTK_CHECK_BUTTON(widget));
  7880. #endif
  7881. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7882. status = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
  7883. #endif
  7884. /* toggle the splines option */
  7885. if (status == TRUE) {
  7886. option_popup = 1;
  7887. } else {
  7888. option_popup = 0;
  7889. }
  7890. /* nop if no data */
  7891. if (validdata == 0) {
  7892. return;
  7893. }
  7894. /* no redraw needed */
  7895. return;
  7896. }
  7897. /* changed type */
  7898. static void pos_changed(GtkWidget * widget, gpointer spinbutton)
  7899. {
  7900. #if (GTK_HAVE_API_VERSION_4 == 1)
  7901. GtkSpinButton *spin = NULL;
  7902. #endif
  7903. gfloat val = 0.0;
  7904. if (widget) {
  7905. }
  7906. if (spinbutton) {
  7907. }
  7908. /* check if there is node data to draw */
  7909. if (validdata == 0) {
  7910. return;
  7911. }
  7912. /* at mirrory option force to keep postype 1 because type 2 does not work anymore. */
  7913. if (option_mirrory) {
  7914. /* message why pos value does not changes */
  7915. printf("%s(): because mirror option is active pos mode is fixed to 1 or turn off mirror option\n", __func__);
  7916. fflush(stdout);
  7917. postype = 1;
  7918. #if (GTK_HAVE_API_VERSION_4 == 1)
  7919. spin = GTK_SPIN_BUTTON(widget);
  7920. gtk_spin_button_set_value(spin, postype);
  7921. #endif
  7922. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7923. /* set the value for the new pos type */
  7924. gtk_spin_button_set_value((GtkSpinButton *) posbutton, postype);
  7925. #endif
  7926. return;
  7927. }
  7928. #if (GTK_HAVE_API_VERSION_4 == 1)
  7929. spin = GTK_SPIN_BUTTON(widget);
  7930. val = gtk_spin_button_get_value(spin);
  7931. #endif
  7932. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7933. /* get the value for the new pos type */
  7934. val = gtk_spin_button_get_value((GtkSpinButton *) spinbutton);
  7935. #endif
  7936. /* set new pos type, 1,2,3,4 */
  7937. postype = (int)val;
  7938. if (1) {
  7939. /* temp complete layout to make sure draw points are correct but can be replaced with below */
  7940. /* do re-layout */
  7941. do_relayout_all(maingraph);
  7942. }
  7943. /* todo to implement below otherwise draw control points are not correct */
  7944. if (0) {
  7945. /* re-calc positions */
  7946. improve_positions(maingraph);
  7947. /* final (x,y) positioning of nodes/edges */
  7948. finalxy(maingraph);
  7949. /* calculate edge connections */
  7950. edgeconnections(maingraph);
  7951. /* update sub parts of drawing */
  7952. positionz(maingraph);
  7953. /* update status text */
  7954. update_status_text(NULL);
  7955. }
  7956. /* only a re-draw needed */
  7957. gtk_widget_queue_draw(drawingarea1);
  7958. return;
  7959. }
  7960. /* stretch in x direction */
  7961. static void xspin_changed(GtkWidget * widget, gpointer spinbutton)
  7962. {
  7963. #if (GTK_HAVE_API_VERSION_4 == 1)
  7964. GtkSpinButton *spin = NULL;
  7965. #endif
  7966. gfloat val = 0.0;
  7967. if (widget) {
  7968. }
  7969. if (spinbutton) {
  7970. }
  7971. #if (GTK_HAVE_API_VERSION_4 == 1)
  7972. spin = GTK_SPIN_BUTTON(widget);
  7973. val = gtk_spin_button_get_value(spin);
  7974. #endif
  7975. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  7976. /* get the value for the new drawing spreading factor */
  7977. val = gtk_spin_button_get_value((GtkSpinButton *) spinbutton);
  7978. #endif
  7979. /* set new spreading factor */
  7980. xspacing = (int)val;
  7981. /* check if there is node data to draw */
  7982. if (validdata == 0) {
  7983. return;
  7984. }
  7985. /* re-calc positions */
  7986. improve_positions(maingraph);
  7987. /* final (x,y) positioning of nodes/edges */
  7988. finalxy(maingraph);
  7989. /* calculate edge connections */
  7990. edgeconnections(maingraph);
  7991. /* update sub parts of drawing */
  7992. positionz(maingraph);
  7993. /* update status text */
  7994. update_status_text(NULL);
  7995. /* only a re-draw needed */
  7996. gtk_widget_queue_draw(drawingarea1);
  7997. return;
  7998. }
  7999. static void yspin_changed(GtkWidget * widget, gpointer spinbutton)
  8000. {
  8001. #if (GTK_HAVE_API_VERSION_4 == 1)
  8002. GtkSpinButton *spin = NULL;
  8003. #endif
  8004. gfloat val = 0.0;
  8005. if (widget) {
  8006. }
  8007. if (spinbutton) {
  8008. }
  8009. #if (GTK_HAVE_API_VERSION_4 == 1)
  8010. spin = GTK_SPIN_BUTTON(widget);
  8011. val = gtk_spin_button_get_value(spin);
  8012. #endif
  8013. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  8014. /* get the value for the new drawing spreading factor */
  8015. val = gtk_spin_button_get_value((GtkSpinButton *) spinbutton);
  8016. #endif
  8017. /* set new spreading factor */
  8018. yspacing = (int)val;
  8019. /* check if there is node data to draw */
  8020. if (validdata == 0) {
  8021. return;
  8022. }
  8023. /* re-calc positions */
  8024. improve_positions(maingraph);
  8025. /* final (x,y) positioning of nodes/edges */
  8026. finalxy(maingraph);
  8027. /* calculate edge connections */
  8028. edgeconnections(maingraph);
  8029. /* update sub parts of drawing */
  8030. positionz(maingraph);
  8031. /* update status text */
  8032. update_status_text(NULL);
  8033. /* only a re-draw needed */
  8034. gtk_widget_queue_draw(drawingarea1);
  8035. return;
  8036. }
  8037. /* changed type */
  8038. static void bary_changed(GtkWidget * widget, gpointer spinbutton)
  8039. {
  8040. #if (GTK_HAVE_API_VERSION_4 == 1)
  8041. GtkSpinButton *spin = NULL;
  8042. #endif
  8043. gfloat val = 0.0;
  8044. if (widget) {
  8045. }
  8046. if (spinbutton) {
  8047. }
  8048. #if (GTK_HAVE_API_VERSION_4 == 1)
  8049. spin = GTK_SPIN_BUTTON(widget);
  8050. val = gtk_spin_button_get_value(spin);
  8051. #endif
  8052. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  8053. /* get the value for the new bary type */
  8054. val = gtk_spin_button_get_value((GtkSpinButton *) spinbutton);
  8055. #endif
  8056. /* set new bary type, 1,2,3 or 4 */
  8057. barytype = (int)val;
  8058. /* check if there is node data to draw */
  8059. if (validdata == 0) {
  8060. return;
  8061. }
  8062. /* re-layout */
  8063. do_relayout_all(maingraph);
  8064. /* now a re-draw needed */
  8065. gtk_widget_queue_draw(drawingarea1);
  8066. return;
  8067. }
  8068. /* changed type */
  8069. static void rank_changed(GtkWidget * widget, gpointer spinbutton)
  8070. {
  8071. #if (GTK_HAVE_API_VERSION_4 == 1)
  8072. GtkSpinButton *spin = NULL;
  8073. #endif
  8074. gfloat val = 0.0;
  8075. if (widget) {
  8076. }
  8077. if (spinbutton) {
  8078. }
  8079. #if (GTK_HAVE_API_VERSION_4 == 1)
  8080. spin = GTK_SPIN_BUTTON(widget);
  8081. val = gtk_spin_button_get_value(spin);
  8082. #endif
  8083. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  8084. /* get the value for the new bary type */
  8085. val = gtk_spin_button_get_value((GtkSpinButton *) spinbutton);
  8086. #endif
  8087. /* set new rank type, 1,2,3 or 4 */
  8088. ranktype = (int)val;
  8089. /* check if there is node data to draw */
  8090. if (validdata == 0) {
  8091. return;
  8092. }
  8093. /* re-layout */
  8094. do_relayout_all(maingraph);
  8095. /* now a re-draw needed */
  8096. gtk_widget_queue_draw(drawingarea1);
  8097. return;
  8098. }
  8099. #if (GTK_HAVE_API_VERSION_4 == 1)
  8100. /* fit drawing in window */
  8101. static void dofit(void)
  8102. {
  8103. double xzscale = 1.0;
  8104. double yzscale = 1.0;
  8105. double newzscale = 1.0;
  8106. double dval = 1.0;
  8107. int val = 0;
  8108. /* if no maxx, maxy is set */
  8109. if (maxx == 0) {
  8110. maxx = 1;
  8111. }
  8112. if (maxy == 0) {
  8113. maxy = 1;
  8114. }
  8115. xzscale = (double)(1000 * drawing_area_xsize / maxx);
  8116. yzscale = (double)(1000 * drawing_area_ysize / maxy);
  8117. xzscale = xzscale / 1000.0;
  8118. yzscale = yzscale / 1000.0;
  8119. if ((xzscale - yzscale) > 0) {
  8120. newzscale = yzscale;
  8121. } else {
  8122. newzscale = xzscale;
  8123. }
  8124. if (option_gdebug > 1) {
  8125. printf
  8126. ("%s(): dval=%f fit zoom to %f from xscale=%f and yscale=%f drawingarea=(%d,%d) maxy=(%d,%d)\n",
  8127. __func__, dval, newzscale, yzscale, xzscale, drawing_area_xsize, drawing_area_ysize, maxx, maxy);
  8128. }
  8129. /* old dval = log ((newzscale * (double) 50.0) / 3.0) - 50.0; */
  8130. dval = log(newzscale) / 3.0;
  8131. dval = (dval * 50.0);
  8132. dval = dval + 50.0;
  8133. val = (int)dval;
  8134. if (val < 0) {
  8135. val = 0;
  8136. }
  8137. if (val > 100) {
  8138. val = 100;
  8139. }
  8140. zfactor = exp((double)(3 * (val - 50)) / (double)50);
  8141. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale1), val);
  8142. if (option_gdebug > 1) {
  8143. printf("%s(): new slider value is %d (dval=%f) zfactor=%f\n", "dofit", val, dval, zfactor);
  8144. }
  8145. /* reset v xy min */
  8146. vxmin = 0;
  8147. vymin = 0;
  8148. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale2), 0);
  8149. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjhscale1), 0);
  8150. return;
  8151. }
  8152. #endif
  8153. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  8154. /* fit drawing in window */
  8155. static void dofit(void)
  8156. {
  8157. double xzscale = 1.0;
  8158. double yzscale = 1.0;
  8159. double newzscale = 1.0;
  8160. double dval = 1.0;
  8161. int val = 0;
  8162. /* if no maxx, maxy is set */
  8163. if (maxx == 0) {
  8164. maxx = 1;
  8165. }
  8166. if (maxy == 0) {
  8167. maxy = 1;
  8168. }
  8169. xzscale = (double)(1000 * drawing_area_xsize / maxx);
  8170. yzscale = (double)(1000 * drawing_area_ysize / maxy);
  8171. xzscale = xzscale / 1000.0;
  8172. yzscale = yzscale / 1000.0;
  8173. if ((xzscale - yzscale) > 0) {
  8174. newzscale = yzscale;
  8175. } else {
  8176. newzscale = xzscale;
  8177. }
  8178. if (option_gdebug > 1) {
  8179. printf
  8180. ("%s(): dval=%f fit zoom to %f from xscale=%f and yscale=%f drawingarea=(%d,%d) maxy=(%d,%d)\n",
  8181. __func__, dval, newzscale, yzscale, xzscale, drawing_area_xsize, drawing_area_ysize, maxx, maxy);
  8182. }
  8183. /* old dval = log ((newzscale * (double) 50.0) / 3.0) - 50.0; */
  8184. dval = log(newzscale) / 3.0;
  8185. dval = (dval * 50.0);
  8186. dval = dval + 50.0;
  8187. val = (int)dval;
  8188. if (val < 0) {
  8189. val = 0;
  8190. }
  8191. if (val > 100) {
  8192. val = 100;
  8193. }
  8194. zfactor = exp((double)(3 * (val - 50)) / (double)50);
  8195. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale1), val);
  8196. if (option_gdebug > 1) {
  8197. printf("%s(): new slider value is %d (dval=%f) zfactor=%f\n", "dofit", val, dval, zfactor);
  8198. }
  8199. /* reset v xy min */
  8200. vxmin = 0;
  8201. vymin = 0;
  8202. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjvscale2), 0);
  8203. gtk_adjustment_set_value(GTK_ADJUSTMENT(adjhscale1), 0);
  8204. return;
  8205. }
  8206. #endif
  8207. /* size of fields */
  8208. static struct gml_p *static_maingtk_textsizes1sz(struct gml_rl *info)
  8209. {
  8210. struct gml_p *data = NULL;
  8211. struct gml_p *dsub = NULL;
  8212. int i = 0;
  8213. data = dp_calloc(1, sizeof(struct gml_p));
  8214. if (info == NULL) { /* shouldnothappen */
  8215. return (data);
  8216. }
  8217. if (info->hd) {
  8218. data->x = info->txsize;
  8219. data->y = info->tysize;
  8220. } else {
  8221. for (i = 0; i < info->nparts; i++) {
  8222. dsub = static_maingtk_textsizes1sz(info->parts[i]);
  8223. if (info->dir == 0) {
  8224. data->x = data->x + dsub->x;
  8225. if (dsub->y > data->y) {
  8226. data->y = dsub->y;
  8227. }
  8228. } else {
  8229. if (dsub->x > data->x) {
  8230. data->x = dsub->x;
  8231. }
  8232. data->y = data->y + dsub->y;
  8233. }
  8234. dsub = dp_free(dsub);
  8235. if (dsub) {
  8236. }
  8237. }
  8238. }
  8239. info->bbx = data->x;
  8240. info->bby = data->y;
  8241. if (yydebug || 0) {
  8242. printf
  8243. ("%s(): hd=%d dir=%d bb(x,y) size is (%d,%d) t(x,x) is (%d,%d) for `%s'\n",
  8244. __func__, info->hd, info->dir, info->bbx, info->bby, info->txsize, info->tysize, info->ulabel);
  8245. }
  8246. return (data);
  8247. }
  8248. static void static_maingtk_textsizes1eq(struct gml_rl *info)
  8249. {
  8250. int i = 0;
  8251. int eqx = 0;
  8252. int eqy = 0;
  8253. int xs = 0;
  8254. int ys = 0;
  8255. int mbbx = 0;
  8256. int mbby = 0;
  8257. char *sdir = NULL;
  8258. if (info == NULL) {
  8259. return;
  8260. }
  8261. if (info->nparts == 0) {
  8262. if (yydebug || 0) {
  8263. printf("%s(): skip \"%s\"\n", __func__, info->ulabel);
  8264. }
  8265. return;
  8266. }
  8267. if (info->hd == 0) {
  8268. /* */
  8269. for (i = 0; i < info->nparts; i++) {
  8270. if (info->parts[i]) {
  8271. if (info->dir == 0) {
  8272. info->parts[i]->bby = info->bby;
  8273. } else {
  8274. info->parts[i]->bbx = info->bbx;
  8275. }
  8276. }
  8277. }
  8278. for (i = 0; i < info->nparts; i++) {
  8279. if (info->parts[i]) {
  8280. if (i == 0) {
  8281. mbbx = info->parts[i]->bbx;
  8282. mbby = info->parts[i]->bby;
  8283. }
  8284. if (info->parts[i]->bbx > mbbx) {
  8285. mbbx = info->parts[i]->bbx;
  8286. }
  8287. if (info->parts[i]->bby > mbby) {
  8288. mbby = info->parts[i]->bby;
  8289. }
  8290. }
  8291. }
  8292. if (yydebug || 0) {
  8293. printf("%s(): info->bbxy(%d,%d) versus mbbxy(%d,%d)\n", __func__, info->bbx, info->bby, mbbx, mbby);
  8294. }
  8295. xs = info->bbx / info->nparts;
  8296. ys = info->bby / info->nparts;
  8297. eqx = 1;
  8298. eqy = 1;
  8299. /* check if parts are same size */
  8300. for (i = 0; i < info->nparts; i++) {
  8301. if (info->parts[i]) {
  8302. if (info->parts[i]->bbx > xs) {
  8303. eqx = 0;
  8304. }
  8305. if (info->parts[i]->bby > ys) {
  8306. eqy = 0;
  8307. }
  8308. }
  8309. }
  8310. /* set step factor if equal spread */
  8311. for (i = 0; i < info->nparts; i++) {
  8312. if (info->parts[i]) {
  8313. if (eqx) {
  8314. info->parts[i]->xstep = xs;
  8315. } else {
  8316. info->parts[i]->xstep = 0;
  8317. }
  8318. if (eqy) {
  8319. info->parts[i]->ystep = ys;
  8320. } else {
  8321. info->parts[i]->ystep = 0;
  8322. }
  8323. if (yydebug || 0) {
  8324. printf("%s(): \"%s\" eqx=%d eqy=%d\n", __func__, info->parts[i]->ulabel, eqx, eqy);
  8325. }
  8326. }
  8327. }
  8328. /* print summary */
  8329. if (yydebug || 0) {
  8330. if (info->dir == 0) {
  8331. sdir = "x-dir";
  8332. } else {
  8333. sdir = "y-dir";
  8334. }
  8335. printf
  8336. ("%s(): size (%d,%d) %s %d parts eqx=%d eqy=%d xstep %d ystep %d\n",
  8337. __func__, info->bbx, info->bby, sdir, info->nparts, eqx, eqy, xs, ys);
  8338. for (i = 0; i < info->nparts; i++) {
  8339. if (info->parts[i]) {
  8340. printf("\t[%d] size (%d,%d) \"%s\" xstep=%d ystep=%d\n", i,
  8341. info->parts[i]->bbx, info->parts[i]->bby,
  8342. info->parts[i]->ulabel, info->parts[i]->xstep, info->parts[i]->ystep);
  8343. }
  8344. }
  8345. }
  8346. for (i = 0; i < info->nparts; i++) {
  8347. if (info->parts[i]) {
  8348. static_maingtk_textsizes1eq(info->parts[i]);
  8349. }
  8350. }
  8351. }
  8352. return;
  8353. }
  8354. /* text size 1 record label */
  8355. static void static_maingtk_textsizes1rl(struct gml_rl *info)
  8356. {
  8357. int i = 0;
  8358. size_t len = 0;
  8359. char *tmpb = NULL;
  8360. char *p = NULL;
  8361. char *q = NULL;
  8362. cairo_surface_t *surface = NULL;
  8363. cairo_t *crdraw = NULL;
  8364. PangoLayout *layout = NULL;
  8365. PangoFontDescription *desc = NULL;
  8366. int w = 0;
  8367. int h = 0;
  8368. char buf[128];
  8369. char *s = NULL;
  8370. /* name of font to use, example "Sans" */
  8371. const char *default_fontname = DEFAULT_FONTNAME;
  8372. /* name of slant to use, example "Italic", "Oblique", "Roman" */
  8373. const char *default_fontslant = DEFAULT_FONTSLANT;
  8374. /* name of weight to use, example "Bold", "Book", "Light", "Medium", "Semi-bold", "Ultra-light" */
  8375. const char *default_fontweight = DEFAULT_FONTWEIGHT;
  8376. /* name of condensed to use, example "Semi-Condensed", "Condensed" */
  8377. const char *default_fontcondensed = DEFAULT_FONTCONDENSED;
  8378. /* font size to use, example "10", "18", "20" etc. */
  8379. const char *default_fontsize = DEFAULT_FONTSIZE;
  8380. if (info == NULL) {
  8381. return;
  8382. }
  8383. /* check if has data */
  8384. if (info->hd) {
  8385. if (info->txsize == 0 && info->tysize == 0) {
  8386. if (info->label == NULL) {
  8387. /* shouldnothappen */
  8388. info->label = uniqstr(" ");
  8389. }
  8390. len = strlen(info->label);
  8391. if (len) {
  8392. tmpb = (char *)dp_calloc(1, (len + 1));
  8393. p = info->label;
  8394. q = tmpb;
  8395. /* un-escape the string */
  8396. while (*p) {
  8397. if (*p == '\\') {
  8398. p++;
  8399. if (*p == 0) {
  8400. *q = '\\';
  8401. q++;
  8402. break;
  8403. }
  8404. if (*p == 'n' || *p == 'l' || *p == 'r') {
  8405. *q = '\n';
  8406. } else {
  8407. *q = *p;
  8408. }
  8409. p++;
  8410. q++;
  8411. } else {
  8412. *q = *p;
  8413. p++;
  8414. q++;
  8415. }
  8416. }
  8417. len = strlen(tmpb);
  8418. if (len) {
  8419. if (tmpb[len - 1] == '\n') {
  8420. tmpb[len - 1] = 0;
  8421. }
  8422. } else {
  8423. info->ulabel = uniqstr(" ");
  8424. }
  8425. info->ulabel = uniqstr(tmpb);
  8426. tmpb = dp_free(tmpb);
  8427. if (tmpb) {
  8428. }
  8429. /* calculate the text area */
  8430. if (surface == NULL) {
  8431. surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10);
  8432. }
  8433. /* */
  8434. if (crdraw == NULL) {
  8435. crdraw = cairo_create(surface);
  8436. }
  8437. /* */
  8438. layout = pango_cairo_create_layout(crdraw);
  8439. /* set the text to draw which is 0 terminated */
  8440. pango_layout_set_text(layout, info->ulabel, -1);
  8441. /* create the fontname description */
  8442. memset(buf, 0, (size_t)128);
  8443. /* name of font to use */
  8444. default_fontname = uniqstr((char *)DEFAULT_FONTNAME);
  8445. /* check if node has a specified font slant */
  8446. default_fontslant = uniqstr((char *)DEFAULT_FONTSLANT);
  8447. /* check if node has a specified font weight */
  8448. default_fontweight = uniqstr((char *)DEFAULT_FONTWEIGHT);
  8449. /* check if node has a specified font size */
  8450. default_fontsize = uniqstr((char *)DEFAULT_FONTSIZE);
  8451. /* create the font name string */
  8452. snprintf(buf, (128 - 1), "%s %s %s %s %s",
  8453. default_fontname, default_fontslant, default_fontweight, default_fontcondensed, default_fontsize);
  8454. /* copy string buffer */
  8455. s = uniqstr(buf);
  8456. /* */
  8457. desc = pango_font_description_from_string(s);
  8458. /* */
  8459. pango_layout_set_font_description(layout, desc);
  8460. /* */
  8461. pango_font_description_free(desc);
  8462. /* */
  8463. pango_cairo_update_layout(crdraw, layout);
  8464. /* */
  8465. w = 0;
  8466. h = 0;
  8467. /* */
  8468. pango_layout_get_size(layout, &w, &h);
  8469. /* */
  8470. g_object_unref(G_OBJECT(layout));
  8471. /* */
  8472. cairo_destroy(crdraw);
  8473. crdraw = NULL;
  8474. /* */
  8475. cairo_surface_destroy(surface);
  8476. surface = NULL;
  8477. /* */
  8478. info->txsize = (w / PANGO_SCALE);
  8479. info->tysize = (h / PANGO_SCALE);
  8480. /* add small margin around text */
  8481. info->txsize = info->txsize + 4;
  8482. info->tysize = info->tysize + 4;
  8483. /* */
  8484. if (yydebug || 0) {
  8485. printf("%s(): (%d,%d) size for `%s'\n", __func__, info->txsize, info->tysize, info->ulabel);
  8486. }
  8487. } else {
  8488. /* at "" string */
  8489. info->txsize = 4;
  8490. info->tysize = 4;
  8491. info->ulabel = uniqstr(" ");
  8492. }
  8493. }
  8494. }
  8495. for (i = 0; i < info->nparts; i++) {
  8496. /* this can be 0 */
  8497. if (info->parts) {
  8498. static_maingtk_textsizes1rl(info->parts[i]);
  8499. }
  8500. }
  8501. return;
  8502. }
  8503. static void static_maingtk_textsizes2rl(struct gml_rl *info, int count, int xoff, int yoff, int bbx, int bby)
  8504. {
  8505. int i = 0;
  8506. char *sdir = NULL;
  8507. int xo = 0;
  8508. int yo = 0;
  8509. int ibbx = 0;
  8510. int ibby = 0;
  8511. int abbx = 0;
  8512. int abby = 0;
  8513. if (info == NULL) {
  8514. return;
  8515. }
  8516. /* check if has data */
  8517. if (info->hd == 0) {
  8518. if (yydebug || 0) {
  8519. printf
  8520. ("%s(%d): xyoff(%d,%d) bbxy(%d,%d) nparts=%d info->bbxy(%d,%d)\n",
  8521. __func__, count, xoff, yoff, bbx, bby, info->nparts, info->bbx, info->bby);
  8522. }
  8523. if (yydebug || 0) {
  8524. if (info->dir == 0) {
  8525. sdir = "x-dir";
  8526. } else {
  8527. sdir = "y-dir";
  8528. }
  8529. printf("%s(): rl=%p %s hd=0 bbxy(%d,%d) nparts=%d\n", __func__, (void *)info, sdir, info->bbx, info->bby, info->nparts);
  8530. for (i = 0; i < info->nparts; i++) {
  8531. if (info->parts[i]) {
  8532. if (info->dir == 0) {
  8533. sdir = "x-dir";
  8534. } else {
  8535. sdir = "y-dir";
  8536. }
  8537. printf("\tparts[%d]=%p %s hd=%d \"%s\"\n", i,
  8538. (void *)info->parts[i], sdir, info->parts[i]->hd, info->parts[i]->ulabel);
  8539. }
  8540. }
  8541. }
  8542. xo = 0;
  8543. yo = 0;
  8544. abbx = 0;
  8545. abby = 0;
  8546. for (i = 0; i < info->nparts; i++) {
  8547. if (info->parts[i]) {
  8548. if (info->parts[i]->hd == 0) {
  8549. ibbx = info->parts[i]->bbx;
  8550. ibby = info->parts[i]->bby;
  8551. abbx = ibbx;
  8552. abby = ibby;
  8553. static_maingtk_textsizes2rl(info->parts[i], i, xoff + xo, yoff + yo, ibbx, ibby);
  8554. /*
  8555. */
  8556. if ((i + 1) < info->nparts) {
  8557. if (info->parts[i + 1]) {
  8558. if (info->parts[i + 1]->hd == 0) {
  8559. if (info->parts[i]->dir == 0) {
  8560. yo = yo + abby;
  8561. } else {
  8562. xo = xo + abbx;
  8563. }
  8564. }
  8565. }
  8566. }
  8567. /*
  8568. *
  8569. */
  8570. } else {
  8571. if (info->parts[i]->dir == 0) {
  8572. info->parts[i]->xoff = xoff + xo + abbx;
  8573. info->parts[i]->yoff = yoff + yo;
  8574. info->parts[i]->bby = bby;
  8575. if (info->parts[i]->xstep) {
  8576. xo = xo + info->parts[i]->xstep + abbx;
  8577. } else {
  8578. xo = xo + info->parts[i]->bbx + abbx;
  8579. }
  8580. } else {
  8581. info->parts[i]->xoff = xoff + xo;
  8582. info->parts[i]->yoff = yoff + yo + abby;
  8583. info->parts[i]->bbx = bbx;
  8584. if (info->parts[i]->ystep) {
  8585. yo = yo + info->parts[i]->ystep + abby;
  8586. } else {
  8587. yo = yo + info->parts[i]->bby + abby;
  8588. }
  8589. }
  8590. abbx = 0;
  8591. abby = 0;
  8592. }
  8593. } /* if (info->parts[i]) */
  8594. } /* for() */
  8595. } else {
  8596. /* info has data */
  8597. if (yydebug || 0) {
  8598. if (info->dir == 0) {
  8599. sdir = "x-dir";
  8600. } else {
  8601. sdir = "y-dir";
  8602. }
  8603. printf
  8604. ("%s(): rl=%p %s hd=1 bbxy(%d,%d) \"%s\" xyoff(%d,%d) bbxy(%d,%d)\n",
  8605. __func__, (void *)info, sdir, info->bbx, info->bby, info->ulabel, xoff, yoff, bbx, bby);
  8606. }
  8607. }
  8608. return;
  8609. }
  8610. /* handle record label sizes for one node */
  8611. static void static_maingtk_textsizes1n(struct gml_node *node)
  8612. {
  8613. struct gml_p *data = NULL;
  8614. /* calc (x,y) text size of all parts in record label */
  8615. static_maingtk_textsizes1rl(node->rlabel);
  8616. data = static_maingtk_textsizes1sz(node->rlabel);
  8617. if (data == NULL) {
  8618. /* shouldnothappen */
  8619. return;
  8620. }
  8621. if (yydebug || 0) {
  8622. printf("%s(): d is (%d,%d) versus bbxy(%d,%d)\n", __func__, data->x, data->y, node->bbx, node->bby);
  8623. }
  8624. /* check for use of step of bb */
  8625. static_maingtk_textsizes1eq(node->rlabel);
  8626. /* now position the text parts and result in the rlabel structs */
  8627. node->bbx = data->x;
  8628. node->bby = data->y;
  8629. /* save copy of full size */
  8630. node->fbbx = data->x;
  8631. node->fbby = data->y;
  8632. /* relocate the parts */
  8633. static_maingtk_textsizes2rl(node->rlabel, 0, 0, 0, node->bbx, node->bby);
  8634. data = dp_free(data);
  8635. if (data) {
  8636. }
  8637. return;
  8638. }
  8639. /* size of one 1 html item
  8640. * the item has fontsize, name and bitflags of type
  8641. */
  8642. static struct gml_p *static_maingtk_textsizes1htmlsz1item(struct gml_hitem *item)
  8643. {
  8644. struct gml_p *data = NULL;
  8645. int fsz = 0;
  8646. char *slant = NULL;
  8647. char *weight = NULL;
  8648. char *fn = NULL;
  8649. cairo_surface_t *surface = NULL;
  8650. cairo_t *crdraw = NULL;
  8651. PangoLayout *layout = NULL;
  8652. PangoFontDescription *desc = NULL;
  8653. char buf[128];
  8654. char *s = NULL;
  8655. int w = 0;
  8656. int h = 0;
  8657. data = dp_calloc(1, sizeof(struct gml_p));
  8658. if (item == NULL) {
  8659. /* shouldnothappen */
  8660. return (data);
  8661. }
  8662. if (item->bitflags.table) {
  8663. if (yydebug || 0) {
  8664. printf("%s(): item is a <table>\n", __func__);
  8665. }
  8666. if (item->table == NULL) {
  8667. /* shouldnothappen */
  8668. printf("%s(): item is a <table> but nil table\n", __func__);
  8669. return (data);
  8670. }
  8671. /* set the size of <table> as size of this item */
  8672. item->txsize = item->table->txsizemin;
  8673. item->tysize = item->table->tysizemin;
  8674. /* */
  8675. data->x = item->txsize;
  8676. data->y = item->tysize;
  8677. if (yydebug || 0) {
  8678. printf("%s(): \"%s\" has size (%d,%d) d (%d,%d)\n", __func__, "<table>", item->txsize, item->tysize, data->x, data->y);
  8679. }
  8680. return (data);
  8681. }
  8682. if (yydebug || 0) {
  8683. printf("%s(): item->text is \"%s\"\n", __func__, item->text);
  8684. }
  8685. if (item->text == NULL) {
  8686. /* shouldnothappen */
  8687. return (data);
  8688. }
  8689. if (strlen(item->text) == 0) {
  8690. /* shouldnothappen */
  8691. return (data);
  8692. }
  8693. /* get fontsize */
  8694. if (item->fontsize < 0) {
  8695. /* not specified */
  8696. fsz = DEFAULT_FONTSIZE_INT;
  8697. item->fontsize = fsz;
  8698. } else {
  8699. /* check fontsize */
  8700. if (item->fontsize < 5) {
  8701. /* too small text */
  8702. return (data);
  8703. }
  8704. fsz = item->fontsize;
  8705. }
  8706. /* italic slant */
  8707. if (item->bitflags.i) {
  8708. slant = "italic";
  8709. } else {
  8710. slant = DEFAULT_FONTSLANT;
  8711. }
  8712. item->fontslant = uniqstr(slant);
  8713. /* bold weight */
  8714. if (item->bitflags.b) {
  8715. weight = "bold";
  8716. } else {
  8717. weight = DEFAULT_FONTWEIGHT;
  8718. }
  8719. item->fontweight = uniqstr(weight);
  8720. /* check if fontname set */
  8721. if (item->fontname) {
  8722. /* at unknown fontname, default is used without warning */
  8723. fn = item->fontname;
  8724. } else {
  8725. fn = DEFAULT_FONTNAME;
  8726. }
  8727. if (surface == NULL) {
  8728. surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10);
  8729. }
  8730. /* */
  8731. if (crdraw == NULL) {
  8732. crdraw = cairo_create(surface);
  8733. }
  8734. /* */
  8735. layout = pango_cairo_create_layout(crdraw);
  8736. /* set the text to draw which is 0 terminated */
  8737. pango_layout_set_text(layout, item->text, -1);
  8738. /* create the fontname description */
  8739. memset(buf, 0, (size_t)128);
  8740. /* create the font name string */
  8741. snprintf(buf, (size_t)(128 - 1), "%s %s %s %s %d", fn, slant, weight, DEFAULT_FONTCONDENSED, fsz);
  8742. s = uniqstr(buf);
  8743. /* */
  8744. desc = pango_font_description_from_string(s);
  8745. /* */
  8746. pango_layout_set_font_description(layout, desc);
  8747. /* */
  8748. pango_font_description_free(desc);
  8749. /* */
  8750. pango_cairo_update_layout(crdraw, layout);
  8751. /* */
  8752. w = 0;
  8753. h = 0;
  8754. /* */
  8755. pango_layout_get_size(layout, &w, &h);
  8756. /* set text (x,y) size */
  8757. item->txsize = (w / PANGO_SCALE);
  8758. item->tysize = (h / PANGO_SCALE);
  8759. /* */
  8760. g_object_unref(G_OBJECT(layout));
  8761. cairo_destroy(crdraw);
  8762. crdraw = NULL;
  8763. /* */
  8764. cairo_surface_destroy(surface);
  8765. surface = NULL;
  8766. data->x = item->txsize;
  8767. data->y = item->tysize;
  8768. if (yydebug || 0) {
  8769. printf("%s(): \"%s\" has size (%d,%d) d (%d,%d)\n", __func__, item->text, item->txsize, item->tysize, data->x, data->y);
  8770. }
  8771. return (data);
  8772. }
  8773. /* size of html items */
  8774. static struct gml_p *static_maingtk_textsizes1htmlszitems(struct gml_node *node, struct gml_hl *info)
  8775. {
  8776. struct gml_p *data = NULL;
  8777. struct gml_p *ditem = NULL;
  8778. struct gml_hitem *pitem = NULL;
  8779. struct gml_hitem *pitem2 = NULL;
  8780. struct gml_hilist *pi = NULL;
  8781. struct gml_hilist *pi2 = NULL;
  8782. struct gml_hilist *sl = NULL;
  8783. struct gml_hilist *el = NULL;
  8784. int mxl = 0;
  8785. int mxl2 = 0;
  8786. int myl = 0;
  8787. int my = 0;
  8788. int mx = 0;
  8789. int tof = 0;
  8790. data = dp_calloc(1, sizeof(struct gml_p));
  8791. if (node == NULL) {
  8792. return (data);
  8793. }
  8794. if (info == NULL) {
  8795. return (data);
  8796. }
  8797. if (info->il == NULL) {
  8798. /* shouldnothappen */
  8799. return (data);
  8800. }
  8801. if (yydebug || 0) {
  8802. printf("%s(): items of node \"%s\" are:\n", __func__, node->name);
  8803. }
  8804. /* get size of the text elements */
  8805. pi = info->il;
  8806. while (pi) {
  8807. pitem = pi->items;
  8808. if (pitem) {
  8809. if (pi->items->bitflags.br) {
  8810. } else if (pi->items->bitflags.hr) {
  8811. } else if (pi->items->bitflags.vr) {
  8812. } else if (pi->items->bitflags.img) {
  8813. } else if (pi->items->bitflags.table) {
  8814. if (0) {
  8815. printf("%s(): table bit set. todo\n", __func__);
  8816. }
  8817. } else {
  8818. if (yydebug || 0) {
  8819. printf("\"%s\"\n", pi->items->text);
  8820. }
  8821. ditem = static_maingtk_textsizes1htmlsz1item(pitem);
  8822. if (ditem->x == 0 || ditem->y == 0) {
  8823. /* zero sized text */
  8824. }
  8825. pitem->txsizemin = ditem->x;
  8826. pitem->tysizemin = ditem->y;
  8827. pitem->txsize = ditem->x;
  8828. pitem->tysize = ditem->y;
  8829. ditem = dp_free(ditem);
  8830. if (ditem) {
  8831. }
  8832. }
  8833. }
  8834. pi = pi->next;
  8835. }
  8836. /* */
  8837. if (yydebug || 0) {
  8838. printf("\n");
  8839. }
  8840. /* determine the size of these lines */
  8841. mx = 0;
  8842. my = 0;
  8843. /* */
  8844. pi = info->il;
  8845. tof = 0;
  8846. while (pi) {
  8847. /* set start/end line */
  8848. sl = pi;
  8849. el = pi;
  8850. pi2 = pi;
  8851. mxl2 = 0;
  8852. myl = 0;
  8853. while (pi2) {
  8854. pitem2 = pi2->items;
  8855. el = pi2;
  8856. if (pi2->items) {
  8857. if (pi2->items->bitflags.br) {
  8858. /* newline */
  8859. if (myl == 0) {
  8860. /* a <br/> can have a fontsize set */
  8861. if (pi2->items->fontsize > 0) {
  8862. myl = pi2->items->fontsize;
  8863. } else {
  8864. myl = DEFAULT_FONTSIZE_INT;
  8865. }
  8866. }
  8867. /* set x at start of line */
  8868. /* mxl = 0; */
  8869. break;
  8870. } else if (pi2->items->bitflags.hr) {
  8871. } else if (pi2->items->bitflags.vr) {
  8872. } else if (pi2->items->bitflags.img) {
  8873. } else if (pi2->items->bitflags.table) {
  8874. if (0) {
  8875. printf("%s(): table bit set todo\n", __func__);
  8876. }
  8877. } else {
  8878. /* text x offset in this line */
  8879. mxl2 = mxl2 + pitem2->txsize;
  8880. if (mxl2 > mx) {
  8881. mx = mxl2;
  8882. }
  8883. if (pitem2->tysize > myl) {
  8884. myl = pitem2->tysize;
  8885. }
  8886. }
  8887. }
  8888. pi2 = pi2->next;
  8889. }
  8890. /* update */
  8891. mxl = 0;
  8892. pi2 = sl;
  8893. while (pi2) {
  8894. pitem2 = pi2->items;
  8895. if (pitem2) {
  8896. /* text x offset in this line */
  8897. pitem2->txoff = mxl;
  8898. mxl = mxl + pitem2->txsize;
  8899. if (mxl > mx) {
  8900. mx = mxl;
  8901. }
  8902. /* y size of this text line */
  8903. pitem2->lysize = myl;
  8904. /* text y offset in this line */
  8905. pitem2->tyoff = (myl - pitem2->tysize) + tof;
  8906. if (pi2 == el) {
  8907. break;
  8908. }
  8909. }
  8910. pi2 = pi2->next;
  8911. }
  8912. tof = tof + myl;
  8913. if (tof > my) {
  8914. my = tof;
  8915. }
  8916. /* continue scan other parts of item */
  8917. if (pi2) {
  8918. pi = pi2->next;
  8919. } else {
  8920. break;
  8921. }
  8922. }
  8923. /* set node text (x,y) */
  8924. node->tx = mx + 2;
  8925. node->ty = my + 2;
  8926. data->x = node->tx;
  8927. data->y = node->ty;
  8928. /* here update text x pos for br align statements if any todo */
  8929. node->txsize = 1;
  8930. if (yydebug || 0) {
  8931. printf("%s(): size (%d,%d) for node \"%s\"\n", __func__, data->x, data->y, node->name);
  8932. }
  8933. return (data);
  8934. }
  8935. /* one <table> in table list */
  8936. static struct gml_p *static_maingtk_textsizes1htmlsz1table(struct gml_node *node, struct gml_htlist *tlptr)
  8937. {
  8938. struct gml_p *data = NULL;
  8939. struct gml_p *subdata = NULL;
  8940. struct gml_p *di = NULL;
  8941. struct gml_titem *titemptr = NULL;
  8942. struct gml_htlist *tlptrsub = NULL;
  8943. struct gml_tritemlist *trptr = NULL; /* list of <tr> items in this table */
  8944. struct gml_tditem *tdiptr = NULL;
  8945. struct gml_hilist *ilptr = NULL;
  8946. int *tdsz = NULL;
  8947. int ntr = 0;
  8948. int numtd = 0;
  8949. int ntdmax = 0;
  8950. int trysum = 0;
  8951. int ilmaxy = 0;
  8952. int trxsum = 0;
  8953. int trmax = 0;
  8954. int tdcount = 0;
  8955. int tdxtotal = 0;
  8956. int tdytotal = 0;
  8957. int wanttd = 0;
  8958. int i = 0;
  8959. struct gml_tditem *dummytd = NULL;
  8960. int ystep = 0;
  8961. int tablebgcolor = 0x00ffffff; /* white */
  8962. data = dp_calloc(1, sizeof(struct gml_p));
  8963. titemptr = tlptr->titem;
  8964. if (titemptr == NULL) {
  8965. /* shouldnothappen */
  8966. return (data);
  8967. }
  8968. /* first scan the sub <table> data */ tlptrsub = titemptr->tl;
  8969. while (tlptrsub) {
  8970. subdata = static_maingtk_textsizes1htmlsz1table(node, tlptrsub);
  8971. /* todo */
  8972. subdata = dp_free(subdata);
  8973. if (subdata) {
  8974. }
  8975. tlptrsub = tlptrsub->next;
  8976. }
  8977. /* fillcolor of this <table> */
  8978. tablebgcolor = titemptr->bgcolor;
  8979. trptr = titemptr->tr; /* list of <tr> items in this table */
  8980. if (trptr == NULL) {
  8981. /* shouldnothappen */
  8982. return (data);
  8983. }
  8984. ntdmax = 0;
  8985. ntr = 0;
  8986. trmax = 0;
  8987. while (trptr) {
  8988. if (trptr->tritem == NULL) {
  8989. /* shouldnothappen */
  8990. return (data);
  8991. }
  8992. /* needed x size for this <tr> */
  8993. trxsum = 0;
  8994. /* <td> in <tr> */
  8995. tdiptr = trptr->tritem->tdi;
  8996. if (tdiptr == NULL) {
  8997. /* shouldnothappen */
  8998. return (data);
  8999. }
  9000. /* number of <td> in this <tr> */
  9001. numtd = 0;
  9002. ilmaxy = 0;
  9003. while (tdiptr) {
  9004. ilptr = tdiptr->il;
  9005. if (ilptr == NULL) {
  9006. /* shouldnothappen */
  9007. return (data);
  9008. }
  9009. /* size of <td> */
  9010. tdxtotal = 0;
  9011. tdytotal = 0;
  9012. while (ilptr) {
  9013. di = static_maingtk_textsizes1htmlsz1item(ilptr->items);
  9014. /* handle item size */
  9015. /* x size of this <td> */
  9016. if (yydebug || 0) {
  9017. printf("%s(): item in td (%d,%d) for \"%s\"\n", __func__, di->x, di->y, ilptr->items->text);
  9018. }
  9019. if (di->x > tdxtotal) {
  9020. tdxtotal = di->x;
  9021. }
  9022. tdytotal = tdytotal + di->y;
  9023. trxsum = trxsum + di->x;
  9024. tdiptr->ysize = di->y;
  9025. /* */
  9026. di = dp_free(di);
  9027. if (di) {
  9028. }
  9029. /* next item */
  9030. ilptr = ilptr->next;
  9031. }
  9032. /* set the size in this <td> */
  9033. tdiptr->xsize = tdxtotal;
  9034. tdiptr->ysize = tdytotal;
  9035. if (tdiptr->ysize > ilmaxy) {
  9036. ilmaxy = tdiptr->ysize;
  9037. }
  9038. if (yydebug || 0) {
  9039. printf("%s(): td (%d,%d) size for this these td items ilmaxy=%d\n", __func__, tdiptr->xsize, tdiptr->ysize, ilmaxy);
  9040. }
  9041. numtd++;
  9042. /* next <td> */
  9043. tdiptr = tdiptr->next;
  9044. }
  9045. if (yydebug || 0) {
  9046. printf("%s(): setting ysize to %d\n", __func__, ilmaxy);
  9047. }
  9048. /* y size in this <tr> for the <td> items */
  9049. trptr->tritem->ysize = ilmaxy;
  9050. /* number of <td> in this <tr> */
  9051. trptr->tritem->numtd = numtd;
  9052. if (numtd > ntdmax) {
  9053. ntdmax = numtd;
  9054. }
  9055. /* number of <tr> statements */
  9056. ntr++;
  9057. /* widest <tr> */
  9058. if (trxsum > trmax) {
  9059. trmax = trxsum;
  9060. }
  9061. /* needed y size for this <td> in this <tr> */
  9062. trysum = trysum + ilmaxy;
  9063. /* next <tr> */
  9064. trptr = trptr->next;
  9065. }
  9066. /* number of <tr> in this <table> */
  9067. titemptr->numtr = ntr;
  9068. titemptr->nrows = ntr;
  9069. /* number of <td> needed for this table */
  9070. titemptr->numtd = ntdmax;
  9071. titemptr->ncols = ntdmax;
  9072. /* needed y size to hold all <td> */
  9073. titemptr->tysize = trysum;
  9074. titemptr->tysizemin = trysum;
  9075. /* re-scan to update the <td> size at <tr> */
  9076. tdsz = dp_calloc(1, (sizeof(int) * ntdmax));
  9077. /* re-scan */
  9078. titemptr = tlptr->titem;
  9079. trptr = titemptr->tr; /* list of <tr> items in this table */
  9080. /* find the widest <td> at a <tr> */
  9081. while (trptr) {
  9082. /* <td> in <tr> */
  9083. tdiptr = trptr->tritem->tdi;
  9084. tdcount = 0;
  9085. while (tdiptr) {
  9086. if (tdiptr->xsize > tdsz[tdcount]) {
  9087. tdsz[tdcount] = tdiptr->xsize;
  9088. }
  9089. tdcount++;
  9090. /* next <td> */
  9091. tdiptr = tdiptr->next;
  9092. }
  9093. /* next <tr> */
  9094. trptr = trptr->next;
  9095. }
  9096. /* update the x step */
  9097. trptr = titemptr->tr; /* list of <tr> items in this table */
  9098. trmax = 0;
  9099. while (trptr) {
  9100. /* <td> in <tr> */
  9101. tdiptr = trptr->tritem->tdi;
  9102. trxsum = 0;
  9103. tdcount = 0;
  9104. while (tdiptr) {
  9105. /* (x,y) size of <td> */
  9106. if (yydebug || 0) {
  9107. printf("%s(): at col=%d size (%d,%d) for this td\n", __func__, tdcount, tdiptr->xsize, tdiptr->ysize);
  9108. }
  9109. tdiptr->xstep = tdsz[tdcount];
  9110. tdiptr->ystep = trptr->tritem->ysize;
  9111. trxsum = trxsum + tdiptr->xstep;
  9112. /* set max reached x size */
  9113. if (trxsum > trmax) {
  9114. trmax = trxsum;
  9115. }
  9116. if (yydebug || 0) {
  9117. printf("%s(): at col=%d size (%d,%d) trmax=%d\n", __func__, tdcount, tdiptr->xstep, tdiptr->ystep, trmax);
  9118. }
  9119. tdcount++;
  9120. /* next <td> */
  9121. tdiptr = tdiptr->next;
  9122. }
  9123. /* next <tr> */
  9124. trptr = trptr->next;
  9125. }
  9126. /* needed x size to hold all <tr> */
  9127. titemptr->txsize = trmax;
  9128. titemptr->txsizemin = trmax;
  9129. /* indicate that min. size is set for this <table> */
  9130. titemptr->sizeset = 1;
  9131. /* set <table> (x,y) size */
  9132. data->x = trmax;
  9133. data->y = trysum;
  9134. /* add dummy <td> to fill the tables */
  9135. trptr = titemptr->tr; /* list of <tr> items in this table */
  9136. /* find the widest <td> at a <tr> */
  9137. while (trptr) {
  9138. /* <td> in <tr> */
  9139. tdiptr = trptr->tritem->tdi;
  9140. /* number of needed <td> */
  9141. wanttd = ntdmax;
  9142. ystep = trptr->tritem->ysize;
  9143. tdcount = 0;
  9144. while (tdiptr) {
  9145. wanttd--;
  9146. /* set min. needed (x,y) size for <td> (x,y) size set earlier */
  9147. tdiptr->xsizemin = tdiptr->xsize;
  9148. tdiptr->ysizemin = tdiptr->ysize;
  9149. tdcount++;
  9150. /* next <td> */
  9151. tdiptr = tdiptr->next;
  9152. }
  9153. if (yydebug || 0) {
  9154. printf("%s(): <tr> has %d <td> but needs %d <td> adding %d dummy <td>\n", __func__, trptr->tritem->numtd,
  9155. ntdmax, wanttd);
  9156. }
  9157. /* add the dummy <td> */
  9158. for (i = 0; i < wanttd; i++) {
  9159. dummytd = dp_calloc(1, sizeof(struct gml_tditem));
  9160. /* this is a <td> with no data */
  9161. dummytd->dummy = 1;
  9162. /* x size depends on pos. of <td> */
  9163. dummytd->xsize = tdsz[tdcount];
  9164. dummytd->xstep = tdsz[tdcount];
  9165. dummytd->xsizemin = tdsz[tdcount];
  9166. /* y size */
  9167. dummytd->ysize = ystep;
  9168. dummytd->ystep = ystep;
  9169. dummytd->ysizemin = ystep;
  9170. /* fill color */
  9171. dummytd->bgcolor = tablebgcolor;
  9172. /* link in */
  9173. if (trptr->tritem->tdi == NULL) {
  9174. trptr->tritem->tdi = dummytd;
  9175. trptr->tritem->tdiend = dummytd;
  9176. } else {
  9177. trptr->tritem->tdiend->next = dummytd;
  9178. trptr->tritem->tdiend = dummytd;
  9179. }
  9180. tdcount++;
  9181. }
  9182. /* next <tr> */
  9183. trptr = trptr->next;
  9184. }
  9185. /* ready with <td> x size data */
  9186. tdsz = dp_free(tdsz);
  9187. if (tdsz) {
  9188. }
  9189. if (yydebug || 0) {
  9190. printf("%s(): size (%d,%d) <table> in for node \"%s\"\n", __func__, data->x, data->y, node->name);
  9191. }
  9192. return (data);
  9193. }
  9194. /* size of html tables */
  9195. static struct gml_p *static_maingtk_textsizes1htmlsztables(struct gml_node *node, struct gml_hl *info)
  9196. {
  9197. struct gml_p *data = NULL;
  9198. struct gml_p *subdata = NULL;
  9199. struct gml_htlist *tlptr = NULL; /* list of sub table items */
  9200. int trx = 0;
  9201. int try = 0;
  9202. data = dp_calloc(1, sizeof(struct gml_p));
  9203. if (node == NULL) {
  9204. /* shouldnothappen */
  9205. return (data);
  9206. }
  9207. if (info == NULL) {
  9208. /* shouldnothappen */
  9209. return (data);
  9210. }
  9211. if (info->tl == NULL) {
  9212. /* shouldnothappen */
  9213. return (data);
  9214. }
  9215. tlptr = info->tl;
  9216. while (tlptr) {
  9217. subdata = static_maingtk_textsizes1htmlsz1table(node, tlptr);
  9218. /* temp test todo */
  9219. trx = subdata->x;
  9220. try = subdata->y;
  9221. subdata = dp_free(subdata);
  9222. if (subdata) {
  9223. }
  9224. tlptr = tlptr->next;
  9225. }
  9226. data->x = trx + 2;
  9227. data->y = try + 2;
  9228. if (yydebug || 0) {
  9229. printf("%s(): size (%d,%d) for node \"%s\"\n", __func__, data->x, data->y, node->name);
  9230. }
  9231. return (data);
  9232. }
  9233. /* size of html */
  9234. static struct gml_p *static_maingtk_textsizes1htmlsz(struct gml_node *node, struct gml_hl *info)
  9235. {
  9236. struct gml_p *data = NULL;
  9237. if (info->mode == 0) {
  9238. /* html items */
  9239. data = static_maingtk_textsizes1htmlszitems(node, info);
  9240. } else {
  9241. /* html tables */
  9242. data = static_maingtk_textsizes1htmlsztables(node, info);
  9243. }
  9244. return (data);
  9245. }
  9246. /* handle html label sizes for one node */
  9247. static void static_maingtk_textsizes1htmln(struct gml_node *node)
  9248. {
  9249. struct gml_p *data = NULL;
  9250. /* preset with small value */
  9251. node->tx = 0;
  9252. node->ty = 0;
  9253. node->bbx = 10;
  9254. node->bby = 10;
  9255. /* save copy of full size */
  9256. node->fbbx = 10;
  9257. node->fbby = 10;
  9258. data = static_maingtk_textsizes1htmlsz(node, node->hlabel);
  9259. /* for a box */
  9260. node->bbx = data->x; /* or node->tx + 4; */
  9261. node->bby = data->y; /* or node->ty + 4; */
  9262. /* save copy of full size */
  9263. node->fbbx = node->bbx;
  9264. node->fbby = node->bby;
  9265. if (yydebug || 0) {
  9266. printf("%s(): size (%d,%d) for node \"%s\"\n", __func__, node->bbx, node->bby, node->name);
  9267. }
  9268. /* */ data = dp_free(data);
  9269. if (data) {
  9270. }
  9271. return;
  9272. }
  9273. /* translate \n \l \r in dot string
  9274. * todo \N and this is already done in dpif.c to check.
  9275. */
  9276. static char *unesc(char *str)
  9277. {
  9278. char *buf = NULL;
  9279. char *p = NULL;
  9280. char *q = NULL;
  9281. if (str == NULL) {
  9282. return (NULL);
  9283. }
  9284. if (strlen(str) == 0) {
  9285. return (str);
  9286. }
  9287. if (strchr(str, '\\') == NULL) {
  9288. /* string has no esc chars */
  9289. return (uniqstr(str));
  9290. }
  9291. buf = dp_calloc(1, (strlen(str) + 1));
  9292. p = str;
  9293. q = buf;
  9294. while (*p) {
  9295. /* check for \n \l \r to change */
  9296. if ((*p) == '\\') {
  9297. if (*(p + 1) == 'n' || *(p + 1) == 'l' || *(p + 1) == 'r') {
  9298. (*q) = '\n';
  9299. q++;
  9300. p++;
  9301. p++;
  9302. } else {
  9303. /* copy other esc char */
  9304. (*q) = (*p);
  9305. p++;
  9306. q++;
  9307. (*q) = (*p);
  9308. p++;
  9309. q++;
  9310. }
  9311. } else {
  9312. /* regular char to copy */
  9313. (*q) = (*p);
  9314. q++;
  9315. p++;
  9316. }
  9317. }
  9318. p = uniqstr(buf);
  9319. buf = dp_free(buf);
  9320. if (buf) {
  9321. }
  9322. return (p);
  9323. }
  9324. /* get size of one char *string */
  9325. static struct gml_p *static_maingtk_textsizes1str(char *str)
  9326. {
  9327. struct gml_p *ret = NULL;
  9328. cairo_surface_t *surface = NULL;
  9329. cairo_t *crdraw = NULL;
  9330. PangoLayout *layout = NULL;
  9331. PangoFontDescription *desc = NULL;
  9332. int w = 0;
  9333. int h = 0;
  9334. char buf[128];
  9335. char *s = NULL;
  9336. /* name of font to use, example "Sans" */
  9337. const char *default_fontname = DEFAULT_FONTNAME;
  9338. /* name of slant to use, example "Italic", "Oblique", "Roman" */
  9339. const char *default_fontslant = DEFAULT_FONTSLANT;
  9340. /* name of weight to use, example "Bold", "Book", "Light", "Medium", "Semi-bold", "Ultra-light" */
  9341. const char *default_fontweight = DEFAULT_FONTWEIGHT;
  9342. /* name of condensed to use, example "Semi-Condensed", "Condensed" */
  9343. const char *default_fontcondensed = DEFAULT_FONTCONDENSED;
  9344. /* font size to use, example "10", "18", "20" etc. */
  9345. const char *default_fontsize = DEFAULT_FONTSIZE;
  9346. /* return size in this */
  9347. ret = (struct gml_p *)dp_calloc(1, sizeof(struct gml_p));
  9348. if (str == NULL) {
  9349. /* shouldnothappen */
  9350. printf("%s(): nil str\n", __func__);
  9351. return (ret);
  9352. }
  9353. if (strlen(str) == 0) {
  9354. /* shouldnothappen */
  9355. printf("%s(): empty str\n", __func__);
  9356. return (ret);
  9357. }
  9358. /* calculate the text area */
  9359. if (surface == NULL) {
  9360. surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, 10, 10);
  9361. }
  9362. /* */
  9363. if (crdraw == NULL) {
  9364. crdraw = cairo_create(surface);
  9365. }
  9366. /* */
  9367. layout = pango_cairo_create_layout(crdraw);
  9368. /* set the text to draw which is 0 terminated */
  9369. pango_layout_set_text(layout, str, -1);
  9370. /* create the fontname description */
  9371. memset(buf, 0, (size_t)128);
  9372. /* name of font to use */
  9373. default_fontname = uniqstr((char *)DEFAULT_FONTNAME);
  9374. /* check if node has a specified font slant */
  9375. default_fontslant = uniqstr((char *)DEFAULT_FONTSLANT);
  9376. /* check if node has a specified font weight */
  9377. default_fontweight = uniqstr((char *)DEFAULT_FONTWEIGHT);
  9378. /* check if node has a specified font size */
  9379. default_fontsize = uniqstr((char *)DEFAULT_FONTSIZE);
  9380. /* create the font name string */
  9381. snprintf(buf, (size_t)(128 - 1), "%s %s %s %s %s",
  9382. default_fontname, default_fontslant, default_fontweight, default_fontcondensed, default_fontsize);
  9383. /* copy string buffer */
  9384. s = uniqstr(buf);
  9385. /* */
  9386. desc = pango_font_description_from_string(s);
  9387. /* */
  9388. pango_layout_set_font_description(layout, desc);
  9389. /* */
  9390. pango_font_description_free(desc);
  9391. /* */
  9392. pango_cairo_update_layout(crdraw, layout);
  9393. /* */
  9394. w = 0;
  9395. h = 0;
  9396. /* */
  9397. pango_layout_get_size(layout, &w, &h);
  9398. /* */
  9399. g_object_unref(G_OBJECT(layout));
  9400. /* */
  9401. if (option_gdebug > 1 || 0) {
  9402. printf("%s(): size (%d,%d) for string \"%s\"\n", __func__, (w / PANGO_SCALE), (h / PANGO_SCALE), str);
  9403. fflush(stdout);
  9404. }
  9405. ret->x = (w / PANGO_SCALE);
  9406. ret->y = (h / PANGO_SCALE);
  9407. /* clear the draw context etc */
  9408. if (layout) {
  9409. layout = NULL;
  9410. }
  9411. if (crdraw) {
  9412. cairo_destroy(crdraw);
  9413. crdraw = NULL;
  9414. }
  9415. if (surface) {
  9416. cairo_surface_destroy(surface);
  9417. surface = NULL;
  9418. }
  9419. return (ret);
  9420. }
  9421. /*zzz
  9422. * update the (x,y) size of text in the nodes
  9423. *
  9424. * a GTK font pattern. These have the syntax
  9425. * fontname [properties] [fontsize]
  9426. *
  9427. * where fontname is the family name,
  9428. * properties is a list of property values separated by spaces,
  9429. * and fontsize is the point size.
  9430. * The properties that you may specify for GTK font patterns are as follows:
  9431. * Slant properties: ‘Italic’ or ‘Oblique’. If omitted, the default (roman) slant is implied.
  9432. * Weight properties: ‘Bold’, ‘Book’, ‘Light’, ‘Medium’, ‘Semi-bold’, or ‘Ultra-light’. If omitted, ‘Medium’ weight is implied.
  9433. * Width properties: ‘Semi-Condensed’ or ‘Condensed’. If omitted, a default width is used.
  9434. * Here are some examples of GTK font patterns:
  9435. * Monospace 12
  9436. * Monospace Bold Italic 12
  9437. *
  9438. * there are nodes with labels whicj is a piece of text on display
  9439. * and nodes with a record type with multiple small text to layout
  9440. * in multiple steps for the different fields.
  9441. * if option labels is 0 then no label text is draw
  9442. */
  9443. static void static_maingtk_textsizes(void)
  9444. {
  9445. struct gml_p *sz = NULL;
  9446. int txname = 0;
  9447. int tyname = 0;
  9448. int bbxname = 0;
  9449. int bbyname = 0;
  9450. struct gml_ellist *elptr = NULL;
  9451. /* */
  9452. struct gml_nlist *nl = NULL;
  9453. int changed = 0;
  9454. /* only once determine edge label sizes */
  9455. if (maingraph->elsizes == 0) {
  9456. if (maingraph->ellist) {
  9457. /* edges with edge labels */
  9458. elptr = maingraph->ellist;
  9459. while (elptr) {
  9460. if (elptr->eledge) {
  9461. /* set size of edge label */
  9462. sz = static_maingtk_textsizes1str(elptr->eledge->elabel);
  9463. elptr->eledge->tx = sz->x;
  9464. elptr->eledge->ty = sz->y;
  9465. sz = (struct gml_p *)dp_free((struct gml_p *)sz);
  9466. if (sz) {
  9467. }
  9468. }
  9469. elptr = elptr->next;
  9470. }
  9471. }
  9472. /* all ready */
  9473. maingraph->elsizes = 1;
  9474. }
  9475. if (maingraph->nodesizes != 0) {
  9476. /* all done already */
  9477. return;
  9478. }
  9479. /* scan the regular node list */
  9480. changed = 0;
  9481. nl = maingraph->nodelist;
  9482. while (nl) {
  9483. if (nl->node) {
  9484. /* check the un-set */
  9485. if (nl->node->txsize == 0 || 0) {
  9486. changed++;
  9487. if (nl->node->dummy) {
  9488. /* dummynode has no text */
  9489. nl->node->tx = 0;
  9490. nl->node->ty = 0;
  9491. nl->node->bbx = 0;
  9492. nl->node->bby = 0;
  9493. nl->node->txsize = 1; /* text size is set */
  9494. } else {
  9495. /* first get size of node name */
  9496. if (nl->node->name == NULL) {
  9497. /* shouldnothapen */
  9498. nl->node->name = uniqstr((char *)"fixme-nil-node-name");
  9499. }
  9500. /* get size of node name */
  9501. sz = static_maingtk_textsizes1str(nl->node->name);
  9502. txname = sz->x;
  9503. tyname = sz->y;
  9504. /* for a box */
  9505. bbxname = txname + 4;
  9506. bbyname = tyname + 4;
  9507. sz = (struct gml_p *)dp_free((struct gml_p *)sz);
  9508. if (sz) {
  9509. }
  9510. /* change esc chars if any */
  9511. nl->node->nlabel = unesc(nl->node->nlabel);
  9512. sz = static_maingtk_textsizes1str(nl->node->nlabel);
  9513. /* set label text size */
  9514. nl->node->tx = sz->x;
  9515. nl->node->ty = sz->y;
  9516. nl->node->ftx = sz->x;
  9517. nl->node->fty = sz->y;
  9518. sz = (struct gml_p *)dp_free((struct gml_p *)sz);
  9519. if (sz) {
  9520. }
  9521. /* for a box */
  9522. nl->node->bbx = nl->node->tx + 4;
  9523. nl->node->bby = nl->node->ty + 4;
  9524. /* full sized copy */
  9525. nl->node->fbbx = nl->node->bbx;
  9526. nl->node->fbby = nl->node->bby;
  9527. if (option_gdebug > 1 || 0) {
  9528. printf("%s(): hlabel=%p done=%d and rlabel=%p done=%d\n", __func__,
  9529. (void *)nl->node->hlabel, nl->node->hlabeldone, (void *)nl->node->rlabel, nl->node->rlabeldone);
  9530. }
  9531. /* html label or record label */
  9532. if ((nl->node->hlabel != NULL) && (nl->node->hlabeldone == 0)) {
  9533. /* html label */
  9534. static_maingtk_textsizes1htmln(nl->node);
  9535. nl->node->hlabeldone = 1;
  9536. } else {
  9537. /* record node label */
  9538. if ((nl->node->rlabel != NULL) && (nl->node->rlabeldone == 0)) {
  9539. static_maingtk_textsizes1n(nl->node);
  9540. nl->node->rlabeldone = 1;
  9541. }
  9542. }
  9543. if (option_nnames == 1) {
  9544. /* use node names instead of labels and do not draw r/h style labels */
  9545. nl->node->drawrh = 0;
  9546. nl->node->tx = txname;
  9547. nl->node->ty = tyname;
  9548. /* for a box */
  9549. nl->node->bbx = bbxname;
  9550. nl->node->bby = bbyname;
  9551. } else {
  9552. nl->node->drawrh = 1;
  9553. }
  9554. /* label==0 then do not draw text label of a node and set small size */
  9555. if (option_labels == 0) {
  9556. nl->node->tx = 10;
  9557. nl->node->ty = 10;
  9558. /* for a box */
  9559. nl->node->bbx = nl->node->tx + 4;
  9560. nl->node->bby = nl->node->ty + 4;
  9561. /* keep fbbx and fbby intact */
  9562. }
  9563. nl->node->txsize = 1; /* text size is set */
  9564. }
  9565. } /* txsize */
  9566. } /* node */
  9567. /* next node in nodelist */
  9568. nl = nl->next;
  9569. }
  9570. if (changed == 0 || 0) {
  9571. maingraph->nodesizes = 1;
  9572. }
  9573. return;
  9574. }
  9575. /* do final (x,y) of nodes/edges for mode 1 todo should use absx */
  9576. static void finalxy1(struct gml_graph *g)
  9577. {
  9578. struct gml_nlist *lnl = NULL;
  9579. int hw = 0;
  9580. int xoff = 0;
  9581. int yoff = 0;
  9582. int i = 0;
  9583. int ecount = 0;
  9584. int tt = 0; /* only for a test absx,y is relative */
  9585. /* x positioning */
  9586. make_posnodes(maingraph);
  9587. maxx = 0;
  9588. xoff = 0;
  9589. /* scan hor. to adjust the x positions. */
  9590. for (i = 0; i < (g->widestnnodes + 1); i++) {
  9591. /* x spacing between the hor. levels */
  9592. xoff = xoff + xspacing;
  9593. /* determine half-way of the xpos. */
  9594. if (g->wpos[i] == 0) {
  9595. /* if only dummy nodes */
  9596. hw = xspacing / 2;
  9597. } else {
  9598. hw = (g->wpos[i] / 2);
  9599. }
  9600. /* update with current x */
  9601. hw = hw + xoff;
  9602. lnl = g->posnodes[i];
  9603. /* scan the nodes at this x pos. */
  9604. while (lnl) {
  9605. /* center the node around the half-way */
  9606. if (tt) {
  9607. /* test */
  9608. lnl->node->finx = lnl->node->absx;
  9609. } else {
  9610. lnl->node->finx = (hw - (lnl->node->bbx / 2));
  9611. }
  9612. if ((lnl->node->finx + lnl->node->bbx) > maxx) {
  9613. maxx = (lnl->node->finx + lnl->node->bbx);
  9614. }
  9615. lnl = lnl->next;
  9616. }
  9617. lnl = g->posnodes[i];
  9618. /* scan the nodes at this x pos. */
  9619. while (lnl) {
  9620. /* center the node around the half-way */
  9621. lnl->node->lx0 = xoff;
  9622. lnl->node->lx1 = xoff + g->wpos[i];
  9623. /* x size of level */
  9624. lnl->node->lxsize = g->wpos[i];
  9625. lnl = lnl->next;
  9626. }
  9627. /* x spacing between the hor. levels */
  9628. xoff = xoff + xspacing;
  9629. /* x to next pos. */
  9630. xoff = xoff + g->wpos[i];
  9631. }
  9632. clear_posnodes_r(maingraph);
  9633. /* y positioning */
  9634. make_levelnodes(maingraph);
  9635. maxy = 0;
  9636. yoff = 0;
  9637. /* number of edges between level n and n+1 */
  9638. g->nume = (int *)dp_calloc(1, (maingraph->maxlevel + 1) * sizeof(int));
  9639. /* scan vert. to adjust the y positions. */
  9640. for (i = 0; i < (maingraph->maxlevel + 1); i++) {
  9641. /* y spacing between the vert. levels */
  9642. yoff = yoff + (yspacing / 1);
  9643. /* determine half-way of the ypos. */
  9644. if (g->hpos[i] == 0) {
  9645. /* if only dummy nodes */
  9646. hw = (yspacing / 2);
  9647. } else {
  9648. hw = (g->hpos[i] / 2);
  9649. }
  9650. /* update with current y */
  9651. hw = hw + yoff;
  9652. lnl = g->levelnodes[i];
  9653. ecount = 0;
  9654. /* scan the nodes at this y pos. */
  9655. while (lnl) {
  9656. /* set start, end of y level */
  9657. lnl->node->ly0 = yoff;
  9658. /* used in drawing */
  9659. lnl->node->ly1 = (yoff + g->hpos[i]);
  9660. /* size of level y */
  9661. lnl->node->lysize = g->hpos[i];
  9662. /* center the node around the half-way */
  9663. if (tt) {
  9664. /* test */
  9665. lnl->node->finy = lnl->node->absy;
  9666. } else {
  9667. lnl->node->finy = (hw - (lnl->node->bby / 2));
  9668. }
  9669. /* update drawing max y pos used */
  9670. if ((lnl->node->finy + lnl->node->bby) > maxy) {
  9671. maxy = (lnl->node->finy + lnl->node->bby);
  9672. }
  9673. /* give dummy nodes a vertical size of the level */
  9674. if (lnl->node->dummy) {
  9675. lnl->node->bby = g->hpos[i];
  9676. /* if only dummy nodes at level, use spacing */
  9677. if (g->hpos[i] == 0) {
  9678. lnl->node->bby = yspacing;
  9679. }
  9680. }
  9681. /* number of edges between level n and n+1 */
  9682. ecount = (ecount + lnl->node->outdegree);
  9683. lnl = lnl->next;
  9684. }
  9685. /* number of edges between level n and n+1 */
  9686. g->nume[i] = ecount;
  9687. /* y spacing between the vert. levels */
  9688. yoff = yoff + (yspacing / 1);
  9689. /* yspacing depends on number of edges at this level
  9690. * turned off because this add too much y-spacing
  9691. * yoff = yoff + (ecount * 3);
  9692. */
  9693. /* yspacing depends on number of crossing edges at this level
  9694. * this has increasing y effect between levels
  9695. */
  9696. if (g->numce) {
  9697. yoff = yoff + (1 * (g->numce[i] / 8));
  9698. }
  9699. /* y to next pos. */
  9700. yoff = yoff + g->hpos[i];
  9701. }
  9702. clear_levelnodes_r(maingraph);
  9703. /* clear number of edges between level n and n+1 */
  9704. clear_nume_r(maingraph);
  9705. return;
  9706. }
  9707. /* for pos2.c which does set finx,finy */
  9708. static void finalxy2(struct gml_graph *g)
  9709. {
  9710. struct gml_nlist *lnl = NULL;
  9711. int my = 0;
  9712. maxx = 0;
  9713. maxy = 0;
  9714. /* adjust for the y size of single nodes */
  9715. if (g->nsinglenodes) {
  9716. my = 0;
  9717. lnl = maingraph->singlenodelist;
  9718. while (lnl) {
  9719. if (lnl->node->bby > my) {
  9720. my = lnl->node->bby;
  9721. }
  9722. lnl = lnl->next;
  9723. }
  9724. /* update level data for single nodes */
  9725. lnl = maingraph->singlenodelist;
  9726. while (lnl) {
  9727. lnl->node->ly0 = 0;
  9728. lnl->node->ly1 = my;
  9729. lnl = lnl->next;
  9730. }
  9731. } else {
  9732. /* no singlenodes, start at top of drawing */
  9733. my = 0;
  9734. }
  9735. /* determine max. x pos in use */
  9736. lnl = maingraph->nodelist;
  9737. while (lnl) {
  9738. /* adjust the non-singlenodes down */
  9739. if (lnl->node->indegree || lnl->node->outdegree) {
  9740. lnl->node->finy = lnl->node->finy + my;
  9741. lnl->node->ly0 = lnl->node->ly0 + my;
  9742. lnl->node->ly1 = lnl->node->ly1 + my;
  9743. }
  9744. if ((lnl->node->finx + lnl->node->bbx) > maxx) {
  9745. maxx = lnl->node->finx + lnl->node->bbx;
  9746. }
  9747. /* update drawing max y pos used */
  9748. if ((lnl->node->finy + lnl->node->bby) > maxy) {
  9749. maxy = (lnl->node->finy + lnl->node->bby);
  9750. }
  9751. lnl = lnl->next;
  9752. }
  9753. return;
  9754. }
  9755. /* for pos.c which does set absx,absy */
  9756. static void finalxy3(struct gml_graph *g)
  9757. {
  9758. struct gml_nlist *lnl = NULL;
  9759. /* recalc drawing size */
  9760. maxx = 0;
  9761. maxy = 0;
  9762. if (g == NULL) {
  9763. /* shouldnothappen */
  9764. return;
  9765. }
  9766. /* determine max. x pos in use */
  9767. lnl = maingraph->nodelist;
  9768. while (lnl) {
  9769. /* copy abs to fin */
  9770. lnl->node->finx = lnl->node->absx;
  9771. lnl->node->finy = lnl->node->absy;
  9772. if ((lnl->node->finx + lnl->node->bbx) > maxx) {
  9773. maxx = lnl->node->finx + lnl->node->bbx;
  9774. }
  9775. /* update drawing max y pos used */
  9776. if ((lnl->node->finy + lnl->node->bby) > maxy) {
  9777. maxy = (lnl->node->finy + lnl->node->bby);
  9778. }
  9779. lnl = lnl->next;
  9780. }
  9781. return;
  9782. }
  9783. /* for pos.c which does set absx,absy */
  9784. static void finalxy4(struct gml_graph *g)
  9785. {
  9786. struct gml_nlist *lnl = NULL;
  9787. printf("%s(): testing mode now\n", __func__);
  9788. /* recalc drawing size */
  9789. maxx = 0;
  9790. maxy = 0;
  9791. if (g == NULL) {
  9792. /* shouldnothappen */
  9793. return;
  9794. }
  9795. /* determine max. x pos in use */
  9796. lnl = maingraph->nodelist;
  9797. while (lnl) {
  9798. /* copy abs to fin */
  9799. lnl->node->finx = lnl->node->absx;
  9800. lnl->node->finy = lnl->node->absy;
  9801. if ((lnl->node->finx + lnl->node->bbx) > maxx) {
  9802. maxx = lnl->node->finx + lnl->node->bbx;
  9803. }
  9804. /* update drawing max y pos used */
  9805. if ((lnl->node->finy + lnl->node->bby) > maxy) {
  9806. maxy = (lnl->node->finy + lnl->node->bby);
  9807. }
  9808. lnl = lnl->next;
  9809. }
  9810. return;
  9811. }
  9812. static void finalxy(struct gml_graph *g)
  9813. {
  9814. struct gml_nlist *lnl = NULL;
  9815. int xpos = 0;
  9816. int my = 0;
  9817. /* depends on positioning modus */
  9818. /* if set use priority algorithm for placement otherwise brandes and kopf */
  9819. if (option_priority) {
  9820. }
  9821. switch (postype) {
  9822. case 1:
  9823. finalxy1(g);
  9824. break;
  9825. case 2:
  9826. finalxy2(g);
  9827. break;
  9828. case 3:
  9829. /* only raw positioning */
  9830. finalxy3(g);
  9831. break;
  9832. case 4: /* brandes kopf algorithm */
  9833. finalxy4(g);
  9834. break;
  9835. default:
  9836. printf("%s(): shouldnothappen\n", __func__);
  9837. finalxy1(g);
  9838. break;
  9839. }
  9840. /* position level 0, single nodes if any */
  9841. if (g->nsinglenodes) {
  9842. my = 0;
  9843. xpos = xspacing;
  9844. lnl = g->singlenodelist;
  9845. while (lnl) {
  9846. lnl->node->finx = xpos;
  9847. lnl->node->finy = 0;
  9848. /* position single nodes at level 0, just next to each other */
  9849. xpos = xpos + lnl->node->bbx + xspacing;
  9850. if (lnl->node->bby > my) {
  9851. my = lnl->node->bby;
  9852. }
  9853. if (xpos > maxx) {
  9854. maxx = xpos;
  9855. }
  9856. lnl = lnl->next;
  9857. }
  9858. }
  9859. return;
  9860. }
  9861. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  9862. /* XPM */
  9863. static const char *data_visualization_1_xpm[] = {
  9864. "50 50 119 2",
  9865. " c #FFFFFF",
  9866. ". c #ECECEC",
  9867. "+ c #B1B1B1",
  9868. "@ c #808080",
  9869. "# c #6C6C6C",
  9870. "$ c #898989",
  9871. "% c #C0C0C0",
  9872. "& c #F6F6F6",
  9873. "* c #BBBBBB",
  9874. "= c #1C1C1C",
  9875. "- c #000000",
  9876. "; c #474747",
  9877. "> c #DADADA",
  9878. ", c #222222",
  9879. "' c #DFDFDF",
  9880. ") c #606060",
  9881. "! c #C7C7C7",
  9882. "~ c #B9B9B9",
  9883. "{ c #383838",
  9884. "] c #666666",
  9885. "^ c #FCFCFC",
  9886. "/ c #F7F7F7",
  9887. "( c #E5E5E5",
  9888. "_ c #D9D9D9",
  9889. ": c #F1F1F1",
  9890. "< c #E4E4E4",
  9891. "[ c #F2F2F2",
  9892. "} c #7F7F7F",
  9893. "| c #989898",
  9894. "1 c #B6B6B6",
  9895. "2 c #E9E9E9",
  9896. "3 c #7E7E7E",
  9897. "4 c #767676",
  9898. "5 c #E3E3E3",
  9899. "6 c #6D6D6D",
  9900. "7 c #B2B2B2",
  9901. "8 c #ACACAC",
  9902. "9 c #EBEBEB",
  9903. "0 c #3D3D3D",
  9904. "a c #2E2E2E",
  9905. "b c #848484",
  9906. "c c #C2C2C2",
  9907. "d c #979797",
  9908. "e c #787878",
  9909. "f c #BFBFBF",
  9910. "g c #C6C6C6",
  9911. "h c #EAEAEA",
  9912. "i c #F9F9F9",
  9913. "j c #161616",
  9914. "k c #838383",
  9915. "l c #5F5F5F",
  9916. "m c #FDFDFD",
  9917. "n c #EFEFEF",
  9918. "o c #F8F8F8",
  9919. "p c #828282",
  9920. "q c #ADADAD",
  9921. "r c #424242",
  9922. "s c #9A9A9A",
  9923. "t c #CECECE",
  9924. "u c #9F9F9F",
  9925. "v c #818181",
  9926. "w c #FAFAFA",
  9927. "x c #F0F0F0",
  9928. "y c #868686",
  9929. "z c #535353",
  9930. "A c #555555",
  9931. "B c #939393",
  9932. "C c #AEAEAE",
  9933. "D c #D1D1D1",
  9934. "E c #878787",
  9935. "F c #777777",
  9936. "G c #404040",
  9937. "H c #CFCFCF",
  9938. "I c #A0A0A0",
  9939. "J c #A1A1A1",
  9940. "K c #3B3B3B",
  9941. "L c #D0D0D0",
  9942. "M c #757575",
  9943. "N c #565656",
  9944. "O c #585858",
  9945. "P c #5A5A5A",
  9946. "Q c #FBFBFB",
  9947. "R c #D8D8D8",
  9948. "S c #B4B4B4",
  9949. "T c #C1C1C1",
  9950. "U c #DEDEDE",
  9951. "V c #636363",
  9952. "W c #DBDBDB",
  9953. "X c #999999",
  9954. "Y c #858585",
  9955. "Z c #A7A7A7",
  9956. "` c #494949",
  9957. " . c #8C8C8C",
  9958. ".. c #8E8E8E",
  9959. "+. c #C8C8C8",
  9960. "@. c #8A8A8A",
  9961. "#. c #FEFEFE",
  9962. "$. c #B8B8B8",
  9963. "%. c #ABABAB",
  9964. "&. c #B5B5B5",
  9965. "*. c #C5C5C5",
  9966. "=. c #9D9D9D",
  9967. "-. c #5D5D5D",
  9968. ";. c #B7B7B7",
  9969. ">. c #353535",
  9970. ",. c #BEBEBE",
  9971. "'. c #656565",
  9972. "). c #EDEDED",
  9973. "!. c #BCBCBC",
  9974. "~. c #262626",
  9975. "{. c #E0E0E0",
  9976. "]. c #F3F3F3",
  9977. "^. c #454545",
  9978. "/. c #BDBDBD",
  9979. "(. c #4B4B4B",
  9980. "_. c #DDDDDD",
  9981. ":. c #323232",
  9982. "<. c #6E6E6E",
  9983. "[. c #A8A8A8",
  9984. " ",
  9985. " ",
  9986. " ",
  9987. " . + @ # $ % & ",
  9988. " * = - - - - - ; > ",
  9989. " * - - - - - - - - , ' ",
  9990. " . = - - ) ! > ~ { - - ] ^ ",
  9991. " + - - ) / ( , - - _ : < [ ",
  9992. " } - - ! | - - 1 2 3 - - - 4 5 ",
  9993. " 6 - - > 7 - - 8 9 0 - - - - - a 5 ",
  9994. " $ - - ~ b - - c d - - - - - - - e ",
  9995. " f - - { ( g - - - h i j - - - - - - - - [ ",
  9996. " & ; - - , | 7 k - - - l m n - - - - - - - - - ( ",
  9997. " > , - - - - - - - - - | ^ o = - - - - - - - - [ ",
  9998. " ' ] - - - - - l - - - | ^ ^ ] - - - - - - - p ",
  9999. " ^ _ 1 q c h m | - - - | ^ ^ d - - - - - - - r 2 ",
  10000. " ^ | - - - | ^ ^ d - - - ] = - j s . ",
  10001. " ^ | - - - d ^ i t u v v u t w ^ d - - - d ^ i x w ",
  10002. " ^ | - - - y z - - - - - - A y - - - d ^ ",
  10003. " m | - - - - - - - - - - - - - - B ^ ",
  10004. " ^ y - - - 0 C D D q 0 - - - E ^ ",
  10005. " w z - - F [ [ 4 - - A w ",
  10006. " t - - G [ [ 0 - - H ",
  10007. " u - - C q - - I ",
  10008. " v - - D D - - p ",
  10009. " v - - D D - - p ",
  10010. " u - - q 8 - - J ",
  10011. " t - - 0 [ : K - - L ",
  10012. " w A - - 4 [ : M - - N w ",
  10013. " ^ E - - - 0 q D D 8 K - - - E ^ ",
  10014. " m | - - - - - - - - - - - - - - B ^ ",
  10015. " ^ | - - - y O - - - - - - P y - - - | ^ ",
  10016. " ^ | - - - d ^ Q D 4 - - 4 D Q ^ d - - - | ^ ",
  10017. " m | - - - B ^ + - - + m | - - - B ^ ",
  10018. " ^ R S q T 2 m | - - - | ^ + - - + ^ | - - - | m 2 T q S R ^ ",
  10019. " U V - - - - - l - - - | ^ + - - + ^ | - - - l - - - - - V ' ",
  10020. " > , - - - - - - - - - | ^ + - - + ^ | - - - - - - - - - , W ",
  10021. " & ; - - , X 7 Y - - - l m Z - - Z m l - - - Y 7 X , - - ` / ",
  10022. " f - - { ( ! - - - 2 / .- - - - ../ 2 - - - +. ( { - - % ",
  10023. " $ - - ~ b - - c m @.- - - - - - .#. T - - Y $.- - @. ",
  10024. " 6 - - > 7 - - 8 > - - - - - - - - W %.- - 7 _ - - 6 ",
  10025. " } - - ! d - - 1 Z - - - - - - - - q &.- - s *.- - v ",
  10026. " 7 - - ) / < = - - > =.- - - - - - - - Z R - - , ( & -.- - 7 ",
  10027. " . = - - l g _ ;.>.- - ] ^ ,.- - - - - - - - ,. ^ '.- - { ~ _ *.-.- - , ). ",
  10028. " !.- - - - - - - - ~.{. ].^.- - - - - - ^.]. ' , - - - - - - - - ,. ",
  10029. " /., - - - - - (.W _.:.- - - - >._. W ` - - - - - , ,. ",
  10030. " ).7 v # @.% / x Z <.<.[.x / % @.# p 7 ). ",
  10031. " ",
  10032. " ",
  10033. " "
  10034. };
  10035. #endif
  10036. /* show about with ok button
  10037. * Android devices are “tyrants” says RMS
  10038. * https://www.gnu.org/philosophy/android-and-users-freedom.html
  10039. * So, Stallman was right ... again
  10040. * https://www.reddit.com/r/StallmanWasRight/
  10041. * https://letmegooglethat.com/?q=stallman+was+right+again
  10042. * This is not a android program and does not need camera, microphone, location, notifications or other anti-features
  10043. */
  10044. static void show_about_bare(void)
  10045. {
  10046. GtkWidget *dialog = NULL;
  10047. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  10048. GdkPixbuf *xpmdata = NULL;
  10049. #endif
  10050. int buflen = 0;
  10051. char *buf = NULL;
  10052. char *pbuf = NULL;
  10053. char *text0 = "This is a GML (Graph-Markup_Language) graph viewer program.\n"
  10054. "This program is free to share, copy, use, modify or fork.\n"
  10055. "This program does not have network telemetry or creates files.\n"
  10056. "This program does not want access to camera, microphone or location.\n"
  10057. "See gml4gtk at sourceforge.net\nemail: mooigraph AT gmail.com\n";
  10058. #ifdef WIN32
  10059. /* Linux software does not need a key but windows users seeem to need a product key. */
  10060. char *text1 = "Product key: B2X2W-DY9D9-YBP8R-G77WC-QB3QM";
  10061. #else
  10062. char *text1 = "Product Key: GNU-GPL-FREE-SOFT-WARE";
  10063. #endif
  10064. #if (GTK_HAVE_API_VERSION_4== 1)
  10065. /* a magyar étel finom és Ilona tökéletes */
  10066. const char *artist[] = { "ILona and her daughter from Hungary", NULL };
  10067. #endif
  10068. buflen = 512;
  10069. buf = dp_calloc(1, buflen);
  10070. /* reserve the last 0x00 space */
  10071. buflen--;
  10072. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  10073. dialog = gtk_about_dialog_new();
  10074. #endif
  10075. #if (GTK_HAVE_API_VERSION_2 == 1)
  10076. gtk_about_dialog_set_name(GTK_ABOUT_DIALOG(dialog), PACKAGE_NAME);
  10077. #endif
  10078. #if (GTK_HAVE_API_VERSION_3 == 1)
  10079. gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), PACKAGE_NAME);
  10080. #endif
  10081. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  10082. /* todo it seems this is depreciated. */
  10083. xpmdata = gdk_pixbuf_new_from_xpm_data(data_visualization_1_xpm);
  10084. gtk_about_dialog_set_logo(GTK_ABOUT_DIALOG(dialog), xpmdata);
  10085. gtk_about_dialog_set_version(GTK_ABOUT_DIALOG(dialog), PACKAGE_VERSION);
  10086. gtk_about_dialog_set_copyright(GTK_ABOUT_DIALOG(dialog), "Copyright is GNU GPL Version 3+, see http://www.gnu.org/");
  10087. #endif
  10088. snprintf(buf, (size_t)(buflen), "%sCompiled on %s\n", text0, COMPILE_DATE);
  10089. pbuf = buf + (int)(strlen(buf));
  10090. /* */
  10091. snprintf(pbuf, (size_t)(buflen - (int)(strlen(buf)) - 1), "%s\n", text1);
  10092. pbuf = buf + (int)(strlen(buf));
  10093. snprintf(pbuf, (size_t)(buflen - (int)(strlen(buf)) - 1), "compiled with gtk %d.%d.%d glib %d.%d.%d pango %s cairo %s\n",
  10094. GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION,
  10095. GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION, PANGO_VERSION_STRING, CAIRO_VERSION_STRING);
  10096. pbuf = buf + (int)(strlen(buf));
  10097. /* */
  10098. /* pango_version_string() and pango_version_string() are the versions at compile time, not run time */
  10099. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  10100. snprintf(pbuf, (size_t)(buflen - (int)(strlen(buf)) - 1), "running with gtk %d.%d.%d glib %d.%d.%d pango %s cairo %s\n",
  10101. gtk_major_version, gtk_minor_version, gtk_micro_version,
  10102. glib_major_version, glib_minor_version, glib_micro_version, pango_version_string(), cairo_version_string());
  10103. #endif
  10104. #if (GTK_HAVE_API_VERSION_4 == 1)
  10105. snprintf(pbuf, (size_t)(buflen - (int)(strlen(buf)) - 1), "running with gtk %u.%u.%u glib %d.%d.%d pango %s cairo %s\n",
  10106. gtk_get_major_version(), gtk_get_minor_version(), gtk_get_micro_version(),
  10107. (int)glib_major_version, (int)glib_minor_version, (int)glib_micro_version, pango_version_string(),
  10108. cairo_version_string());
  10109. #endif
  10110. pbuf = buf + (int)(strlen(buf));
  10111. snprintf(pbuf, (size_t)(buflen - (int)(strlen(buf)) - 1), "running with zlib version %s\n", zlibVersion());
  10112. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  10113. gtk_about_dialog_set_comments(GTK_ABOUT_DIALOG(dialog), buf);
  10114. gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), PACKAGE_URL);
  10115. /* suppress warning */
  10116. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  10117. gtk_dialog_run(GTK_DIALOG(dialog));
  10118. gtk_widget_destroy(dialog);
  10119. #endif
  10120. #if (GTK_HAVE_API_VERSION_4== 1)
  10121. dialog = gtk_about_dialog_new();
  10122. gtk_about_dialog_set_program_name(GTK_ABOUT_DIALOG(dialog), PACKAGE_STRING);
  10123. gtk_about_dialog_set_website(GTK_ABOUT_DIALOG(dialog), PACKAGE_URL);
  10124. gtk_about_dialog_set_website_label(GTK_ABOUT_DIALOG(dialog), PACKAGE_URL);
  10125. gtk_about_dialog_set_license_type(GTK_ABOUT_DIALOG(dialog), GTK_LICENSE_GPL_3_0);
  10126. gtk_about_dialog_set_system_information(GTK_ABOUT_DIALOG(dialog), buf);
  10127. gtk_about_dialog_set_artists(GTK_ABOUT_DIALOG(dialog), artist);
  10128. /* suppress warning */
  10129. gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(mainwindow1));
  10130. gtk_widget_show(dialog);
  10131. #endif
  10132. buf = dp_free(buf);
  10133. if (buf) {
  10134. }
  10135. return;
  10136. }
  10137. #if (GTK_HAVE_API_VERSION_2 == 1) || (GTK_HAVE_API_VERSION_3 == 1)
  10138. /* show about with ok button */
  10139. static void show_about(GtkWidget * widget, gpointer data)
  10140. {
  10141. if (widget) {
  10142. }
  10143. if (data) {
  10144. }
  10145. show_about_bare();
  10146. return;
  10147. }
  10148. #endif
  10149. /* end */