SleepIsDeath/gameSource/TimbreEditor.cpp

702 lines
20 KiB
C++

#include "TimbreEditor.h"
#include "TimbrePicker.h"
#include "BorderPanel.h"
#include "labels.h"
#include "SelectionManager.h"
#include "packSaver.h"
#include "GridOverlay.h"
#include "minorGems/util/log/AppLog.h"
extern TimbrePicker *mainTimbrePicker;
extern int gameWidth, gameHeight;
extern TextGL *largeTextFixed;
template <>
void SizeLimitedVector<TimbreResource>::deleteElementOfType(
TimbreResource inElement ) {
// no delete necessary
}
static rgbaColor emptyC = { { 0,0,0,255 } };
TimbreEditor::TimbreEditor( ScreenGL *inScreen )
: Editor( inScreen ),
mPlayerTimbreIndex( 0 ),
mUndoStack( MAX_UNDOS, false ) {
mCloseButton->setToolTip( "tip_closeEdit_timbre" );
mSidePanel->add( mainTimbrePicker );
mainTimbrePicker->addActionListener( this );
double offset = P;
double buttonSize = (gameHeight - 2 * offset - 8) / P;
rgbaColor c = { { 0,0,0,255 } };
for( int y=0; y<F; y++ ) {
for( int x=0; x<FL; x++ ) {
mButtonGrid[y][x] = new ColorButtonGL(
c,
8 + x * buttonSize,
gameWidth - ( 48 + (y + 1) * buttonSize ),
buttonSize,
buttonSize );
mMainPanel->add( mButtonGrid[y][x] );
mButtonGrid[y][x]->addActionListener( this );
}
mZeroButtons[y] =new ColorButtonGL(
c,
8 - buttonSize,
gameWidth - ( 48 + (y + 1) * buttonSize ),
buttonSize,
buttonSize );
mMainPanel->add( mZeroButtons[y] );
mZeroButtons[y]->addActionListener( this );
// force dark border to make black button invisible
mZeroButtons[y]->setColor( emptyC, true );
}
EightPixelLabel *fieldLabel = new EightPixelLabel( 150, 54,
"timbreName" );
mMainPanel->add( fieldLabel );
int fieldHeight = 8;
int fieldWidth = 8 * 10;
const char *defaultText = "default";
mNameField = 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( mNameField );
mNameField->setFocus( true );
//mNameField->lockFocus( true );
mNameField->setCursorPosition( strlen( defaultText ) );
mNameField->addActionListener( this );
// center add button
double gridEdge = 8 + buttonSize * FL;
double extra = gameHeight - gridEdge;
// center it vertically on timbre picker
double addY = mainTimbrePicker->getAnchorY() +
mainTimbrePicker->getHeight() - 15;
double sideButtonsX = gridEdge + (extra - 16) / 2;
mAddButton = new AddButtonGL( sideButtonsX,
addY,
16, 16 );
mMainPanel->add( mAddButton );
mAddButton->addActionListener( this );
mAddButton->setToolTip( "tip_addTimbre" );
mAddAction = false;
double miniButtonSize = P + 4;
mMiniViewButton = new SpriteButtonGL(
NULL, 1,
gridEdge + ( extra - miniButtonSize ) / 2,
addY - 24,
miniButtonSize,
miniButtonSize );
mMainPanel->add( mMiniViewButton );
double undoButtonY = gameWidth - ( 48 + FL * 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 );
Color *thumbColor = new Color( .5, .5, .5, .5 );
Color *borderColor = new Color( .35, .35, .35, .35 );
mAttackSlider = new ToolTipSliderGL( 8, 48,
40, 10,
NULL, 0,
new Color( 0, 1, 0, 1 ),
new Color( 1, 1, 0, 1 ),
thumbColor->copy(),
borderColor->copy(),
1, 4, 1 );
mMainPanel->add( mAttackSlider );
mAttackSlider->setThumbPosition( 1.0 );
mAttackSlider->addActionListener( this );
mAttackSlider->setToolTip( "tip_attack" );
mHoldSlider = new ToolTipSliderGL( 50, 48,
40, 10,
NULL, 0,
new Color( 1, 1, 0, 1 ),
new Color( 1, 1, 0, 1 ),
thumbColor->copy(),
borderColor->copy(),
1, 4, 1 );
mMainPanel->add( mHoldSlider );
mHoldSlider->setThumbPosition( 1.00 );
mHoldSlider->addActionListener( this );
mHoldSlider->setToolTip( "tip_hold" );
mReleaseSlider = new ToolTipSliderGL( 92, 48,
40, 10,
NULL, 0,
new Color( 1, 1, 0, 1 ),
new Color( 1, 0, 0, 1 ),
thumbColor->copy(),
borderColor->copy(),
1, 4, 1 );
mMainPanel->add( mReleaseSlider );
mReleaseSlider->setThumbPosition( 0 );
mReleaseSlider->addActionListener( this );
mReleaseSlider->setToolTip( "tip_release" );
delete thumbColor;
delete borderColor;
for( int i=0; i<NUM_OCTAVES; i++ ) {
double x = mMiniViewButton->getAnchorX() + 3;
double y = mMiniViewButton->getAnchorY() - 10 - 11 * (i+1) - 1;
mOctaveButtons[i] = new SelectableButtonGL(
new Sprite( "octave.tga", true ),
1,
x, y, 12, 12 );
mOctaveButtons[i]->setToolTip( "tip_octave" );
mMainPanel->add( mOctaveButtons[i] );
mOctaveButtons[i]->addActionListener( this );
mOctaveButtons[i]->setEnabled( true );
}
setTimbreToEdit( mainTimbrePicker->getSelectedResource() );
mPenDown = false;
mIgnoreSliders = false;
GridOverlay *overlay = new GridOverlay(
8,
gameWidth - ( 48 + F * buttonSize ),
FL * buttonSize, F * buttonSize,
F );
mMainPanel->add( overlay );
postConstruction();
}
TimbreEditor::~TimbreEditor() {
mSidePanel->remove( mainTimbrePicker );
}
extern Color harmonicLowColor;
extern Color harmonicHighColor;
#include "musicPlayer.h"
void TimbreEditor::setTimbreToEdit( TimbreResource inTimbre,
char inUpdatePlayerTimbre,
char inUpdatePlayerEnvelope ) {
mTimbreToEdit = inTimbre;
/*
rgbaColor fullC = { { (unsigned char)( harmonicLowColor.r * 255 ),
(unsigned char)( harmonicLowColor.g * 255 ),
(unsigned char)( harmonicLowColor.b * 255 ) } };
rgbaColor fullHotC = { { (unsigned char)( harmonicHighColor.r * 255 ),
(unsigned char)( harmonicHighColor.g * 255 ),
(unsigned char)( harmonicHighColor.b * 255 ) } };
*/
rgbaColor fullHotC = mTimbreToEdit.getTimbreColor();
rgbaColor fullC = fullHotC;
fullC.comp.r = (unsigned char)( fullC.comp.r * 0.50 );
fullC.comp.g = (unsigned char)( fullC.comp.g * 0.50 );
fullC.comp.b = (unsigned char)( fullC.comp.b * 0.50 );
for( int y=0; y<F; y++ ) {
for( int x=0; x<FL; x++ ) {
if( mTimbreToEdit.getHarmonicLevel( y ) > x ) {
mButtonGrid[F - y - 1][x]->setColor(
blend( fullC, fullHotC, x / (double)FL ), true );
}
else {
mButtonGrid[F - y - 1][x]->setColor( emptyC );
}
}
}
refreshMiniView();
char *name = mTimbreToEdit.getTimbreName();
mNameField->setText( name );
mNameField->setCursorPosition( strlen( name ) );
delete [] name;
mIgnoreSliders = true;
// round to nearest pixel
// attack slider works in reverse
mAttackSlider->setThumbPosition(
(int)( (255 - mTimbreToEdit.getAttack()) /
255.0 * 80 )
/ 80.0 );
mHoldSlider->setThumbPosition(
(int)( mTimbreToEdit.getHold() /
255.0 * 80 )
/ 80.0 );
mReleaseSlider->setThumbPosition(
(int)( mTimbreToEdit.getRelease() /
255.0 * 80 )
/ 80.0 );
mIgnoreSliders = false;
int octave = mTimbreToEdit.getOctavesDown();
for( int i=0; i<NUM_OCTAVES; i++ ) {
mOctaveButtons[i]->setSelected( i == octave );
}
mTimbreToEdit.setInPlayer( mPlayerTimbreIndex,
inUpdatePlayerTimbre, inUpdatePlayerEnvelope );
}
void TimbreEditor::setPlayerTimbreToEdit( int inTimbre ) {
mPlayerTimbreIndex = inTimbre;
}
void TimbreEditor::refreshMiniView() {
// don't use cached version
mMiniViewButton->setSprite( mTimbreToEdit.getSprite( false, false ) );
}
void TimbreEditor::saveUndoPoint() {
mUndoStack.push_back( mTimbreToEdit );
mUndoButton->setEnabled( true );
// new branch... "redo" future now impossible
mRedoStack.deleteAll();
mRedoButton->setEnabled( false );
}
void TimbreEditor::actionPerformed( GUIComponent *inTarget ) {
// superclass
Editor::actionPerformed( inTarget );
for( int i=0; i<NUM_OCTAVES; i++ ) {
if( inTarget == mOctaveButtons[i] ) {
char oldSelected = mOctaveButtons[i]->getSelected();
if( !oldSelected ) {
saveUndoPoint();
mTimbreToEdit.editOctavesDown( i );
setTimbreToEdit( mTimbreToEdit, true, false );
}
return;
}
}
if( inTarget == mainTimbrePicker ) {
TimbreResource timbrePicked = mainTimbrePicker->getSelectedResource();
if( ! mAddAction &&
! mainTimbrePicker->wasLastActionFromPress() ) {
// will change timbre
mUndoStack.push_back( mTimbreToEdit );
mUndoButton->setEnabled( true );
setTimbreToEdit( timbrePicked );
// new branch... "redo" future now impossible
mRedoStack.deleteAll();
mRedoButton->setEnabled( false );
}
}
else if( inTarget == mNameField ) {
mUndoStack.push_back( mTimbreToEdit );
mUndoButton->setEnabled( true );
// new branch... "redo" future now impossible
mRedoStack.deleteAll();
mRedoButton->setEnabled( false );
mTimbreToEdit.editTimbreName( mNameField->getText() );
}
else if( inTarget == mAddButton ) {
addTimbre();
}
else if( inTarget == mUndoButton ) {
int lastIndex = mUndoStack.size() - 1;
TimbreResource last = *( mUndoStack.getElement( lastIndex ) );
mUndoStack.deleteElement( lastIndex );
if( mUndoStack.size() == 0 ) {
mUndoButton->setEnabled( false );
}
mRedoStack.push_back( mTimbreToEdit );
mRedoButton->setEnabled( true );
setTimbreToEdit( last );
}
else if( inTarget == mRedoButton ) {
int nextIndex = mRedoStack.size() - 1;
TimbreResource next = *( mRedoStack.getElement( nextIndex ) );
mRedoStack.deleteElement( nextIndex );
if( mRedoStack.size() == 0 ) {
mRedoButton->setEnabled( false );
}
mUndoStack.push_back( mTimbreToEdit );
mUndoButton->setEnabled( true );
setTimbreToEdit( next );
}
else if( inTarget == mAttackSlider && ! mIgnoreSliders ) {
if( mAttackSlider->mJustPressed ) {
// first move in this adjustment, save an undo point here
saveUndoPoint();
}
// attack reversed
int attack = 255 -
(int)( 255 * mAttackSlider->getThumbPosition() );
int hold =
(int)( 255 * mHoldSlider->getThumbPosition() );
int release =
(int)( 255 * mReleaseSlider->getThumbPosition() );
if( release + attack + hold > 255 ) {
if( hold > 0 ) {
// push hold slider
hold = 255 - attack - release;
if( hold < 0 ) {
hold = 0;
}
mIgnoreSliders = true;
// round to nearest pixel
mHoldSlider->setThumbPosition(
(int)( hold / 255.0 * 80 )
/ 80.0 );
mIgnoreSliders = false;
}
if( release + attack + hold > 255 ) {
// push release
release = 255 - attack - hold;
mIgnoreSliders = true;
// round to nearest pixel
mReleaseSlider->setThumbPosition(
(int)( release / 255.0 * 80 )
/ 80.0 );
mIgnoreSliders = false;
}
}
mTimbreToEdit.editEnvelope( attack, hold, release );
if( mAttackSlider->mJustReleased ) {
// actually adjust
mTimbreToEdit.setInPlayer( mPlayerTimbreIndex,
false, true );
}
}
else if( inTarget == mHoldSlider && ! mIgnoreSliders ) {
if( mHoldSlider->mJustPressed ) {
// first move in this adjustment, save an undo point here
saveUndoPoint();
}
// attack reversed
int attack = 255 -
(int)( 255 * mAttackSlider->getThumbPosition() );
int hold =
(int)( 255 * mHoldSlider->getThumbPosition() );
int release =
(int)( 255 * mReleaseSlider->getThumbPosition() );
if( release + attack + hold > 255 ) {
if( attack > 0 ) {
// push attack slider
attack = 255 - release - hold;
if( attack < 0 ) {
attack = 0;
}
mIgnoreSliders = true;
// round to nearest pixel
mAttackSlider->setThumbPosition(
(int)( (255 - attack) / 255.0 * 80 )
/ 80.0 );
mIgnoreSliders = false;
}
if( release + attack + hold > 255 ) {
// push release
release = 255 - hold - attack;
mIgnoreSliders = true;
// round to nearest pixel
mReleaseSlider->setThumbPosition(
(int)( release / 255.0 * 80 )
/ 80.0 );
mIgnoreSliders = false;
}
}
mTimbreToEdit.editEnvelope( attack, hold, release );
if( mHoldSlider->mJustReleased ) {
// actually adjust
mTimbreToEdit.setInPlayer( mPlayerTimbreIndex,
false, true );
}
}
else if( inTarget == mReleaseSlider && ! mIgnoreSliders ) {
if( mReleaseSlider->mJustPressed ) {
// first move in this adjustment, save an undo point here
saveUndoPoint();
}
// release reversed
int attack = 255 -
(int)( 255 * mAttackSlider->getThumbPosition() );
int hold =
(int)( 255 * mHoldSlider->getThumbPosition() );
int release =
(int)( 255 * mReleaseSlider->getThumbPosition() );
if( release + attack + hold > 255 ) {
if( hold > 0 ) {
if( hold < 0 ) {
hold = 0;
}
// push hold
hold = 255 - release - attack;
mIgnoreSliders = true;
// round to nearest pixel
mHoldSlider->setThumbPosition(
(int)( hold / 255.0 * 80 )
/ 80.0 );
mIgnoreSliders = false;
}
if( release + attack + hold > 255 ) {
// push attack slider
attack = 255 - release - hold;
mIgnoreSliders = true;
// round to nearest pixel
mAttackSlider->setThumbPosition(
(int)( (255 - attack) / 255.0 * 80 )
/ 80.0 );
mIgnoreSliders = false;
}
}
mTimbreToEdit.editEnvelope( attack, hold, release );
if( mReleaseSlider->mJustReleased ) {
// actually adjust
mTimbreToEdit.setInPlayer( mPlayerTimbreIndex,
false, true );
}
}
else {
// check grid
char found = false;
for( int y=0; y<F && !found; y++ ) {
for( int x=0; x<FL && !found; x++ ) {
if( ( inTarget == mButtonGrid[y][x] &&
! mButtonGrid[y][x]->wasLastActionHover() )
||
( inTarget == mZeroButtons[y] &&
! mZeroButtons[y]->wasLastActionHover() ) ) {
if( inTarget == mZeroButtons[y] ) {
// okay, since we're leaving loop anyway
x = -1;
}
ColorButtonGL *targetButton = (ColorButtonGL*)inTarget;
found = true;
if( !mPenDown ) {
mPenDown = true;
// save undo only from start of mouse action
saveUndoPoint();
}
else {
if( ! targetButton->isPressed() ) {
// release
mPenDown = false;
}
}
int oldHarmonicLevel =
mTimbreToEdit.getHarmonicLevel( F - y - 1 );
if( x+1 != oldHarmonicLevel ) {
// improve performance by only updating when changed
mTimbreToEdit.editHarmonic( F - y - 1, x+1 );
setTimbreToEdit( mTimbreToEdit, true, false );
}
}
}
}
}
}
void TimbreEditor::editorClosing() {
addTimbre();
}
void TimbreEditor::addTimbre() {
mAddAction = true;
mTimbreToEdit.finishEdit();
mainTimbrePicker->setSelectedResource( mTimbreToEdit, true );
mAddAction = false;
}