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