gcsx_sceneeditlayer.cpp 165 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374
  1. /* GCSx
  2. ** SCENEEDITLAYER.CPP
  3. **
  4. ** Scene editing- tile layers
  5. */
  6. /*****************************************************************************
  7. ** Copyright (C) 2003-2006 Janson
  8. **
  9. ** This program is free software; you can redistribute it and/or modify
  10. ** it under the terms of the GNU General Public License as published by
  11. ** the Free Software Foundation; either version 2 of the License, or
  12. ** (at your option) any later version.
  13. **
  14. ** This program is distributed in the hope that it will be useful,
  15. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. ** GNU General Public License for more details.
  18. **
  19. ** You should have received a copy of the GNU General Public License
  20. ** along with this program; if not, write to the Free Software
  21. ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  22. *****************************************************************************/
  23. #include "all.h"
  24. // Tool panel
  25. const ToolSelect::ToolIconStruct SceneEditLayerTools::toolIcons[TOOLSELECT_NUM_TOOLS] = {
  26. { TOOLS_PEN, 0, 0, "Draw (place tile or pattern)" },
  27. { TOOLS_LINE, 20, 0, "Straight line" },
  28. { TOOLS_DROPPER, 40, 40, "Dropper (grab tile or pattern)" },
  29. { TOOLS_FILL, 80, 0, "Flood fill" },
  30. { TOOLS_RECT, 80, 60, "Rectangle (outline)" },
  31. { TOOLS_RECTFILL, 40, 0, "Rectangle (filled)" },
  32. { TOOLS_ELLIPSE, 40, 80, "Ellipse (outline)" },
  33. { TOOLS_ELLIPSEFILL, 60, 0, "Ellipse (filled)" },
  34. { TOOLS_SELECT, 0, 20, "Select area (rectangle)" },
  35. { TOOLS_SELECTELLIPSE, 20, 20, "Select area (ellipse)" },
  36. { TOOLS_WAND, 40, 20, "Magic wand (select area by tile)" },
  37. { TOOLS_SELECTITEM, 0, 120, "Select/modify sprite(s)" },
  38. { TOOLS_PLACEITEM, 80, 100, "Place new sprite" },
  39. { TOOLS_PLACESERIES, 80, 120, "Place multiple sprites" },
  40. };
  41. FrameWindow* SceneEditLayerTools::createWindowed() { start_func
  42. // Prevent duplication
  43. if (myFrame) {
  44. return myFrame;
  45. }
  46. // We remember the frame pointer even though it'll delete itself
  47. myFrame = new FrameWindow("Tools", FrameWindow::RESIZING_SNAP, FrameWindow::FRAMETYPE_DIALOG, this, FrameWindow::TITLEBAR_TOOL, 0);
  48. return myFrame;
  49. }
  50. Window::WindowSort SceneEditLayerTools::windowSort() const { start_func
  51. return WINDOWSORT_ONTOP;
  52. }
  53. void SceneEditLayerTools::adjustForTool() { start_func
  54. WCheckBox* check = dynamic_cast<WCheckBox*>(findWidget(ID_CONTIGUOUS));
  55. if ((*toolLPtr == TOOLS_WAND) || (*toolLPtr == TOOLS_FILL) || (*toolRPtr == TOOLS_WAND) || (*toolRPtr == TOOLS_FILL)) {
  56. check->enable();
  57. }
  58. else {
  59. check->disable();
  60. }
  61. paintArea->newToolSelected();
  62. }
  63. int SceneEditLayerTools::event(int hasFocus, const SDL_Event* event) { start_func
  64. if (event->type == SDL_COMMAND) {
  65. // Simple cases
  66. switch (event->user.code) {
  67. case VIEW_GRID:
  68. *gridPtr = *gridPtr ? 0 : 1;
  69. findWidget(ID_GRID)->load();
  70. paintArea->refresh();
  71. config->write(LAYEREDIT_GRID, *gridPtr);
  72. return 1;
  73. case TOOLS_CONTIGUOUS:
  74. *contiguousPtr = *contiguousPtr ? 0 : 1;
  75. findWidget(ID_CONTIGUOUS)->load();
  76. return 1;
  77. }
  78. // Choose tool
  79. int newToolL = 0;
  80. int newToolR = 0;
  81. WButton* toolButtonL = dynamic_cast<WButton*>(findWidget(ID_TOOLL));
  82. WButton* toolButtonR = dynamic_cast<WButton*>(findWidget(ID_TOOLR));
  83. int x, y;
  84. int modeSwap = 0;
  85. if (event->user.code == TOOLS_CHOOSE) {
  86. newToolL = toolSelect->run(toolButtonL->getScreenX(), toolButtonL->getScreenY() + toolButtonL->getHeight());
  87. }
  88. else if (event->user.code == TOOLS_CHOOSER) {
  89. newToolR = toolSelect->run(toolButtonR->getScreenX(), toolButtonR->getScreenY() + toolButtonR->getHeight());
  90. }
  91. else if (toolSelect->isTool(event->user.code)) {
  92. newToolL = event->user.code;
  93. paintArea->startToolIfMove();
  94. }
  95. if ((newToolL) || (newToolR)) {
  96. int targetToolL = *toolLPtr;
  97. int targetToolR = *toolRPtr;
  98. if (newToolL) targetToolL = newToolL;
  99. if (newToolR) targetToolR = newToolR;
  100. // Mode swap?
  101. if ((targetToolL == TOOLS_PLACEITEM) || (targetToolL == TOOLS_PLACESERIES) || (targetToolL == TOOLS_SELECTITEM)) {
  102. if ((targetToolR != TOOLS_PLACEITEM) && (targetToolR != TOOLS_PLACESERIES) && (targetToolR != TOOLS_SELECTITEM)) {
  103. modeSwap = 1;
  104. }
  105. }
  106. else {
  107. if ((targetToolR == TOOLS_PLACEITEM) || (targetToolR == TOOLS_PLACESERIES) || (targetToolR == TOOLS_SELECTITEM)) {
  108. modeSwap = 1;
  109. }
  110. }
  111. if (modeSwap) {
  112. swap(*toolLPtr, otherModeToolL);
  113. swap(*toolRPtr, otherModeToolR);
  114. }
  115. if (newToolL) *toolLPtr = newToolL;
  116. if (newToolR) *toolRPtr = newToolR;
  117. if (toolSelect->getToolIcon(*toolLPtr, x, y)) toolButtonL->changeIcon(x, y);
  118. if (toolSelect->getToolIcon(*toolRPtr, x, y)) toolButtonR->changeIcon(x, y);
  119. adjustForTool();
  120. return 1;
  121. }
  122. if ((event->user.code == TOOLS_CHOOSE) || (event->user.code == TOOLS_CHOOSER)) return 1;
  123. }
  124. return Dialog::event(hasFocus, event);
  125. }
  126. void SceneEditLayerTools::childModified(Window* modified) { start_func
  127. Dialog::childModified(modified);
  128. Widget* widget = dynamic_cast<Widget*>(modified);
  129. if (widget) {
  130. // If certain settings modified, tile area needs to refresh
  131. if (widget->getId() == ID_GRID) {
  132. paintArea->refresh();
  133. }
  134. // Save config settings
  135. config->write(LAYEREDIT_GRID, *gridPtr);
  136. }
  137. }
  138. int SceneEditLayerTools::wantsToBeDeleted() const { start_func
  139. return 1;
  140. }
  141. SceneEditLayerTools::~SceneEditLayerTools() { start_func
  142. delete toolSelect;
  143. }
  144. SceneEditLayerTools::SceneEditLayerTools(SceneEditLayer* tPaintArea, int* toolL, int* toolR, int* contiguous, int* grid) : Dialog(blankString, 1, 0, 1) { start_func
  145. paintArea = tPaintArea;
  146. toolLPtr = toolL;
  147. toolRPtr = toolR;
  148. contiguousPtr = contiguous;
  149. gridPtr = grid;
  150. // Other-mode tools based on currently selected tool
  151. if ((*toolL == TOOLS_PLACEITEM) || (*toolL == TOOLS_PLACESERIES) || (*toolL == TOOLS_SELECTITEM)) {
  152. otherModeToolL = TOOLS_PEN;
  153. }
  154. else {
  155. otherModeToolL = TOOLS_PLACESERIES;
  156. }
  157. if ((*toolR == TOOLS_PLACEITEM) || (*toolR == TOOLS_PLACESERIES) || (*toolR == TOOLS_SELECTITEM)) {
  158. otherModeToolR = TOOLS_DROPPER;
  159. }
  160. else {
  161. otherModeToolR = TOOLS_SELECTITEM;
  162. }
  163. Widget* w = NULL;
  164. myFrame = NULL;
  165. toolSelect = new ToolSelect(getIconSurface(), TOOLSELECT_NUM_TOOLS, toolIcons);
  166. int x = 0;
  167. int y = 0;
  168. toolSelect->getToolIcon(*toolLPtr, x, y);
  169. w = new WButton(ID_TOOLL, getIconSurface(), x, y, 20, 20, Dialog::BUTTON_NOTHING, TOOLS_CHOOSE);
  170. w->setToolTip("Change tool (left button)");
  171. w->addTo(this);
  172. x = y = 0;
  173. toolSelect->getToolIcon(*toolRPtr, x, y);
  174. w = new WButton(ID_TOOLR, getIconSurface(), x, y, 20, 20, Dialog::BUTTON_NOTHING, TOOLS_CHOOSER);
  175. w->setToolTip("Change tool (right button)");
  176. w->addTo(this);
  177. w = new WCheckBox(ID_CONTIGUOUS, "Contiguous", contiguous, 1);
  178. w->setToolTip("Only flood-fill or wand-select a single, connected area");
  179. w->addTo(this);
  180. arrangeRow();
  181. w = new WButton(ID_COPY, getIconSurface(), 60, 20, 20, 20, Dialog::BUTTON_NOTHING, EDIT_COPY);
  182. w->setToolTip("Copy");
  183. w->addTo(this);
  184. w = new WButton(ID_PASTE, getIconSurface(), 80, 20, 20, 20, Dialog::BUTTON_NOTHING, EDIT_PASTE);
  185. w->setToolTip("Paste (as new selection)");
  186. w->addTo(this);
  187. w = new WCheckBox(ID_GRID, getIconSurface(), 0, 100, 20, 20, grid, 1);
  188. w->setToolTip("Show or hide grid");
  189. w->addTo(this);
  190. arrangeRow();
  191. adjustForTool();
  192. runAsPanel();
  193. }
  194. // Layer panel
  195. FrameWindow* SceneEditLayerList::createWindowed() { start_func
  196. // Prevent duplication
  197. if (myFrame) {
  198. return myFrame;
  199. }
  200. // We remember the frame pointer even though it'll delete itself
  201. myFrame = new FrameWindow("Layers", FrameWindow::RESIZING_SNAP, FrameWindow::FRAMETYPE_DIALOG, this, FrameWindow::TITLEBAR_TOOL, 0);
  202. return myFrame;
  203. }
  204. Window::WindowSort SceneEditLayerList::windowSort() const { start_func
  205. return WINDOWSORT_ONTOP;
  206. }
  207. int SceneEditLayerList::event(int hasFocus, const SDL_Event* event) { start_func
  208. if (event->type == SDL_COMMAND) {
  209. // Simple cases
  210. switch (event->user.code) {
  211. case VIEW_ALLLAYER:
  212. case VIEW_DIMLAYER:
  213. case VIEW_NOLAYER:
  214. case VIEW_PREV:
  215. case VIEW_NEXT:
  216. return layerList->event(0, event);
  217. }
  218. }
  219. return Dialog::event(hasFocus, event);
  220. }
  221. void SceneEditLayerList::childModified(Window* modified) { start_func
  222. Dialog::childModified(modified);
  223. Widget* widget = dynamic_cast<Widget*>(modified);
  224. if (widget) {
  225. // Layer visibility/selection
  226. if (widget == layerList) {
  227. paintArea->refreshLayers();
  228. }
  229. }
  230. }
  231. int SceneEditLayerList::wantsToBeDeleted() const { start_func
  232. return 1;
  233. }
  234. SceneEditLayerList::~SceneEditLayerList() { start_func
  235. }
  236. SceneEditLayerList::SceneEditLayerList(SceneEditLayer* tPaintArea) : Dialog(blankString, 1, 0, 1) { start_func
  237. paintArea = tPaintArea;
  238. Widget* w = NULL;
  239. myFrame = NULL;
  240. w = layerList = new WLayerListBox(ID_LAYER, &selectedLayer);
  241. // @TODO: More specific tooltips
  242. w->setToolTip("Select which layer(s) to view and edit");
  243. w->addTo(this);
  244. arrangeRow();
  245. w = new WButton(ID_LAYERADD, "Add...", Dialog::BUTTON_NOTHING, NEW_LAYER);
  246. w->setToolTip("Add a new layer");
  247. w->addTo(this);
  248. arrangeRow();
  249. runAsPanel();
  250. }
  251. // Sprite panel
  252. FrameWindow* SceneEditSpriteList::createWindowed() { start_func
  253. // Prevent duplication
  254. if (myFrame) {
  255. return myFrame;
  256. }
  257. // We remember the frame pointer even though it'll delete itself
  258. myFrame = new FrameWindow("Objects", FrameWindow::RESIZING_SNAP, FrameWindow::FRAMETYPE_DIALOG, this, FrameWindow::TITLEBAR_TOOL, 0);
  259. return myFrame;
  260. }
  261. Window::WindowSort SceneEditSpriteList::windowSort() const { start_func
  262. return WINDOWSORT_ONTOP;
  263. }
  264. int SceneEditSpriteList::wantsToBeDeleted() const { start_func
  265. return 1;
  266. }
  267. SceneEditSpriteList::~SceneEditSpriteList() { start_func
  268. if (spriteList) {
  269. WidgetScroll* ws = dynamic_cast<WidgetScroll*>(spriteList->getParent());
  270. if (ws) ws->newClient();
  271. delete spriteList;
  272. }
  273. }
  274. SceneEditSpriteList::SceneEditSpriteList(SceneEditLayer* tPaintArea, WorldEdit* tWorld) : Dialog(blankString, 1, 0, 1) { start_func
  275. paintArea = tPaintArea;
  276. world = tWorld;
  277. buildingList = 0;
  278. myFrame = NULL;
  279. spriteList = new TreeView(blankString, NULL, 0, NULL, 1);
  280. buildSpriteList();
  281. // @TODO: add ::event and catch add/delete scripts
  282. buildingList = 1;
  283. spriteList->addTo(this, -1, 6);
  284. buildingList = 0;
  285. // @TODO: Tooltips
  286. arrangeRow();
  287. runAsPanel();
  288. }
  289. void SceneEditSpriteList::buildSpriteList() { start_func
  290. TreeView* scripts;
  291. TreeView* item;
  292. buildingList = 1;
  293. spriteList->insert(scripts = new TreeView("(custom object)", this, 1, treeViewWrapOther), 0);
  294. // @TODO: spriteList->insert(new TreeView("Libraries", this, 0, treeViewWrapOther), 0);
  295. // @TODO: spriteList->insert(new TreeView("Recent", this, 0, treeViewWrapOther), 0);
  296. spriteList->insert(scripts = new TreeView("Scripts", this, 0, treeViewWrapOther), 0);
  297. // @TODO: spriteList->insert(new TreeView("Used in Scene", this, 0, treeViewWrapOther), 0);
  298. World::ScriptIndex::const_iterator end = world->endScript();
  299. for (World::ScriptIndex::const_iterator pos = world->beginScript(); pos != end; ++pos) {
  300. ScriptEdit* script = dynamic_cast<ScriptEdit*>((*pos).second);
  301. if (script->getType() == Script::SCRIPT_CODE) {
  302. scripts->insert(item = new TreeView(script->getName(), this, script->getId(), treeViewWrapScript), 0);
  303. item->setIcon(script->getDefaultId() ? 13 : 12);
  304. }
  305. }
  306. buildingList = 0;
  307. }
  308. int SceneEditSpriteList::treeViewWrapScript(void* ptr, int code, int command, int check) { start_func
  309. return ((SceneEditSpriteList*)ptr)->treeViewScript(code, command, check);
  310. }
  311. int SceneEditSpriteList::treeViewScript(int code, int command, int check) { start_func
  312. if (check) {
  313. return Window::COMMAND_HIDE;
  314. }
  315. if (buildingList) return 0;
  316. if ((command == LV_MOVE) || (command == LV_LCLICK)) {
  317. ScriptEdit* script = dynamic_cast<ScriptEdit*>(world->findScript(code));
  318. if (script) {
  319. SpawnEdit* newSpawn = new SpawnEdit(world, NULL);
  320. newSpawn->markLock();
  321. newSpawn->setName(script->getName());
  322. newSpawn->setScript(script);
  323. newSpawn->setSprite(script->getDefaultAnimgroup(), script->getDefaultTileset(),
  324. script->getDefaultId());
  325. paintArea->setSpawnPlace(newSpawn);
  326. }
  327. return 1;
  328. }
  329. return 0;
  330. }
  331. int SceneEditSpriteList::treeViewWrapOther(void* ptr, int code, int command, int check) { start_func
  332. return ((SceneEditSpriteList*)ptr)->treeViewOther(code, command, check);
  333. }
  334. int SceneEditSpriteList::treeViewOther(int code, int command, int check) { start_func
  335. if (check) {
  336. return Window::COMMAND_HIDE;
  337. }
  338. if (buildingList) return 0;
  339. if ((command == LV_MOVE) || (command == LV_LCLICK)) {
  340. if (code == 1) {
  341. // Blank starting point
  342. SpawnEdit* newSpawn = new SpawnEdit(world, NULL);
  343. newSpawn->markLock();
  344. paintArea->setSpawnPlace(newSpawn);
  345. }
  346. return 1;
  347. }
  348. return 0;
  349. }
  350. // Main edit window
  351. SceneEditLayer::SceneEditLayer(SceneEdit* myScene) : selectedSpawns(), backupSelectedSpawns() throw_File { start_func
  352. assert(myScene);
  353. cursorX = cursorY = virtualCursorX = virtualCursorY = 0;
  354. cursorSpriteX = cursorSpriteY = 0;
  355. cursorW = cursorH = 1;
  356. haveFocus = partialFocus = 0;
  357. toolActive = startToolOnMove = 0;
  358. dirtyRange.w = 0;
  359. selectionRect.w = 0;
  360. selectionMode = SELECTION_OUTLINE;
  361. selectionXOffs = 0;
  362. selectionYOffs = 0;
  363. selectedSpawnRect.w = 0;
  364. backupSelectedSpawnRect.w = 0;
  365. scene = myScene;
  366. world = scene->getWorldEdit();
  367. scene->markLock(); // Exception point
  368. // Intentionally doesn't remember last tool selected
  369. // If we ever do, we must ensure both tools in this startup position
  370. // are sprite or non-sprite tools
  371. toolL = TOOLS_PEN;
  372. toolR = TOOLS_DROPPER;
  373. spriteMode = 0;
  374. spriteShown = 0;
  375. spriteAtCursor = 0;
  376. spawnPlace = new SpawnEdit(world, NULL);
  377. spawnPlace->markLock();
  378. spawnPropertiesDone = 0;
  379. contiguous = 1;
  380. // Recall last settings
  381. enableGrid = config->readNum(LAYEREDIT_GRID) ? 1 : 0;
  382. myFrame = NULL;
  383. tools = NULL;
  384. imagebar = NULL;
  385. colorbar = NULL;
  386. layerlist = NULL;
  387. spritelist = NULL;
  388. selected = NULL;
  389. backupSelected = NULL;
  390. for (int pos = 0; pos < MAX_LAYERS; ++pos) {
  391. layerEdit[pos][0] = NULL;
  392. layerEdit[pos][1] = NULL;
  393. layerEdit[pos][2] = NULL;
  394. }
  395. FrameWindow* toolsFrame = NULL;
  396. FrameWindow* imagebarFrame = NULL;
  397. FrameWindow* colorbarFrame = NULL;
  398. FrameWindow* layerlistFrame = NULL;
  399. FrameWindow* spritelistFrame = NULL;
  400. try {
  401. // Init frame up here so reloadLayerStats sets it's scroll size properly
  402. myFrame = new FrameWindow(blankString, FrameWindow::RESIZING_NORMAL, FrameWindow::FRAMETYPE_BEVEL_BK, this);
  403. myFrame->setAutoCenter(1);
  404. // First call to this determines our cursor layer
  405. initAvailableLayers();
  406. reloadLayerStats(1);
  407. refreshData(0);
  408. LayerEdit* layer = scene->getLayerEdit(cursorLayer);
  409. TileSetEdit* tileset = layer->getTileSetEdit();
  410. imagebar = new ImageSelect(tileset, &colors); // One exception point (others?)
  411. colorbar = new ColorSelect(&colors, 0, 0, Layer::LAYER_EXT_ALPHA_BITDEPTH, Layer::LAYER_TILE_COLOR_BITDEPTH);
  412. tools = new SceneEditLayerTools(this, &toolL, &toolR, &contiguous, &enableGrid);
  413. layerlist = new SceneEditLayerList(this);
  414. spritelist = new SceneEditSpriteList(this, world);
  415. setUsesExt(layerExt);
  416. imagebarFrame = imagebar->createWindowed();
  417. colorbarFrame = colorbar->createWindowed();
  418. toolsFrame = tools->createWindowed();
  419. layerlistFrame = layerlist->createWindowed();
  420. spritelistFrame = spritelist->createWindowed();
  421. // Second call to this fills our layer list
  422. initAvailableLayers();
  423. updateTitlebar();
  424. myFrame->addToolPanel(imagebarFrame, FrameWindow::CLIENT_BOTTOM);
  425. myFrame->addToolPanel(colorbarFrame, FrameWindow::CLIENT_RIGHT);
  426. myFrame->addToolPanel(toolsFrame, FrameWindow::CLIENT_RIGHT);
  427. myFrame->addToolPanel(layerlistFrame, FrameWindow::CLIENT_RIGHT);
  428. myFrame->addToolPanel(spritelistFrame, FrameWindow::CLIENT_RIGHT);
  429. myFrame->show(FrameWindow::SHOW_CASCADE, FrameWindow::SHOW_CASCADE, FrameWindow::SHOW_CURRENT, FrameWindow::SHOW_CURRENT);
  430. imagebar->colorRefresh();
  431. }
  432. catch (...) {
  433. if (myFrame) {
  434. myFrame->dropClients();
  435. delete myFrame;
  436. myFrame = NULL;
  437. }
  438. if (spritelistFrame) {
  439. delete spritelistFrame;
  440. }
  441. else {
  442. delete spritelist;
  443. }
  444. if (layerlistFrame) {
  445. delete layerlistFrame;
  446. }
  447. else {
  448. delete layerlist;
  449. }
  450. if (toolsFrame) {
  451. delete toolsFrame;
  452. }
  453. else {
  454. delete tools;
  455. }
  456. if (colorbarFrame) {
  457. delete colorbarFrame;
  458. }
  459. else {
  460. delete colorbar;
  461. }
  462. if (imagebarFrame) {
  463. delete imagebarFrame;
  464. }
  465. else {
  466. delete imagebar;
  467. }
  468. for (int pos = 0; pos < MAX_LAYERS; ++pos) {
  469. delete[] layerEdit[pos][0];
  470. delete[] layerEdit[pos][1];
  471. delete[] layerEdit[pos][2];
  472. }
  473. delete[] selected;
  474. delete[] backupSelected;
  475. scene->markUnlock();
  476. throw;
  477. }
  478. // Disabled/etc status on various tools
  479. updateCopyTool();
  480. }
  481. SceneEditLayer::~SceneEditLayer() { start_func
  482. for (int pos = 0; pos < MAX_LAYERS; ++pos) {
  483. delete[] layerEdit[pos][0];
  484. delete[] layerEdit[pos][1];
  485. delete[] layerEdit[pos][2];
  486. }
  487. delete[] selected;
  488. delete[] backupSelected;
  489. delete spawnPlace;
  490. if (scene) scene->markUnlock();
  491. }
  492. void SceneEditLayer::updateCopyTool() { start_func
  493. if ((selectionRect.w) || (selectedSpawnRect.w)) tools->findWidget(SceneEditLayerTools::ID_COPY)->enable();
  494. else tools->findWidget(SceneEditLayerTools::ID_COPY)->disable();
  495. }
  496. void SceneEditLayer::setSpawnPlace(class SpawnEdit* newSpawn) {
  497. delete spawnPlace;
  498. spawnPlace = newSpawn;
  499. spawnPropertiesDone = 0;
  500. if ((toolL != TOOLS_PLACEITEM) && (toolR != TOOLS_PLACEITEM) &&
  501. (toolL != TOOLS_PLACESERIES) && (toolR != TOOLS_PLACESERIES)) {
  502. desktop->broadcastEvent(SDL_COMMAND, TOOLS_PLACEITEM);
  503. desktop->broadcastEvent(SDL_COMMAND, CMD_RELEASE);
  504. }
  505. // @TODO: Dirty sprite area only
  506. setDirty(1);
  507. }
  508. void SceneEditLayer::setDirtyRect(const Rect& rect, int selectionFeather) { start_func
  509. // Clip
  510. Rect bound = { 0, 0, layerWidth, layerHeight };
  511. if (intersectRects(bound, rect)) {
  512. // Scale to tile size
  513. bound.x *= tileWidth;
  514. bound.y *= tileHeight;
  515. bound.w *= tileWidth;
  516. bound.h *= tileHeight;
  517. // Feather for selection modification?
  518. if (selectionFeather) {
  519. if (bound.x > 0) {
  520. --bound.x;
  521. ++bound.w;
  522. }
  523. if (bound.y > 0) {
  524. --bound.y;
  525. ++bound.h;
  526. }
  527. // We don't bother checking if our w/h goes over the limit-
  528. // this will get clipped; but negative x/y is too odd to allow, above
  529. ++bound.w;
  530. ++bound.h;
  531. }
  532. // Add rectangle into dirty range
  533. boundRects(dirtyRange, bound);
  534. setDirty();
  535. }
  536. }
  537. void SceneEditLayer::setDirtyBox(int x1, int y1, int x2, int y2, int selectionFeather) { start_func
  538. // Create a rectangle
  539. // Add rectangle into dirty range
  540. setDirtyRect(createRect(x1, y1, x2, y2), selectionFeather);
  541. }
  542. void SceneEditLayer::setDirtyPixelBox(int x1, int y1, int x2, int y2) { start_func
  543. boundRects(dirtyRange, createRect(x1, y1, x2, y2));
  544. setDirty();
  545. }
  546. void SceneEditLayer::setUsesExt(int usesExt) { start_func
  547. if (colorbar) colorbar->alphaDepth(usesExt ? Layer::LAYER_EXT_ALPHA_BITDEPTH : 0);
  548. if (imagebar) imagebar->allowAlpha(usesExt);
  549. }
  550. void SceneEditLayer::siblingModified(Window* modified) { start_func
  551. // Img selector updates with any color change
  552. if (modified == colorbar) {
  553. if (imagebar) imagebar->colorRefresh();
  554. }
  555. }
  556. // Note: any change to this function may need to also propogate to OBJMOD_TILES handler (+ OBJMOD_COLL?)
  557. void SceneEditLayer::refreshData(int cursorLayerOnly, int x1, int y1, int x2, int y2) { start_func
  558. assert(scene);
  559. Rect affect = createRect(x1, y1, x2, y2);
  560. Rect bound = { 0, 0, layerWidth, layerHeight };
  561. if (!intersectRects(affect, bound)) return;
  562. Uint32 bit = 1;
  563. int pos = 0;
  564. int max = numLayers - 1;
  565. if (cursorLayerOnly) {
  566. pos = max = cursorLayer;
  567. if (pos) bit <<= pos;
  568. }
  569. for (; pos <= max; ++pos, bit <<= 1) {
  570. if (layersAffect & bit) {
  571. scene->getLayerEdit(pos)->loadLayer(layerEdit[pos][0] + affect.x + affect.y * layerWidth,
  572. layerEdit[pos][1] + affect.x + affect.y * layerWidth,
  573. layerEdit[pos][2] + affect.x + affect.y * layerWidth,
  574. layerWidth, affect);
  575. }
  576. }
  577. }
  578. void SceneEditLayer::applyData(int cursorLayerOnly, int x1, int y1, int x2, int y2) { start_func
  579. assert(scene);
  580. Rect affect = createRect(x1, y1, x2, y2);
  581. Rect bound = { 0, 0, layerWidth, layerHeight };
  582. if (!intersectRects(affect, bound)) return;
  583. Uint32 bit = 1;
  584. int pos = 0;
  585. int max = numLayers - 1;
  586. if (cursorLayerOnly) {
  587. pos = max = cursorLayer;
  588. if (pos) bit <<= pos;
  589. }
  590. for (; pos <= max; ++pos, bit <<= 1) {
  591. if (layersAffect & bit) {
  592. scene->getLayerEdit(pos)->saveLayer(layerEdit[pos][0] + affect.x + affect.y * layerWidth,
  593. layerEdit[pos][1] + affect.x + affect.y * layerWidth,
  594. layerEdit[pos][2] + affect.x + affect.y * layerWidth,
  595. layerWidth, affect, this);
  596. }
  597. }
  598. // @TODO: preview redraw
  599. }
  600. void SceneEditLayer::initAvailableLayers() { start_func
  601. // Fill layer variables etc.
  602. numLayers = scene->getLayerCount();
  603. // (must be at least one layer)
  604. assert(numLayers);
  605. // @TODO: Remember current layer(s) during a session? (reopening windows)
  606. if (layerlist) {
  607. if (layerlist->layerList) {
  608. layerlist->layerList->clear();
  609. layerlist->layerList->setScene(scene);
  610. }
  611. }
  612. Uint32 bit = 1;
  613. layersAffect = 0;
  614. layersDim = 0;
  615. layersAvailable = 0;
  616. layersView = 0;
  617. for (int pos = 0; pos < numLayers; ++pos, bit <<= 1) {
  618. layersView |= bit;
  619. Layer* layer = scene->getLayer(pos);
  620. if (layer->getType() == Layer::LAYER_TILE) {
  621. layersAvailable |= bit;
  622. if (!layersAffect) {
  623. layersAffect = bit;
  624. cursorLayer = pos;
  625. }
  626. }
  627. // All layers get added
  628. if (layerlist) {
  629. if (layerlist->layerList) {
  630. // (select item if cursor layer)
  631. layerlist->layerList->WListBox::addItem(ListEntry(layer->getName(), pos,
  632. ((layersView & bit) ? WLayerListBox::FLAG_VISIBLE : 0) |
  633. ((layersAffect & bit) ? WLayerListBox::FLAG_EDITABLE : 0),
  634. layer->getType(),
  635. 0, !(layersAvailable & bit)),
  636. cursorLayer == pos);
  637. }
  638. }
  639. }
  640. // (must be at least one tile layer)
  641. assert(layersAffect);
  642. }
  643. void SceneEditLayer::reloadLayerStats(int resizeView) { start_func
  644. assert(cursorLayer >= 0);
  645. assert(cursorLayer < numLayers);
  646. // Retain old selection?
  647. int retainSelData = 0;
  648. Uint8* oldSelected = NULL;
  649. int oldSelectedPitch;
  650. int oldSelectedHeight;
  651. if (selectionRect.w) {
  652. oldSelected = selected;
  653. oldSelectedPitch = selectedPitch;
  654. oldSelectedHeight = layerHeight;
  655. // Retain contents of a floating selection?
  656. if (selectionMode != SELECTION_OUTLINE) retainSelData = 1;
  657. }
  658. else {
  659. delete[] selected;
  660. selectionMode = SELECTION_OUTLINE;
  661. }
  662. delete[] backupSelected;
  663. selected = NULL;
  664. backupSelected = NULL;
  665. // Old sizes for retaining data
  666. int prevWidth = layerWidth;
  667. int prevHeight = layerHeight;
  668. // Get stats on current layer
  669. LayerEdit* layer = scene->getLayerEdit(cursorLayer);
  670. layerWidth = layer->getXSize();
  671. layerHeight = layer->getYSize();
  672. layerExt = layer->getUsesExt();
  673. setUsesExt(layerExt);
  674. TileSetEdit* tileset = layer->getTileSetEdit();
  675. numTiles = tileset->getCount();
  676. tileWidth = tileset->getWidth();
  677. tileHeight = tileset->getHeight();
  678. // Layer should have already locked tileset- exception should never happen
  679. try {
  680. if (imagebar) imagebar->changeSet(tileset);
  681. }
  682. catch (FileException& e) {
  683. fatalCrash(0, "Error reading tileset- %s", e.details);
  684. }
  685. // Clip cursor
  686. if (cursorX >= layerWidth) cursorX = layerWidth - 1;
  687. if (cursorY >= layerHeight) cursorY = layerHeight - 1;
  688. // Allocate selection storage
  689. selectedPitch = (layerWidth + 7) / 8;
  690. selected = new Uint8[selectedPitch * layerHeight];
  691. backupSelected = new Uint8[selectedPitch * layerHeight];
  692. memset(selected, 0, selectedPitch * layerHeight);
  693. memset(backupSelected, 0, selectedPitch * layerHeight);
  694. // Copy over saved selection
  695. if (oldSelected) {
  696. matrixCopy(oldSelected, selected, min(selectedPitch, oldSelectedPitch), min(oldSelectedHeight, layerHeight), oldSelectedPitch, selectedPitch);
  697. fixSelectionRect();
  698. delete[] oldSelected;
  699. }
  700. // Allocate layer storage
  701. Uint32 bit = 1;
  702. int affectedChange = 0;
  703. for (int pos = 0; pos < numLayers; ++pos, bit <<= 1) {
  704. if (layersAffect & bit) {
  705. // Ensure this layer has the same stats
  706. int same = 1;
  707. Layer* layer = scene->getLayer(pos);
  708. if ((layerWidth != layer->getXSize()) || (layerHeight != layer->getYSize())) same = 0;
  709. TileSet* tileset = layer->getTileSet();
  710. if ((tileWidth != tileset->getWidth()) || (tileHeight != tileset->getHeight())) same = 0;
  711. if (same) {
  712. int usesExt = layer->getUsesExt();
  713. int usesFx = layer->getUsesFx();
  714. int layerSize = layerWidth * layerHeight;
  715. // Retain a floating selection?
  716. if (retainSelData) {
  717. Uint32* newEdit = NULL;
  718. newEdit = new Uint32[layerSize];
  719. memSet32(newEdit, Layer::LAYER_TILE_DEFAULT, layerSize);
  720. matrixCopy(layerEdit[pos][0], newEdit, min(prevWidth, layerWidth) * 4, min(prevHeight, layerHeight), prevWidth * 4, layerWidth * 4);
  721. delete[] layerEdit[pos][0];
  722. layerEdit[pos][0] = newEdit;
  723. newEdit = NULL;
  724. if (usesExt) {
  725. newEdit = new Uint32[layerSize];
  726. memSet32(newEdit, Layer::LAYER_EXT_DEFAULT, layerSize);
  727. if (layerEdit[pos][1]) {
  728. matrixCopy(layerEdit[pos][1], newEdit, min(prevWidth, layerWidth) * 4, min(prevHeight, layerHeight), prevWidth * 4, layerWidth * 4);
  729. delete[] layerEdit[pos][1];
  730. }
  731. layerEdit[pos][1] = newEdit;
  732. newEdit = NULL;
  733. }
  734. else {
  735. delete[] layerEdit[pos][1];
  736. layerEdit[pos][1] = NULL;
  737. }
  738. if (usesFx) {
  739. newEdit = new Uint32[layerSize];
  740. memSet32(newEdit, Layer::LAYER_FX_DEFAULT, layerSize);
  741. if (layerEdit[pos][2]) {
  742. matrixCopy(layerEdit[pos][2], newEdit, min(prevWidth, layerWidth) * 4, min(prevHeight, layerHeight), prevWidth * 4, layerWidth * 4);
  743. delete[] layerEdit[pos][2];
  744. }
  745. layerEdit[pos][2] = newEdit;
  746. newEdit = NULL;
  747. }
  748. else {
  749. delete[] layerEdit[pos][2];
  750. layerEdit[pos][2] = NULL;
  751. }
  752. }
  753. else {
  754. // Allocate storage (no need to fill with empty- layer will load over it)
  755. delete[] layerEdit[pos][0];
  756. layerEdit[pos][0] = NULL;
  757. layerEdit[pos][0] = new Uint32[layerSize];
  758. delete[] layerEdit[pos][1];
  759. layerEdit[pos][1] = NULL;
  760. delete[] layerEdit[pos][2];
  761. layerEdit[pos][2] = NULL;
  762. if (usesExt) layerEdit[pos][1] = new Uint32[layerSize];
  763. if (usesFx) layerEdit[pos][2] = new Uint32[layerSize];
  764. }
  765. }
  766. else {
  767. // Layer is no longer "affected"
  768. layersAffect &= ~bit;
  769. affectedChange = 1;
  770. }
  771. }
  772. if (!(layersAffect & bit)) {
  773. // Free any previously allocated memory
  774. delete[] layerEdit[pos][0];
  775. delete[] layerEdit[pos][1];
  776. delete[] layerEdit[pos][2];
  777. layerEdit[pos][0] = NULL;
  778. layerEdit[pos][1] = NULL;
  779. layerEdit[pos][2] = NULL;
  780. }
  781. }
  782. // Update layers list if we modified layersAffect
  783. if ((affectedChange) && (layerlist)) {
  784. if (layerlist->layerList) {
  785. layerlist->layerList->setBitMask(layersAffect, layersView, layersDim);
  786. }
  787. }
  788. // Resize to match current layer
  789. setDirty(1);
  790. resize(tileWidth * layerWidth, tileHeight * layerHeight);
  791. if (myFrame) {
  792. myFrame->setScroll(tileWidth, tileHeight);
  793. if (resizeView) myFrame->requestViewSize(width, height);
  794. }
  795. }
  796. // @TODO: call when layer changes
  797. void SceneEditLayer::updateTitlebar() { start_func
  798. if ((myFrame) && (scene)) {
  799. myFrame->setTitle(formatString("%s : %s : Layer %s", world->getTitle().c_str(), scene->getName().c_str(), scene->getLayer(cursorLayer)->getName().c_str()));
  800. }
  801. }
  802. int SceneEditLayer::event(int hasFocus, const SDL_Event* event) { start_func
  803. int changed = 0;
  804. int clickX, clickY;
  805. ObjChange* obj;
  806. switch (event->type) {
  807. case SDL_CLOSE:
  808. // Merge any existing selection
  809. try {
  810. mergeSelection();
  811. }
  812. catch (UndoException& e) {
  813. }
  814. return 1;
  815. case SDL_SPECIAL:
  816. // Refresh selection rectangles?
  817. if ((event->user.code == SDL_IDLEPHASE) && (partialFocus)) {
  818. Rect rect = { selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs, selectionRect.w, selectionRect.h };
  819. setDirtyRect(rect);
  820. setDirtySelectedSpawns();
  821. if (toolActive == TOOLS_SELECTITEM)
  822. setDirtyPixelBox(toolStartX, toolStartY, toolLastX, toolLastY);
  823. }
  824. // Refresh cursor?
  825. if (((event->user.code == SDL_IDLECURSOR) || (event->user.code == SDL_IDLEPHASE)) && (haveFocus)) {
  826. Rect rect = { cursorX, cursorY, cursorW, cursorH };
  827. setDirtyRect(rect);
  828. }
  829. return 1;
  830. case SDL_COMMAND:
  831. switch (event->user.code) {
  832. case EDIT_UNDO:
  833. // finish instead of cancel- this causes undo to undo current
  834. // tool if one is being used
  835. finishTool();
  836. // (let world handle from here)
  837. break;
  838. case EDIT_REDO:
  839. cancelTool();
  840. // (let world handle from here)
  841. break;
  842. case EDIT_COPY:
  843. if (useSpawnSelection()) copySpawnSelection();
  844. else copySelection();
  845. return 1;
  846. case EDIT_CUT:
  847. try {
  848. world->undo.preUndoBlock();
  849. if (useSpawnSelection()) {
  850. copySpawnSelection();
  851. deleteSpawnSelection();
  852. clearSpawnSelection();
  853. }
  854. else {
  855. copySelection();
  856. deleteSelection();
  857. clearSelection();
  858. }
  859. world->undo.postUndoBlock();
  860. }
  861. catch (UndoException& e) {
  862. }
  863. return 1;
  864. case EDIT_DELETE:
  865. try {
  866. world->undo.preUndoBlock();
  867. deleteSpawnSelection();
  868. deleteSelection();
  869. world->undo.postUndoBlock();
  870. }
  871. catch (UndoException& e) {
  872. }
  873. return 1;
  874. case EDIT_SELECTALL:
  875. try {
  876. if (spriteMode) {
  877. undoStoreSpawnSelect();
  878. selectSpawnRect(0, 0, 0, 0, 1, 1);
  879. recheckSpawnSelection();
  880. setDirtySelectedSpawns();
  881. // Ensure selection tool active
  882. if ((!toolActive) && (toolL != TOOLS_SELECTITEM)) {
  883. desktop->broadcastEvent(SDL_COMMAND, TOOLS_SELECTITEM);
  884. desktop->broadcastEvent(SDL_COMMAND, CMD_RELEASE);
  885. }
  886. }
  887. else {
  888. world->undo.preUndoBlock();
  889. // Merge any floating
  890. mergeSelection();
  891. // Store undo for entire selection
  892. undoStoreSelect(0, 0, layerWidth, layerHeight);
  893. world->undo.postUndoBlock();
  894. // Select all
  895. memset(selected, 255, selectedPitch * layerHeight);
  896. selectionRect.x = 0;
  897. selectionRect.y = 0;
  898. selectionRect.w = layerWidth;
  899. selectionRect.h = layerHeight;
  900. setDirty(1);
  901. }
  902. updateCopyTool();
  903. }
  904. catch (UndoException& e) {
  905. }
  906. return 1;
  907. case EDIT_DESELECTALL:
  908. cancelTool();
  909. try {
  910. doneSelection();
  911. clearSpawnSelection();
  912. }
  913. catch (UndoException& e) {
  914. }
  915. return 1;
  916. case EDIT_PASTE:
  917. try {
  918. changed = pasteSelection();
  919. }
  920. catch (UndoException& e) {
  921. }
  922. // Make sure a selection tool is current
  923. if (changed == TOOLS_SELECT) {
  924. if ((!toolActive) && (toolL != TOOLS_SELECT) && (toolL != TOOLS_SELECTELLIPSE) && (toolL != TOOLS_WAND)) {
  925. desktop->broadcastEvent(SDL_COMMAND, TOOLS_SELECT);
  926. desktop->broadcastEvent(SDL_COMMAND, CMD_RELEASE);
  927. }
  928. }
  929. else if (changed == TOOLS_SELECTITEM) {
  930. if ((!toolActive) && (toolL != TOOLS_SELECTITEM)) {
  931. desktop->broadcastEvent(SDL_COMMAND, TOOLS_SELECTITEM);
  932. desktop->broadcastEvent(SDL_COMMAND, CMD_RELEASE);
  933. }
  934. }
  935. return 1;
  936. case CMD_RELEASE:
  937. finishTool(); // Clears startToolOnMove too; safe even if no tool
  938. moveCursor(cursorSpriteX, cursorSpriteY);
  939. return 1;
  940. case NEW_LAYER:
  941. try {
  942. scene->newLayer(myFrame);
  943. }
  944. catch (FileException& e) {
  945. guiErrorBox(string(e.details), errorTitleFile);
  946. }
  947. return 1;
  948. case TOOLS_NEXTIMAGE:
  949. imagebar->nextImage();
  950. return 1;
  951. case TOOLS_PREVIMAGE:
  952. imagebar->prevImage();
  953. return 1;
  954. case TOOLS_NEXTCOLOR:
  955. colorbar->colorSelection(ColorSelect::SELECTED_FG,
  956. colorbar->colorSelection(ColorSelect::SELECTED_FG) + 1);
  957. return 1;
  958. case TOOLS_PREVCOLOR:
  959. colorbar->colorSelection(ColorSelect::SELECTED_FG,
  960. colorbar->colorSelection(ColorSelect::SELECTED_FG) - 1);
  961. return 1;
  962. case TOOLS_EDITCOLOR:
  963. colorbar->editColor(colorbar->colorSelection(ColorSelect::SELECTED_FG));
  964. return 1;
  965. }
  966. if (world->commandEvent(event->user.code)) return 1;
  967. break;
  968. case SDL_OBJECTCHANGE:
  969. if (!scene) return 0;
  970. obj = (ObjChange*)event->user.data1;
  971. if (event->user.code & OBJ_SPAWN) {
  972. // One of our layers?
  973. SpawnEdit* spawn = (SpawnEdit*)obj->obj;
  974. Layer* spawnLayer = spawn->getLayer();
  975. if (!spawnLayer) break;
  976. // Find out if it matches one of our layers (and if we're editing that layer)
  977. Uint32 bit = 1;
  978. int layerNum = -1;
  979. int affected = 0;
  980. for (int pos = 0; pos < numLayers; ++pos, bit <<= 1) {
  981. Layer* layer = scene->getLayer(pos);
  982. if (spawnLayer == layer) {
  983. layerNum = pos;
  984. affected = layersAffect & bit;
  985. break;
  986. }
  987. }
  988. // Not one of our layers
  989. if (layerNum < 0) break;
  990. setDirty(1);
  991. // Any change could affect our selection boundaries
  992. if ((affected) && (selectedSpawns.count(spawn->getId()))) {
  993. if (event->user.code & OBJMOD_DELETE)
  994. selectedSpawns.erase(spawn->getId());
  995. recheckSpawnSelection();
  996. }
  997. }
  998. if (event->user.code & OBJ_LAYER) {
  999. // Find out if it matches one of our layers (and if we're editing that layer)
  1000. Uint32 bit = 1;
  1001. int layerNum = -1;
  1002. int affected = 0;
  1003. for (int pos = 0; pos < numLayers; ++pos, bit <<= 1) {
  1004. Layer* layer = scene->getLayer(pos);
  1005. if (obj->obj == layer) {
  1006. layerNum = pos;
  1007. affected = layersAffect & bit;
  1008. break;
  1009. }
  1010. }
  1011. // Not one of our layers
  1012. if (layerNum < 0) break;
  1013. if (event->user.code & OBJMOD_TILES) {
  1014. if (affected) {
  1015. if (selectionMode == SELECTION_OUTLINE) {
  1016. Rect affect = { 0, 0, layerWidth, layerHeight };
  1017. scene->getLayerEdit(layerNum)->loadLayer(layerEdit[layerNum][0], layerEdit[layerNum][1], layerEdit[layerNum][2], layerWidth, affect);
  1018. }
  1019. }
  1020. setDirty(1);
  1021. }
  1022. if (event->user.code & OBJMOD_NAME) {
  1023. layerlist->layerList->modifyItem(layerNum, &((Layer*)(obj->obj))->getName());
  1024. }
  1025. if ((event->user.code & OBJMOD_WIDTH) || (event->user.code & OBJMOD_HEIGHT) || (event->user.code & OBJMOD_USESFX) || (event->user.code & OBJMOD_USESEXT) || (event->user.code & OBJMOD_TILESET)) {
  1026. if (affected) {
  1027. // @TODO: undo won't properly undo the loss of size on the selection
  1028. // we need to have a layer that resizes scan all windows and
  1029. // resize all appropriate selections as part of it's undo block
  1030. reloadLayerStats();
  1031. if (selectionMode == SELECTION_OUTLINE) refreshData(0);
  1032. }
  1033. else {
  1034. setDirty(1);
  1035. }
  1036. }
  1037. if (event->user.code & OBJMOD_TYPE) {
  1038. // Layer becomes available if not already; nothing else affected except type icon
  1039. int type = ((Layer*)(obj->obj))->getType();
  1040. Uint32 newLayersAvailable = layersAvailable;
  1041. Uint32 newLayersAffect = layersAffect;
  1042. if (type == Layer::LAYER_TILE) newLayersAvailable |= bit;
  1043. else {
  1044. newLayersAvailable &= ~bit;
  1045. newLayersAffect &= ~bit;
  1046. }
  1047. // No layers to affect anymore? Close
  1048. if (!newLayersAvailable) {
  1049. scene->markUnlock();
  1050. scene = NULL;
  1051. closeWindow();
  1052. return 1;
  1053. }
  1054. // No affected layers? pick first one
  1055. if (!newLayersAffect) {
  1056. newLayersAffect = 1;
  1057. while (!(newLayersAvailable & newLayersAffect)) {
  1058. newLayersAffect <<= 1;
  1059. }
  1060. }
  1061. // Update layers list
  1062. int disable = !(newLayersAvailable & bit);
  1063. layerlist->layerList->modifyItem(layerNum, NULL, &disable, NULL, &type);
  1064. // (this fixes cursor layer if it needs to be)
  1065. layersAvailable = newLayersAvailable;
  1066. refreshLayers(newLayersAffect, layersView, layersDim);
  1067. }
  1068. }
  1069. if (event->user.code & OBJ_TILESET) {
  1070. LayerEdit* layer = scene->getLayerEdit(cursorLayer);
  1071. TileSetEdit* tileset = layer->getTileSetEdit();
  1072. if (obj->obj == (TileSet*)tileset) {
  1073. // @TODO: OBJMOD_COUNTCOLL-
  1074. // stuff will need reloading once we can edit collisions
  1075. if ((event->user.code & OBJMOD_WIDTH) || (event->user.code & OBJMOD_HEIGHT) || (event->user.code & OBJMOD_COUNT) || (event->user.code & OBJMOD_TILE)) {
  1076. // Width/height require actual layer stat change
  1077. if ((event->user.code & OBJMOD_WIDTH) || (event->user.code & OBJMOD_HEIGHT)) {
  1078. reloadLayerStats();
  1079. if (selectionMode == SELECTION_OUTLINE) refreshData(0);
  1080. }
  1081. // All require visual refresh and imagebar adjustment
  1082. setDirty(1);
  1083. // Layer should have already locked tileset- exception should never happen
  1084. try {
  1085. if (imagebar) imagebar->changeSet(tileset);
  1086. }
  1087. catch (FileException& e) {
  1088. fatalCrash(0, "Error reading tileset- %s", e.details);
  1089. }
  1090. }
  1091. }
  1092. }
  1093. if ((event->user.code & OBJ_SCENE) && (obj->obj == scene)) {
  1094. if (event->user.code & OBJMOD_LAYERDEL) {
  1095. // Update our data
  1096. --numLayers;
  1097. // Determine which bits "shift down" to fill hole
  1098. Uint32 bitsToShift = 0;
  1099. for (Uint32 bit = 2 << obj->info1; bit; bit <<= 1) {
  1100. bitsToShift |= bit;
  1101. }
  1102. Uint32 bitsToLeave = (bitsToShift ^ 0xFFFFFFFF) ^ (1 << obj->info1);
  1103. layersView = (layersView & bitsToLeave) | ((layersView & bitsToShift) >> 1);
  1104. layersDim = (layersDim & bitsToLeave) | ((layersDim & bitsToShift) >> 1);
  1105. layersAffect = (layersAffect & bitsToLeave) | ((layersAffect & bitsToShift) >> 1);
  1106. layersAvailable = (layersAvailable & bitsToLeave) | ((layersAvailable & bitsToShift) >> 1);
  1107. // Shift data down
  1108. delete[] layerEdit[obj->info1][0];
  1109. delete[] layerEdit[obj->info1][1];
  1110. delete[] layerEdit[obj->info1][2];
  1111. for (int pos = obj->info1 + 1; pos < MAX_LAYERS; ++pos) {
  1112. layerEdit[pos - 1][0] = layerEdit[pos][0];
  1113. layerEdit[pos - 1][1] = layerEdit[pos][1];
  1114. layerEdit[pos - 1][2] = layerEdit[pos][2];
  1115. }
  1116. layerEdit[MAX_LAYERS - 1][0] = NULL;
  1117. layerEdit[MAX_LAYERS - 1][1] = NULL;
  1118. layerEdit[MAX_LAYERS - 1][2] = NULL;
  1119. // Cursor layer- shift down? if cursorlayer was deleted, "no" cursor layer
  1120. if (cursorLayer == obj->info1) cursorLayer = -1;
  1121. else if (cursorLayer > obj->info1) --cursorLayer;
  1122. // No layers to affect anymore? Close
  1123. if (!layersAvailable) {
  1124. scene->markUnlock();
  1125. scene = NULL;
  1126. closeWindow();
  1127. return 1;
  1128. }
  1129. // Remove from layer list (this might call widget/childmodified
  1130. // leading to refreshlayers)
  1131. layerlist->layerList->removeItem(obj->info1);
  1132. // Determine new stats (this may attempt a merge selection,
  1133. // which should be safe even if no cursorlayer/affectedlayer)
  1134. refreshLayers();
  1135. // Update screen
  1136. setDirty(1);
  1137. }
  1138. if (event->user.code & OBJMOD_LAYERADD) {
  1139. // We need to double check that this layer isn't already added
  1140. // (can happen when first creating a scene)
  1141. if (scene->getLayerCount() > numLayers) {
  1142. // Determine which bits "shift up" to open hole
  1143. Uint32 bitsToShift = 0;
  1144. for (Uint32 bit = 1 << obj->info1; bit; bit <<= 1) {
  1145. bitsToShift |= bit;
  1146. }
  1147. Uint32 bitsToLeave = bitsToShift ^ 0xFFFFFFFF;
  1148. layersView = (layersView & bitsToLeave) | ((layersView & bitsToShift) << 1);
  1149. layersDim = (layersDim & bitsToLeave) | ((layersDim & bitsToShift) << 1);
  1150. layersAffect = (layersAffect & bitsToLeave) | ((layersAffect & bitsToShift) << 1);
  1151. layersAvailable = (layersAvailable & bitsToLeave) | ((layersAvailable & bitsToShift) << 1);
  1152. // Shift data up
  1153. for (int pos = MAX_LAYERS - 1; pos > obj->info1; --pos) {
  1154. layerEdit[pos][0] = layerEdit[pos - 1][0];
  1155. layerEdit[pos][1] = layerEdit[pos - 1][1];
  1156. layerEdit[pos][2] = layerEdit[pos - 1][2];
  1157. }
  1158. layerEdit[obj->info1][0] = NULL;
  1159. layerEdit[obj->info1][1] = NULL;
  1160. layerEdit[obj->info1][2] = NULL;
  1161. // Cursor layer- shift up?
  1162. if (cursorLayer >= obj->info1) ++cursorLayer;
  1163. // Add layer, but not as editable until user selects
  1164. Uint32 bit = 1 << obj->info1;
  1165. layersView |= bit;
  1166. Layer* layer = scene->getLayer(obj->info1);
  1167. if (layer->getType() == Layer::LAYER_TILE) layersAvailable |= bit;
  1168. layerlist->layerList->addItem(obj->info1,
  1169. ListEntry(layer->getName(), obj->info1,
  1170. (layersView & bit) ? WLayerListBox::FLAG_VISIBLE : 0,
  1171. layer->getType(), 0,
  1172. !(layersAvailable & bit)));
  1173. ++numLayers;
  1174. setDirty(1);
  1175. }
  1176. }
  1177. if (event->user.code & OBJMOD_LAYERMOVE) {
  1178. // If we swap all data to match, a move ultimately only affects
  1179. // the visual appearance (layers above/below each other)
  1180. Uint32 bit1 = 1 << obj->info1;
  1181. Uint32 bit2 = 1 << obj->info2;
  1182. Uint32 bits = bit1 | bit2;
  1183. // Swap appropriate bits, if only one of the two is set
  1184. if (((layersView & bits) == bit1) || ((layersView & bits) == bit2)) layersView ^= bits;
  1185. if (((layersDim & bits) == bit1) || ((layersDim & bits) == bit2)) layersDim ^= bits;
  1186. if (((layersAffect & bits) == bit1) || ((layersAffect & bits) == bit2)) layersAffect ^= bits;
  1187. if (((layersAvailable & bits) == bit1) || ((layersAvailable & bits) == bit2)) layersAvailable ^= bits;
  1188. // Swap cursor
  1189. if (cursorLayer == obj->info1) cursorLayer = obj->info2;
  1190. else if (cursorLayer == obj->info2) cursorLayer = obj->info1;
  1191. // Swap layer data
  1192. swap(layerEdit[obj->info1][0], layerEdit[obj->info2][0]);
  1193. swap(layerEdit[obj->info1][1], layerEdit[obj->info2][1]);
  1194. swap(layerEdit[obj->info1][2], layerEdit[obj->info2][2]);
  1195. // Swap in layer list
  1196. layerlist->layerList->swapItems(obj->info1, obj->info2);
  1197. // Update screen
  1198. setDirty(1);
  1199. }
  1200. }
  1201. if ((event->user.code & OBJ_WORLD) && (obj->obj == world)) {
  1202. if (event->user.code & OBJMOD_DELETE) {
  1203. imagebar->changeSet(NULL, 1);
  1204. scene = NULL;
  1205. closeWindow();
  1206. }
  1207. if (event->user.code & OBJMOD_NAME) {
  1208. updateTitlebar();
  1209. }
  1210. }
  1211. return 1;
  1212. case SDL_MOUSEBUTTONDOWN:
  1213. case SDL_MOUSEBUTTONDBL:
  1214. if ((event->button.button == SDL_BUTTON_LEFT) || (event->button.button == SDL_BUTTON_RIGHT)) {
  1215. spriteAtCursor = 0;
  1216. // Signed as it could go off the edge
  1217. clickX = (Sint16)event->button.x;
  1218. clickY = (Sint16)event->button.y;
  1219. // If unmodified selection-tool click and within selection, this is a selection drag
  1220. if ((!toolActive) &&
  1221. !(SDL_GetModState() & (KMOD_CTRL | KMOD_ALT)) && (
  1222. (((toolL == TOOLS_SELECT) || (toolL == TOOLS_SELECTELLIPSE) || (toolL == TOOLS_WAND)) &&
  1223. (event->button.button == SDL_BUTTON_LEFT)) ||
  1224. (((toolR == TOOLS_SELECT) || (toolR == TOOLS_SELECTELLIPSE) || (toolR == TOOLS_WAND)) &&
  1225. (event->button.button == SDL_BUTTON_RIGHT))
  1226. ) && (isInSelection(clickX / tileWidth, clickY / tileHeight))) {
  1227. startToolOnMove = 0;
  1228. moveCursor(clickX, clickY);
  1229. startToolSelectionDrag();
  1230. }
  1231. else if ((!toolActive) &&
  1232. !(SDL_GetModState() & (KMOD_CTRL | KMOD_ALT)) && (
  1233. ((toolL == TOOLS_SELECTITEM) &&
  1234. (event->button.button == SDL_BUTTON_LEFT)) ||
  1235. ((toolR == TOOLS_SELECTITEM) &&
  1236. (event->button.button == SDL_BUTTON_RIGHT))
  1237. ) && (isInSpawnSelection(clickX, clickY))) {
  1238. startToolOnMove = 0;
  1239. moveCursor(clickX, clickY);
  1240. startToolSpawnSelectionDrag();
  1241. }
  1242. else {
  1243. moveCursor(clickX, clickY);
  1244. startTool(event->button.button);
  1245. }
  1246. updateSpriteShown();
  1247. return 1;
  1248. }
  1249. break;
  1250. case SDL_MOUSEBUTTONUP:
  1251. finishTool();
  1252. // Force cursor back into area, no more virtual
  1253. moveCursor(cursorSpriteX, cursorSpriteY);
  1254. return 1;
  1255. case SDL_MOUSEMOTION:
  1256. spriteAtCursor = 0;
  1257. pixelMouseX = (Sint16)event->motion.x;
  1258. pixelMouseY = (Sint16)event->motion.y;
  1259. if ((event->motion.state & SDL_BUTTON_LMASK) || (event->motion.state & SDL_BUTTON_RMASK)) {
  1260. // Signed as it could go off the edge
  1261. moveCursor((Sint16)event->motion.x, (Sint16)event->motion.y);
  1262. }
  1263. else {
  1264. // Update mouse pointer
  1265. mousePointer((Sint16)event->motion.x, (Sint16)event->motion.y);
  1266. }
  1267. updateSpriteShown();
  1268. return 1;
  1269. case SDL_MOUSEFOCUS:
  1270. if (event->user.code & 1) {
  1271. hover = 1;
  1272. mousePointer();
  1273. }
  1274. else {
  1275. hover = 0;
  1276. selectMouse(MOUSE_NORMAL);
  1277. }
  1278. updateSpriteShown();
  1279. return 1;
  1280. case SDL_INPUTFOCUS:
  1281. if (event->user.code & 1) {
  1282. if (!haveFocus) {
  1283. haveFocus = partialFocus = 1;
  1284. changed = 1;
  1285. }
  1286. }
  1287. else if (event->user.code & 2) {
  1288. if (!partialFocus) {
  1289. partialFocus = 1;
  1290. changed = 1;
  1291. }
  1292. }
  1293. else {
  1294. if (partialFocus) {
  1295. partialFocus = 0;
  1296. changed = 1;
  1297. }
  1298. }
  1299. if (!(event->user.code & 1)) {
  1300. if (haveFocus) {
  1301. cancelTool();
  1302. haveFocus = 0;
  1303. changed = 1;
  1304. }
  1305. }
  1306. if (changed) {
  1307. // Refresh selection rectangle and cursor
  1308. Rect rect = { selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs, selectionRect.w, selectionRect.h };
  1309. Rect rect2 = { cursorX, cursorY, cursorW, cursorH };
  1310. setDirtyRect(rect);
  1311. setDirtyRect(rect2);
  1312. setDirtySelectedSpawns();
  1313. updateSpriteShown();
  1314. }
  1315. return 1;
  1316. case SDL_KEYUP:
  1317. switch (event->key.keysym.sym) {
  1318. case SDLK_LSHIFT:
  1319. case SDLK_RSHIFT:
  1320. case SDLK_SPACE:
  1321. finishTool();
  1322. // Force cursor back into area, no more virtual
  1323. moveCursor(cursorSpriteX, cursorSpriteY);
  1324. return 1;
  1325. case SDLK_LALT:
  1326. case SDLK_RALT:
  1327. case SDLK_LCTRL:
  1328. case SDLK_RCTRL:
  1329. modifyTool();
  1330. return 1;
  1331. default:
  1332. break;
  1333. }
  1334. break;
  1335. case SDL_KEYDOWN:
  1336. // We can't stick modifiers in due to the numerous combinations that
  1337. // could occur of ctrl/shift/alt in use of various tools
  1338. switch (event->key.keysym.sym) {
  1339. case SDLK_KP_ENTER:
  1340. case SDLK_RETURN:
  1341. // Merge any existing selection
  1342. try {
  1343. mergeSelection();
  1344. }
  1345. catch (UndoException& e) {
  1346. }
  1347. return 1;
  1348. case SDLK_LALT:
  1349. case SDLK_RALT:
  1350. case SDLK_LCTRL:
  1351. case SDLK_RCTRL:
  1352. modifyTool();
  1353. return 1;
  1354. case SDLK_SPACE:
  1355. // (ensure on a tile boundary)
  1356. moveCursor(virtualCursorX * tileWidth, virtualCursorY * tileHeight);
  1357. startTool(SDL_BUTTON_LEFT);
  1358. changed = 1;
  1359. break;
  1360. case SDLK_LSHIFT:
  1361. // (ensure on a tile boundary)
  1362. moveCursor(virtualCursorX * tileWidth, virtualCursorY * tileHeight);
  1363. startToolOnMove = 1;
  1364. return 1;
  1365. // @TODO: This should probably end up as a configurable shortcut somehow; should SHIFTs/SPACE too?
  1366. case SDLK_RSHIFT:
  1367. // (ensure on a tile boundary)
  1368. moveCursor(virtualCursorX * tileWidth, virtualCursorY * tileHeight);
  1369. startTool(SDL_BUTTON_RIGHT);
  1370. changed = 1;
  1371. break;
  1372. case SDLK_RIGHT:
  1373. // @TODO: cursor drag of sprite (or regular?) selection
  1374. if (selectionMode != SELECTION_OUTLINE) {
  1375. if (event->key.keysym.mod & KMOD_CTRL) moveSelection(layerWidth - selectionRect.w - selectionRect.x, selectionYOffs);
  1376. else moveSelection(selectionXOffs + 1, selectionYOffs);
  1377. }
  1378. else {
  1379. if (event->key.keysym.mod & KMOD_CTRL) scanCursor(1, 0);
  1380. else moveCursor(virtualCursorX * tileWidth + tileWidth, virtualCursorY * tileHeight);
  1381. }
  1382. changed = 1;
  1383. break;
  1384. case SDLK_END:
  1385. if (selectionMode != SELECTION_OUTLINE) {
  1386. if (event->key.keysym.mod & KMOD_CTRL) moveSelection(layerWidth - selectionRect.w - selectionRect.x, layerHeight - selectionRect.h - selectionRect.y);
  1387. else moveSelection(layerWidth - selectionRect.w - selectionRect.x, selectionYOffs);
  1388. }
  1389. else {
  1390. if (event->key.keysym.mod & KMOD_CTRL) moveCursor((layerWidth - cursorW) * tileWidth, (layerHeight - cursorH) * tileHeight);
  1391. else moveCursor((layerWidth - cursorW) * tileWidth, virtualCursorY * tileHeight);
  1392. }
  1393. changed = 1;
  1394. break;
  1395. case SDLK_LEFT:
  1396. if (selectionMode != SELECTION_OUTLINE) {
  1397. if (event->key.keysym.mod & KMOD_CTRL) moveSelection(-selectionRect.x, selectionYOffs);
  1398. else moveSelection(selectionXOffs - 1, selectionYOffs);
  1399. }
  1400. else {
  1401. if (event->key.keysym.mod & KMOD_CTRL) scanCursor(-1, 0);
  1402. else moveCursor(virtualCursorX * tileWidth - tileWidth, virtualCursorY * tileHeight);
  1403. }
  1404. changed = 1;
  1405. break;
  1406. case SDLK_HOME:
  1407. if (selectionMode != SELECTION_OUTLINE) {
  1408. if (event->key.keysym.mod & KMOD_CTRL) moveSelection(-selectionRect.x, -selectionRect.y);
  1409. else moveSelection(-selectionRect.x, selectionYOffs);
  1410. }
  1411. else {
  1412. if (event->key.keysym.mod & KMOD_CTRL) moveCursor(0, 0);
  1413. else moveCursor(0, virtualCursorY * tileHeight);
  1414. }
  1415. changed = 1;
  1416. break;
  1417. case SDLK_DOWN:
  1418. if (selectionMode != SELECTION_OUTLINE) {
  1419. if (event->key.keysym.mod & KMOD_CTRL) moveSelection(selectionXOffs, layerHeight - selectionRect.h - selectionRect.y);
  1420. else moveSelection(selectionXOffs, selectionYOffs + 1);
  1421. }
  1422. else {
  1423. if (event->key.keysym.mod & KMOD_CTRL) scanCursor(0, 1);
  1424. else moveCursor(virtualCursorX * tileWidth, virtualCursorY * tileHeight + tileHeight);
  1425. }
  1426. changed = 1;
  1427. break;
  1428. case SDLK_UP:
  1429. if (selectionMode != SELECTION_OUTLINE) {
  1430. if (event->key.keysym.mod & KMOD_CTRL) moveSelection(selectionXOffs, -selectionRect.y);
  1431. else moveSelection(selectionXOffs, selectionYOffs - 1);
  1432. }
  1433. else {
  1434. if (event->key.keysym.mod & KMOD_CTRL) scanCursor(0, -1);
  1435. else moveCursor(virtualCursorX * tileWidth, virtualCursorY * tileHeight - tileHeight);
  1436. }
  1437. changed = 1;
  1438. break;
  1439. case SDLK_PAGEDOWN:
  1440. if (selectionMode != SELECTION_OUTLINE) {
  1441. moveSelection(selectionXOffs, selectionYOffs + (viewHeight / tileHeight - 1));
  1442. }
  1443. else {
  1444. moveCursor(virtualCursorX * tileWidth, (virtualCursorY + (viewHeight / tileHeight - 1)) * tileHeight);
  1445. }
  1446. changed = 1;
  1447. break;
  1448. case SDLK_PAGEUP:
  1449. if (selectionMode != SELECTION_OUTLINE) {
  1450. moveSelection(selectionXOffs, selectionYOffs - (viewHeight / tileHeight - 1));
  1451. }
  1452. else {
  1453. moveCursor(virtualCursorX * tileWidth, (virtualCursorY - (viewHeight / tileHeight - 1)) * tileHeight);
  1454. }
  1455. changed = 1;
  1456. break;
  1457. default:
  1458. break;
  1459. }
  1460. if (changed) {
  1461. spriteAtCursor = 1;
  1462. updateSpriteShown();
  1463. return 1;
  1464. }
  1465. break;
  1466. }
  1467. return 0;
  1468. }
  1469. void SceneEditLayer::scanCursor(int xDir, int yDir) { start_func
  1470. assert(xDir || yDir);
  1471. assert((xDir == -1) || (xDir == 0) || (xDir == 1));
  1472. assert((yDir == -1) || (yDir == 0) || (yDir == 1));
  1473. int x = virtualCursorX;
  1474. int y = virtualCursorY;
  1475. if (x < 0) x = 0;
  1476. if (y < 0) y = 0;
  1477. if (x >= layerWidth) x = layerWidth - 1;
  1478. if (y >= layerHeight) y = layerHeight - 1;
  1479. int offset = x + y * layerWidth;
  1480. int type;
  1481. int first = 1;
  1482. do {
  1483. x += xDir;
  1484. y += yDir;
  1485. if (x < 0) break;
  1486. if (x >= layerWidth) break;
  1487. if (y < 0) break;
  1488. if (y >= layerHeight) break;
  1489. offset += xDir + yDir * layerWidth;
  1490. if (first) {
  1491. first = 0;
  1492. type = layerEdit[cursorLayer][0][offset] & Layer::LAYER_TILE_INDEX;
  1493. }
  1494. else if (layerEdit[cursorLayer][0][offset] & Layer::LAYER_TILE_INDEX) {
  1495. if (!type) break;
  1496. }
  1497. else {
  1498. if (type) {
  1499. x -= xDir;
  1500. y -= yDir;
  1501. break;
  1502. }
  1503. }
  1504. } while (1);
  1505. moveCursor(x * tileWidth, y * tileHeight);
  1506. }
  1507. int SceneEditLayer::useSpawnSelection() const { start_func
  1508. if (selectedSpawns.empty()) return 0;
  1509. if (selectionRect.w) return spriteMode;
  1510. return 1;
  1511. }
  1512. void SceneEditLayer::moveSelection(int newX, int newY) { start_func
  1513. // No dragging of outlines allowed
  1514. if (selectionMode == SELECTION_OUTLINE) return;
  1515. if ((newX != selectionXOffs) || (newY != selectionYOffs)) {
  1516. // Dirty old
  1517. Rect rect = { selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs, selectionRect.w, selectionRect.h };
  1518. setDirtyRect(rect, 1);
  1519. // Move (no limits to where it can move to)
  1520. selectionXOffs = newX;
  1521. selectionYOffs = newY;
  1522. // Dirty new
  1523. rect.x = selectionRect.x + newX;
  1524. rect.y = selectionRect.y + newY;
  1525. setDirtyRect(rect, 1);
  1526. }
  1527. }
  1528. void SceneEditLayer::moveCursor(int newX, int newY) { start_func
  1529. int doTool = 0;
  1530. int newTileX = newX / tileWidth;
  1531. int newTileY = newY / tileHeight;
  1532. if (startToolOnMove) startTool(SDL_BUTTON_LEFT);
  1533. // This alone doesn't make anything dirty; normally, this isn't used;
  1534. // anything that does use it, dirties; we don't track virtual cursor
  1535. // if no active tool
  1536. if (toolActive) {
  1537. if ((newTileX != virtualCursorX) || (virtualCursorY != newTileY)) {
  1538. virtualCursorX = newTileX;
  1539. virtualCursorY = newTileY;
  1540. // Tool
  1541. if (!spriteMode) doTool = 1;
  1542. }
  1543. }
  1544. if (newTileX + cursorW < 1) newTileX = 1 - cursorW;
  1545. if (newTileY + cursorH < 1) newTileY = 1 - cursorH;
  1546. if (newTileX >= layerWidth) newTileX = layerWidth - 1;
  1547. if (newTileY >= layerHeight) newTileY = layerHeight - 1;
  1548. if ((newTileX != cursorX) || (newTileY != cursorY)) {
  1549. Rect rect = { cursorX, cursorY, cursorW, cursorH };
  1550. setDirtyRect(rect);
  1551. cursorX = newTileX;
  1552. cursorY = newTileY;
  1553. // Scroll?
  1554. if (!spriteMode)
  1555. if (myFrame) myFrame->scrollToView(cursorX * tileWidth, cursorY * tileHeight,
  1556. cursorW * tileWidth, cursorH * tileHeight);
  1557. // Dirty
  1558. Rect rect2 = { cursorX, cursorY, cursorW, cursorH };
  1559. setDirtyRect(rect2);
  1560. }
  1561. if ((newX != cursorSpriteX) || (newY != cursorSpriteY)) {
  1562. cursorSpriteX = newX;
  1563. cursorSpriteY = newY;
  1564. // Scroll?
  1565. // @TODO: account for sprite size
  1566. if ((spriteMode) && (myFrame)) myFrame->scrollToView(cursorSpriteX, cursorSpriteY, 1, 1);
  1567. if ((spriteMode) && (toolActive)) doTool = 1;
  1568. }
  1569. if (doTool) dragTool();
  1570. // No active tool, we track virtual cursor, but to CLIPPED coordinates
  1571. else if (!toolActive) {
  1572. virtualCursorX = newTileX;
  1573. virtualCursorY = newTileY;
  1574. }
  1575. }
  1576. void SceneEditLayer::startToolSelectionDrag() { start_func
  1577. startToolOnMove = 0;
  1578. if (toolActive) return;
  1579. toolActive = TOOLS_SELECTDRAG;
  1580. toolStartX = virtualCursorX;
  1581. toolStartY = virtualCursorY;
  1582. toolCtrl = SDL_GetModState() & KMOD_CTRL;
  1583. toolAlt = SDL_GetModState() & KMOD_ALT;
  1584. mousePointer();
  1585. dragTool(1);
  1586. }
  1587. void SceneEditLayer::startTool(int button) { start_func
  1588. startToolOnMove = 0;
  1589. if (toolActive) return;
  1590. // Merge any existing selection
  1591. try {
  1592. mergeSelection();
  1593. }
  1594. catch (UndoException& e) {
  1595. return;
  1596. }
  1597. toolMinX = virtualCursorX;
  1598. toolMinY = virtualCursorY;
  1599. toolMaxX = virtualCursorX;
  1600. toolMaxY = virtualCursorY;
  1601. toolActive = button == SDL_BUTTON_LEFT ? toolL : toolR;
  1602. if (spriteMode) {
  1603. toolStartX = cursorSpriteX;
  1604. toolStartY = cursorSpriteY;
  1605. }
  1606. else {
  1607. toolStartX = virtualCursorX;
  1608. toolStartY = virtualCursorY;
  1609. }
  1610. toolCtrl = SDL_GetModState() & KMOD_CTRL;
  1611. toolAlt = SDL_GetModState() & KMOD_ALT;
  1612. toolContiguous = contiguous;
  1613. imagebar->getDataExt(toolData, toolExt, toolFx);
  1614. // @TODO: not determined: ambient, tweak, collision data, animation
  1615. // @TODO: advanced mode where user determines what to place
  1616. toolDataMask = Layer::LAYER_TILE_COLLISION;
  1617. toolExtMask = Layer::LAYER_EXT_COLL | Layer::LAYER_EXT_COLLTYPE | Layer::LAYER_EXT_UNUSED | Layer::LAYER_EXT_ANIMON | Layer::LAYER_EXT_ANIMREV;
  1618. toolFxMask = Layer::LAYER_FX_UNDEFINED;
  1619. mousePointer();
  1620. dragTool(1);
  1621. }
  1622. void SceneEditLayer::modifyTool() { start_func
  1623. if (toolActive) {
  1624. toolCtrl = SDL_GetModState() & KMOD_CTRL;
  1625. toolAlt = SDL_GetModState() & KMOD_ALT;
  1626. // Selection tools need entire area dirtied because this may cause
  1627. // a deleted selection to reappear
  1628. if ((toolActive == TOOLS_SELECT) || (toolActive == TOOLS_SELECTELLIPSE) || (toolActive == TOOLS_WAND)) {
  1629. setDirty(1);
  1630. }
  1631. dragTool();
  1632. }
  1633. // Always update mouse pointer even if no active tool
  1634. mousePointer();
  1635. }
  1636. void SceneEditLayer::dragTool(int firstTime, int lastTime) { start_func
  1637. if (toolActive) {
  1638. int rX, rY;
  1639. int slope1, slope2;
  1640. Rect rect;
  1641. Rect layerBound = { 0, 0, layerWidth, layerHeight };
  1642. int nonDraw = 0;
  1643. if ((toolActive == TOOLS_SELECT) || (toolActive == TOOLS_SELECTELLIPSE) ||
  1644. (toolActive == TOOLS_DROPPER) || (toolActive == TOOLS_WAND) ||
  1645. (toolActive == TOOLS_SELECTDRAG) || (toolActive == TOOLS_SELECTITEMDRAG) ||
  1646. (toolActive == TOOLS_PLACEITEM) || (toolActive == TOOLS_PLACESERIES) ||
  1647. (toolActive == TOOLS_SELECTITEM)) {
  1648. nonDraw = 1;
  1649. }
  1650. // So that undo warning boxes don't cancel us!
  1651. int tool = toolActive;
  1652. if (lastTime) toolActive = 0;
  1653. try {
  1654. switch (tool) {
  1655. case TOOLS_SELECTITEMDRAG:
  1656. setDirtySelectedSpawns();
  1657. if (lastTime) {
  1658. // For undo
  1659. moveSpawnSelection(toolStartX - toolLastX, toolStartY - toolLastY);
  1660. world->undo.preUndoBlock();
  1661. moveSpawnSelection(cursorSpriteX - toolStartX, cursorSpriteY - toolStartY, 0);
  1662. world->undo.postUndoBlock();
  1663. }
  1664. else if (!firstTime) {
  1665. moveSpawnSelection(cursorSpriteX - toolLastX, cursorSpriteY - toolLastY);
  1666. }
  1667. setDirtySelectedSpawns();
  1668. break;
  1669. case TOOLS_SELECTITEM:
  1670. // Mark old range/rect dirty
  1671. setDirtyPixelBox(toolStartX, toolStartY, toolLastX, toolLastY);
  1672. setDirtySelectedSpawns();
  1673. // Keep a backup copy of old selection
  1674. if (firstTime) {
  1675. backupSelectedSpawns = selectedSpawns;
  1676. backupSelectedSpawnRect = selectedSpawnRect;
  1677. }
  1678. // Refresh from backup if dragging with ctrl/alt or last time (for undo)
  1679. else if ((toolCtrl) || (toolAlt) || (lastTime)) {
  1680. selectedSpawns = backupSelectedSpawns;
  1681. selectedSpawnRect = backupSelectedSpawnRect;
  1682. }
  1683. // Undo?
  1684. if (lastTime) {
  1685. if ((!toolCtrl) && (!toolAlt)) {
  1686. // Clear it AND store undo
  1687. clearSpawnSelection();
  1688. }
  1689. else {
  1690. // Just store undo
  1691. undoStoreSpawnSelect();
  1692. }
  1693. }
  1694. // Clear selection if no ctrl/alt
  1695. else if ((!toolCtrl) && (!toolAlt)) clearSpawnSelection(0);
  1696. // Select
  1697. selectSpawnRect(toolStartX, toolStartY, cursorSpriteX, cursorSpriteY, toolAlt ? 0 : 1);
  1698. recheckSpawnSelection();
  1699. // If first time, no modifiers, and something was selected- switch to drag now
  1700. if ((firstTime) && (!toolCtrl) && (!toolAlt) && (selectedSpawnRect.w)) {
  1701. // Handles undo by running through right now as lasttime
  1702. finishTool();
  1703. startToolSpawnSelectionDrag();
  1704. return;
  1705. }
  1706. // Mark new range dirty
  1707. setDirtyPixelBox(toolStartX, toolStartY, cursorSpriteX, cursorSpriteY);
  1708. setDirtySelectedSpawns();
  1709. // Allow copy now?
  1710. if (lastTime) updateCopyTool();
  1711. break;
  1712. case TOOLS_PLACEITEM:
  1713. case TOOLS_PLACESERIES:
  1714. if (lastTime) {
  1715. // Position it
  1716. spawnPlace->setPos(cursorSpriteX, cursorSpriteY, 1);
  1717. // Add sprite
  1718. // @TODO: Catch undo (and delete newspawn if needed)
  1719. // @TODO: load from currently selected sprite/object/dialog
  1720. // Create
  1721. LayerEdit* layer = scene->getLayerEdit(cursorLayer);
  1722. SpawnEdit* newSpawn = new SpawnEdit(spawnPlace, layer, world->unusedSpawnId());
  1723. newSpawn->markLock();
  1724. // If properties done, shortcut dialog for now
  1725. if ((spawnPropertiesDone) || (newSpawn->propertiesDialog())) {
  1726. // Place on layer- this is the undo point
  1727. newSpawn->setUndoReady();
  1728. layer->addSpawn(newSpawn, myFrame, this); // @TODO: can throw_File / Undo
  1729. newSpawn->markUnlock(); // Layer has it locked now
  1730. // Remember settings for next placement
  1731. delete spawnPlace;
  1732. spawnPlace = new SpawnEdit(newSpawn, NULL);
  1733. spawnPlace->markLock();
  1734. spawnPropertiesDone = 1;
  1735. }
  1736. else {
  1737. delete newSpawn;
  1738. }
  1739. // @TODO: Dirty sprite area only
  1740. setDirty(1);
  1741. if ((tool == TOOLS_PLACEITEM) && (toolL == TOOLS_PLACEITEM)) {
  1742. desktop->broadcastEvent(SDL_COMMAND, TOOLS_SELECTITEM);
  1743. desktop->broadcastEvent(SDL_COMMAND, CMD_RELEASE);
  1744. }
  1745. }
  1746. break;
  1747. case TOOLS_SELECTDRAG:
  1748. // @TODO: Can this use moveselection()?
  1749. // Dirty current selection area
  1750. setDirtyBox(selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs,
  1751. selectionRect.x + selectionRect.w - 1 + selectionXOffs,
  1752. selectionRect.y + selectionRect.h - 1 + selectionYOffs, 1);
  1753. // Float selection?
  1754. if (firstTime) {
  1755. floatSelection();
  1756. }
  1757. else {
  1758. // Move selection
  1759. selectionXOffs += virtualCursorX - toolLastX;
  1760. selectionYOffs += virtualCursorY - toolLastY;
  1761. // Dirty new area also
  1762. setDirtyBox(selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs,
  1763. selectionRect.x + selectionRect.w - 1 + selectionXOffs,
  1764. selectionRect.y + selectionRect.h - 1 + selectionYOffs, 1);
  1765. }
  1766. break;
  1767. case TOOLS_WAND:
  1768. case TOOLS_SELECT:
  1769. case TOOLS_SELECTELLIPSE:
  1770. // Keep a backup copy of old selection
  1771. if (firstTime) {
  1772. memcpy(backupSelected, selected, selectedPitch * layerHeight);
  1773. backupSelectionRect = selectionRect;
  1774. }
  1775. // Refresh from backup if dragging with ctrl/alt
  1776. else if ((toolCtrl) || (toolAlt)) {
  1777. memcpy(selected, backupSelected, selectedPitch * layerHeight);
  1778. selectionRect = backupSelectionRect;
  1779. }
  1780. if (tool == TOOLS_WAND) {
  1781. // We get rectangle from previous time
  1782. if (!firstTime) {
  1783. rect.x = toolMinX;
  1784. rect.y = toolMinY;
  1785. rect.w = toolMaxX - toolMinX + 1;
  1786. rect.h = toolMaxY - toolMinY + 1;
  1787. // Mark previous rect dirty
  1788. setDirtyRect(rect, 1);
  1789. }
  1790. else {
  1791. rect.w = 0;
  1792. }
  1793. }
  1794. else if (tool == TOOLS_SELECT) {
  1795. rect = createRect(toolStartX, toolStartY, virtualCursorX, virtualCursorY);
  1796. }
  1797. else {
  1798. rX = abs(toolStartX - virtualCursorX);
  1799. rY = abs(toolStartY - virtualCursorY);
  1800. // Special case
  1801. if (rX < 1) rX = 1;
  1802. if (rY < 1) rY = 1;
  1803. rect = createRect(toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY);
  1804. }
  1805. // We can't have a selection rect that's bigger than the selection surface
  1806. intersectRects(rect, layerBound);
  1807. // Undo?
  1808. if (lastTime) {
  1809. // If we're clearing selection, we must do extra work here
  1810. if ((!toolCtrl) && (!toolAlt)) {
  1811. // Refresh from backup
  1812. memcpy(selected, backupSelected, selectedPitch * layerHeight);
  1813. selectionRect = backupSelectionRect;
  1814. // Add into rectangle the area we're selecting
  1815. boundRects(selectionRect, rect);
  1816. // Clear it AND store undo
  1817. clearSelection();
  1818. }
  1819. else {
  1820. // Just undo the area we're adding/deleting from
  1821. if (rect.w) undoStoreSelect(rect.x, rect.y, rect.w, rect.h);
  1822. }
  1823. }
  1824. // Clear selection if no ctrl/alt
  1825. else if ((!toolCtrl) && (!toolAlt)) clearSelection(0);
  1826. // Draw
  1827. if (tool == TOOLS_WAND) {
  1828. // @TODO:
  1829. // if (!toolContiguous) { start_func
  1830. // rect = floodFillNonContiguous32(tile, selection, virtualCursorX, virtualCursorY, mapColor32(0, 0, 0, toolAlt ? 0 : 255), toolTolerance);
  1831. // }
  1832. // else {
  1833. // // Use alpha workspace as temp area, use 255/255/255 as filler color
  1834. // drawRect(0, 0, alphaWorkspace->w, alphaWorkspace->h, mapColor32(255, 255, 255, 255), alphaWorkspace);
  1835. // rect = floodFill32(tile, alphaWorkspace, virtualCursorX, virtualCursorY, mapColor32(0, 0, 0, toolAlt ? 0 : 255), toolTolerance);
  1836. // SDL_SetAlpha(alphaWorkspace, 0, 255);
  1837. // SDL_SetColorKey(alphaWorkspace, SDL_SRCCOLORKEY, mapColor32(255, 255, 255, 255));
  1838. // blit(0, 0, alphaWorkspace, 0, 0, selection, tileWidth, tileHeight);
  1839. // SDL_SetColorKey(alphaWorkspace, 0, 0);
  1840. // SDL_SetAlpha(alphaWorkspace, SDL_SRCALPHA, 255);
  1841. // }
  1842. // Remember min/max for undo next time
  1843. if (rect.w) {
  1844. toolMinX = rect.x;
  1845. toolMinY = rect.y;
  1846. toolMaxX = rect.x + rect.w - 1;
  1847. toolMaxY = rect.y + rect.h - 1;
  1848. }
  1849. else {
  1850. // Causes no undo area or undirty to occur next frame
  1851. toolMinX = toolMaxX = -1;
  1852. }
  1853. }
  1854. else if (tool == TOOLS_SELECT) {
  1855. selectRect(toolStartX, toolStartY, virtualCursorX, virtualCursorY, toolAlt ? 0 : 1);
  1856. }
  1857. else {
  1858. selectEllipse(toolStartX, toolStartY, rX, rY, toolAlt ? 0 : 1);
  1859. }
  1860. setDirtyRect(rect, 1);
  1861. // Add to overall selection bounding box
  1862. if (!toolAlt) boundRects(selectionRect, rect);
  1863. // ...or fix selection rectangle if removing stuff
  1864. else fixSelectionRect();
  1865. // Previous
  1866. if (!firstTime) {
  1867. if (tool == TOOLS_WAND) {
  1868. // (was dirtied above, at beginning)
  1869. }
  1870. else if (tool == TOOLS_SELECT) {
  1871. setDirtyBox(toolStartX, toolStartY, toolLastX, toolLastY, 1);
  1872. }
  1873. else {
  1874. rX = abs(toolStartX - toolLastX);
  1875. rY = abs(toolStartY - toolLastY);
  1876. if (rX < 1) rX = 1;
  1877. if (rY < 1) rY = 1;
  1878. setDirtyBox(toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY, 1);
  1879. }
  1880. }
  1881. // Allow copy now?
  1882. if (lastTime) updateCopyTool();
  1883. break;
  1884. case TOOLS_DROPPER:
  1885. // @TODO:
  1886. break;
  1887. case TOOLS_PEN:
  1888. if (!lastTime) {
  1889. layerDrawLine(toolStartX, toolStartY, virtualCursorX, virtualCursorY, layerEdit[cursorLayer][0], toolDataMask, toolData);
  1890. if (layerEdit[cursorLayer][1]) layerDrawLine(toolStartX, toolStartY, virtualCursorX, virtualCursorY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
  1891. if (layerEdit[cursorLayer][2]) layerDrawLine(toolStartX, toolStartY, virtualCursorX, virtualCursorY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
  1892. setDirtyBox(toolStartX, toolStartY, virtualCursorX, virtualCursorY);
  1893. }
  1894. // Track area covered for undo
  1895. if (virtualCursorX < toolMinX) toolMinX = virtualCursorX;
  1896. if (virtualCursorX > toolMaxX) toolMaxX = virtualCursorX;
  1897. if (virtualCursorY < toolMinY) toolMinY = virtualCursorY;
  1898. if (virtualCursorY > toolMaxY) toolMaxY = virtualCursorY;
  1899. if (toolStartX < toolMinX) toolMinX = toolStartX;
  1900. if (toolStartX > toolMaxX) toolMaxX = toolStartX;
  1901. if (toolStartY < toolMinY) toolMinY = toolStartY;
  1902. if (toolStartY > toolMaxY) toolMaxY = toolStartY;
  1903. toolStartX = virtualCursorX;
  1904. toolStartY = virtualCursorY;
  1905. if (lastTime) undoStoreLayerBox(toolMinX, toolMinY, toolMaxX, toolMaxY);
  1906. else if (tools) ; // @TODO: preview redraw
  1907. break;
  1908. case TOOLS_FILL:
  1909. // @TODO: advanced option to specify mask of what to check fill against
  1910. // Undo based on rectangle from last time
  1911. if (lastTime) undoStoreLayerBox(toolMinX, toolMinY, toolMaxX, toolMaxY);
  1912. // Dirty previous rectangle
  1913. if (!firstTime) {
  1914. refreshData(1, toolMinX, toolMinY, toolMaxX, toolMaxY);
  1915. setDirtyBox(toolMinX, toolMinY, toolMaxX, toolMaxY);
  1916. }
  1917. // Flood fill
  1918. // @TODO: doesn't support layer [2] (effects data)
  1919. if (!toolContiguous) {
  1920. if (layerEdit[cursorLayer][1]) rect = layerMatchFill(virtualCursorX, virtualCursorY, Layer::LAYER_TILE_FILL_MASK, layerEdit[cursorLayer][0], toolDataMask, toolData, layerEdit[cursorLayer][1], toolExtMask, toolExt);
  1921. else rect = layerMatchFill(virtualCursorX, virtualCursorY, Layer::LAYER_TILE_FILL_MASK, layerEdit[cursorLayer][0], toolDataMask, toolData);
  1922. }
  1923. else {
  1924. if (layerEdit[cursorLayer][1]) rect = layerFloodFill(virtualCursorX, virtualCursorY, Layer::LAYER_TILE_FILL_MASK, layerEdit[cursorLayer][0], toolDataMask, toolData, layerEdit[cursorLayer][1], toolExtMask, toolExt);
  1925. else rect = layerFloodFill(virtualCursorX, virtualCursorY, Layer::LAYER_TILE_FILL_MASK, layerEdit[cursorLayer][0], toolDataMask, toolData);
  1926. }
  1927. setDirtyRect(rect);
  1928. // Remember min/max for undo on last time
  1929. if (rect.w) {
  1930. toolMinX = rect.x;
  1931. toolMinY = rect.y;
  1932. toolMaxX = rect.x + rect.w - 1;
  1933. toolMaxY = rect.y + rect.h - 1;
  1934. }
  1935. else {
  1936. // Causes no undo area or undirty to occur next frame
  1937. toolMinX = toolMaxX = -1;
  1938. }
  1939. break;
  1940. case TOOLS_LINE:
  1941. case TOOLS_RECT:
  1942. case TOOLS_RECTFILL:
  1943. if (lastTime) undoStoreLayerBox(toolStartX, toolStartY, virtualCursorX, virtualCursorY);
  1944. // Reload from last time, not entire layer
  1945. if (!firstTime) refreshData(1, toolStartX, toolStartY, toolLastX, toolLastY);
  1946. rX = virtualCursorX;
  1947. rY = virtualCursorY;
  1948. // Limit to square or straight line?
  1949. if (toolCtrl) {
  1950. if (tool == TOOLS_LINE) {
  1951. // Determine approximate slope of line
  1952. slope1 = abs(toolStartX - rX);
  1953. slope2 = abs(toolStartY - rY);
  1954. // (we only care, if both sizes are > 0)
  1955. if ((slope1) && (slope2)) {
  1956. if (slope1 > slope2) swap(slope1, slope2);
  1957. // slope1/slope2 will be a fraction between 0 (flat) and
  1958. // 1 (diagonal of 45deg multiple); cutoff point is 0.5
  1959. if (slope1 * 2 / slope2 >= 1) {
  1960. // Square
  1961. if (abs(toolStartX - rX) < abs(toolStartY - rY)) {
  1962. rY = toolStartY + abs(toolStartX - rX) * (toolStartY < rY ? 1 : -1);
  1963. }
  1964. else {
  1965. rX = toolStartX + abs(toolStartY - rY) * (toolStartX < rX ? 1 : -1);
  1966. }
  1967. }
  1968. else {
  1969. // Flat line
  1970. if (abs(toolStartX - rX) < abs(toolStartY - rY)) {
  1971. rX = toolStartX;
  1972. }
  1973. else {
  1974. rY = toolStartY;
  1975. }
  1976. }
  1977. }
  1978. }
  1979. else {
  1980. // Square
  1981. if (abs(toolStartX - rX) < abs(toolStartY - rY)) {
  1982. rY = toolStartY + abs(toolStartX - rX) * (toolStartY < rY ? 1 : -1);
  1983. }
  1984. else {
  1985. rX = toolStartX + abs(toolStartY - rY) * (toolStartX < rX ? 1 : -1);
  1986. }
  1987. }
  1988. }
  1989. if (tool == TOOLS_LINE) {
  1990. layerDrawLine(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][0], toolDataMask, toolData);
  1991. if (layerEdit[cursorLayer][1]) layerDrawLine(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
  1992. if (layerEdit[cursorLayer][2]) layerDrawLine(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
  1993. }
  1994. else if (tool == TOOLS_RECT) {
  1995. layerDrawBox(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][0], toolDataMask, toolData);
  1996. if (layerEdit[cursorLayer][1]) layerDrawBox(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
  1997. if (layerEdit[cursorLayer][2]) layerDrawBox(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
  1998. }
  1999. else {
  2000. layerDrawRect(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][0], toolDataMask, toolData);
  2001. if (layerEdit[cursorLayer][1]) layerDrawRect(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
  2002. if (layerEdit[cursorLayer][2]) layerDrawRect(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
  2003. }
  2004. setDirtyBox(toolStartX, toolStartY, rX, rY);
  2005. // (no need to limit based on toolCtrl, as a limited area will always
  2006. // be smaller than this area we use here)
  2007. if (!firstTime) setDirtyBox(toolStartX, toolStartY, toolLastX, toolLastY);
  2008. break;
  2009. case TOOLS_ELLIPSE:
  2010. case TOOLS_ELLIPSEFILL:
  2011. rX = abs(toolStartX - virtualCursorX);
  2012. rY = abs(toolStartY - virtualCursorY);
  2013. // Special case
  2014. if (rX < 1) rX = 1;
  2015. if (rY < 1) rY = 1;
  2016. // Circle?
  2017. if (toolCtrl) {
  2018. rX = min(rX, rY);
  2019. rY = rX;
  2020. }
  2021. if (lastTime) undoStoreLayerBox(toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY);
  2022. // reload from area affected last time, not entire layer
  2023. int prX, prY;
  2024. if (!firstTime) {
  2025. prX = abs(toolStartX - toolLastX);
  2026. prY = abs(toolStartY - toolLastY);
  2027. if (prX < 1) prX = 1;
  2028. if (prY < 1) prY = 1;
  2029. // (no need to limit to a circle based on toolCtrl, this will always
  2030. // cover the minimum area needed)
  2031. refreshData(1, toolStartX - prX, toolStartY - prY, toolStartX + prX, toolStartY + prY);
  2032. }
  2033. if (tool == TOOLS_ELLIPSE) {
  2034. layerDrawEllipse(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][0], toolDataMask, toolData);
  2035. if (layerEdit[cursorLayer][1]) layerDrawEllipse(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
  2036. if (layerEdit[cursorLayer][2]) layerDrawEllipse(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
  2037. }
  2038. else {
  2039. layerDrawEllipseFill(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][0], toolDataMask, toolData);
  2040. if (layerEdit[cursorLayer][1]) layerDrawEllipseFill(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
  2041. if (layerEdit[cursorLayer][2]) layerDrawEllipseFill(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
  2042. }
  2043. setDirtyBox(toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY);
  2044. // Previous
  2045. if (!firstTime) {
  2046. setDirtyBox(toolStartX - prX, toolStartY - prY, toolStartX + prX, toolStartY + prY);
  2047. }
  2048. break;
  2049. }
  2050. }
  2051. catch (UndoException& e) {
  2052. toolActive = tool;
  2053. cancelTool();
  2054. return;
  2055. }
  2056. if ((lastTime) && (!nonDraw)) {
  2057. // @TODO: only apply a section (to reduce overhead on preview updates)
  2058. applyData(1);
  2059. }
  2060. else if (!nonDraw) ; // @TODO: preview redraw
  2061. if (spriteMode) {
  2062. toolLastX = cursorSpriteX;
  2063. toolLastY = cursorSpriteY;
  2064. }
  2065. else {
  2066. toolLastX = virtualCursorX;
  2067. toolLastY = virtualCursorY;
  2068. }
  2069. }
  2070. }
  2071. void SceneEditLayer::cancelTool() { start_func
  2072. startToolOnMove = 0;
  2073. if (toolActive) {
  2074. int rX;
  2075. int rY;
  2076. switch (toolActive) {
  2077. case TOOLS_SELECT:
  2078. case TOOLS_SELECTELLIPSE:
  2079. case TOOLS_WAND:
  2080. // Refresh from backup, dirty all
  2081. memcpy(selected, backupSelected, selectedPitch * layerHeight);
  2082. backupSelectionRect = selectionRect;
  2083. setDirty(1);
  2084. break;
  2085. case TOOLS_PEN:
  2086. case TOOLS_FILL:
  2087. refreshData(1, toolMinX, toolMinY, toolMaxX, toolMaxY);
  2088. // @TODO: preview redraw
  2089. setDirtyBox(toolMinX, toolMinY, toolMaxX, toolMaxY);
  2090. break;
  2091. case TOOLS_LINE:
  2092. case TOOLS_RECT:
  2093. case TOOLS_RECTFILL:
  2094. refreshData(1, toolStartX, toolStartY, toolLastX, toolLastY);
  2095. // @TODO: preview redraw
  2096. setDirtyBox(toolStartX, toolStartY, toolLastX, toolLastY);
  2097. break;
  2098. case TOOLS_ELLIPSE:
  2099. case TOOLS_ELLIPSEFILL:
  2100. rX = abs(toolStartX - toolLastX);
  2101. rY = abs(toolStartY - toolLastY);
  2102. if (rX < 1) rX = 1;
  2103. if (rY < 1) rY = 1;
  2104. refreshData(1, toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY);
  2105. // @TODO: preview redraw
  2106. setDirtyBox(toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY);
  2107. break;
  2108. }
  2109. mousePointer();
  2110. toolActive = 0;
  2111. }
  2112. }
  2113. void SceneEditLayer::finishTool() { start_func
  2114. startToolOnMove = 0;
  2115. if (toolActive) {
  2116. dragTool(0, 1);
  2117. mousePointer();
  2118. // toolActive = 0 taken care of by dragtool
  2119. }
  2120. }
  2121. void SceneEditLayer::display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset) { start_func
  2122. assert(destSurface);
  2123. if (visible) {
  2124. // If dirty, redraw range or all
  2125. if (dirty) {
  2126. if (totalDirty) {
  2127. // Range should include entire area, so we cover "outside" current
  2128. // layer if appropriate
  2129. toDisplay = clipArea;
  2130. }
  2131. else {
  2132. dirtyRange.x += x + xOffset;
  2133. dirtyRange.y += y + yOffset;
  2134. // Range must include requested update area as well
  2135. boundRects(toDisplay, dirtyRange);
  2136. }
  2137. dirty = totalDirty = 0;
  2138. dirtyRange.w = 0;
  2139. intersectRects(toDisplay, clipArea);
  2140. }
  2141. xOffset += x;
  2142. yOffset += y;
  2143. // Anything to draw?
  2144. if (toDisplay.w) {
  2145. SDL_SetClipRect(destSurface, &toDisplay);
  2146. SDL_FillRect(destSurface, &toDisplay, guiPacked[COLOR_BKFILL]);
  2147. // Draw all visible layers, bottom up
  2148. int pos = numLayers - 1;
  2149. Uint32 bit = 1 << pos;
  2150. for (; pos >= 0; --pos, bit >>= 1) {
  2151. if (layersView & bit) {
  2152. int dim = layersDim & bit;
  2153. if (pos == cursorLayer) dim = 0;
  2154. if (layersAffect & bit) {
  2155. // Draw directly from our data, or use our data as floating?
  2156. if (selectionMode == SELECTION_OUTLINE) {
  2157. LayerEdit::blitTileLayer(scene->getLayerEdit(pos)->getTileSetEdit(),
  2158. layerEdit[pos][0], layerEdit[pos][1],
  2159. layerWidth, layerHeight,
  2160. toDisplay.x - xOffset, toDisplay.y - yOffset,
  2161. toDisplay.w, toDisplay.h,
  2162. xOffset, yOffset, destSurface, dim);
  2163. }
  2164. else {
  2165. LayerEdit* layer = scene->getLayerEdit(pos);
  2166. LayerEdit::blitTileLayer(layer->getTileSetEdit(),
  2167. layer->getTileData(), layer->getExtendedData(),
  2168. layerWidth, layerHeight,
  2169. toDisplay.x - xOffset, toDisplay.y - yOffset,
  2170. toDisplay.w, toDisplay.h,
  2171. xOffset, yOffset, destSurface, dim,
  2172. layerEdit[pos][0], layerEdit[pos][1],
  2173. selectionXOffs, selectionYOffs, layerWidth);
  2174. }
  2175. }
  2176. else {
  2177. scene->getLayerEdit(pos)->blit(toDisplay.x - xOffset, toDisplay.y - yOffset,
  2178. toDisplay.w, toDisplay.h,
  2179. xOffset, yOffset, destSurface, dim);
  2180. }
  2181. // @TODO: separate dim determination for spawns
  2182. scene->getLayerEdit(pos)->blitSpawns(toDisplay.x - xOffset, toDisplay.y - yOffset,
  2183. toDisplay.w, toDisplay.h,
  2184. xOffset, yOffset, destSurface,
  2185. &selectedSpawns, dim ? 1 : 0);
  2186. }
  2187. }
  2188. // Draw grid (top/left lines)
  2189. if (enableGrid) {
  2190. // Determine first/last rows to show
  2191. int tY = max(0, (toDisplay.y - yOffset) / tileHeight);
  2192. int bottom = (toDisplay.y + toDisplay.h - yOffset - 1) / tileHeight;
  2193. if (bottom > layerHeight) bottom = layerHeight;
  2194. // Determine first/last tiles of each row we need to show
  2195. int tX = max(0, (toDisplay.x - xOffset) / tileWidth);
  2196. int rightmost = (toDisplay.x + toDisplay.w - xOffset - 1) / tileWidth;
  2197. if (rightmost > layerWidth) rightmost = layerWidth;
  2198. // Determine the starting x/y pixel
  2199. int dX = xOffset + tX * tileWidth;
  2200. int dY = yOffset + tY * tileHeight;
  2201. int fY = dY;
  2202. // Determine length of lines
  2203. // @TODO: displays one pixel too short in some corner cases
  2204. int lineW = min((int)toDisplay.w, layerWidth * tileWidth - toDisplay.x + xOffset);
  2205. int lineH = min((int)toDisplay.h, layerHeight * tileHeight - toDisplay.y + yOffset);
  2206. // Horizontal lines
  2207. if (lineW > 0) {
  2208. for (; tY <= bottom; ++tY) {
  2209. drawHLine(dX, toDisplay.x + lineW, dY, guiPacked[COLOR_GRID], destSurface);
  2210. dY += tileHeight;
  2211. }
  2212. }
  2213. // Vertical lines
  2214. if (lineH > 0) {
  2215. for (; tX <= rightmost; ++tX) {
  2216. drawVLine(fY, toDisplay.y + lineH, dX, guiPacked[COLOR_GRID], destSurface);
  2217. dX += tileWidth;
  2218. }
  2219. }
  2220. }
  2221. // Draw cursor (@TODO: cursors>1 combined with a centered client within frame may allow cursor to go off edges- ok?)
  2222. if (partialFocus) {
  2223. int cX = xOffset + cursorX * tileWidth;
  2224. int cY = yOffset + cursorY * tileHeight;
  2225. drawSelectRect(cX, cY, cursorW * tileWidth, cursorH * tileHeight,
  2226. guiPacked[haveFocus ? COLOR_TILECURSOR : COLOR_TILESELECTION], destSurface,
  2227. haveFocus ? desktop->currentCursorAlpha() : 128);
  2228. drawBox(cX, cY, cursorW * tileWidth, cursorH * tileHeight, guiPacked[COLOR_TILECURSORBORDER1], destSurface);
  2229. drawBox(cX + 1, cY + 1, cursorW * tileWidth - 2, cursorH * tileHeight - 2, guiPacked[COLOR_TILECURSORBORDER2], destSurface);
  2230. }
  2231. // Now handle selection borders
  2232. if ((partialFocus) && (selectionRect.w)) {
  2233. // Determine first/last rows to show
  2234. int tY = max(0, (toDisplay.y - yOffset) / tileHeight);
  2235. int bottom = (toDisplay.y + toDisplay.h - yOffset - 1) / tileHeight;
  2236. if (bottom >= layerHeight) bottom = layerHeight - 1;
  2237. // Determine first/last tiles of each row we need to show
  2238. int leftmost = max(0, (toDisplay.x - xOffset) / tileWidth);
  2239. int rightmost = (toDisplay.x + toDisplay.w - xOffset - 1) / tileWidth;
  2240. if (rightmost >= layerWidth) rightmost = layerWidth - 1;
  2241. // Clip to selection boundaries
  2242. if (tY < selectionRect.y + selectionYOffs) tY = selectionRect.y + selectionYOffs;
  2243. if (bottom >= selectionRect.y + selectionRect.h + selectionYOffs) bottom = selectionRect.y + selectionRect.h + selectionYOffs - 1;
  2244. if (leftmost < selectionRect.x + selectionXOffs) leftmost = selectionRect.x + selectionXOffs;
  2245. if (rightmost >= selectionRect.x + selectionRect.w + selectionXOffs) rightmost = selectionRect.x + selectionRect.w + selectionXOffs - 1;
  2246. // Determine the starting x/y pixel
  2247. int dX = xOffset + leftmost * tileWidth;
  2248. int dY = yOffset + tY * tileHeight;
  2249. for (; tY <= bottom; ++tY) {
  2250. // Place in bitarray terms
  2251. Uint8 bit = 1 << ((leftmost - selectionXOffs) & 7);
  2252. Uint8* selData = selected + ((leftmost - selectionXOffs) >> 3) + (tY - selectionYOffs) * selectedPitch;
  2253. Uint8 prevbit = bit >> 1;
  2254. Uint8* prevData = selData;
  2255. if (prevbit == 0) {
  2256. prevbit = 128;
  2257. --prevData;
  2258. }
  2259. Uint8 nextbit = bit << 1;
  2260. Uint8* nextData = selData;
  2261. if (nextbit == 0) {
  2262. nextbit = 1;
  2263. ++nextData;
  2264. }
  2265. for (int tX = leftmost; tX <= rightmost; ++tX) {
  2266. if (*selData & bit) {
  2267. // Don't highlight if part of cursor
  2268. if ((tX < cursorX) || (tX >= cursorX + cursorW) ||
  2269. (tY < cursorY) || (tY >= cursorY + cursorH)) {
  2270. drawSelectRect(dX, dY, tileWidth, tileHeight,
  2271. guiPacked[COLOR_TILESELECTION], destSurface);
  2272. }
  2273. // Draw ants borders
  2274. int drawT = 1;
  2275. int drawB = 1;
  2276. int drawL = 1;
  2277. int drawR = 1;
  2278. // Determine which borders to hide
  2279. if ((tY > selectionYOffs) && (*(selData - selectedPitch) & bit)) drawT = 0;
  2280. if ((tY < (layerHeight + selectionYOffs - 1)) && (*(selData + selectedPitch) & bit)) drawB = 0;
  2281. if ((tX > selectionXOffs) && (*prevData & prevbit)) drawL = 0;
  2282. if ((tX < (layerWidth + selectionXOffs - 1)) && (*nextData & nextbit)) drawR = 0;
  2283. if (drawT) drawAntsHLine(dX, dX + tileWidth - 1, dY, desktop->currentSelectionPhase(), destSurface);
  2284. if (drawB) drawAntsHLine(dX, dX + tileWidth - 1, dY + tileHeight - 1, desktop->currentSelectionPhase(), destSurface);
  2285. if (drawL) drawAntsVLine(dY, dY + tileHeight - 1, dX, desktop->currentSelectionPhase(), destSurface);
  2286. if (drawR) drawAntsVLine(dY, dY + tileHeight - 1, dX + tileWidth - 1, desktop->currentSelectionPhase(), destSurface);
  2287. }
  2288. prevbit = bit;
  2289. bit = nextbit;
  2290. prevData = selData;
  2291. selData = nextData;
  2292. nextbit <<= 1;
  2293. if (nextbit == 0) {
  2294. nextbit = 1;
  2295. ++nextData;
  2296. }
  2297. dX += tileWidth;
  2298. }
  2299. dX = xOffset + leftmost * tileWidth;
  2300. dY += tileHeight;
  2301. }
  2302. }
  2303. // Draw sprite cursor?
  2304. if (spriteShown) {
  2305. spawnPlace->setPos(spriteShownX, spriteShownY, 1);
  2306. spawnPlace->blit(xOffset, yOffset, destSurface, toDisplay.x - xOffset,
  2307. toDisplay.y - yOffset, toDisplay.w, toDisplay.h, 2);
  2308. }
  2309. // Sprite selection box?
  2310. if (toolActive == TOOLS_SELECTITEM) {
  2311. Rect selArea = createRect(toolStartX, toolStartY, toolLastX, toolLastY);
  2312. drawSelectRect(selArea.x + xOffset, selArea.y + yOffset,
  2313. selArea.w, selArea.h,
  2314. guiPacked[COLOR_SELECTION1], destSurface);
  2315. drawAntsBox(selArea.x + xOffset, selArea.y + yOffset,
  2316. selArea.w, selArea.h,
  2317. desktop->currentSelectionPhase(), destSurface);
  2318. }
  2319. }
  2320. }
  2321. }
  2322. void SceneEditLayer::undoStoreLayerBox(int x1, int y1, int x2, int y2, int cursorLayerOnly) throw_Undo { start_func
  2323. if (x1 > x2) swap(x1, x2);
  2324. if (y1 > y2) swap(y1, y2);
  2325. undoStoreLayer(x1, y1, x2 - x1 + 1, y2 - y1 + 1, cursorLayerOnly);
  2326. }
  2327. void SceneEditLayer::undoStoreLayer(int x, int y, int w, int h, int cursorLayerOnly) throw_Undo { start_func
  2328. Uint32 bit = 1;
  2329. int pos = 0;
  2330. int max = numLayers - 1;
  2331. if (cursorLayerOnly) {
  2332. pos = max = cursorLayer;
  2333. if (pos) bit <<= pos;
  2334. }
  2335. world->undo.preUndoBlock();
  2336. for (; pos <= max; ++pos, bit <<= 1) {
  2337. if (layersAffect & bit) {
  2338. world->undo.storeUndoLayerTile(scene->getLayer(pos)->getId(), x, y, w, h, myFrame);
  2339. }
  2340. }
  2341. world->undo.postUndoBlock();
  2342. }
  2343. void SceneEditLayer::undoStoreSelect(int x, int y, int w, int h, int forceStoreData) throw_Undo { start_func
  2344. // we have to ensure x/y/w/h are within range ourselves
  2345. if (x < 0) x = 0;
  2346. if (y < 0) y = 0;
  2347. if (x + w >= layerWidth) w = layerWidth - x - 1;
  2348. if (y + h >= layerHeight) h = layerHeight - y - 1;
  2349. world->undo.preUndoBlock();
  2350. world->undo.storeUndoLayerTileCur(layersAffect, layersView, layersDim, myFrame);
  2351. // Before data, if not floating
  2352. if (selectionMode == SELECTION_OUTLINE) {
  2353. world->undo.storeUndoLayerTileSelection(&selected, x, y, w, h, selectedPitch, selectionXOffs, selectionYOffs, selectionMode, myFrame);
  2354. }
  2355. // Store data too, if not an outline
  2356. if ((selectionMode != SELECTION_OUTLINE) || (forceStoreData)) {
  2357. Uint32 bit = 1;
  2358. for (int pos = 0; pos < numLayers; ++pos, bit <<= 1) {
  2359. if (layersAffect & bit) {
  2360. world->undo.storeUndoLayerTileTemp(&layerEdit[pos][0], &layerEdit[pos][1], &layerEdit[pos][2], x, y, w, h, layerWidth, myFrame);
  2361. }
  2362. }
  2363. }
  2364. // After data, if floating
  2365. if (selectionMode != SELECTION_OUTLINE) {
  2366. world->undo.storeUndoLayerTileSelection(&selected, x, y, w, h, selectedPitch, selectionXOffs, selectionYOffs, selectionMode, myFrame);
  2367. }
  2368. world->undo.storeUndoLayerTileCur(layersAffect, layersView, layersDim, myFrame);
  2369. world->undo.postUndoBlock();
  2370. }
  2371. void SceneEditLayer::clearSelection(int storeUndo) throw_Undo { start_func
  2372. assert(selected);
  2373. if (selectionRect.w) {
  2374. if (storeUndo) undoStoreSelect(selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h);
  2375. memset(selected, 0, selectedPitch * layerHeight);
  2376. // If a floating selection, reload data
  2377. if (selectionMode != SELECTION_OUTLINE) refreshData(0);
  2378. // Add in offset so proper area is dirtied
  2379. selectionRect.x += selectionXOffs;
  2380. selectionRect.y += selectionYOffs;
  2381. setDirtyRect(selectionRect);
  2382. selectionRect.w = 0;
  2383. selectionXOffs = selectionYOffs = 0;
  2384. selectionMode = SELECTION_OUTLINE;
  2385. }
  2386. updateCopyTool();
  2387. }
  2388. void SceneEditLayer::floatSelection(int copyPrep, int delSel) throw_Undo { start_func
  2389. if ((selectionMode == SELECTION_OUTLINE) && (selectionRect.w)) {
  2390. if (!copyPrep) {
  2391. world->undo.preUndoBlock();
  2392. undoStoreLayer(selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h, 0);
  2393. undoStoreSelect(selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h, 1);
  2394. world->undo.postUndoBlock();
  2395. }
  2396. // (set dirty first, in case rect resizes)
  2397. setDirtyRect(selectionRect);
  2398. // Cut out selection on each layer
  2399. Uint32* tempFloat = NULL;
  2400. Uint32* tempFloatExt = NULL;
  2401. Uint32* tempFloatFx = NULL;
  2402. Rect affect = { 0, 0, layerWidth, layerHeight };
  2403. int affectBit = 1;
  2404. int layerSize = layerWidth * layerHeight;
  2405. for (int pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
  2406. if (layersAffect & affectBit) {
  2407. // Allocate temporary storage to float selection to
  2408. tempFloat = new Uint32[layerSize];
  2409. memSet32(tempFloat, Layer::LAYER_TILE_DEFAULT, layerSize);
  2410. if (layerEdit[pos][1]) {
  2411. tempFloatExt = new Uint32[layerSize];
  2412. memSet32(tempFloatExt, Layer::LAYER_EXT_DEFAULT, layerSize);
  2413. }
  2414. if (layerEdit[pos][2]) {
  2415. tempFloatFx = new Uint32[layerSize];
  2416. memSet32(tempFloatFx, Layer::LAYER_FX_DEFAULT, layerSize);
  2417. }
  2418. // Scan layer and move selected data that isn't tile 0
  2419. Uint8 bit = 1;
  2420. Uint8* source = selected;
  2421. Uint32* src = layerEdit[pos][0];
  2422. Uint32* srcExt = layerEdit[pos][1];
  2423. Uint32* srcFx = layerEdit[pos][2];
  2424. Uint32* dest = tempFloat;
  2425. Uint32* destExt = tempFloatExt;
  2426. Uint32* destFx = tempFloatFx;
  2427. for (int y = 0; y < layerHeight; ++y) {
  2428. for (int x = 0; x < layerWidth; ++x) {
  2429. if (((*src & Layer::LAYER_TILE_INDEX) != 0) && (*source & bit)) {
  2430. *dest = *src;
  2431. *src = Layer::LAYER_TILE_DEFAULT;
  2432. if (srcExt) {
  2433. *destExt = *srcExt;
  2434. *srcExt = Layer::LAYER_EXT_DEFAULT;
  2435. }
  2436. if (srcFx) {
  2437. *destFx = *srcFx;
  2438. *srcFx = Layer::LAYER_FX_DEFAULT;
  2439. }
  2440. }
  2441. ++src;
  2442. ++dest;
  2443. if (srcExt) {
  2444. ++srcExt;
  2445. ++destExt;
  2446. }
  2447. if (srcFx) {
  2448. ++srcFx;
  2449. ++destFx;
  2450. }
  2451. bit <<= 1;
  2452. if (bit == 0) {
  2453. bit = 1;
  2454. ++source;
  2455. }
  2456. }
  2457. // If bit just wrapped to 1, we have an even multiple
  2458. // otherwise, move forward the final byte
  2459. if (bit > 1) ++source;
  2460. bit = 1;
  2461. }
  2462. // Apply data
  2463. if (!copyPrep) scene->getLayerEdit(pos)->saveLayer(layerEdit[pos][0], layerEdit[pos][1], layerEdit[pos][2], layerWidth, affect, this);
  2464. // Replace our layer data
  2465. if (delSel) {
  2466. delete[] tempFloat;
  2467. delete[] tempFloatExt;
  2468. delete[] tempFloatFx;
  2469. }
  2470. else {
  2471. delete[] layerEdit[pos][0];
  2472. delete[] layerEdit[pos][1];
  2473. delete[] layerEdit[pos][2];
  2474. layerEdit[pos][0] = tempFloat;
  2475. layerEdit[pos][1] = tempFloatExt;
  2476. layerEdit[pos][2] = tempFloatFx;
  2477. }
  2478. tempFloat = NULL;
  2479. tempFloatExt = NULL;
  2480. tempFloatFx = NULL;
  2481. }
  2482. }
  2483. if (delSel) return;
  2484. fixSelectionRect(1);
  2485. selectionMode = SELECTION_OPAQUE;
  2486. // (possible that there's no selection now)
  2487. updateCopyTool();
  2488. }
  2489. }
  2490. void SceneEditLayer::doneSelection() throw_Undo { start_func
  2491. if (selectionMode == SELECTION_OUTLINE) clearSelection();
  2492. else mergeSelection();
  2493. }
  2494. int SceneEditLayer::pasteSelection() throw_Undo { start_func
  2495. if (canConvertClipboard(CLIPBOARD_SPAWN)) {
  2496. int pNumSpawns;
  2497. int pNumLayers;
  2498. clipboardPasteSpawnInfo(&pNumSpawns, &pNumLayers);
  2499. // Note affected layers- warn user for problems
  2500. int affectBit = 1;
  2501. int matchedLayers = 0;
  2502. int pos = 0;
  2503. map<int, int> layerMapping;
  2504. // One layer of data = always on cursor layer
  2505. if (pNumLayers == 1) {
  2506. layerMapping[0] = cursorLayer;
  2507. matchedLayers = 1;
  2508. }
  2509. else {
  2510. for (; pos < numLayers; ++pos, affectBit <<= 1) {
  2511. if (layersAffect & affectBit) {
  2512. layerMapping[matchedLayers] = pos;
  2513. ++matchedLayers;
  2514. }
  2515. }
  2516. }
  2517. // Too many layers?
  2518. if (matchedLayers < pNumLayers) {
  2519. if (!guiConfirmBox("Clipboard contains objects on more layers than marked for editing- continue?", "Layer Mismatch")) return 0;
  2520. }
  2521. // Determine base x/y-
  2522. // Start with mouse position
  2523. // Prefer cursor position if more recently used
  2524. // Prefer offset from current selection position if any
  2525. // Ensure upperleft corner is not further up than onscreen upper-left
  2526. // (move selection to be visible if too far offscreen to right/bottom)
  2527. int baseX = pixelMouseX;
  2528. int baseY = pixelMouseY;
  2529. if (spriteAtCursor) {
  2530. baseX = cursorX * tileWidth;
  2531. baseY = cursorY * tileHeight;
  2532. }
  2533. if (selectedSpawnRect.w) {
  2534. baseX = selectedSpawnRect.x + tileWidth;
  2535. baseY = selectedSpawnRect.y + tileHeight;
  2536. }
  2537. while (baseX > -x + viewWidth - tileWidth) baseX -= tileWidth;
  2538. while (baseY > -y + viewHeight - tileHeight) baseY -= tileHeight;
  2539. while (baseX < -x) baseX += tileWidth;
  2540. while (baseY < -y) baseY += tileHeight;
  2541. // Start undo and clear current spawn selection (storing undo for that too)
  2542. world->undo.preUndoBlock();
  2543. setDirtySelectedSpawns();
  2544. clearSpawnSelection(); // @TODO: can throw Undo (ok?)
  2545. // Now actually paste spawn data
  2546. for (pos = 0; pos < pNumSpawns; ++pos) {
  2547. int lNum;
  2548. SpawnEdit* newSpawn = new SpawnEdit(world, NULL, world->unusedSpawnId());
  2549. clipboardPasteSpawn(pos, newSpawn, &lNum, baseX, baseY);
  2550. LayerEdit* layer = scene->getLayerEdit(layerMapping[lNum]);
  2551. newSpawn->setLayer(layer);
  2552. newSpawn->setUndoReady();
  2553. layer->addSpawn(newSpawn, myFrame, this); // @TODO: can throw_File / Undo
  2554. selectedSpawns.insert(newSpawn->getId());
  2555. }
  2556. // Finalize selection and undo
  2557. recheckSpawnSelection();
  2558. world->undo.postUndoBlock();
  2559. updateCopyTool();
  2560. setDirtySelectedSpawns();
  2561. return TOOLS_SELECTITEM;
  2562. }
  2563. else if (canConvertClipboard(CLIPBOARD_LAYER)) {
  2564. int pNumLayers;
  2565. int pWidth;
  2566. int pHeight;
  2567. const void* pTileSet;
  2568. int pHasExt;
  2569. int pHasFx;
  2570. int warnedTileSet = 0;
  2571. int warnedExt = 0;
  2572. int warnedFx = 0;
  2573. clipboardPasteLayerInfo(&pNumLayers, &pWidth, &pHeight);
  2574. // Match up against affected layers- warn user for problems
  2575. int affectBit = 1;
  2576. int matchedLayers = 0;
  2577. int pos = 0;
  2578. for (; pos < numLayers; ++pos, affectBit <<= 1) {
  2579. if (layersAffect & affectBit) {
  2580. clipboardPasteLayerInfoDetails(matchedLayers, &pTileSet, &pHasExt, &pHasFx);
  2581. // Same tileset? (if one specified)
  2582. if ((pTileSet) && (!warnedTileSet)) {
  2583. if (pTileSet != scene->getLayer(pos)->getTileSet()) {
  2584. if (!guiConfirmBox("Layer tileset may not match clipboard data- continue?", "Tileset Mismatch")) return 0;
  2585. warnedTileSet = 1;
  2586. }
  2587. }
  2588. // Effects data
  2589. if ((pHasExt) && (!warnedExt)) {
  2590. if (!layerEdit[pos][1]) {
  2591. if (!guiConfirmBox("Clipboard includes extended collision, alpha, and/or animation data, which layer does not support- continue?", "Extended Data Mismatch")) return 0;
  2592. warnedFx = 1;
  2593. }
  2594. }
  2595. // Collision data
  2596. if ((pHasFx) && (!warnedFx)) {
  2597. if (!layerEdit[pos][2]) {
  2598. if (!guiConfirmBox("Clipboard includes effects data, which layer does not support- continue?", "Effects Data Mismatch")) return 0;
  2599. warnedFx = 1;
  2600. }
  2601. }
  2602. ++matchedLayers;
  2603. if (matchedLayers == pNumLayers) break;
  2604. }
  2605. }
  2606. // Too many layers?
  2607. if (matchedLayers < pNumLayers) {
  2608. if (!guiConfirmBox("Clipboard contains more layers than marked for editing- continue?", "Layer Mismatch")) return 0;
  2609. }
  2610. world->undo.preUndoBlock();
  2611. doneSelection();
  2612. undoStoreSelect(0, 0, layerWidth, layerHeight, 1);
  2613. world->undo.postUndoBlock();
  2614. // "Default" data/fx if paste data doesn't supply it
  2615. Uint32 defData;
  2616. Uint32 defExt;
  2617. Uint32 defFx;
  2618. imagebar->getDataExt(defData, defExt, defFx);
  2619. // Now actually paste layer data
  2620. affectBit = 1;
  2621. matchedLayers = 0;
  2622. // @TODO: If only one layer's worth of data, always paste to cursor layer
  2623. // this may require adjusting the data clearing portion, below
  2624. for (pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
  2625. if (layersAffect & affectBit) {
  2626. memSet32(layerEdit[pos][0], Layer::LAYER_TILE_DEFAULT, layerWidth * layerHeight);
  2627. if (layerEdit[pos][1]) memSet32(layerEdit[pos][1], Layer::LAYER_EXT_DEFAULT, layerWidth * layerHeight);
  2628. if (layerEdit[pos][2]) memSet32(layerEdit[pos][2], Layer::LAYER_FX_DEFAULT, layerWidth * layerHeight);
  2629. clipboardPasteLayer(matchedLayers, layerEdit[pos][0], layerEdit[pos][1], layerEdit[pos][2], 0, 0, layerWidth, layerHeight, layerWidth, defData, defExt, defFx);
  2630. ++matchedLayers;
  2631. if (matchedLayers == pNumLayers) {
  2632. // So we start at the right layer for clearing data
  2633. ++pos;
  2634. affectBit <<= 1;
  2635. break;
  2636. }
  2637. }
  2638. }
  2639. // (any remaining layers- clear data)
  2640. for (; pos < numLayers; ++pos, affectBit <<= 1) {
  2641. if (layersAffect & affectBit) {
  2642. memSet32(layerEdit[pos][0], Layer::LAYER_TILE_DEFAULT, layerWidth * layerHeight);
  2643. if (layerEdit[pos][1]) memSet32(layerEdit[pos][1], Layer::LAYER_EXT_DEFAULT, layerWidth * layerHeight);
  2644. if (layerEdit[pos][2]) memSet32(layerEdit[pos][2], Layer::LAYER_FX_DEFAULT, layerWidth * layerHeight);
  2645. }
  2646. }
  2647. // Determine selection mask (select all, then deselect empties)
  2648. memset(selected, 255, selectedPitch * layerHeight);
  2649. selectionRect.x = 0;
  2650. selectionRect.y = 0;
  2651. selectionRect.w = layerWidth;
  2652. selectionRect.h = layerHeight;
  2653. selectionMode = SELECTION_OPAQUE;
  2654. fixSelectionRect(1);
  2655. // Possible nothing was actually pasted
  2656. fixSelectionRect();
  2657. updateCopyTool();
  2658. if (selectionRect.w) {
  2659. // @TODO: Move selection to ensure it's visible; may affect dirty below
  2660. // Should ideally appear near previous selection (but not on top) or at cursor, adjusted to be on screen
  2661. }
  2662. // Dirty
  2663. setDirtyRect(selectionRect);
  2664. return TOOLS_SELECT;
  2665. }
  2666. return 0;
  2667. }
  2668. void SceneEditLayer::copySelection() { start_func
  2669. if (selectionRect.w) {
  2670. int setFloat = 0;
  2671. // If not floating, float it to copy; backup selection
  2672. if (selectionMode == SELECTION_OUTLINE) {
  2673. memcpy(backupSelected, selected, selectedPitch * layerHeight);
  2674. backupSelectionRect = selectionRect;
  2675. setFloat = 1;
  2676. floatSelection(1); // Will NOT throw undo
  2677. }
  2678. // Ensure there's a selection still
  2679. if (selectionRect.w) {
  2680. // We copy what's in the floating selection
  2681. const void* cTileset[MAX_LAYERS];
  2682. Uint32* cData[MAX_LAYERS];
  2683. Uint32* cDataExt[MAX_LAYERS];
  2684. Uint32* cDataFx[MAX_LAYERS];
  2685. int cNumLayers = 0;
  2686. // Copy each active layer
  2687. int affectBit = 1;
  2688. for (int pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
  2689. if (layersAffect & affectBit) {
  2690. cTileset[cNumLayers] = scene->getLayer(pos)->getTileSet();
  2691. cData[cNumLayers] = layerEdit[pos][0];
  2692. cDataExt[cNumLayers] = layerEdit[pos][1];
  2693. cDataFx[cNumLayers] = layerEdit[pos][2];
  2694. ++cNumLayers;
  2695. }
  2696. }
  2697. clipboardCopy(cNumLayers, cTileset, cData, cDataExt, cDataFx, selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h, layerWidth);
  2698. }
  2699. // If was floating, defloat it now
  2700. if (setFloat) {
  2701. refreshData(0);
  2702. selectionMode = SELECTION_OUTLINE;
  2703. memcpy(selected, backupSelected, selectedPitch * layerHeight);
  2704. selectionRect = backupSelectionRect;
  2705. }
  2706. }
  2707. }
  2708. void SceneEditLayer::deleteSelection() throw_Undo { start_func
  2709. if ((selectionMode == SELECTION_OUTLINE) && (selectionRect.w)) {
  2710. // Float to nowhere
  2711. floatSelection(0, 1);
  2712. }
  2713. else if (selectionRect.w) {
  2714. // Delete floating selection
  2715. clearSelection();
  2716. }
  2717. }
  2718. void SceneEditLayer::mergeSelection() throw_Undo { start_func
  2719. // (no scene = closing)
  2720. if ((selectionMode != SELECTION_OUTLINE) && (scene)) {
  2721. world->undo.preUndoBlock();
  2722. // Paste selection, with offset
  2723. if (selectionRect.w) {
  2724. undoStoreLayer(selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs, selectionRect.w, selectionRect.h, 0);
  2725. undoStoreSelect(selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h);
  2726. // Underlay existing layer data under selection on each layer
  2727. Uint32* tempFloat = NULL;
  2728. Uint32* tempFloatExt = NULL;
  2729. Uint32* tempFloatFx = NULL;
  2730. Rect affect = { 0, 0, layerWidth, layerHeight };
  2731. int affectBit = 1;
  2732. int layerSize = layerWidth * layerHeight;
  2733. for (int pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
  2734. if (layersAffect & affectBit) {
  2735. // Allocate temporary storage to overlay selection to
  2736. tempFloat = new Uint32[layerSize];
  2737. if (layerEdit[pos][1]) {
  2738. tempFloatExt = new Uint32[layerSize];
  2739. }
  2740. if (layerEdit[pos][2]) {
  2741. tempFloatFx = new Uint32[layerSize];
  2742. }
  2743. // Grab original layer data
  2744. scene->getLayerEdit(pos)->loadLayer(tempFloat, tempFloatExt, tempFloatFx, layerWidth, affect);
  2745. // Scan selection and overlay selected data that isn't tile 0
  2746. Uint32* src = layerEdit[pos][0];
  2747. Uint32* srcExt = layerEdit[pos][1];
  2748. Uint32* srcFx = layerEdit[pos][2];
  2749. Uint32* dest = tempFloat + selectionXOffs + selectionYOffs * layerWidth;
  2750. Uint32* destExt = tempFloatExt;
  2751. Uint32* destFx = tempFloatFx;
  2752. if (destExt) destExt += selectionXOffs + selectionYOffs * layerWidth;
  2753. if (destFx) destFx += selectionXOffs + selectionYOffs * layerWidth;
  2754. for (int y = 0; y < layerHeight; ++y) {
  2755. for (int x = 0; x < layerWidth; ++x) {
  2756. if ((*src & Layer::LAYER_TILE_INDEX) != 0) {
  2757. if ((x < layerWidth - selectionXOffs) && (x >= -selectionXOffs) && (y < layerHeight - selectionYOffs) && (y >= -selectionYOffs)) {
  2758. *dest = *src;
  2759. if (srcExt) {
  2760. *destExt = *srcExt;
  2761. }
  2762. if (srcFx) {
  2763. *destFx = *srcFx;
  2764. }
  2765. }
  2766. }
  2767. ++src;
  2768. ++dest;
  2769. if (srcExt) {
  2770. ++srcExt;
  2771. ++destExt;
  2772. }
  2773. if (srcFx) {
  2774. ++srcFx;
  2775. ++destFx;
  2776. }
  2777. }
  2778. }
  2779. // Replace our layer data
  2780. delete[] layerEdit[pos][0];
  2781. delete[] layerEdit[pos][1];
  2782. delete[] layerEdit[pos][2];
  2783. layerEdit[pos][0] = tempFloat;
  2784. layerEdit[pos][1] = tempFloatExt;
  2785. layerEdit[pos][2] = tempFloatFx;
  2786. tempFloat = NULL;
  2787. tempFloatExt = NULL;
  2788. tempFloatFx = NULL;
  2789. // Apply data
  2790. scene->getLayerEdit(pos)->saveLayer(layerEdit[pos][0], layerEdit[pos][1], layerEdit[pos][2], layerWidth, affect, this);
  2791. }
  2792. }
  2793. }
  2794. // Clear selection (also sets dirty for us)
  2795. clearSelection(0);
  2796. world->undo.postUndoBlock();
  2797. }
  2798. }
  2799. int SceneEditLayer::isInSelection(int x, int y) const { start_func
  2800. if (!selectionRect.w) return 0;
  2801. x -= selectionXOffs;
  2802. y -= selectionYOffs;
  2803. Uint8 bit = 1 << (x & 7);
  2804. Uint8* selData = selected + (x >> 3) + y * selectedPitch;
  2805. return *selData & bit;
  2806. }
  2807. void SceneEditLayer::fixSelectionRect(int deselEmpty) { start_func
  2808. int minX = -1;
  2809. int maxX;
  2810. int minY;
  2811. int maxY;
  2812. Uint8 bit = 1;
  2813. Uint8* source = selected;
  2814. int dataOffset = 0;
  2815. for (int y = 0; y < layerHeight; ++y) {
  2816. for (int x = 0; x < layerWidth; ++x) {
  2817. if (deselEmpty) {
  2818. // Check all affected layers
  2819. int empty = 1;
  2820. for (int pos = 0; pos < numLayers; ++pos) {
  2821. if (layerEdit[pos][0]) {
  2822. if ((layerEdit[pos][0][dataOffset] & Layer::LAYER_TILE_INDEX) != 0) {
  2823. empty = 0;
  2824. break;
  2825. }
  2826. }
  2827. }
  2828. // Empty- deselct this bit
  2829. if (empty) {
  2830. *source &= ~bit;
  2831. }
  2832. }
  2833. if (*source & bit) {
  2834. if (minX == -1) {
  2835. minX = maxX = x;
  2836. minY = maxY = y;
  2837. }
  2838. else {
  2839. if (x < minX) minX = x;
  2840. else if (x > maxX) maxX = x;
  2841. if (y < minY) minY = y;
  2842. else if (y > maxY) maxY = y;
  2843. }
  2844. }
  2845. ++dataOffset;
  2846. bit <<= 1;
  2847. if (bit == 0) {
  2848. bit = 1;
  2849. ++source;
  2850. }
  2851. }
  2852. // If bit just wrapped to 1, we have an even multiple
  2853. // otherwise, move forward the final byte
  2854. if (bit > 1) ++source;
  2855. bit = 1;
  2856. }
  2857. if (minX == -1) {
  2858. selectionRect.w = 0;
  2859. }
  2860. else {
  2861. selectionRect = createRect(minX, minY, maxX, maxY);
  2862. }
  2863. }
  2864. void SceneEditLayer::updateSpriteShown() { start_func
  2865. int newSpriteShown = 0;
  2866. int newSpriteX = spriteShownX;
  2867. int newSpriteY = spriteShownY;
  2868. // If we don't have input focus, don't show
  2869. // If mouse isn't over us, and not showing at cursor, don't show
  2870. if ((!partialFocus) || ((!hover) && (!spriteAtCursor))) {
  2871. // (already set above)
  2872. }
  2873. // Show sprite if currently in use tool is a sprite tool OR
  2874. // current tool is a sprite tool and not in use
  2875. else if ((toolActive == TOOLS_PLACEITEM) || (toolActive == TOOLS_PLACESERIES) ||
  2876. ((!toolActive) &&
  2877. ((toolL == TOOLS_PLACEITEM) || (toolL == TOOLS_PLACESERIES) ||
  2878. (toolR == TOOLS_PLACEITEM) || (toolR == TOOLS_PLACESERIES)))) {
  2879. newSpriteShown = 1;
  2880. // Now determine position
  2881. if (spriteAtCursor) {
  2882. newSpriteX = cursorX * tileWidth;
  2883. newSpriteY = cursorY * tileHeight;
  2884. }
  2885. else {
  2886. newSpriteX = pixelMouseX;
  2887. newSpriteY = pixelMouseY;
  2888. }
  2889. }
  2890. // Change from last time?
  2891. if ((newSpriteShown != spriteShown) || (newSpriteX != spriteShownX) || (newSpriteY != spriteShownY)) {
  2892. // @TODO: Dirty old and new areas only
  2893. setDirty(1);
  2894. spriteShown = newSpriteShown;
  2895. spriteShownX = newSpriteX;
  2896. spriteShownY = newSpriteY;
  2897. }
  2898. }
  2899. void SceneEditLayer::mousePointer(int mouseX, int mouseY) { start_func
  2900. lastMouseX = mouseX;
  2901. lastMouseY = mouseY;
  2902. mousePointer();
  2903. }
  2904. void SceneEditLayer::mousePointer() { start_func
  2905. if (!hover) return;
  2906. if ((toolActive == TOOLS_SELECT) || (toolActive == TOOLS_SELECTELLIPSE) ||
  2907. (toolActive == TOOLS_WAND) || (toolActive == TOOLS_SELECTITEM)) {
  2908. if (toolAlt) {
  2909. selectMouse(MOUSE_SUBTRACT);
  2910. return;
  2911. }
  2912. else if (toolCtrl) {
  2913. selectMouse(MOUSE_ADD);
  2914. return;
  2915. }
  2916. }
  2917. if ((toolActive == TOOLS_SELECTDRAG) || (toolActive == TOOLS_SELECTITEMDRAG)) {
  2918. selectMouse(MOUSE_FOURDIRECTION);
  2919. return;
  2920. }
  2921. if (((!toolActive) && ((toolL == TOOLS_SELECT) || (toolL == TOOLS_SELECTELLIPSE) ||
  2922. (toolL == TOOLS_WAND)))
  2923. || (toolL == TOOLS_SELECTITEM)) {
  2924. if (SDL_GetModState() & KMOD_ALT) {
  2925. selectMouse(MOUSE_SUBTRACT);
  2926. return;
  2927. }
  2928. if (SDL_GetModState() & KMOD_CTRL) {
  2929. selectMouse(MOUSE_ADD);
  2930. return;
  2931. }
  2932. if (toolL == TOOLS_SELECTITEM) {
  2933. if (isInSpawnSelection(lastMouseX, lastMouseY)) {
  2934. selectMouse(MOUSE_FOURDIRECTION);
  2935. return;
  2936. }
  2937. }
  2938. else {
  2939. if (isInSelection(lastMouseX / tileWidth, lastMouseY / tileHeight)) {
  2940. selectMouse(MOUSE_FOURDIRECTION);
  2941. return;
  2942. }
  2943. }
  2944. }
  2945. selectMouse(MOUSE_NORMAL);
  2946. }
  2947. Window::CommandSupport SceneEditLayer::supportsCommand(int code) const { start_func
  2948. switch (code) {
  2949. // Options
  2950. case VIEW_GRID:
  2951. return (Window::CommandSupport)((enableGrid ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);
  2952. case TOOLS_CONTIGUOUS:
  2953. if ((toolL == TOOLS_WAND) || (toolL == TOOLS_FILL) || (toolR == TOOLS_WAND) || (toolR == TOOLS_FILL)) {
  2954. return (Window::CommandSupport)((contiguous ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);
  2955. }
  2956. else return (Window::CommandSupport)((contiguous ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_DISABLE);;
  2957. case TOOLS_PEN:
  2958. case TOOLS_LINE:
  2959. case TOOLS_RECT:
  2960. case TOOLS_RECTFILL:
  2961. case TOOLS_ELLIPSE:
  2962. case TOOLS_ELLIPSEFILL:
  2963. case TOOLS_SELECT:
  2964. case TOOLS_SELECTELLIPSE:
  2965. case TOOLS_DROPPER:
  2966. case TOOLS_FILL:
  2967. case TOOLS_WAND:
  2968. return (Window::CommandSupport)(((toolL == code) ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_RADIO | Window::COMMAND_ENABLE);
  2969. // These are always available (techincally you could have 1 or 0
  2970. // colors/images available, but not worth worrying about)
  2971. case TOOLS_CHOOSE:
  2972. case TOOLS_CHOOSER:
  2973. case EDIT_SELECTALL:
  2974. case TOOLS_SETTINGS:
  2975. case TOOLS_EDITCOLOR:
  2976. case TOOLS_NEXTCOLOR:
  2977. case TOOLS_PREVCOLOR:
  2978. case TOOLS_NEXTIMAGE:
  2979. case TOOLS_PREVIMAGE:
  2980. case NEW_LAYER:
  2981. return Window::COMMAND_ENABLE;
  2982. case VIEW_PREV:
  2983. for (int pos = 0; pos < cursorLayer; ++pos) {
  2984. if (layersAvailable & (1 << pos)) return Window::COMMAND_ENABLE;
  2985. }
  2986. return Window::COMMAND_DISABLE;
  2987. case VIEW_NEXT:
  2988. for (int pos = cursorLayer + 1; pos < numLayers; ++pos) {
  2989. if (layersAvailable & (1 << pos)) return Window::COMMAND_ENABLE;
  2990. }
  2991. return Window::COMMAND_DISABLE;
  2992. case VIEW_ALLLAYER:
  2993. case VIEW_DIMLAYER:
  2994. case VIEW_NOLAYER:
  2995. if (numLayers > 1) return Window::COMMAND_ENABLE;
  2996. return Window::COMMAND_DISABLE;
  2997. case EDIT_COPY:
  2998. case EDIT_CUT:
  2999. case EDIT_DELETE:
  3000. case EDIT_DESELECTALL:
  3001. if (selectionRect.w) return Window::COMMAND_ENABLE;
  3002. else return Window::COMMAND_DISABLE;
  3003. case EDIT_PASTE:
  3004. if (canConvertClipboard(CLIPBOARD_LAYER)) return Window::COMMAND_ENABLE;
  3005. else return Window::COMMAND_DISABLE;
  3006. }
  3007. return world->supportsCommand(code);
  3008. }
  3009. void SceneEditLayer::newToolSelected() { start_func
  3010. // @TODO: abort currently used tool?
  3011. if ((toolL == TOOLS_PLACEITEM) || (toolL == TOOLS_PLACESERIES) || (toolL == TOOLS_SELECTITEM)) spriteMode = 1;
  3012. else spriteMode = 0;
  3013. updateSpriteShown();
  3014. }
  3015. void SceneEditLayer::startToolIfMove() { start_func
  3016. startToolOnMove = 1;
  3017. }
  3018. void SceneEditLayer::refresh() { start_func
  3019. setDirty(1);
  3020. }
  3021. void SceneEditLayer::refreshLayers(Uint32 newLayersAffect, Uint32 newLayersView, Uint32 newLayersDim) { start_func
  3022. // Determine new desired cursor layer, affected layers, visible/dim layers
  3023. int newCursorLayer = layerlist->selectedLayer;
  3024. if (newLayersAffect) {
  3025. // Layers provided- just ensure cursor layer valid and then apply to layer list
  3026. int cursorBit = 1 << newCursorLayer;
  3027. if (!(newLayersAffect & cursorBit)) {
  3028. for (newCursorLayer = 0, cursorBit = 1; newCursorLayer < numLayers; ++newCursorLayer, cursorBit <<= 1) {
  3029. if (newLayersAffect & cursorBit) break;
  3030. }
  3031. assert(newCursorLayer < numLayers);
  3032. }
  3033. layerlist->layerList->setBitMask(newLayersAffect, newLayersView, newLayersDim, newCursorLayer);
  3034. }
  3035. else {
  3036. // Grab layers from layer list
  3037. layerlist->layerList->determineBitMasks(newLayersView, newLayersDim, newLayersAffect);
  3038. }
  3039. // Compare to current settings and determine what needs redrawing or reloading
  3040. // refresh = need to reload layer data
  3041. int refresh = 0;
  3042. // Merge any selection before changing affect bits unless from an undo
  3043. if ((newLayersAffect != layersAffect) || (newCursorLayer != cursorLayer)) {
  3044. // (we merge event if just "affected layers" changes because that changes what
  3045. // the selection would be applying to)
  3046. try {
  3047. mergeSelection();
  3048. }
  3049. catch (UndoException& e) {
  3050. // If undo fails, we force layerlist to previous set of layers
  3051. layerlist->layerList->setBitMask(layersAffect, layersView, layersDim, cursorLayer);
  3052. return;
  3053. }
  3054. }
  3055. if (newLayersAffect != layersAffect) {
  3056. layersAffect = newLayersAffect;
  3057. refresh = 1;
  3058. }
  3059. if (newCursorLayer != cursorLayer) {
  3060. cursorLayer = newCursorLayer;
  3061. refresh = 1;
  3062. }
  3063. if (refresh) {
  3064. reloadLayerStats();
  3065. refreshData(0);
  3066. }
  3067. // Now, refresh = need to redraw
  3068. if ((newLayersView != layersView) || (newLayersDim != layersDim)) {
  3069. layersView = newLayersView;
  3070. layersDim = newLayersDim;
  3071. refresh = 1;
  3072. }
  3073. if (refresh) {
  3074. recheckSpawnSelection();
  3075. setDirty(1);
  3076. }
  3077. }
  3078. void SceneEditLayer::selectEllipse(int x, int y, int rx, int ry, int set) { start_func
  3079. // ** Code modified from sge_primitives.cpp **
  3080. int ix, iy;
  3081. int h, i, j, k;
  3082. int oh, oi, oj, ok;
  3083. if (rx < 1) rx = 1;
  3084. if (ry < 1) ry = 1;
  3085. oh = oi = oj = ok = 0xFFFF;
  3086. if (rx > ry) {
  3087. ix = 0;
  3088. iy = rx * 64;
  3089. do {
  3090. h = (ix + 32) >> 6;
  3091. i = (iy + 32) >> 6;
  3092. j = (h * ry) / rx;
  3093. k = (i * ry) / rx;
  3094. if ((k != ok) && (k != oj)) {
  3095. if (k) {
  3096. selectRect(x - h, y - k, x + h, y - k, set);
  3097. selectRect(x - h, y + k, x + h, y + k, set);
  3098. }
  3099. else selectRect(x - h, y, x + h, y, set);
  3100. ok = k;
  3101. }
  3102. if ((j != oj) && (j != ok) && (k != j)) {
  3103. if (j) {
  3104. selectRect(x - i, y - j, x + i, y - j, set);
  3105. selectRect(x - i, y + j, x + i, y + j, set);
  3106. }
  3107. else selectRect(x - i, y, x + i, y, set);
  3108. oj = j;
  3109. }
  3110. ix = ix + iy / rx;
  3111. iy = iy - ix / rx;
  3112. } while (i > h);
  3113. }
  3114. else {
  3115. ix = 0;
  3116. iy = ry * 64;
  3117. do {
  3118. h = (ix + 32) >> 6;
  3119. i = (iy + 32) >> 6;
  3120. j = (h * rx) / ry;
  3121. k = (i * rx) / ry;
  3122. if ((i != oi) && (i != oh)) {
  3123. if (i) {
  3124. selectRect(x - j, y - i, x + j, y - i, set);
  3125. selectRect(x - j, y + i, x + j, y + i, set);
  3126. }
  3127. else selectRect(x - j, y, x + j, y, set);
  3128. oi = i;
  3129. }
  3130. if ((h != oh) && (h != oi) && (i != h)) {
  3131. if (h) {
  3132. selectRect(x - k, y - h, x + k, y - h, set);
  3133. selectRect(x - k, y + h, x + k, y + h, set);
  3134. }
  3135. else selectRect(x - k, y, x + k, y, set);
  3136. oh = h;
  3137. }
  3138. ix = ix + iy / ry;
  3139. iy = iy - ix / ry;
  3140. } while(i > h);
  3141. }
  3142. }
  3143. void SceneEditLayer::selectRect(int x1, int y1, int x2, int y2, int set) { start_func
  3144. Rect rect = createRect(x1, y1, x2, y2);
  3145. Rect bound = { 0, 0, layerWidth, layerHeight };
  3146. if (intersectRects(rect, bound)) {
  3147. y1 = rect.y;
  3148. y2 = y1 + rect.h - 1;
  3149. x1 = rect.x;
  3150. x2 = x1 + rect.w - 1;
  3151. for (; y1 <= y2; ++y1) {
  3152. // Place in bitarray terms
  3153. Uint8 bit = 1 << (x1 & 7);
  3154. Uint8* selData = selected + (x1 >> 3) + y1 * selectedPitch;
  3155. for (int x = x1; x <= x2; ++x) {
  3156. if (set) {
  3157. *selData |= bit;
  3158. }
  3159. else {
  3160. *selData &= ~bit;
  3161. }
  3162. bit <<= 1;
  3163. if (bit == 0) {
  3164. bit = 1;
  3165. ++selData;
  3166. }
  3167. }
  3168. }
  3169. }
  3170. }
  3171. // @TODO: account for selection masking
  3172. void SceneEditLayer::layerDrawEllipse(int x, int y, int rx, int ry, Uint32* data, Uint32 mask, Uint32 set) const { start_func
  3173. // (skip if nothing being drawn)
  3174. if ((mask == 0xFFFFFFFF) && (set == 0)) return;
  3175. // ** Code modified from sge_primitives.cpp **
  3176. int ix, iy;
  3177. int h, i, j, k;
  3178. int oh, oi, oj, ok;
  3179. Uint32* target;
  3180. if (rx < 1) rx = 1;
  3181. if (ry < 1) ry = 1;
  3182. h = i = j = k = 0xFFFF;
  3183. #define PUTPIXEL(x, y) {\
  3184. if (((x) >= 0) && ((x) < layerWidth) && ((y) >= 0) && ((y) < layerHeight)) {\
  3185. target = data + (x) + (y) * layerWidth;\
  3186. *target = (*target & mask) | set;\
  3187. }\
  3188. }
  3189. if (rx > ry) {
  3190. ix = 0;
  3191. iy = rx * 64;
  3192. do {
  3193. oh = h;
  3194. oi = i;
  3195. oj = j;
  3196. ok = k;
  3197. h = (ix + 32) >> 6;
  3198. i = (iy + 32) >> 6;
  3199. j = (h * ry) / rx;
  3200. k = (i * ry) / rx;
  3201. if (((h != oh) || (k != ok)) && (h < oi)) {
  3202. PUTPIXEL(x + h, y + k);
  3203. if (h) PUTPIXEL(x - h, y + k);
  3204. if (k) {
  3205. PUTPIXEL(x + h, y - k);
  3206. if (h) PUTPIXEL(x - h, y - k);
  3207. }
  3208. }
  3209. if (((i != oi) || (j != oj)) && (h < i)) {
  3210. PUTPIXEL(x + i, y + j);
  3211. if (i) PUTPIXEL(x - i, y + j);
  3212. if (j) {
  3213. PUTPIXEL(x + i, y - j);
  3214. if (i) PUTPIXEL(x - i, y - j);
  3215. }
  3216. }
  3217. ix = ix + iy / rx;
  3218. iy = iy - ix / rx;
  3219. } while (i > h);
  3220. }
  3221. else {
  3222. ix = 0;
  3223. iy = ry * 64;
  3224. do {
  3225. oh = h;
  3226. oi = i;
  3227. oj = j;
  3228. ok = k;
  3229. h = (ix + 32) >> 6;
  3230. i = (iy + 32) >> 6;
  3231. j = (h * rx) / ry;
  3232. k = (i * rx) / ry;
  3233. if (((j != oj) || (i != oi)) && (h < i)) {
  3234. PUTPIXEL(x + j, y + i);
  3235. if (j) PUTPIXEL(x - j, y + i);
  3236. if (i) {
  3237. PUTPIXEL(x + j, y - i);
  3238. if (j) PUTPIXEL(x - j, y - i);
  3239. }
  3240. }
  3241. if (((k != ok) || (h != oh)) && (h < oi)) {
  3242. PUTPIXEL(x + k, y + h);
  3243. if (k) PUTPIXEL(x - k, y + h);
  3244. if (h) {
  3245. PUTPIXEL(x + k, y - h);
  3246. if (k) PUTPIXEL(x - k, y - h);
  3247. }
  3248. }
  3249. ix = ix + iy / ry;
  3250. iy = iy - ix / ry;
  3251. } while(i > h);
  3252. }
  3253. }
  3254. // @TODO: account for selection masking
  3255. void SceneEditLayer::layerDrawEllipseFill(int x, int y, int rx, int ry, Uint32* data, Uint32 mask, Uint32 set) const { start_func
  3256. // (skip if nothing being drawn)
  3257. if ((mask == 0xFFFFFFFF) && (set == 0)) return;
  3258. // ** Code modified from sge_primitives.cpp **
  3259. int ix, iy;
  3260. int h, i, j, k;
  3261. int oh, oi, oj, ok;
  3262. if (rx < 1) rx = 1;
  3263. if (ry < 1) ry = 1;
  3264. oh = oi = oj = ok = 0xFFFF;
  3265. if (rx > ry) {
  3266. ix = 0;
  3267. iy = rx * 64;
  3268. do {
  3269. h = (ix + 32) >> 6;
  3270. i = (iy + 32) >> 6;
  3271. j = (h * ry) / rx;
  3272. k = (i * ry) / rx;
  3273. if ((k != ok) && (k != oj)) {
  3274. if (k) {
  3275. layerDrawRect(x - h, y - k, x + h, y - k, data, mask, set);
  3276. layerDrawRect(x - h, y + k, x + h, y + k, data, mask, set);
  3277. }
  3278. else layerDrawRect(x - h, y, x + h, y, data, mask, set);
  3279. ok = k;
  3280. }
  3281. if ((j != oj) && (j != ok) && (k != j)) {
  3282. if (j) {
  3283. layerDrawRect(x - i, y - j, x + i, y - j, data, mask, set);
  3284. layerDrawRect(x - i, y + j, x + i, y + j, data, mask, set);
  3285. }
  3286. else layerDrawRect(x - i, y, x + i, y, data, mask, set);
  3287. oj = j;
  3288. }
  3289. ix = ix + iy / rx;
  3290. iy = iy - ix / rx;
  3291. } while (i > h);
  3292. }
  3293. else {
  3294. ix = 0;
  3295. iy = ry * 64;
  3296. do {
  3297. h = (ix + 32) >> 6;
  3298. i = (iy + 32) >> 6;
  3299. j = (h * rx) / ry;
  3300. k = (i * rx) / ry;
  3301. if ((i != oi) && (i != oh)) {
  3302. if (i) {
  3303. layerDrawRect(x - j, y - i, x + j, y - i, data, mask, set);
  3304. layerDrawRect(x - j, y + i, x + j, y + i, data, mask, set);
  3305. }
  3306. else layerDrawRect(x - j, y, x + j, y, data, mask, set);
  3307. oi = i;
  3308. }
  3309. if ((h != oh) && (h != oi) && (i != h)) {
  3310. if (h) {
  3311. layerDrawRect(x - k, y - h, x + k, y - h, data, mask, set);
  3312. layerDrawRect(x - k, y + h, x + k, y + h, data, mask, set);
  3313. }
  3314. else layerDrawRect(x - k, y, x + k, y, data, mask, set);
  3315. oh = h;
  3316. }
  3317. ix = ix + iy / ry;
  3318. iy = iy - ix / ry;
  3319. } while(i > h);
  3320. }
  3321. }
  3322. // @TODO: account for selection masking
  3323. // @TODO: additional matchmask to cover ext data as well
  3324. Rect SceneEditLayer::layerFloodFill(int x, int y, Uint32 matchMask, Uint32* data1, Uint32 mask1, Uint32 set1, Uint32* data2, Uint32 mask2, Uint32 set2) const { start_func
  3325. assert(data1);
  3326. // Min/Max area
  3327. Rect result = { 0, 0, 0, 0 };
  3328. // Clip area
  3329. if ((x < 0) || (y < 0) || (x >= layerWidth) || (y >= layerHeight)) return result;
  3330. // Extreme points
  3331. int x1 = x;
  3332. int x2 = x;
  3333. int y1 = y;
  3334. int y2 = y;
  3335. // Stack
  3336. #define FLOOD_STACK_SIZE 250
  3337. struct {
  3338. Uint32* d1;
  3339. Uint32* d2;
  3340. int x;
  3341. int y;
  3342. int yD;
  3343. } floodStack[FLOOD_STACK_SIZE];
  3344. int stackPos = 0;
  3345. #define PUSH(dp1, dp2, xp, yp, ydiff) {\
  3346. if (stackPos < FLOOD_STACK_SIZE) {\
  3347. floodStack[stackPos].d1 = dp1;\
  3348. floodStack[stackPos].d2 = dp2;\
  3349. floodStack[stackPos].x = xp;\
  3350. floodStack[stackPos].y = yp;\
  3351. floodStack[stackPos++].yD = ydiff;\
  3352. }\
  3353. }
  3354. #define POP(dp1, dp2, xp, yp, ydiff) {\
  3355. assert(stackPos);\
  3356. dp1 = floodStack[--stackPos].d1;\
  3357. dp2 = floodStack[stackPos].d2;\
  3358. xp = floodStack[stackPos].x;\
  3359. yp = floodStack[stackPos].y;\
  3360. ydiff = floodStack[stackPos].yD;\
  3361. }
  3362. // Starting point etc.
  3363. Uint32* dataPoint1 = data1 + x + y * layerWidth;
  3364. Uint32* dataPoint2 = NULL;
  3365. if (data2) dataPoint2 = data2 + x + y * layerWidth;
  3366. // Determine what we're matching against, don't fill if matches what we're doing
  3367. Uint32 target = *dataPoint1 & matchMask;
  3368. if (((target & mask1) | set1) == target) return result;
  3369. // Work areas
  3370. int top, bottom;
  3371. int lX;
  3372. int yDiff;
  3373. // Push starting point
  3374. PUSH(dataPoint1, dataPoint2, x, y, 0);
  3375. while (stackPos) {
  3376. // Next point to fill, then scan left and right
  3377. POP(dataPoint1, dataPoint2, x, y, yDiff);
  3378. dataPoint1 += yDiff * layerWidth;
  3379. if (dataPoint2) dataPoint2 += yDiff * layerWidth;
  3380. y += yDiff;
  3381. // Don't fill given point directly- instead, we'll scan it manually in the second loop
  3382. // Update extreme points- y
  3383. if (y < y1) y1 = y;
  3384. if (y > y2) y2 = y;
  3385. // Check both top and bottom for matches
  3386. top = bottom = 1;
  3387. // Fill as far left as possible
  3388. lX = x;
  3389. while ((lX > 0) && ((dataPoint1[-1] & matchMask) == target)) {
  3390. --lX;
  3391. --dataPoint1;
  3392. *dataPoint1 = (*dataPoint1 & mask1) | set1;
  3393. if (dataPoint2) {
  3394. --dataPoint2;
  3395. *dataPoint2 = (*dataPoint2 & mask2) | set2;
  3396. }
  3397. // Is point above fillable?
  3398. if ((y > 0) && ((dataPoint1[-layerWidth] & matchMask) == target)) {
  3399. // Are we pushing "above" points right now?
  3400. if (top) {
  3401. // Push onto stack
  3402. PUSH(dataPoint1, dataPoint2, lX, y, -1);
  3403. top = 0;
  3404. }
  3405. }
  3406. // Not fillable, we will now push the next "above" point we find
  3407. else top = 1;
  3408. // Is point below fillable?
  3409. if ((y < layerHeight - 1) && ((dataPoint1[layerWidth] & matchMask) == target)) {
  3410. // Are we pushing "below" points right now?
  3411. if (bottom) {
  3412. // Push onto stack
  3413. PUSH(dataPoint1, dataPoint2, lX, y, 1);
  3414. bottom = 0;
  3415. }
  3416. }
  3417. // Not fillable, we will now push the next "below" point we find
  3418. else bottom = 1;
  3419. }
  3420. // Update extreme left point
  3421. if (lX < x1) x1 = lX;
  3422. // Recenter, minus one, so that we scan the center/given point as well
  3423. --x;
  3424. dataPoint1 += x - lX;
  3425. if (dataPoint2) dataPoint2 += x - lX;
  3426. top = bottom = 1;
  3427. // Fill as far right as possible; this loop intentionally catches our first, central point
  3428. while ((x < layerWidth - 1) && ((dataPoint1[1] & matchMask) == target)) {
  3429. ++x;
  3430. ++dataPoint1;
  3431. *dataPoint1 = (*dataPoint1 & mask1) | set1;
  3432. if (dataPoint2) {
  3433. ++dataPoint2;
  3434. *dataPoint2 = (*dataPoint2 & mask2) | set2;
  3435. }
  3436. // Is point above fillable?
  3437. if ((y > 0) && ((dataPoint1[-layerWidth] & matchMask) == target)) {
  3438. // Are we pushing "above" points right now?
  3439. if (top) {
  3440. // Push onto stack
  3441. PUSH(dataPoint1, dataPoint2, x, y, -1);
  3442. top = 0;
  3443. }
  3444. }
  3445. // Not fillable, we will now push the next "above" point we find
  3446. else top = 1;
  3447. // Is point below fillable?
  3448. if ((y < layerHeight - 1) && ((dataPoint1[layerWidth] & matchMask) == target)) {
  3449. // Are we pushing "below" points right now?
  3450. if (bottom) {
  3451. // Push onto stack
  3452. PUSH(dataPoint1, dataPoint2, x, y, 1);
  3453. bottom = 0;
  3454. }
  3455. }
  3456. // Not fillable, we will now push the next "below" point we find
  3457. else bottom = 1;
  3458. }
  3459. // Update extreme right point
  3460. if (x > x2) x2 = x;
  3461. }
  3462. result.x = x1;
  3463. result.y = y1;
  3464. result.w = x2 - x1 + 1;
  3465. result.h = y2 - y1 + 1;
  3466. return result;
  3467. }
  3468. // @TODO: account for selection masking
  3469. Rect SceneEditLayer::layerMatchFill(int x, int y, Uint32 matchMask, Uint32* data1, Uint32 mask1, Uint32 set1, Uint32* data2, Uint32 mask2, Uint32 set2) const { start_func
  3470. assert(data1);
  3471. // Min/Max area
  3472. Rect result = { 0, 0, 0, 0 };
  3473. // Clip area
  3474. if ((x < 0) || (y < 0) || (x >= layerWidth) || (y >= layerHeight)) return result;
  3475. // Extreme points
  3476. int x1 = x;
  3477. int x2 = x;
  3478. int y1 = y;
  3479. int y2 = y;
  3480. // Determine what we're matching against, don't fill if matches what we're doing
  3481. Uint32 target = data1[x + y * layerWidth] & matchMask;
  3482. if (((target & mask1) | set1) == target) return result;
  3483. for (y = 0; y < layerHeight; ++y) {
  3484. for (x = 0; x < layerWidth; ++x) {
  3485. if ((*data1 & matchMask) == target) {
  3486. *data1 = (*data1 & mask1) | set1;
  3487. if (data2) *data2 = (*data2 & mask2) | set2;
  3488. // Update extreme points
  3489. if (y < y1) y1 = y;
  3490. if (y > y2) y2 = y;
  3491. if (x < x1) x1 = x;
  3492. if (x > x2) x2 = x;
  3493. }
  3494. ++data1;
  3495. if (data2) ++data2;
  3496. }
  3497. }
  3498. result.x = x1;
  3499. result.y = y1;
  3500. result.w = x2 - x1 + 1;
  3501. result.h = y2 - y1 + 1;
  3502. return result;
  3503. }
  3504. // @TODO: account for selection masking
  3505. void SceneEditLayer::layerDrawRect(int x1, int y1, int x2, int y2, Uint32* data, Uint32 mask, Uint32 set) const { start_func
  3506. assert(data);
  3507. // (skip if nothing being drawn)
  3508. if ((mask == 0xFFFFFFFF) && (set == 0)) return;
  3509. Rect affect = createRect(x1, y1, x2, y2);
  3510. Rect bound = { 0, 0, layerWidth, layerHeight };
  3511. if (!intersectRects(affect, bound)) return;
  3512. data += affect.y * layerWidth + affect.x;
  3513. for (int row = affect.h; row > 0; --row) {
  3514. for (int col = affect.w; col > 0; --col) {
  3515. *data = (*data & mask) | set;
  3516. ++data;
  3517. }
  3518. data += layerWidth - affect.w;
  3519. }
  3520. }
  3521. void SceneEditLayer::layerDrawBox(int x1, int y1, int x2, int y2, Uint32* data, Uint32 mask, Uint32 set) const { start_func
  3522. layerDrawRect(x1, y1, x2, y1, data, mask, set);
  3523. layerDrawRect(x1, y1, x1, y2, data, mask, set);
  3524. layerDrawRect(x2, y1, x2, y2, data, mask, set);
  3525. layerDrawRect(x1, y2, x2, y2, data, mask, set);
  3526. }
  3527. // @TODO: account for selection masking
  3528. void SceneEditLayer::layerDrawLine(int x1, int y1, int x2, int y2, Uint32* data, Uint32 mask, Uint32 set) const { start_func
  3529. assert(data);
  3530. // (skip if nothing being drawn)
  3531. if ((mask == 0xFFFFFFFF) && (set == 0)) return;
  3532. Sint16 x = x1;
  3533. Sint16 y = y1;
  3534. Sint16 dy = y2 - y1;
  3535. Sint16 dx = x2 - x1;
  3536. Sint16 G, DeltaG1, DeltaG2;//, minG, maxG;
  3537. Sint16 inc = 1;
  3538. if (abs(dy) < abs(dx)) {
  3539. if (dx < 0) {
  3540. dx = -dx;
  3541. dy = -dy;
  3542. y1 = y2;
  3543. y2 = y;
  3544. y = y1;
  3545. x1 = x2;
  3546. x2 = x;
  3547. x = x1;
  3548. }
  3549. if (dy < 0) {
  3550. dy = -dy;
  3551. inc = -1;
  3552. }
  3553. G = 2 * dy - dx;
  3554. DeltaG1 = 2 * (dy - dx);
  3555. DeltaG2 = 2 * dy;
  3556. data += y * layerWidth + x;
  3557. if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = (*data & mask) | set;
  3558. while (++x <= x2) {
  3559. ++data;
  3560. if (G > 0) { G += DeltaG1; y += inc; data += inc * layerWidth; }
  3561. else G += DeltaG2;
  3562. if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = (*data & mask) | set;
  3563. }
  3564. }
  3565. else {
  3566. if (dy < 0) {
  3567. dx = -dx;
  3568. dy = -dy;
  3569. y1 = y2;
  3570. y2 = y;
  3571. y = y1;
  3572. x1 = x2;
  3573. x2 = x;
  3574. x = x1;
  3575. }
  3576. if (dx < 0) {
  3577. dx = -dx;
  3578. inc = -1;
  3579. }
  3580. G = 2 * dx - dy;
  3581. //minG = maxG = G;
  3582. DeltaG1 = 2 * (dx - dy);
  3583. DeltaG2 = 2 * dx;
  3584. data += y * layerWidth + x;
  3585. if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = (*data & mask) | set;
  3586. while (++y <= y2) {
  3587. data += layerWidth;
  3588. if (G > 0) { G += DeltaG1; x += inc; data += inc; }
  3589. else G += DeltaG2;
  3590. if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = (*data & mask) | set;
  3591. }
  3592. }
  3593. }
  3594. void SceneEditLayer::swapSelectionParameters(int& xoffs, int& yoffs, int& mode) { start_func
  3595. swap(xoffs, selectionXOffs);
  3596. swap(yoffs, selectionYOffs);
  3597. if (mode != selectionMode) {
  3598. if (mode == SELECTION_OUTLINE) {
  3599. refreshData(0);
  3600. }
  3601. else {
  3602. Uint32 affectBit = 1;
  3603. for (int pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
  3604. if (layersAffect & affectBit) {
  3605. memSet32(layerEdit[pos][0], Layer::LAYER_TILE_DEFAULT, layerWidth * layerHeight);
  3606. if (layerEdit[pos][1]) memSet32(layerEdit[pos][1], Layer::LAYER_EXT_DEFAULT, layerWidth * layerHeight);
  3607. if (layerEdit[pos][2]) memSet32(layerEdit[pos][2], Layer::LAYER_FX_DEFAULT, layerWidth * layerHeight);
  3608. }
  3609. }
  3610. }
  3611. }
  3612. swap(mode, selectionMode);
  3613. // Refresh
  3614. fixSelectionRect();
  3615. setDirty(1);
  3616. }
  3617. Window::WindowType SceneEditLayer::windowType() const { start_func
  3618. return WINDOW_CLIENT;
  3619. }
  3620. void SceneEditLayer::setDirtySelectedSpawns() { start_func
  3621. setDirtyPixelBox(selectedSpawnRect.x, selectedSpawnRect.y,
  3622. selectedSpawnRect.x + selectedSpawnRect.w - 1,
  3623. selectedSpawnRect.y + selectedSpawnRect.h - 1);
  3624. }
  3625. void SceneEditLayer::copySpawnSelection() { start_func
  3626. set<int>::iterator pos = selectedSpawns.begin();
  3627. set<int>::iterator end = selectedSpawns.end();
  3628. vector<const SpawnEdit*> toCopy;
  3629. vector<int> toCopyLayers;
  3630. while (pos != end) {
  3631. // Find spawn
  3632. SpawnEdit* spawn = world->findSpawn(*pos);
  3633. if (spawn) {
  3634. // Determine layer
  3635. int lPos = scene->findLayer(spawn->getLayer());
  3636. if (lPos >= 0) {
  3637. int bit = 1 << lPos;
  3638. if (layersAffect & bit) {
  3639. toCopy.push_back(spawn);
  3640. toCopyLayers.push_back(lPos);
  3641. }
  3642. }
  3643. }
  3644. ++pos;
  3645. }
  3646. clipboardCopy(toCopy, toCopyLayers);
  3647. }
  3648. void SceneEditLayer::deleteSpawnSelection() throw_Undo { start_func
  3649. set<int>::iterator pos = selectedSpawns.begin();
  3650. set<int>::iterator end = selectedSpawns.end();
  3651. world->undo.preUndoBlock();
  3652. undoStoreSpawnSelect();
  3653. while (pos != end) {
  3654. // Find spawn
  3655. SpawnEdit* spawn = world->findSpawn(*pos);
  3656. if (spawn) {
  3657. // Determine layer
  3658. int lPos = scene->findLayer(spawn->getLayer());
  3659. if (lPos >= 0) {
  3660. int bit = 1 << lPos;
  3661. if (layersAffect & bit) {
  3662. spawn->getLayer()->deleteSpawn(spawn, myFrame, this); // Exception point (undoes other deletions for us)
  3663. }
  3664. }
  3665. }
  3666. ++pos;
  3667. }
  3668. setDirtySelectedSpawns();
  3669. selectedSpawns.clear();
  3670. selectedSpawnRect.w = 0;
  3671. world->undo.postUndoBlock();
  3672. }
  3673. void SceneEditLayer::clearSpawnSelection(int storeUndo) throw_Undo { start_func
  3674. if (storeUndo) undoStoreSpawnSelect();
  3675. if (!selectedSpawns.empty()) {
  3676. setDirtySelectedSpawns();
  3677. selectedSpawns.clear();
  3678. selectedSpawnRect.w = 0;
  3679. }
  3680. }
  3681. void SceneEditLayer::updatedSpawnSelection() { start_func
  3682. recheckSpawnSelection();
  3683. setDirty(1);
  3684. }
  3685. void SceneEditLayer::recheckSpawnSelection() { start_func
  3686. set<int>::iterator pos = selectedSpawns.begin();
  3687. set<int>::iterator end = selectedSpawns.end();
  3688. set<int>::iterator check;
  3689. selectedSpawnRect.w = 0;
  3690. while (pos != end) {
  3691. check = pos;
  3692. ++pos;
  3693. // This spawn still in one of our affected layers?
  3694. int kill = 1;
  3695. SpawnEdit* spawn = world->findSpawn(*check);
  3696. if (spawn) {
  3697. // Determine layer
  3698. int lPos = scene->findLayer(spawn->getLayer());
  3699. if (lPos >= 0) {
  3700. int bit = 1 << lPos;
  3701. if (layersAffect & bit) {
  3702. Rect spawnRect = { spawn->getX(), spawn->getY(), spawn->getW(), spawn->getH() };
  3703. boundRects(selectedSpawnRect, spawnRect);
  3704. kill = 0;
  3705. }
  3706. }
  3707. }
  3708. if (kill) selectedSpawns.erase(check);
  3709. }
  3710. }
  3711. void SceneEditLayer::undoStoreSpawnSelect() throw_Undo { start_func
  3712. world->undo.storeUndoLayerSpawnSelection(&selectedSpawns, myFrame);
  3713. }
  3714. int SceneEditLayer::isInSpawnSelection(int x, int y) { start_func
  3715. // Find spawns in one of our affected layers
  3716. set<int>::iterator pos = selectedSpawns.begin();
  3717. set<int>::iterator end = selectedSpawns.end();
  3718. while (pos != end) {
  3719. // Find spawn
  3720. SpawnEdit* spawn = world->findSpawn(*pos);
  3721. if (spawn) {
  3722. // Determine layer
  3723. int lPos = scene->findLayer(spawn->getLayer());
  3724. if (lPos >= 0) {
  3725. int bit = 1 << lPos;
  3726. if (layersAffect & bit) {
  3727. if ((x >= spawn->getX()) &&
  3728. (y >= spawn->getY()) &&
  3729. (x < spawn->getX() + spawn->getW()) &&
  3730. (y < spawn->getY() + spawn->getH()))
  3731. return spawn->getId();
  3732. }
  3733. }
  3734. }
  3735. ++pos;
  3736. }
  3737. return 0;
  3738. }
  3739. void SceneEditLayer::startToolSpawnSelectionDrag() { start_func
  3740. startToolOnMove = 0;
  3741. if (toolActive) return;
  3742. toolActive = TOOLS_SELECTITEMDRAG;
  3743. toolStartX = cursorSpriteX;
  3744. toolStartY = cursorSpriteY;
  3745. toolCtrl = SDL_GetModState() & KMOD_CTRL;
  3746. toolAlt = SDL_GetModState() & KMOD_ALT;
  3747. mousePointer();
  3748. dragTool(1);
  3749. }
  3750. void SceneEditLayer::selectSpawnRect(int x1, int y1, int x2, int y2, int select, int selectAll) { start_func
  3751. Rect area = createRect(x1, y1, x2, y2);
  3752. int bit = 1;
  3753. for (int lPos = 0; lPos < numLayers; ++lPos, bit <<= 1) {
  3754. if (layersAffect & bit) {
  3755. // Check all spawns in this layer
  3756. LayerEdit* layer = scene->getLayerEdit(lPos);
  3757. for (int sPos = layer->getSpawnCount() - 1; sPos >= 0; --sPos) {
  3758. SpawnEdit* spawn = layer->getSpawn(sPos);
  3759. Rect spawnRect = { spawn->getX(), spawn->getY(), spawn->getW(), spawn->getH() };
  3760. if ((selectAll) || (intersectRects(spawnRect, area))) {
  3761. if (select) selectedSpawns.insert(spawn->getId());
  3762. else selectedSpawns.erase(spawn->getId());
  3763. }
  3764. }
  3765. }
  3766. }
  3767. }
  3768. void SceneEditLayer::moveSpawnSelection(int byX, int byY, int skipUndo) { start_func
  3769. set<int>::iterator pos = selectedSpawns.begin();
  3770. set<int>::iterator end = selectedSpawns.end();
  3771. while (pos != end) {
  3772. // Find spawn
  3773. SpawnEdit* spawn = world->findSpawn(*pos);
  3774. if (spawn) {
  3775. // Determine layer
  3776. int lPos = scene->findLayer(spawn->getLayer());
  3777. if (lPos >= 0) {
  3778. int bit = 1 << lPos;
  3779. if (layersAffect & bit) {
  3780. spawn->setPos(spawn->getX() + byX, spawn->getY() + byY, skipUndo, myFrame, this);
  3781. }
  3782. }
  3783. }
  3784. ++pos;
  3785. }
  3786. selectedSpawnRect.x += byX;
  3787. selectedSpawnRect.y += byY;
  3788. }