00001 00002 // MathGUI = a WYSIWYG equation editor + a powerful math engine // 00003 // Copyright (C) 2003 by Francesco Montorsi // 00004 // // 00005 // This library is free software; you can redistribute it and/or // 00006 // modify it under the terms of the GNU Lesser General Public // 00007 // License as published by the Free Software Foundation; either // 00008 // version 2.1 of the License, or (at your option) any later // 00009 // version. // 00010 // // 00011 // This library is distributed in the hope that it will be useful, // 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of // 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // 00014 // GNU Lesser General Public License for more details. // 00015 // // 00016 // You should have received a copy of the GNU Lesser General Public // 00017 // License along with this program; if not, write to the Free // 00018 // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, // 00019 // MA 02111-1307, USA. // 00020 // // 00021 // For any comment, suggestion or feature request, please contact // 00022 // the administrator of the project at frm@users.sourceforge.net // 00023 // // 00030 00031 00032 00033 // optimization for GCC compiler 00034 #if defined(__GNUG__) && !defined(__APPLE__) 00035 #pragma implementation "OptDlg.h" 00036 #endif 00037 00038 00039 // includes 00040 #include "mg/mgprec.h" 00041 00042 #ifndef mgPRECOMP 00043 #include "mg/OptDlg.h" 00044 #include "mg/OptBtnPanel.h" 00045 #include "mg/OptTreeCtrl.h" 00046 00047 // the panels which can be displayed by this dialog... 00048 #include "mg/OptBasePanel.h" 00049 #include "mg/OptGeneral.h" 00050 #include "mg/OptKeyBindings.h" 00051 #include "mg/OptFontSettings.h" 00052 #endif 00053 00054 00055 00056 // event table for mgOptDlg 00057 IMPLEMENT_CLASS(mgOptDlg, wxDialog ) 00058 BEGIN_EVENT_TABLE(mgOptDlg,wxDialog) 00059 EVT_BUTTON( OPTIONSDLG_BTN_OK, mgOptDlg::OnOkButton ) 00060 EVT_BUTTON( OPTIONSDLG_BTN_CANCEL, mgOptDlg::OnCancelButton ) 00061 EVT_BUTTON( OPTIONSDLG_BTN_APPLY, mgOptDlg::OnApplyButton ) 00062 EVT_TREE_SEL_CHANGED( OPTIONSDLG_TREELIST, mgOptDlg::OnItemSelected ) 00063 END_EVENT_TABLE() 00064 00065 // defines the custom command event sent to the app object when options change 00066 DEFINE_EVENT_TYPE( mgEVT_OPTIONS_CHANGED ) 00067 00068 00069 00070 00071 // -------------------------------------------- 00072 // mcOPTIONSDLG 00073 // -------------------------------------------- 00074 00075 mgOptDlg::mgOptDlg( wxWindow* parent, wxWindowID id, wxConfig* config ) 00076 : wxDialog( parent, id, wxT("MathStudio Options"), 00077 wxDefaultPosition, wxSize( 660, 500), 00078 wxCAPTION | wxSYSTEM_MENU | wxRESIZE_BORDER ) 00079 { 00080 // inits the option's panel actually displayed 00081 m_actualPanel = 0; 00082 // m_emptyPanel = 0; 00083 00084 // set the event handler which will receive our custom events 00085 SetClientEvtHandler(parent); 00086 00087 // creates the button panel and the treelist control 00088 m_treeWnd = new mgOptionsTreeCtrl( this ); 00089 m_buttonWnd = new mgOptionsBtnPanel( this ); 00090 00091 CreateLayout( this ); // creates the layout objects for the tree child windows 00092 //DisplayPanel( Id_mgOptBasePanel ); // creates and displays the empy panel 00093 00094 // selects the first children of the root node: THIS DOESN'T WORK 00095 // on wxGTK: it provokes a segmentation fault !!!! 00096 //long tmp; 00097 //wxTreeItemId n = m_treeWnd->GetRootItem(); 00098 //m_treeWnd->SelectItem(m_treeWnd->GetItemData(m_treeWnd->GetFirstChild(n, tmp))); 00099 } 00100 00102 mgOptDlg::~mgOptDlg() 00103 { 00104 } 00105 00106 00107 00108 00109 void mgOptDlg::CreateLayout( wxWindow* parent ) 00110 { 00111 #ifdef OPTIONSDLG_USE_LAYOUTCONSTRAINTS 00112 // Set constraints for the tree list control: same as the parent window 00113 // with a 10 pixel margin and an absolute width of 160 pixels 00114 wxLayoutConstraints* treeLayout = new wxLayoutConstraints; 00115 wxASSERT( treeLayout ); 00116 00117 treeLayout->left.SameAs (parent, wxLeft, 10 ); 00118 treeLayout->top.SameAs (parent, wxTop, 10 ); 00119 treeLayout->width.Absolute ( 160 ); 00120 treeLayout->bottom.SameAs( parent, wxBottom, 10); 00121 m_treeWnd->SetConstraints( treeLayout ); 00122 00123 // Set constraints for the button panel window: 00124 // The button panel is located just left of the tree list control, at the 00125 // bottom of parent window and it has an absolute height of 70 pixels 00126 // Its width is strechable to the right end of the parent 00127 wxLayoutConstraints* buttonLayout = new wxLayoutConstraints; 00128 wxASSERT( buttonLayout ); 00129 00130 buttonLayout->left.RightOf ( m_treeWnd, 10 ); 00131 buttonLayout->height.Absolute ( 70 ); 00132 buttonLayout->right.SameAs ( parent, wxRight, 10 ); 00133 buttonLayout->bottom.SameAs( parent, wxBottom, 10); 00134 m_buttonWnd->SetConstraints( buttonLayout ); 00135 00136 // creates the layout for the option's panels 00137 // but since no windows are yet created, it does not call SetConstraints for 00138 // this object, instead it is stored in a data members and when option's panels 00139 // will be created, a newly created copy of this object is set as constraints 00140 // for the panel 00141 m_optionLayout = new wxLayoutConstraints; 00142 wxASSERT( m_optionLayout ); 00143 00144 m_optionLayout->left.RightOf ( m_treeWnd, 10 ); 00145 m_optionLayout->top.SameAs( parent, wxTop, 10 ); 00146 m_optionLayout->right.SameAs ( parent, wxRight, 10 ); 00147 m_optionLayout->bottom.Above( m_buttonWnd, 10); 00148 00149 // forces layout to be handled automatically by wxWidgets in OnSize() handlers 00150 SetAutoLayout( TRUE ); 00151 00152 #else 00153 00154 // use sizers... 00155 m_mainSizer = new wxBoxSizer(wxHORIZONTAL); 00156 m_optionSizer = new wxBoxSizer(wxVERTICAL); 00157 00158 // DisplayPanel() will prepend to this sizer the actual panel 00159 m_optionSizer->Add(m_buttonWnd, 1, wxGROW); 00160 00161 // place in the m_mainSizer sizer of the dialog both the treectrl, 00162 // the actual panel and the OK, CANCEL, APPLY buttons 00163 m_mainSizer->Add(m_treeWnd, 2, wxGROW | wxALL, 10); 00164 m_mainSizer->Add(m_optionSizer, 5, wxGROW | wxALL, 5); 00165 00166 SetSizer(m_mainSizer); 00167 m_mainSizer->SetSizeHints(this); 00168 00169 #endif // OPTIONSDLG_USE_LAYOUTCONSTRAINTS 00170 00171 // this doesn't work :-( 00172 /*long tmp; 00173 wxTreeItemId n = m_treeWnd->GetRootItem(); 00174 m_treeWnd->SelectItem(m_treeWnd->GetItemData(m_treeWnd->GetFirstChild(n, tmp)));*/ 00175 } 00176 00177 00178 00179 mgOptBasePanel *mgOptDlg::CreatePanel( mgOptTreeCtrlItemData *itemData, const wxString &itemLabel ) 00180 { 00181 mgLogDebug( wxT("mgOptDlg::CreatePanel() itemData=%p"), itemData ); 00182 wxASSERT( itemData ); 00183 00184 #ifdef OPTIONSDLG_USE_LAYOUTCONSTRAINTS 00185 // the copy of the constraints object 00186 wxLayoutConstraints* c = new wxLayoutConstraints( *m_optionLayout ); 00187 wxASSERT( c ); 00188 #endif 00189 00190 mgOptBasePanel* panel = 0; 00191 00192 #ifdef NOT_DEFINED 00193 // this piece of code constructs a mgOptBasePanel-derived class from its 00194 // classname using wxWidgets's RTTI feature and the 'wxCreateDynamicObject()' 00195 // function. 00196 // It seems that not all platforms supports the dynamic creation of objects 00197 // so I have stripped out this code fragment 00198 // but I still leave the possibility of using this feature in the future 00199 wxString className = itemData->m_className; 00200 panel = ( mgOptBasePanel*) ::wxCreateDynamicObject( className ); 00201 #endif 00202 00203 // gets the ID of the class 00204 IdOptionsPanel id = itemData->m_classID; 00205 00206 switch ( id ) { 00207 case Id_mgOptGeneralPanel : 00208 panel = new mgOptGeneralPanel(); 00209 break; 00210 case Id_mgOptKeyBindingsPanel : 00211 panel = new mgOptKeyBindingsPanel(); 00212 break; 00213 case Id_mgOptFontSettingsPanel: 00214 panel = new mgOptFontSettingsPanel(); 00215 break; 00216 default : 00217 panel = NULL; 00218 break; 00219 } 00220 00221 wxASSERT( panel ); 00222 00223 00224 // two step creation because dynamic creation only accepts default ctor 00225 // the problem is that in the default ctor we cannot set much (for 00226 // example ew cannot call SetBackgroundColor() becasue the object is 00227 // not yet created. 00228 // We have to set backgrounds and children only when the Create function 00229 // is called. 00230 panel->Create( this, -1 ); 00231 00232 // after the windows substystem has fully created the underlaying structures 00233 // we can call the virtual Setup() function in order to let the derived 00234 // panel initialize itself 00235 panel->Setup( itemLabel ); 00236 00237 #ifdef OPTIONSDLG_USE_LAYOUTCONSTRAINTS 00238 // use constraints 00239 panel->SetConstraints( c ); 00240 #endif 00241 00242 mgLogDebug( wxT("mgOptDlg::CreatePanel() . panel created") ); 00243 00244 return panel; 00245 } 00246 00247 void mgOptDlg::DisplayPanel( wxTreeItemId itemId ) 00248 { 00249 mgLogDebug( wxT("mgOptDlg::DisplayPanel() - start\n") ); 00250 wxASSERT( itemId.IsOk() ); 00251 00252 // gets the item-data structure associated with the treelist item 00253 mgOptTreeCtrlItemData *itemData = 00254 ( mgOptTreeCtrlItemData* ) m_treeWnd->GetItemData( itemId ); 00255 00256 // gets the item label 00257 wxString itemLabel = m_treeWnd->GetItemText( itemId ); 00258 00259 mgLogDebug( wxT("mgOptDlg::Display Panel() label=%s, item-data=%p"), 00260 itemLabel.c_str(), itemData ); 00261 00262 wxASSERT( itemData != 0 ); 00263 00264 // gets the panel pointer (NULL if not yet created) 00265 mgOptBasePanel* newPanel = itemData->m_panel; 00266 mgLogDebug( wxT("mgOptDlg::DisplayPanel() - itemData=%p panel=%p classname=%s"), 00267 itemData, itemData->m_panel, (itemData->m_className).c_str() ); 00268 00269 00270 // if newPanel == ZERO no instance of the specialized class was yet created 00271 // so creates it and stores the pointer in the item-data structure 00272 if ( newPanel == 0 ) { 00273 newPanel = CreatePanel( itemData, itemLabel ); 00274 itemData->m_panel = newPanel; 00275 } 00276 00277 // if the selected panel is the already displayed one (the user just 00278 // clicks twice upon a tree-list item), does nothing 00279 if ( m_actualPanel == newPanel ) 00280 return; 00281 00282 // hides the previously displayed panel and shows the actual one 00283 if ( m_actualPanel != 0 ) 00284 m_actualPanel->Show( FALSE ); 00285 00286 #ifndef OPTIONSDLG_USE_LAYOUTCONSTRAINTS 00287 00288 // remove old panel from sizer 00289 if (m_actualPanel) 00290 m_optionSizer->Remove(m_actualPanel); 00291 00292 // prepend the new one 00293 m_optionSizer->Prepend(newPanel, 7, wxALL | wxGROW, 5); 00294 m_optionSizer->Layout(); 00295 m_mainSizer->Layout(); 00296 00297 // this call is very important because it sets the minimum size 00298 // which is allowed for the options dlg: it's surely changed 00299 // if we changed the currently displayed panel... 00300 m_mainSizer->SetSizeHints(this); 00301 00302 mgLogDebug( wxT("mgOptDlg::DisplayPanel() - sizer has been prepended") ); 00303 00304 #endif 00305 00306 wxASSERT( newPanel != 0 ); 00307 00308 mgLogDebug( wxT("mgOptDlg::DisplayPanel() - showing the panel") ); 00309 00310 // refresh and center the dialog 00311 CenterOnScreen(); 00312 newPanel->Show( TRUE ); 00313 m_actualPanel = newPanel; 00314 Refresh(); 00315 } 00316 00317 void mgOptDlg::CommitChanges() 00318 { 00319 mgLogDebug( wxT("Edit - Options dialog box: Committing changes") ); 00320 //return; // for now, 00321 00322 // iterate through m_treeWnd treelist's items and obtain 00323 // the m_panel data member of itemdata structure 00324 // then calls the CommitChanges() function of every panel which 00325 // returns the type of changes the panel is responsible of. 00326 // The type returned from the panel's CommitChanges function 00327 // is OR'ed with the previuos returned one. 00328 // After all panel's CommitChanges() function were called, the 00329 // cumulative type of changes is stored in the m_clientData 00330 // member of the custom event 00331 //mgOptChangedType t = OptChanged_None; 00332 //mgOptBasePanel *panel = 0; 00333 wxASSERT( m_treeWnd != 0 ); 00334 00335 int depthLevel = 0; 00336 00337 long cookie[OPTIONSDLG_MAX_TREELIST_DEPTH]; // used for iteration 00338 wxTreeItemId rootID = m_treeWnd->GetRootItem(); 00339 wxTreeItemId childId[OPTIONSDLG_MAX_TREELIST_DEPTH]; 00340 00341 // obtains the first child of the root node and checks if 00342 // it is valid. if not, there are no items in the treelist 00343 childId[0] = m_treeWnd->GetFirstChild( rootID, cookie[0] ); 00344 if ( !childId[0].IsOk() ) { 00345 mgLogDebug( wxT("mgOptDlg::CommitChanges() - no items in trelist\n") ); 00346 return; 00347 } 00348 00349 // iterates through items and sub-items. 00350 while ( 1 ) { 00351 // checks if the childId[0] is valid 00352 // otherwise, there are no more items 00353 // we checkk if the actual level child has children. Is yes, 00354 // we increse the depth level and obtain the children of the child 00355 if ( m_treeWnd->ItemHasChildren( childId[depthLevel] )) { 00356 wxTreeItemId temp; // the parent id 00357 ++depthLevel; 00358 wxASSERT( depthLevel < OPTIONSDLG_MAX_TREELIST_DEPTH ); 00359 childId[depthLevel] = m_treeWnd->GetFirstChild( temp, cookie[depthLevel] ); 00360 } 00361 else { 00362 // the item has no children, so we do not go down the hierarchy 00363 // but we obtain the panel's pointer of the item and call its 00364 // CommitChanges function. 00365 mgOptTreeCtrlItemData *itemData = 00366 (mgOptTreeCtrlItemData*) m_treeWnd->GetItemData( childId[depthLevel] ); 00367 wxASSERT( itemData != 0 ); 00368 00369 if ( itemData->m_panel != 0 ) { 00370 itemData->m_panel->CommitChanges( m_config ); 00371 } 00372 00373 // we get the next sibling of the item until no more 00374 // siblings are returned. 00375 // when no more siblings are returned we go up in the hierarchy 00376 // by decreasing the depthLevel 00377 childId[depthLevel] = m_treeWnd->GetNextSibling( childId[depthLevel]); 00378 if ( !childId[depthLevel].IsOk() ) { 00379 // no more siblings, we go up in the hierarchy 00380 --depthLevel; 00381 // the last sibling item is the child of the root node? 00382 // if yes, we are done 00383 if ( depthLevel < 0 ) 00384 break; 00385 } 00386 } 00387 } 00388 00389 // if event notification is enabled, send our custom event to the 00390 // client event handler... 00391 wxCommandEvent ev( mgEVT_OPTIONS_CHANGED ); 00392 if (m_pClientEvtHandler) 00393 m_pClientEvtHandler->AddPendingEvent( ev ); 00394 } 00395 00396 00397 00398 void mgOptDlg::OnOkButton( wxCommandEvent &ev ) 00399 { 00400 CommitChanges(); 00401 EndModal( wxID_OK ); 00402 } 00403 00404 void mgOptDlg::OnCancelButton( wxCommandEvent &ev ) 00405 { 00406 EndModal( wxID_CANCEL ); 00407 } 00408 00409 void mgOptDlg::OnApplyButton( wxCommandEvent &ev ) 00410 { 00411 CommitChanges(); 00412 } 00413 00414 void mgOptDlg::OnItemSelected( wxTreeEvent& ev ) 00415 { 00416 // gets the newly selected item ID 00417 wxTreeItemId id = ev.GetItem(); 00418 00419 // calls the DisplayPanel function in order to display the option's panel 00420 // relevant for the selected item. 00421 DisplayPanel( id ); 00422 } 00423 00424 00425 00426 00427 00428
[ Top ] |