sampleprops.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664
  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name: samples/propgrid/sampleprops.cpp
  3. // Purpose: wxPropertyGrid Sample Properties
  4. // Author: Jaakko Salli
  5. // Modified by:
  6. // Created: 2006-03-05
  7. // Copyright: (c) Jaakko Salli
  8. // Licence: wxWindows licence
  9. /////////////////////////////////////////////////////////////////////////////
  10. // For compilers that support precompilation, includes "wx/wx.h".
  11. #include "wx/wxprec.h"
  12. #ifdef __BORLANDC__
  13. #pragma hdrstop
  14. #endif
  15. // for all others, include the necessary headers (this file is usually all you
  16. // need because it includes almost all "standard" wxWidgets headers)
  17. #ifndef WX_PRECOMP
  18. #include "wx/wx.h"
  19. #endif
  20. #include "wx/fontdlg.h"
  21. // -----------------------------------------------------------------------
  22. #include <wx/propgrid/propgrid.h>
  23. #include <wx/propgrid/advprops.h>
  24. #ifndef WX_PROPGRID_SAMPLEPROPS_H
  25. #include "sampleprops.h"
  26. #endif
  27. // -----------------------------------------------------------------------
  28. // wxFontDataProperty
  29. // -----------------------------------------------------------------------
  30. // Dummy comparison required by value type implementation.
  31. bool operator == (const wxFontData&, const wxFontData&)
  32. {
  33. return FALSE;
  34. }
  35. // Custom version of wxFontProperty that also holds colour in the value.
  36. // Original version by Vladimir Vainer.
  37. IMPLEMENT_VARIANT_OBJECT_SHALLOWCMP(wxFontData)
  38. WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFontDataProperty,wxFontProperty,
  39. wxFontData,const wxFontData&,TextCtrlAndButton)
  40. wxFontDataProperty::wxFontDataProperty( const wxString& label, const wxString& name,
  41. const wxFontData& value ) : wxFontProperty(label,name,value.GetInitialFont())
  42. {
  43. wxFontData fontData(value);
  44. // Fix value.
  45. fontData.SetChosenFont(value.GetInitialFont());
  46. if ( !fontData.GetColour().IsOk() )
  47. fontData.SetColour(*wxBLACK);
  48. // Set initial value - should be done in a simpler way like this
  49. // (instead of calling SetValue) in derived (wxObject) properties.
  50. m_value_wxFontData << value;
  51. // Add extra children.
  52. AddPrivateChild( new wxColourProperty(_("Colour"), wxPG_LABEL,
  53. fontData.GetColour() ) );
  54. }
  55. wxFontDataProperty::~wxFontDataProperty () { }
  56. void wxFontDataProperty::OnSetValue()
  57. {
  58. if ( m_value.GetType() != "wxFontData" )
  59. {
  60. if ( m_value.GetType() == "wxFont" )
  61. {
  62. wxFont font;
  63. font << m_value;
  64. wxFontData fontData;
  65. fontData.SetChosenFont(font);
  66. if ( !m_value_wxFontData.IsNull() )
  67. {
  68. wxFontData oldFontData;
  69. oldFontData << m_value_wxFontData;
  70. fontData.SetColour(oldFontData.GetColour());
  71. }
  72. else
  73. {
  74. fontData.SetColour(*wxBLACK);
  75. }
  76. wxVariant variant;
  77. variant << fontData;
  78. m_value_wxFontData = variant;
  79. }
  80. else
  81. {
  82. wxFAIL_MSG(wxT("Value to wxFontDataProperty must be eithe wxFontData or wxFont"));
  83. }
  84. }
  85. else
  86. {
  87. // Set m_value to wxFont so that wxFontProperty methods will work
  88. // correctly.
  89. m_value_wxFontData = m_value;
  90. wxFontData fontData;
  91. fontData << m_value_wxFontData;
  92. wxFont font = fontData.GetChosenFont();
  93. if ( !font.IsOk() )
  94. font = wxFont(10,wxSWISS,wxNORMAL,wxNORMAL);
  95. m_value = WXVARIANT(font);
  96. }
  97. }
  98. wxVariant wxFontDataProperty::DoGetValue() const
  99. {
  100. return m_value_wxFontData;
  101. }
  102. // Must re-create font dialog displayer.
  103. bool wxFontDataProperty::OnEvent( wxPropertyGrid* propgrid,
  104. wxWindow* WXUNUSED(primary), wxEvent& event )
  105. {
  106. if ( propgrid->IsMainButtonEvent(event) )
  107. {
  108. wxVariant useValue = propgrid->GetUncommittedPropertyValue();
  109. wxFontData fontData;
  110. fontData << useValue;
  111. fontData.SetInitialFont(fontData.GetChosenFont());
  112. wxFontDialog dlg(propgrid, fontData);
  113. if ( dlg.ShowModal() == wxID_OK )
  114. {
  115. wxVariant variant;
  116. variant << dlg.GetFontData();
  117. SetValueInEvent( variant );
  118. return true;
  119. }
  120. }
  121. return false;
  122. }
  123. void wxFontDataProperty::RefreshChildren()
  124. {
  125. wxFontProperty::RefreshChildren();
  126. if ( GetChildCount() < 6 ) // Number is count of wxFontProperty's children + 1.
  127. return;
  128. wxFontData fontData; fontData << m_value_wxFontData;
  129. wxVariant variant; variant << fontData.GetColour();
  130. Item(6)->SetValue( variant );
  131. }
  132. wxVariant wxFontDataProperty::ChildChanged( wxVariant& thisValue,
  133. int childIndex,
  134. wxVariant& childValue ) const
  135. {
  136. wxFontData fontData;
  137. fontData << thisValue;
  138. wxColour col;
  139. wxVariant variant;
  140. switch ( childIndex )
  141. {
  142. case 6:
  143. col << childValue;
  144. fontData.SetColour( col );
  145. break;
  146. default:
  147. // Transfer from subset to superset.
  148. wxFont font = fontData.GetChosenFont();
  149. variant = WXVARIANT(font);
  150. wxFontProperty::ChildChanged( variant, childIndex, childValue );
  151. font << variant;
  152. fontData.SetChosenFont(font);
  153. }
  154. wxVariant newVariant;
  155. newVariant << fontData;
  156. return newVariant;
  157. }
  158. // -----------------------------------------------------------------------
  159. // wxSizeProperty
  160. // -----------------------------------------------------------------------
  161. WX_PG_IMPLEMENT_PROPERTY_CLASS(wxSizeProperty,wxPGProperty,
  162. wxSize,const wxSize&,TextCtrl)
  163. wxSizeProperty::wxSizeProperty( const wxString& label, const wxString& name,
  164. const wxSize& value) : wxPGProperty(label,name)
  165. {
  166. SetValueI(value);
  167. AddPrivateChild( new wxIntProperty(wxT("Width"),wxPG_LABEL,value.x) );
  168. AddPrivateChild( new wxIntProperty(wxT("Height"),wxPG_LABEL,value.y) );
  169. }
  170. wxSizeProperty::~wxSizeProperty() { }
  171. void wxSizeProperty::RefreshChildren()
  172. {
  173. if ( !GetChildCount() ) return;
  174. const wxSize& size = wxSizeRefFromVariant(m_value);
  175. Item(0)->SetValue( (long)size.x );
  176. Item(1)->SetValue( (long)size.y );
  177. }
  178. wxVariant wxSizeProperty::ChildChanged( wxVariant& thisValue,
  179. int childIndex,
  180. wxVariant& childValue ) const
  181. {
  182. wxSize& size = wxSizeRefFromVariant(thisValue);
  183. int val = childValue.GetLong();
  184. switch ( childIndex )
  185. {
  186. case 0: size.x = val; break;
  187. case 1: size.y = val; break;
  188. }
  189. wxVariant newVariant;
  190. newVariant << size;
  191. return newVariant;
  192. }
  193. // -----------------------------------------------------------------------
  194. // wxPointProperty
  195. // -----------------------------------------------------------------------
  196. WX_PG_IMPLEMENT_PROPERTY_CLASS(wxPointProperty,wxPGProperty,
  197. wxPoint,const wxPoint&,TextCtrl)
  198. wxPointProperty::wxPointProperty( const wxString& label, const wxString& name,
  199. const wxPoint& value) : wxPGProperty(label,name)
  200. {
  201. SetValueI(value);
  202. AddPrivateChild( new wxIntProperty(wxT("X"),wxPG_LABEL,value.x) );
  203. AddPrivateChild( new wxIntProperty(wxT("Y"),wxPG_LABEL,value.y) );
  204. }
  205. wxPointProperty::~wxPointProperty() { }
  206. void wxPointProperty::RefreshChildren()
  207. {
  208. if ( !GetChildCount() ) return;
  209. const wxPoint& point = wxPointRefFromVariant(m_value);
  210. Item(0)->SetValue( (long)point.x );
  211. Item(1)->SetValue( (long)point.y );
  212. }
  213. wxVariant wxPointProperty::ChildChanged( wxVariant& thisValue,
  214. int childIndex,
  215. wxVariant& childValue ) const
  216. {
  217. wxPoint& point = wxPointRefFromVariant(thisValue);
  218. int val = childValue.GetLong();
  219. switch ( childIndex )
  220. {
  221. case 0: point.x = val; break;
  222. case 1: point.y = val; break;
  223. }
  224. wxVariant newVariant;
  225. newVariant << point;
  226. return newVariant;
  227. }
  228. // -----------------------------------------------------------------------
  229. // Dirs Property
  230. // -----------------------------------------------------------------------
  231. WX_PG_IMPLEMENT_ARRAYSTRING_PROPERTY_WITH_VALIDATOR(wxDirsProperty, ',',
  232. "Browse")
  233. #if wxUSE_VALIDATORS
  234. wxValidator* wxDirsProperty::DoGetValidator() const
  235. {
  236. return wxFileProperty::GetClassValidator();
  237. }
  238. #endif
  239. bool wxDirsProperty::OnCustomStringEdit( wxWindow* parent, wxString& value )
  240. {
  241. wxDirDialog dlg(parent,
  242. _("Select a directory to be added to the list:"),
  243. value,
  244. 0);
  245. if ( dlg.ShowModal() == wxID_OK )
  246. {
  247. value = dlg.GetPath();
  248. return TRUE;
  249. }
  250. return FALSE;
  251. }
  252. // -----------------------------------------------------------------------
  253. // wxArrayDoubleEditorDialog
  254. // -----------------------------------------------------------------------
  255. //
  256. // You can *almost* convert wxArrayDoubleEditorDialog to wxArrayXXXEditorDialog
  257. // by replacing each ArrayDouble with ArrayXXX.
  258. //
  259. class wxArrayDoubleEditorDialog : public wxPGArrayEditorDialog
  260. {
  261. public:
  262. wxArrayDoubleEditorDialog();
  263. void Init();
  264. wxArrayDoubleEditorDialog(wxWindow *parent,
  265. const wxString& message,
  266. const wxString& caption,
  267. wxArrayDouble& array,
  268. long style = wxAEDIALOG_STYLE,
  269. const wxPoint& pos = wxDefaultPosition,
  270. const wxSize& sz = wxDefaultSize );
  271. bool Create(wxWindow *parent,
  272. const wxString& message,
  273. const wxString& caption,
  274. wxArrayDouble& array,
  275. long style = wxAEDIALOG_STYLE,
  276. const wxPoint& pos = wxDefaultPosition,
  277. const wxSize& sz = wxDefaultSize );
  278. const wxArrayDouble& GetArray() const { return m_array; }
  279. // Extra method for this type of array
  280. void SetPrecision ( int precision )
  281. {
  282. m_precision = precision;
  283. m_dtoaTemplate.Empty();
  284. }
  285. protected:
  286. // Mandatory array of type
  287. wxArrayDouble m_array;
  288. // Use this to avoid extra wxString creation+Printf
  289. // on double-to-wxString conversion.
  290. wxString m_dtoaTemplate;
  291. int m_precision;
  292. // Mandatory overridden methods
  293. virtual wxString ArrayGet( size_t index );
  294. virtual size_t ArrayGetCount();
  295. virtual bool ArrayInsert( const wxString& str, int index );
  296. virtual bool ArraySet( size_t index, const wxString& str );
  297. virtual void ArrayRemoveAt( int index );
  298. virtual void ArraySwap( size_t first, size_t second );
  299. private:
  300. wxDECLARE_DYNAMIC_CLASS_NO_COPY(wxArrayDoubleEditorDialog);
  301. };
  302. IMPLEMENT_DYNAMIC_CLASS(wxArrayDoubleEditorDialog, wxPGArrayEditorDialog)
  303. //
  304. // Array dialog array access and manipulation
  305. //
  306. wxString wxArrayDoubleEditorDialog::ArrayGet( size_t index )
  307. {
  308. wxString str;
  309. wxPropertyGrid::DoubleToString(str,m_array[index],m_precision,true,&m_dtoaTemplate);
  310. return str;
  311. }
  312. size_t wxArrayDoubleEditorDialog::ArrayGetCount()
  313. {
  314. return m_array.GetCount();
  315. }
  316. bool wxArrayDoubleEditorDialog::ArrayInsert( const wxString& str, int index )
  317. {
  318. double d;
  319. if ( !str.ToDouble(&d) )
  320. return FALSE;
  321. if (index<0)
  322. m_array.Add(d);
  323. else
  324. m_array.Insert(d,index);
  325. return TRUE;
  326. }
  327. bool wxArrayDoubleEditorDialog::ArraySet( size_t index, const wxString& str )
  328. {
  329. double d;
  330. if ( !str.ToDouble(&d) )
  331. return FALSE;
  332. m_array[index] = d;
  333. return TRUE;
  334. }
  335. void wxArrayDoubleEditorDialog::ArrayRemoveAt( int index )
  336. {
  337. m_array.RemoveAt(index);
  338. }
  339. void wxArrayDoubleEditorDialog::ArraySwap( size_t first, size_t second )
  340. {
  341. double a = m_array[first];
  342. double b = m_array[second];
  343. m_array[first] = b;
  344. m_array[second] = a;
  345. }
  346. //
  347. // Array dialog construction etc.
  348. //
  349. wxArrayDoubleEditorDialog::wxArrayDoubleEditorDialog()
  350. : wxPGArrayEditorDialog()
  351. {
  352. Init();
  353. }
  354. void wxArrayDoubleEditorDialog::Init()
  355. {
  356. wxPGArrayEditorDialog::Init();
  357. SetPrecision(-1);
  358. }
  359. wxArrayDoubleEditorDialog::wxArrayDoubleEditorDialog(wxWindow *parent,
  360. const wxString& message,
  361. const wxString& caption,
  362. wxArrayDouble& array,
  363. long style,
  364. const wxPoint& pos,
  365. const wxSize& sz )
  366. : wxPGArrayEditorDialog()
  367. {
  368. Init();
  369. Create(parent,message,caption,array,style,pos,sz);
  370. }
  371. bool wxArrayDoubleEditorDialog::Create(wxWindow *parent,
  372. const wxString& message,
  373. const wxString& caption,
  374. wxArrayDouble& array,
  375. long style,
  376. const wxPoint& pos,
  377. const wxSize& sz )
  378. {
  379. m_array = array;
  380. return wxPGArrayEditorDialog::Create (parent,message,caption,style,pos,sz);
  381. }
  382. // -----------------------------------------------------------------------
  383. // wxArrayDoubleProperty
  384. // -----------------------------------------------------------------------
  385. #include <math.h> // for fabs
  386. // Comparison required by value type implementation.
  387. bool operator == (const wxArrayDouble& a, const wxArrayDouble& b)
  388. {
  389. if ( a.GetCount() != b.GetCount() )
  390. return FALSE;
  391. size_t i;
  392. for ( i=0; i<a.GetCount(); i++ )
  393. {
  394. // Can't do direct equality comparison with floating point numbers.
  395. if ( fabs(a[i] - b[i]) > 0.0000000001 )
  396. {
  397. //wxLogDebug(wxT("%f != %f"),a[i],b[i]);
  398. return FALSE;
  399. }
  400. }
  401. return TRUE;
  402. }
  403. WX_PG_IMPLEMENT_VARIANT_DATA_DUMMY_EQ(wxArrayDouble)
  404. WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayDoubleProperty,
  405. wxPGProperty,
  406. wxArrayDouble,
  407. const wxArrayDouble&,
  408. TextCtrlAndButton)
  409. wxArrayDoubleProperty::wxArrayDoubleProperty (const wxString& label,
  410. const wxString& name,
  411. const wxArrayDouble& array )
  412. : wxPGProperty(label,name)
  413. {
  414. m_precision = -1;
  415. //
  416. // Need to figure out delimiter needed for this locale
  417. // (ie. can't use comma when comma acts as decimal point in float).
  418. wxChar use_delimiter = wxT(',');
  419. if (wxString::Format(wxT("%.2f"),12.34).Find(use_delimiter) >= 0)
  420. use_delimiter = wxT(';');
  421. m_delimiter = use_delimiter;
  422. SetValue( WXVARIANT(array) );
  423. }
  424. wxArrayDoubleProperty::~wxArrayDoubleProperty () { }
  425. void wxArrayDoubleProperty::OnSetValue()
  426. {
  427. // Generate cached display string, to optimize grid drawing
  428. GenerateValueAsString( m_display, m_precision, true );
  429. }
  430. wxString wxArrayDoubleProperty::ValueToString( wxVariant& value,
  431. int argFlags ) const
  432. {
  433. wxString s;
  434. if ( argFlags & wxPG_FULL_VALUE )
  435. {
  436. GenerateValueAsString(s,-1,false);
  437. }
  438. else
  439. {
  440. //
  441. // Display cached string only if value truly matches m_value
  442. if ( value.GetData() == m_value.GetData() )
  443. return m_display;
  444. else
  445. GenerateValueAsString( s, m_precision, true );
  446. }
  447. return s;
  448. }
  449. void wxArrayDoubleProperty::GenerateValueAsString( wxString& target, int prec, bool removeZeroes ) const
  450. {
  451. wxString s;
  452. wxString template_str;
  453. wxChar between[3] = wxT(", ");
  454. size_t i;
  455. between[0] = m_delimiter;
  456. target.Empty();
  457. const wxArrayDouble& value = wxArrayDoubleRefFromVariant(m_value);
  458. for ( i=0; i<value.GetCount(); i++ )
  459. {
  460. wxPropertyGrid::DoubleToString(s,value[i],prec,removeZeroes,&template_str);
  461. target += s;
  462. if ( i<(value.GetCount()-1) )
  463. target += between;
  464. }
  465. }
  466. bool wxArrayDoubleProperty::OnEvent( wxPropertyGrid* propgrid,
  467. wxWindow* WXUNUSED(primary),
  468. wxEvent& event)
  469. {
  470. if ( propgrid->IsMainButtonEvent(event) )
  471. {
  472. // Update the value in case of last minute changes
  473. wxVariant useValue = propgrid->GetUncommittedPropertyValue();
  474. wxArrayDouble& value = wxArrayDoubleRefFromVariant(useValue);
  475. // Create editor dialog.
  476. wxArrayDoubleEditorDialog dlg;
  477. dlg.SetPrecision(m_precision);
  478. dlg.Create( propgrid, wxEmptyString, m_label, value );
  479. dlg.Move( propgrid->GetGoodEditorDialogPosition(this,dlg.GetSize()) );
  480. // Execute editor dialog
  481. int res = dlg.ShowModal();
  482. if ( res == wxID_OK && dlg.IsModified() )
  483. {
  484. SetValueInEvent( WXVARIANT(dlg.GetArray()) );
  485. return true;
  486. }
  487. return false;
  488. }
  489. return false;
  490. }
  491. bool wxArrayDoubleProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
  492. {
  493. double tval;
  494. wxString tstr;
  495. // Add values to a temporary array so that in case
  496. // of error we can opt not to use them.
  497. wxArrayDouble new_array;
  498. bool ok = true;
  499. wxChar delimiter = m_delimiter;
  500. WX_PG_TOKENIZER1_BEGIN(text,delimiter)
  501. if ( !token.empty() )
  502. {
  503. // If token was invalid, exit the loop now
  504. if ( !token.ToDouble(&tval) )
  505. {
  506. tstr.Printf ( _("\"%s\" is not a floating-point number."), token.c_str() );
  507. ok = false;
  508. break;
  509. }
  510. // TODO: Put validator code here
  511. new_array.Add(tval);
  512. }
  513. WX_PG_TOKENIZER1_END()
  514. // When invalid token found, show error message and don't change anything
  515. if ( !ok )
  516. {
  517. //ShowError( tstr );
  518. return false;
  519. }
  520. if ( !(wxArrayDoubleRefFromVariant(m_value) == new_array) )
  521. {
  522. variant = WXVARIANT(new_array);
  523. return true;
  524. }
  525. return false;
  526. }
  527. bool wxArrayDoubleProperty::DoSetAttribute( const wxString& name, wxVariant& value )
  528. {
  529. if ( name == wxPG_FLOAT_PRECISION )
  530. {
  531. m_precision = value.GetLong();
  532. GenerateValueAsString( m_display, m_precision, true );
  533. return true;
  534. }
  535. return false;
  536. }