#include "TileEditor.h" #include "TilePicker.h" #include "ColorWells.h" #include "ColorEditor.h" #include "PaletteEditor.h" #include "BorderPanel.h" #include "labels.h" #include "SelectionManager.h" #include "GridOverlay.h" extern ColorWells *mainColorStack; extern TilePicker *mainTilePicker; extern ColorEditor *mainColorEditor; extern PaletteEditor *mainPaletteEditor; extern int gameWidth, gameHeight; extern TextGL *largeTextFixed; template <> void SizeLimitedVector::deleteElementOfType( Tile inElement ) { // no delete necessary } TileEditor::TileEditor( ScreenGL *inScreen ) : Editor( inScreen ), mUndoStack( MAX_UNDOS, false ) { mCloseButton->setToolTip( "tip_closeEdit_tile" ); /* LabelGL *titleLabel = new LabelGL( 0.75, 0.5, 0.25, 0.1, "Tile Editor", largeText ); mSidePanel->add( titleLabel ); */ mSidePanel->add( mainColorStack ); mainColorStack->addActionListener( this ); mSidePanel->add( mainTilePicker ); mainTilePicker->addActionListener( this ); mEditColorButton = new EditButtonGL( mainColorStack->getAnchorX() - 9, mainColorStack->getAnchorY() + mainColorStack->getHeight() - 7, 8, 8 ); mSidePanel->add( mEditColorButton ); mEditColorButton->addActionListener( this ); mEditColorButton->setToolTip( "tip_edit_color" ); mEditPaletteButton = new EditButtonGL( mainColorStack->getAnchorX() - 9, mainColorStack->getAnchorY() + mainColorStack->getHeight() - 51, 8, 8 ); mSidePanel->add( mEditPaletteButton ); mEditPaletteButton->addActionListener( this ); mEditPaletteButton->setToolTip( "tip_edit_palette" ); /* // 1-pixel wide white border // inner panel to provide a 1-pixel wide black gap BorderPanel *workingColorBorderPanel = new BorderPanel( 256, 206, 48, 14, new Color( 0, 0, 0, 1 ), new Color( 1, 1, 1, 1 ), 1 ); // smaller to leave black gap GUIPanelGL *workingColorPanel = new GUIPanelGL( 258, 208, 44, 10, mWorkingColor ); mSidePanel->add( workingColorBorderPanel ); workingColorBorderPanel->add( workingColorPanel ); mAddButton = new AddButtonGL( 272, 184, 16, 16 ); mSidePanel->add( mAddButton ); mAddButton->addActionListener( this ); */ double offset = P; double buttonSize = (gameHeight - 2 * offset - 8) / P; rgbaColor c = { { 0,0,0,255 } }; for( int y=0; yadd( mButtonGrid[y][x] ); mButtonGrid[y][x]->addActionListener( this ); } } mToolSet = new DrawToolSet( 2, 42 ); mMainPanel->add( mToolSet ); mToolSet->addActionListener( this ); mSelectionButton = new SelectableButtonGL( new Sprite( "selection.tga", true ), 1, mToolSet->getAnchorX() + mToolSet->getWidth() + 5, 42, 20, 20 ); mMainPanel->add( mSelectionButton ); mSelectionButton->setSelected( false ); mSelectionButton->addActionListener( this ); mSelectionButton->setToolTip( "tip_selection" ); EightPixelLabel *fieldLabel = new EightPixelLabel( 150, 54, "tileSetName" ); mMainPanel->add( fieldLabel ); int fieldHeight = 8; int fieldWidth = 8 * 10; const char *defaultText = "default"; mSetNameField = new TextFieldGL( 150, 43, fieldWidth, fieldHeight, 1, defaultText, largeTextFixed, new Color( 0.75, 0.75, 0.75 ), new Color( 0.75, 0.75, 0.75 ), new Color( 0.15, 0.15, 0.15 ), new Color( 0.75, 0.75, 0.75 ), 10, false ); mMainPanel->add( mSetNameField ); mSetNameField->setFocus( true ); //mSetNameField->lockFocus( true ); mSetNameField->setCursorPosition( strlen( defaultText ) ); mSetNameField->addActionListener( this ); // center add button double gridEdge = 8 + P * buttonSize; double extra = gameHeight - gridEdge; // center it vertically on tile picker double addY = mainTilePicker->getAnchorY() + mainTilePicker->getHeight() - 15; double sideButtonsX = gridEdge + (extra - 16) / 2; mAddButton = new AddButtonGL( sideButtonsX, addY, 16, 16 ); mMainPanel->add( mAddButton ); mAddButton->addActionListener( this ); mAddButton->setToolTip( "tip_addTile" ); mAddAction = false; double miniButtonSize = P + 4; mMiniViewButton = new SpriteButtonGL( NULL, 1, gridEdge + ( extra - miniButtonSize ) / 2, addY - 24, miniButtonSize, miniButtonSize ); mMainPanel->add( mMiniViewButton ); mTransformToolSet = new TransformToolSet( sideButtonsX, mMiniViewButton->getAnchorY() - 10 - 100, true ) ; mMainPanel->add( mTransformToolSet ); mTransformToolSet->addActionListener( this ); double undoButtonY = gameWidth - ( 48 + P * buttonSize ); mUndoButton = new UndoButtonGL( sideButtonsX, undoButtonY, 16, 16 ); mMainPanel->add( mUndoButton ); mUndoButton->addActionListener( this ); mUndoButton->setEnabled( false ); mRedoButton = new RedoButtonGL( sideButtonsX, undoButtonY + 19, 16, 16 ); mMainPanel->add( mRedoButton ); mRedoButton->addActionListener( this ); mRedoButton->setEnabled( false ); setTileToEdit( mainTilePicker->getSelectedResource() ); mPenDown = false; // fully-opaque gray to avoid color distortions Color gridColor( 0.25, 0.25, 0.25, 1.0 ); GridOverlay *overlay = new GridOverlay( 8, gameWidth - ( 48 + P * buttonSize ), P * buttonSize, P * buttonSize, P, gridColor ); mMainPanel->add( overlay ); postConstruction(); } TileEditor::~TileEditor() { mSidePanel->remove( mainColorStack ); mSidePanel->remove( mainTilePicker ); } void TileEditor::setTileToEdit( Tile inTile ) { mTileToEdit = inTile; for( int y=0; ysetColor( mTileToEdit.getColor( x, y ) ); } } refreshMiniView(); char *name = mTileToEdit.getTileSetName(); mSetNameField->setText( name ); mSetNameField->setCursorPosition( strlen( name ) ); delete [] name; } void TileEditor::refreshMiniView() { // don't use cached version mMiniViewButton->setSprite( mTileToEdit.getSprite( false, false ) ); } char TileEditor::recursiveFill( int inX, int inY, rgbaColor inOldColor, rgbaColor inNewColor, drawTool inTool ) { if( equal( mTileToEdit.getColor( inX, inY ), inOldColor ) && !equal( mTileToEdit.getColor( inX, inY ), inNewColor ) ) { mButtonGrid[inY][inX]->setColor( inNewColor ); mTileToEdit.editTile( inX, inY, inNewColor ); // call on neighbors if( inTool == fill || inTool == horLine ) { if( inX > 0 ) { recursiveFill( inX - 1, inY, inOldColor, inNewColor, inTool ); } if( inX < P - 1 ) { recursiveFill( inX + 1, inY, inOldColor, inNewColor, inTool ); } } if( inTool == fill || inTool == verLine ) { if( inY > 0 ) { recursiveFill( inX, inY - 1, inOldColor, inNewColor, inTool ); } if( inY < P - 1 ) { recursiveFill( inX, inY + 1, inOldColor, inNewColor, inTool ); } } return true; } return false; } char TileEditor::recursiveSelectionFill( int inX, int inY, rgbaColor inOldColor, char inOldSelection, char inNewSelection, drawTool inTool ) { if( equal( mTileToEdit.getColor( inX, inY ), inOldColor ) && SelectionManager::isInSelection( inX, inY ) == inOldSelection && SelectionManager::isInSelection( inX, inY ) != inNewSelection ) { SelectionManager::toggleSelection( inX, inY, inNewSelection ); mButtonGrid[inY][inX]->setSelection( inNewSelection ); if( inNewSelection ) { SelectionManager::setColor( inX, inY, mTileToEdit.getColor( inX, inY ) ); SelectionManager::setTrans( inX, inY, false ); } // call on neighbors if( inTool == fill || inTool == horLine ) { if( inX > 0 ) { recursiveSelectionFill( inX - 1, inY, inOldColor, inOldSelection, inNewSelection, inTool ); } if( inX < P - 1 ) { recursiveSelectionFill( inX + 1, inY, inOldColor, inOldSelection, inNewSelection, inTool ); } } if( inTool == fill || inTool == verLine ) { if( inY > 0 ) { recursiveSelectionFill( inX, inY - 1, inOldColor, inOldSelection, inNewSelection, inTool ); } if( inY < P - 1 ) { recursiveSelectionFill( inX, inY + 1, inOldColor, inOldSelection, inNewSelection, inTool ); } } return true; } return false; } void TileEditor::toggleSelection() { mSelectionButton->setSelected( ! mSelectionButton->getSelected() ); char showSel = mSelectionButton->getSelected(); for( int y=0; ysetSelection( SelectionManager::isInSelection( x, y ) && showSel ); } } // commit selection only when it is turned on // (right before it is turned off, the last edits of selection have updated // the selected colors) if( showSel ) { // copy colors for( int y=0; y setOverlay( false ); } } } void TileEditor::colorEditorClosed() { // it might have been closed by an EditPalette button press if( mainColorEditor->mEditPalettePressed ) { showPaletteEditor(); } } void TileEditor::actionPerformed( GUIComponent *inTarget ) { // superclass Editor::actionPerformed( inTarget ); if( inTarget == mainColorStack ) { // new color picked on stack } else if( inTarget == mainTilePicker ) { if( ! mAddAction && ! mainTilePicker->wasLastActionFromPress() ) { // will change tile mUndoStack.push_back( mTileToEdit ); mUndoButton->setEnabled( true ); setTileToEdit( mainTilePicker->getSelectedResource() ); // new branch... "redo" future now impossible mRedoStack.deleteAll(); mRedoButton->setEnabled( false ); } } else if( inTarget == mSetNameField ) { mUndoStack.push_back( mTileToEdit ); mUndoButton->setEnabled( true ); // new branch... "redo" future now impossible mRedoStack.deleteAll(); mRedoButton->setEnabled( false ); mTileToEdit.editTileSetName( mSetNameField->getText() ); } else if( inTarget == mAddButton ) { addTile(); } else if( inTarget == mEditColorButton ) { mainColorEditor->setEditPaletteButtonVisible( true ); showColorEditor(); } else if( inTarget == mEditPaletteButton ) { showPaletteEditor(); } else if( inTarget == mUndoButton ) { int lastIndex = mUndoStack.size() - 1; Tile last = *( mUndoStack.getElement( lastIndex ) ); mUndoStack.deleteElement( lastIndex ); if( mUndoStack.size() == 0 ) { mUndoButton->setEnabled( false ); } mRedoStack.push_back( mTileToEdit ); mRedoButton->setEnabled( true ); setTileToEdit( last ); } else if( inTarget == mRedoButton ) { int nextIndex = mRedoStack.size() - 1; Tile next = *( mRedoStack.getElement( nextIndex ) ); mRedoStack.deleteElement( nextIndex ); if( mRedoStack.size() == 0 ) { mRedoButton->setEnabled( false ); } mUndoStack.push_back( mTileToEdit ); mUndoButton->setEnabled( true ); setTileToEdit( next ); } else if( inTarget == mSelectionButton ) { toggleSelection(); } else if( inTarget == mTransformToolSet ) { mUndoStack.push_back( mTileToEdit ); mUndoButton->setEnabled( true ); // new branch... "redo" future now impossible mRedoStack.deleteAll(); mRedoButton->setEnabled( false ); Tile oldTileState = mTileToEdit; switch( mTransformToolSet->getLastPressed() ) { case flipH: { for( int y=0; ysetColor( flipColor ); mTileToEdit.editTile( x, y, flipColor ); } } } break; case flipV: { for( int y=0; ysetColor( flipColor ); mTileToEdit.editTile( x, y, flipColor ); } } } break; case rotateCCW: { for( int y=0; ysetColor( flipColor ); mTileToEdit.editTile( x, y, flipColor ); } } } break; case rotateCW: { for( int y=0; ysetColor( flipColor ); mTileToEdit.editTile( x, y, flipColor ); } } } break; case clear: { rgbaColor black; black.comp.r = 0; black.comp.g = 0; black.comp.b = 0; black.comp.a = 255; for( int y=0; ysetColor( black ); mTileToEdit.editTile( x, y, black ); } } } break; case colorize: { rgbaColor c = mainColorStack->getSelectedColor(); for( int y=0; ysetColor( oldColor ); mTileToEdit.editTile( x, y, oldColor ); } } } break; } refreshMiniView(); } else if( inTarget == mToolSet ) { clearStampOverlay(); } else if( !mainColorEditor->getDragging() ){ // check grid // but only if not in the middle of drag-picking a color in the editor char found = false; for( int y=0; y

