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