1 /////////////////////////////////////////////////////////////////////////////
2 // Name: samples/propgrid/sampleprops.cpp
3 // Purpose: wxPropertyGrid Sample Properties
4 // Author: Jaakko Salli
7 // Copyright: (c) Jaakko Salli
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
18 // for all others, include the necessary headers (this file is usually all you
19 // need because it includes almost all "standard" wxWidgets headers)
24 #include "wx/fontdlg.h"
26 // -----------------------------------------------------------------------
29 #include <wx/propgrid/propgrid.h>
30 #include <wx/propgrid/advprops.h>
32 #ifndef WX_PROPGRID_SAMPLEPROPS_H
33 #include "sampleprops.h"
37 // -----------------------------------------------------------------------
39 // -----------------------------------------------------------------------
41 // Dummy comparison required by value type implementation.
42 bool operator == (const wxFontData
&, const wxFontData
&)
47 // Custom version of wxFontProperty that also holds colour in the value.
48 // Original version by Vladimir Vainer.
50 IMPLEMENT_VARIANT_OBJECT_SHALLOWCMP(wxFontData
)
52 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFontDataProperty
,wxFontProperty
,
53 wxFontData
,const wxFontData
&,TextCtrlAndButton
)
55 wxFontDataProperty::wxFontDataProperty( const wxString
& label
, const wxString
& name
,
56 const wxFontData
& value
) : wxFontProperty(label
,name
,value
.GetInitialFont())
58 wxFontData
fontData(value
);
61 fontData
.SetChosenFont(value
.GetInitialFont());
62 if ( !fontData
.GetColour().IsOk() )
63 fontData
.SetColour(*wxBLACK
);
65 // Set initial value - should be done in a simpler way like this
66 // (instead of calling SetValue) in derived (wxObject) properties.
67 m_value_wxFontData
<< value
;
69 // Add extra children.
70 AddPrivateChild( new wxColourProperty(_("Colour"), wxPG_LABEL
,
71 fontData
.GetColour() ) );
74 wxFontDataProperty::~wxFontDataProperty () { }
76 void wxFontDataProperty::OnSetValue()
78 if ( m_value
.GetType() != "wxFontData" )
80 if ( m_value
.GetType() == "wxFont" )
85 fontData
.SetChosenFont(font
);
86 if ( !m_value_wxFontData
.IsNull() )
88 wxFontData oldFontData
;
89 oldFontData
<< m_value_wxFontData
;
90 fontData
.SetColour(oldFontData
.GetColour());
94 fontData
.SetColour(*wxBLACK
);
98 m_value_wxFontData
= variant
;
102 wxFAIL_MSG(wxT("Value to wxFontDataProperty must be eithe wxFontData or wxFont"));
107 // Set m_value to wxFont so that wxFontProperty methods will work
109 m_value_wxFontData
= m_value
;
112 fontData
<< m_value_wxFontData
;
114 wxFont font
= fontData
.GetChosenFont();
116 font
= wxFont(10,wxSWISS
,wxNORMAL
,wxNORMAL
);
118 m_value
= WXVARIANT(font
);
122 wxVariant
wxFontDataProperty::DoGetValue() const
124 return m_value_wxFontData
;
127 // Must re-create font dialog displayer.
128 bool wxFontDataProperty::OnEvent( wxPropertyGrid
* propgrid
,
129 wxWindow
* WXUNUSED(primary
), wxEvent
& event
)
131 if ( propgrid
->IsMainButtonEvent(event
) )
133 wxVariant useValue
= propgrid
->GetUncommittedPropertyValue();
136 fontData
<< useValue
;
138 fontData
.SetInitialFont(fontData
.GetChosenFont());
140 wxFontDialog
dlg(propgrid
, fontData
);
142 if ( dlg
.ShowModal() == wxID_OK
)
145 variant
<< dlg
.GetFontData();
146 SetValueInEvent( variant
);
153 void wxFontDataProperty::RefreshChildren()
155 wxFontProperty::RefreshChildren();
156 if ( GetChildCount() < 6 ) // Number is count of wxFontProperty's children + 1.
158 wxFontData fontData
; fontData
<< m_value_wxFontData
;
159 wxVariant variant
; variant
<< fontData
.GetColour();
160 Item(6)->SetValue( variant
);
163 wxVariant
wxFontDataProperty::ChildChanged( wxVariant
& thisValue
,
165 wxVariant
& childValue
) const
168 fontData
<< thisValue
;
172 switch ( childIndex
)
176 fontData
.SetColour( col
);
179 // Transfer from subset to superset.
180 wxFont font
= fontData
.GetChosenFont();
181 variant
= WXVARIANT(font
);
182 wxFontProperty::ChildChanged( variant
, childIndex
, childValue
);
184 fontData
.SetChosenFont(font
);
187 wxVariant newVariant
;
188 newVariant
<< fontData
;
192 // -----------------------------------------------------------------------
194 // -----------------------------------------------------------------------
196 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxSizeProperty
,wxPGProperty
,
197 wxSize
,const wxSize
&,TextCtrl
)
199 wxSizeProperty::wxSizeProperty( const wxString
& label
, const wxString
& name
,
200 const wxSize
& value
) : wxPGProperty(label
,name
)
203 AddPrivateChild( new wxIntProperty(wxT("Width"),wxPG_LABEL
,value
.x
) );
204 AddPrivateChild( new wxIntProperty(wxT("Height"),wxPG_LABEL
,value
.y
) );
207 wxSizeProperty::~wxSizeProperty() { }
209 void wxSizeProperty::RefreshChildren()
211 if ( !GetChildCount() ) return;
212 const wxSize
& size
= wxSizeRefFromVariant(m_value
);
213 Item(0)->SetValue( (long)size
.x
);
214 Item(1)->SetValue( (long)size
.y
);
217 wxVariant
wxSizeProperty::ChildChanged( wxVariant
& thisValue
,
219 wxVariant
& childValue
) const
221 wxSize
& size
= wxSizeRefFromVariant(thisValue
);
222 int val
= childValue
.GetLong();
223 switch ( childIndex
)
225 case 0: size
.x
= val
; break;
226 case 1: size
.y
= val
; break;
228 wxVariant newVariant
;
233 // -----------------------------------------------------------------------
235 // -----------------------------------------------------------------------
237 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxPointProperty
,wxPGProperty
,
238 wxPoint
,const wxPoint
&,TextCtrl
)
240 wxPointProperty::wxPointProperty( const wxString
& label
, const wxString
& name
,
241 const wxPoint
& value
) : wxPGProperty(label
,name
)
244 AddPrivateChild( new wxIntProperty(wxT("X"),wxPG_LABEL
,value
.x
) );
245 AddPrivateChild( new wxIntProperty(wxT("Y"),wxPG_LABEL
,value
.y
) );
248 wxPointProperty::~wxPointProperty() { }
250 void wxPointProperty::RefreshChildren()
252 if ( !GetChildCount() ) return;
253 const wxPoint
& point
= wxPointRefFromVariant(m_value
);
254 Item(0)->SetValue( (long)point
.x
);
255 Item(1)->SetValue( (long)point
.y
);
258 wxVariant
wxPointProperty::ChildChanged( wxVariant
& thisValue
,
260 wxVariant
& childValue
) const
262 wxPoint
& point
= wxPointRefFromVariant(thisValue
);
263 int val
= childValue
.GetLong();
264 switch ( childIndex
)
266 case 0: point
.x
= val
; break;
267 case 1: point
.y
= val
; break;
269 wxVariant newVariant
;
275 // -----------------------------------------------------------------------
277 // -----------------------------------------------------------------------
279 WX_PG_IMPLEMENT_ARRAYSTRING_PROPERTY_WITH_VALIDATOR(wxDirsProperty
, ',',
284 wxValidator
* wxDirsProperty::DoGetValidator() const
286 return wxFileProperty::GetClassValidator();
292 bool wxDirsProperty::OnCustomStringEdit( wxWindow
* parent
, wxString
& value
)
294 wxDirDialog
dlg(parent
,
295 _("Select a directory to be added to the list:"),
299 if ( dlg
.ShowModal() == wxID_OK
)
301 value
= dlg
.GetPath();
307 // -----------------------------------------------------------------------
308 // wxArrayDoubleEditorDialog
309 // -----------------------------------------------------------------------
313 // You can *almost* convert wxArrayDoubleEditorDialog to wxArrayXXXEditorDialog
314 // by replacing each ArrayDouble with ArrayXXX.
317 class wxArrayDoubleEditorDialog
: public wxPGArrayEditorDialog
320 wxArrayDoubleEditorDialog();
324 wxArrayDoubleEditorDialog(wxWindow
*parent
,
325 const wxString
& message
,
326 const wxString
& caption
,
327 wxArrayDouble
& array
,
328 long style
= wxAEDIALOG_STYLE
,
329 const wxPoint
& pos
= wxDefaultPosition
,
330 const wxSize
& sz
= wxDefaultSize
);
332 bool Create(wxWindow
*parent
,
333 const wxString
& message
,
334 const wxString
& caption
,
335 wxArrayDouble
& array
,
336 long style
= wxAEDIALOG_STYLE
,
337 const wxPoint
& pos
= wxDefaultPosition
,
338 const wxSize
& sz
= wxDefaultSize
);
340 const wxArrayDouble
& GetArray() const { return m_array
; }
342 // Extra method for this type of array
343 void SetPrecision ( int precision
)
345 m_precision
= precision
;
346 m_dtoaTemplate
.Empty();
350 // Mandatory array of type
351 wxArrayDouble m_array
;
353 // Use this to avoid extra wxString creation+Printf
354 // on double-to-wxString conversion.
355 wxString m_dtoaTemplate
;
359 // Mandatory overridden methods
360 virtual wxString
ArrayGet( size_t index
);
361 virtual size_t ArrayGetCount();
362 virtual bool ArrayInsert( const wxString
& str
, int index
);
363 virtual bool ArraySet( size_t index
, const wxString
& str
);
364 virtual void ArrayRemoveAt( int index
);
365 virtual void ArraySwap( size_t first
, size_t second
);
368 DECLARE_DYNAMIC_CLASS_NO_COPY(wxArrayDoubleEditorDialog
)
371 IMPLEMENT_DYNAMIC_CLASS(wxArrayDoubleEditorDialog
, wxPGArrayEditorDialog
)
374 // Array dialog array access and manipulation
377 wxString
wxArrayDoubleEditorDialog::ArrayGet( size_t index
)
380 wxPropertyGrid::DoubleToString(str
,m_array
[index
],m_precision
,true,&m_dtoaTemplate
);
384 size_t wxArrayDoubleEditorDialog::ArrayGetCount()
386 return m_array
.GetCount();
389 bool wxArrayDoubleEditorDialog::ArrayInsert( const wxString
& str
, int index
)
392 if ( !str
.ToDouble(&d
) )
398 m_array
.Insert(d
,index
);
402 bool wxArrayDoubleEditorDialog::ArraySet( size_t index
, const wxString
& str
)
405 if ( !str
.ToDouble(&d
) )
411 void wxArrayDoubleEditorDialog::ArrayRemoveAt( int index
)
413 m_array
.RemoveAt(index
);
416 void wxArrayDoubleEditorDialog::ArraySwap( size_t first
, size_t second
)
418 double a
= m_array
[first
];
419 double b
= m_array
[second
];
425 // Array dialog construction etc.
428 wxArrayDoubleEditorDialog::wxArrayDoubleEditorDialog()
429 : wxPGArrayEditorDialog()
434 void wxArrayDoubleEditorDialog::Init()
436 wxPGArrayEditorDialog::Init();
440 wxArrayDoubleEditorDialog::wxArrayDoubleEditorDialog(wxWindow
*parent
,
441 const wxString
& message
,
442 const wxString
& caption
,
443 wxArrayDouble
& array
,
447 : wxPGArrayEditorDialog()
450 Create(parent
,message
,caption
,array
,style
,pos
,sz
);
453 bool wxArrayDoubleEditorDialog::Create(wxWindow
*parent
,
454 const wxString
& message
,
455 const wxString
& caption
,
456 wxArrayDouble
& array
,
464 return wxPGArrayEditorDialog::Create (parent
,message
,caption
,style
,pos
,sz
);
467 // -----------------------------------------------------------------------
468 // wxArrayDoubleProperty
469 // -----------------------------------------------------------------------
471 #include <math.h> // for fabs
473 // Comparison required by value type implementation.
474 bool operator == (const wxArrayDouble
& a
, const wxArrayDouble
& b
)
476 if ( a
.GetCount() != b
.GetCount() )
481 for ( i
=0; i
<a
.GetCount(); i
++ )
483 // Can't do direct equality comparison with floating point numbers.
484 if ( fabs(a
[i
] - b
[i
]) > 0.0000000001 )
486 //wxLogDebug(wxT("%f != %f"),a[i],b[i]);
493 WX_PG_IMPLEMENT_VARIANT_DATA_DUMMY_EQ(wxArrayDouble
)
495 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayDoubleProperty
,
498 const wxArrayDouble
&,
502 wxArrayDoubleProperty::wxArrayDoubleProperty (const wxString
& label
,
503 const wxString
& name
,
504 const wxArrayDouble
& array
)
505 : wxPGProperty(label
,name
)
510 // Need to figure out delimiter needed for this locale
511 // (ie. can't use comma when comma acts as decimal point in float).
512 wxChar use_delimiter
= wxT(',');
514 if (wxString::Format(wxT("%.2f"),12.34).Find(use_delimiter
) >= 0)
515 use_delimiter
= wxT(';');
517 m_delimiter
= use_delimiter
;
519 SetValue( WXVARIANT(array
) );
522 wxArrayDoubleProperty::~wxArrayDoubleProperty () { }
524 void wxArrayDoubleProperty::OnSetValue()
526 // Generate cached display string, to optimize grid drawing
527 GenerateValueAsString( m_display
, m_precision
, true );
530 wxString
wxArrayDoubleProperty::ValueToString( wxVariant
& value
,
535 if ( argFlags
& wxPG_FULL_VALUE
)
537 GenerateValueAsString(s
,-1,false);
542 // Display cached string only if value truly matches m_value
543 if ( value
.GetData() == m_value
.GetData() )
546 GenerateValueAsString( s
, m_precision
, true );
552 void wxArrayDoubleProperty::GenerateValueAsString( wxString
& target
, int prec
, bool removeZeroes
) const
555 wxString template_str
;
556 wxChar between
[3] = wxT(", ");
559 between
[0] = m_delimiter
;
563 const wxArrayDouble
& value
= wxArrayDoubleRefFromVariant(m_value
);
565 for ( i
=0; i
<value
.GetCount(); i
++ )
568 wxPropertyGrid::DoubleToString(s
,value
[i
],prec
,removeZeroes
,&template_str
);
572 if ( i
<(value
.GetCount()-1) )
577 bool wxArrayDoubleProperty::OnEvent( wxPropertyGrid
* propgrid
,
578 wxWindow
* WXUNUSED(primary
),
581 if ( propgrid
->IsMainButtonEvent(event
) )
583 // Update the value in case of last minute changes
584 wxVariant useValue
= propgrid
->GetUncommittedPropertyValue();
586 wxArrayDouble
& value
= wxArrayDoubleRefFromVariant(useValue
);
588 // Create editor dialog.
589 wxArrayDoubleEditorDialog dlg
;
590 dlg
.SetPrecision(m_precision
);
591 dlg
.Create( propgrid
, wxEmptyString
, m_label
, value
);
592 dlg
.Move( propgrid
->GetGoodEditorDialogPosition(this,dlg
.GetSize()) );
594 // Execute editor dialog
595 int res
= dlg
.ShowModal();
596 if ( res
== wxID_OK
&& dlg
.IsModified() )
598 SetValueInEvent( WXVARIANT(dlg
.GetArray()) );
606 bool wxArrayDoubleProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
610 // Add values to a temporary array so that in case
611 // of error we can opt not to use them.
612 wxArrayDouble new_array
;
616 wxChar delimiter
= m_delimiter
;
618 WX_PG_TOKENIZER1_BEGIN(text
,delimiter
)
620 if ( !token
.empty() )
623 // If token was invalid, exit the loop now
624 if ( !token
.ToDouble(&tval
) )
626 tstr
.Printf ( _("\"%s\" is not a floating-point number."), token
.c_str() );
630 // TODO: Put validator code here
636 WX_PG_TOKENIZER1_END()
638 // When invalid token found, show error message and don't change anything
645 if ( !(wxArrayDoubleRefFromVariant(m_value
) == new_array
) )
647 variant
= WXVARIANT(new_array
);
654 bool wxArrayDoubleProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
656 if ( name
== wxPG_FLOAT_PRECISION
)
658 m_precision
= value
.GetLong();
659 GenerateValueAsString( m_display
, m_precision
, true );