123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374 |
- /* GCSx
- ** SCENEEDITLAYER.CPP
- **
- ** Scene editing- tile layers
- */
- /*****************************************************************************
- ** Copyright (C) 2003-2006 Janson
- **
- ** This program is free software; you can redistribute it and/or modify
- ** it under the terms of the GNU General Public License as published by
- ** the Free Software Foundation; either version 2 of the License, or
- ** (at your option) any later version.
- **
- ** This program is distributed in the hope that it will be useful,
- ** but WITHOUT ANY WARRANTY; without even the implied warranty of
- ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- ** GNU General Public License for more details.
- **
- ** You should have received a copy of the GNU General Public License
- ** along with this program; if not, write to the Free Software
- ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
- *****************************************************************************/
- #include "all.h"
- // Tool panel
- const ToolSelect::ToolIconStruct SceneEditLayerTools::toolIcons[TOOLSELECT_NUM_TOOLS] = {
- { TOOLS_PEN, 0, 0, "Draw (place tile or pattern)" },
- { TOOLS_LINE, 20, 0, "Straight line" },
- { TOOLS_DROPPER, 40, 40, "Dropper (grab tile or pattern)" },
- { TOOLS_FILL, 80, 0, "Flood fill" },
- { TOOLS_RECT, 80, 60, "Rectangle (outline)" },
- { TOOLS_RECTFILL, 40, 0, "Rectangle (filled)" },
- { TOOLS_ELLIPSE, 40, 80, "Ellipse (outline)" },
- { TOOLS_ELLIPSEFILL, 60, 0, "Ellipse (filled)" },
- { TOOLS_SELECT, 0, 20, "Select area (rectangle)" },
- { TOOLS_SELECTELLIPSE, 20, 20, "Select area (ellipse)" },
- { TOOLS_WAND, 40, 20, "Magic wand (select area by tile)" },
- { TOOLS_SELECTITEM, 0, 120, "Select/modify sprite(s)" },
- { TOOLS_PLACEITEM, 80, 100, "Place new sprite" },
- { TOOLS_PLACESERIES, 80, 120, "Place multiple sprites" },
- };
- FrameWindow* SceneEditLayerTools::createWindowed() { start_func
- // Prevent duplication
- if (myFrame) {
- return myFrame;
- }
- // We remember the frame pointer even though it'll delete itself
- myFrame = new FrameWindow("Tools", FrameWindow::RESIZING_SNAP, FrameWindow::FRAMETYPE_DIALOG, this, FrameWindow::TITLEBAR_TOOL, 0);
- return myFrame;
- }
- Window::WindowSort SceneEditLayerTools::windowSort() const { start_func
- return WINDOWSORT_ONTOP;
- }
- void SceneEditLayerTools::adjustForTool() { start_func
- WCheckBox* check = dynamic_cast<WCheckBox*>(findWidget(ID_CONTIGUOUS));
- if ((*toolLPtr == TOOLS_WAND) || (*toolLPtr == TOOLS_FILL) || (*toolRPtr == TOOLS_WAND) || (*toolRPtr == TOOLS_FILL)) {
- check->enable();
- }
- else {
- check->disable();
- }
-
- paintArea->newToolSelected();
- }
- int SceneEditLayerTools::event(int hasFocus, const SDL_Event* event) { start_func
- if (event->type == SDL_COMMAND) {
- // Simple cases
- switch (event->user.code) {
- case VIEW_GRID:
- *gridPtr = *gridPtr ? 0 : 1;
- findWidget(ID_GRID)->load();
- paintArea->refresh();
- config->write(LAYEREDIT_GRID, *gridPtr);
- return 1;
- case TOOLS_CONTIGUOUS:
- *contiguousPtr = *contiguousPtr ? 0 : 1;
- findWidget(ID_CONTIGUOUS)->load();
- return 1;
- }
- // Choose tool
- int newToolL = 0;
- int newToolR = 0;
- WButton* toolButtonL = dynamic_cast<WButton*>(findWidget(ID_TOOLL));
- WButton* toolButtonR = dynamic_cast<WButton*>(findWidget(ID_TOOLR));
- int x, y;
- int modeSwap = 0;
- if (event->user.code == TOOLS_CHOOSE) {
- newToolL = toolSelect->run(toolButtonL->getScreenX(), toolButtonL->getScreenY() + toolButtonL->getHeight());
- }
- else if (event->user.code == TOOLS_CHOOSER) {
- newToolR = toolSelect->run(toolButtonR->getScreenX(), toolButtonR->getScreenY() + toolButtonR->getHeight());
- }
- else if (toolSelect->isTool(event->user.code)) {
- newToolL = event->user.code;
- paintArea->startToolIfMove();
- }
- if ((newToolL) || (newToolR)) {
- int targetToolL = *toolLPtr;
- int targetToolR = *toolRPtr;
-
- if (newToolL) targetToolL = newToolL;
- if (newToolR) targetToolR = newToolR;
-
- // Mode swap?
- if ((targetToolL == TOOLS_PLACEITEM) || (targetToolL == TOOLS_PLACESERIES) || (targetToolL == TOOLS_SELECTITEM)) {
- if ((targetToolR != TOOLS_PLACEITEM) && (targetToolR != TOOLS_PLACESERIES) && (targetToolR != TOOLS_SELECTITEM)) {
- modeSwap = 1;
- }
- }
- else {
- if ((targetToolR == TOOLS_PLACEITEM) || (targetToolR == TOOLS_PLACESERIES) || (targetToolR == TOOLS_SELECTITEM)) {
- modeSwap = 1;
- }
- }
-
- if (modeSwap) {
- swap(*toolLPtr, otherModeToolL);
- swap(*toolRPtr, otherModeToolR);
- }
-
- if (newToolL) *toolLPtr = newToolL;
- if (newToolR) *toolRPtr = newToolR;
-
- if (toolSelect->getToolIcon(*toolLPtr, x, y)) toolButtonL->changeIcon(x, y);
- if (toolSelect->getToolIcon(*toolRPtr, x, y)) toolButtonR->changeIcon(x, y);
-
- adjustForTool();
- return 1;
- }
- if ((event->user.code == TOOLS_CHOOSE) || (event->user.code == TOOLS_CHOOSER)) return 1;
- }
- return Dialog::event(hasFocus, event);
- }
- void SceneEditLayerTools::childModified(Window* modified) { start_func
- Dialog::childModified(modified);
- Widget* widget = dynamic_cast<Widget*>(modified);
- if (widget) {
- // If certain settings modified, tile area needs to refresh
- if (widget->getId() == ID_GRID) {
- paintArea->refresh();
- }
- // Save config settings
- config->write(LAYEREDIT_GRID, *gridPtr);
- }
- }
- int SceneEditLayerTools::wantsToBeDeleted() const { start_func
- return 1;
- }
- SceneEditLayerTools::~SceneEditLayerTools() { start_func
- delete toolSelect;
- }
- SceneEditLayerTools::SceneEditLayerTools(SceneEditLayer* tPaintArea, int* toolL, int* toolR, int* contiguous, int* grid) : Dialog(blankString, 1, 0, 1) { start_func
- paintArea = tPaintArea;
- toolLPtr = toolL;
- toolRPtr = toolR;
- contiguousPtr = contiguous;
- gridPtr = grid;
-
- // Other-mode tools based on currently selected tool
- if ((*toolL == TOOLS_PLACEITEM) || (*toolL == TOOLS_PLACESERIES) || (*toolL == TOOLS_SELECTITEM)) {
- otherModeToolL = TOOLS_PEN;
- }
- else {
- otherModeToolL = TOOLS_PLACESERIES;
- }
- if ((*toolR == TOOLS_PLACEITEM) || (*toolR == TOOLS_PLACESERIES) || (*toolR == TOOLS_SELECTITEM)) {
- otherModeToolR = TOOLS_DROPPER;
- }
- else {
- otherModeToolR = TOOLS_SELECTITEM;
- }
- Widget* w = NULL;
- myFrame = NULL;
- toolSelect = new ToolSelect(getIconSurface(), TOOLSELECT_NUM_TOOLS, toolIcons);
- int x = 0;
- int y = 0;
- toolSelect->getToolIcon(*toolLPtr, x, y);
- w = new WButton(ID_TOOLL, getIconSurface(), x, y, 20, 20, Dialog::BUTTON_NOTHING, TOOLS_CHOOSE);
- w->setToolTip("Change tool (left button)");
- w->addTo(this);
- x = y = 0;
- toolSelect->getToolIcon(*toolRPtr, x, y);
- w = new WButton(ID_TOOLR, getIconSurface(), x, y, 20, 20, Dialog::BUTTON_NOTHING, TOOLS_CHOOSER);
- w->setToolTip("Change tool (right button)");
- w->addTo(this);
- w = new WCheckBox(ID_CONTIGUOUS, "Contiguous", contiguous, 1);
- w->setToolTip("Only flood-fill or wand-select a single, connected area");
- w->addTo(this);
- arrangeRow();
- w = new WButton(ID_COPY, getIconSurface(), 60, 20, 20, 20, Dialog::BUTTON_NOTHING, EDIT_COPY);
- w->setToolTip("Copy");
- w->addTo(this);
- w = new WButton(ID_PASTE, getIconSurface(), 80, 20, 20, 20, Dialog::BUTTON_NOTHING, EDIT_PASTE);
- w->setToolTip("Paste (as new selection)");
- w->addTo(this);
- w = new WCheckBox(ID_GRID, getIconSurface(), 0, 100, 20, 20, grid, 1);
- w->setToolTip("Show or hide grid");
- w->addTo(this);
- arrangeRow();
- adjustForTool();
- runAsPanel();
- }
- // Layer panel
- FrameWindow* SceneEditLayerList::createWindowed() { start_func
- // Prevent duplication
- if (myFrame) {
- return myFrame;
- }
- // We remember the frame pointer even though it'll delete itself
- myFrame = new FrameWindow("Layers", FrameWindow::RESIZING_SNAP, FrameWindow::FRAMETYPE_DIALOG, this, FrameWindow::TITLEBAR_TOOL, 0);
- return myFrame;
- }
- Window::WindowSort SceneEditLayerList::windowSort() const { start_func
- return WINDOWSORT_ONTOP;
- }
- int SceneEditLayerList::event(int hasFocus, const SDL_Event* event) { start_func
- if (event->type == SDL_COMMAND) {
- // Simple cases
- switch (event->user.code) {
- case VIEW_ALLLAYER:
- case VIEW_DIMLAYER:
- case VIEW_NOLAYER:
- case VIEW_PREV:
- case VIEW_NEXT:
- return layerList->event(0, event);
- }
- }
- return Dialog::event(hasFocus, event);
- }
- void SceneEditLayerList::childModified(Window* modified) { start_func
- Dialog::childModified(modified);
- Widget* widget = dynamic_cast<Widget*>(modified);
- if (widget) {
- // Layer visibility/selection
- if (widget == layerList) {
- paintArea->refreshLayers();
- }
- }
- }
- int SceneEditLayerList::wantsToBeDeleted() const { start_func
- return 1;
- }
- SceneEditLayerList::~SceneEditLayerList() { start_func
- }
- SceneEditLayerList::SceneEditLayerList(SceneEditLayer* tPaintArea) : Dialog(blankString, 1, 0, 1) { start_func
- paintArea = tPaintArea;
- Widget* w = NULL;
- myFrame = NULL;
- w = layerList = new WLayerListBox(ID_LAYER, &selectedLayer);
- // @TODO: More specific tooltips
- w->setToolTip("Select which layer(s) to view and edit");
- w->addTo(this);
- arrangeRow();
- w = new WButton(ID_LAYERADD, "Add...", Dialog::BUTTON_NOTHING, NEW_LAYER);
- w->setToolTip("Add a new layer");
- w->addTo(this);
- arrangeRow();
- runAsPanel();
- }
- // Sprite panel
- FrameWindow* SceneEditSpriteList::createWindowed() { start_func
- // Prevent duplication
- if (myFrame) {
- return myFrame;
- }
- // We remember the frame pointer even though it'll delete itself
- myFrame = new FrameWindow("Objects", FrameWindow::RESIZING_SNAP, FrameWindow::FRAMETYPE_DIALOG, this, FrameWindow::TITLEBAR_TOOL, 0);
- return myFrame;
- }
- Window::WindowSort SceneEditSpriteList::windowSort() const { start_func
- return WINDOWSORT_ONTOP;
- }
- int SceneEditSpriteList::wantsToBeDeleted() const { start_func
- return 1;
- }
- SceneEditSpriteList::~SceneEditSpriteList() { start_func
- if (spriteList) {
- WidgetScroll* ws = dynamic_cast<WidgetScroll*>(spriteList->getParent());
- if (ws) ws->newClient();
- delete spriteList;
- }
- }
- SceneEditSpriteList::SceneEditSpriteList(SceneEditLayer* tPaintArea, WorldEdit* tWorld) : Dialog(blankString, 1, 0, 1) { start_func
- paintArea = tPaintArea;
- world = tWorld;
- buildingList = 0;
- myFrame = NULL;
- spriteList = new TreeView(blankString, NULL, 0, NULL, 1);
- buildSpriteList();
- // @TODO: add ::event and catch add/delete scripts
- buildingList = 1;
- spriteList->addTo(this, -1, 6);
- buildingList = 0;
- // @TODO: Tooltips
- arrangeRow();
- runAsPanel();
- }
- void SceneEditSpriteList::buildSpriteList() { start_func
- TreeView* scripts;
- TreeView* item;
- buildingList = 1;
- spriteList->insert(scripts = new TreeView("(custom object)", this, 1, treeViewWrapOther), 0);
- // @TODO: spriteList->insert(new TreeView("Libraries", this, 0, treeViewWrapOther), 0);
- // @TODO: spriteList->insert(new TreeView("Recent", this, 0, treeViewWrapOther), 0);
- spriteList->insert(scripts = new TreeView("Scripts", this, 0, treeViewWrapOther), 0);
- // @TODO: spriteList->insert(new TreeView("Used in Scene", this, 0, treeViewWrapOther), 0);
-
- World::ScriptIndex::const_iterator end = world->endScript();
- for (World::ScriptIndex::const_iterator pos = world->beginScript(); pos != end; ++pos) {
- ScriptEdit* script = dynamic_cast<ScriptEdit*>((*pos).second);
- if (script->getType() == Script::SCRIPT_CODE) {
- scripts->insert(item = new TreeView(script->getName(), this, script->getId(), treeViewWrapScript), 0);
- item->setIcon(script->getDefaultId() ? 13 : 12);
- }
- }
-
- buildingList = 0;
- }
- int SceneEditSpriteList::treeViewWrapScript(void* ptr, int code, int command, int check) { start_func
- return ((SceneEditSpriteList*)ptr)->treeViewScript(code, command, check);
- }
- int SceneEditSpriteList::treeViewScript(int code, int command, int check) { start_func
- if (check) {
- return Window::COMMAND_HIDE;
- }
-
- if (buildingList) return 0;
- if ((command == LV_MOVE) || (command == LV_LCLICK)) {
- ScriptEdit* script = dynamic_cast<ScriptEdit*>(world->findScript(code));
- if (script) {
- SpawnEdit* newSpawn = new SpawnEdit(world, NULL);
- newSpawn->markLock();
- newSpawn->setName(script->getName());
- newSpawn->setScript(script);
- newSpawn->setSprite(script->getDefaultAnimgroup(), script->getDefaultTileset(),
- script->getDefaultId());
- paintArea->setSpawnPlace(newSpawn);
- }
- return 1;
- }
- return 0;
- }
- int SceneEditSpriteList::treeViewWrapOther(void* ptr, int code, int command, int check) { start_func
- return ((SceneEditSpriteList*)ptr)->treeViewOther(code, command, check);
- }
- int SceneEditSpriteList::treeViewOther(int code, int command, int check) { start_func
- if (check) {
- return Window::COMMAND_HIDE;
- }
- if (buildingList) return 0;
- if ((command == LV_MOVE) || (command == LV_LCLICK)) {
- if (code == 1) {
- // Blank starting point
- SpawnEdit* newSpawn = new SpawnEdit(world, NULL);
- newSpawn->markLock();
- paintArea->setSpawnPlace(newSpawn);
- }
-
- return 1;
- }
- return 0;
- }
- // Main edit window
- SceneEditLayer::SceneEditLayer(SceneEdit* myScene) : selectedSpawns(), backupSelectedSpawns() throw_File { start_func
- assert(myScene);
- cursorX = cursorY = virtualCursorX = virtualCursorY = 0;
- cursorSpriteX = cursorSpriteY = 0;
- cursorW = cursorH = 1;
- haveFocus = partialFocus = 0;
- toolActive = startToolOnMove = 0;
- dirtyRange.w = 0;
- selectionRect.w = 0;
- selectionMode = SELECTION_OUTLINE;
- selectionXOffs = 0;
- selectionYOffs = 0;
- selectedSpawnRect.w = 0;
- backupSelectedSpawnRect.w = 0;
- scene = myScene;
- world = scene->getWorldEdit();
- scene->markLock(); // Exception point
- // Intentionally doesn't remember last tool selected
- // If we ever do, we must ensure both tools in this startup position
- // are sprite or non-sprite tools
- toolL = TOOLS_PEN;
- toolR = TOOLS_DROPPER;
- spriteMode = 0;
- spriteShown = 0;
- spriteAtCursor = 0;
- spawnPlace = new SpawnEdit(world, NULL);
- spawnPlace->markLock();
- spawnPropertiesDone = 0;
- contiguous = 1;
- // Recall last settings
- enableGrid = config->readNum(LAYEREDIT_GRID) ? 1 : 0;
- myFrame = NULL;
- tools = NULL;
- imagebar = NULL;
- colorbar = NULL;
- layerlist = NULL;
- spritelist = NULL;
- selected = NULL;
- backupSelected = NULL;
- for (int pos = 0; pos < MAX_LAYERS; ++pos) {
- layerEdit[pos][0] = NULL;
- layerEdit[pos][1] = NULL;
- layerEdit[pos][2] = NULL;
- }
- FrameWindow* toolsFrame = NULL;
- FrameWindow* imagebarFrame = NULL;
- FrameWindow* colorbarFrame = NULL;
- FrameWindow* layerlistFrame = NULL;
- FrameWindow* spritelistFrame = NULL;
- try {
- // Init frame up here so reloadLayerStats sets it's scroll size properly
- myFrame = new FrameWindow(blankString, FrameWindow::RESIZING_NORMAL, FrameWindow::FRAMETYPE_BEVEL_BK, this);
- myFrame->setAutoCenter(1);
- // First call to this determines our cursor layer
- initAvailableLayers();
- reloadLayerStats(1);
- refreshData(0);
- LayerEdit* layer = scene->getLayerEdit(cursorLayer);
- TileSetEdit* tileset = layer->getTileSetEdit();
-
- imagebar = new ImageSelect(tileset, &colors); // One exception point (others?)
- colorbar = new ColorSelect(&colors, 0, 0, Layer::LAYER_EXT_ALPHA_BITDEPTH, Layer::LAYER_TILE_COLOR_BITDEPTH);
- tools = new SceneEditLayerTools(this, &toolL, &toolR, &contiguous, &enableGrid);
- layerlist = new SceneEditLayerList(this);
- spritelist = new SceneEditSpriteList(this, world);
- setUsesExt(layerExt);
-
- imagebarFrame = imagebar->createWindowed();
- colorbarFrame = colorbar->createWindowed();
- toolsFrame = tools->createWindowed();
- layerlistFrame = layerlist->createWindowed();
- spritelistFrame = spritelist->createWindowed();
-
- // Second call to this fills our layer list
- initAvailableLayers();
-
- updateTitlebar();
- myFrame->addToolPanel(imagebarFrame, FrameWindow::CLIENT_BOTTOM);
- myFrame->addToolPanel(colorbarFrame, FrameWindow::CLIENT_RIGHT);
- myFrame->addToolPanel(toolsFrame, FrameWindow::CLIENT_RIGHT);
- myFrame->addToolPanel(layerlistFrame, FrameWindow::CLIENT_RIGHT);
- myFrame->addToolPanel(spritelistFrame, FrameWindow::CLIENT_RIGHT);
- myFrame->show(FrameWindow::SHOW_CASCADE, FrameWindow::SHOW_CASCADE, FrameWindow::SHOW_CURRENT, FrameWindow::SHOW_CURRENT);
- imagebar->colorRefresh();
- }
- catch (...) {
- if (myFrame) {
- myFrame->dropClients();
- delete myFrame;
- myFrame = NULL;
- }
- if (spritelistFrame) {
- delete spritelistFrame;
- }
- else {
- delete spritelist;
- }
- if (layerlistFrame) {
- delete layerlistFrame;
- }
- else {
- delete layerlist;
- }
- if (toolsFrame) {
- delete toolsFrame;
- }
- else {
- delete tools;
- }
- if (colorbarFrame) {
- delete colorbarFrame;
- }
- else {
- delete colorbar;
- }
- if (imagebarFrame) {
- delete imagebarFrame;
- }
- else {
- delete imagebar;
- }
- for (int pos = 0; pos < MAX_LAYERS; ++pos) {
- delete[] layerEdit[pos][0];
- delete[] layerEdit[pos][1];
- delete[] layerEdit[pos][2];
- }
- delete[] selected;
- delete[] backupSelected;
- scene->markUnlock();
- throw;
- }
- // Disabled/etc status on various tools
- updateCopyTool();
- }
- SceneEditLayer::~SceneEditLayer() { start_func
- for (int pos = 0; pos < MAX_LAYERS; ++pos) {
- delete[] layerEdit[pos][0];
- delete[] layerEdit[pos][1];
- delete[] layerEdit[pos][2];
- }
- delete[] selected;
- delete[] backupSelected;
- delete spawnPlace;
- if (scene) scene->markUnlock();
- }
- void SceneEditLayer::updateCopyTool() { start_func
- if ((selectionRect.w) || (selectedSpawnRect.w)) tools->findWidget(SceneEditLayerTools::ID_COPY)->enable();
- else tools->findWidget(SceneEditLayerTools::ID_COPY)->disable();
- }
- void SceneEditLayer::setSpawnPlace(class SpawnEdit* newSpawn) {
- delete spawnPlace;
- spawnPlace = newSpawn;
- spawnPropertiesDone = 0;
-
- if ((toolL != TOOLS_PLACEITEM) && (toolR != TOOLS_PLACEITEM) &&
- (toolL != TOOLS_PLACESERIES) && (toolR != TOOLS_PLACESERIES)) {
- desktop->broadcastEvent(SDL_COMMAND, TOOLS_PLACEITEM);
- desktop->broadcastEvent(SDL_COMMAND, CMD_RELEASE);
- }
- // @TODO: Dirty sprite area only
- setDirty(1);
- }
- void SceneEditLayer::setDirtyRect(const Rect& rect, int selectionFeather) { start_func
- // Clip
- Rect bound = { 0, 0, layerWidth, layerHeight };
- if (intersectRects(bound, rect)) {
- // Scale to tile size
- bound.x *= tileWidth;
- bound.y *= tileHeight;
- bound.w *= tileWidth;
- bound.h *= tileHeight;
-
- // Feather for selection modification?
- if (selectionFeather) {
- if (bound.x > 0) {
- --bound.x;
- ++bound.w;
- }
- if (bound.y > 0) {
- --bound.y;
- ++bound.h;
- }
- // We don't bother checking if our w/h goes over the limit-
- // this will get clipped; but negative x/y is too odd to allow, above
- ++bound.w;
- ++bound.h;
- }
- // Add rectangle into dirty range
- boundRects(dirtyRange, bound);
- setDirty();
- }
- }
- void SceneEditLayer::setDirtyBox(int x1, int y1, int x2, int y2, int selectionFeather) { start_func
- // Create a rectangle
- // Add rectangle into dirty range
- setDirtyRect(createRect(x1, y1, x2, y2), selectionFeather);
- }
- void SceneEditLayer::setDirtyPixelBox(int x1, int y1, int x2, int y2) { start_func
- boundRects(dirtyRange, createRect(x1, y1, x2, y2));
- setDirty();
- }
- void SceneEditLayer::setUsesExt(int usesExt) { start_func
- if (colorbar) colorbar->alphaDepth(usesExt ? Layer::LAYER_EXT_ALPHA_BITDEPTH : 0);
- if (imagebar) imagebar->allowAlpha(usesExt);
- }
- void SceneEditLayer::siblingModified(Window* modified) { start_func
- // Img selector updates with any color change
- if (modified == colorbar) {
- if (imagebar) imagebar->colorRefresh();
- }
- }
- // Note: any change to this function may need to also propogate to OBJMOD_TILES handler (+ OBJMOD_COLL?)
- void SceneEditLayer::refreshData(int cursorLayerOnly, int x1, int y1, int x2, int y2) { start_func
- assert(scene);
-
- Rect affect = createRect(x1, y1, x2, y2);
- Rect bound = { 0, 0, layerWidth, layerHeight };
- if (!intersectRects(affect, bound)) return;
-
- Uint32 bit = 1;
- int pos = 0;
- int max = numLayers - 1;
- if (cursorLayerOnly) {
- pos = max = cursorLayer;
- if (pos) bit <<= pos;
- }
- for (; pos <= max; ++pos, bit <<= 1) {
- if (layersAffect & bit) {
- scene->getLayerEdit(pos)->loadLayer(layerEdit[pos][0] + affect.x + affect.y * layerWidth,
- layerEdit[pos][1] + affect.x + affect.y * layerWidth,
- layerEdit[pos][2] + affect.x + affect.y * layerWidth,
- layerWidth, affect);
- }
- }
- }
- void SceneEditLayer::applyData(int cursorLayerOnly, int x1, int y1, int x2, int y2) { start_func
- assert(scene);
-
- Rect affect = createRect(x1, y1, x2, y2);
- Rect bound = { 0, 0, layerWidth, layerHeight };
- if (!intersectRects(affect, bound)) return;
-
- Uint32 bit = 1;
- int pos = 0;
- int max = numLayers - 1;
- if (cursorLayerOnly) {
- pos = max = cursorLayer;
- if (pos) bit <<= pos;
- }
- for (; pos <= max; ++pos, bit <<= 1) {
- if (layersAffect & bit) {
- scene->getLayerEdit(pos)->saveLayer(layerEdit[pos][0] + affect.x + affect.y * layerWidth,
- layerEdit[pos][1] + affect.x + affect.y * layerWidth,
- layerEdit[pos][2] + affect.x + affect.y * layerWidth,
- layerWidth, affect, this);
- }
- }
- // @TODO: preview redraw
- }
- void SceneEditLayer::initAvailableLayers() { start_func
- // Fill layer variables etc.
- numLayers = scene->getLayerCount();
- // (must be at least one layer)
- assert(numLayers);
-
- // @TODO: Remember current layer(s) during a session? (reopening windows)
-
- if (layerlist) {
- if (layerlist->layerList) {
- layerlist->layerList->clear();
- layerlist->layerList->setScene(scene);
- }
- }
-
- Uint32 bit = 1;
- layersAffect = 0;
- layersDim = 0;
- layersAvailable = 0;
- layersView = 0;
- for (int pos = 0; pos < numLayers; ++pos, bit <<= 1) {
- layersView |= bit;
- Layer* layer = scene->getLayer(pos);
- if (layer->getType() == Layer::LAYER_TILE) {
- layersAvailable |= bit;
- if (!layersAffect) {
- layersAffect = bit;
- cursorLayer = pos;
- }
- }
- // All layers get added
- if (layerlist) {
- if (layerlist->layerList) {
- // (select item if cursor layer)
- layerlist->layerList->WListBox::addItem(ListEntry(layer->getName(), pos,
- ((layersView & bit) ? WLayerListBox::FLAG_VISIBLE : 0) |
- ((layersAffect & bit) ? WLayerListBox::FLAG_EDITABLE : 0),
- layer->getType(),
- 0, !(layersAvailable & bit)),
- cursorLayer == pos);
- }
- }
- }
-
- // (must be at least one tile layer)
- assert(layersAffect);
- }
- void SceneEditLayer::reloadLayerStats(int resizeView) { start_func
- assert(cursorLayer >= 0);
- assert(cursorLayer < numLayers);
- // Retain old selection?
- int retainSelData = 0;
- Uint8* oldSelected = NULL;
- int oldSelectedPitch;
- int oldSelectedHeight;
- if (selectionRect.w) {
- oldSelected = selected;
- oldSelectedPitch = selectedPitch;
- oldSelectedHeight = layerHeight;
- // Retain contents of a floating selection?
- if (selectionMode != SELECTION_OUTLINE) retainSelData = 1;
- }
- else {
- delete[] selected;
- selectionMode = SELECTION_OUTLINE;
- }
- delete[] backupSelected;
- selected = NULL;
- backupSelected = NULL;
-
- // Old sizes for retaining data
- int prevWidth = layerWidth;
- int prevHeight = layerHeight;
- // Get stats on current layer
- LayerEdit* layer = scene->getLayerEdit(cursorLayer);
- layerWidth = layer->getXSize();
- layerHeight = layer->getYSize();
- layerExt = layer->getUsesExt();
- setUsesExt(layerExt);
- TileSetEdit* tileset = layer->getTileSetEdit();
- numTiles = tileset->getCount();
- tileWidth = tileset->getWidth();
- tileHeight = tileset->getHeight();
- // Layer should have already locked tileset- exception should never happen
- try {
- if (imagebar) imagebar->changeSet(tileset);
- }
- catch (FileException& e) {
- fatalCrash(0, "Error reading tileset- %s", e.details);
- }
-
- // Clip cursor
- if (cursorX >= layerWidth) cursorX = layerWidth - 1;
- if (cursorY >= layerHeight) cursorY = layerHeight - 1;
-
- // Allocate selection storage
- selectedPitch = (layerWidth + 7) / 8;
- selected = new Uint8[selectedPitch * layerHeight];
- backupSelected = new Uint8[selectedPitch * layerHeight];
- memset(selected, 0, selectedPitch * layerHeight);
- memset(backupSelected, 0, selectedPitch * layerHeight);
-
- // Copy over saved selection
- if (oldSelected) {
- matrixCopy(oldSelected, selected, min(selectedPitch, oldSelectedPitch), min(oldSelectedHeight, layerHeight), oldSelectedPitch, selectedPitch);
- fixSelectionRect();
- delete[] oldSelected;
- }
-
- // Allocate layer storage
- Uint32 bit = 1;
- int affectedChange = 0;
- for (int pos = 0; pos < numLayers; ++pos, bit <<= 1) {
- if (layersAffect & bit) {
- // Ensure this layer has the same stats
- int same = 1;
-
- Layer* layer = scene->getLayer(pos);
- if ((layerWidth != layer->getXSize()) || (layerHeight != layer->getYSize())) same = 0;
-
- TileSet* tileset = layer->getTileSet();
- if ((tileWidth != tileset->getWidth()) || (tileHeight != tileset->getHeight())) same = 0;
-
- if (same) {
- int usesExt = layer->getUsesExt();
- int usesFx = layer->getUsesFx();
- int layerSize = layerWidth * layerHeight;
-
- // Retain a floating selection?
- if (retainSelData) {
- Uint32* newEdit = NULL;
-
- newEdit = new Uint32[layerSize];
- memSet32(newEdit, Layer::LAYER_TILE_DEFAULT, layerSize);
- matrixCopy(layerEdit[pos][0], newEdit, min(prevWidth, layerWidth) * 4, min(prevHeight, layerHeight), prevWidth * 4, layerWidth * 4);
- delete[] layerEdit[pos][0];
- layerEdit[pos][0] = newEdit;
- newEdit = NULL;
- if (usesExt) {
- newEdit = new Uint32[layerSize];
- memSet32(newEdit, Layer::LAYER_EXT_DEFAULT, layerSize);
- if (layerEdit[pos][1]) {
- matrixCopy(layerEdit[pos][1], newEdit, min(prevWidth, layerWidth) * 4, min(prevHeight, layerHeight), prevWidth * 4, layerWidth * 4);
- delete[] layerEdit[pos][1];
- }
- layerEdit[pos][1] = newEdit;
- newEdit = NULL;
- }
- else {
- delete[] layerEdit[pos][1];
- layerEdit[pos][1] = NULL;
- }
- if (usesFx) {
- newEdit = new Uint32[layerSize];
- memSet32(newEdit, Layer::LAYER_FX_DEFAULT, layerSize);
- if (layerEdit[pos][2]) {
- matrixCopy(layerEdit[pos][2], newEdit, min(prevWidth, layerWidth) * 4, min(prevHeight, layerHeight), prevWidth * 4, layerWidth * 4);
- delete[] layerEdit[pos][2];
- }
- layerEdit[pos][2] = newEdit;
- newEdit = NULL;
- }
- else {
- delete[] layerEdit[pos][2];
- layerEdit[pos][2] = NULL;
- }
- }
- else {
- // Allocate storage (no need to fill with empty- layer will load over it)
- delete[] layerEdit[pos][0];
- layerEdit[pos][0] = NULL;
- layerEdit[pos][0] = new Uint32[layerSize];
- delete[] layerEdit[pos][1];
- layerEdit[pos][1] = NULL;
- delete[] layerEdit[pos][2];
- layerEdit[pos][2] = NULL;
- if (usesExt) layerEdit[pos][1] = new Uint32[layerSize];
- if (usesFx) layerEdit[pos][2] = new Uint32[layerSize];
- }
- }
- else {
- // Layer is no longer "affected"
- layersAffect &= ~bit;
- affectedChange = 1;
- }
- }
-
- if (!(layersAffect & bit)) {
- // Free any previously allocated memory
- delete[] layerEdit[pos][0];
- delete[] layerEdit[pos][1];
- delete[] layerEdit[pos][2];
- layerEdit[pos][0] = NULL;
- layerEdit[pos][1] = NULL;
- layerEdit[pos][2] = NULL;
- }
- }
-
- // Update layers list if we modified layersAffect
- if ((affectedChange) && (layerlist)) {
- if (layerlist->layerList) {
- layerlist->layerList->setBitMask(layersAffect, layersView, layersDim);
- }
- }
- // Resize to match current layer
- setDirty(1);
- resize(tileWidth * layerWidth, tileHeight * layerHeight);
- if (myFrame) {
- myFrame->setScroll(tileWidth, tileHeight);
- if (resizeView) myFrame->requestViewSize(width, height);
- }
- }
- // @TODO: call when layer changes
- void SceneEditLayer::updateTitlebar() { start_func
- if ((myFrame) && (scene)) {
- myFrame->setTitle(formatString("%s : %s : Layer %s", world->getTitle().c_str(), scene->getName().c_str(), scene->getLayer(cursorLayer)->getName().c_str()));
- }
- }
- int SceneEditLayer::event(int hasFocus, const SDL_Event* event) { start_func
- int changed = 0;
- int clickX, clickY;
- ObjChange* obj;
- switch (event->type) {
- case SDL_CLOSE:
- // Merge any existing selection
- try {
- mergeSelection();
- }
- catch (UndoException& e) {
- }
- return 1;
-
- case SDL_SPECIAL:
- // Refresh selection rectangles?
- if ((event->user.code == SDL_IDLEPHASE) && (partialFocus)) {
- Rect rect = { selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs, selectionRect.w, selectionRect.h };
- setDirtyRect(rect);
- setDirtySelectedSpawns();
- if (toolActive == TOOLS_SELECTITEM)
- setDirtyPixelBox(toolStartX, toolStartY, toolLastX, toolLastY);
- }
- // Refresh cursor?
- if (((event->user.code == SDL_IDLECURSOR) || (event->user.code == SDL_IDLEPHASE)) && (haveFocus)) {
- Rect rect = { cursorX, cursorY, cursorW, cursorH };
- setDirtyRect(rect);
- }
- return 1;
- case SDL_COMMAND:
- switch (event->user.code) {
- case EDIT_UNDO:
- // finish instead of cancel- this causes undo to undo current
- // tool if one is being used
- finishTool();
- // (let world handle from here)
- break;
-
- case EDIT_REDO:
- cancelTool();
- // (let world handle from here)
- break;
- case EDIT_COPY:
- if (useSpawnSelection()) copySpawnSelection();
- else copySelection();
- return 1;
-
- case EDIT_CUT:
- try {
- world->undo.preUndoBlock();
- if (useSpawnSelection()) {
- copySpawnSelection();
- deleteSpawnSelection();
- clearSpawnSelection();
- }
- else {
- copySelection();
- deleteSelection();
- clearSelection();
- }
- world->undo.postUndoBlock();
- }
- catch (UndoException& e) {
- }
- return 1;
-
- case EDIT_DELETE:
- try {
- world->undo.preUndoBlock();
- deleteSpawnSelection();
- deleteSelection();
- world->undo.postUndoBlock();
- }
- catch (UndoException& e) {
- }
- return 1;
-
- case EDIT_SELECTALL:
- try {
- if (spriteMode) {
- undoStoreSpawnSelect();
- selectSpawnRect(0, 0, 0, 0, 1, 1);
- recheckSpawnSelection();
- setDirtySelectedSpawns();
-
- // Ensure selection tool active
- if ((!toolActive) && (toolL != TOOLS_SELECTITEM)) {
- desktop->broadcastEvent(SDL_COMMAND, TOOLS_SELECTITEM);
- desktop->broadcastEvent(SDL_COMMAND, CMD_RELEASE);
- }
- }
- else {
- world->undo.preUndoBlock();
- // Merge any floating
- mergeSelection();
- // Store undo for entire selection
- undoStoreSelect(0, 0, layerWidth, layerHeight);
- world->undo.postUndoBlock();
-
- // Select all
- memset(selected, 255, selectedPitch * layerHeight);
- selectionRect.x = 0;
- selectionRect.y = 0;
- selectionRect.w = layerWidth;
- selectionRect.h = layerHeight;
- setDirty(1);
- }
- updateCopyTool();
- }
- catch (UndoException& e) {
- }
- return 1;
-
- case EDIT_DESELECTALL:
- cancelTool();
- try {
- doneSelection();
- clearSpawnSelection();
- }
- catch (UndoException& e) {
- }
- return 1;
-
- case EDIT_PASTE:
- try {
- changed = pasteSelection();
- }
- catch (UndoException& e) {
- }
-
- // Make sure a selection tool is current
- if (changed == TOOLS_SELECT) {
- if ((!toolActive) && (toolL != TOOLS_SELECT) && (toolL != TOOLS_SELECTELLIPSE) && (toolL != TOOLS_WAND)) {
- desktop->broadcastEvent(SDL_COMMAND, TOOLS_SELECT);
- desktop->broadcastEvent(SDL_COMMAND, CMD_RELEASE);
- }
- }
- else if (changed == TOOLS_SELECTITEM) {
- if ((!toolActive) && (toolL != TOOLS_SELECTITEM)) {
- desktop->broadcastEvent(SDL_COMMAND, TOOLS_SELECTITEM);
- desktop->broadcastEvent(SDL_COMMAND, CMD_RELEASE);
- }
- }
-
- return 1;
-
- case CMD_RELEASE:
- finishTool(); // Clears startToolOnMove too; safe even if no tool
- moveCursor(cursorSpriteX, cursorSpriteY);
- return 1;
-
- case NEW_LAYER:
- try {
- scene->newLayer(myFrame);
- }
- catch (FileException& e) {
- guiErrorBox(string(e.details), errorTitleFile);
- }
- return 1;
-
- case TOOLS_NEXTIMAGE:
- imagebar->nextImage();
- return 1;
-
- case TOOLS_PREVIMAGE:
- imagebar->prevImage();
- return 1;
- case TOOLS_NEXTCOLOR:
- colorbar->colorSelection(ColorSelect::SELECTED_FG,
- colorbar->colorSelection(ColorSelect::SELECTED_FG) + 1);
- return 1;
- case TOOLS_PREVCOLOR:
- colorbar->colorSelection(ColorSelect::SELECTED_FG,
- colorbar->colorSelection(ColorSelect::SELECTED_FG) - 1);
- return 1;
- case TOOLS_EDITCOLOR:
- colorbar->editColor(colorbar->colorSelection(ColorSelect::SELECTED_FG));
- return 1;
- }
-
- if (world->commandEvent(event->user.code)) return 1;
- break;
- case SDL_OBJECTCHANGE:
- if (!scene) return 0;
- obj = (ObjChange*)event->user.data1;
- if (event->user.code & OBJ_SPAWN) {
- // One of our layers?
- SpawnEdit* spawn = (SpawnEdit*)obj->obj;
- Layer* spawnLayer = spawn->getLayer();
- if (!spawnLayer) break;
-
- // Find out if it matches one of our layers (and if we're editing that layer)
- Uint32 bit = 1;
- int layerNum = -1;
- int affected = 0;
- for (int pos = 0; pos < numLayers; ++pos, bit <<= 1) {
- Layer* layer = scene->getLayer(pos);
- if (spawnLayer == layer) {
- layerNum = pos;
- affected = layersAffect & bit;
- break;
- }
- }
-
- // Not one of our layers
- if (layerNum < 0) break;
- setDirty(1);
- // Any change could affect our selection boundaries
- if ((affected) && (selectedSpawns.count(spawn->getId()))) {
- if (event->user.code & OBJMOD_DELETE)
- selectedSpawns.erase(spawn->getId());
- recheckSpawnSelection();
- }
- }
- if (event->user.code & OBJ_LAYER) {
- // Find out if it matches one of our layers (and if we're editing that layer)
- Uint32 bit = 1;
- int layerNum = -1;
- int affected = 0;
- for (int pos = 0; pos < numLayers; ++pos, bit <<= 1) {
- Layer* layer = scene->getLayer(pos);
- if (obj->obj == layer) {
- layerNum = pos;
- affected = layersAffect & bit;
- break;
- }
- }
-
- // Not one of our layers
- if (layerNum < 0) break;
-
- if (event->user.code & OBJMOD_TILES) {
- if (affected) {
- if (selectionMode == SELECTION_OUTLINE) {
- Rect affect = { 0, 0, layerWidth, layerHeight };
- scene->getLayerEdit(layerNum)->loadLayer(layerEdit[layerNum][0], layerEdit[layerNum][1], layerEdit[layerNum][2], layerWidth, affect);
- }
- }
- setDirty(1);
- }
- if (event->user.code & OBJMOD_NAME) {
- layerlist->layerList->modifyItem(layerNum, &((Layer*)(obj->obj))->getName());
- }
- 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)) {
- if (affected) {
- // @TODO: undo won't properly undo the loss of size on the selection
- // we need to have a layer that resizes scan all windows and
- // resize all appropriate selections as part of it's undo block
- reloadLayerStats();
- if (selectionMode == SELECTION_OUTLINE) refreshData(0);
- }
- else {
- setDirty(1);
- }
- }
- if (event->user.code & OBJMOD_TYPE) {
- // Layer becomes available if not already; nothing else affected except type icon
- int type = ((Layer*)(obj->obj))->getType();
- Uint32 newLayersAvailable = layersAvailable;
- Uint32 newLayersAffect = layersAffect;
- if (type == Layer::LAYER_TILE) newLayersAvailable |= bit;
- else {
- newLayersAvailable &= ~bit;
- newLayersAffect &= ~bit;
- }
- // No layers to affect anymore? Close
- if (!newLayersAvailable) {
- scene->markUnlock();
- scene = NULL;
- closeWindow();
- return 1;
- }
- // No affected layers? pick first one
- if (!newLayersAffect) {
- newLayersAffect = 1;
- while (!(newLayersAvailable & newLayersAffect)) {
- newLayersAffect <<= 1;
- }
- }
- // Update layers list
- int disable = !(newLayersAvailable & bit);
- layerlist->layerList->modifyItem(layerNum, NULL, &disable, NULL, &type);
- // (this fixes cursor layer if it needs to be)
- layersAvailable = newLayersAvailable;
- refreshLayers(newLayersAffect, layersView, layersDim);
- }
- }
- if (event->user.code & OBJ_TILESET) {
- LayerEdit* layer = scene->getLayerEdit(cursorLayer);
- TileSetEdit* tileset = layer->getTileSetEdit();
- if (obj->obj == (TileSet*)tileset) {
- // @TODO: OBJMOD_COUNTCOLL-
- // stuff will need reloading once we can edit collisions
- if ((event->user.code & OBJMOD_WIDTH) || (event->user.code & OBJMOD_HEIGHT) || (event->user.code & OBJMOD_COUNT) || (event->user.code & OBJMOD_TILE)) {
- // Width/height require actual layer stat change
- if ((event->user.code & OBJMOD_WIDTH) || (event->user.code & OBJMOD_HEIGHT)) {
- reloadLayerStats();
- if (selectionMode == SELECTION_OUTLINE) refreshData(0);
- }
-
- // All require visual refresh and imagebar adjustment
- setDirty(1);
- // Layer should have already locked tileset- exception should never happen
- try {
- if (imagebar) imagebar->changeSet(tileset);
- }
- catch (FileException& e) {
- fatalCrash(0, "Error reading tileset- %s", e.details);
- }
- }
- }
- }
- if ((event->user.code & OBJ_SCENE) && (obj->obj == scene)) {
- if (event->user.code & OBJMOD_LAYERDEL) {
- // Update our data
- --numLayers;
-
- // Determine which bits "shift down" to fill hole
- Uint32 bitsToShift = 0;
- for (Uint32 bit = 2 << obj->info1; bit; bit <<= 1) {
- bitsToShift |= bit;
- }
- Uint32 bitsToLeave = (bitsToShift ^ 0xFFFFFFFF) ^ (1 << obj->info1);
-
- layersView = (layersView & bitsToLeave) | ((layersView & bitsToShift) >> 1);
- layersDim = (layersDim & bitsToLeave) | ((layersDim & bitsToShift) >> 1);
- layersAffect = (layersAffect & bitsToLeave) | ((layersAffect & bitsToShift) >> 1);
- layersAvailable = (layersAvailable & bitsToLeave) | ((layersAvailable & bitsToShift) >> 1);
-
- // Shift data down
- delete[] layerEdit[obj->info1][0];
- delete[] layerEdit[obj->info1][1];
- delete[] layerEdit[obj->info1][2];
- for (int pos = obj->info1 + 1; pos < MAX_LAYERS; ++pos) {
- layerEdit[pos - 1][0] = layerEdit[pos][0];
- layerEdit[pos - 1][1] = layerEdit[pos][1];
- layerEdit[pos - 1][2] = layerEdit[pos][2];
- }
- layerEdit[MAX_LAYERS - 1][0] = NULL;
- layerEdit[MAX_LAYERS - 1][1] = NULL;
- layerEdit[MAX_LAYERS - 1][2] = NULL;
-
- // Cursor layer- shift down? if cursorlayer was deleted, "no" cursor layer
- if (cursorLayer == obj->info1) cursorLayer = -1;
- else if (cursorLayer > obj->info1) --cursorLayer;
- // No layers to affect anymore? Close
- if (!layersAvailable) {
- scene->markUnlock();
- scene = NULL;
- closeWindow();
- return 1;
- }
-
- // Remove from layer list (this might call widget/childmodified
- // leading to refreshlayers)
- layerlist->layerList->removeItem(obj->info1);
- // Determine new stats (this may attempt a merge selection,
- // which should be safe even if no cursorlayer/affectedlayer)
- refreshLayers();
-
- // Update screen
- setDirty(1);
- }
- if (event->user.code & OBJMOD_LAYERADD) {
- // We need to double check that this layer isn't already added
- // (can happen when first creating a scene)
- if (scene->getLayerCount() > numLayers) {
- // Determine which bits "shift up" to open hole
- Uint32 bitsToShift = 0;
- for (Uint32 bit = 1 << obj->info1; bit; bit <<= 1) {
- bitsToShift |= bit;
- }
- Uint32 bitsToLeave = bitsToShift ^ 0xFFFFFFFF;
-
- layersView = (layersView & bitsToLeave) | ((layersView & bitsToShift) << 1);
- layersDim = (layersDim & bitsToLeave) | ((layersDim & bitsToShift) << 1);
- layersAffect = (layersAffect & bitsToLeave) | ((layersAffect & bitsToShift) << 1);
- layersAvailable = (layersAvailable & bitsToLeave) | ((layersAvailable & bitsToShift) << 1);
-
- // Shift data up
- for (int pos = MAX_LAYERS - 1; pos > obj->info1; --pos) {
- layerEdit[pos][0] = layerEdit[pos - 1][0];
- layerEdit[pos][1] = layerEdit[pos - 1][1];
- layerEdit[pos][2] = layerEdit[pos - 1][2];
- }
- layerEdit[obj->info1][0] = NULL;
- layerEdit[obj->info1][1] = NULL;
- layerEdit[obj->info1][2] = NULL;
-
- // Cursor layer- shift up?
- if (cursorLayer >= obj->info1) ++cursorLayer;
- // Add layer, but not as editable until user selects
- Uint32 bit = 1 << obj->info1;
- layersView |= bit;
- Layer* layer = scene->getLayer(obj->info1);
- if (layer->getType() == Layer::LAYER_TILE) layersAvailable |= bit;
-
- layerlist->layerList->addItem(obj->info1,
- ListEntry(layer->getName(), obj->info1,
- (layersView & bit) ? WLayerListBox::FLAG_VISIBLE : 0,
- layer->getType(), 0,
- !(layersAvailable & bit)));
- ++numLayers;
- setDirty(1);
- }
- }
- if (event->user.code & OBJMOD_LAYERMOVE) {
- // If we swap all data to match, a move ultimately only affects
- // the visual appearance (layers above/below each other)
- Uint32 bit1 = 1 << obj->info1;
- Uint32 bit2 = 1 << obj->info2;
- Uint32 bits = bit1 | bit2;
- // Swap appropriate bits, if only one of the two is set
- if (((layersView & bits) == bit1) || ((layersView & bits) == bit2)) layersView ^= bits;
- if (((layersDim & bits) == bit1) || ((layersDim & bits) == bit2)) layersDim ^= bits;
- if (((layersAffect & bits) == bit1) || ((layersAffect & bits) == bit2)) layersAffect ^= bits;
- if (((layersAvailable & bits) == bit1) || ((layersAvailable & bits) == bit2)) layersAvailable ^= bits;
- // Swap cursor
- if (cursorLayer == obj->info1) cursorLayer = obj->info2;
- else if (cursorLayer == obj->info2) cursorLayer = obj->info1;
- // Swap layer data
- swap(layerEdit[obj->info1][0], layerEdit[obj->info2][0]);
- swap(layerEdit[obj->info1][1], layerEdit[obj->info2][1]);
- swap(layerEdit[obj->info1][2], layerEdit[obj->info2][2]);
- // Swap in layer list
- layerlist->layerList->swapItems(obj->info1, obj->info2);
- // Update screen
- setDirty(1);
- }
- }
- if ((event->user.code & OBJ_WORLD) && (obj->obj == world)) {
- if (event->user.code & OBJMOD_DELETE) {
- imagebar->changeSet(NULL, 1);
- scene = NULL;
- closeWindow();
- }
- if (event->user.code & OBJMOD_NAME) {
- updateTitlebar();
- }
- }
- return 1;
-
- case SDL_MOUSEBUTTONDOWN:
- case SDL_MOUSEBUTTONDBL:
- if ((event->button.button == SDL_BUTTON_LEFT) || (event->button.button == SDL_BUTTON_RIGHT)) {
- spriteAtCursor = 0;
- // Signed as it could go off the edge
- clickX = (Sint16)event->button.x;
- clickY = (Sint16)event->button.y;
- // If unmodified selection-tool click and within selection, this is a selection drag
- if ((!toolActive) &&
- !(SDL_GetModState() & (KMOD_CTRL | KMOD_ALT)) && (
- (((toolL == TOOLS_SELECT) || (toolL == TOOLS_SELECTELLIPSE) || (toolL == TOOLS_WAND)) &&
- (event->button.button == SDL_BUTTON_LEFT)) ||
- (((toolR == TOOLS_SELECT) || (toolR == TOOLS_SELECTELLIPSE) || (toolR == TOOLS_WAND)) &&
- (event->button.button == SDL_BUTTON_RIGHT))
- ) && (isInSelection(clickX / tileWidth, clickY / tileHeight))) {
- startToolOnMove = 0;
- moveCursor(clickX, clickY);
- startToolSelectionDrag();
- }
- else if ((!toolActive) &&
- !(SDL_GetModState() & (KMOD_CTRL | KMOD_ALT)) && (
- ((toolL == TOOLS_SELECTITEM) &&
- (event->button.button == SDL_BUTTON_LEFT)) ||
- ((toolR == TOOLS_SELECTITEM) &&
- (event->button.button == SDL_BUTTON_RIGHT))
- ) && (isInSpawnSelection(clickX, clickY))) {
- startToolOnMove = 0;
- moveCursor(clickX, clickY);
- startToolSpawnSelectionDrag();
- }
- else {
- moveCursor(clickX, clickY);
- startTool(event->button.button);
- }
- updateSpriteShown();
- return 1;
- }
- break;
-
- case SDL_MOUSEBUTTONUP:
- finishTool();
-
- // Force cursor back into area, no more virtual
- moveCursor(cursorSpriteX, cursorSpriteY);
- return 1;
-
- case SDL_MOUSEMOTION:
- spriteAtCursor = 0;
- pixelMouseX = (Sint16)event->motion.x;
- pixelMouseY = (Sint16)event->motion.y;
- if ((event->motion.state & SDL_BUTTON_LMASK) || (event->motion.state & SDL_BUTTON_RMASK)) {
- // Signed as it could go off the edge
- moveCursor((Sint16)event->motion.x, (Sint16)event->motion.y);
- }
- else {
- // Update mouse pointer
- mousePointer((Sint16)event->motion.x, (Sint16)event->motion.y);
- }
- updateSpriteShown();
- return 1;
- case SDL_MOUSEFOCUS:
- if (event->user.code & 1) {
- hover = 1;
- mousePointer();
- }
- else {
- hover = 0;
- selectMouse(MOUSE_NORMAL);
- }
- updateSpriteShown();
- return 1;
-
- case SDL_INPUTFOCUS:
- if (event->user.code & 1) {
- if (!haveFocus) {
- haveFocus = partialFocus = 1;
- changed = 1;
- }
- }
- else if (event->user.code & 2) {
- if (!partialFocus) {
- partialFocus = 1;
- changed = 1;
- }
- }
- else {
- if (partialFocus) {
- partialFocus = 0;
- changed = 1;
- }
- }
- if (!(event->user.code & 1)) {
- if (haveFocus) {
- cancelTool();
- haveFocus = 0;
- changed = 1;
- }
- }
-
- if (changed) {
- // Refresh selection rectangle and cursor
- Rect rect = { selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs, selectionRect.w, selectionRect.h };
- Rect rect2 = { cursorX, cursorY, cursorW, cursorH };
- setDirtyRect(rect);
- setDirtyRect(rect2);
- setDirtySelectedSpawns();
- updateSpriteShown();
- }
- return 1;
- case SDL_KEYUP:
- switch (event->key.keysym.sym) {
- case SDLK_LSHIFT:
- case SDLK_RSHIFT:
- case SDLK_SPACE:
- finishTool();
- // Force cursor back into area, no more virtual
- moveCursor(cursorSpriteX, cursorSpriteY);
- return 1;
-
- case SDLK_LALT:
- case SDLK_RALT:
- case SDLK_LCTRL:
- case SDLK_RCTRL:
- modifyTool();
- return 1;
-
- default:
- break;
- }
- break;
- case SDL_KEYDOWN:
- // We can't stick modifiers in due to the numerous combinations that
- // could occur of ctrl/shift/alt in use of various tools
- switch (event->key.keysym.sym) {
- case SDLK_KP_ENTER:
- case SDLK_RETURN:
- // Merge any existing selection
- try {
- mergeSelection();
- }
- catch (UndoException& e) {
- }
- return 1;
- case SDLK_LALT:
- case SDLK_RALT:
- case SDLK_LCTRL:
- case SDLK_RCTRL:
- modifyTool();
- return 1;
- case SDLK_SPACE:
- // (ensure on a tile boundary)
- moveCursor(virtualCursorX * tileWidth, virtualCursorY * tileHeight);
- startTool(SDL_BUTTON_LEFT);
- changed = 1;
- break;
- case SDLK_LSHIFT:
- // (ensure on a tile boundary)
- moveCursor(virtualCursorX * tileWidth, virtualCursorY * tileHeight);
- startToolOnMove = 1;
- return 1;
-
- // @TODO: This should probably end up as a configurable shortcut somehow; should SHIFTs/SPACE too?
- case SDLK_RSHIFT:
- // (ensure on a tile boundary)
- moveCursor(virtualCursorX * tileWidth, virtualCursorY * tileHeight);
- startTool(SDL_BUTTON_RIGHT);
- changed = 1;
- break;
-
- case SDLK_RIGHT:
- // @TODO: cursor drag of sprite (or regular?) selection
- if (selectionMode != SELECTION_OUTLINE) {
- if (event->key.keysym.mod & KMOD_CTRL) moveSelection(layerWidth - selectionRect.w - selectionRect.x, selectionYOffs);
- else moveSelection(selectionXOffs + 1, selectionYOffs);
- }
- else {
- if (event->key.keysym.mod & KMOD_CTRL) scanCursor(1, 0);
- else moveCursor(virtualCursorX * tileWidth + tileWidth, virtualCursorY * tileHeight);
- }
- changed = 1;
- break;
-
- case SDLK_END:
- if (selectionMode != SELECTION_OUTLINE) {
- if (event->key.keysym.mod & KMOD_CTRL) moveSelection(layerWidth - selectionRect.w - selectionRect.x, layerHeight - selectionRect.h - selectionRect.y);
- else moveSelection(layerWidth - selectionRect.w - selectionRect.x, selectionYOffs);
- }
- else {
- if (event->key.keysym.mod & KMOD_CTRL) moveCursor((layerWidth - cursorW) * tileWidth, (layerHeight - cursorH) * tileHeight);
- else moveCursor((layerWidth - cursorW) * tileWidth, virtualCursorY * tileHeight);
- }
- changed = 1;
- break;
-
- case SDLK_LEFT:
- if (selectionMode != SELECTION_OUTLINE) {
- if (event->key.keysym.mod & KMOD_CTRL) moveSelection(-selectionRect.x, selectionYOffs);
- else moveSelection(selectionXOffs - 1, selectionYOffs);
- }
- else {
- if (event->key.keysym.mod & KMOD_CTRL) scanCursor(-1, 0);
- else moveCursor(virtualCursorX * tileWidth - tileWidth, virtualCursorY * tileHeight);
- }
- changed = 1;
- break;
- case SDLK_HOME:
- if (selectionMode != SELECTION_OUTLINE) {
- if (event->key.keysym.mod & KMOD_CTRL) moveSelection(-selectionRect.x, -selectionRect.y);
- else moveSelection(-selectionRect.x, selectionYOffs);
- }
- else {
- if (event->key.keysym.mod & KMOD_CTRL) moveCursor(0, 0);
- else moveCursor(0, virtualCursorY * tileHeight);
- }
- changed = 1;
- break;
-
- case SDLK_DOWN:
- if (selectionMode != SELECTION_OUTLINE) {
- if (event->key.keysym.mod & KMOD_CTRL) moveSelection(selectionXOffs, layerHeight - selectionRect.h - selectionRect.y);
- else moveSelection(selectionXOffs, selectionYOffs + 1);
- }
- else {
- if (event->key.keysym.mod & KMOD_CTRL) scanCursor(0, 1);
- else moveCursor(virtualCursorX * tileWidth, virtualCursorY * tileHeight + tileHeight);
- }
- changed = 1;
- break;
- case SDLK_UP:
- if (selectionMode != SELECTION_OUTLINE) {
- if (event->key.keysym.mod & KMOD_CTRL) moveSelection(selectionXOffs, -selectionRect.y);
- else moveSelection(selectionXOffs, selectionYOffs - 1);
- }
- else {
- if (event->key.keysym.mod & KMOD_CTRL) scanCursor(0, -1);
- else moveCursor(virtualCursorX * tileWidth, virtualCursorY * tileHeight - tileHeight);
- }
- changed = 1;
- break;
- case SDLK_PAGEDOWN:
- if (selectionMode != SELECTION_OUTLINE) {
- moveSelection(selectionXOffs, selectionYOffs + (viewHeight / tileHeight - 1));
- }
- else {
- moveCursor(virtualCursorX * tileWidth, (virtualCursorY + (viewHeight / tileHeight - 1)) * tileHeight);
- }
- changed = 1;
- break;
- case SDLK_PAGEUP:
- if (selectionMode != SELECTION_OUTLINE) {
- moveSelection(selectionXOffs, selectionYOffs - (viewHeight / tileHeight - 1));
- }
- else {
- moveCursor(virtualCursorX * tileWidth, (virtualCursorY - (viewHeight / tileHeight - 1)) * tileHeight);
- }
- changed = 1;
- break;
-
- default:
- break;
- }
- if (changed) {
- spriteAtCursor = 1;
- updateSpriteShown();
- return 1;
- }
- break;
- }
- return 0;
- }
- void SceneEditLayer::scanCursor(int xDir, int yDir) { start_func
- assert(xDir || yDir);
- assert((xDir == -1) || (xDir == 0) || (xDir == 1));
- assert((yDir == -1) || (yDir == 0) || (yDir == 1));
-
- int x = virtualCursorX;
- int y = virtualCursorY;
- if (x < 0) x = 0;
- if (y < 0) y = 0;
- if (x >= layerWidth) x = layerWidth - 1;
- if (y >= layerHeight) y = layerHeight - 1;
- int offset = x + y * layerWidth;
- int type;
- int first = 1;
- do {
- x += xDir;
- y += yDir;
- if (x < 0) break;
- if (x >= layerWidth) break;
- if (y < 0) break;
- if (y >= layerHeight) break;
- offset += xDir + yDir * layerWidth;
- if (first) {
- first = 0;
- type = layerEdit[cursorLayer][0][offset] & Layer::LAYER_TILE_INDEX;
- }
- else if (layerEdit[cursorLayer][0][offset] & Layer::LAYER_TILE_INDEX) {
- if (!type) break;
- }
- else {
- if (type) {
- x -= xDir;
- y -= yDir;
- break;
- }
- }
- } while (1);
-
- moveCursor(x * tileWidth, y * tileHeight);
- }
- int SceneEditLayer::useSpawnSelection() const { start_func
- if (selectedSpawns.empty()) return 0;
- if (selectionRect.w) return spriteMode;
- return 1;
- }
- void SceneEditLayer::moveSelection(int newX, int newY) { start_func
- // No dragging of outlines allowed
- if (selectionMode == SELECTION_OUTLINE) return;
-
- if ((newX != selectionXOffs) || (newY != selectionYOffs)) {
- // Dirty old
- Rect rect = { selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs, selectionRect.w, selectionRect.h };
- setDirtyRect(rect, 1);
-
- // Move (no limits to where it can move to)
- selectionXOffs = newX;
- selectionYOffs = newY;
-
- // Dirty new
- rect.x = selectionRect.x + newX;
- rect.y = selectionRect.y + newY;
- setDirtyRect(rect, 1);
- }
- }
-
- void SceneEditLayer::moveCursor(int newX, int newY) { start_func
- int doTool = 0;
- int newTileX = newX / tileWidth;
- int newTileY = newY / tileHeight;
-
- if (startToolOnMove) startTool(SDL_BUTTON_LEFT);
- // This alone doesn't make anything dirty; normally, this isn't used;
- // anything that does use it, dirties; we don't track virtual cursor
- // if no active tool
- if (toolActive) {
- if ((newTileX != virtualCursorX) || (virtualCursorY != newTileY)) {
- virtualCursorX = newTileX;
- virtualCursorY = newTileY;
-
- // Tool
- if (!spriteMode) doTool = 1;
- }
- }
- if (newTileX + cursorW < 1) newTileX = 1 - cursorW;
- if (newTileY + cursorH < 1) newTileY = 1 - cursorH;
- if (newTileX >= layerWidth) newTileX = layerWidth - 1;
- if (newTileY >= layerHeight) newTileY = layerHeight - 1;
-
- if ((newTileX != cursorX) || (newTileY != cursorY)) {
- Rect rect = { cursorX, cursorY, cursorW, cursorH };
- setDirtyRect(rect);
- cursorX = newTileX;
- cursorY = newTileY;
- // Scroll?
- if (!spriteMode)
- if (myFrame) myFrame->scrollToView(cursorX * tileWidth, cursorY * tileHeight,
- cursorW * tileWidth, cursorH * tileHeight);
- // Dirty
- Rect rect2 = { cursorX, cursorY, cursorW, cursorH };
- setDirtyRect(rect2);
- }
- if ((newX != cursorSpriteX) || (newY != cursorSpriteY)) {
- cursorSpriteX = newX;
- cursorSpriteY = newY;
- // Scroll?
- // @TODO: account for sprite size
- if ((spriteMode) && (myFrame)) myFrame->scrollToView(cursorSpriteX, cursorSpriteY, 1, 1);
- if ((spriteMode) && (toolActive)) doTool = 1;
- }
- if (doTool) dragTool();
- // No active tool, we track virtual cursor, but to CLIPPED coordinates
- else if (!toolActive) {
- virtualCursorX = newTileX;
- virtualCursorY = newTileY;
- }
- }
- void SceneEditLayer::startToolSelectionDrag() { start_func
- startToolOnMove = 0;
- if (toolActive) return;
- toolActive = TOOLS_SELECTDRAG;
- toolStartX = virtualCursorX;
- toolStartY = virtualCursorY;
- toolCtrl = SDL_GetModState() & KMOD_CTRL;
- toolAlt = SDL_GetModState() & KMOD_ALT;
- mousePointer();
- dragTool(1);
- }
- void SceneEditLayer::startTool(int button) { start_func
- startToolOnMove = 0;
- if (toolActive) return;
- // Merge any existing selection
- try {
- mergeSelection();
- }
- catch (UndoException& e) {
- return;
- }
- toolMinX = virtualCursorX;
- toolMinY = virtualCursorY;
- toolMaxX = virtualCursorX;
- toolMaxY = virtualCursorY;
-
- toolActive = button == SDL_BUTTON_LEFT ? toolL : toolR;
- if (spriteMode) {
- toolStartX = cursorSpriteX;
- toolStartY = cursorSpriteY;
- }
- else {
- toolStartX = virtualCursorX;
- toolStartY = virtualCursorY;
- }
- toolCtrl = SDL_GetModState() & KMOD_CTRL;
- toolAlt = SDL_GetModState() & KMOD_ALT;
- toolContiguous = contiguous;
-
- imagebar->getDataExt(toolData, toolExt, toolFx);
- // @TODO: not determined: ambient, tweak, collision data, animation
- // @TODO: advanced mode where user determines what to place
- toolDataMask = Layer::LAYER_TILE_COLLISION;
- toolExtMask = Layer::LAYER_EXT_COLL | Layer::LAYER_EXT_COLLTYPE | Layer::LAYER_EXT_UNUSED | Layer::LAYER_EXT_ANIMON | Layer::LAYER_EXT_ANIMREV;
- toolFxMask = Layer::LAYER_FX_UNDEFINED;
-
- mousePointer();
- dragTool(1);
- }
- void SceneEditLayer::modifyTool() { start_func
- if (toolActive) {
- toolCtrl = SDL_GetModState() & KMOD_CTRL;
- toolAlt = SDL_GetModState() & KMOD_ALT;
- // Selection tools need entire area dirtied because this may cause
- // a deleted selection to reappear
- if ((toolActive == TOOLS_SELECT) || (toolActive == TOOLS_SELECTELLIPSE) || (toolActive == TOOLS_WAND)) {
- setDirty(1);
- }
- dragTool();
- }
- // Always update mouse pointer even if no active tool
- mousePointer();
- }
- void SceneEditLayer::dragTool(int firstTime, int lastTime) { start_func
- if (toolActive) {
- int rX, rY;
- int slope1, slope2;
- Rect rect;
- Rect layerBound = { 0, 0, layerWidth, layerHeight };
- int nonDraw = 0;
- if ((toolActive == TOOLS_SELECT) || (toolActive == TOOLS_SELECTELLIPSE) ||
- (toolActive == TOOLS_DROPPER) || (toolActive == TOOLS_WAND) ||
- (toolActive == TOOLS_SELECTDRAG) || (toolActive == TOOLS_SELECTITEMDRAG) ||
- (toolActive == TOOLS_PLACEITEM) || (toolActive == TOOLS_PLACESERIES) ||
- (toolActive == TOOLS_SELECTITEM)) {
- nonDraw = 1;
- }
- // So that undo warning boxes don't cancel us!
- int tool = toolActive;
- if (lastTime) toolActive = 0;
-
- try {
- switch (tool) {
- case TOOLS_SELECTITEMDRAG:
- setDirtySelectedSpawns();
- if (lastTime) {
- // For undo
- moveSpawnSelection(toolStartX - toolLastX, toolStartY - toolLastY);
- world->undo.preUndoBlock();
- moveSpawnSelection(cursorSpriteX - toolStartX, cursorSpriteY - toolStartY, 0);
- world->undo.postUndoBlock();
-
- }
- else if (!firstTime) {
- moveSpawnSelection(cursorSpriteX - toolLastX, cursorSpriteY - toolLastY);
- }
- setDirtySelectedSpawns();
- break;
-
- case TOOLS_SELECTITEM:
- // Mark old range/rect dirty
- setDirtyPixelBox(toolStartX, toolStartY, toolLastX, toolLastY);
- setDirtySelectedSpawns();
-
- // Keep a backup copy of old selection
- if (firstTime) {
- backupSelectedSpawns = selectedSpawns;
- backupSelectedSpawnRect = selectedSpawnRect;
- }
- // Refresh from backup if dragging with ctrl/alt or last time (for undo)
- else if ((toolCtrl) || (toolAlt) || (lastTime)) {
- selectedSpawns = backupSelectedSpawns;
- selectedSpawnRect = backupSelectedSpawnRect;
- }
-
- // Undo?
- if (lastTime) {
- if ((!toolCtrl) && (!toolAlt)) {
- // Clear it AND store undo
- clearSpawnSelection();
- }
- else {
- // Just store undo
- undoStoreSpawnSelect();
- }
- }
- // Clear selection if no ctrl/alt
- else if ((!toolCtrl) && (!toolAlt)) clearSpawnSelection(0);
-
- // Select
- selectSpawnRect(toolStartX, toolStartY, cursorSpriteX, cursorSpriteY, toolAlt ? 0 : 1);
- recheckSpawnSelection();
-
- // If first time, no modifiers, and something was selected- switch to drag now
- if ((firstTime) && (!toolCtrl) && (!toolAlt) && (selectedSpawnRect.w)) {
- // Handles undo by running through right now as lasttime
- finishTool();
- startToolSpawnSelectionDrag();
- return;
- }
-
- // Mark new range dirty
- setDirtyPixelBox(toolStartX, toolStartY, cursorSpriteX, cursorSpriteY);
- setDirtySelectedSpawns();
-
- // Allow copy now?
- if (lastTime) updateCopyTool();
- break;
-
- case TOOLS_PLACEITEM:
- case TOOLS_PLACESERIES:
- if (lastTime) {
- // Position it
- spawnPlace->setPos(cursorSpriteX, cursorSpriteY, 1);
-
- // Add sprite
- // @TODO: Catch undo (and delete newspawn if needed)
- // @TODO: load from currently selected sprite/object/dialog
-
- // Create
- LayerEdit* layer = scene->getLayerEdit(cursorLayer);
- SpawnEdit* newSpawn = new SpawnEdit(spawnPlace, layer, world->unusedSpawnId());
- newSpawn->markLock();
-
- // If properties done, shortcut dialog for now
- if ((spawnPropertiesDone) || (newSpawn->propertiesDialog())) {
- // Place on layer- this is the undo point
- newSpawn->setUndoReady();
- layer->addSpawn(newSpawn, myFrame, this); // @TODO: can throw_File / Undo
- newSpawn->markUnlock(); // Layer has it locked now
-
- // Remember settings for next placement
- delete spawnPlace;
- spawnPlace = new SpawnEdit(newSpawn, NULL);
- spawnPlace->markLock();
- spawnPropertiesDone = 1;
- }
- else {
- delete newSpawn;
- }
-
- // @TODO: Dirty sprite area only
- setDirty(1);
-
- if ((tool == TOOLS_PLACEITEM) && (toolL == TOOLS_PLACEITEM)) {
- desktop->broadcastEvent(SDL_COMMAND, TOOLS_SELECTITEM);
- desktop->broadcastEvent(SDL_COMMAND, CMD_RELEASE);
- }
- }
- break;
-
- case TOOLS_SELECTDRAG:
- // @TODO: Can this use moveselection()?
- // Dirty current selection area
- setDirtyBox(selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs,
- selectionRect.x + selectionRect.w - 1 + selectionXOffs,
- selectionRect.y + selectionRect.h - 1 + selectionYOffs, 1);
-
- // Float selection?
- if (firstTime) {
- floatSelection();
- }
- else {
- // Move selection
- selectionXOffs += virtualCursorX - toolLastX;
- selectionYOffs += virtualCursorY - toolLastY;
-
- // Dirty new area also
- setDirtyBox(selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs,
- selectionRect.x + selectionRect.w - 1 + selectionXOffs,
- selectionRect.y + selectionRect.h - 1 + selectionYOffs, 1);
- }
- break;
-
- case TOOLS_WAND:
- case TOOLS_SELECT:
- case TOOLS_SELECTELLIPSE:
- // Keep a backup copy of old selection
- if (firstTime) {
- memcpy(backupSelected, selected, selectedPitch * layerHeight);
- backupSelectionRect = selectionRect;
- }
- // Refresh from backup if dragging with ctrl/alt
- else if ((toolCtrl) || (toolAlt)) {
- memcpy(selected, backupSelected, selectedPitch * layerHeight);
- selectionRect = backupSelectionRect;
- }
-
- if (tool == TOOLS_WAND) {
- // We get rectangle from previous time
- if (!firstTime) {
- rect.x = toolMinX;
- rect.y = toolMinY;
- rect.w = toolMaxX - toolMinX + 1;
- rect.h = toolMaxY - toolMinY + 1;
-
- // Mark previous rect dirty
- setDirtyRect(rect, 1);
- }
- else {
- rect.w = 0;
- }
- }
- else if (tool == TOOLS_SELECT) {
- rect = createRect(toolStartX, toolStartY, virtualCursorX, virtualCursorY);
- }
- else {
- rX = abs(toolStartX - virtualCursorX);
- rY = abs(toolStartY - virtualCursorY);
-
- // Special case
- if (rX < 1) rX = 1;
- if (rY < 1) rY = 1;
-
- rect = createRect(toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY);
- }
-
- // We can't have a selection rect that's bigger than the selection surface
- intersectRects(rect, layerBound);
-
- // Undo?
- if (lastTime) {
- // If we're clearing selection, we must do extra work here
- if ((!toolCtrl) && (!toolAlt)) {
- // Refresh from backup
- memcpy(selected, backupSelected, selectedPitch * layerHeight);
- selectionRect = backupSelectionRect;
- // Add into rectangle the area we're selecting
- boundRects(selectionRect, rect);
- // Clear it AND store undo
- clearSelection();
- }
- else {
- // Just undo the area we're adding/deleting from
- if (rect.w) undoStoreSelect(rect.x, rect.y, rect.w, rect.h);
- }
- }
- // Clear selection if no ctrl/alt
- else if ((!toolCtrl) && (!toolAlt)) clearSelection(0);
-
- // Draw
- if (tool == TOOLS_WAND) {
- // @TODO:
- // if (!toolContiguous) { start_func
- // rect = floodFillNonContiguous32(tile, selection, virtualCursorX, virtualCursorY, mapColor32(0, 0, 0, toolAlt ? 0 : 255), toolTolerance);
- // }
- // else {
- // // Use alpha workspace as temp area, use 255/255/255 as filler color
- // drawRect(0, 0, alphaWorkspace->w, alphaWorkspace->h, mapColor32(255, 255, 255, 255), alphaWorkspace);
- // rect = floodFill32(tile, alphaWorkspace, virtualCursorX, virtualCursorY, mapColor32(0, 0, 0, toolAlt ? 0 : 255), toolTolerance);
- // SDL_SetAlpha(alphaWorkspace, 0, 255);
- // SDL_SetColorKey(alphaWorkspace, SDL_SRCCOLORKEY, mapColor32(255, 255, 255, 255));
- // blit(0, 0, alphaWorkspace, 0, 0, selection, tileWidth, tileHeight);
- // SDL_SetColorKey(alphaWorkspace, 0, 0);
- // SDL_SetAlpha(alphaWorkspace, SDL_SRCALPHA, 255);
- // }
-
- // Remember min/max for undo next time
- if (rect.w) {
- toolMinX = rect.x;
- toolMinY = rect.y;
- toolMaxX = rect.x + rect.w - 1;
- toolMaxY = rect.y + rect.h - 1;
- }
- else {
- // Causes no undo area or undirty to occur next frame
- toolMinX = toolMaxX = -1;
- }
- }
- else if (tool == TOOLS_SELECT) {
- selectRect(toolStartX, toolStartY, virtualCursorX, virtualCursorY, toolAlt ? 0 : 1);
- }
- else {
- selectEllipse(toolStartX, toolStartY, rX, rY, toolAlt ? 0 : 1);
- }
- setDirtyRect(rect, 1);
-
- // Add to overall selection bounding box
- if (!toolAlt) boundRects(selectionRect, rect);
- // ...or fix selection rectangle if removing stuff
- else fixSelectionRect();
-
- // Previous
- if (!firstTime) {
- if (tool == TOOLS_WAND) {
- // (was dirtied above, at beginning)
- }
- else if (tool == TOOLS_SELECT) {
- setDirtyBox(toolStartX, toolStartY, toolLastX, toolLastY, 1);
- }
- else {
- rX = abs(toolStartX - toolLastX);
- rY = abs(toolStartY - toolLastY);
- if (rX < 1) rX = 1;
- if (rY < 1) rY = 1;
- setDirtyBox(toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY, 1);
- }
- }
-
- // Allow copy now?
- if (lastTime) updateCopyTool();
- break;
-
- case TOOLS_DROPPER:
- // @TODO:
- break;
-
- case TOOLS_PEN:
- if (!lastTime) {
- layerDrawLine(toolStartX, toolStartY, virtualCursorX, virtualCursorY, layerEdit[cursorLayer][0], toolDataMask, toolData);
- if (layerEdit[cursorLayer][1]) layerDrawLine(toolStartX, toolStartY, virtualCursorX, virtualCursorY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
- if (layerEdit[cursorLayer][2]) layerDrawLine(toolStartX, toolStartY, virtualCursorX, virtualCursorY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
- setDirtyBox(toolStartX, toolStartY, virtualCursorX, virtualCursorY);
- }
-
- // Track area covered for undo
- if (virtualCursorX < toolMinX) toolMinX = virtualCursorX;
- if (virtualCursorX > toolMaxX) toolMaxX = virtualCursorX;
- if (virtualCursorY < toolMinY) toolMinY = virtualCursorY;
- if (virtualCursorY > toolMaxY) toolMaxY = virtualCursorY;
- if (toolStartX < toolMinX) toolMinX = toolStartX;
- if (toolStartX > toolMaxX) toolMaxX = toolStartX;
- if (toolStartY < toolMinY) toolMinY = toolStartY;
- if (toolStartY > toolMaxY) toolMaxY = toolStartY;
-
- toolStartX = virtualCursorX;
- toolStartY = virtualCursorY;
-
- if (lastTime) undoStoreLayerBox(toolMinX, toolMinY, toolMaxX, toolMaxY);
- else if (tools) ; // @TODO: preview redraw
- break;
-
- case TOOLS_FILL:
- // @TODO: advanced option to specify mask of what to check fill against
-
- // Undo based on rectangle from last time
- if (lastTime) undoStoreLayerBox(toolMinX, toolMinY, toolMaxX, toolMaxY);
-
- // Dirty previous rectangle
- if (!firstTime) {
- refreshData(1, toolMinX, toolMinY, toolMaxX, toolMaxY);
- setDirtyBox(toolMinX, toolMinY, toolMaxX, toolMaxY);
- }
-
- // Flood fill
- // @TODO: doesn't support layer [2] (effects data)
- if (!toolContiguous) {
- if (layerEdit[cursorLayer][1]) rect = layerMatchFill(virtualCursorX, virtualCursorY, Layer::LAYER_TILE_FILL_MASK, layerEdit[cursorLayer][0], toolDataMask, toolData, layerEdit[cursorLayer][1], toolExtMask, toolExt);
- else rect = layerMatchFill(virtualCursorX, virtualCursorY, Layer::LAYER_TILE_FILL_MASK, layerEdit[cursorLayer][0], toolDataMask, toolData);
- }
- else {
- if (layerEdit[cursorLayer][1]) rect = layerFloodFill(virtualCursorX, virtualCursorY, Layer::LAYER_TILE_FILL_MASK, layerEdit[cursorLayer][0], toolDataMask, toolData, layerEdit[cursorLayer][1], toolExtMask, toolExt);
- else rect = layerFloodFill(virtualCursorX, virtualCursorY, Layer::LAYER_TILE_FILL_MASK, layerEdit[cursorLayer][0], toolDataMask, toolData);
- }
- setDirtyRect(rect);
-
- // Remember min/max for undo on last time
- if (rect.w) {
- toolMinX = rect.x;
- toolMinY = rect.y;
- toolMaxX = rect.x + rect.w - 1;
- toolMaxY = rect.y + rect.h - 1;
- }
- else {
- // Causes no undo area or undirty to occur next frame
- toolMinX = toolMaxX = -1;
- }
- break;
-
- case TOOLS_LINE:
- case TOOLS_RECT:
- case TOOLS_RECTFILL:
- if (lastTime) undoStoreLayerBox(toolStartX, toolStartY, virtualCursorX, virtualCursorY);
-
- // Reload from last time, not entire layer
- if (!firstTime) refreshData(1, toolStartX, toolStartY, toolLastX, toolLastY);
-
- rX = virtualCursorX;
- rY = virtualCursorY;
-
- // Limit to square or straight line?
- if (toolCtrl) {
- if (tool == TOOLS_LINE) {
- // Determine approximate slope of line
- slope1 = abs(toolStartX - rX);
- slope2 = abs(toolStartY - rY);
- // (we only care, if both sizes are > 0)
- if ((slope1) && (slope2)) {
- if (slope1 > slope2) swap(slope1, slope2);
- // slope1/slope2 will be a fraction between 0 (flat) and
- // 1 (diagonal of 45deg multiple); cutoff point is 0.5
- if (slope1 * 2 / slope2 >= 1) {
- // Square
- if (abs(toolStartX - rX) < abs(toolStartY - rY)) {
- rY = toolStartY + abs(toolStartX - rX) * (toolStartY < rY ? 1 : -1);
- }
- else {
- rX = toolStartX + abs(toolStartY - rY) * (toolStartX < rX ? 1 : -1);
- }
- }
- else {
- // Flat line
- if (abs(toolStartX - rX) < abs(toolStartY - rY)) {
- rX = toolStartX;
- }
- else {
- rY = toolStartY;
- }
- }
- }
- }
- else {
- // Square
- if (abs(toolStartX - rX) < abs(toolStartY - rY)) {
- rY = toolStartY + abs(toolStartX - rX) * (toolStartY < rY ? 1 : -1);
- }
- else {
- rX = toolStartX + abs(toolStartY - rY) * (toolStartX < rX ? 1 : -1);
- }
- }
- }
-
- if (tool == TOOLS_LINE) {
- layerDrawLine(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][0], toolDataMask, toolData);
- if (layerEdit[cursorLayer][1]) layerDrawLine(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
- if (layerEdit[cursorLayer][2]) layerDrawLine(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
- }
- else if (tool == TOOLS_RECT) {
- layerDrawBox(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][0], toolDataMask, toolData);
- if (layerEdit[cursorLayer][1]) layerDrawBox(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
- if (layerEdit[cursorLayer][2]) layerDrawBox(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
- }
- else {
- layerDrawRect(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][0], toolDataMask, toolData);
- if (layerEdit[cursorLayer][1]) layerDrawRect(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
- if (layerEdit[cursorLayer][2]) layerDrawRect(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
- }
- setDirtyBox(toolStartX, toolStartY, rX, rY);
- // (no need to limit based on toolCtrl, as a limited area will always
- // be smaller than this area we use here)
- if (!firstTime) setDirtyBox(toolStartX, toolStartY, toolLastX, toolLastY);
- break;
-
- case TOOLS_ELLIPSE:
- case TOOLS_ELLIPSEFILL:
- rX = abs(toolStartX - virtualCursorX);
- rY = abs(toolStartY - virtualCursorY);
-
- // Special case
- if (rX < 1) rX = 1;
- if (rY < 1) rY = 1;
-
- // Circle?
- if (toolCtrl) {
- rX = min(rX, rY);
- rY = rX;
- }
-
- if (lastTime) undoStoreLayerBox(toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY);
- // reload from area affected last time, not entire layer
- int prX, prY;
- if (!firstTime) {
- prX = abs(toolStartX - toolLastX);
- prY = abs(toolStartY - toolLastY);
- if (prX < 1) prX = 1;
- if (prY < 1) prY = 1;
- // (no need to limit to a circle based on toolCtrl, this will always
- // cover the minimum area needed)
- refreshData(1, toolStartX - prX, toolStartY - prY, toolStartX + prX, toolStartY + prY);
- }
-
- if (tool == TOOLS_ELLIPSE) {
- layerDrawEllipse(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][0], toolDataMask, toolData);
- if (layerEdit[cursorLayer][1]) layerDrawEllipse(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
- if (layerEdit[cursorLayer][2]) layerDrawEllipse(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
- }
- else {
- layerDrawEllipseFill(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][0], toolDataMask, toolData);
- if (layerEdit[cursorLayer][1]) layerDrawEllipseFill(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][1], toolExtMask, toolExt);
- if (layerEdit[cursorLayer][2]) layerDrawEllipseFill(toolStartX, toolStartY, rX, rY, layerEdit[cursorLayer][2], toolFxMask, toolFx);
- }
-
- setDirtyBox(toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY);
-
- // Previous
- if (!firstTime) {
- setDirtyBox(toolStartX - prX, toolStartY - prY, toolStartX + prX, toolStartY + prY);
- }
- break;
- }
- }
- catch (UndoException& e) {
- toolActive = tool;
- cancelTool();
- return;
- }
-
- if ((lastTime) && (!nonDraw)) {
- // @TODO: only apply a section (to reduce overhead on preview updates)
- applyData(1);
- }
- else if (!nonDraw) ; // @TODO: preview redraw
-
- if (spriteMode) {
- toolLastX = cursorSpriteX;
- toolLastY = cursorSpriteY;
- }
- else {
- toolLastX = virtualCursorX;
- toolLastY = virtualCursorY;
- }
- }
- }
- void SceneEditLayer::cancelTool() { start_func
- startToolOnMove = 0;
- if (toolActive) {
- int rX;
- int rY;
-
- switch (toolActive) {
- case TOOLS_SELECT:
- case TOOLS_SELECTELLIPSE:
- case TOOLS_WAND:
- // Refresh from backup, dirty all
- memcpy(selected, backupSelected, selectedPitch * layerHeight);
- backupSelectionRect = selectionRect;
- setDirty(1);
- break;
- case TOOLS_PEN:
- case TOOLS_FILL:
- refreshData(1, toolMinX, toolMinY, toolMaxX, toolMaxY);
- // @TODO: preview redraw
- setDirtyBox(toolMinX, toolMinY, toolMaxX, toolMaxY);
- break;
-
- case TOOLS_LINE:
- case TOOLS_RECT:
- case TOOLS_RECTFILL:
- refreshData(1, toolStartX, toolStartY, toolLastX, toolLastY);
- // @TODO: preview redraw
- setDirtyBox(toolStartX, toolStartY, toolLastX, toolLastY);
- break;
-
- case TOOLS_ELLIPSE:
- case TOOLS_ELLIPSEFILL:
- rX = abs(toolStartX - toolLastX);
- rY = abs(toolStartY - toolLastY);
- if (rX < 1) rX = 1;
- if (rY < 1) rY = 1;
- refreshData(1, toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY);
- // @TODO: preview redraw
- setDirtyBox(toolStartX - rX, toolStartY - rY, toolStartX + rX, toolStartY + rY);
- break;
- }
-
- mousePointer();
- toolActive = 0;
- }
- }
- void SceneEditLayer::finishTool() { start_func
- startToolOnMove = 0;
- if (toolActive) {
- dragTool(0, 1);
- mousePointer();
- // toolActive = 0 taken care of by dragtool
- }
- }
- void SceneEditLayer::display(SDL_Surface* destSurface, Rect& toDisplay, const Rect& clipArea, int xOffset, int yOffset) { start_func
- assert(destSurface);
- if (visible) {
- // If dirty, redraw range or all
- if (dirty) {
- if (totalDirty) {
- // Range should include entire area, so we cover "outside" current
- // layer if appropriate
- toDisplay = clipArea;
- }
- else {
- dirtyRange.x += x + xOffset;
- dirtyRange.y += y + yOffset;
- // Range must include requested update area as well
- boundRects(toDisplay, dirtyRange);
- }
- dirty = totalDirty = 0;
- dirtyRange.w = 0;
- intersectRects(toDisplay, clipArea);
- }
-
- xOffset += x;
- yOffset += y;
-
- // Anything to draw?
- if (toDisplay.w) {
- SDL_SetClipRect(destSurface, &toDisplay);
- SDL_FillRect(destSurface, &toDisplay, guiPacked[COLOR_BKFILL]);
-
- // Draw all visible layers, bottom up
- int pos = numLayers - 1;
- Uint32 bit = 1 << pos;
- for (; pos >= 0; --pos, bit >>= 1) {
- if (layersView & bit) {
- int dim = layersDim & bit;
- if (pos == cursorLayer) dim = 0;
-
- if (layersAffect & bit) {
- // Draw directly from our data, or use our data as floating?
- if (selectionMode == SELECTION_OUTLINE) {
- LayerEdit::blitTileLayer(scene->getLayerEdit(pos)->getTileSetEdit(),
- layerEdit[pos][0], layerEdit[pos][1],
- layerWidth, layerHeight,
- toDisplay.x - xOffset, toDisplay.y - yOffset,
- toDisplay.w, toDisplay.h,
- xOffset, yOffset, destSurface, dim);
- }
- else {
- LayerEdit* layer = scene->getLayerEdit(pos);
-
- LayerEdit::blitTileLayer(layer->getTileSetEdit(),
- layer->getTileData(), layer->getExtendedData(),
- layerWidth, layerHeight,
- toDisplay.x - xOffset, toDisplay.y - yOffset,
- toDisplay.w, toDisplay.h,
- xOffset, yOffset, destSurface, dim,
- layerEdit[pos][0], layerEdit[pos][1],
- selectionXOffs, selectionYOffs, layerWidth);
- }
- }
- else {
- scene->getLayerEdit(pos)->blit(toDisplay.x - xOffset, toDisplay.y - yOffset,
- toDisplay.w, toDisplay.h,
- xOffset, yOffset, destSurface, dim);
- }
-
- // @TODO: separate dim determination for spawns
- scene->getLayerEdit(pos)->blitSpawns(toDisplay.x - xOffset, toDisplay.y - yOffset,
- toDisplay.w, toDisplay.h,
- xOffset, yOffset, destSurface,
- &selectedSpawns, dim ? 1 : 0);
- }
- }
-
- // Draw grid (top/left lines)
- if (enableGrid) {
- // Determine first/last rows to show
- int tY = max(0, (toDisplay.y - yOffset) / tileHeight);
- int bottom = (toDisplay.y + toDisplay.h - yOffset - 1) / tileHeight;
- if (bottom > layerHeight) bottom = layerHeight;
-
- // Determine first/last tiles of each row we need to show
- int tX = max(0, (toDisplay.x - xOffset) / tileWidth);
- int rightmost = (toDisplay.x + toDisplay.w - xOffset - 1) / tileWidth;
- if (rightmost > layerWidth) rightmost = layerWidth;
-
- // Determine the starting x/y pixel
- int dX = xOffset + tX * tileWidth;
- int dY = yOffset + tY * tileHeight;
- int fY = dY;
-
- // Determine length of lines
- // @TODO: displays one pixel too short in some corner cases
- int lineW = min((int)toDisplay.w, layerWidth * tileWidth - toDisplay.x + xOffset);
- int lineH = min((int)toDisplay.h, layerHeight * tileHeight - toDisplay.y + yOffset);
- // Horizontal lines
- if (lineW > 0) {
- for (; tY <= bottom; ++tY) {
- drawHLine(dX, toDisplay.x + lineW, dY, guiPacked[COLOR_GRID], destSurface);
- dY += tileHeight;
- }
- }
-
- // Vertical lines
- if (lineH > 0) {
- for (; tX <= rightmost; ++tX) {
- drawVLine(fY, toDisplay.y + lineH, dX, guiPacked[COLOR_GRID], destSurface);
- dX += tileWidth;
- }
- }
- }
-
- // Draw cursor (@TODO: cursors>1 combined with a centered client within frame may allow cursor to go off edges- ok?)
- if (partialFocus) {
- int cX = xOffset + cursorX * tileWidth;
- int cY = yOffset + cursorY * tileHeight;
- drawSelectRect(cX, cY, cursorW * tileWidth, cursorH * tileHeight,
- guiPacked[haveFocus ? COLOR_TILECURSOR : COLOR_TILESELECTION], destSurface,
- haveFocus ? desktop->currentCursorAlpha() : 128);
- drawBox(cX, cY, cursorW * tileWidth, cursorH * tileHeight, guiPacked[COLOR_TILECURSORBORDER1], destSurface);
- drawBox(cX + 1, cY + 1, cursorW * tileWidth - 2, cursorH * tileHeight - 2, guiPacked[COLOR_TILECURSORBORDER2], destSurface);
- }
- // Now handle selection borders
- if ((partialFocus) && (selectionRect.w)) {
- // Determine first/last rows to show
- int tY = max(0, (toDisplay.y - yOffset) / tileHeight);
- int bottom = (toDisplay.y + toDisplay.h - yOffset - 1) / tileHeight;
- if (bottom >= layerHeight) bottom = layerHeight - 1;
-
- // Determine first/last tiles of each row we need to show
- int leftmost = max(0, (toDisplay.x - xOffset) / tileWidth);
- int rightmost = (toDisplay.x + toDisplay.w - xOffset - 1) / tileWidth;
- if (rightmost >= layerWidth) rightmost = layerWidth - 1;
-
- // Clip to selection boundaries
- if (tY < selectionRect.y + selectionYOffs) tY = selectionRect.y + selectionYOffs;
- if (bottom >= selectionRect.y + selectionRect.h + selectionYOffs) bottom = selectionRect.y + selectionRect.h + selectionYOffs - 1;
- if (leftmost < selectionRect.x + selectionXOffs) leftmost = selectionRect.x + selectionXOffs;
- if (rightmost >= selectionRect.x + selectionRect.w + selectionXOffs) rightmost = selectionRect.x + selectionRect.w + selectionXOffs - 1;
-
- // Determine the starting x/y pixel
- int dX = xOffset + leftmost * tileWidth;
- int dY = yOffset + tY * tileHeight;
-
- for (; tY <= bottom; ++tY) {
- // Place in bitarray terms
- Uint8 bit = 1 << ((leftmost - selectionXOffs) & 7);
- Uint8* selData = selected + ((leftmost - selectionXOffs) >> 3) + (tY - selectionYOffs) * selectedPitch;
- Uint8 prevbit = bit >> 1;
- Uint8* prevData = selData;
- if (prevbit == 0) {
- prevbit = 128;
- --prevData;
- }
- Uint8 nextbit = bit << 1;
- Uint8* nextData = selData;
- if (nextbit == 0) {
- nextbit = 1;
- ++nextData;
- }
-
- for (int tX = leftmost; tX <= rightmost; ++tX) {
- if (*selData & bit) {
- // Don't highlight if part of cursor
- if ((tX < cursorX) || (tX >= cursorX + cursorW) ||
- (tY < cursorY) || (tY >= cursorY + cursorH)) {
- drawSelectRect(dX, dY, tileWidth, tileHeight,
- guiPacked[COLOR_TILESELECTION], destSurface);
- }
-
- // Draw ants borders
- int drawT = 1;
- int drawB = 1;
- int drawL = 1;
- int drawR = 1;
-
- // Determine which borders to hide
- if ((tY > selectionYOffs) && (*(selData - selectedPitch) & bit)) drawT = 0;
- if ((tY < (layerHeight + selectionYOffs - 1)) && (*(selData + selectedPitch) & bit)) drawB = 0;
- if ((tX > selectionXOffs) && (*prevData & prevbit)) drawL = 0;
- if ((tX < (layerWidth + selectionXOffs - 1)) && (*nextData & nextbit)) drawR = 0;
-
- if (drawT) drawAntsHLine(dX, dX + tileWidth - 1, dY, desktop->currentSelectionPhase(), destSurface);
- if (drawB) drawAntsHLine(dX, dX + tileWidth - 1, dY + tileHeight - 1, desktop->currentSelectionPhase(), destSurface);
- if (drawL) drawAntsVLine(dY, dY + tileHeight - 1, dX, desktop->currentSelectionPhase(), destSurface);
- if (drawR) drawAntsVLine(dY, dY + tileHeight - 1, dX + tileWidth - 1, desktop->currentSelectionPhase(), destSurface);
- }
-
- prevbit = bit;
- bit = nextbit;
-
- prevData = selData;
- selData = nextData;
-
- nextbit <<= 1;
- if (nextbit == 0) {
- nextbit = 1;
- ++nextData;
- }
-
- dX += tileWidth;
- }
-
- dX = xOffset + leftmost * tileWidth;
- dY += tileHeight;
- }
- }
- // Draw sprite cursor?
- if (spriteShown) {
- spawnPlace->setPos(spriteShownX, spriteShownY, 1);
- spawnPlace->blit(xOffset, yOffset, destSurface, toDisplay.x - xOffset,
- toDisplay.y - yOffset, toDisplay.w, toDisplay.h, 2);
- }
-
- // Sprite selection box?
- if (toolActive == TOOLS_SELECTITEM) {
- Rect selArea = createRect(toolStartX, toolStartY, toolLastX, toolLastY);
- drawSelectRect(selArea.x + xOffset, selArea.y + yOffset,
- selArea.w, selArea.h,
- guiPacked[COLOR_SELECTION1], destSurface);
- drawAntsBox(selArea.x + xOffset, selArea.y + yOffset,
- selArea.w, selArea.h,
- desktop->currentSelectionPhase(), destSurface);
- }
- }
- }
- }
- void SceneEditLayer::undoStoreLayerBox(int x1, int y1, int x2, int y2, int cursorLayerOnly) throw_Undo { start_func
- if (x1 > x2) swap(x1, x2);
- if (y1 > y2) swap(y1, y2);
- undoStoreLayer(x1, y1, x2 - x1 + 1, y2 - y1 + 1, cursorLayerOnly);
- }
- void SceneEditLayer::undoStoreLayer(int x, int y, int w, int h, int cursorLayerOnly) throw_Undo { start_func
- Uint32 bit = 1;
- int pos = 0;
- int max = numLayers - 1;
- if (cursorLayerOnly) {
- pos = max = cursorLayer;
- if (pos) bit <<= pos;
- }
- world->undo.preUndoBlock();
- for (; pos <= max; ++pos, bit <<= 1) {
- if (layersAffect & bit) {
- world->undo.storeUndoLayerTile(scene->getLayer(pos)->getId(), x, y, w, h, myFrame);
- }
- }
- world->undo.postUndoBlock();
- }
- void SceneEditLayer::undoStoreSelect(int x, int y, int w, int h, int forceStoreData) throw_Undo { start_func
- // we have to ensure x/y/w/h are within range ourselves
- if (x < 0) x = 0;
- if (y < 0) y = 0;
- if (x + w >= layerWidth) w = layerWidth - x - 1;
- if (y + h >= layerHeight) h = layerHeight - y - 1;
-
- world->undo.preUndoBlock();
- world->undo.storeUndoLayerTileCur(layersAffect, layersView, layersDim, myFrame);
-
- // Before data, if not floating
- if (selectionMode == SELECTION_OUTLINE) {
- world->undo.storeUndoLayerTileSelection(&selected, x, y, w, h, selectedPitch, selectionXOffs, selectionYOffs, selectionMode, myFrame);
- }
-
- // Store data too, if not an outline
- if ((selectionMode != SELECTION_OUTLINE) || (forceStoreData)) {
- Uint32 bit = 1;
- for (int pos = 0; pos < numLayers; ++pos, bit <<= 1) {
- if (layersAffect & bit) {
- world->undo.storeUndoLayerTileTemp(&layerEdit[pos][0], &layerEdit[pos][1], &layerEdit[pos][2], x, y, w, h, layerWidth, myFrame);
- }
- }
- }
- // After data, if floating
- if (selectionMode != SELECTION_OUTLINE) {
- world->undo.storeUndoLayerTileSelection(&selected, x, y, w, h, selectedPitch, selectionXOffs, selectionYOffs, selectionMode, myFrame);
- }
- world->undo.storeUndoLayerTileCur(layersAffect, layersView, layersDim, myFrame);
- world->undo.postUndoBlock();
- }
- void SceneEditLayer::clearSelection(int storeUndo) throw_Undo { start_func
- assert(selected);
- if (selectionRect.w) {
- if (storeUndo) undoStoreSelect(selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h);
-
- memset(selected, 0, selectedPitch * layerHeight);
-
- // If a floating selection, reload data
- if (selectionMode != SELECTION_OUTLINE) refreshData(0);
- // Add in offset so proper area is dirtied
- selectionRect.x += selectionXOffs;
- selectionRect.y += selectionYOffs;
- setDirtyRect(selectionRect);
-
- selectionRect.w = 0;
- selectionXOffs = selectionYOffs = 0;
- selectionMode = SELECTION_OUTLINE;
- }
-
- updateCopyTool();
- }
- void SceneEditLayer::floatSelection(int copyPrep, int delSel) throw_Undo { start_func
- if ((selectionMode == SELECTION_OUTLINE) && (selectionRect.w)) {
- if (!copyPrep) {
- world->undo.preUndoBlock();
- undoStoreLayer(selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h, 0);
- undoStoreSelect(selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h, 1);
- world->undo.postUndoBlock();
- }
- // (set dirty first, in case rect resizes)
- setDirtyRect(selectionRect);
-
- // Cut out selection on each layer
- Uint32* tempFloat = NULL;
- Uint32* tempFloatExt = NULL;
- Uint32* tempFloatFx = NULL;
-
- Rect affect = { 0, 0, layerWidth, layerHeight };
- int affectBit = 1;
- int layerSize = layerWidth * layerHeight;
- for (int pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
- if (layersAffect & affectBit) {
- // Allocate temporary storage to float selection to
- tempFloat = new Uint32[layerSize];
- memSet32(tempFloat, Layer::LAYER_TILE_DEFAULT, layerSize);
- if (layerEdit[pos][1]) {
- tempFloatExt = new Uint32[layerSize];
- memSet32(tempFloatExt, Layer::LAYER_EXT_DEFAULT, layerSize);
- }
- if (layerEdit[pos][2]) {
- tempFloatFx = new Uint32[layerSize];
- memSet32(tempFloatFx, Layer::LAYER_FX_DEFAULT, layerSize);
- }
- // Scan layer and move selected data that isn't tile 0
- Uint8 bit = 1;
- Uint8* source = selected;
- Uint32* src = layerEdit[pos][0];
- Uint32* srcExt = layerEdit[pos][1];
- Uint32* srcFx = layerEdit[pos][2];
- Uint32* dest = tempFloat;
- Uint32* destExt = tempFloatExt;
- Uint32* destFx = tempFloatFx;
- for (int y = 0; y < layerHeight; ++y) {
- for (int x = 0; x < layerWidth; ++x) {
- if (((*src & Layer::LAYER_TILE_INDEX) != 0) && (*source & bit)) {
- *dest = *src;
- *src = Layer::LAYER_TILE_DEFAULT;
- if (srcExt) {
- *destExt = *srcExt;
- *srcExt = Layer::LAYER_EXT_DEFAULT;
- }
- if (srcFx) {
- *destFx = *srcFx;
- *srcFx = Layer::LAYER_FX_DEFAULT;
- }
- }
- ++src;
- ++dest;
- if (srcExt) {
- ++srcExt;
- ++destExt;
- }
- if (srcFx) {
- ++srcFx;
- ++destFx;
- }
- bit <<= 1;
- if (bit == 0) {
- bit = 1;
- ++source;
- }
- }
- // If bit just wrapped to 1, we have an even multiple
- // otherwise, move forward the final byte
- if (bit > 1) ++source;
- bit = 1;
- }
-
- // Apply data
- if (!copyPrep) scene->getLayerEdit(pos)->saveLayer(layerEdit[pos][0], layerEdit[pos][1], layerEdit[pos][2], layerWidth, affect, this);
-
- // Replace our layer data
- if (delSel) {
- delete[] tempFloat;
- delete[] tempFloatExt;
- delete[] tempFloatFx;
- }
- else {
- delete[] layerEdit[pos][0];
- delete[] layerEdit[pos][1];
- delete[] layerEdit[pos][2];
- layerEdit[pos][0] = tempFloat;
- layerEdit[pos][1] = tempFloatExt;
- layerEdit[pos][2] = tempFloatFx;
- }
- tempFloat = NULL;
- tempFloatExt = NULL;
- tempFloatFx = NULL;
- }
- }
-
- if (delSel) return;
- fixSelectionRect(1);
- selectionMode = SELECTION_OPAQUE;
- // (possible that there's no selection now)
- updateCopyTool();
- }
- }
- void SceneEditLayer::doneSelection() throw_Undo { start_func
- if (selectionMode == SELECTION_OUTLINE) clearSelection();
- else mergeSelection();
- }
- int SceneEditLayer::pasteSelection() throw_Undo { start_func
- if (canConvertClipboard(CLIPBOARD_SPAWN)) {
- int pNumSpawns;
- int pNumLayers;
-
- clipboardPasteSpawnInfo(&pNumSpawns, &pNumLayers);
-
- // Note affected layers- warn user for problems
- int affectBit = 1;
- int matchedLayers = 0;
- int pos = 0;
- map<int, int> layerMapping;
- // One layer of data = always on cursor layer
- if (pNumLayers == 1) {
- layerMapping[0] = cursorLayer;
- matchedLayers = 1;
- }
- else {
- for (; pos < numLayers; ++pos, affectBit <<= 1) {
- if (layersAffect & affectBit) {
- layerMapping[matchedLayers] = pos;
- ++matchedLayers;
- }
- }
- }
-
- // Too many layers?
- if (matchedLayers < pNumLayers) {
- if (!guiConfirmBox("Clipboard contains objects on more layers than marked for editing- continue?", "Layer Mismatch")) return 0;
- }
-
- // Determine base x/y-
- // Start with mouse position
- // Prefer cursor position if more recently used
- // Prefer offset from current selection position if any
- // Ensure upperleft corner is not further up than onscreen upper-left
- // (move selection to be visible if too far offscreen to right/bottom)
- int baseX = pixelMouseX;
- int baseY = pixelMouseY;
- if (spriteAtCursor) {
- baseX = cursorX * tileWidth;
- baseY = cursorY * tileHeight;
- }
- if (selectedSpawnRect.w) {
- baseX = selectedSpawnRect.x + tileWidth;
- baseY = selectedSpawnRect.y + tileHeight;
- }
- while (baseX > -x + viewWidth - tileWidth) baseX -= tileWidth;
- while (baseY > -y + viewHeight - tileHeight) baseY -= tileHeight;
- while (baseX < -x) baseX += tileWidth;
- while (baseY < -y) baseY += tileHeight;
-
- // Start undo and clear current spawn selection (storing undo for that too)
- world->undo.preUndoBlock();
- setDirtySelectedSpawns();
- clearSpawnSelection(); // @TODO: can throw Undo (ok?)
- // Now actually paste spawn data
- for (pos = 0; pos < pNumSpawns; ++pos) {
- int lNum;
- SpawnEdit* newSpawn = new SpawnEdit(world, NULL, world->unusedSpawnId());
- clipboardPasteSpawn(pos, newSpawn, &lNum, baseX, baseY);
- LayerEdit* layer = scene->getLayerEdit(layerMapping[lNum]);
- newSpawn->setLayer(layer);
- newSpawn->setUndoReady();
- layer->addSpawn(newSpawn, myFrame, this); // @TODO: can throw_File / Undo
- selectedSpawns.insert(newSpawn->getId());
- }
-
- // Finalize selection and undo
- recheckSpawnSelection();
- world->undo.postUndoBlock();
- updateCopyTool();
- setDirtySelectedSpawns();
-
- return TOOLS_SELECTITEM;
- }
- else if (canConvertClipboard(CLIPBOARD_LAYER)) {
- int pNumLayers;
- int pWidth;
- int pHeight;
- const void* pTileSet;
- int pHasExt;
- int pHasFx;
- int warnedTileSet = 0;
- int warnedExt = 0;
- int warnedFx = 0;
-
- clipboardPasteLayerInfo(&pNumLayers, &pWidth, &pHeight);
-
- // Match up against affected layers- warn user for problems
- int affectBit = 1;
- int matchedLayers = 0;
- int pos = 0;
- for (; pos < numLayers; ++pos, affectBit <<= 1) {
- if (layersAffect & affectBit) {
- clipboardPasteLayerInfoDetails(matchedLayers, &pTileSet, &pHasExt, &pHasFx);
-
- // Same tileset? (if one specified)
- if ((pTileSet) && (!warnedTileSet)) {
- if (pTileSet != scene->getLayer(pos)->getTileSet()) {
- if (!guiConfirmBox("Layer tileset may not match clipboard data- continue?", "Tileset Mismatch")) return 0;
- warnedTileSet = 1;
- }
- }
- // Effects data
- if ((pHasExt) && (!warnedExt)) {
- if (!layerEdit[pos][1]) {
- if (!guiConfirmBox("Clipboard includes extended collision, alpha, and/or animation data, which layer does not support- continue?", "Extended Data Mismatch")) return 0;
- warnedFx = 1;
- }
- }
- // Collision data
- if ((pHasFx) && (!warnedFx)) {
- if (!layerEdit[pos][2]) {
- if (!guiConfirmBox("Clipboard includes effects data, which layer does not support- continue?", "Effects Data Mismatch")) return 0;
- warnedFx = 1;
- }
- }
-
- ++matchedLayers;
- if (matchedLayers == pNumLayers) break;
- }
- }
-
- // Too many layers?
- if (matchedLayers < pNumLayers) {
- if (!guiConfirmBox("Clipboard contains more layers than marked for editing- continue?", "Layer Mismatch")) return 0;
- }
-
- world->undo.preUndoBlock();
- doneSelection();
- undoStoreSelect(0, 0, layerWidth, layerHeight, 1);
- world->undo.postUndoBlock();
- // "Default" data/fx if paste data doesn't supply it
- Uint32 defData;
- Uint32 defExt;
- Uint32 defFx;
- imagebar->getDataExt(defData, defExt, defFx);
- // Now actually paste layer data
- affectBit = 1;
- matchedLayers = 0;
- // @TODO: If only one layer's worth of data, always paste to cursor layer
- // this may require adjusting the data clearing portion, below
- for (pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
- if (layersAffect & affectBit) {
- memSet32(layerEdit[pos][0], Layer::LAYER_TILE_DEFAULT, layerWidth * layerHeight);
- if (layerEdit[pos][1]) memSet32(layerEdit[pos][1], Layer::LAYER_EXT_DEFAULT, layerWidth * layerHeight);
- if (layerEdit[pos][2]) memSet32(layerEdit[pos][2], Layer::LAYER_FX_DEFAULT, layerWidth * layerHeight);
- clipboardPasteLayer(matchedLayers, layerEdit[pos][0], layerEdit[pos][1], layerEdit[pos][2], 0, 0, layerWidth, layerHeight, layerWidth, defData, defExt, defFx);
- ++matchedLayers;
- if (matchedLayers == pNumLayers) {
- // So we start at the right layer for clearing data
- ++pos;
- affectBit <<= 1;
- break;
- }
- }
- }
-
- // (any remaining layers- clear data)
- for (; pos < numLayers; ++pos, affectBit <<= 1) {
- if (layersAffect & affectBit) {
- memSet32(layerEdit[pos][0], Layer::LAYER_TILE_DEFAULT, layerWidth * layerHeight);
- if (layerEdit[pos][1]) memSet32(layerEdit[pos][1], Layer::LAYER_EXT_DEFAULT, layerWidth * layerHeight);
- if (layerEdit[pos][2]) memSet32(layerEdit[pos][2], Layer::LAYER_FX_DEFAULT, layerWidth * layerHeight);
- }
- }
-
- // Determine selection mask (select all, then deselect empties)
- memset(selected, 255, selectedPitch * layerHeight);
- selectionRect.x = 0;
- selectionRect.y = 0;
- selectionRect.w = layerWidth;
- selectionRect.h = layerHeight;
- selectionMode = SELECTION_OPAQUE;
- fixSelectionRect(1);
- // Possible nothing was actually pasted
- fixSelectionRect();
- updateCopyTool();
- if (selectionRect.w) {
- // @TODO: Move selection to ensure it's visible; may affect dirty below
- // Should ideally appear near previous selection (but not on top) or at cursor, adjusted to be on screen
- }
- // Dirty
- setDirtyRect(selectionRect);
-
- return TOOLS_SELECT;
- }
-
- return 0;
- }
- void SceneEditLayer::copySelection() { start_func
- if (selectionRect.w) {
- int setFloat = 0;
-
- // If not floating, float it to copy; backup selection
- if (selectionMode == SELECTION_OUTLINE) {
- memcpy(backupSelected, selected, selectedPitch * layerHeight);
- backupSelectionRect = selectionRect;
- setFloat = 1;
- floatSelection(1); // Will NOT throw undo
- }
- // Ensure there's a selection still
- if (selectionRect.w) {
- // We copy what's in the floating selection
- const void* cTileset[MAX_LAYERS];
- Uint32* cData[MAX_LAYERS];
- Uint32* cDataExt[MAX_LAYERS];
- Uint32* cDataFx[MAX_LAYERS];
- int cNumLayers = 0;
-
- // Copy each active layer
- int affectBit = 1;
- for (int pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
- if (layersAffect & affectBit) {
- cTileset[cNumLayers] = scene->getLayer(pos)->getTileSet();
- cData[cNumLayers] = layerEdit[pos][0];
- cDataExt[cNumLayers] = layerEdit[pos][1];
- cDataFx[cNumLayers] = layerEdit[pos][2];
- ++cNumLayers;
- }
- }
-
- clipboardCopy(cNumLayers, cTileset, cData, cDataExt, cDataFx, selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h, layerWidth);
- }
-
- // If was floating, defloat it now
- if (setFloat) {
- refreshData(0);
- selectionMode = SELECTION_OUTLINE;
- memcpy(selected, backupSelected, selectedPitch * layerHeight);
- selectionRect = backupSelectionRect;
- }
- }
- }
- void SceneEditLayer::deleteSelection() throw_Undo { start_func
- if ((selectionMode == SELECTION_OUTLINE) && (selectionRect.w)) {
- // Float to nowhere
- floatSelection(0, 1);
- }
- else if (selectionRect.w) {
- // Delete floating selection
- clearSelection();
- }
- }
- void SceneEditLayer::mergeSelection() throw_Undo { start_func
- // (no scene = closing)
- if ((selectionMode != SELECTION_OUTLINE) && (scene)) {
- world->undo.preUndoBlock();
- // Paste selection, with offset
- if (selectionRect.w) {
- undoStoreLayer(selectionRect.x + selectionXOffs, selectionRect.y + selectionYOffs, selectionRect.w, selectionRect.h, 0);
- undoStoreSelect(selectionRect.x, selectionRect.y, selectionRect.w, selectionRect.h);
- // Underlay existing layer data under selection on each layer
- Uint32* tempFloat = NULL;
- Uint32* tempFloatExt = NULL;
- Uint32* tempFloatFx = NULL;
-
- Rect affect = { 0, 0, layerWidth, layerHeight };
- int affectBit = 1;
- int layerSize = layerWidth * layerHeight;
- for (int pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
- if (layersAffect & affectBit) {
- // Allocate temporary storage to overlay selection to
- tempFloat = new Uint32[layerSize];
- if (layerEdit[pos][1]) {
- tempFloatExt = new Uint32[layerSize];
- }
- if (layerEdit[pos][2]) {
- tempFloatFx = new Uint32[layerSize];
- }
-
- // Grab original layer data
- scene->getLayerEdit(pos)->loadLayer(tempFloat, tempFloatExt, tempFloatFx, layerWidth, affect);
-
- // Scan selection and overlay selected data that isn't tile 0
- Uint32* src = layerEdit[pos][0];
- Uint32* srcExt = layerEdit[pos][1];
- Uint32* srcFx = layerEdit[pos][2];
- Uint32* dest = tempFloat + selectionXOffs + selectionYOffs * layerWidth;
- Uint32* destExt = tempFloatExt;
- Uint32* destFx = tempFloatFx;
- if (destExt) destExt += selectionXOffs + selectionYOffs * layerWidth;
- if (destFx) destFx += selectionXOffs + selectionYOffs * layerWidth;
- for (int y = 0; y < layerHeight; ++y) {
- for (int x = 0; x < layerWidth; ++x) {
- if ((*src & Layer::LAYER_TILE_INDEX) != 0) {
- if ((x < layerWidth - selectionXOffs) && (x >= -selectionXOffs) && (y < layerHeight - selectionYOffs) && (y >= -selectionYOffs)) {
- *dest = *src;
- if (srcExt) {
- *destExt = *srcExt;
- }
- if (srcFx) {
- *destFx = *srcFx;
- }
- }
- }
- ++src;
- ++dest;
- if (srcExt) {
- ++srcExt;
- ++destExt;
- }
- if (srcFx) {
- ++srcFx;
- ++destFx;
- }
- }
- }
-
- // Replace our layer data
- delete[] layerEdit[pos][0];
- delete[] layerEdit[pos][1];
- delete[] layerEdit[pos][2];
- layerEdit[pos][0] = tempFloat;
- layerEdit[pos][1] = tempFloatExt;
- layerEdit[pos][2] = tempFloatFx;
- tempFloat = NULL;
- tempFloatExt = NULL;
- tempFloatFx = NULL;
- // Apply data
- scene->getLayerEdit(pos)->saveLayer(layerEdit[pos][0], layerEdit[pos][1], layerEdit[pos][2], layerWidth, affect, this);
- }
- }
- }
-
- // Clear selection (also sets dirty for us)
- clearSelection(0);
- world->undo.postUndoBlock();
- }
- }
- int SceneEditLayer::isInSelection(int x, int y) const { start_func
- if (!selectionRect.w) return 0;
- x -= selectionXOffs;
- y -= selectionYOffs;
- Uint8 bit = 1 << (x & 7);
- Uint8* selData = selected + (x >> 3) + y * selectedPitch;
- return *selData & bit;
- }
- void SceneEditLayer::fixSelectionRect(int deselEmpty) { start_func
- int minX = -1;
- int maxX;
- int minY;
- int maxY;
- Uint8 bit = 1;
- Uint8* source = selected;
- int dataOffset = 0;
- for (int y = 0; y < layerHeight; ++y) {
- for (int x = 0; x < layerWidth; ++x) {
- if (deselEmpty) {
- // Check all affected layers
- int empty = 1;
- for (int pos = 0; pos < numLayers; ++pos) {
- if (layerEdit[pos][0]) {
- if ((layerEdit[pos][0][dataOffset] & Layer::LAYER_TILE_INDEX) != 0) {
- empty = 0;
- break;
- }
- }
- }
- // Empty- deselct this bit
- if (empty) {
- *source &= ~bit;
- }
- }
- if (*source & bit) {
- if (minX == -1) {
- minX = maxX = x;
- minY = maxY = y;
- }
- else {
- if (x < minX) minX = x;
- else if (x > maxX) maxX = x;
- if (y < minY) minY = y;
- else if (y > maxY) maxY = y;
- }
- }
- ++dataOffset;
- bit <<= 1;
- if (bit == 0) {
- bit = 1;
- ++source;
- }
- }
- // If bit just wrapped to 1, we have an even multiple
- // otherwise, move forward the final byte
- if (bit > 1) ++source;
- bit = 1;
- }
-
- if (minX == -1) {
- selectionRect.w = 0;
- }
- else {
- selectionRect = createRect(minX, minY, maxX, maxY);
- }
- }
- void SceneEditLayer::updateSpriteShown() { start_func
- int newSpriteShown = 0;
- int newSpriteX = spriteShownX;
- int newSpriteY = spriteShownY;
- // If we don't have input focus, don't show
- // If mouse isn't over us, and not showing at cursor, don't show
- if ((!partialFocus) || ((!hover) && (!spriteAtCursor))) {
- // (already set above)
- }
- // Show sprite if currently in use tool is a sprite tool OR
- // current tool is a sprite tool and not in use
- else if ((toolActive == TOOLS_PLACEITEM) || (toolActive == TOOLS_PLACESERIES) ||
- ((!toolActive) &&
- ((toolL == TOOLS_PLACEITEM) || (toolL == TOOLS_PLACESERIES) ||
- (toolR == TOOLS_PLACEITEM) || (toolR == TOOLS_PLACESERIES)))) {
- newSpriteShown = 1;
-
- // Now determine position
- if (spriteAtCursor) {
- newSpriteX = cursorX * tileWidth;
- newSpriteY = cursorY * tileHeight;
- }
- else {
- newSpriteX = pixelMouseX;
- newSpriteY = pixelMouseY;
- }
- }
-
- // Change from last time?
- if ((newSpriteShown != spriteShown) || (newSpriteX != spriteShownX) || (newSpriteY != spriteShownY)) {
- // @TODO: Dirty old and new areas only
- setDirty(1);
-
- spriteShown = newSpriteShown;
- spriteShownX = newSpriteX;
- spriteShownY = newSpriteY;
- }
- }
- void SceneEditLayer::mousePointer(int mouseX, int mouseY) { start_func
- lastMouseX = mouseX;
- lastMouseY = mouseY;
- mousePointer();
- }
- void SceneEditLayer::mousePointer() { start_func
- if (!hover) return;
- if ((toolActive == TOOLS_SELECT) || (toolActive == TOOLS_SELECTELLIPSE) ||
- (toolActive == TOOLS_WAND) || (toolActive == TOOLS_SELECTITEM)) {
- if (toolAlt) {
- selectMouse(MOUSE_SUBTRACT);
- return;
- }
- else if (toolCtrl) {
- selectMouse(MOUSE_ADD);
- return;
- }
- }
- if ((toolActive == TOOLS_SELECTDRAG) || (toolActive == TOOLS_SELECTITEMDRAG)) {
- selectMouse(MOUSE_FOURDIRECTION);
- return;
- }
- if (((!toolActive) && ((toolL == TOOLS_SELECT) || (toolL == TOOLS_SELECTELLIPSE) ||
- (toolL == TOOLS_WAND)))
- || (toolL == TOOLS_SELECTITEM)) {
- if (SDL_GetModState() & KMOD_ALT) {
- selectMouse(MOUSE_SUBTRACT);
- return;
- }
- if (SDL_GetModState() & KMOD_CTRL) {
- selectMouse(MOUSE_ADD);
- return;
- }
-
- if (toolL == TOOLS_SELECTITEM) {
- if (isInSpawnSelection(lastMouseX, lastMouseY)) {
- selectMouse(MOUSE_FOURDIRECTION);
- return;
- }
- }
- else {
- if (isInSelection(lastMouseX / tileWidth, lastMouseY / tileHeight)) {
- selectMouse(MOUSE_FOURDIRECTION);
- return;
- }
- }
- }
-
- selectMouse(MOUSE_NORMAL);
- }
- Window::CommandSupport SceneEditLayer::supportsCommand(int code) const { start_func
- switch (code) {
- // Options
- case VIEW_GRID:
- return (Window::CommandSupport)((enableGrid ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);
-
- case TOOLS_CONTIGUOUS:
- if ((toolL == TOOLS_WAND) || (toolL == TOOLS_FILL) || (toolR == TOOLS_WAND) || (toolR == TOOLS_FILL)) {
- return (Window::CommandSupport)((contiguous ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_ENABLE);
- }
- else return (Window::CommandSupport)((contiguous ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_CHECKBOX | Window::COMMAND_DISABLE);;
- case TOOLS_PEN:
- case TOOLS_LINE:
- case TOOLS_RECT:
- case TOOLS_RECTFILL:
- case TOOLS_ELLIPSE:
- case TOOLS_ELLIPSEFILL:
- case TOOLS_SELECT:
- case TOOLS_SELECTELLIPSE:
- case TOOLS_DROPPER:
- case TOOLS_FILL:
- case TOOLS_WAND:
- return (Window::CommandSupport)(((toolL == code) ? Window::COMMAND_SELECTED : 0) | Window::COMMAND_RADIO | Window::COMMAND_ENABLE);
- // These are always available (techincally you could have 1 or 0
- // colors/images available, but not worth worrying about)
- case TOOLS_CHOOSE:
- case TOOLS_CHOOSER:
- case EDIT_SELECTALL:
- case TOOLS_SETTINGS:
- case TOOLS_EDITCOLOR:
- case TOOLS_NEXTCOLOR:
- case TOOLS_PREVCOLOR:
- case TOOLS_NEXTIMAGE:
- case TOOLS_PREVIMAGE:
- case NEW_LAYER:
- return Window::COMMAND_ENABLE;
-
- case VIEW_PREV:
- for (int pos = 0; pos < cursorLayer; ++pos) {
- if (layersAvailable & (1 << pos)) return Window::COMMAND_ENABLE;
- }
- return Window::COMMAND_DISABLE;
-
- case VIEW_NEXT:
- for (int pos = cursorLayer + 1; pos < numLayers; ++pos) {
- if (layersAvailable & (1 << pos)) return Window::COMMAND_ENABLE;
- }
- return Window::COMMAND_DISABLE;
- case VIEW_ALLLAYER:
- case VIEW_DIMLAYER:
- case VIEW_NOLAYER:
- if (numLayers > 1) return Window::COMMAND_ENABLE;
- return Window::COMMAND_DISABLE;
- case EDIT_COPY:
- case EDIT_CUT:
- case EDIT_DELETE:
- case EDIT_DESELECTALL:
- if (selectionRect.w) return Window::COMMAND_ENABLE;
- else return Window::COMMAND_DISABLE;
-
- case EDIT_PASTE:
- if (canConvertClipboard(CLIPBOARD_LAYER)) return Window::COMMAND_ENABLE;
- else return Window::COMMAND_DISABLE;
- }
-
- return world->supportsCommand(code);
- }
- void SceneEditLayer::newToolSelected() { start_func
- // @TODO: abort currently used tool?
- if ((toolL == TOOLS_PLACEITEM) || (toolL == TOOLS_PLACESERIES) || (toolL == TOOLS_SELECTITEM)) spriteMode = 1;
- else spriteMode = 0;
- updateSpriteShown();
- }
- void SceneEditLayer::startToolIfMove() { start_func
- startToolOnMove = 1;
- }
- void SceneEditLayer::refresh() { start_func
- setDirty(1);
- }
- void SceneEditLayer::refreshLayers(Uint32 newLayersAffect, Uint32 newLayersView, Uint32 newLayersDim) { start_func
- // Determine new desired cursor layer, affected layers, visible/dim layers
- int newCursorLayer = layerlist->selectedLayer;
- if (newLayersAffect) {
- // Layers provided- just ensure cursor layer valid and then apply to layer list
- int cursorBit = 1 << newCursorLayer;
- if (!(newLayersAffect & cursorBit)) {
- for (newCursorLayer = 0, cursorBit = 1; newCursorLayer < numLayers; ++newCursorLayer, cursorBit <<= 1) {
- if (newLayersAffect & cursorBit) break;
- }
- assert(newCursorLayer < numLayers);
- }
- layerlist->layerList->setBitMask(newLayersAffect, newLayersView, newLayersDim, newCursorLayer);
- }
- else {
- // Grab layers from layer list
- layerlist->layerList->determineBitMasks(newLayersView, newLayersDim, newLayersAffect);
- }
-
- // Compare to current settings and determine what needs redrawing or reloading
- // refresh = need to reload layer data
- int refresh = 0;
- // Merge any selection before changing affect bits unless from an undo
- if ((newLayersAffect != layersAffect) || (newCursorLayer != cursorLayer)) {
- // (we merge event if just "affected layers" changes because that changes what
- // the selection would be applying to)
- try {
- mergeSelection();
- }
- catch (UndoException& e) {
- // If undo fails, we force layerlist to previous set of layers
- layerlist->layerList->setBitMask(layersAffect, layersView, layersDim, cursorLayer);
- return;
- }
- }
- if (newLayersAffect != layersAffect) {
- layersAffect = newLayersAffect;
- refresh = 1;
- }
- if (newCursorLayer != cursorLayer) {
- cursorLayer = newCursorLayer;
- refresh = 1;
- }
- if (refresh) {
- reloadLayerStats();
- refreshData(0);
- }
-
- // Now, refresh = need to redraw
- if ((newLayersView != layersView) || (newLayersDim != layersDim)) {
- layersView = newLayersView;
- layersDim = newLayersDim;
- refresh = 1;
- }
-
- if (refresh) {
- recheckSpawnSelection();
- setDirty(1);
- }
- }
- void SceneEditLayer::selectEllipse(int x, int y, int rx, int ry, int set) { start_func
- // ** Code modified from sge_primitives.cpp **
- int ix, iy;
- int h, i, j, k;
- int oh, oi, oj, ok;
- if (rx < 1) rx = 1;
- if (ry < 1) ry = 1;
- oh = oi = oj = ok = 0xFFFF;
- if (rx > ry) {
- ix = 0;
- iy = rx * 64;
- do {
- h = (ix + 32) >> 6;
- i = (iy + 32) >> 6;
- j = (h * ry) / rx;
- k = (i * ry) / rx;
- if ((k != ok) && (k != oj)) {
- if (k) {
- selectRect(x - h, y - k, x + h, y - k, set);
- selectRect(x - h, y + k, x + h, y + k, set);
- }
- else selectRect(x - h, y, x + h, y, set);
- ok = k;
- }
- if ((j != oj) && (j != ok) && (k != j)) {
- if (j) {
- selectRect(x - i, y - j, x + i, y - j, set);
- selectRect(x - i, y + j, x + i, y + j, set);
- }
- else selectRect(x - i, y, x + i, y, set);
- oj = j;
- }
- ix = ix + iy / rx;
- iy = iy - ix / rx;
- } while (i > h);
- }
- else {
- ix = 0;
- iy = ry * 64;
- do {
- h = (ix + 32) >> 6;
- i = (iy + 32) >> 6;
- j = (h * rx) / ry;
- k = (i * rx) / ry;
- if ((i != oi) && (i != oh)) {
- if (i) {
- selectRect(x - j, y - i, x + j, y - i, set);
- selectRect(x - j, y + i, x + j, y + i, set);
- }
- else selectRect(x - j, y, x + j, y, set);
- oi = i;
- }
- if ((h != oh) && (h != oi) && (i != h)) {
- if (h) {
- selectRect(x - k, y - h, x + k, y - h, set);
- selectRect(x - k, y + h, x + k, y + h, set);
- }
- else selectRect(x - k, y, x + k, y, set);
- oh = h;
- }
- ix = ix + iy / ry;
- iy = iy - ix / ry;
- } while(i > h);
- }
- }
- void SceneEditLayer::selectRect(int x1, int y1, int x2, int y2, int set) { start_func
- Rect rect = createRect(x1, y1, x2, y2);
- Rect bound = { 0, 0, layerWidth, layerHeight };
- if (intersectRects(rect, bound)) {
- y1 = rect.y;
- y2 = y1 + rect.h - 1;
- x1 = rect.x;
- x2 = x1 + rect.w - 1;
-
- for (; y1 <= y2; ++y1) {
- // Place in bitarray terms
- Uint8 bit = 1 << (x1 & 7);
- Uint8* selData = selected + (x1 >> 3) + y1 * selectedPitch;
-
- for (int x = x1; x <= x2; ++x) {
- if (set) {
- *selData |= bit;
- }
- else {
- *selData &= ~bit;
- }
- bit <<= 1;
- if (bit == 0) {
- bit = 1;
- ++selData;
- }
- }
- }
- }
- }
- // @TODO: account for selection masking
- void SceneEditLayer::layerDrawEllipse(int x, int y, int rx, int ry, Uint32* data, Uint32 mask, Uint32 set) const { start_func
- // (skip if nothing being drawn)
- if ((mask == 0xFFFFFFFF) && (set == 0)) return;
- // ** Code modified from sge_primitives.cpp **
- int ix, iy;
- int h, i, j, k;
- int oh, oi, oj, ok;
- Uint32* target;
- if (rx < 1) rx = 1;
- if (ry < 1) ry = 1;
- h = i = j = k = 0xFFFF;
-
- #define PUTPIXEL(x, y) {\
- if (((x) >= 0) && ((x) < layerWidth) && ((y) >= 0) && ((y) < layerHeight)) {\
- target = data + (x) + (y) * layerWidth;\
- *target = (*target & mask) | set;\
- }\
- }
- if (rx > ry) {
- ix = 0;
- iy = rx * 64;
- do {
- oh = h;
- oi = i;
- oj = j;
- ok = k;
- h = (ix + 32) >> 6;
- i = (iy + 32) >> 6;
- j = (h * ry) / rx;
- k = (i * ry) / rx;
- if (((h != oh) || (k != ok)) && (h < oi)) {
- PUTPIXEL(x + h, y + k);
- if (h) PUTPIXEL(x - h, y + k);
- if (k) {
- PUTPIXEL(x + h, y - k);
- if (h) PUTPIXEL(x - h, y - k);
- }
- }
- if (((i != oi) || (j != oj)) && (h < i)) {
- PUTPIXEL(x + i, y + j);
- if (i) PUTPIXEL(x - i, y + j);
- if (j) {
- PUTPIXEL(x + i, y - j);
- if (i) PUTPIXEL(x - i, y - j);
- }
- }
- ix = ix + iy / rx;
- iy = iy - ix / rx;
- } while (i > h);
- }
- else {
- ix = 0;
- iy = ry * 64;
- do {
- oh = h;
- oi = i;
- oj = j;
- ok = k;
- h = (ix + 32) >> 6;
- i = (iy + 32) >> 6;
- j = (h * rx) / ry;
- k = (i * rx) / ry;
- if (((j != oj) || (i != oi)) && (h < i)) {
- PUTPIXEL(x + j, y + i);
- if (j) PUTPIXEL(x - j, y + i);
- if (i) {
- PUTPIXEL(x + j, y - i);
- if (j) PUTPIXEL(x - j, y - i);
- }
- }
- if (((k != ok) || (h != oh)) && (h < oi)) {
- PUTPIXEL(x + k, y + h);
- if (k) PUTPIXEL(x - k, y + h);
- if (h) {
- PUTPIXEL(x + k, y - h);
- if (k) PUTPIXEL(x - k, y - h);
- }
- }
- ix = ix + iy / ry;
- iy = iy - ix / ry;
- } while(i > h);
- }
- }
- // @TODO: account for selection masking
- void SceneEditLayer::layerDrawEllipseFill(int x, int y, int rx, int ry, Uint32* data, Uint32 mask, Uint32 set) const { start_func
- // (skip if nothing being drawn)
- if ((mask == 0xFFFFFFFF) && (set == 0)) return;
- // ** Code modified from sge_primitives.cpp **
- int ix, iy;
- int h, i, j, k;
- int oh, oi, oj, ok;
- if (rx < 1) rx = 1;
- if (ry < 1) ry = 1;
- oh = oi = oj = ok = 0xFFFF;
- if (rx > ry) {
- ix = 0;
- iy = rx * 64;
- do {
- h = (ix + 32) >> 6;
- i = (iy + 32) >> 6;
- j = (h * ry) / rx;
- k = (i * ry) / rx;
- if ((k != ok) && (k != oj)) {
- if (k) {
- layerDrawRect(x - h, y - k, x + h, y - k, data, mask, set);
- layerDrawRect(x - h, y + k, x + h, y + k, data, mask, set);
- }
- else layerDrawRect(x - h, y, x + h, y, data, mask, set);
- ok = k;
- }
- if ((j != oj) && (j != ok) && (k != j)) {
- if (j) {
- layerDrawRect(x - i, y - j, x + i, y - j, data, mask, set);
- layerDrawRect(x - i, y + j, x + i, y + j, data, mask, set);
- }
- else layerDrawRect(x - i, y, x + i, y, data, mask, set);
- oj = j;
- }
- ix = ix + iy / rx;
- iy = iy - ix / rx;
- } while (i > h);
- }
- else {
- ix = 0;
- iy = ry * 64;
- do {
- h = (ix + 32) >> 6;
- i = (iy + 32) >> 6;
- j = (h * rx) / ry;
- k = (i * rx) / ry;
- if ((i != oi) && (i != oh)) {
- if (i) {
- layerDrawRect(x - j, y - i, x + j, y - i, data, mask, set);
- layerDrawRect(x - j, y + i, x + j, y + i, data, mask, set);
- }
- else layerDrawRect(x - j, y, x + j, y, data, mask, set);
- oi = i;
- }
- if ((h != oh) && (h != oi) && (i != h)) {
- if (h) {
- layerDrawRect(x - k, y - h, x + k, y - h, data, mask, set);
- layerDrawRect(x - k, y + h, x + k, y + h, data, mask, set);
- }
- else layerDrawRect(x - k, y, x + k, y, data, mask, set);
- oh = h;
- }
- ix = ix + iy / ry;
- iy = iy - ix / ry;
- } while(i > h);
- }
- }
- // @TODO: account for selection masking
- // @TODO: additional matchmask to cover ext data as well
- Rect SceneEditLayer::layerFloodFill(int x, int y, Uint32 matchMask, Uint32* data1, Uint32 mask1, Uint32 set1, Uint32* data2, Uint32 mask2, Uint32 set2) const { start_func
- assert(data1);
- // Min/Max area
- Rect result = { 0, 0, 0, 0 };
- // Clip area
- if ((x < 0) || (y < 0) || (x >= layerWidth) || (y >= layerHeight)) return result;
-
- // Extreme points
- int x1 = x;
- int x2 = x;
- int y1 = y;
- int y2 = y;
-
- // Stack
- #define FLOOD_STACK_SIZE 250
- struct {
- Uint32* d1;
- Uint32* d2;
- int x;
- int y;
- int yD;
- } floodStack[FLOOD_STACK_SIZE];
- int stackPos = 0;
-
- #define PUSH(dp1, dp2, xp, yp, ydiff) {\
- if (stackPos < FLOOD_STACK_SIZE) {\
- floodStack[stackPos].d1 = dp1;\
- floodStack[stackPos].d2 = dp2;\
- floodStack[stackPos].x = xp;\
- floodStack[stackPos].y = yp;\
- floodStack[stackPos++].yD = ydiff;\
- }\
- }
- #define POP(dp1, dp2, xp, yp, ydiff) {\
- assert(stackPos);\
- dp1 = floodStack[--stackPos].d1;\
- dp2 = floodStack[stackPos].d2;\
- xp = floodStack[stackPos].x;\
- yp = floodStack[stackPos].y;\
- ydiff = floodStack[stackPos].yD;\
- }
- // Starting point etc.
- Uint32* dataPoint1 = data1 + x + y * layerWidth;
- Uint32* dataPoint2 = NULL;
- if (data2) dataPoint2 = data2 + x + y * layerWidth;
- // Determine what we're matching against, don't fill if matches what we're doing
- Uint32 target = *dataPoint1 & matchMask;
- if (((target & mask1) | set1) == target) return result;
- // Work areas
- int top, bottom;
- int lX;
- int yDiff;
-
- // Push starting point
- PUSH(dataPoint1, dataPoint2, x, y, 0);
-
- while (stackPos) {
- // Next point to fill, then scan left and right
- POP(dataPoint1, dataPoint2, x, y, yDiff);
- dataPoint1 += yDiff * layerWidth;
- if (dataPoint2) dataPoint2 += yDiff * layerWidth;
- y += yDiff;
-
- // Don't fill given point directly- instead, we'll scan it manually in the second loop
- // Update extreme points- y
- if (y < y1) y1 = y;
- if (y > y2) y2 = y;
-
- // Check both top and bottom for matches
- top = bottom = 1;
-
- // Fill as far left as possible
- lX = x;
- while ((lX > 0) && ((dataPoint1[-1] & matchMask) == target)) {
- --lX;
- --dataPoint1;
- *dataPoint1 = (*dataPoint1 & mask1) | set1;
- if (dataPoint2) {
- --dataPoint2;
- *dataPoint2 = (*dataPoint2 & mask2) | set2;
- }
-
- // Is point above fillable?
- if ((y > 0) && ((dataPoint1[-layerWidth] & matchMask) == target)) {
- // Are we pushing "above" points right now?
- if (top) {
- // Push onto stack
- PUSH(dataPoint1, dataPoint2, lX, y, -1);
- top = 0;
- }
- }
- // Not fillable, we will now push the next "above" point we find
- else top = 1;
-
- // Is point below fillable?
- if ((y < layerHeight - 1) && ((dataPoint1[layerWidth] & matchMask) == target)) {
- // Are we pushing "below" points right now?
- if (bottom) {
- // Push onto stack
- PUSH(dataPoint1, dataPoint2, lX, y, 1);
- bottom = 0;
- }
- }
- // Not fillable, we will now push the next "below" point we find
- else bottom = 1;
- }
-
- // Update extreme left point
- if (lX < x1) x1 = lX;
-
- // Recenter, minus one, so that we scan the center/given point as well
- --x;
- dataPoint1 += x - lX;
- if (dataPoint2) dataPoint2 += x - lX;
- top = bottom = 1;
-
- // Fill as far right as possible; this loop intentionally catches our first, central point
- while ((x < layerWidth - 1) && ((dataPoint1[1] & matchMask) == target)) {
- ++x;
- ++dataPoint1;
- *dataPoint1 = (*dataPoint1 & mask1) | set1;
- if (dataPoint2) {
- ++dataPoint2;
- *dataPoint2 = (*dataPoint2 & mask2) | set2;
- }
-
- // Is point above fillable?
- if ((y > 0) && ((dataPoint1[-layerWidth] & matchMask) == target)) {
- // Are we pushing "above" points right now?
- if (top) {
- // Push onto stack
- PUSH(dataPoint1, dataPoint2, x, y, -1);
- top = 0;
- }
- }
- // Not fillable, we will now push the next "above" point we find
- else top = 1;
-
- // Is point below fillable?
- if ((y < layerHeight - 1) && ((dataPoint1[layerWidth] & matchMask) == target)) {
- // Are we pushing "below" points right now?
- if (bottom) {
- // Push onto stack
- PUSH(dataPoint1, dataPoint2, x, y, 1);
- bottom = 0;
- }
- }
- // Not fillable, we will now push the next "below" point we find
- else bottom = 1;
- }
- // Update extreme right point
- if (x > x2) x2 = x;
- }
-
- result.x = x1;
- result.y = y1;
- result.w = x2 - x1 + 1;
- result.h = y2 - y1 + 1;
- return result;
- }
- // @TODO: account for selection masking
- Rect SceneEditLayer::layerMatchFill(int x, int y, Uint32 matchMask, Uint32* data1, Uint32 mask1, Uint32 set1, Uint32* data2, Uint32 mask2, Uint32 set2) const { start_func
- assert(data1);
- // Min/Max area
- Rect result = { 0, 0, 0, 0 };
- // Clip area
- if ((x < 0) || (y < 0) || (x >= layerWidth) || (y >= layerHeight)) return result;
-
- // Extreme points
- int x1 = x;
- int x2 = x;
- int y1 = y;
- int y2 = y;
-
- // Determine what we're matching against, don't fill if matches what we're doing
- Uint32 target = data1[x + y * layerWidth] & matchMask;
- if (((target & mask1) | set1) == target) return result;
- for (y = 0; y < layerHeight; ++y) {
- for (x = 0; x < layerWidth; ++x) {
- if ((*data1 & matchMask) == target) {
- *data1 = (*data1 & mask1) | set1;
- if (data2) *data2 = (*data2 & mask2) | set2;
-
- // Update extreme points
- if (y < y1) y1 = y;
- if (y > y2) y2 = y;
- if (x < x1) x1 = x;
- if (x > x2) x2 = x;
- }
-
- ++data1;
- if (data2) ++data2;
- }
- }
-
- result.x = x1;
- result.y = y1;
- result.w = x2 - x1 + 1;
- result.h = y2 - y1 + 1;
- return result;
- }
- // @TODO: account for selection masking
- void SceneEditLayer::layerDrawRect(int x1, int y1, int x2, int y2, Uint32* data, Uint32 mask, Uint32 set) const { start_func
- assert(data);
- // (skip if nothing being drawn)
- if ((mask == 0xFFFFFFFF) && (set == 0)) return;
- Rect affect = createRect(x1, y1, x2, y2);
- Rect bound = { 0, 0, layerWidth, layerHeight };
- if (!intersectRects(affect, bound)) return;
-
- data += affect.y * layerWidth + affect.x;
- for (int row = affect.h; row > 0; --row) {
- for (int col = affect.w; col > 0; --col) {
- *data = (*data & mask) | set;
- ++data;
- }
- data += layerWidth - affect.w;
- }
- }
- void SceneEditLayer::layerDrawBox(int x1, int y1, int x2, int y2, Uint32* data, Uint32 mask, Uint32 set) const { start_func
- layerDrawRect(x1, y1, x2, y1, data, mask, set);
- layerDrawRect(x1, y1, x1, y2, data, mask, set);
- layerDrawRect(x2, y1, x2, y2, data, mask, set);
- layerDrawRect(x1, y2, x2, y2, data, mask, set);
- }
- // @TODO: account for selection masking
- void SceneEditLayer::layerDrawLine(int x1, int y1, int x2, int y2, Uint32* data, Uint32 mask, Uint32 set) const { start_func
- assert(data);
-
- // (skip if nothing being drawn)
- if ((mask == 0xFFFFFFFF) && (set == 0)) return;
- Sint16 x = x1;
- Sint16 y = y1;
- Sint16 dy = y2 - y1;
- Sint16 dx = x2 - x1;
-
- Sint16 G, DeltaG1, DeltaG2;//, minG, maxG;
- Sint16 inc = 1;
- if (abs(dy) < abs(dx)) {
- if (dx < 0) {
- dx = -dx;
- dy = -dy;
-
- y1 = y2;
- y2 = y;
- y = y1;
-
- x1 = x2;
- x2 = x;
- x = x1;
- }
- if (dy < 0) {
- dy = -dy;
- inc = -1;
- }
-
- G = 2 * dy - dx;
- DeltaG1 = 2 * (dy - dx);
- DeltaG2 = 2 * dy;
-
- data += y * layerWidth + x;
- if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = (*data & mask) | set;
- while (++x <= x2) {
- ++data;
- if (G > 0) { G += DeltaG1; y += inc; data += inc * layerWidth; }
- else G += DeltaG2;
-
- if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = (*data & mask) | set;
- }
- }
- else {
- if (dy < 0) {
- dx = -dx;
- dy = -dy;
-
- y1 = y2;
- y2 = y;
- y = y1;
-
- x1 = x2;
- x2 = x;
- x = x1;
- }
- if (dx < 0) {
- dx = -dx;
- inc = -1;
- }
-
- G = 2 * dx - dy;
- //minG = maxG = G;
- DeltaG1 = 2 * (dx - dy);
- DeltaG2 = 2 * dx;
-
- data += y * layerWidth + x;
- if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = (*data & mask) | set;
- while (++y <= y2) {
- data += layerWidth;
- if (G > 0) { G += DeltaG1; x += inc; data += inc; }
- else G += DeltaG2;
-
- if ((x >= 0) && (y >= 0) && (x < layerWidth) && (y < layerHeight)) *data = (*data & mask) | set;
- }
- }
- }
- void SceneEditLayer::swapSelectionParameters(int& xoffs, int& yoffs, int& mode) { start_func
- swap(xoffs, selectionXOffs);
- swap(yoffs, selectionYOffs);
- if (mode != selectionMode) {
- if (mode == SELECTION_OUTLINE) {
- refreshData(0);
- }
- else {
- Uint32 affectBit = 1;
- for (int pos = 0; pos < numLayers; ++pos, affectBit <<= 1) {
- if (layersAffect & affectBit) {
- memSet32(layerEdit[pos][0], Layer::LAYER_TILE_DEFAULT, layerWidth * layerHeight);
- if (layerEdit[pos][1]) memSet32(layerEdit[pos][1], Layer::LAYER_EXT_DEFAULT, layerWidth * layerHeight);
- if (layerEdit[pos][2]) memSet32(layerEdit[pos][2], Layer::LAYER_FX_DEFAULT, layerWidth * layerHeight);
- }
- }
- }
- }
- swap(mode, selectionMode);
- // Refresh
- fixSelectionRect();
- setDirty(1);
- }
- Window::WindowType SceneEditLayer::windowType() const { start_func
- return WINDOW_CLIENT;
- }
- void SceneEditLayer::setDirtySelectedSpawns() { start_func
- setDirtyPixelBox(selectedSpawnRect.x, selectedSpawnRect.y,
- selectedSpawnRect.x + selectedSpawnRect.w - 1,
- selectedSpawnRect.y + selectedSpawnRect.h - 1);
- }
- void SceneEditLayer::copySpawnSelection() { start_func
- set<int>::iterator pos = selectedSpawns.begin();
- set<int>::iterator end = selectedSpawns.end();
- vector<const SpawnEdit*> toCopy;
- vector<int> toCopyLayers;
-
- while (pos != end) {
- // Find spawn
- SpawnEdit* spawn = world->findSpawn(*pos);
- if (spawn) {
- // Determine layer
- int lPos = scene->findLayer(spawn->getLayer());
- if (lPos >= 0) {
- int bit = 1 << lPos;
- if (layersAffect & bit) {
- toCopy.push_back(spawn);
- toCopyLayers.push_back(lPos);
- }
- }
- }
- ++pos;
- }
-
- clipboardCopy(toCopy, toCopyLayers);
- }
- void SceneEditLayer::deleteSpawnSelection() throw_Undo { start_func
- set<int>::iterator pos = selectedSpawns.begin();
- set<int>::iterator end = selectedSpawns.end();
- world->undo.preUndoBlock();
- undoStoreSpawnSelect();
- while (pos != end) {
- // Find spawn
- SpawnEdit* spawn = world->findSpawn(*pos);
- if (spawn) {
- // Determine layer
- int lPos = scene->findLayer(spawn->getLayer());
- if (lPos >= 0) {
- int bit = 1 << lPos;
- if (layersAffect & bit) {
- spawn->getLayer()->deleteSpawn(spawn, myFrame, this); // Exception point (undoes other deletions for us)
- }
- }
- }
- ++pos;
- }
- setDirtySelectedSpawns();
- selectedSpawns.clear();
- selectedSpawnRect.w = 0;
- world->undo.postUndoBlock();
- }
- void SceneEditLayer::clearSpawnSelection(int storeUndo) throw_Undo { start_func
- if (storeUndo) undoStoreSpawnSelect();
- if (!selectedSpawns.empty()) {
- setDirtySelectedSpawns();
- selectedSpawns.clear();
- selectedSpawnRect.w = 0;
- }
- }
- void SceneEditLayer::updatedSpawnSelection() { start_func
- recheckSpawnSelection();
- setDirty(1);
- }
- void SceneEditLayer::recheckSpawnSelection() { start_func
- set<int>::iterator pos = selectedSpawns.begin();
- set<int>::iterator end = selectedSpawns.end();
- set<int>::iterator check;
- selectedSpawnRect.w = 0;
- while (pos != end) {
- check = pos;
- ++pos;
-
- // This spawn still in one of our affected layers?
- int kill = 1;
- SpawnEdit* spawn = world->findSpawn(*check);
- if (spawn) {
- // Determine layer
- int lPos = scene->findLayer(spawn->getLayer());
- if (lPos >= 0) {
- int bit = 1 << lPos;
- if (layersAffect & bit) {
- Rect spawnRect = { spawn->getX(), spawn->getY(), spawn->getW(), spawn->getH() };
- boundRects(selectedSpawnRect, spawnRect);
- kill = 0;
- }
- }
- }
- if (kill) selectedSpawns.erase(check);
- }
- }
- void SceneEditLayer::undoStoreSpawnSelect() throw_Undo { start_func
- world->undo.storeUndoLayerSpawnSelection(&selectedSpawns, myFrame);
- }
- int SceneEditLayer::isInSpawnSelection(int x, int y) { start_func
- // Find spawns in one of our affected layers
- set<int>::iterator pos = selectedSpawns.begin();
- set<int>::iterator end = selectedSpawns.end();
- while (pos != end) {
- // Find spawn
- SpawnEdit* spawn = world->findSpawn(*pos);
- if (spawn) {
- // Determine layer
- int lPos = scene->findLayer(spawn->getLayer());
- if (lPos >= 0) {
- int bit = 1 << lPos;
- if (layersAffect & bit) {
- if ((x >= spawn->getX()) &&
- (y >= spawn->getY()) &&
- (x < spawn->getX() + spawn->getW()) &&
- (y < spawn->getY() + spawn->getH()))
- return spawn->getId();
- }
- }
- }
- ++pos;
- }
- return 0;
- }
- void SceneEditLayer::startToolSpawnSelectionDrag() { start_func
- startToolOnMove = 0;
- if (toolActive) return;
- toolActive = TOOLS_SELECTITEMDRAG;
- toolStartX = cursorSpriteX;
- toolStartY = cursorSpriteY;
- toolCtrl = SDL_GetModState() & KMOD_CTRL;
- toolAlt = SDL_GetModState() & KMOD_ALT;
- mousePointer();
- dragTool(1);
- }
- void SceneEditLayer::selectSpawnRect(int x1, int y1, int x2, int y2, int select, int selectAll) { start_func
- Rect area = createRect(x1, y1, x2, y2);
-
- int bit = 1;
- for (int lPos = 0; lPos < numLayers; ++lPos, bit <<= 1) {
- if (layersAffect & bit) {
- // Check all spawns in this layer
- LayerEdit* layer = scene->getLayerEdit(lPos);
- for (int sPos = layer->getSpawnCount() - 1; sPos >= 0; --sPos) {
- SpawnEdit* spawn = layer->getSpawn(sPos);
- Rect spawnRect = { spawn->getX(), spawn->getY(), spawn->getW(), spawn->getH() };
- if ((selectAll) || (intersectRects(spawnRect, area))) {
- if (select) selectedSpawns.insert(spawn->getId());
- else selectedSpawns.erase(spawn->getId());
- }
- }
- }
- }
- }
- void SceneEditLayer::moveSpawnSelection(int byX, int byY, int skipUndo) { start_func
- set<int>::iterator pos = selectedSpawns.begin();
- set<int>::iterator end = selectedSpawns.end();
-
- while (pos != end) {
- // Find spawn
- SpawnEdit* spawn = world->findSpawn(*pos);
- if (spawn) {
- // Determine layer
- int lPos = scene->findLayer(spawn->getLayer());
- if (lPos >= 0) {
- int bit = 1 << lPos;
- if (layersAffect & bit) {
- spawn->setPos(spawn->getX() + byX, spawn->getY() + byY, skipUndo, myFrame, this);
- }
- }
- }
- ++pos;
- }
-
- selectedSpawnRect.x += byX;
- selectedSpawnRect.y += byY;
- }
|