wasLastActionHover() ) { found = true; Tile oldTileState = mTileToEdit; char changed = false; switch( mToolSet->getSelected() ) { case pen: { if( mSelectionButton->getSelected() ) { // edit selection with pen if( !mPenDown ) { // set ink until released mSelectionInk = ! SelectionManager:: isInSelection( x, y ); mPenDown = true; changed = true; } // use ink already set SelectionManager::toggleSelection( x, y, mSelectionInk ); mButtonGrid[y][x]->setSelection( mSelectionInk ); if( mSelectionInk ) { SelectionManager::setColor( x, y, mTileToEdit.getColor( x, y ) ); SelectionManager::setTrans( x, y, false ); } } else { if( mainColorEditor->isVisible() ) { // push edited color onto stack first mainColorEditor->addColor(); } rgbaColor c = mainColorStack->getSelectedColor(); if( ! equal( c, mTileToEdit.getColor( x, y ) ) ) { mButtonGrid[y][x]->setColor( c ); mTileToEdit.editTile( x, y, c ); refreshMiniView(); // don't count single pen dots as undoable // until pen is released // save undo state only on on initial // presses if( !mPenDown ) { mPenDown = true; changed = true; } } if( !mButtonGrid[y][x]->isPressed() ) { // a release mPenDown = false; } } } break; case horLine: case verLine: case fill: if( mSelectionButton->getSelected() ) { if( !mPenDown ) { mSelectionInk = ! SelectionManager:: isInSelection( x, y ); } recursiveSelectionFill( x, y, mTileToEdit.getColor( x, y ), SelectionManager:: isInSelection( x, y ), mSelectionInk, mToolSet->getSelected() ); if( !mPenDown ) { mPenDown = true; } if( !mButtonGrid[y][x]->isPressed() ) { // a release mPenDown = false; } } else { if( mainColorEditor->isVisible() ) { // push edited color onto stack first mainColorEditor->addColor(); } changed = recursiveFill( x, y, mTileToEdit.getColor( x, y ), mainColorStack->getSelectedColor(), mToolSet->getSelected() ); refreshMiniView(); } break; case pickColor: mainColorStack->pushColor( mTileToEdit.getColor( x, y ) ); break; case stamp: { if( !mPenDown ) { changed = true; mPenDown = true; } // insert colors from selection intPair center = SelectionManager::getSelectionCenter( true ); for( int sy=0; sy= 0 && ix >= 0 ) { rgbaColor c = SelectionManager:: getColor( sx, sy ); mButtonGrid[iy][ix]->setColor( c ); mTileToEdit.editTile( ix, iy, c ); } } } } refreshMiniView(); if( !mButtonGrid[y][x]->isPressed() ) { // a release mPenDown = false; } } break; } if( changed ) { mUndoStack.push_back( oldTileState ); mUndoButton->setEnabled( true ); // new branch... "redo" future now impossible mRedoStack.deleteAll(); mRedoButton->setEnabled( false ); } } else if( inTarget == mButtonGrid[y][x] && mButtonGrid[y][x]->wasLastActionHover() ) { found = true; if( mToolSet->getSelected() == stamp ) { // preview of selection that will be inserted // upon click // first, turn all overlays off for( int by=0; by setOverlay( false ); } } intPair center = SelectionManager::getSelectionCenter( true ); for( int sy=0; sy= 0 && ix >= 0 ) { rgbaColor c = SelectionManager:: getColor( sx, sy ); mButtonGrid[iy][ix]-> setOverlayColor( c ); mButtonGrid[iy][ix]-> setOverlay( true ); } } } } } } } } } } void TileEditor::editorClosing() { addTile(); } void TileEditor::addTile() { mAddAction = true; mTileToEdit.finishEdit(); mainTilePicker->setSelectedResource( mTileToEdit, true ); mAddAction = false; }