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