diff --git a/.svnignore b/.svnignore new file mode 100644 index 000000000..a9cdbbe03 --- /dev/null +++ b/.svnignore @@ -0,0 +1,6 @@ +Makefile.in +*.moc +.libs +embedded_resources.h +.deps +Makefile diff --git a/ChangeLog b/ChangeLog index 74afda63b..7be78259b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,167 @@ +2008-03-16 Paul Giblock + + * Makefile.am: + Added lmmsStyle to the Makefile again. + + * src/widgets/lcd_spinbox.cpp: + * include/lcd_spinbox.h: + - Added separate function for deriving control size + - Added property for side-margins + - Fixed memory leak with the pixmap + - Added yours truly to the copyright + + * src/core/lmms_style.cpp: + * include/lmms_style.h: + - Re-added lmmsStyle. I don't know why these files disappeared + - Getting ready to draw pretty borders + + * plugins/sf2_player/sf2_player.cpp: + * plugins/sf2_player/sf2_player.h: + - Hopefully plugged some leaks caused by the leaky fluidSynth. It seems + to run fine, but only time will tell + - Added sfont file sharing between instances of sf2Player + - Added synthMutex to keep play() from freezing while we are recreating + the synth due to a file load. + + * src/widgets/combobox.cpp: + Draw styled border. Don't worry, the style will be improved + + * src/core/fx_mixer.cpp: + Improved drawing of LCD Channel numbers. + + * .: + * m4: + * buildtools: + * plugins: + * plugins/ladspa_effect: + * plugins/ladspa_effect/caps: + * plugins/ladspa_effect/caps/waves: + * plugins/ladspa_effect/caps/dsp: + * plugins/ladspa_effect/caps/dsp/tonestack: + * plugins/patman: + * plugins/lb302: + * plugins/organic: + * plugins/bass_booster: + * plugins/bit_invader: + * plugins/vst_effect: + * plugins/vibed: + * plugins/triple_oscillator: + * plugins/singerbot: + * plugins/live_tool: + * plugins/audio_file_processor: + * plugins/stk: + * plugins/stk/mallets: + * plugins/stk/voices: + * plugins/stk/voices/flute: + * plugins/stk/voices/resonate: + * plugins/stk/voices/include: + * plugins/stk/voices/wurley: + * plugins/stk/voices/src: + * plugins/stk/voices/percflute: + * plugins/stk/voices/rhodey: + * plugins/stk/voices/tubebell: + * plugins/stk/voices/bowed: + * plugins/stk/voices/clarinet: + * plugins/stk/voices/moog: + * plugins/stk/voices/metal: + * plugins/stk/voices/b3: + * plugins/stk/voices/blow_hole: + * plugins/stk/voices/brass: + * plugins/stk/voices/fmvoices: + * plugins/stk/voices/bandedwg: + * plugins/stk/voices/blow_bottle: + * plugins/plucked_string_synth: + * plugins/stereo_enhancer: + * plugins/sf2_player: + * plugins/vestige: + * plugins/vst_base: + * plugins/ladspa_browser: + * plugins/kicker: + * plugins/polyb302: + * plugins/flp_import: + * plugins/flp_import/unrtf: + * plugins/midi_import: + * include: + * src: + * src/audio: + * src/midi: + * src/lib: + * src/widgets: + * src/tracks: + * src/3rdparty: + * src/3rdparty/samplerate: + * src/core: + * data: + * data/locale: + * data/track_icons: + * data/midi-maps: + * data/samples: + * data/samples/effects: + * data/samples/stringsnpads: + * data/samples/basses: + * data/samples/shapes: + * data/samples/latin: + * data/samples/bassloopes: + * data/samples/drums: + * data/samples/instruments: + * data/samples/misc: + * data/samples/drumsynth: + * data/samples/drumsynth/effects: + * data/samples/drumsynth/misc_synth: + * data/samples/drumsynth/tr606: + * data/samples/drumsynth/cr78: + * data/samples/drumsynth/magnetboy: + * data/samples/drumsynth/tr808: + * data/samples/drumsynth/tr909: + * data/samples/drumsynth/misc_fx: + * data/samples/drumsynth/misc: + * data/samples/drumsynth/electro: + * data/samples/drumsynth/linn: + * data/samples/drumsynth/ferraro: + * data/samples/drumsynth/r_b: + * data/samples/drumsynth/misc_bass: + * data/samples/drumsynth/tr77: + * data/samples/drumsynth/misc_perc: + * data/samples/drumsynth/latin: + * data/samples/drumsynth/instrument: + * data/samples/drumsynth/misc_electro: + * data/samples/drumsynth/acoustic: + * data/samples/drumsynth/misc_hats: + * data/samples/drumsynth/farfisa: + * data/samples/drumsynth/jorgensohn: + * data/samples/drumsynth/cr8000: + * data/samples/drumsynth/misc_claps: + * data/samples/beats: + * data/presets: + * data/presets/AudioFileProcessor: + * data/presets/LB302: + * data/presets/Organic: + * data/presets/PluckedStringSynth: + * data/presets/VeSTige: + * data/presets/BitInvader: + * data/presets/Vibed: + * data/presets/TripleOscillator: + * data/themes: + * data/themes/blue_scene: + * data/themes/blue_scene/plugins: + * data/themes/default: + * data/projects: + * data/projects/covers: + * data/projects/recorded_loops: + * data/projects/cool_songs: + * data/projects/tutorials: + * data/projects/demos: + * data/projects/misc: + * data/projects/templates: + Added svn:ignore property for temporary buildtime files. Prevents + dozens of items showing in diff and status. The file + .svnignore describes which files are ignored. + + * .svnignore: + Can change this file to ignore more stuff. Reapply by running: + svn -R propset svn:ignore -F .svnignore . + + 2008-03-16 Tobias Doerffel * src/widgets/visualization_widget.cpp: @@ -341,7 +505,7 @@ * src/core/main.cpp: * Makefile.am: added lmmsStyle to aim for a consistant interface. Some Qt themes - make LMMS look really bad. Hopefully, overtime, we can make a style + make LMMS look really bad. Hopefully, over time, we can make a style the unifies all our gui elements * src/core/track.cpp: diff --git a/Makefile.am b/Makefile.am index 1e66eb1b0..e425dec34 100644 --- a/Makefile.am +++ b/Makefile.am @@ -180,6 +180,7 @@ lmms_SOURCES = \ $(srcdir)/src/core/ladspa_2_lmms.cpp \ $(srcdir)/src/core/ladspa_manager.cpp \ $(srcdir)/src/core/ladspa_control.cpp \ + $(srcdir)/src/core/lmms_style.cpp \ $(srcdir)/src/core/main_window.cpp \ $(srcdir)/src/core/main.cpp \ $(srcdir)/src/core/meter_dialog.cpp \ diff --git a/include/lcd_spinbox.h b/include/lcd_spinbox.h index a272893fc..a2fb0c9b0 100644 --- a/include/lcd_spinbox.h +++ b/include/lcd_spinbox.h @@ -64,6 +64,7 @@ public: public slots: virtual void setEnabled( bool _on ); + virtual void setMarginWidth( int _width ); virtual void update( void ); @@ -74,9 +75,11 @@ protected: virtual void mouseReleaseEvent( QMouseEvent * _me ); virtual void wheelEvent( QWheelEvent * _we ); virtual void paintEvent( QPaintEvent * _me ); + + virtual void updateSize(); private: - + static const int charsPerPixmap = 12; QMap m_textForValue; @@ -89,6 +92,7 @@ private: int m_cellWidth; int m_cellHeight; int m_numDigits; + int m_marginWidth; QPoint m_origMousePos; diff --git a/include/lmms_style.h b/include/lmms_style.h index a44a15049..2f5accd26 100644 --- a/include/lmms_style.h +++ b/include/lmms_style.h @@ -39,6 +39,11 @@ public: virtual ~lmmsStyle() { } + + virtual void drawPrimitive( PrimitiveElement element, const QStyleOption *option, + QPainter *painter, const QWidget *widget = 0 ) const; + + }; #endif diff --git a/plugins/sf2_player/sf2_player.cpp b/plugins/sf2_player/sf2_player.cpp index b09dda1ea..87631ba67 100644 --- a/plugins/sf2_player/sf2_player.cpp +++ b/plugins/sf2_player/sf2_player.cpp @@ -22,6 +22,7 @@ * */ +#include #include #include @@ -65,6 +66,14 @@ plugin::descriptor sf2player_plugin_descriptor = } +// Static map of current sfonts +QMap sf2Instrument::s_fonts; + +// Static functor to fluid's built-in free function. Used when we want +// to really delete the soundfont, instead of just changing refCount +int (* sf2Instrument::s_origFree)( fluid_sfont_t * ); + + sf2Instrument::sf2Instrument( instrumentTrack * _instrument_track ) : instrument( _instrument_track, &sf2player_plugin_descriptor ), m_fontId( 0 ), @@ -75,44 +84,47 @@ sf2Instrument::sf2Instrument( instrumentTrack * _instrument_track ) : for( int i = 0; i < 128; ++i ) { m_notesRunning[i] = 0; - } + } + m_settings = new_fluid_settings(); - /* Set the synthesizer settings, if necessary */ - - + // This is just our starting instance of synth. It is recreated + // everytime we load a new soundfont. m_synth = new_fluid_synth( m_settings ); + // Install our callbacks + fluid_sfloader_t * pLoader + = (fluid_sfloader_t *) malloc( sizeof( fluid_sfloader_t ) ); - //fluid_settings_setstr(settings, "audio.driver", "jack"); - - //adriver = new_fluid_audio_driver(settings, synth); + pLoader->data = (void *) this; + pLoader->load = sf2Instrument::sfloaderLoad; + pLoader->free = sf2Instrument::sfloaderFree; + fluid_synth_add_sfloader( m_synth, pLoader ); instrumentPlayHandle * iph = new instrumentPlayHandle( this ); engine::getMixer()->addPlayHandle( iph ); connect( &m_bankNum, SIGNAL( dataChanged() ), - this, SLOT( updatePatch() ) ); + this, SLOT( updatePatch() ) ); connect( &m_patchNum, SIGNAL( dataChanged() ), - this, SLOT( updatePatch() ) ); -} + this, SLOT( updatePatch() ) ); +} sf2Instrument::~sf2Instrument() { - engine::getMixer()->removePlayHandles( getInstrumentTrack() ); - delete_fluid_synth( m_synth ); - delete_fluid_settings( m_settings ); + engine::getMixer()->removePlayHandles( getInstrumentTrack() ); + delete_fluid_synth( m_synth ); + delete_fluid_settings( m_settings ); } - void sf2Instrument::saveSettings( QDomDocument & _doc, - QDomElement & _this ) + QDomElement & _this ) { _this.setAttribute( "src", m_filename ); m_patchNum.saveSettings( _doc, _this, "patch" ); @@ -121,7 +133,6 @@ void sf2Instrument::saveSettings( QDomDocument & _doc, - void sf2Instrument::loadSettings( const QDomElement & _this ) { openFile( _this.attribute( "src" ) ); @@ -131,41 +142,68 @@ void sf2Instrument::loadSettings( const QDomElement & _this ) - QString sf2Instrument::nodeName( void ) const { return( sf2player_plugin_descriptor.name ); } + void sf2Instrument::openFile( const QString & _sf2File ) { - if( m_filename != "") + // Remove synth from this fluidSynth (but not necessarily memory) + if ( m_filename != "" ) { - fluid_synth_sfunload( m_synth, m_fontId, TRUE); + // Recreate synth + m_synthMutex.lock(); + delete_fluid_synth( m_synth ); + m_synth = new_fluid_synth( m_settings ); + m_synthMutex.unlock(); + + // No need to explicitly delete font. Deleting fluidSynth calls free + // on all fonts. This, causes sfloaderFreeFont to run. } - m_fontId = fluid_synth_sfload( m_synth, _sf2File.toLocal8Bit(), TRUE ); + const char * sf2Ascii = qPrintable( _sf2File ); + m_fontId = fluid_synth_sfload( m_synth, sf2Ascii, TRUE ); - if( m_fontId >= 0) + QString sf2Key = qPrintable( _sf2File ); + + // Add to map, if doesn't exist. + // We can't do this in callback because fluid hasn't created the sfont yet + if( !s_fonts.contains( sf2Key ) && fluid_synth_sfcount( m_synth ) > 0 ) { - m_patchNum.setValue(0); - m_bankNum.setValue(0); + // Grab this sf from the top of the stack + fluid_sfont_t * sfont = fluid_synth_get_sfont( m_synth, 0 ); + + // Hold on to real free function for executing later. + s_origFree = sfont->free; + sfont->free = sf2Instrument::sfloaderFreeFont; + + // Finally, add font + s_fonts.insert( sf2Key, new sf2Font( sfont ) ); + } + + if( m_fontId >= 0 ) + { + m_patchNum.setValue( 0 ); + m_bankNum.setValue( 0 ); m_filename = _sf2File; emit fileChanged(); } } + + void sf2Instrument::updatePatch( void ) { - printf("update patch\n"); if( m_bankNum.value() >= 0 && m_patchNum.value() >= 0 ) { fluid_synth_program_select( m_synth, 1, m_fontId, m_bankNum.value(), m_patchNum.value() ); } } - + void sf2Instrument::playNote( notePlayHandle * _n, bool ) @@ -174,7 +212,8 @@ void sf2Instrument::playNote( notePlayHandle * _n, bool ) const f_cnt_t tfp = _n->totalFramesPlayed(); - int midiNote = (int)floor( ( log2( _n->frequency() ) - LOG440 ) * 12+69-58)+0.5; + int midiNote = (int)floor( 12 * ( log2( _n->frequency() ) - LOG440 ) - 4 ); + // out of range? if( midiNote <= 0 || midiNote >= 128 ) { @@ -184,30 +223,33 @@ void sf2Instrument::playNote( notePlayHandle * _n, bool ) if ( tfp == 0 ) { _n->m_pluginData = new int( midiNote ); + + m_synthMutex.lock(); fluid_synth_noteon( m_synth, 1, midiNote, _n->getVolume() ); + m_synthMutex.unlock(); + m_notesRunningMutex.lock(); ++m_notesRunning[midiNote]; m_notesRunningMutex.unlock(); } else if( _n->released() ) { - // Doesn't happen with release frames = 0 + // Doesn't happen with release frames = 0 } } - void sf2Instrument::play( bool _try_parallelizing ) { const fpp_t frames = engine::getMixer()->framesPerPeriod(); sampleFrame * buf = new sampleFrame[frames]; - // Assumes stereo and float sample_t - + m_synthMutex.lock(); fluid_synth_write_float( m_synth, frames, buf, 0, 2, buf, 1, 2 ); + m_synthMutex.unlock(); getInstrumentTrack()->processAudioBuffer( buf, frames, NULL ); @@ -216,6 +258,71 @@ void sf2Instrument::play( bool _try_parallelizing ) +int sf2Instrument::sfloaderFree( fluid_sfloader_t * _loader ) +{ + if( _loader != NULL ) + { + free( _loader ); + } + return 0; +} + + + +int sf2Instrument::sfloaderFreeFont( fluid_sfont_t * _sfont ) +{ + QString key = QString( _sfont->get_name(_sfont) ); + + sf2Font * f = sf2Instrument::s_fonts[key]; + + --(f->refCount); + + // No more references + if( f->refCount <= 0 ) + { + QTextStream cout( stdout, QIODevice::WriteOnly ); + cout << "Really deleting " << key << endl; + + sf2Instrument::s_fonts.remove( key ); + delete f; + + // Let fluidsynth free the font, as if we were not here + return s_origFree( _sfont ); + } + + // Make fluid think we freed the sfont + return 0; +} + + + +fluid_sfont_t * sf2Instrument::sfloaderLoad( + fluid_sfloader_t * _loader, const char *_filename ) +{ + if( _loader == NULL ) + { + return NULL; + } + + QString filename = _filename; + + if( sf2Instrument::s_fonts.contains( filename ) ) + { + QTextStream cout( stdout, QIODevice::WriteOnly ); + cout << "Using existing reference to " << filename << endl; + + sf2Font * font = sf2Instrument::s_fonts[ filename ]; + + font->refCount++; + return font->fluidFont; + } + + // fluidsynth will call next (default) loader... + return NULL; +} + + + void sf2Instrument::deleteNotePluginData( notePlayHandle * _n ) { int * midiNote = static_cast( _n->m_pluginData ); @@ -224,7 +331,9 @@ void sf2Instrument::deleteNotePluginData( notePlayHandle * _n ) m_notesRunningMutex.unlock(); if( n <= 0 ) { + m_synthMutex.lock(); fluid_synth_noteoff( m_synth, 1, *midiNote ); + m_synthMutex.unlock(); } delete midiNote; @@ -238,9 +347,8 @@ pluginView * sf2Instrument::instantiateView( QWidget * _parent ) - sf2InstrumentView::sf2InstrumentView( instrument * _instrument, - QWidget * _parent ) : + QWidget * _parent ) : instrumentView( _instrument, _parent ) { QVBoxLayout * vl = new QVBoxLayout( this ); @@ -250,36 +358,36 @@ sf2InstrumentView::sf2InstrumentView( instrument * _instrument, m_fileDialogButton = new pixmapButton( this, NULL ); m_fileDialogButton->setCursor( QCursor( Qt::PointingHandCursor ) ); m_fileDialogButton->setActiveGraphic( embed::getIconPixmap( - "project_open_down" ) ); + "project_open_down" ) ); m_fileDialogButton->setInactiveGraphic( embed::getIconPixmap( - "project_open" ) ); + "project_open" ) ); connect( m_fileDialogButton, SIGNAL( clicked() ), - this, SLOT( showFileDialog() ) ); + this, SLOT( showFileDialog() ) ); toolTip::add( m_fileDialogButton, tr( "Open other SoundFont file" ) ); m_fileDialogButton->setWhatsThis( - tr( "Click here to open another SF2 file" ) ); + tr( "Click here to open another SF2 file" ) ); // Patch Button m_patchDialogButton = new pixmapButton( this, NULL ); m_patchDialogButton->setCursor( QCursor( Qt::PointingHandCursor ) ); m_patchDialogButton->setActiveGraphic( embed::getIconPixmap( - "track_op_menu" ) ); + "track_op_menu" ) ); m_patchDialogButton->setInactiveGraphic( embed::getIconPixmap( - "track_op_menu" ) ); + "track_op_menu" ) ); connect( m_patchDialogButton, SIGNAL( clicked() ), - this, SLOT( showPatchDialog() ) ); + this, SLOT( showPatchDialog() ) ); toolTip::add( m_patchDialogButton, tr( "Choose the patch" ) ); // LCDs m_bankNumLcd = new lcdSpinBox( 3, this, "Bank" ); - m_bankNumLcd->setLabel( "Bank:" ); + m_bankNumLcd->setLabel( "BANK" ); m_bankNumLcd->addTextForValue( -1, "---" ); m_bankNumLcd->setEnabled( FALSE ); m_patchNumLcd = new lcdSpinBox( 3, this, "Patch" ); - m_patchNumLcd->setLabel( "Patch:" ); + m_patchNumLcd->setLabel( "PATCH" ); m_patchNumLcd->addTextForValue( -1, "---" ); m_patchNumLcd->setEnabled( FALSE ); @@ -293,17 +401,16 @@ sf2InstrumentView::sf2InstrumentView( instrument * _instrument, // Next row hl = new QHBoxLayout(); - - m_filenameLabel = new QLabel( this ); - - hl->addWidget( m_filenameLabel ); + m_filenameLabel = new QLabel( this ); + + hl->addWidget( m_filenameLabel ); vl->addLayout( hl ); setAutoFillBackground( TRUE ); QPalette pal; pal.setBrush( backgroundRole(), PLUGIN_NAME::getIconPixmap( - "artwork" ) ); + "artwork" ) ); setPalette( pal ); updateFilename(); @@ -311,12 +418,12 @@ sf2InstrumentView::sf2InstrumentView( instrument * _instrument, - sf2InstrumentView::~sf2InstrumentView() { } + void sf2InstrumentView::modelChanged( void ) { sf2Instrument * k = castModel(); @@ -324,22 +431,24 @@ void sf2InstrumentView::modelChanged( void ) m_patchNumLcd->setModel( &k->m_patchNum ); connect(k, SIGNAL( fileChanged( void ) ), - this, SLOT( updateFilename( void ) ) ); - + this, SLOT( updateFilename( void ) ) ); + updateFilename(); } + void sf2InstrumentView::updateFilename( void ) { - m_filenameLabel->setText("File: " + + m_filenameLabel->setText( "File: " + castModel()->m_filename + - "\nPatch: TODO"); + "\nPatch: TODO" ); update(); } + void sf2InstrumentView::showFileDialog( void ) { sf2Instrument * k = castModel(); @@ -361,7 +470,7 @@ void sf2InstrumentView::showFileDialog( void ) if( QFileInfo( f ).exists() == FALSE ) { f = configManager::inst()->factorySamplesDir() + - k->m_filename; + k->m_filename; } } ofd.setDirectory( QFileInfo( f ).absolutePath() ); @@ -381,27 +490,30 @@ void sf2InstrumentView::showFileDialog( void ) engine::getSong()->setModified(); } } - - } + + +// Single instance of the patch dialog patchesDialog * sf2InstrumentView::s_patchDialog = NULL; void sf2InstrumentView::showPatchDialog( void ) { sf2Instrument * k = castModel(); - if( s_patchDialog == NULL ) { - printf("Creating patchDialog\n"); - s_patchDialog = new patchesDialog(this); + if( s_patchDialog == NULL ) + { + s_patchDialog = new patchesDialog( this ); } - s_patchDialog->setup( k->m_synth, 1, k->getInstrumentTrack()->name(), + + s_patchDialog->setup( k->m_synth, 1, k->getInstrumentTrack()->name(), &k->m_bankNum, &k->m_patchNum ); - + s_patchDialog->exec(); } + extern "C" { @@ -409,7 +521,7 @@ extern "C" plugin * lmms_plugin_main( model *, void * _data ) { return( new sf2Instrument( - static_cast( _data ) ) ); + static_cast( _data ) ) ); } diff --git a/plugins/sf2_player/sf2_player.h b/plugins/sf2_player/sf2_player.h index 23d4bef69..1f963df56 100644 --- a/plugins/sf2_player/sf2_player.h +++ b/plugins/sf2_player/sf2_player.h @@ -36,6 +36,7 @@ #include "fluidsynth.h" class sf2InstrumentView; +class sf2Font; class notePlayHandle; class patchesDialog; @@ -51,12 +52,12 @@ public: virtual void play( bool _try_parallelizing ); virtual void FASTCALL playNote( notePlayHandle * _n, - bool _try_parallelizing ); + bool _try_parallelizing ); virtual void FASTCALL deleteNotePluginData( notePlayHandle * _n ); virtual void FASTCALL saveSettings( QDomDocument & _doc, - QDomElement & _parent ); + QDomElement & _parent ); virtual void FASTCALL loadSettings( const QDomElement & _this ); virtual QString nodeName( void ) const; @@ -71,13 +72,11 @@ public: return( FALSE ); } - virtual bool supportsParallelizing( void ) const { return( FALSE ); } - virtual pluginView * instantiateView( QWidget * _parent ); @@ -87,22 +86,34 @@ public slots: private: - fluid_settings_t* m_settings; + static QMap s_fonts; + static int (* s_origFree)( fluid_sfont_t * ); + fluid_settings_t* m_settings; fluid_synth_t* m_synth; - fluid_audio_driver_t* m_adriver; - int m_fontId; - QMutex m_notesRunningMutex; - int m_notesRunning[128]; - - QString m_filename; + // Protect the array of active notes + QMutex m_notesRunningMutex; + + // Protect synth when we are re-creating it. + QMutex m_synthMutex; + int m_notesRunning[128]; + lcdSpinBoxModel m_bankNum; lcdSpinBoxModel m_patchNum; +private: + // Our special callback functions + static int sfloaderFree( fluid_sfloader_t * _loader ); + static fluid_sfont_t * sfloaderLoad( + fluid_sfloader_t * _loader, const char * _filename ); + + static int sfloaderFreeFont( fluid_sfont_t * _soundFont ); + + friend class sf2InstrumentView; signals: @@ -113,6 +124,21 @@ signals: +// A soundfont in our font-map +class sf2Font +{ +public: + sf2Font( fluid_sfont_t * f ) : + fluidFont( f ), + refCount( 1 ) + {}; + + fluid_sfont_t * fluidFont; + int refCount; +}; + + + class sf2InstrumentView : public instrumentView { Q_OBJECT diff --git a/src/core/fx_mixer.cpp b/src/core/fx_mixer.cpp index 07c4a6dcc..6b0ee0365 100644 --- a/src/core/fx_mixer.cpp +++ b/src/core/fx_mixer.cpp @@ -369,7 +369,9 @@ fxMixerView::fxMixerView() : lcdSpinBox * l = new lcdSpinBox( 2, cv->m_fxLine ); l->model()->setRange( i, i ); l->model()->setValue( i ); - l->update(); + l->move( 2, 4 ); + l->setMarginWidth( 1 ); + cv->m_fader = new fader( &m->m_fxChannels[i]->m_volumeModel, cv->m_fxLine ); cv->m_fader->move( 15-cv->m_fader->width()/2, 80 ); diff --git a/src/core/lmms_style.cpp b/src/core/lmms_style.cpp new file mode 100644 index 000000000..c3a1f4634 --- /dev/null +++ b/src/core/lmms_style.cpp @@ -0,0 +1,110 @@ +#include +#include +#include +#include +#include + +#include "lmms_style.h" + + +void lmmsStyle::drawPrimitive( PrimitiveElement element, + const QStyleOption *option, QPainter *painter, + const QWidget *widget) const +{ + QPlastiqueStyle::drawPrimitive( element, option, painter, widget ); + /* + if( element == QStyle::PE_Frame ) { + printf("Frame\n"); + + QFrame::Shadow shadow = QFrame::Plain; + if (option->state & State_Sunken) + shadow = QFrame::Sunken; + else if (option->state & State_Raised) + shadow = QFrame::Raised; + + QPen oldPen = painter->pen(); + QBrush border; + QBrush corner; + QBrush innerTopLeft; + QBrush innerBottomRight; + + if (shadow != QFrame::Plain && (option->state & QStyle::State_HasFocus)) { + border = option->palette.highlight(); + qBrushSetAlphaF(&border, 0.8); + corner = option->palette.highlight(); + qBrushSetAlphaF(&corner, 0.5); + innerTopLeft = qBrushDark(option->palette.highlight(), 125); + innerBottomRight = option->palette.highlight(); + qBrushSetAlphaF(&innerBottomRight, 0.65); + } else { + border = option->palette.shadow(); + qBrushSetAlphaF(&border, 0.4); + corner = option->palette.shadow(); + qBrushSetAlphaF(&corner, 0.25); + innerTopLeft = option->palette.shadow(); + innerBottomRight = option->palette.highlight(); + if (shadow == QFrame::Sunken) { + qBrushSetAlphaF(&innerTopLeft, 0.23); + qBrushSetAlphaF(&innerBottomRight, 0.075); + } else { + qBrushSetAlphaF(&innerTopLeft, 0.075); + qBrushSetAlphaF(&innerBottomRight, 0.23); + } + } + + QLine lines[4]; + QPoint points[8]; + + // Opaque corner lines + painter->setPen(QPen(border, 0)); + lines[0] = QLine(rect.left() + 2, rect.top(), rect.right() - 2, rect.top()); + lines[1] = QLine(rect.left() + 2, rect.bottom(), rect.right() - 2, rect.bottom()); + lines[2] = QLine(rect.left(), rect.top() + 2, rect.left(), rect.bottom() - 2); + lines[3] = QLine(rect.right(), rect.top() + 2, rect.right(), rect.bottom() - 2); + painter->drawLines(lines, 4); + + // Opaque corner dots + points[0] = QPoint(rect.left() + 1, rect.top() + 1); + points[1] = QPoint(rect.left() + 1, rect.bottom() - 1); + points[2] = QPoint(rect.right() - 1, rect.top() + 1); + points[3] = QPoint(rect.right() - 1, rect.bottom() - 1); + painter->drawPoints(points, 4); + + // Shaded corner dots + painter->setPen(QPen(corner, 0)); + points[0] = QPoint(rect.left(), rect.top() + 1); + points[1] = QPoint(rect.left(), rect.bottom() - 1); + points[2] = QPoint(rect.left() + 1, rect.top()); + points[3] = QPoint(rect.left() + 1, rect.bottom()); + points[4] = QPoint(rect.right(), rect.top() + 1); + points[5] = QPoint(rect.right(), rect.bottom() - 1); + points[6] = QPoint(rect.right() - 1, rect.top()); + points[7] = QPoint(rect.right() - 1, rect.bottom()); + painter->drawPoints(points, 8); + + // Shadows + if (shadow != QFrame::Plain) { + painter->setPen(QPen(innerTopLeft, 0)); + lines[0] = QLine(rect.left() + 2, rect.top() + 1, rect.right() - 2, rect.top() + 1); + lines[1] = QLine(rect.left() + 1, rect.top() + 2, rect.left() + 1, rect.bottom() - 2); + painter->drawLines(lines, 2); + painter->setPen(QPen(innerBottomRight, 0)); + lines[0] = QLine(rect.left() + 2, rect.bottom() - 1, rect.right() - 2, rect.bottom() - 1); + lines[1] = QLine(rect.right() - 1, rect.top() + 2, rect.right() - 1, rect.bottom() - 2); + painter->drawLines(lines, 2); + } + + painter->setPen(oldPen); + + } + else { + QPlastiqueStyle::drawPrimitive( element, option, painter, widget ); + } + // brighter line at bottom/right + p.setPen( QColor( 160, 160, 160 ) ); + p.drawLine( width() - 1, 0, width() - 1, height() - 1 ); + p.drawLine( 0, height() - 1, width() - 1, height() - 1 ); +*/ + + +} diff --git a/src/widgets/combobox.cpp b/src/widgets/combobox.cpp index 18f492f8c..f2b140e05 100644 --- a/src/widgets/combobox.cpp +++ b/src/widgets/combobox.cpp @@ -182,7 +182,7 @@ void comboBox::paintEvent( QPaintEvent * _pe ) // Border QStyleOptionFrame opt; opt.initFrom( this ); - opt.state = QStyle::State_Sunken; + opt.state = 0; style()->drawPrimitive( QStyle::PE_Frame, &opt, &p, this ); diff --git a/src/widgets/lcd_spinbox.cpp b/src/widgets/lcd_spinbox.cpp index f701f465a..d939ec486 100644 --- a/src/widgets/lcd_spinbox.cpp +++ b/src/widgets/lcd_spinbox.cpp @@ -4,6 +4,7 @@ * lcd_spinbox.cpp - class lcdSpinBox, an improved QLCDNumber * * Copyright (c) 2005-2008 Tobias Doerffel + * Paul Giblock * * This file is part of Linux MultiMedia Studio - http://lmms.sourceforge.net * @@ -34,7 +35,6 @@ #include #include - #include "automatable_model_templates.h" #include "caption_menu.h" #include "embed.h" @@ -43,29 +43,29 @@ lcdSpinBox::lcdSpinBox( int _num_digits, QWidget * _parent, - const QString & _name ) : + const QString & _name ) : QWidget( _parent ), autoModelView( new autoModel( 0, 0, 0, 1, NULL, TRUE ) ), m_label(), m_numDigits( _num_digits ), m_origMousePos() -{ +{ setEnabled( TRUE ); setAccessibleName( _name ); m_lcdPixmap = new QPixmap( embed::getIconPixmap( "lcd_19green" ) ); - int margin = 1; //QStyle::PM_DefaultFrameWidth; - m_cellWidth = m_lcdPixmap->size().width() / lcdSpinBox::charsPerPixmap; m_cellHeight = m_lcdPixmap->size().height() / 2; - setFixedSize( m_cellWidth * (_num_digits+1) + (2*margin), - m_cellHeight + (2*margin) ); + m_marginWidth = m_cellWidth / 2; + + updateSize(); } -lcdSpinBox::lcdSpinBox( int _num_digits, const QString & _lcd_style, + +lcdSpinBox::lcdSpinBox( int _num_digits, const QString & _lcd_style, QWidget * _parent, const QString & _name ) : QWidget( _parent ), autoModelView( new autoModel( 0, 0, 0, 1, NULL, TRUE ) ), @@ -77,23 +77,22 @@ lcdSpinBox::lcdSpinBox( int _num_digits, const QString & _lcd_style, setAccessibleName( _name ); + // We should make a factory for these or something. m_lcdPixmap = new QPixmap( embed::getIconPixmap( QString( "lcd_" + _lcd_style ).toAscii().constData() ) ); - int margin = 1; //QStyle::PM_DefaultFrameWidth; - m_cellWidth = m_lcdPixmap->size().width() / lcdSpinBox::charsPerPixmap; m_cellHeight = m_lcdPixmap->size().height() / 2; - setFixedSize( m_cellWidth * (_num_digits+1) + (2*margin), - m_cellHeight + (2*margin) ); + m_marginWidth = m_cellWidth / 2; + + updateSize(); } - - lcdSpinBox::~lcdSpinBox() { + delete m_lcdPixmap; } @@ -102,17 +101,17 @@ void lcdSpinBox::paintEvent( QPaintEvent * _me ) QRect ur = _me->rect(); QPainter p( this ); - + QSize cellSize( m_cellWidth, m_cellHeight ); QRect cellRect( 0, 0, m_cellWidth, m_cellHeight ); - - int margin = 1;// QStyle::PM_DefaultFrameWidth; - int lcdWidth = m_cellWidth * (m_numDigits+1) + (margin*2); + + int margin = 1; // QStyle::PM_DefaultFrameWidth; + int lcdWidth = m_cellWidth * m_numDigits + (margin*m_marginWidth)*2; p.translate( width() / 2 - lcdWidth / 2, 0 ); p.save(); - + p.translate( margin, margin ); // Left Margin @@ -120,8 +119,8 @@ void lcdSpinBox::paintEvent( QPaintEvent * _me ) QRect( QPoint( charsPerPixmap*m_cellWidth, isEnabled()?0:m_cellHeight ), cellSize ) ); - - p.translate( (m_cellWidth+1) / 2, 0 ); + + p.translate( m_marginWidth, 0 ); // Padding for( int i=0; i < m_numDigits - m_display.length(); i++ ) @@ -150,7 +149,7 @@ void lcdSpinBox::paintEvent( QPaintEvent * _me ) } // Right Margin - p.drawPixmap( QRect( 0, 0, m_cellWidth / 2, m_cellHeight ), *m_lcdPixmap, + p.drawPixmap( QRect( 0, 0, m_marginWidth-1, m_cellHeight ), *m_lcdPixmap, QRect( charsPerPixmap*m_cellWidth, isEnabled()?0:m_cellHeight, m_cellWidth / 2, m_cellHeight ) ); @@ -161,7 +160,7 @@ void lcdSpinBox::paintEvent( QPaintEvent * _me ) QStyleOptionFrame opt; opt.initFrom( this ); opt.state = QStyle::State_Sunken; - opt.rect = QRect( 0, 0, m_cellWidth * (m_numDigits+1) + (margin*2), + opt.rect = QRect( 0, 0, m_cellWidth * m_numDigits + (margin+m_marginWidth)*2 - 1, m_cellHeight + (margin*2) ); style()->drawPrimitive( QStyle::PE_Frame, &opt, &p, this ); @@ -185,7 +184,6 @@ void lcdSpinBox::paintEvent( QPaintEvent * _me ) } - void lcdSpinBox::update( void ) { QString s = m_textForValue[model()->value()]; @@ -201,36 +199,50 @@ void lcdSpinBox::update( void ) */ } m_display = s; - + QWidget::update(); } - - void lcdSpinBox::setLabel( const QString & _txt ) { int margin = 1; m_label = _txt; - - setFixedSize( m_cellWidth * (m_numDigits+1) + (2*margin), - m_cellHeight + (2*margin) ); - setFixedSize( tMax( m_cellWidth*(m_numDigits+1) + (2*margin), - QFontMetrics( pointSize<6>( font() ) ).width( m_label ) ), - m_cellHeight + (2*margin) + 10 ); - update(); + updateSize(); } - - void lcdSpinBox::setEnabled( bool _on ) { QWidget::setEnabled( _on ); } +void lcdSpinBox::setMarginWidth( int _width ) +{ + m_marginWidth = _width; + + updateSize(); +} + + +void lcdSpinBox::updateSize() +{ + int margin = 1; + if (m_label.isEmpty()) { + setFixedSize( m_cellWidth * m_numDigits + 2*(margin+m_marginWidth), + m_cellHeight + (2*margin) ); + } + else { + setFixedSize( tMax( + m_cellWidth * m_numDigits + 2*(margin+m_marginWidth), + QFontMetrics( pointSize<6>( font() ) ).width( m_label ) ), + m_cellHeight + (2*margin) + 10 ); + } + + update(); +} void lcdSpinBox::contextMenuEvent( QContextMenuEvent * _me ) @@ -258,8 +270,6 @@ void lcdSpinBox::contextMenuEvent( QContextMenuEvent * _me ) } - - void lcdSpinBox::mousePressEvent( QMouseEvent * _me ) { if( _me->button() == Qt::LeftButton && _me->y() < m_cellHeight + 2 ) @@ -271,8 +281,6 @@ void lcdSpinBox::mousePressEvent( QMouseEvent * _me ) } - - void lcdSpinBox::mouseMoveEvent( QMouseEvent * _me ) { if( _me->buttons() & Qt::LeftButton ) @@ -289,8 +297,6 @@ void lcdSpinBox::mouseMoveEvent( QMouseEvent * _me ) } - - void lcdSpinBox::mouseReleaseEvent( QMouseEvent * _me ) { model()->addJournalEntryFromOldToCurVal(); @@ -300,8 +306,6 @@ void lcdSpinBox::mouseReleaseEvent( QMouseEvent * _me ) } - - void lcdSpinBox::wheelEvent( QWheelEvent * _we ) { _we->accept(); @@ -312,7 +316,6 @@ void lcdSpinBox::wheelEvent( QWheelEvent * _we ) - #include "lcd_spinbox.moc"