/********************************************************************** Audacity: A Digital Audio Editor AvcCompressor.cpp Vincent A. Busam *******************************************************************//** \class EffectAvcCompressor \brief An unused Effect (we use EffectCompressor instead) derived from EffectSimplePairedTwoTrackBase *//****************************************************************//** \class iAVCBufferList \brief An unused class used by EffectAvcCompressor. *//****************************************************************//** \class AvcCompressorDialog \brief An unused class used by unused effect, EffectAvcCompressor. *//*******************************************************************/ /* TODO List: 1. Add graph shows curve specified by grid, keep it up to date, allow setting of grid points by moving points in grid. 2. Better help 3. Radio button selection so Adjustment Settings can be times instead of samples. 4. Radio button selection so Amplification Settings can be db instead of raw values. 5. Save settings by name 6. Remove "help" text in window when Audacity help available. */ #include #include #include #include #include #include "../WaveTrack.h" #include "../Envelope.h" #include "../widgets/Ruler.h" #include "../Prefs.h" // Including the following cpp file is quite unorthodox, but it gives the opportunity to // use iAVC's capability of generating inline code for the important methods. We // can't trust compilers to generated inline code, even when the inline keyword is // used. #ifdef _WINDOWS // kludge for Audacity since we don't really have MS Windows #define max(a,b) ( (aGetEffectDescription()); //old //return wxString::Format("Applied effect: %s change window = %d samples", //(const char *)(this->GetEffectName()), mnChangeWindow); } inline void EffectAvcCompressor::OutputSample ( IAVCSAMPLETYPE left, IAVCSAMPLETYPE right ) { if ( mpBufferList->mnNext >= mpBufferList->mnLen ) { // have filled up this buffer, move to next iAVCBufferList * pOld = mpBufferList; mpBufferList = mpBufferList->mpNext; delete pOld; } if ( mpBufferList == NULL ) return; // set the output sample values ((IAVCSAMPLETYPE*)mpBufferList->mpLeftBuffer)[mpBufferList->mnNext] = left; if ( mpBufferList->mpRightBuffer ) ((IAVCSAMPLETYPE*)mpBufferList->mpRightBuffer)[mpBufferList->mnNext] = right; ++mpBufferList->mnNext; } bool EffectAvcCompressor::PromptUser() { if ( mpDialog == NULL ) // reuse dialog so we keep user changes to values mpDialog = new AvcCompressorDialog(mParent, -1, wxT("Automatic Volume Control")); mpDialog->CentreOnParent(); mpDialog->ShowModal(); if (!mpDialog->GetReturnCode()) return false; mAutoVolCtrl.Reset(); // reset control before setting values // Set parameters for iAVC class unsigned short int *nTransform = new unsigned short int [ MULTIPLY_PCT_ARRAY_SIZE ]; mnChangeWindow=mpDialog->GetChangeWindow(); mpDialog->GetTransformArray(nTransform); if ( mAutoVolCtrl.SetSampleWindowSize(mpDialog->GetAdjusterWindow()+mnChangeWindow, mpDialog->GetAdjusterWindow(), 0) == false || mAutoVolCtrl.SetMinSamplesBeforeSwitch(mnChangeWindow) == false ) { wxMessageBox("Error setting parameters for automatic volume control."); return false; } mAutoVolCtrl.SetMaxPctChangeAtOnce(mpDialog->GetMinimumPercent()); mAutoVolCtrl.SetMultipliers(nTransform); mAutoVolCtrl.SetNumberTracks(mnTracks); mnDelay = mpDialog->GetDelay(); delete [] nTransform; return true; } bool EffectAvcCompressor::TransferParameters( Shuttle & shuttle ) { wxASSERT( false );// Not yet implemented. // shuttle.TransferInt("",,0); return true; } bool EffectAvcCompressor::Init() // invoked before PromptUser { if ( EffectSimplePairedTwoTrack::Init() == false ) return false; return true; } bool EffectAvcCompressor::ProcessSimplePairedTwoTrack(/*IAVCSAMPLETYPE*/ void *bufferLeft, /*IAVCSAMPLETYPE*/ void *bufferRight, // may be 0 sampleCount len) { // build new iAVCBufferList node iAVCBufferList * pBufferNode = new iAVCBufferList; if ( mpBufferPrevious != NULL ) mpBufferPrevious->mpNext = pBufferNode; // link to end of list else mpBufferList = pBufferNode; // have first node in list mpBufferPrevious = pBufferNode; // this node now the last added to list pBufferNode->mpNext = NULL; pBufferNode->mpLeftBuffer = bufferLeft; pBufferNode->mpRightBuffer = bufferRight; pBufferNode->mnLen = len; pBufferNode->mnNext = 0; // process samples in these buffer(s) IAVCSAMPLETYPE* typedBufferLeft = (IAVCSAMPLETYPE*)bufferLeft; IAVCSAMPLETYPE* typedBufferRight = (IAVCSAMPLETYPE*)bufferRight; sampleCount i; IAVCSAMPLETYPE left; IAVCSAMPLETYPE right = 0; for ( i = 0 ; i < len ; ++i ) { left = typedBufferLeft[i]; if ( typedBufferRight ) right = typedBufferRight[i]; #ifdef IAVC_INLINE // use inline SetNextSample() #define IAVC_SETNEXTSAMPLE #include "../../lib-src/iAVC/iAVC.cpp" #undef IAVC_SETNEXTSAMPLE // use inline GetNextSample() if ( mnDelay <= 0 ) { // get a value only if past desired delay #define IAVC_GETNEXTSAMPLE #include "../../lib-src/iAVC/iAVC.cpp" #undef IAVC_SETNEXTSAMPLE } #else // call SetNextSample() and GetNextSample() mAutoVolCtrl.SetNextSample(left, right); if ( mnDelay <= 0 ) { // get a value only if past desired delay mAutoVolCtrl.GetNextSample(left, right); } #endif if ( mnDelay <= 0 ) { // get a value only if past desired delay OutputSample ( left, right ); typedBufferLeft[i] = left; if ( typedBufferRight ) typedBufferRight[i] = right; } else { // count down the delay amount --mnDelay; } } return true; } void EffectAvcCompressor::End() { IAVCSAMPLETYPE left; IAVCSAMPLETYPE right = 0; // We now need to output any samples still waiting because while ( mpBufferList != NULL ) { #ifdef IAVC_INLINE // use inline GetNextSample() #define IAVC_GETNEXTSAMPLE #include "../../lib-src/iAVC/iAVC.cpp" #undef IAVC_SETNEXTSAMPLE #else // call GetNextSample() mAutoVolCtrl.GetNextSample(left, right); #endif OutputSample ( left, right ); } mpBufferPrevious = NULL; EffectSimplePairedTwoTrack::End(); } // WDR: class implementations //---------------------------------------------------------------------------- // AvcCompressorDialog //---------------------------------------------------------------------------- #define PREF_ADJWIN "/Effect/AVC/user1/adjwin" #define PREF_DELAY "/Effect/AVC/user1/delay" #define PREF_CHANGE "/Effect/AVC/user1/change" #define PREF_MINPCT "/Effect/AVC/user1/minpct" #define PREF_ENABLE "/Effect/AVC/user1/%d/enable" #define PREF_HORIZ "/Effect/AVC/user1/%d/horiz" #define PREV_VERT "/Effect/AVC/user1/%d/vert" // WDR: event table for AvcCompressorDialog BEGIN_EVENT_TABLE(AvcCompressorDialog,wxDialog) EVT_BUTTON( wxID_OK, AvcCompressorDialog::OnOK ) EVT_BUTTON( wxID_CANCEL, AvcCompressorDialog::OnCancel ) EVT_BUTTON( ID_RESTORE_DEFAULTS, AvcCompressorDialog::OnRestoreDefaults ) EVT_CHECKBOX(ID_FIRST_CURVE_CHECK+1, AvcCompressorDialog::OnCheckBox) EVT_CHECKBOX(ID_FIRST_CURVE_CHECK+2, AvcCompressorDialog::OnCheckBox) EVT_CHECKBOX(ID_FIRST_CURVE_CHECK+3, AvcCompressorDialog::OnCheckBox) EVT_CHECKBOX(ID_FIRST_CURVE_CHECK+4, AvcCompressorDialog::OnCheckBox) EVT_CHECKBOX(ID_FIRST_CURVE_CHECK+5, AvcCompressorDialog::OnCheckBox) END_EVENT_TABLE() AvcCompressorDialog::AvcCompressorDialog(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& size, long style ) : wxDialog( parent, id, title, position, size, style ), mctlAdjWin ( 0 ), mctlDelay ( 0 ), mctlChangeWin ( 0 ), mctlMinPct ( 0 ) { for ( int i = 0 ; i < NUM_CURVE_POINTS ; ++i ) { mctlCheckBoxes[i] = 0; mctlXAxis[i] = 0; mctlYAxis[i] = 0; } MakeAvcCompressorDialog( this, TRUE ); // First make sure all value initialized, especially horiz and vert first & last values wxCommandEvent event; OnRestoreDefaults(event); // Now read in from registry ReadPrefs(); } AvcCompressorDialog::~AvcCompressorDialog() { // zero out pointers in case reference counts being used mctlAdjWin = 0; mctlDelay = 0; mctlChangeWin = 0; mctlMinPct = 0; for ( int i = 0 ; i < NUM_CURVE_POINTS ; ++i ) { mctlCheckBoxes[i] = 0; mctlXAxis[i] = 0; mctlYAxis[i] = 0; } } // figure out Y value for each possible X value void AvcCompressorDialog::GetTransformArray( unsigned short int nTransform[MULTIPLY_PCT_ARRAY_SIZE] ) { long iCurPoint = 0; // index to mnXAxis and mnYAxis long iPrevPoint= 0; // index to mnXAxis and mnYAxis long iMultiply = 1; // iMultiply and iDivide used to calculate fractional slopes long iDivide = 1; long iBias = 0; // keeps values from decreasing nTransform [ 0 ] = 0; for ( long i = 0 ; i < MULTIPLY_PCT_ARRAY_SIZE - 1 ; ++i ) { if ( i == mnXAxis [ iCurPoint ] && iCurPoint < NUM_CURVE_POINTS - 1 ) { // time to move to next point iPrevPoint = iCurPoint; // find next checked point while ( mctlCheckBoxes[++iCurPoint]->GetValue() == false) ; // last box guaranteed to be checked // Recalculate bias based on what would be calculated with old values and // what would be calculated with new values. long iOld = i * iMultiply / iDivide + iBias; iMultiply = mnYAxis [ iCurPoint ] - mnYAxis [ iPrevPoint ]; iDivide = mnXAxis [ iCurPoint ] - mnXAxis [ iPrevPoint ]; iBias = iOld - ( i * iMultiply / iDivide ); } nTransform [ i ] = (unsigned short int) ( i * iMultiply / iDivide + iBias ); } // set boundary case for loudest sound nTransform [ MULTIPLY_PCT_ARRAY_SIZE - 1 ] = MULTIPLY_PCT_ARRAY_SIZE - 1; } bool AvcCompressorDialog::LongRangeCheck ( wxWindow *window, const long nValue, const long nMin, const long nMax ) { if ( nValue < nMin || nValue > nMax ) { // value out of range if ( !wxValidator::IsSilent() ) wxBell(); wxString strTemp; strTemp.Printf ( wxT("Value must be from %d to %d."), nMin, nMax ); wxMessageBox(strTemp, wxT("Validation error"), wxOK | wxICON_EXCLAMATION, GetParent() ); if ( window ) window->SetFocus(); return false; } return true; } // WDR: handler implementations for AvcCompressorDialog void AvcCompressorDialog::OnOK(wxCommandEvent &event) { if ( Validate() && TransferDataFromWindow() ) { // do our dialog specific validation // Check Adjustment Settings mstrAdjWin.ToLong(&mnAdjWin); if ( LongRangeCheck( mctlAdjWin, mnAdjWin, ADJWIN_MIN, ADJWIN_MAX ) == false ) { // value out of range return; } mstrDelay.ToLong(&mnDelay); if ( LongRangeCheck( mctlDelay, mnDelay, DELAY_MIN, DELAY_MAX ) == false ) { // value out of range return; } mstrChangeWin.ToLong(&mnChangeWin); if ( LongRangeCheck( mctlChangeWin, mnChangeWin, CHANGE_MIN, CHANGE_MAX ) == false ) { // value out of range return; } if ( mnChangeWin > mnAdjWin ) { wxMessageBox(wxT("Change window size must be less than or equal to Adjustment window size."), wxT("Validation error"), wxOK | wxICON_EXCLAMATION, GetParent() ); if ( mctlChangeWin ) mctlChangeWin->SetFocus(); return; } mstrMinPct.ToLong(&mnMinPct); if ( LongRangeCheck( mctlMinPct, mnMinPct, MINPCT_MIN, MINPCT_MAX ) == false ) { // value out of range return; } // Check Amplification Settings long iPrevPoint= 0; // index to mnXAxis and mnYAxis for ( int i = 0 ; i < NUM_CURVE_POINTS ; ++i ) { mstrXAxis[i].ToLong(&mnXAxis[i]); mstrYAxis[i].ToLong(&mnYAxis[i]); // see if this is a checked point if ( mctlCheckBoxes[i]->GetValue() == false) continue; // last box guaranteed to be checked if ( i > 0 ) { if ( mnXAxis[i] <= mnXAxis[iPrevPoint] ) { wxMessageBox(wxT("Values in columns must be in ascending order."), wxT("Validation error"), wxOK | wxICON_EXCLAMATION, GetParent() ); mctlXAxis[(i==NUM_CURVE_POINTS-1) ? iPrevPoint : i]->SetFocus(); return; } if ( mnYAxis[i] <= mnYAxis[iPrevPoint] ) { wxMessageBox(wxT("Values in columns must be in ascending order."), wxT("Validation error"), wxOK | wxICON_EXCLAMATION, GetParent() ); mctlYAxis[(i==NUM_CURVE_POINTS-1) ? iPrevPoint : i]->SetFocus(); return; } } iPrevPoint = i; } // AOK, time to return WritePrefs(); // save values user entered for next execution if ( IsModal() ) EndModal(wxID_OK); else { SetReturnCode(wxID_OK); this->Show(FALSE); } } } void AvcCompressorDialog::OnCancel(wxCommandEvent &event) { EndModal(false); } static int* naSampleChoicesHoriz[5] = {iHoriz_1K_1K,iHoriz_1K_3HK,iHoriz_E75_5K,iHoriz_75_3500,iHoriz_AE75_3HK}; static int* naSampleChoicesVert[5] = {iVert_1K_1K, iVert_1K_3HK, iVert_E75_5K, iVert_75_3500, iVert_AE75_3HK}; void AvcCompressorDialog::OnRestoreDefaults(wxCommandEvent &event) { static int* naSampleChoicesHoriz[5] = {iHoriz_1K_1K,iHoriz_1K_3HK,iHoriz_E75_5K,iHoriz_75_3500,iHoriz_AE75_3HK}; static int* naSampleChoicesVert[5] = {iVert_1K_1K, iVert_1K_3HK, iVert_E75_5K, iVert_75_3500, iVert_AE75_3HK}; mstrAdjWin.Printf("%d", ADJWIN_DEFAULT); mstrDelay.Printf("%d", DELAY_DEFAULT); mstrChangeWin.Printf("%d", CHANGE_DEFAULT); mstrMinPct.Printf("%d", MINPCT_DEFAULT); for ( int i = 0 ; i < NUM_CURVE_POINTS ; ++ i ) { mctlCheckBoxes[i]->SetValue(true); mctlXAxis[i]->Show ( true ); mctlYAxis[i]->Show ( true ); mstrXAxis[i].Printf( "%d", naSampleChoicesHoriz[4][i] ); mstrYAxis[i].Printf( "%d", naSampleChoicesVert[4][i] ); } TransferDataToWindow(); } void AvcCompressorDialog::ReadPrefs() { int nTemp; bool bTemp; wxString strTemp; nTemp = gPrefs->Read ( PREF_ADJWIN, ADJWIN_DEFAULT ); mstrAdjWin.Printf("%d", nTemp); nTemp = gPrefs->Read ( PREF_DELAY, DELAY_DEFAULT ); mstrDelay.Printf("%d", nTemp); nTemp = gPrefs->Read ( PREF_CHANGE, CHANGE_DEFAULT ); mstrChangeWin.Printf("%d", nTemp); nTemp = gPrefs->Read ( PREF_MINPCT, MINPCT_DEFAULT ); mstrMinPct.Printf("%d", nTemp); for ( int i = 1 ; i < NUM_CURVE_POINTS - 1 ; ++ i ) { strTemp.Printf(PREF_ENABLE,i); bTemp = ( gPrefs->Read ( strTemp, true ) == 0 ) ? false : true; mctlCheckBoxes[i]->SetValue(bTemp); mctlXAxis[i]->Show ( bTemp ); mctlYAxis[i]->Show ( bTemp ); strTemp.Printf(PREF_HORIZ,i); nTemp = gPrefs->Read ( strTemp, naSampleChoicesHoriz[4][i] ); mstrXAxis[i].Printf( "%d", nTemp ); strTemp.Printf(PREV_VERT,i); nTemp = gPrefs->Read ( strTemp, naSampleChoicesVert[4][i] ); mstrYAxis[i].Printf( "%d", nTemp ); } TransferDataToWindow(); } void AvcCompressorDialog::WritePrefs() { wxString strTemp; gPrefs->Write ( PREF_ADJWIN, mnAdjWin ); gPrefs->Write ( PREF_DELAY, mnDelay ); gPrefs->Write ( PREF_CHANGE, mnChangeWin ); gPrefs->Write ( PREF_MINPCT, mnMinPct ); for ( int i = 1 ; i < NUM_CURVE_POINTS - 1 ; ++ i ) { strTemp.Printf(PREF_ENABLE,i); gPrefs->Write ( strTemp, mctlCheckBoxes[i]->GetValue() ); strTemp.Printf(PREF_HORIZ,i); gPrefs->Write ( strTemp, mnXAxis[i] ); strTemp.Printf(PREV_VERT,i); gPrefs->Write ( strTemp, mnYAxis[i] ); } } void AvcCompressorDialog::OnCheckBox(wxCommandEvent & event) { bool bCheck = mctlCheckBoxes[event.m_id-ID_FIRST_CURVE_CHECK]->GetValue(); mctlXAxis[event.m_id-ID_FIRST_CURVE_CHECK]->Show ( bCheck ); mctlYAxis[event.m_id-ID_FIRST_CURVE_CHECK]->Show ( bCheck ); } wxSizer *AvcCompressorDialog::MakeAvcCompressorDialog(wxWindow * parent, bool call_fit, bool set_sizer) { wxBoxSizer *mainSizer = new wxBoxSizer(wxVERTICAL); wxStaticBoxSizer *group; wxBoxSizer *boxSizer; wxStaticText *staticText; //wxTextCtrl *textCtrl; wxButton *button; wxFlexGridSizer *flexGridSizer; staticText = new wxStaticText(parent, ID_TEXT, wxT("Automatic Volume Control by Vincent A. Busam"), wxDefaultPosition, wxDefaultSize, 0); mainSizer->Add(staticText, 0, wxALIGN_CENTRE | wxALL, 5); // 0. Box Sizer for horizontal components wxBoxSizer *horizontalSizer = new wxBoxSizer(wxHORIZONTAL); // 1. Box Sizer for leftmost group of controls wxBoxSizer *leftSizer = new wxBoxSizer(wxVERTICAL); // 1.1 Group Box for adjustment window settings group = new wxStaticBoxSizer(new wxStaticBox(parent, -1, wxT("Adjustment Settings")), wxVERTICAL); flexGridSizer = new wxFlexGridSizer(2, 0, 0); // 1.1.1 Adjustment Window staticText = new wxStaticText(parent, ID_TEXT, wxT("Adjustment Window:"), wxDefaultPosition, wxDefaultSize, 0 ); flexGridSizer->Add(staticText, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxALL, 5); mctlAdjWin = new wxTextCtrl(parent, ID_ADJWINTEXT, "", wxDefaultPosition, wxSize(40, -1), 0, wxTextValidator(wxFILTER_NUMERIC, &mstrAdjWin ) ); flexGridSizer->Add(mctlAdjWin, 0, wxALIGN_CENTRE | wxALL, 5); // 1.1.2 Adjustment Delay staticText = new wxStaticText(parent, ID_TEXT, wxT("Adjustment Delay:"), wxDefaultPosition, wxDefaultSize, 0); flexGridSizer->Add(staticText, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxALL, 5); mctlDelay = new wxTextCtrl(parent, ID_DELAYTEXT, "", wxDefaultPosition, wxSize(40, -1), 0, wxTextValidator(wxFILTER_NUMERIC, &mstrDelay )); flexGridSizer->Add(mctlDelay, 0, wxALIGN_CENTRE | wxALL, 5); // 1.1.3 Min Change Window /* i18n-hint: the minimum size of the window that is changed */ staticText = new wxStaticText(parent, ID_TEXT, wxT("Minimum Change Window:"), wxDefaultPosition, wxDefaultSize, 0); flexGridSizer->Add(staticText, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxALL, 5); mctlChangeWin = new wxTextCtrl(parent, ID_CHANGEWINTEXT, "", wxDefaultPosition, wxSize(40, -1), 0, wxTextValidator(wxFILTER_NUMERIC, &mstrChangeWin )); flexGridSizer->Add(mctlChangeWin, 0, wxALIGN_CENTRE | wxALL, 5); // 1.1.4 Min Change % staticText = new wxStaticText(parent, ID_TEXT, wxT("Minimum Change %:"), wxDefaultPosition, wxDefaultSize, 0); flexGridSizer->Add(staticText, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxALL, 5); mctlMinPct = new wxTextCtrl(parent, ID_MINPCTTEXT, "", wxDefaultPosition, wxSize(40, -1), 0, wxTextValidator(wxFILTER_NUMERIC, &mstrMinPct )); flexGridSizer->Add(mctlMinPct, 0, wxALIGN_CENTRE | wxALL, 5); // 1.1.end Add group group->Add( flexGridSizer, 0, wxALIGN_CENTRE|wxALL, 5 ); leftSizer->Add( group, 0, wxALIGN_TOP |wxALL, 5 ); // DMM: the following text box is too difficult to translate as-is. Taken out of // i18n for now. // 1.2 area under group box staticText = new wxStaticText(parent, ID_TEXT, ("Above values are in samples.\n" "Adjustment Window defines number of \nsamples in moving average.\n" "Change window defines minimum time \nbetween volume changes.\n" "Minimum % change of volume adjustment \nbefore making a volume change.\n" "Grid at right determines how much to amplify \neach volume level.\n" "For more information see: \n" "http://www.busam.com/skyland/iavc\n" "7/21/02: WAV and MP3 files both work." ), wxDefaultPosition, wxDefaultSize, 0); leftSizer->Add(staticText, 0, wxALIGN_CENTRE | wxALL, 5); // 1.end horizontalSizer->Add( leftSizer, 0, wxALIGN_TOP |wxALL, 5 ); // 2. Group Box for volume settings group = new wxStaticBoxSizer(new wxStaticBox(parent, -1, wxT("Amplification Settings")), wxVERTICAL); // 2.1 Add one row each time through loop flexGridSizer = new wxFlexGridSizer(3, 0, 0); staticText = new wxStaticText(parent, ID_TEXT, _("Enabled"), wxDefaultPosition, wxDefaultSize, 0); flexGridSizer->Add(staticText, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxALL, 5); staticText = new wxStaticText(parent, ID_TEXT, wxT("Original Value"), wxDefaultPosition, wxDefaultSize, 0); flexGridSizer->Add(staticText, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxALL, 5); staticText = new wxStaticText(parent, ID_TEXT, wxT("New Value"), wxDefaultPosition, wxDefaultSize, 0); flexGridSizer->Add(staticText, 0, wxALIGN_RIGHT | wxALIGN_CENTER_VERTICAL | wxALL, 5); for ( int i = 0 ; i < NUM_CURVE_POINTS ; ++i ) { mctlCheckBoxes[i] = new wxCheckBox(parent, ID_FIRST_CURVE_CHECK + i, "", wxDefaultPosition, wxSize(40, -1), 0); flexGridSizer->Add(mctlCheckBoxes[i], 0, wxALIGN_CENTRE | wxALL, 5); mctlCheckBoxes[i]->SetValue(true); mctlXAxis[i] = new wxTextCtrl(parent, ID_FIRST_CURVE_X + i, "", wxDefaultPosition, wxSize(40, -1), 0, wxTextValidator(wxFILTER_NUMERIC, &mstrXAxis[i] )); flexGridSizer->Add(mctlXAxis[i], 0, wxALIGN_CENTRE | wxALL, 5); mctlYAxis[i] = new wxTextCtrl(parent, ID_FIRST_CURVE_Y + i, "", wxDefaultPosition, wxSize(40, -1), 0, wxTextValidator(wxFILTER_NUMERIC, &mstrYAxis[i] )); flexGridSizer->Add(mctlYAxis[i], 0, wxALIGN_CENTRE | wxALL, 5); } mctlCheckBoxes[0]->Enable(false); mctlXAxis[0]->Enable(false); mctlYAxis[0]->Enable(false); mctlCheckBoxes[NUM_CURVE_POINTS-1]->Enable(false); mctlXAxis[NUM_CURVE_POINTS-1]->Enable(false); mctlYAxis[NUM_CURVE_POINTS-1]->Enable(false); // 2.end Add group group->Add( flexGridSizer, 0, wxALIGN_CENTRE|wxALL, 5 ); horizontalSizer->Add( group, 0, wxALIGN_CENTRE|wxALL, 5 ); mainSizer->Add( horizontalSizer, 0, wxALIGN_CENTRE|wxALL, 5 ); // Last: Add buttons boxSizer = new wxBoxSizer(wxHORIZONTAL); // Add restore defaults button button = new wxButton(parent, ID_RESTORE_DEFAULTS, wxT("Restore Defaults"), wxDefaultPosition, wxDefaultSize, 0); boxSizer->Add(button, 0, wxALIGN_CENTRE | wxALL, 5); // Add Cancel button button = new wxButton(parent, wxID_CANCEL, _("&Cancel"), wxDefaultPosition, wxDefaultSize, 0); boxSizer->Add(button, 0, wxALIGN_CENTRE | wxALL, 5); // Add OK button button = new wxButton(parent, wxID_OK, _("OK"), wxDefaultPosition, wxDefaultSize, 0); button->SetDefault(); boxSizer->Add(button, 0, wxALIGN_CENTRE | wxALL, 5); mainSizer->Add(boxSizer, 0, wxALIGN_CENTRE | wxALL, 5); if (set_sizer) { parent->SetAutoLayout(TRUE); parent->SetSizer(mainSizer); if (call_fit) { mainSizer->Fit(parent); mainSizer->SetSizeHints(parent); } } return mainSizer; } // Indentation settings for Vim and Emacs and unique identifier for Arch, a // version control system. Please do not modify past this point. // // Local Variables: // c-basic-offset: 3 // indent-tabs-mode: nil // End: // // vim: et sts=3 sw=3 // arch-tag: 129a8b19-9efd-4b47-95cb-c5534840a0f0