12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373 |
- /* 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;
- }
|