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