gcsx_sceneeditlayer.cpp 165 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373
  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)) || (toolL == TOOLS_SELECTITEM)) {
  2923. if (SDL_GetModState() & KMOD_ALT) {
  2924. selectMouse(MOUSE_SUBTRACT);
  2925. return;
  2926. }
  2927. if (SDL_GetModState() & KMOD_CTRL) {
  2928. selectMouse(MOUSE_ADD);
  2929. return;
  2930. }
  2931. if (toolL == TOOLS_SELECTITEM) {
  2932. if (isInSpawnSelection(lastMouseX, lastMouseY)) {
  2933. selectMouse(MOUSE_FOURDIRECTION);
  2934. return;
  2935. }
  2936. }
  2937. else {
  2938. if (isInSelection(lastMouseX / tileWidth, lastMouseY / tileHeight)) {
  2939. selectMouse(MOUSE_FOURDIRECTION);
  2940. return;
  2941. }
  2942. }
  2943. }
  2944. selectMouse(MOUSE_NORMAL);
  2945. }
  2946. Window::CommandSupport SceneEditLayer::supportsCommand(int code) const { start_func
  2947. switch (code) {
  2948. // Options
  2949. case VIEW_GRID:
  2950. return (Window::CommandSupport)((enableGrid ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);
  2951. case TOOLS_CONTIGUOUS:
  2952. if ((toolL == TOOLS_WAND) || (toolL == TOOLS_FILL) || (toolR == TOOLS_WAND) || (toolR == TOOLS_FILL)) {
  2953. return (Window::CommandSupport)((contiguous ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);
  2954. }
  2955. else return (Window::CommandSupport)((contiguous ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_DISABLE);;
  2956. case TOOLS_PEN:
  2957. case TOOLS_LINE:
  2958. case TOOLS_RECT:
  2959. case TOOLS_RECTFILL:
  2960. case TOOLS_ELLIPSE:
  2961. case TOOLS_ELLIPSEFILL:
  2962. case TOOLS_SELECT:
  2963. case TOOLS_SELECTELLIPSE:
  2964. case TOOLS_DROPPER:
  2965. case TOOLS_FILL:
  2966. case TOOLS_WAND:
  2967. return (Window::CommandSupport)(((toolL == code) ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_RADIO | Window::COMMAND_ENABLE);
  2968. // These are always available (techincally you could have 1 or 0
  2969. // colors/images available, but not worth worrying about)
  2970. case TOOLS_CHOOSE:
  2971. case TOOLS_CHOOSER:
  2972. case EDIT_SELECTALL:
  2973. case TOOLS_SETTINGS:
  2974. case TOOLS_EDITCOLOR:
  2975. case TOOLS_NEXTCOLOR:
  2976. case TOOLS_PREVCOLOR:
  2977. case TOOLS_NEXTIMAGE:
  2978. case TOOLS_PREVIMAGE:
  2979. case NEW_LAYER:
  2980. return Window::COMMAND_ENABLE;
  2981. case VIEW_PREV:
  2982. for (int pos = 0; pos < cursorLayer; ++pos) {
  2983. if (layersAvailable & (1 << pos)) return Window::COMMAND_ENABLE;
  2984. }
  2985. return Window::COMMAND_DISABLE;
  2986. case VIEW_NEXT:
  2987. for (int pos = cursorLayer + 1; pos < numLayers; ++pos) {
  2988. if (layersAvailable & (1 << pos)) return Window::COMMAND_ENABLE;
  2989. }
  2990. return Window::COMMAND_DISABLE;
  2991. case VIEW_ALLLAYER:
  2992. case VIEW_DIMLAYER:
  2993. case VIEW_NOLAYER:
  2994. if (numLayers > 1) return Window::COMMAND_ENABLE;
  2995. return Window::COMMAND_DISABLE;
  2996. case EDIT_COPY:
  2997. case EDIT_CUT:
  2998. case EDIT_DELETE:
  2999. case EDIT_DESELECTALL:
  3000. if (selectionRect.w) return Window::COMMAND_ENABLE;
  3001. else return Window::COMMAND_DISABLE;
  3002. case EDIT_PASTE:
  3003. if (canConvertClipboard(CLIPBOARD_LAYER)) return Window::COMMAND_ENABLE;
  3004. else return Window::COMMAND_DISABLE;
  3005. }
  3006. return world->supportsCommand(code);
  3007. }
  3008. void SceneEditLayer::newToolSelected() { start_func
  3009. // @TODO: abort currently used tool?
  3010. if ((toolL == TOOLS_PLACEITEM) || (toolL == TOOLS_PLACESERIES) || (toolL == TOOLS_SELECTITEM)) spriteMode = 1;
  3011. else spriteMode = 0;
  3012. updateSpriteShown();
  3013. }
  3014. void SceneEditLayer::startToolIfMove() { start_func
  3015. startToolOnMove = 1;
  3016. }
  3017. void SceneEditLayer::refresh() { start_func
  3018. setDirty(1);
  3019. }
  3020. void SceneEditLayer::refreshLayers(Uint32 newLayersAffect, Uint32 newLayersView, Uint32 newLayersDim) { start_func
  3021. // Determine new desired cursor layer, affected layers, visible/dim layers
  3022. int newCursorLayer = layerlist->selectedLayer;
  3023. if (newLayersAffect) {
  3024. // Layers provided- just ensure cursor layer valid and then apply to layer list
  3025. int cursorBit = 1 << newCursorLayer;
  3026. if (!(newLayersAffect & cursorBit)) {
  3027. for (newCursorLayer = 0, cursorBit = 1; newCursorLayer < numLayers; ++newCursorLayer, cursorBit <<= 1) {
  3028. if (newLayersAffect & cursorBit) break;
  3029. }
  3030. assert(newCursorLayer < numLayers);
  3031. }
  3032. layerlist->layerList->setBitMask(newLayersAffect, newLayersView, newLayersDim, newCursorLayer);
  3033. }
  3034. else {
  3035. // Grab layers from layer list
  3036. layerlist->layerList->determineBitMasks(newLayersView, newLayersDim, newLayersAffect);
  3037. }
  3038. // Compare to current settings and determine what needs redrawing or reloading
  3039. // refresh = need to reload layer data
  3040. int refresh = 0;
  3041. // Merge any selection before changing affect bits unless from an undo
  3042. if ((newLayersAffect != layersAffect) || (newCursorLayer != cursorLayer)) {
  3043. // (we merge event if just "affected layers" changes because that changes what
  3044. // the selection would be applying to)
  3045. try {
  3046. mergeSelection();
  3047. }
  3048. catch (UndoException& e) {
  3049. // If undo fails, we force layerlist to previous set of layers
  3050. layerlist->layerList->setBitMask(layersAffect, layersView, layersDim, cursorLayer);
  3051. return;
  3052. }
  3053. }
  3054. if (newLayersAffect != layersAffect) {
  3055. layersAffect = newLayersAffect;
  3056. refresh = 1;
  3057. }
  3058. if (newCursorLayer != cursorLayer) {
  3059. cursorLayer = newCursorLayer;
  3060. refresh = 1;
  3061. }
  3062. if (refresh) {
  3063. reloadLayerStats();
  3064. refreshData(0);
  3065. }
  3066. // Now, refresh = need to redraw
  3067. if ((newLayersView != layersView) || (newLayersDim != layersDim)) {
  3068. layersView = newLayersView;
  3069. layersDim = newLayersDim;
  3070. refresh = 1;
  3071. }
  3072. if (refresh) {
  3073. recheckSpawnSelection();
  3074. setDirty(1);
  3075. }
  3076. }
  3077. void SceneEditLayer::selectEllipse(int x, int y, int rx, int ry, int set) { start_func
  3078. // ** Code modified from sge_primitives.cpp **
  3079. int ix, iy;
  3080. int h, i, j, k;
  3081. int oh, oi, oj, ok;
  3082. if (rx < 1) rx = 1;
  3083. if (ry < 1) ry = 1;
  3084. oh = oi = oj = ok = 0xFFFF;
  3085. if (rx > ry) {
  3086. ix = 0;
  3087. iy = rx * 64;
  3088. do {
  3089. h = (ix + 32) >> 6;
  3090. i = (iy + 32) >> 6;
  3091. j = (h * ry) / rx;
  3092. k = (i * ry) / rx;
  3093. if ((k != ok) && (k != oj)) {
  3094. if (k) {
  3095. selectRect(x - h, y - k, x + h, y - k, set);
  3096. selectRect(x - h, y + k, x + h, y + k, set);
  3097. }
  3098. else selectRect(x - h, y, x + h, y, set);
  3099. ok = k;
  3100. }
  3101. if ((j != oj) && (j != ok) && (k != j)) {
  3102. if (j) {
  3103. selectRect(x - i, y - j, x + i, y - j, set);
  3104. selectRect(x - i, y + j, x + i, y + j, set);
  3105. }
  3106. else selectRect(x - i, y, x + i, y, set);
  3107. oj = j;
  3108. }
  3109. ix = ix + iy / rx;
  3110. iy = iy - ix / rx;
  3111. } while (i > h);
  3112. }
  3113. else {
  3114. ix = 0;
  3115. iy = ry * 64;
  3116. do {
  3117. h = (ix + 32) >> 6;
  3118. i = (iy + 32) >> 6;
  3119. j = (h * rx) / ry;
  3120. k = (i * rx) / ry;
  3121. if ((i != oi) && (i != oh)) {
  3122. if (i) {
  3123. selectRect(x - j, y - i, x + j, y - i, set);
  3124. selectRect(x - j, y + i, x + j, y + i, set);
  3125. }
  3126. else selectRect(x - j, y, x + j, y, set);
  3127. oi = i;
  3128. }
  3129. if ((h != oh) && (h != oi) && (i != h)) {
  3130. if (h) {
  3131. selectRect(x - k, y - h, x + k, y - h, set);
  3132. selectRect(x - k, y + h, x + k, y + h, set);
  3133. }
  3134. else selectRect(x - k, y, x + k, y, set);
  3135. oh = h;
  3136. }
  3137. ix = ix + iy / ry;
  3138. iy = iy - ix / ry;
  3139. } while(i > h);
  3140. }
  3141. }
  3142. void SceneEditLayer::selectRect(int x1, int y1, int x2, int y2, int set) { start_func
  3143. Rect rect = createRect(x1, y1, x2, y2);
  3144. Rect bound = { 0, 0, layerWidth, layerHeight };
  3145. if (intersectRects(rect, bound)) {
  3146. y1 = rect.y;
  3147. y2 = y1 + rect.h - 1;
  3148. x1 = rect.x;
  3149. x2 = x1 + rect.w - 1;
  3150. for (; y1 <= y2; ++y1) {
  3151. // Place in bitarray terms
  3152. Uint8 bit = 1 << (x1 & 7);
  3153. Uint8* selData = selected + (x1 >> 3) + y1 * selectedPitch;
  3154. for (int x = x1; x <= x2; ++x) {
  3155. if (set) {
  3156. *selData |= bit;
  3157. }
  3158. else {
  3159. *selData &= ~bit;
  3160. }
  3161. bit <<= 1;
  3162. if (bit == 0) {
  3163. bit = 1;
  3164. ++selData;
  3165. }
  3166. }
  3167. }
  3168. }
  3169. }
  3170. // @TODO: account for selection masking
  3171. void SceneEditLayer::layerDrawEllipse(int x, int y, int rx, int ry, Uint32* data, Uint32 mask, Uint32 set) const { start_func
  3172. // (skip if nothing being drawn)
  3173. if ((mask == 0xFFFFFFFF) && (set == 0)) return;
  3174. // ** Code modified from sge_primitives.cpp **
  3175. int ix, iy;
  3176. int h, i, j, k;
  3177. int oh, oi, oj, ok;
  3178. Uint32* target;
  3179. if (rx < 1) rx = 1;
  3180. if (ry < 1) ry = 1;
  3181. h = i = j = k = 0xFFFF;
  3182. #define PUTPIXEL(x, y) {\
  3183. if (((x) >= 0) && ((x) < layerWidth) && ((y) >= 0) && ((y) < layerHeight)) {\
  3184. target = data + (x) + (y) * layerWidth;\
  3185. *target = *target & mask | set;\
  3186. }\
  3187. }
  3188. if (rx > ry) {
  3189. ix = 0;
  3190. iy = rx * 64;
  3191. do {
  3192. oh = h;
  3193. oi = i;
  3194. oj = j;
  3195. ok = k;
  3196. h = (ix + 32) >> 6;
  3197. i = (iy + 32) >> 6;
  3198. j = (h * ry) / rx;
  3199. k = (i * ry) / rx;
  3200. if (((h != oh) || (k != ok)) && (h < oi)) {
  3201. PUTPIXEL(x + h, y + k);
  3202. if (h) PUTPIXEL(x - h, y + k);
  3203. if (k) {
  3204. PUTPIXEL(x + h, y - k);
  3205. if (h) PUTPIXEL(x - h, y - k);
  3206. }
  3207. }
  3208. if (((i != oi) || (j != oj)) && (h < i)) {
  3209. PUTPIXEL(x + i, y + j);
  3210. if (i) PUTPIXEL(x - i, y + j);
  3211. if (j) {
  3212. PUTPIXEL(x + i, y - j);
  3213. if (i) PUTPIXEL(x - i, y - j);
  3214. }
  3215. }
  3216. ix = ix + iy / rx;
  3217. iy = iy - ix / rx;
  3218. } while (i > h);
  3219. }
  3220. else {
  3221. ix = 0;
  3222. iy = ry * 64;
  3223. do {
  3224. oh = h;
  3225. oi = i;
  3226. oj = j;
  3227. ok = k;
  3228. h = (ix + 32) >> 6;
  3229. i = (iy + 32) >> 6;
  3230. j = (h * rx) / ry;
  3231. k = (i * rx) / ry;
  3232. if (((j != oj) || (i != oi)) && (h < i)) {
  3233. PUTPIXEL(x + j, y + i);
  3234. if (j) PUTPIXEL(x - j, y + i);
  3235. if (i) {
  3236. PUTPIXEL(x + j, y - i);
  3237. if (j) PUTPIXEL(x - j, y - i);
  3238. }
  3239. }
  3240. if (((k != ok) || (h != oh)) && (h < oi)) {
  3241. PUTPIXEL(x + k, y + h);
  3242. if (k) PUTPIXEL(x - k, y + h);
  3243. if (h) {
  3244. PUTPIXEL(x + k, y - h);
  3245. if (k) PUTPIXEL(x - k, y - h);
  3246. }
  3247. }
  3248. ix = ix + iy / ry;
  3249. iy = iy - ix / ry;
  3250. } while(i > h);
  3251. }
  3252. }
  3253. // @TODO: account for selection masking
  3254. void SceneEditLayer::layerDrawEllipseFill(int x, int y, int rx, int ry, Uint32* data, Uint32 mask, Uint32 set) const { start_func
  3255. // (skip if nothing being drawn)
  3256. if ((mask == 0xFFFFFFFF) && (set == 0)) return;
  3257. // ** Code modified from sge_primitives.cpp **
  3258. int ix, iy;
  3259. int h, i, j, k;
  3260. int oh, oi, oj, ok;
  3261. if (rx < 1) rx = 1;
  3262. if (ry < 1) ry = 1;
  3263. oh = oi = oj = ok = 0xFFFF;
  3264. if (rx > ry) {
  3265. ix = 0;
  3266. iy = rx * 64;
  3267. do {
  3268. h = (ix + 32) >> 6;
  3269. i = (iy + 32) >> 6;
  3270. j = (h * ry) / rx;
  3271. k = (i * ry) / rx;
  3272. if ((k != ok) && (k != oj)) {
  3273. if (k) {
  3274. layerDrawRect(x - h, y - k, x + h, y - k, data, mask, set);
  3275. layerDrawRect(x - h, y + k, x + h, y + k, data, mask, set);
  3276. }
  3277. else layerDrawRect(x - h, y, x + h, y, data, mask, set);
  3278. ok = k;
  3279. }
  3280. if ((j != oj) && (j != ok) && (k != j)) {
  3281. if (j) {
  3282. layerDrawRect(x - i, y - j, x + i, y - j, data, mask, set);
  3283. layerDrawRect(x - i, y + j, x + i, y + j, data, mask, set);
  3284. }
  3285. else layerDrawRect(x - i, y, x + i, y, data, mask, set);
  3286. oj = j;
  3287. }
  3288. ix = ix + iy / rx;
  3289. iy = iy - ix / rx;
  3290. } while (i > h);
  3291. }
  3292. else {
  3293. ix = 0;
  3294. iy = ry * 64;
  3295. do {
  3296. h = (ix + 32) >> 6;
  3297. i = (iy + 32) >> 6;
  3298. j = (h * rx) / ry;
  3299. k = (i * rx) / ry;
  3300. if ((i != oi) && (i != oh)) {
  3301. if (i) {
  3302. layerDrawRect(x - j, y - i, x + j, y - i, data, mask, set);
  3303. layerDrawRect(x - j, y + i, x + j, y + i, data, mask, set);
  3304. }
  3305. else layerDrawRect(x - j, y, x + j, y, data, mask, set);
  3306. oi = i;
  3307. }
  3308. if ((h != oh) && (h != oi) && (i != h)) {
  3309. if (h) {
  3310. layerDrawRect(x - k, y - h, x + k, y - h, data, mask, set);
  3311. layerDrawRect(x - k, y + h, x + k, y + h, data, mask, set);
  3312. }
  3313. else layerDrawRect(x - k, y, x + k, y, data, mask, set);
  3314. oh = h;
  3315. }
  3316. ix = ix + iy / ry;
  3317. iy = iy - ix / ry;
  3318. } while(i > h);
  3319. }
  3320. }
  3321. // @TODO: account for selection masking
  3322. // @TODO: additional matchmask to cover ext data as well
  3323. Rect SceneEditLayer::layerFloodFill(int x, int y, Uint32 matchMask, Uint32* data1, Uint32 mask1, Uint32 set1, Uint32* data2, Uint32 mask2, Uint32 set2) const { start_func
  3324. assert(data1);
  3325. // Min/Max area
  3326. Rect result = { 0, 0, 0, 0 };
  3327. // Clip area
  3328. if ((x < 0) || (y < 0) || (x >= layerWidth) || (y >= layerHeight)) return result;
  3329. // Extreme points
  3330. int x1 = x;
  3331. int x2 = x;
  3332. int y1 = y;
  3333. int y2 = y;
  3334. // Stack
  3335. #define FLOOD_STACK_SIZE 250
  3336. struct {
  3337. Uint32* d1;
  3338. Uint32* d2;
  3339. int x;
  3340. int y;
  3341. int yD;
  3342. } floodStack[FLOOD_STACK_SIZE];
  3343. int stackPos = 0;
  3344. #define PUSH(dp1, dp2, xp, yp, ydiff) {\
  3345. if (stackPos < FLOOD_STACK_SIZE) {\
  3346. floodStack[stackPos].d1 = dp1;\
  3347. floodStack[stackPos].d2 = dp2;\
  3348. floodStack[stackPos].x = xp;\
  3349. floodStack[stackPos].y = yp;\
  3350. floodStack[stackPos++].yD = ydiff;\
  3351. }\
  3352. }
  3353. #define POP(dp1, dp2, xp, yp, ydiff) {\
  3354. assert(stackPos);\
  3355. dp1 = floodStack[--stackPos].d1;\
  3356. dp2 = floodStack[stackPos].d2;\
  3357. xp = floodStack[stackPos].x;\
  3358. yp = floodStack[stackPos].y;\
  3359. ydiff = floodStack[stackPos].yD;\
  3360. }
  3361. // Starting point etc.
  3362. Uint32* dataPoint1 = data1 + x + y * layerWidth;
  3363. Uint32* dataPoint2 = NULL;
  3364. if (data2) dataPoint2 = data2 + x + y * layerWidth;
  3365. // Determine what we're matching against, don't fill if matches what we're doing
  3366. Uint32 target = *dataPoint1 & matchMask;
  3367. if ((target & mask1 | set1) == target) return result;
  3368. // Work areas
  3369. int top, bottom;
  3370. int lX;
  3371. int yDiff;
  3372. // Push starting point
  3373. PUSH(dataPoint1, dataPoint2, x, y, 0);
  3374. while (stackPos) {
  3375. // Next point to fill, then scan left and right
  3376. POP(dataPoint1, dataPoint2, x, y, yDiff);
  3377. dataPoint1 += yDiff * layerWidth;
  3378. if (dataPoint2) dataPoint2 += yDiff * layerWidth;
  3379. y += yDiff;
  3380. // Don't fill given point directly- instead, we'll scan it manually in the second loop
  3381. // Update extreme points- y
  3382. if (y < y1) y1 = y;
  3383. if (y > y2) y2 = y;
  3384. // Check both top and bottom for matches
  3385. top = bottom = 1;
  3386. // Fill as far left as possible
  3387. lX = x;
  3388. while ((lX > 0) && ((dataPoint1[-1] & matchMask) == target)) {
  3389. --lX;
  3390. --dataPoint1;
  3391. *dataPoint1 = *dataPoint1 & mask1 | set1;
  3392. if (dataPoint2) {
  3393. --dataPoint2;
  3394. *dataPoint2 = *dataPoint2 & mask2 | set2;
  3395. }
  3396. // Is point above fillable?
  3397. if ((y > 0) && ((dataPoint1[-layerWidth] & matchMask) == target)) {
  3398. // Are we pushing "above" points right now?
  3399. if (top) {
  3400. // Push onto stack
  3401. PUSH(dataPoint1, dataPoint2, lX, y, -1);
  3402. top = 0;
  3403. }
  3404. }
  3405. // Not fillable, we will now push the next "above" point we find
  3406. else top = 1;
  3407. // Is point below fillable?
  3408. if ((y < layerHeight - 1) && ((dataPoint1[layerWidth] & matchMask) == target)) {
  3409. // Are we pushing "below" points right now?
  3410. if (bottom) {
  3411. // Push onto stack
  3412. PUSH(dataPoint1, dataPoint2, lX, y, 1);
  3413. bottom = 0;
  3414. }
  3415. }
  3416. // Not fillable, we will now push the next "below" point we find
  3417. else bottom = 1;
  3418. }
  3419. // Update extreme left point
  3420. if (lX < x1) x1 = lX;
  3421. // Recenter, minus one, so that we scan the center/given point as well
  3422. --x;
  3423. dataPoint1 += x - lX;
  3424. if (dataPoint2) dataPoint2 += x - lX;
  3425. top = bottom = 1;
  3426. // Fill as far right as possible; this loop intentionally catches our first, central point
  3427. while ((x < layerWidth - 1) && ((dataPoint1[1] & matchMask) == target)) {
  3428. ++x;
  3429. ++dataPoint1;
  3430. *dataPoint1 = *dataPoint1 & mask1 | set1;
  3431. if (dataPoint2) {
  3432. ++dataPoint2;
  3433. *dataPoint2 = *dataPoint2 & mask2 | set2;
  3434. }
  3435. // Is point above fillable?
  3436. if ((y > 0) && ((dataPoint1[-layerWidth] & matchMask) == target)) {
  3437. // Are we pushing "above" points right now?
  3438. if (top) {
  3439. // Push onto stack
  3440. PUSH(dataPoint1, dataPoint2, x, y, -1);
  3441. top = 0;
  3442. }
  3443. }
  3444. // Not fillable, we will now push the next "above" point we find
  3445. else top = 1;
  3446. // Is point below fillable?
  3447. if ((y < layerHeight - 1) && ((dataPoint1[layerWidth] & matchMask) == target)) {
  3448. // Are we pushing "below" points right now?
  3449. if (bottom) {
  3450. // Push onto stack
  3451. PUSH(dataPoint1, dataPoint2, x, y, 1);
  3452. bottom = 0;
  3453. }
  3454. }
  3455. // Not fillable, we will now push the next "below" point we find
  3456. else bottom = 1;
  3457. }
  3458. // Update extreme right point
  3459. if (x > x2) x2 = x;
  3460. }
  3461. result.x = x1;
  3462. result.y = y1;
  3463. result.w = x2 - x1 + 1;
  3464. result.h = y2 - y1 + 1;
  3465. return result;
  3466. }
  3467. // @TODO: account for selection masking
  3468. Rect SceneEditLayer::layerMatchFill(int x, int y, Uint32 matchMask, Uint32* data1, Uint32 mask1, Uint32 set1, Uint32* data2, Uint32 mask2, Uint32 set2) const { start_func
  3469. assert(data1);
  3470. // Min/Max area
  3471. Rect result = { 0, 0, 0, 0 };
  3472. // Clip area
  3473. if ((x < 0) || (y < 0) || (x >= layerWidth) || (y >= layerHeight)) return result;
  3474. // Extreme points
  3475. int x1 = x;
  3476. int x2 = x;
  3477. int y1 = y;
  3478. int y2 = y;
  3479. // Determine what we're matching against, don't fill if matches what we're doing
  3480. Uint32 target = data1[x + y * layerWidth] & matchMask;
  3481. if ((target & mask1 | set1) == target) return result;
  3482. for (y = 0; y < layerHeight; ++y) {
  3483. for (x = 0; x < layerWidth; ++x) {
  3484. if ((*data1 & matchMask) == target) {
  3485. *data1 = *data1 & mask1 | set1;
  3486. if (data2) *data2 = *data2 & mask2 | set2;
  3487. // Update extreme points
  3488. if (y < y1) y1 = y;
  3489. if (y > y2) y2 = y;
  3490. if (x < x1) x1 = x;
  3491. if (x > x2) x2 = x;
  3492. }
  3493. ++data1;
  3494. if (data2) ++data2;
  3495. }
  3496. }
  3497. result.x = x1;
  3498. result.y = y1;
  3499. result.w = x2 - x1 + 1;
  3500. result.h = y2 - y1 + 1;
  3501. return result;
  3502. }
  3503. // @TODO: account for selection masking
  3504. void SceneEditLayer::layerDrawRect(int x1, int y1, int x2, int y2, Uint32* data, Uint32 mask, Uint32 set) const { start_func
  3505. assert(data);
  3506. // (skip if nothing being drawn)
  3507. if ((mask == 0xFFFFFFFF) && (set == 0)) return;
  3508. Rect affect = createRect(x1, y1, x2, y2);
  3509. Rect bound = { 0, 0, layerWidth, layerHeight };
  3510. if (!intersectRects(affect, bound)) return;
  3511. data += affect.y * layerWidth + affect.x;
  3512. for (int row = affect.h; row > 0; --row) {
  3513. for (int col = affect.w; col > 0; --col) {
  3514. *data = *data & mask | set;
  3515. ++data;
  3516. }
  3517. data += layerWidth - affect.w;
  3518. }
  3519. }
  3520. void SceneEditLayer::layerDrawBox(int x1, int y1, int x2, int y2, Uint32* data, Uint32 mask, Uint32 set) const { start_func
  3521. layerDrawRect(x1, y1, x2, y1, data, mask, set);
  3522. layerDrawRect(x1, y1, x1, y2, data, mask, set);
  3523. layerDrawRect(x2, y1, x2, y2, data, mask, set);
  3524. layerDrawRect(x1, y2, x2, y2, data, mask, set);
  3525. }
  3526. // @TODO: account for selection masking
  3527. void SceneEditLayer::layerDrawLine(int x1, int y1, int x2, int y2, Uint32* data, Uint32 mask, Uint32 set) const { start_func
  3528. assert(data);
  3529. // (skip if nothing being drawn)
  3530. if ((mask == 0xFFFFFFFF) && (set == 0)) return;
  3531. Sint16 x = x1;
  3532. Sint16 y = y1;
  3533. Sint16 dy = y2 - y1;
  3534. Sint16 dx = x2 - x1;
  3535. Sint16 G, DeltaG1, DeltaG2, minG, maxG;
  3536. Sint16 inc = 1;
  3537. if (abs(dy) < abs(dx)) {
  3538. if (dx < 0) {
  3539. dx = -dx;
  3540. dy = -dy;
  3541. y1 = y2;
  3542. y2 = y;
  3543. y = y1;
  3544. x1 = x2;
  3545. x2 = x;
  3546. x = x1;
  3547. }
  3548. if (dy < 0) {
  3549. dy = -dy;
  3550. inc = -1;
  3551. }
  3552. G = 2 * dy - dx;
  3553. DeltaG1 = 2 * (dy - dx);
  3554. DeltaG2 = 2 * dy;
  3555. data += y * layerWidth + x;
  3556. if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = *data & mask | set;
  3557. while (++x <= x2) {
  3558. ++data;
  3559. if (G > 0) { G += DeltaG1; y += inc; data += inc * layerWidth; }
  3560. else G += DeltaG2;
  3561. if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = *data & mask | set;
  3562. }
  3563. }
  3564. else {
  3565. if (dy < 0) {
  3566. dx = -dx;
  3567. dy = -dy;
  3568. y1 = y2;
  3569. y2 = y;
  3570. y = y1;
  3571. x1 = x2;
  3572. x2 = x;
  3573. x = x1;
  3574. }
  3575. if (dx < 0) {
  3576. dx = -dx;
  3577. inc = -1;
  3578. }
  3579. G = 2 * dx - dy;
  3580. minG = maxG = G;
  3581. DeltaG1 = 2 * (dx - dy);
  3582. DeltaG2 = 2 * dx;
  3583. data += y * layerWidth + x;
  3584. if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = *data & mask | set;
  3585. while (++y <= y2) {
  3586. data += layerWidth;
  3587. if (G > 0) { G += DeltaG1; x += inc; data += inc; }
  3588. else G += DeltaG2;
  3589. if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = *data & mask | set;
  3590. }
  3591. }
  3592. }
  3593. void SceneEditLayer::swapSelectionParameters(int& xoffs, int& yoffs, int& mode) { start_func
  3594. swap(xoffs, selectionXOffs);
  3595. swap(yoffs, selectionYOffs);
  3596. if (mode != selectionMode) {
  3597. if (mode == SELECTION_OUTLINE) {
  3598. refreshData(0);
  3599. }
  3600. else {
  3601. Uint32 affectBit = 1;
  3602. for (int pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
  3603. if (layersAffect & affectBit) {
  3604. memSet32(layerEdit[pos][0], Layer::LAYER_TILE_DEFAULT, layerWidth * layerHeight);
  3605. if (layerEdit[pos][1]) memSet32(layerEdit[pos][1], Layer::LAYER_EXT_DEFAULT, layerWidth * layerHeight);
  3606. if (layerEdit[pos][2]) memSet32(layerEdit[pos][2], Layer::LAYER_FX_DEFAULT, layerWidth * layerHeight);
  3607. }
  3608. }
  3609. }
  3610. }
  3611. swap(mode, selectionMode);
  3612. // Refresh
  3613. fixSelectionRect();
  3614. setDirty(1);
  3615. }
  3616. Window::WindowType SceneEditLayer::windowType() const { start_func
  3617. return WINDOW_CLIENT;
  3618. }
  3619. void SceneEditLayer::setDirtySelectedSpawns() { start_func
  3620. setDirtyPixelBox(selectedSpawnRect.x, selectedSpawnRect.y,
  3621. selectedSpawnRect.x + selectedSpawnRect.w - 1,
  3622. selectedSpawnRect.y + selectedSpawnRect.h - 1);
  3623. }
  3624. void SceneEditLayer::copySpawnSelection() { start_func
  3625. set<int>::iterator pos = selectedSpawns.begin();
  3626. set<int>::iterator end = selectedSpawns.end();
  3627. vector<const SpawnEdit*> toCopy;
  3628. vector<int> toCopyLayers;
  3629. while (pos != end) {
  3630. // Find spawn
  3631. SpawnEdit* spawn = world->findSpawn(*pos);
  3632. if (spawn) {
  3633. // Determine layer
  3634. int lPos = scene->findLayer(spawn->getLayer());
  3635. if (lPos >= 0) {
  3636. int bit = 1 << lPos;
  3637. if (layersAffect & bit) {
  3638. toCopy.push_back(spawn);
  3639. toCopyLayers.push_back(lPos);
  3640. }
  3641. }
  3642. }
  3643. ++pos;
  3644. }
  3645. clipboardCopy(toCopy, toCopyLayers);
  3646. }
  3647. void SceneEditLayer::deleteSpawnSelection() throw_Undo { start_func
  3648. set<int>::iterator pos = selectedSpawns.begin();
  3649. set<int>::iterator end = selectedSpawns.end();
  3650. world->undo.preUndoBlock();
  3651. undoStoreSpawnSelect();
  3652. while (pos != end) {
  3653. // Find spawn
  3654. SpawnEdit* spawn = world->findSpawn(*pos);
  3655. if (spawn) {
  3656. // Determine layer
  3657. int lPos = scene->findLayer(spawn->getLayer());
  3658. if (lPos >= 0) {
  3659. int bit = 1 << lPos;
  3660. if (layersAffect & bit) {
  3661. spawn->getLayer()->deleteSpawn(spawn, myFrame, this); // Exception point (undoes other deletions for us)
  3662. }
  3663. }
  3664. }
  3665. ++pos;
  3666. }
  3667. setDirtySelectedSpawns();
  3668. selectedSpawns.clear();
  3669. selectedSpawnRect.w = 0;
  3670. world->undo.postUndoBlock();
  3671. }
  3672. void SceneEditLayer::clearSpawnSelection(int storeUndo) throw_Undo { start_func
  3673. if (storeUndo) undoStoreSpawnSelect();
  3674. if (!selectedSpawns.empty()) {
  3675. setDirtySelectedSpawns();
  3676. selectedSpawns.clear();
  3677. selectedSpawnRect.w = 0;
  3678. }
  3679. }
  3680. void SceneEditLayer::updatedSpawnSelection() { start_func
  3681. recheckSpawnSelection();
  3682. setDirty(1);
  3683. }
  3684. void SceneEditLayer::recheckSpawnSelection() { start_func
  3685. set<int>::iterator pos = selectedSpawns.begin();
  3686. set<int>::iterator end = selectedSpawns.end();
  3687. set<int>::iterator check;
  3688. selectedSpawnRect.w = 0;
  3689. while (pos != end) {
  3690. check = pos;
  3691. ++pos;
  3692. // This spawn still in one of our affected layers?
  3693. int kill = 1;
  3694. SpawnEdit* spawn = world->findSpawn(*check);
  3695. if (spawn) {
  3696. // Determine layer
  3697. int lPos = scene->findLayer(spawn->getLayer());
  3698. if (lPos >= 0) {
  3699. int bit = 1 << lPos;
  3700. if (layersAffect & bit) {
  3701. Rect spawnRect = { spawn->getX(), spawn->getY(), spawn->getW(), spawn->getH() };
  3702. boundRects(selectedSpawnRect, spawnRect);
  3703. kill = 0;
  3704. }
  3705. }
  3706. }
  3707. if (kill) selectedSpawns.erase(check);
  3708. }
  3709. }
  3710. void SceneEditLayer::undoStoreSpawnSelect() throw_Undo { start_func
  3711. world->undo.storeUndoLayerSpawnSelection(&selectedSpawns, myFrame);
  3712. }
  3713. int SceneEditLayer::isInSpawnSelection(int x, int y) { start_func
  3714. // Find spawns in one of our affected layers
  3715. set<int>::iterator pos = selectedSpawns.begin();
  3716. set<int>::iterator end = selectedSpawns.end();
  3717. while (pos != end) {
  3718. // Find spawn
  3719. SpawnEdit* spawn = world->findSpawn(*pos);
  3720. if (spawn) {
  3721. // Determine layer
  3722. int lPos = scene->findLayer(spawn->getLayer());
  3723. if (lPos >= 0) {
  3724. int bit = 1 << lPos;
  3725. if (layersAffect & bit) {
  3726. if ((x >= spawn->getX()) &&
  3727. (y >= spawn->getY()) &&
  3728. (x < spawn->getX() + spawn->getW()) &&
  3729. (y < spawn->getY() + spawn->getH()))
  3730. return spawn->getId();
  3731. }
  3732. }
  3733. }
  3734. ++pos;
  3735. }
  3736. return 0;
  3737. }
  3738. void SceneEditLayer::startToolSpawnSelectionDrag() { start_func
  3739. startToolOnMove = 0;
  3740. if (toolActive) return;
  3741. toolActive = TOOLS_SELECTITEMDRAG;
  3742. toolStartX = cursorSpriteX;
  3743. toolStartY = cursorSpriteY;
  3744. toolCtrl = SDL_GetModState() & KMOD_CTRL;
  3745. toolAlt = SDL_GetModState() & KMOD_ALT;
  3746. mousePointer();
  3747. dragTool(1);
  3748. }
  3749. void SceneEditLayer::selectSpawnRect(int x1, int y1, int x2, int y2, int select, int selectAll) { start_func
  3750. Rect area = createRect(x1, y1, x2, y2);
  3751. int bit = 1;
  3752. for (int lPos = 0; lPos < numLayers; ++lPos, bit <<= 1) {
  3753. if (layersAffect & bit) {
  3754. // Check all spawns in this layer
  3755. LayerEdit* layer = scene->getLayerEdit(lPos);
  3756. for (int sPos = layer->getSpawnCount() - 1; sPos >= 0; --sPos) {
  3757. SpawnEdit* spawn = layer->getSpawn(sPos);
  3758. Rect spawnRect = { spawn->getX(), spawn->getY(), spawn->getW(), spawn->getH() };
  3759. if ((selectAll) || (intersectRects(spawnRect, area))) {
  3760. if (select) selectedSpawns.insert(spawn->getId());
  3761. else selectedSpawns.erase(spawn->getId());
  3762. }
  3763. }
  3764. }
  3765. }
  3766. }
  3767. void SceneEditLayer::moveSpawnSelection(int byX, int byY, int skipUndo) { start_func
  3768. set<int>::iterator pos = selectedSpawns.begin();
  3769. set<int>::iterator end = selectedSpawns.end();
  3770. while (pos != end) {
  3771. // Find spawn
  3772. SpawnEdit* spawn = world->findSpawn(*pos);
  3773. if (spawn) {
  3774. // Determine layer
  3775. int lPos = scene->findLayer(spawn->getLayer());
  3776. if (lPos >= 0) {
  3777. int bit = 1 << lPos;
  3778. if (layersAffect & bit) {
  3779. spawn->setPos(spawn->getX() + byX, spawn->getY() + byY, skipUndo, myFrame, this);
  3780. }
  3781. }
  3782. }
  3783. ++pos;
  3784. }
  3785. selectedSpawnRect.x += byX;
  3786. selectedSpawnRect.y += byY;
  3787. }