1 /////////////////////////////////////////////////////////////////////////////
2 // Name: samples/propgrid/sampleprops.cpp
3 // Purpose: wxPropertyGrid Sample Properties
4 // Author: Jaakko Salli
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
19 // for all others, include the necessary headers (this file is usually all you
20 // need because it includes almost all "standard" wxWidgets headers)
25 // -----------------------------------------------------------------------
28 #include <wx/propgrid/propgrid.h>
29 #include <wx/propgrid/advprops.h>
31 #ifndef WX_PROPGRID_SAMPLEPROPS_H
32 #include "sampleprops.h"
36 // -----------------------------------------------------------------------
38 // -----------------------------------------------------------------------
40 // Dummy comparison required by value type implementation.
41 bool operator == (const wxFontData
&, const wxFontData
&)
46 // Custom version of wxFontProperty that also holds colour in the value.
47 // Original version by Vladimir Vainer.
49 #include <wx/fontdlg.h>
51 IMPLEMENT_VARIANT_OBJECT_SHALLOWCMP(wxFontData
)
53 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFontDataProperty
,wxFontProperty
,
54 wxFontData
,const wxFontData
&,TextCtrlAndButton
)
56 wxFontDataProperty::wxFontDataProperty( const wxString
& label
, const wxString
& name
,
57 const wxFontData
& value
) : wxFontProperty(label
,name
,value
.GetInitialFont())
59 wxFontData
fontData(value
);
62 fontData
.SetChosenFont(value
.GetInitialFont());
63 if ( !fontData
.GetColour().Ok() )
64 fontData
.SetColour(*wxBLACK
);
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
;
70 SetParentalType(wxPG_PROP_AGGREGATE
);
72 // Add extra children.
73 AddChild( new wxColourProperty(_("Colour"), wxPG_LABEL
,
74 fontData
.GetColour() ) );
77 wxFontDataProperty::~wxFontDataProperty () { }
79 void wxFontDataProperty::OnSetValue()
81 if ( m_value
.GetType() != "wxFontData" )
83 if ( m_value
.GetType() == "wxFont" )
88 fontData
.SetChosenFont(font
);
89 if ( !m_value_wxFontData
.IsNull() )
91 wxFontData oldFontData
;
92 oldFontData
<< m_value_wxFontData
;
93 fontData
.SetColour(oldFontData
.GetColour());
97 fontData
.SetColour(*wxBLACK
);
101 m_value_wxFontData
= variant
;
105 wxFAIL_MSG(wxT("Value to wxFontDataProperty must be eithe wxFontData or wxFont"));
110 // Set m_value to wxFont so that wxFontProperty methods will work
112 m_value_wxFontData
= m_value
;
115 fontData
<< m_value_wxFontData
;
117 wxFont font
= fontData
.GetChosenFont();
119 font
= wxFont(10,wxSWISS
,wxNORMAL
,wxNORMAL
);
121 m_value
= WXVARIANT(font
);
125 wxVariant
wxFontDataProperty::DoGetValue() const
127 return m_value_wxFontData
;
130 // Must re-create font dialog displayer.
131 bool wxFontDataProperty::OnEvent( wxPropertyGrid
* propgrid
,
132 wxWindow
* WXUNUSED(primary
), wxEvent
& event
)
134 if ( propgrid
->IsMainButtonEvent(event
) )
136 wxVariant useValue
= propgrid
->GetUncommittedPropertyValue();
139 fontData
<< useValue
;
141 fontData
.SetInitialFont(fontData
.GetChosenFont());
143 wxFontDialog
dlg(propgrid
, fontData
);
145 if ( dlg
.ShowModal() == wxID_OK
)
148 variant
<< dlg
.GetFontData();
149 SetValueInEvent( variant
);
156 void wxFontDataProperty::RefreshChildren()
158 wxFontProperty::RefreshChildren();
159 if ( GetChildCount() < 6 ) // Number is count of wxFontProperty's children + 1.
161 wxFontData fontData
; fontData
<< m_value_wxFontData
;
162 wxVariant variant
; variant
<< fontData
.GetColour();
163 Item(6)->SetValue( variant
);
166 void wxFontDataProperty::ChildChanged( wxVariant
& thisValue
, int childIndex
, wxVariant
& childValue
) const
169 fontData
<< thisValue
;
173 switch ( childIndex
)
177 fontData
.SetColour( col
);
180 // Transfer from subset to superset.
181 wxFont font
= fontData
.GetChosenFont();
182 variant
= WXVARIANT(font
);
183 wxFontProperty::ChildChanged( variant
, childIndex
, childValue
);
185 fontData
.SetChosenFont(font
);
188 thisValue
<< fontData
;
191 // -----------------------------------------------------------------------
193 // -----------------------------------------------------------------------
195 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxSizeProperty
,wxPGProperty
,
196 wxSize
,const wxSize
&,TextCtrl
)
198 wxSizeProperty::wxSizeProperty( const wxString
& label
, const wxString
& name
,
199 const wxSize
& value
) : wxPGProperty(label
,name
)
202 SetParentalType(wxPG_PROP_AGGREGATE
);
203 AddChild( new wxIntProperty(wxT("Width"),wxPG_LABEL
,value
.x
) );
204 AddChild( 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 void wxSizeProperty::ChildChanged( wxVariant
& thisValue
, int childIndex
, wxVariant
& childValue
) const
219 wxSize
& size
= wxSizeRefFromVariant(thisValue
);
220 int val
= wxPGVariantToInt(childValue
);
221 switch ( childIndex
)
223 case 0: size
.x
= val
; break;
224 case 1: size
.y
= val
; break;
228 // -----------------------------------------------------------------------
230 // -----------------------------------------------------------------------
232 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxPointProperty
,wxPGProperty
,
233 wxPoint
,const wxPoint
&,TextCtrl
)
235 wxPointProperty::wxPointProperty( const wxString
& label
, const wxString
& name
,
236 const wxPoint
& value
) : wxPGProperty(label
,name
)
239 SetParentalType(wxPG_PROP_AGGREGATE
);
240 AddChild( new wxIntProperty(wxT("X"),wxPG_LABEL
,value
.x
) );
241 AddChild( new wxIntProperty(wxT("Y"),wxPG_LABEL
,value
.y
) );
244 wxPointProperty::~wxPointProperty() { }
246 void wxPointProperty::RefreshChildren()
248 if ( !GetChildCount() ) return;
249 const wxPoint
& point
= wxPointRefFromVariant(m_value
);
250 Item(0)->SetValue( (long)point
.x
);
251 Item(1)->SetValue( (long)point
.y
);
254 void wxPointProperty::ChildChanged( wxVariant
& thisValue
, int childIndex
, wxVariant
& childValue
) const
256 wxPoint
& point
= wxPointRefFromVariant(thisValue
);
257 int val
= wxPGVariantToInt(childValue
);
258 switch ( childIndex
)
260 case 0: point
.x
= val
; break;
261 case 1: point
.y
= val
; break;
266 // -----------------------------------------------------------------------
268 // -----------------------------------------------------------------------
270 WX_PG_IMPLEMENT_ARRAYSTRING_PROPERTY_WITH_VALIDATOR(wxDirsProperty
,wxT(','),wxT("Browse"))
274 wxValidator
* wxDirsProperty::DoGetValidator() const
276 return wxFileProperty::GetClassValidator();
282 bool wxDirsProperty::OnCustomStringEdit( wxWindow
* parent
, wxString
& value
)
284 wxDirDialog
dlg(parent
,
285 _("Select a directory to be added to the list:"),
289 if ( dlg
.ShowModal() == wxID_OK
)
291 value
= dlg
.GetPath();
297 // -----------------------------------------------------------------------
298 // wxArrayDoubleEditorDialog
299 // -----------------------------------------------------------------------
303 // You can *almost* convert wxArrayDoubleEditorDialog to wxArrayXXXEditorDialog
304 // by replacing each ArrayDouble with ArrayXXX.
307 class wxArrayDoubleEditorDialog
: public wxArrayEditorDialog
310 wxArrayDoubleEditorDialog();
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
);
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
);
330 const wxArrayDouble
& GetArray() const { return m_array
; }
332 // Extra method for this type of array
333 void SetPrecision ( int precision
)
335 m_precision
= precision
;
336 m_dtoaTemplate
.Empty();
340 // Mandatory array of type
341 wxArrayDouble m_array
;
343 // Use this to avoid extra wxString creation+Printf
344 // on double-to-wxString conversion.
345 wxString m_dtoaTemplate
;
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
);
358 DECLARE_DYNAMIC_CLASS_NO_COPY(wxArrayDoubleEditorDialog
)
361 IMPLEMENT_DYNAMIC_CLASS(wxArrayDoubleEditorDialog
, wxArrayEditorDialog
)
364 // Array dialog array access and manipulation
367 wxString
wxArrayDoubleEditorDialog::ArrayGet( size_t index
)
370 wxPropertyGrid::DoubleToString(str
,m_array
[index
],m_precision
,true,&m_dtoaTemplate
);
374 size_t wxArrayDoubleEditorDialog::ArrayGetCount()
376 return m_array
.GetCount();
379 bool wxArrayDoubleEditorDialog::ArrayInsert( const wxString
& str
, int index
)
382 if ( !str
.ToDouble(&d
) )
388 m_array
.Insert(d
,index
);
392 bool wxArrayDoubleEditorDialog::ArraySet( size_t index
, const wxString
& str
)
395 if ( !str
.ToDouble(&d
) )
401 void wxArrayDoubleEditorDialog::ArrayRemoveAt( int index
)
403 m_array
.RemoveAt(index
);
406 void wxArrayDoubleEditorDialog::ArraySwap( size_t first
, size_t second
)
408 double a
= m_array
[first
];
409 double b
= m_array
[second
];
415 // Array dialog construction etc.
418 wxArrayDoubleEditorDialog::wxArrayDoubleEditorDialog()
419 : wxArrayEditorDialog()
424 void wxArrayDoubleEditorDialog::Init()
426 wxArrayEditorDialog::Init();
430 wxArrayDoubleEditorDialog::wxArrayDoubleEditorDialog(wxWindow
*parent
,
431 const wxString
& message
,
432 const wxString
& caption
,
433 wxArrayDouble
& array
,
437 : wxArrayEditorDialog()
440 Create(parent
,message
,caption
,array
,style
,pos
,sz
);
443 bool wxArrayDoubleEditorDialog::Create(wxWindow
*parent
,
444 const wxString
& message
,
445 const wxString
& caption
,
446 wxArrayDouble
& array
,
454 return wxArrayEditorDialog::Create (parent
,message
,caption
,style
,pos
,sz
);
457 // -----------------------------------------------------------------------
458 // wxArrayDoubleProperty
459 // -----------------------------------------------------------------------
461 #include <math.h> // for fabs
463 // Comparison required by value type implementation.
464 bool operator == (const wxArrayDouble
& a
, const wxArrayDouble
& b
)
466 if ( a
.GetCount() != b
.GetCount() )
471 for ( i
=0; i
<a
.GetCount(); i
++ )
473 // Can't do direct equality comparison with floating point numbers.
474 if ( fabs(a
[i
] - b
[i
]) > 0.0000000001 )
476 //wxLogDebug(wxT("%f != %f"),a[i],b[i]);
483 WX_PG_IMPLEMENT_VARIANT_DATA_DUMMY_EQ(wxArrayDouble
)
485 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxArrayDoubleProperty
,
488 const wxArrayDouble
&,
492 wxArrayDoubleProperty::wxArrayDoubleProperty (const wxString
& label
,
493 const wxString
& name
,
494 const wxArrayDouble
& array
)
495 : wxPGProperty(label
,name
)
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(',');
504 if (wxString::Format(wxT("%.2f"),12.34).Find(use_delimiter
) >= 0)
505 use_delimiter
= wxT(';');
507 m_delimiter
= use_delimiter
;
509 SetValue( WXVARIANT(array
) );
512 wxArrayDoubleProperty::~wxArrayDoubleProperty () { }
514 void wxArrayDoubleProperty::OnSetValue()
516 // Generate cached display string, to optimize grid drawing
517 GenerateValueAsString( m_display
, m_precision
, true );
520 wxString
wxArrayDoubleProperty::ValueToString( wxVariant
& value
,
525 if ( argFlags
& wxPG_FULL_VALUE
)
527 GenerateValueAsString(s
,-1,false);
532 // Display cached string only if value truly matches m_value
533 if ( value
.GetData() == m_value
.GetData() )
536 GenerateValueAsString( s
, m_precision
, true );
542 void wxArrayDoubleProperty::GenerateValueAsString( wxString
& target
, int prec
, bool removeZeroes
) const
545 wxString template_str
;
546 wxChar between
[3] = wxT(", ");
549 between
[0] = m_delimiter
;
553 const wxArrayDouble
& value
= wxArrayDoubleRefFromVariant(m_value
);
555 for ( i
=0; i
<value
.GetCount(); i
++ )
558 wxPropertyGrid::DoubleToString(s
,value
[i
],prec
,removeZeroes
,&template_str
);
562 if ( i
<(value
.GetCount()-1) )
567 bool wxArrayDoubleProperty::OnEvent( wxPropertyGrid
* propgrid
,
568 wxWindow
* WXUNUSED(primary
),
571 if ( propgrid
->IsMainButtonEvent(event
) )
573 // Update the value in case of last minute changes
574 wxVariant useValue
= propgrid
->GetUncommittedPropertyValue();
576 wxArrayDouble
& value
= wxArrayDoubleRefFromVariant(useValue
);
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()) );
584 // Execute editor dialog
585 int res
= dlg
.ShowModal();
586 if ( res
== wxID_OK
&& dlg
.IsModified() )
588 SetValueInEvent( WXVARIANT(dlg
.GetArray()) );
596 bool wxArrayDoubleProperty::StringToValue( wxVariant
& variant
, const wxString
& text
, int ) const
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
;
606 wxChar delimiter
= m_delimiter
;
608 WX_PG_TOKENIZER1_BEGIN(text
,delimiter
)
610 if ( token
.length() )
613 // If token was invalid, exit the loop now
614 if ( !token
.ToDouble(&tval
) )
616 tstr
.Printf ( _("\"%s\" is not a floating-point number."), token
.c_str() );
620 // TODO: Put validator code here
626 WX_PG_TOKENIZER1_END()
628 // When invalid token found, show error message and don't change anything
635 if ( !(wxArrayDoubleRefFromVariant(m_value
) == new_array
) )
637 variant
= WXVARIANT(new_array
);
644 bool wxArrayDoubleProperty::DoSetAttribute( const wxString
& name
, wxVariant
& value
)
646 if ( name
== wxPG_FLOAT_PRECISION
)
648 m_precision
= value
.GetLong();
649 GenerateValueAsString( m_display
, m_precision
, true );