1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        src/propgrid/advprops.cpp
3 // Purpose:     wxPropertyGrid Advanced Properties (font, colour, etc.)
4 // Author:      Jaakko Salli
5 // Modified by:
6 // Created:     2004-09-25
7 // Copyright:   (c) Jaakko Salli
8 // Licence:     wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10 
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
13 
14 #ifdef __BORLANDC__
15     #pragma hdrstop
16 #endif
17 
18 #if wxUSE_PROPGRID
19 
20 #ifndef WX_PRECOMP
21     #include "wx/defs.h"
22     #include "wx/object.h"
23     #include "wx/hash.h"
24     #include "wx/string.h"
25     #include "wx/log.h"
26     #include "wx/event.h"
27     #include "wx/window.h"
28     #include "wx/panel.h"
29     #include "wx/dc.h"
30     #include "wx/dcclient.h"
31     #include "wx/button.h"
32     #include "wx/pen.h"
33     #include "wx/brush.h"
34     #include "wx/cursor.h"
35     #include "wx/dialog.h"
36     #include "wx/settings.h"
37     #include "wx/msgdlg.h"
38     #include "wx/choice.h"
39     #include "wx/stattext.h"
40     #include "wx/textctrl.h"
41     #include "wx/scrolwin.h"
42     #include "wx/dirdlg.h"
43     #include "wx/combobox.h"
44     #include "wx/sizer.h"
45     #include "wx/textdlg.h"
46     #include "wx/filedlg.h"
47     #include "wx/intl.h"
48     #include "wx/wxcrtvararg.h"
49 #endif
50 
51 #define __wxPG_SOURCE_FILE__
52 
53 #include "wx/propgrid/propgrid.h"
54 
55 #if wxPG_INCLUDE_ADVPROPS
56 
57 #include "wx/propgrid/advprops.h"
58 
59 #ifdef __WXMSW__
60     #include "wx/msw/private.h"
61     #include "wx/msw/dc.h"
62 #endif
63 
64 #include "wx/odcombo.h"
65 #include "wx/numformatter.h"
66 
67 // -----------------------------------------------------------------------
68 
69 #if defined(__WXMSW__)
70     #define wxPG_CAN_DRAW_CURSOR           1
71 #elif defined(__WXGTK__)
72     #define wxPG_CAN_DRAW_CURSOR           0
73 #elif defined(__WXMAC__)
74     #define wxPG_CAN_DRAW_CURSOR           0
75 #else
76     #define wxPG_CAN_DRAW_CURSOR           0
77 #endif
78 
79 
80 // -----------------------------------------------------------------------
81 // Value type related
82 // -----------------------------------------------------------------------
83 
84 
85 // Implement dynamic class for type value.
86 IMPLEMENT_DYNAMIC_CLASS(wxColourPropertyValue, wxObject)
87 
88 bool operator == (const wxColourPropertyValue& a, const wxColourPropertyValue& b)
89 {
90     return ( ( a.m_colour == b.m_colour ) && (a.m_type == b.m_type) );
91 }
92 
operator ==(const wxArrayInt & array1,const wxArrayInt & array2)93 bool operator == (const wxArrayInt& array1, const wxArrayInt& array2)
94 {
95     if ( array1.size() != array2.size() )
96         return false;
97     size_t i;
98     for ( i=0; i<array1.size(); i++ )
99     {
100         if ( array1[i] != array2[i] )
101             return false;
102     }
103     return true;
104 }
105 
106 // -----------------------------------------------------------------------
107 // wxSpinCtrl-based property editor
108 // -----------------------------------------------------------------------
109 
110 #if wxUSE_SPINBTN
111 
112 
113 #ifdef __WXMSW__
114   #define IS_MOTION_SPIN_SUPPORTED  1
115 #else
116   #define IS_MOTION_SPIN_SUPPORTED  0
117 #endif
118 
119 #if IS_MOTION_SPIN_SUPPORTED
120 
121 //
122 // This class implements ability to rapidly change "spin" value
123 // by moving mouse when one of the spin buttons is depressed.
124 class wxPGSpinButton : public wxSpinButton
125 {
126 public:
wxPGSpinButton()127     wxPGSpinButton() : wxSpinButton()
128     {
129         m_bLeftDown = false;
130         m_hasCapture = false;
131         m_spins = 1;
132 
133         Connect( wxEVT_LEFT_DOWN,
134                  wxMouseEventHandler(wxPGSpinButton::OnMouseEvent) );
135         Connect( wxEVT_LEFT_UP,
136                  wxMouseEventHandler(wxPGSpinButton::OnMouseEvent) );
137         Connect( wxEVT_MOTION,
138                  wxMouseEventHandler(wxPGSpinButton::OnMouseEvent) );
139         Connect( wxEVT_MOUSE_CAPTURE_LOST,
140           wxMouseCaptureLostEventHandler(wxPGSpinButton::OnMouseCaptureLost) );
141     }
142 
GetSpins() const143     int GetSpins() const
144     {
145         return m_spins;
146     }
147 
148 private:
149     wxPoint m_ptPosition;
150 
151     // Having a separate spins variable allows us to handle validation etc. for
152     // multiple spin events at once (with quick mouse movements there could be
153     // hundreds of 'spins' being done at once). Technically things like this
154     // should be stored in event (wxSpinEvent in this case), but there probably
155     // isn't anything there that can be reliably reused.
156     int     m_spins;
157 
158     bool    m_bLeftDown;
159 
160     // SpinButton seems to be a special for mouse capture, so we may need track
161     // privately whether mouse is actually captured.
162     bool    m_hasCapture;
163 
Capture()164     void Capture()
165     {
166         if ( !m_hasCapture )
167         {
168             CaptureMouse();
169             m_hasCapture = true;
170         }
171 
172         SetCursor(wxCURSOR_SIZENS);
173     }
Release()174     void Release()
175     {
176         m_bLeftDown = false;
177 
178         if ( m_hasCapture )
179         {
180             ReleaseMouse();
181             m_hasCapture = false;
182         }
183 
184         wxWindow *parent = GetParent();
185         if ( parent )
186             SetCursor(parent->GetCursor());
187         else
188             SetCursor(wxNullCursor);
189     }
190 
OnMouseEvent(wxMouseEvent & event)191     void OnMouseEvent(wxMouseEvent& event)
192     {
193         if ( event.GetEventType() == wxEVT_LEFT_DOWN )
194         {
195             m_bLeftDown = true;
196             m_ptPosition = event.GetPosition();
197         }
198         else if ( event.GetEventType() == wxEVT_LEFT_UP )
199         {
200             Release();
201             m_bLeftDown = false;
202         }
203         else if ( event.GetEventType() == wxEVT_MOTION )
204         {
205             if ( m_bLeftDown )
206             {
207                 int dy = m_ptPosition.y - event.GetPosition().y;
208                 if ( dy )
209                 {
210                     Capture();
211                     m_ptPosition = event.GetPosition();
212 
213                     wxSpinEvent evtscroll( (dy >= 0) ? wxEVT_SCROLL_LINEUP :
214                                                        wxEVT_SCROLL_LINEDOWN,
215                                            GetId() );
216                     evtscroll.SetEventObject(this);
217 
218                     wxASSERT( m_spins == 1 );
219 
220                     m_spins = abs(dy);
221                     GetEventHandler()->ProcessEvent(evtscroll);
222                     m_spins = 1;
223                 }
224             }
225         }
226 
227         event.Skip();
228     }
OnMouseCaptureLost(wxMouseCaptureLostEvent & WXUNUSED (event))229     void OnMouseCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
230     {
231         Release();
232     }
233 };
234 
235 #endif  // IS_MOTION_SPIN_SUPPORTED
236 
237 
WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(SpinCtrl,wxPGSpinCtrlEditor,wxPGEditor)238 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(SpinCtrl,
239                                       wxPGSpinCtrlEditor,
240                                       wxPGEditor)
241 
242 
243 // Destructor. It is useful to reset the global pointer in it.
244 wxPGSpinCtrlEditor::~wxPGSpinCtrlEditor()
245 {
246     wxPG_EDITOR(SpinCtrl) = NULL;
247 }
248 
249 // Create controls and initialize event handling.
CreateControls(wxPropertyGrid * propgrid,wxPGProperty * property,const wxPoint & pos,const wxSize & sz) const250 wxPGWindowList wxPGSpinCtrlEditor::CreateControls( wxPropertyGrid* propgrid, wxPGProperty* property,
251                                                    const wxPoint& pos, const wxSize& sz ) const
252 {
253     const int margin = 1;
254     wxSize butSz(18, sz.y);
255     wxSize tcSz(sz.x - butSz.x - margin, sz.y);
256     wxPoint butPos(pos.x + tcSz.x + margin, pos.y);
257 
258     wxSpinButton* wnd2;
259 
260 #if IS_MOTION_SPIN_SUPPORTED
261     if ( property->GetAttributeAsLong(wxT("MotionSpin"), 0) )
262     {
263         wnd2 = new wxPGSpinButton();
264     }
265     else
266 #endif
267     {
268         wnd2 = new wxSpinButton();
269     }
270 
271 #ifdef __WXMSW__
272     wnd2->Hide();
273 #endif
274     wnd2->Create( propgrid->GetPanel(), wxPG_SUBID2, butPos, butSz, wxSP_VERTICAL );
275 
276     wnd2->SetRange( INT_MIN, INT_MAX );
277     wnd2->SetValue( 0 );
278 
279     wxWindow* wnd1 = wxPGTextCtrlEditor::CreateControls(propgrid, property, pos, tcSz).m_primary;
280 #if wxUSE_VALIDATORS
281     // Let's add validator to make sure only numbers can be entered
282     wxTextValidator validator(wxFILTER_NUMERIC, &m_tempString);
283     wnd1->SetValidator(validator);
284 #endif
285 
286     return wxPGWindowList(wnd1, wnd2);
287 }
288 
289 // Control's events are redirected here
OnEvent(wxPropertyGrid * propgrid,wxPGProperty * property,wxWindow * wnd,wxEvent & event) const290 bool wxPGSpinCtrlEditor::OnEvent( wxPropertyGrid* propgrid, wxPGProperty* property,
291                                   wxWindow* wnd, wxEvent& event ) const
292 {
293     int evtType = event.GetEventType();
294     int keycode = -1;
295     int spins = 1;
296     bool bigStep = false;
297 
298     if ( evtType == wxEVT_KEY_DOWN )
299     {
300         wxKeyEvent& keyEvent = (wxKeyEvent&)event;
301         keycode = keyEvent.GetKeyCode();
302 
303         if ( keycode == WXK_UP )
304             evtType = wxEVT_SCROLL_LINEUP;
305         else if ( keycode == WXK_DOWN )
306             evtType = wxEVT_SCROLL_LINEDOWN;
307         else if ( keycode == WXK_PAGEUP )
308         {
309             evtType = wxEVT_SCROLL_LINEUP;
310             bigStep = true;
311         }
312         else if ( keycode == WXK_PAGEDOWN )
313         {
314             evtType = wxEVT_SCROLL_LINEDOWN;
315             bigStep = true;
316         }
317     }
318 
319     if ( evtType == wxEVT_SCROLL_LINEUP || evtType == wxEVT_SCROLL_LINEDOWN )
320     {
321     #if IS_MOTION_SPIN_SUPPORTED
322         if ( property->GetAttributeAsLong(wxT("MotionSpin"), 0) )
323         {
324             wxPGSpinButton* spinButton =
325                 (wxPGSpinButton*) propgrid->GetEditorControlSecondary();
326 
327             if ( spinButton )
328                 spins = spinButton->GetSpins();
329         }
330     #endif
331 
332         wxString s;
333         // Can't use wnd since it might be clipper window
334         wxTextCtrl* tc = wxDynamicCast(propgrid->GetEditorControl(), wxTextCtrl);
335 
336         if ( tc )
337             s = tc->GetValue();
338         else
339             s = property->GetValueAsString(wxPG_FULL_VALUE);
340 
341         int mode = wxPG_PROPERTY_VALIDATION_SATURATE;
342 
343         if ( property->GetAttributeAsLong(wxT("Wrap"), 0) )
344             mode = wxPG_PROPERTY_VALIDATION_WRAP;
345 
346         if ( property->GetValueType() == wxT("double") )
347         {
348             double v_d;
349             double step = property->GetAttributeAsDouble(wxT("Step"), 1.0);
350 
351             // Try double
352             if ( s.ToDouble(&v_d) )
353             {
354                 if ( bigStep )
355                     step *= 10.0;
356 
357                 step *= (double) spins;
358 
359                 if ( evtType == wxEVT_SCROLL_LINEUP ) v_d += step;
360                 else v_d -= step;
361 
362                 // Min/Max check
363                 wxFloatProperty::DoValidation(property, v_d, NULL, mode);
364 
365                 int precision = -1;
366                 wxVariant v = property->GetAttribute(wxPG_FLOAT_PRECISION);
367                 if ( !v.IsNull() )
368                 {
369                     precision = v.GetInteger();
370                 }
371 
372                 s = wxNumberFormatter::ToString(v_d, precision, wxNumberFormatter::Style_NoTrailingZeroes);
373             }
374             else
375             {
376                 return false;
377             }
378         }
379         else
380         {
381             wxLongLong_t v_ll;
382             wxLongLong_t step = property->GetAttributeAsLong(wxT("Step"), 1);
383 
384             // Try (long) long
385             if ( s.ToLongLong(&v_ll, 10) )
386             {
387                 if ( bigStep )
388                     step *= 10;
389 
390                 step *= spins;
391 
392                 if ( evtType == wxEVT_SCROLL_LINEUP ) v_ll += step;
393                 else v_ll -= step;
394 
395                 // Min/Max check
396                 wxIntProperty::DoValidation(property, v_ll, NULL, mode);
397 
398                 s = wxLongLong(v_ll).ToString();
399             }
400             else
401             {
402                 return false;
403             }
404         }
405 
406         if ( tc )
407         {
408             int ip = tc->GetInsertionPoint();
409             int lp = tc->GetLastPosition();
410             tc->SetValue(s);
411             tc->SetInsertionPoint(ip+(tc->GetLastPosition()-lp));
412         }
413 
414         return true;
415     }
416 
417     return wxPGTextCtrlEditor::OnEvent(propgrid,property,wnd,event);
418 }
419 
420 #endif // wxUSE_SPINBTN
421 
422 
423 // -----------------------------------------------------------------------
424 // wxDatePickerCtrl-based property editor
425 // -----------------------------------------------------------------------
426 
427 #if wxUSE_DATEPICKCTRL
428 
429 
430 #include "wx/datectrl.h"
431 #include "wx/dateevt.h"
432 
433 class wxPGDatePickerCtrlEditor : public wxPGEditor
434 {
435     DECLARE_DYNAMIC_CLASS(wxPGDatePickerCtrlEditor)
436 public:
437     virtual ~wxPGDatePickerCtrlEditor();
438 
439     wxString GetName() const;
440     virtual wxPGWindowList CreateControls(wxPropertyGrid* propgrid,
441                                           wxPGProperty* property,
442                                           const wxPoint& pos,
443                                           const wxSize& size) const;
444     virtual void UpdateControl( wxPGProperty* property, wxWindow* wnd ) const;
445     virtual bool OnEvent( wxPropertyGrid* propgrid, wxPGProperty* property,
446         wxWindow* wnd, wxEvent& event ) const;
447     virtual bool GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* wnd ) const;
448     virtual void SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* wnd ) const;
449 };
450 
451 
WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(DatePickerCtrl,wxPGDatePickerCtrlEditor,wxPGEditor)452 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(DatePickerCtrl,
453                                       wxPGDatePickerCtrlEditor,
454                                       wxPGEditor)
455 
456 
457 wxPGDatePickerCtrlEditor::~wxPGDatePickerCtrlEditor()
458 {
459     wxPG_EDITOR(DatePickerCtrl) = NULL;
460 }
461 
CreateControls(wxPropertyGrid * propgrid,wxPGProperty * property,const wxPoint & pos,const wxSize & sz) const462 wxPGWindowList wxPGDatePickerCtrlEditor::CreateControls( wxPropertyGrid* propgrid,
463                                                          wxPGProperty* property,
464                                                          const wxPoint& pos,
465                                                          const wxSize& sz ) const
466 {
467     wxCHECK_MSG( wxDynamicCast(property, wxDateProperty),
468                  NULL,
469                  wxT("DatePickerCtrl editor can only be used with wxDateProperty or derivative.") );
470 
471     wxDateProperty* prop = wxDynamicCast(property, wxDateProperty);
472 
473     // Use two stage creation to allow cleaner display on wxMSW
474     wxDatePickerCtrl* ctrl = new wxDatePickerCtrl();
475 #ifdef __WXMSW__
476     ctrl->Hide();
477     wxSize useSz = wxDefaultSize;
478     useSz.x = sz.x;
479 #else
480     wxSize useSz = sz;
481 #endif
482 
483     wxDateTime dateValue(wxInvalidDateTime);
484 
485     wxVariant value = prop->GetValue();
486     if ( value.GetType() == wxT("datetime") )
487         dateValue = value.GetDateTime();
488 
489     ctrl->Create(propgrid->GetPanel(),
490                  wxPG_SUBID1,
491                  dateValue,
492                  pos,
493                  useSz,
494                  prop->GetDatePickerStyle() | wxNO_BORDER);
495 
496 #ifdef __WXMSW__
497     ctrl->Show();
498 #endif
499 
500     return ctrl;
501 }
502 
503 // Copies value from property to control
UpdateControl(wxPGProperty * property,wxWindow * wnd) const504 void wxPGDatePickerCtrlEditor::UpdateControl( wxPGProperty* property,
505                                               wxWindow* wnd ) const
506 {
507     wxDatePickerCtrl* ctrl = (wxDatePickerCtrl*) wnd;
508     wxASSERT( wxDynamicCast(ctrl, wxDatePickerCtrl) );
509 
510     wxDateTime dateValue(wxInvalidDateTime);
511     wxVariant v(property->GetValue());
512     if ( v.GetType() == wxT("datetime") )
513         dateValue = v.GetDateTime();
514 
515     ctrl->SetValue( dateValue );
516 }
517 
518 // Control's events are redirected here
OnEvent(wxPropertyGrid * WXUNUSED (propgrid),wxPGProperty * WXUNUSED (property),wxWindow * WXUNUSED (wnd),wxEvent & event) const519 bool wxPGDatePickerCtrlEditor::OnEvent( wxPropertyGrid* WXUNUSED(propgrid),
520                                         wxPGProperty* WXUNUSED(property),
521                                         wxWindow* WXUNUSED(wnd),
522                                         wxEvent& event ) const
523 {
524     if ( event.GetEventType() == wxEVT_DATE_CHANGED )
525         return true;
526 
527     return false;
528 }
529 
GetValueFromControl(wxVariant & variant,wxPGProperty * WXUNUSED (property),wxWindow * wnd) const530 bool wxPGDatePickerCtrlEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* WXUNUSED(property), wxWindow* wnd ) const
531 {
532     wxDatePickerCtrl* ctrl = (wxDatePickerCtrl*) wnd;
533     wxASSERT( wxDynamicCast(ctrl, wxDatePickerCtrl) );
534 
535     variant = ctrl->GetValue();
536 
537     return true;
538 }
539 
SetValueToUnspecified(wxPGProperty * property,wxWindow * wnd) const540 void wxPGDatePickerCtrlEditor::SetValueToUnspecified( wxPGProperty* property,
541                                                       wxWindow* wnd ) const
542 {
543     wxDatePickerCtrl* ctrl = (wxDatePickerCtrl*) wnd;
544     wxASSERT( wxDynamicCast(ctrl, wxDatePickerCtrl) );
545 
546     wxDateProperty* prop = wxDynamicCast(property, wxDateProperty);
547 
548     if ( prop )
549     {
550         int datePickerStyle = prop->GetDatePickerStyle();
551         if ( datePickerStyle & wxDP_ALLOWNONE )
552             ctrl->SetValue(wxInvalidDateTime);
553     }
554 }
555 
556 #endif // wxUSE_DATEPICKCTRL
557 
558 
559 // -----------------------------------------------------------------------
560 // wxFontProperty
561 // -----------------------------------------------------------------------
562 
563 #include "wx/fontdlg.h"
564 #include "wx/fontenum.h"
565 
566 //
567 // NB: Do not use wxS here since unlike wxT it doesn't translate to wxChar*
568 //
569 
570 static const wxChar* const gs_fp_es_family_labels[] = {
571     wxT("Default"), wxT("Decorative"),
572     wxT("Roman"), wxT("Script"),
573     wxT("Swiss"), wxT("Modern"),
574     wxT("Teletype"), wxT("Unknown"),
575     (const wxChar*) NULL
576 };
577 
578 static const long gs_fp_es_family_values[] = {
579     wxFONTFAMILY_DEFAULT, wxFONTFAMILY_DECORATIVE,
580     wxFONTFAMILY_ROMAN, wxFONTFAMILY_SCRIPT,
581     wxFONTFAMILY_SWISS, wxFONTFAMILY_MODERN,
582     wxFONTFAMILY_TELETYPE, wxFONTFAMILY_UNKNOWN
583 };
584 
585 static const wxChar* const gs_fp_es_style_labels[] = {
586     wxT("Normal"),
587     wxT("Slant"),
588     wxT("Italic"),
589     (const wxChar*) NULL
590 };
591 
592 static const long gs_fp_es_style_values[] = {
593     wxNORMAL,
594     wxSLANT,
595     wxITALIC
596 };
597 
598 static const wxChar* const gs_fp_es_weight_labels[] = {
599     wxT("Normal"),
600     wxT("Light"),
601     wxT("Bold"),
602     (const wxChar*) NULL
603 };
604 
605 static const long gs_fp_es_weight_values[] = {
606     wxNORMAL,
607     wxLIGHT,
608     wxBOLD
609 };
610 
611 // Class body is in advprops.h
612 
613 
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFontProperty,wxPGProperty,wxFont,const wxFont &,TextCtrlAndButton)614 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxFontProperty,wxPGProperty,
615                                wxFont,const wxFont&,TextCtrlAndButton)
616 
617 
618 wxFontProperty::wxFontProperty( const wxString& label, const wxString& name,
619                                 const wxFont& value )
620     : wxPGProperty(label,name)
621 {
622     SetValue(WXVARIANT(value));
623 
624     // Initialize font family choices list
625     if ( !wxPGGlobalVars->m_fontFamilyChoices )
626     {
627         wxArrayString faceNames = wxFontEnumerator::GetFacenames();
628 
629         faceNames.Sort();
630 
631         wxPGGlobalVars->m_fontFamilyChoices = new wxPGChoices(faceNames);
632     }
633 
634     wxString emptyString(wxEmptyString);
635 
636     wxFont font;
637     font << m_value;
638 
639     AddPrivateChild( new wxIntProperty( _("Point Size"),
640                      wxS("Point Size"),(long)font.GetPointSize() ) );
641 
642     wxString faceName = font.GetFaceName();
643     // If font was not in there, add it now
644     if ( !faceName.empty() &&
645          wxPGGlobalVars->m_fontFamilyChoices->Index(faceName) == wxNOT_FOUND )
646         wxPGGlobalVars->m_fontFamilyChoices->AddAsSorted(faceName);
647 
648     wxPGProperty* p = new wxEnumProperty(_("Face Name"), wxS("Face Name"),
649                                          *wxPGGlobalVars->m_fontFamilyChoices);
650 
651     p->SetValueFromString(faceName, wxPG_FULL_VALUE);
652 
653     AddPrivateChild( p );
654 
655     AddPrivateChild( new wxEnumProperty(_("Style"), wxS("Style"),
656                      gs_fp_es_style_labels,gs_fp_es_style_values,
657                      font.GetStyle()) );
658 
659     AddPrivateChild( new wxEnumProperty(_("Weight"), wxS("Weight"),
660                      gs_fp_es_weight_labels,gs_fp_es_weight_values,
661                      font.GetWeight()) );
662 
663     AddPrivateChild( new wxBoolProperty(_("Underlined"), wxS("Underlined"),
664                      font.GetUnderlined()) );
665 
666     AddPrivateChild( new wxEnumProperty(_("Family"), wxS("PointSize"),
667                      gs_fp_es_family_labels,gs_fp_es_family_values,
668                      font.GetFamily()) );
669 }
670 
~wxFontProperty()671 wxFontProperty::~wxFontProperty() { }
672 
OnSetValue()673 void wxFontProperty::OnSetValue()
674 {
675     wxFont font;
676     font << m_value;
677 
678     if ( !font.IsOk() )
679     {
680         m_value << *wxNORMAL_FONT;
681     }
682 }
683 
ValueToString(wxVariant & value,int argFlags) const684 wxString wxFontProperty::ValueToString( wxVariant& value,
685                                         int argFlags ) const
686 {
687     return wxPGProperty::ValueToString(value, argFlags);
688 }
689 
OnEvent(wxPropertyGrid * propgrid,wxWindow * WXUNUSED (primary),wxEvent & event)690 bool wxFontProperty::OnEvent( wxPropertyGrid* propgrid, wxWindow* WXUNUSED(primary),
691                               wxEvent& event )
692 {
693     if ( propgrid->IsMainButtonEvent(event) )
694     {
695         // Update value from last minute changes
696         wxVariant useValue = propgrid->GetUncommittedPropertyValue();
697 
698         wxFontData data;
699         wxFont font;
700 
701         if ( useValue.GetType() == wxS("wxFont") )
702             font << useValue;
703 
704         data.SetInitialFont( font );
705         data.SetColour(*wxBLACK);
706 
707         wxFontDialog dlg(propgrid, data);
708         if ( dlg.ShowModal() == wxID_OK )
709         {
710             propgrid->EditorsValueWasModified();
711 
712             wxVariant variant;
713             variant << dlg.GetFontData().GetChosenFont();
714             SetValueInEvent( variant );
715             return true;
716         }
717     }
718     return false;
719 }
720 
RefreshChildren()721 void wxFontProperty::RefreshChildren()
722 {
723     if ( !GetChildCount() ) return;
724     wxFont font;
725     font << m_value;
726     Item(0)->SetValue( (long)font.GetPointSize() );
727     Item(1)->SetValueFromString( font.GetFaceName(), wxPG_FULL_VALUE );
728     Item(2)->SetValue( (long)font.GetStyle() );
729     Item(3)->SetValue( (long)font.GetWeight() );
730     Item(4)->SetValue( font.GetUnderlined() );
731     Item(5)->SetValue( (long)font.GetFamily() );
732 }
733 
ChildChanged(wxVariant & thisValue,int ind,wxVariant & childValue) const734 wxVariant wxFontProperty::ChildChanged( wxVariant& thisValue,
735                                         int ind,
736                                         wxVariant& childValue ) const
737 {
738     wxFont font;
739     font << thisValue;
740 
741     if ( ind == 0 )
742     {
743         font.SetPointSize( childValue.GetLong() );
744     }
745     else if ( ind == 1 )
746     {
747         wxString faceName;
748         int faceIndex = childValue.GetLong();
749 
750         if ( faceIndex >= 0 )
751             faceName = wxPGGlobalVars->m_fontFamilyChoices->GetLabel(faceIndex);
752 
753         font.SetFaceName( faceName );
754     }
755     else if ( ind == 2 )
756     {
757         int st = childValue.GetLong();
758         if ( st != wxFONTSTYLE_NORMAL &&
759              st != wxFONTSTYLE_SLANT &&
760              st != wxFONTSTYLE_ITALIC )
761              st = wxFONTWEIGHT_NORMAL;
762         font.SetStyle( st );
763     }
764     else if ( ind == 3 )
765     {
766         int wt = childValue.GetLong();
767         if ( wt != wxFONTWEIGHT_NORMAL &&
768              wt != wxFONTWEIGHT_LIGHT &&
769              wt != wxFONTWEIGHT_BOLD )
770              wt = wxFONTWEIGHT_NORMAL;
771         font.SetWeight( wt );
772     }
773     else if ( ind == 4 )
774     {
775         font.SetUnderlined( childValue.GetBool() );
776     }
777     else if ( ind == 5 )
778     {
779         int fam = childValue.GetLong();
780         if ( fam < wxDEFAULT ||
781              fam > wxTELETYPE )
782              fam = wxDEFAULT;
783         font.SetFamily( fam );
784     }
785 
786     wxVariant newVariant;
787     newVariant << font;
788     return newVariant;
789 }
790 
791 /*
792 wxSize wxFontProperty::OnMeasureImage() const
793 {
794     return wxSize(-1,-1);
795 }
796 
797 void wxFontProperty::OnCustomPaint(wxDC& dc,
798                                         const wxRect& rect,
799                                         wxPGPaintData& paintData)
800 {
801     wxString drawFace;
802     if ( paintData.m_choiceItem >= 0 )
803         drawFace = wxPGGlobalVars->m_fontFamilyChoices->GetLabel(paintData.m_choiceItem);
804     else
805         drawFace = m_value_wxFont.GetFaceName();
806 
807     if ( !drawFace.empty() )
808     {
809         // Draw the background
810         dc.SetBrush( wxColour(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE)) );
811         //dc.SetBrush( *wxWHITE_BRUSH );
812         //dc.SetPen( *wxMEDIUM_GREY_PEN );
813         dc.DrawRectangle( rect );
814 
815         wxFont oldFont = dc.GetFont();
816         wxFont drawFont(oldFont.GetPointSize(),
817                         wxDEFAULT,wxNORMAL,wxBOLD,false,drawFace);
818         dc.SetFont(drawFont);
819 
820         dc.SetTextForeground( wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT) );
821         dc.DrawText( wxT("Aa"), rect.x+2, rect.y+1 );
822 
823         dc.SetFont(oldFont);
824     }
825     else
826     {
827         // No file - just draw a white box
828         dc.SetBrush ( *wxWHITE_BRUSH );
829         dc.DrawRectangle ( rect );
830     }
831 }
832 */
833 
834 
835 // -----------------------------------------------------------------------
836 // wxSystemColourProperty
837 // -----------------------------------------------------------------------
838 
839 // wxEnumProperty based classes cannot use wxPG_PROP_CLASS_SPECIFIC_1
840 #define wxPG_PROP_HIDE_CUSTOM_COLOUR        wxPG_PROP_CLASS_SPECIFIC_2
841 
842 #include "wx/colordlg.h"
843 
844 //#define wx_cp_es_syscolours_len 25
845 static const wxChar* const gs_cp_es_syscolour_labels[] = {
846     wxT("AppWorkspace"),
847     wxT("ActiveBorder"),
848     wxT("ActiveCaption"),
849     wxT("ButtonFace"),
850     wxT("ButtonHighlight"),
851     wxT("ButtonShadow"),
852     wxT("ButtonText"),
853     wxT("CaptionText"),
854     wxT("ControlDark"),
855     wxT("ControlLight"),
856     wxT("Desktop"),
857     wxT("GrayText"),
858     wxT("Highlight"),
859     wxT("HighlightText"),
860     wxT("InactiveBorder"),
861     wxT("InactiveCaption"),
862     wxT("InactiveCaptionText"),
863     wxT("Menu"),
864     wxT("Scrollbar"),
865     wxT("Tooltip"),
866     wxT("TooltipText"),
867     wxT("Window"),
868     wxT("WindowFrame"),
869     wxT("WindowText"),
870     wxT("Custom"),
871     (const wxChar*) NULL
872 };
873 
874 static const long gs_cp_es_syscolour_values[] = {
875     wxSYS_COLOUR_APPWORKSPACE,
876     wxSYS_COLOUR_ACTIVEBORDER,
877     wxSYS_COLOUR_ACTIVECAPTION,
878     wxSYS_COLOUR_BTNFACE,
879     wxSYS_COLOUR_BTNHIGHLIGHT,
880     wxSYS_COLOUR_BTNSHADOW,
881     wxSYS_COLOUR_BTNTEXT ,
882     wxSYS_COLOUR_CAPTIONTEXT,
883     wxSYS_COLOUR_3DDKSHADOW,
884     wxSYS_COLOUR_3DLIGHT,
885     wxSYS_COLOUR_BACKGROUND,
886     wxSYS_COLOUR_GRAYTEXT,
887     wxSYS_COLOUR_HIGHLIGHT,
888     wxSYS_COLOUR_HIGHLIGHTTEXT,
889     wxSYS_COLOUR_INACTIVEBORDER,
890     wxSYS_COLOUR_INACTIVECAPTION,
891     wxSYS_COLOUR_INACTIVECAPTIONTEXT,
892     wxSYS_COLOUR_MENU,
893     wxSYS_COLOUR_SCROLLBAR,
894     wxSYS_COLOUR_INFOBK,
895     wxSYS_COLOUR_INFOTEXT,
896     wxSYS_COLOUR_WINDOW,
897     wxSYS_COLOUR_WINDOWFRAME,
898     wxSYS_COLOUR_WINDOWTEXT,
899     wxPG_COLOUR_CUSTOM
900 };
901 
902 
IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxColourPropertyValue,WXDLLIMPEXP_PROPGRID)903 IMPLEMENT_VARIANT_OBJECT_EXPORTED_SHALLOWCMP(wxColourPropertyValue, WXDLLIMPEXP_PROPGRID)
904 
905 
906 // Class body is in advprops.h
907 
908 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxSystemColourProperty,wxEnumProperty,
909                                wxColourPropertyValue,const wxColourPropertyValue&,Choice)
910 
911 
912 void wxSystemColourProperty::Init( int type, const wxColour& colour )
913 {
914     wxColourPropertyValue cpv;
915 
916     if ( colour.IsOk() )
917         cpv.Init( type, colour );
918     else
919         cpv.Init( type, *wxWHITE );
920 
921     m_flags |= wxPG_PROP_STATIC_CHOICES; // Colour selection cannot be changed.
922 
923     m_value << cpv;
924 
925     OnSetValue();
926 }
927 
928 
929 static wxPGChoices gs_wxSystemColourProperty_choicesCache;
930 
931 
wxSystemColourProperty(const wxString & label,const wxString & name,const wxColourPropertyValue & value)932 wxSystemColourProperty::wxSystemColourProperty( const wxString& label, const wxString& name,
933     const wxColourPropertyValue& value )
934     : wxEnumProperty( label,
935                       name,
936                       gs_cp_es_syscolour_labels,
937                       gs_cp_es_syscolour_values,
938                       &gs_wxSystemColourProperty_choicesCache )
939 {
940     if ( &value )
941         Init( value.m_type, value.m_colour );
942     else
943         Init( wxPG_COLOUR_CUSTOM, *wxWHITE );
944 }
945 
946 
wxSystemColourProperty(const wxString & label,const wxString & name,const wxChar * const * labels,const long * values,wxPGChoices * choicesCache,const wxColourPropertyValue & value)947 wxSystemColourProperty::wxSystemColourProperty( const wxString& label, const wxString& name,
948     const wxChar* const* labels, const long* values, wxPGChoices* choicesCache,
949     const wxColourPropertyValue& value )
950     : wxEnumProperty( label, name, labels, values, choicesCache )
951 {
952     if ( &value )
953         Init( value.m_type, value.m_colour );
954     else
955         Init( wxPG_COLOUR_CUSTOM, *wxWHITE );
956 }
957 
958 
wxSystemColourProperty(const wxString & label,const wxString & name,const wxChar * const * labels,const long * values,wxPGChoices * choicesCache,const wxColour & value)959 wxSystemColourProperty::wxSystemColourProperty( const wxString& label, const wxString& name,
960     const wxChar* const* labels, const long* values, wxPGChoices* choicesCache,
961     const wxColour& value )
962     : wxEnumProperty( label, name, labels, values, choicesCache )
963 {
964     if ( &value )
965         Init( wxPG_COLOUR_CUSTOM, value );
966     else
967         Init( wxPG_COLOUR_CUSTOM, *wxWHITE );
968 }
969 
970 
~wxSystemColourProperty()971 wxSystemColourProperty::~wxSystemColourProperty() { }
972 
973 
GetVal(const wxVariant * pVariant) const974 wxColourPropertyValue wxSystemColourProperty::GetVal( const wxVariant* pVariant ) const
975 {
976     if ( !pVariant )
977         pVariant = &m_value;
978 
979     if ( pVariant->IsNull() )
980         return wxColourPropertyValue(wxPG_COLOUR_UNSPECIFIED, wxColour());
981 
982     if ( pVariant->GetType() == wxS("wxColourPropertyValue") )
983     {
984         wxColourPropertyValue v;
985         v << *pVariant;
986         return v;
987     }
988 
989     wxColour col;
990     bool variantProcessed = true;
991 
992     if ( pVariant->GetType() == wxS("wxColour*") )
993     {
994         wxColour* pCol = wxStaticCast(pVariant->GetWxObjectPtr(), wxColour);
995         col = *pCol;
996     }
997     else if ( pVariant->GetType() == wxS("wxColour") )
998     {
999         col << *pVariant;
1000     }
1001     else if ( pVariant->GetType() == wxArrayInt_VariantType )
1002     {
1003         // This code is mostly needed for wxPython bindings, which
1004         // may offer tuple of integers as colour value.
1005         wxArrayInt arr;
1006         arr << *pVariant;
1007 
1008         if ( arr.size() >= 3 )
1009         {
1010             int r, g, b;
1011             int a = 255;
1012 
1013             r = arr[0];
1014             g = arr[1];
1015             b = arr[2];
1016             if ( arr.size() >= 4 )
1017                 a = arr[3];
1018 
1019             col = wxColour(r, g, b, a);
1020         }
1021         else
1022         {
1023             variantProcessed = false;
1024         }
1025     }
1026     else
1027     {
1028         variantProcessed = false;
1029     }
1030 
1031     if ( !variantProcessed )
1032         return wxColourPropertyValue(wxPG_COLOUR_UNSPECIFIED, wxColour());
1033 
1034     wxColourPropertyValue v2( wxPG_COLOUR_CUSTOM, col );
1035 
1036     int colInd = ColToInd(col);
1037     if ( colInd != wxNOT_FOUND )
1038         v2.m_type = colInd;
1039 
1040     return v2;
1041 }
1042 
DoTranslateVal(wxColourPropertyValue & v) const1043 wxVariant wxSystemColourProperty::DoTranslateVal( wxColourPropertyValue& v ) const
1044 {
1045     wxVariant variant;
1046     variant << v;
1047     return variant;
1048 }
1049 
ColToInd(const wxColour & colour) const1050 int wxSystemColourProperty::ColToInd( const wxColour& colour ) const
1051 {
1052     size_t i;
1053     size_t i_max = m_choices.GetCount();
1054 
1055     if ( !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
1056         i_max -= 1;
1057 
1058     for ( i=0; i<i_max; i++ )
1059     {
1060         int ind = m_choices[i].GetValue();
1061 
1062         if ( colour == GetColour(ind) )
1063         {
1064             /*wxLogDebug(wxT("%s(%s): Index %i for ( getcolour(%i,%i,%i), colour(%i,%i,%i))"),
1065                 GetClassName(),GetLabel().c_str(),
1066                 (int)i,(int)GetColour(ind).Red(),(int)GetColour(ind).Green(),(int)GetColour(ind).Blue(),
1067                 (int)colour.Red(),(int)colour.Green(),(int)colour.Blue());*/
1068             return ind;
1069         }
1070     }
1071     return wxNOT_FOUND;
1072 }
1073 
OnSetValue()1074 void wxSystemColourProperty::OnSetValue()
1075 {
1076     // Convert from generic wxobject ptr to wxPGVariantDataColour
1077     if ( m_value.GetType() == wxS("wxColour*") )
1078     {
1079         wxColour* pCol = wxStaticCast(m_value.GetWxObjectPtr(), wxColour);
1080         m_value << *pCol;
1081     }
1082 
1083     wxColourPropertyValue val = GetVal(&m_value);
1084 
1085     if ( val.m_type == wxPG_COLOUR_UNSPECIFIED )
1086     {
1087         m_value.MakeNull();
1088         return;
1089     }
1090     else
1091     {
1092 
1093         if ( val.m_type < wxPG_COLOUR_WEB_BASE )
1094             val.m_colour = GetColour( val.m_type );
1095 
1096         m_value = TranslateVal(val);
1097     }
1098 
1099     int ind = wxNOT_FOUND;
1100 
1101     if ( m_value.GetType() == wxS("wxColourPropertyValue") )
1102     {
1103         wxColourPropertyValue cpv;
1104         cpv << m_value;
1105         wxColour col = cpv.m_colour;
1106 
1107         if ( !col.IsOk() )
1108         {
1109             SetValueToUnspecified();
1110             SetIndex(wxNOT_FOUND);
1111             return;
1112         }
1113 
1114         if ( cpv.m_type < wxPG_COLOUR_WEB_BASE ||
1115              (m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
1116         {
1117             ind = GetIndexForValue(cpv.m_type);
1118         }
1119         else
1120         {
1121             cpv.m_type = wxPG_COLOUR_CUSTOM;
1122             ind = GetCustomColourIndex();
1123         }
1124     }
1125     else
1126     {
1127         wxColour col;
1128         col << m_value;
1129 
1130         if ( !col.IsOk() )
1131         {
1132             SetValueToUnspecified();
1133             SetIndex(wxNOT_FOUND);
1134             return;
1135         }
1136 
1137         ind = ColToInd(col);
1138 
1139         if ( ind == wxNOT_FOUND &&
1140              !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
1141             ind = GetCustomColourIndex();
1142     }
1143 
1144     SetIndex(ind);
1145 }
1146 
1147 
GetColour(int index) const1148 wxColour wxSystemColourProperty::GetColour( int index ) const
1149 {
1150     return wxSystemSettings::GetColour( (wxSystemColour)index );
1151 }
1152 
ColourToString(const wxColour & col,int index,int argFlags) const1153 wxString wxSystemColourProperty::ColourToString( const wxColour& col,
1154                                                  int index,
1155                                                  int argFlags ) const
1156 {
1157 
1158     if ( index == wxNOT_FOUND )
1159     {
1160 
1161         if ( (argFlags & wxPG_FULL_VALUE) ||
1162              GetAttributeAsLong(wxPG_COLOUR_HAS_ALPHA, 0) )
1163         {
1164             return wxString::Format(wxS("(%i,%i,%i,%i)"),
1165                                     (int)col.Red(),
1166                                     (int)col.Green(),
1167                                     (int)col.Blue(),
1168                                     (int)col.Alpha());
1169         }
1170         else
1171         {
1172             return wxString::Format(wxS("(%i,%i,%i)"),
1173                                     (int)col.Red(),
1174                                     (int)col.Green(),
1175                                     (int)col.Blue());
1176         }
1177     }
1178     else
1179     {
1180         return m_choices.GetLabel(index);
1181     }
1182 }
1183 
ValueToString(wxVariant & value,int argFlags) const1184 wxString wxSystemColourProperty::ValueToString( wxVariant& value,
1185                                                 int argFlags ) const
1186 {
1187     wxColourPropertyValue val = GetVal(&value);
1188 
1189     int index;
1190 
1191     if ( argFlags & wxPG_VALUE_IS_CURRENT )
1192     {
1193         // GetIndex() only works reliably if wxPG_VALUE_IS_CURRENT flag is set,
1194         // but we should use it whenever possible.
1195         index = GetIndex();
1196 
1197         // If custom colour was selected, use invalid index, so that
1198         // ColourToString() will return properly formatted colour text.
1199         if ( index == GetCustomColourIndex() &&
1200              !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
1201             index = wxNOT_FOUND;
1202     }
1203     else
1204     {
1205         index = m_choices.Index(val.m_type);
1206     }
1207 
1208     return ColourToString(val.m_colour, index, argFlags);
1209 }
1210 
1211 
OnMeasureImage(int) const1212 wxSize wxSystemColourProperty::OnMeasureImage( int ) const
1213 {
1214     return wxPG_DEFAULT_IMAGE_SIZE;
1215 }
1216 
1217 
GetCustomColourIndex() const1218 int wxSystemColourProperty::GetCustomColourIndex() const
1219 {
1220     return m_choices.GetCount() - 1;
1221 }
1222 
1223 
QueryColourFromUser(wxVariant & variant) const1224 bool wxSystemColourProperty::QueryColourFromUser( wxVariant& variant ) const
1225 {
1226     wxASSERT( m_value.GetType() != wxPG_VARIANT_TYPE_STRING );
1227     bool res = false;
1228 
1229     wxPropertyGrid* propgrid = GetGrid();
1230     wxASSERT( propgrid );
1231 
1232     // Must only occur when user triggers event
1233     if ( !(propgrid->GetInternalFlags() & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT) )
1234         return res;
1235 
1236     wxColourPropertyValue val = GetVal();
1237 
1238     val.m_type = wxPG_COLOUR_CUSTOM;
1239 
1240     wxColourData data;
1241     data.SetChooseFull(true);
1242     data.SetColour(val.m_colour);
1243     int i;
1244     for ( i = 0; i < 16; i++)
1245     {
1246         wxColour colour(i*16, i*16, i*16);
1247         data.SetCustomColour(i, colour);
1248     }
1249 
1250     wxColourDialog dialog(propgrid, &data);
1251     if ( dialog.ShowModal() == wxID_OK )
1252     {
1253         wxColourData retData = dialog.GetColourData();
1254         val.m_colour = retData.GetColour();
1255 
1256         variant = DoTranslateVal(val);
1257 
1258         SetValueInEvent(variant);
1259 
1260         res = true;
1261     }
1262 
1263     return res;
1264 }
1265 
1266 
IntToValue(wxVariant & variant,int number,int argFlags) const1267 bool wxSystemColourProperty::IntToValue( wxVariant& variant, int number, int argFlags ) const
1268 {
1269     int index = number;
1270     int type = m_choices.GetValue(index);
1271 
1272     if ( m_choices.GetLabel(index) == _("Custom") )
1273     {
1274          if ( !(argFlags & wxPG_PROPERTY_SPECIFIC) )
1275             return QueryColourFromUser(variant);
1276 
1277          // Call from event handler.
1278          // User will be asked for custom color later on in OnEvent().
1279          wxColourPropertyValue val = GetVal();
1280          variant = DoTranslateVal(val);
1281     }
1282     else
1283     {
1284         variant = TranslateVal( type, GetColour(type) );
1285     }
1286 
1287     return true;
1288 }
1289 
1290 // Need to do some extra event handling.
OnEvent(wxPropertyGrid * propgrid,wxWindow * WXUNUSED (primary),wxEvent & event)1291 bool wxSystemColourProperty::OnEvent( wxPropertyGrid* propgrid,
1292                                       wxWindow* WXUNUSED(primary),
1293                                       wxEvent& event )
1294 {
1295     bool askColour = false;
1296 
1297     if ( propgrid->IsMainButtonEvent(event) )
1298     {
1299         // We need to handle button click in case editor has been
1300         // switched to one that has wxButton as well.
1301         askColour = true;
1302     }
1303     else if ( event.GetEventType() == wxEVT_COMBOBOX )
1304     {
1305         // Must override index detection since at this point GetIndex()
1306         // will return old value.
1307         wxOwnerDrawnComboBox* cb =
1308             static_cast<wxOwnerDrawnComboBox*>(propgrid->GetEditorControl());
1309 
1310         if ( cb )
1311         {
1312             int index = cb->GetSelection();
1313 
1314             if ( index == GetCustomColourIndex() &&
1315                     !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
1316                 askColour = true;
1317         }
1318     }
1319 
1320     if ( askColour && !propgrid->WasValueChangedInEvent() )
1321     {
1322         wxVariant variant;
1323         if ( QueryColourFromUser(variant) )
1324             return true;
1325     }
1326     return false;
1327 }
1328 
1329 /*class wxPGColourPropertyRenderer : public wxPGDefaultRenderer
1330 {
1331 public:
1332     virtual void Render( wxDC& dc, const wxRect& rect,
1333                          const wxPropertyGrid* propertyGrid, wxPGProperty* property,
1334                          int WXUNUSED(column), int item, int WXUNUSED(flags) ) const
1335     {
1336         wxASSERT( wxDynamicCast(property, wxSystemColourProperty) );
1337         wxSystemColourProperty* prop = wxStaticCast(property, wxSystemColourProperty);
1338 
1339         dc.SetPen(*wxBLACK_PEN);
1340         if ( item >= 0 &&
1341              ( item < (int)(GetCustomColourIndex) || (prop->HasFlag(wxPG_PROP_HIDE_CUSTOM_COLOUR)))
1342            )
1343         {
1344             int colInd;
1345             const wxArrayInt& values = prop->GetValues();
1346             if ( values.GetChildCount() )
1347                 colInd = values[item];
1348             else
1349                 colInd = item;
1350             dc.SetBrush( wxColour( prop->GetColour( colInd ) ) );
1351         }
1352         else if ( !prop->IsValueUnspecified() )
1353             dc.SetBrush( prop->GetVal().m_colour );
1354         else
1355             dc.SetBrush( *wxWHITE );
1356 
1357         wxRect imageRect = propertyGrid->GetImageRect(property, item);
1358         wxLogDebug(wxT("%i, %i"),imageRect.x,imageRect.y);
1359         dc.DrawRectangle( rect.x+imageRect.x, rect.y+imageRect.y,
1360                           imageRect.width, imageRect.height );
1361 
1362         wxString text;
1363         if ( item == -1 )
1364             text = property->GetValueAsString();
1365         else
1366             text = property->GetChoiceString(item);
1367         DrawText( dc, rect, imageRect.width, text );
1368     }
1369 protected:
1370 };
1371 
1372 wxPGColourPropertyRenderer g_wxPGColourPropertyRenderer;
1373 
1374 wxPGCellRenderer* wxSystemColourProperty::GetCellRenderer( int column ) const
1375 {
1376     if ( column == 1 )
1377         return &g_wxPGColourPropertyRenderer;
1378     return wxEnumProperty::GetCellRenderer(column);
1379 }*/
1380 
OnCustomPaint(wxDC & dc,const wxRect & rect,wxPGPaintData & paintdata)1381 void wxSystemColourProperty::OnCustomPaint( wxDC& dc, const wxRect& rect,
1382                                             wxPGPaintData& paintdata )
1383 {
1384     wxColour col;
1385 
1386     if ( paintdata.m_choiceItem >= 0 &&
1387          paintdata.m_choiceItem < (int)m_choices.GetCount() &&
1388          (paintdata.m_choiceItem != GetCustomColourIndex() ||
1389           m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
1390     {
1391         int colInd = m_choices[paintdata.m_choiceItem].GetValue();
1392         col = GetColour( colInd );
1393     }
1394     else if ( !IsValueUnspecified() )
1395     {
1396         col = GetVal().m_colour;
1397     }
1398 
1399     if ( col.IsOk() )
1400     {
1401         dc.SetBrush(col);
1402         dc.DrawRectangle(rect);
1403     }
1404 }
1405 
1406 
StringToValue(wxVariant & value,const wxString & text,int argFlags) const1407 bool wxSystemColourProperty::StringToValue( wxVariant& value, const wxString& text, int argFlags ) const
1408 {
1409     wxString custColName(m_choices.GetLabel(GetCustomColourIndex()));
1410     wxString colStr(text);
1411     colStr.Trim(true);
1412     colStr.Trim(false);
1413 
1414     wxColour customColour;
1415     bool conversionSuccess = false;
1416 
1417     if ( colStr != custColName )
1418     {
1419         if ( colStr.Find(wxS("(")) == 0 )
1420         {
1421             // Eliminate whitespace
1422             colStr.Replace(wxS(" "), wxEmptyString);
1423 
1424             int commaCount = colStr.Freq(wxS(','));
1425             if ( commaCount == 2 )
1426             {
1427                 // Convert (R,G,B) to rgb(R,G,B)
1428                 colStr = wxS("rgb") + colStr;
1429             }
1430             else if ( commaCount == 3 )
1431             {
1432                 // We have int alpha, CSS format that wxColour takes as
1433                 // input processes float alpha. So, let's parse the colour
1434                 // ourselves instead of trying to convert it to a format
1435                 // that wxColour::FromString() understands.
1436                 int r = -1, g = -1, b = -1, a = -1;
1437                 wxSscanf(colStr, wxS("(%i,%i,%i,%i)"), &r, &g, &b, &a);
1438                 customColour.Set(r, g, b, a);
1439                 conversionSuccess = customColour.IsOk();
1440             }
1441         }
1442 
1443         if ( !conversionSuccess )
1444             conversionSuccess = customColour.Set(colStr);
1445     }
1446 
1447     if ( !conversionSuccess && m_choices.GetCount() &&
1448          !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) &&
1449          colStr == custColName )
1450     {
1451         if ( !(argFlags & wxPG_EDITABLE_VALUE ))
1452         {
1453             // This really should not occur...
1454             // wxASSERT(false);
1455             ResetNextIndex();
1456             return false;
1457         }
1458 
1459         if ( (argFlags & wxPG_PROPERTY_SPECIFIC) )
1460         {
1461             // Query for value from the event handler.
1462             // User will be asked for custom color later on in OnEvent().
1463             ResetNextIndex();
1464             return false;
1465         }
1466         if ( !QueryColourFromUser(value) )
1467         {
1468             ResetNextIndex();
1469             return false;
1470         }
1471     }
1472     else
1473     {
1474         wxColourPropertyValue val;
1475 
1476         bool done = false;
1477 
1478         if ( !conversionSuccess )
1479         {
1480             // Try predefined colour first
1481             bool res = wxEnumProperty::StringToValue(value,
1482                                                      colStr,
1483                                                      argFlags);
1484             if ( res && GetIndex() >= 0 )
1485             {
1486                 val.m_type = GetIndex();
1487                 if ( val.m_type < m_choices.GetCount() )
1488                     val.m_type = m_choices[val.m_type].GetValue();
1489 
1490                 // Get proper colour for type.
1491                 val.m_colour = GetColour(val.m_type);
1492 
1493                 done = true;
1494             }
1495         }
1496         else
1497         {
1498             val.m_type = wxPG_COLOUR_CUSTOM;
1499             val.m_colour = customColour;
1500             done = true;
1501         }
1502 
1503         if ( !done )
1504         {
1505             ResetNextIndex();
1506             return false;
1507         }
1508 
1509         value = DoTranslateVal(val);
1510     }
1511 
1512     return true;
1513 }
1514 
1515 
DoSetAttribute(const wxString & name,wxVariant & value)1516 bool wxSystemColourProperty::DoSetAttribute( const wxString& name, wxVariant& value )
1517 {
1518     if ( name == wxPG_COLOUR_ALLOW_CUSTOM )
1519     {
1520         int ival = value.GetLong();
1521 
1522         if ( ival && (m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
1523         {
1524             // Show custom choice
1525             m_choices.Insert(wxT("Custom"), GetCustomColourIndex(), wxPG_COLOUR_CUSTOM);
1526             m_flags &= ~(wxPG_PROP_HIDE_CUSTOM_COLOUR);
1527         }
1528         else if ( !ival && !(m_flags & wxPG_PROP_HIDE_CUSTOM_COLOUR) )
1529         {
1530             // Hide custom choice
1531             m_choices.RemoveAt(GetCustomColourIndex());
1532             m_flags |= wxPG_PROP_HIDE_CUSTOM_COLOUR;
1533         }
1534         return true;
1535     }
1536     return false;
1537 }
1538 
1539 
1540 // -----------------------------------------------------------------------
1541 // wxColourProperty
1542 // -----------------------------------------------------------------------
1543 
1544 static const wxChar* const gs_cp_es_normcolour_labels[] = {
1545     wxT("Black"),
1546     wxT("Maroon"),
1547     wxT("Navy"),
1548     wxT("Purple"),
1549     wxT("Teal"),
1550     wxT("Gray"),
1551     wxT("Green"),
1552     wxT("Olive"),
1553     wxT("Brown"),
1554     wxT("Blue"),
1555     wxT("Fuchsia"),
1556     wxT("Red"),
1557     wxT("Orange"),
1558     wxT("Silver"),
1559     wxT("Lime"),
1560     wxT("Aqua"),
1561     wxT("Yellow"),
1562     wxT("White"),
1563     wxT("Custom"),
1564     (const wxChar*) NULL
1565 };
1566 
1567 static const unsigned long gs_cp_es_normcolour_colours[] = {
1568     wxPG_COLOUR(0,0,0),
1569     wxPG_COLOUR(128,0,0),
1570     wxPG_COLOUR(0,0,128),
1571     wxPG_COLOUR(128,0,128),
1572     wxPG_COLOUR(0,128,128),
1573     wxPG_COLOUR(128,128,128),
1574     wxPG_COLOUR(0,128,0),
1575     wxPG_COLOUR(128,128,0),
1576     wxPG_COLOUR(166,124,81),
1577     wxPG_COLOUR(0,0,255),
1578     wxPG_COLOUR(255,0,255),
1579     wxPG_COLOUR(255,0,0),
1580     wxPG_COLOUR(247,148,28),
1581     wxPG_COLOUR(192,192,192),
1582     wxPG_COLOUR(0,255,0),
1583     wxPG_COLOUR(0,255,255),
1584     wxPG_COLOUR(255,255,0),
1585     wxPG_COLOUR(255,255,255),
1586     wxPG_COLOUR(0,0,0)
1587 };
1588 
1589 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxColourProperty, wxSystemColourProperty,
1590                                wxColour, const wxColour&, TextCtrlAndButton)
1591 
1592 static wxPGChoices gs_wxColourProperty_choicesCache;
1593 
wxColourProperty(const wxString & label,const wxString & name,const wxColour & value)1594 wxColourProperty::wxColourProperty( const wxString& label,
1595                       const wxString& name,
1596                       const wxColour& value )
1597     : wxSystemColourProperty(label, name, gs_cp_es_normcolour_labels,
1598                              NULL,
1599                              &gs_wxColourProperty_choicesCache, value )
1600 {
1601      wxASSERT_MSG( wxTheColourDatabase, wxT("No colour database") );
1602      if ( wxTheColourDatabase )
1603      {
1604         // Extended colour database with custom PG colours.
1605         const wxChar* const* colourLabels = gs_cp_es_normcolour_labels;
1606         for ( int i = 0; *colourLabels; colourLabels++, i++ )
1607         {
1608             wxColour clr = wxTheColourDatabase->Find(*colourLabels);
1609             // Use standard wx colour value if its label was found,
1610             // otherwise register custom PG colour.
1611             if ( !clr.IsOk() )
1612             {
1613                 clr.Set(gs_cp_es_normcolour_colours[i]);
1614                 wxTheColourDatabase->AddColour(*colourLabels, clr);
1615             }
1616         }
1617      }
1618 
1619     Init( value );
1620 
1621     m_flags |= wxPG_PROP_TRANSLATE_CUSTOM;
1622 }
1623 
~wxColourProperty()1624 wxColourProperty::~wxColourProperty()
1625 {
1626 }
1627 
Init(wxColour colour)1628 void wxColourProperty::Init( wxColour colour )
1629 {
1630     if ( !colour.IsOk() )
1631         colour = *wxWHITE;
1632     wxVariant variant;
1633     variant << colour;
1634     m_value = variant;
1635     int ind = ColToInd(colour);
1636     if ( ind < 0 )
1637         ind = m_choices.GetCount() - 1;
1638     SetIndex( ind );
1639 }
1640 
ValueToString(wxVariant & value,int argFlags) const1641 wxString wxColourProperty::ValueToString( wxVariant& value,
1642                                           int argFlags ) const
1643 {
1644     const wxPGEditor* editor = GetEditorClass();
1645     if ( editor != wxPGEditor_Choice &&
1646          editor != wxPGEditor_ChoiceAndButton &&
1647          editor != wxPGEditor_ComboBox )
1648         argFlags |= wxPG_PROPERTY_SPECIFIC;
1649 
1650     return wxSystemColourProperty::ValueToString(value, argFlags);
1651 }
1652 
GetColour(int index) const1653 wxColour wxColourProperty::GetColour( int index ) const
1654 {
1655     return wxColour(gs_cp_es_normcolour_labels[m_choices.GetValue(index)]);
1656 }
1657 
DoTranslateVal(wxColourPropertyValue & v) const1658 wxVariant wxColourProperty::DoTranslateVal( wxColourPropertyValue& v ) const
1659 {
1660     wxVariant variant;
1661     variant << v.m_colour;
1662     return variant;
1663 }
1664 
1665 // -----------------------------------------------------------------------
1666 // wxCursorProperty
1667 // -----------------------------------------------------------------------
1668 
1669 #define wxPG_CURSOR_IMAGE_WIDTH     32
1670 
1671 #define NUM_CURSORS 28
1672 
1673 //#define wx_cp_es_syscursors_len 28
1674 static const wxChar* const gs_cp_es_syscursors_labels[NUM_CURSORS+1] = {
1675     wxT("Default"),
1676     wxT("Arrow"),
1677     wxT("Right Arrow"),
1678     wxT("Blank"),
1679     wxT("Bullseye"),
1680     wxT("Character"),
1681     wxT("Cross"),
1682     wxT("Hand"),
1683     wxT("I-Beam"),
1684     wxT("Left Button"),
1685     wxT("Magnifier"),
1686     wxT("Middle Button"),
1687     wxT("No Entry"),
1688     wxT("Paint Brush"),
1689     wxT("Pencil"),
1690     wxT("Point Left"),
1691     wxT("Point Right"),
1692     wxT("Question Arrow"),
1693     wxT("Right Button"),
1694     wxT("Sizing NE-SW"),
1695     wxT("Sizing N-S"),
1696     wxT("Sizing NW-SE"),
1697     wxT("Sizing W-E"),
1698     wxT("Sizing"),
1699     wxT("Spraycan"),
1700     wxT("Wait"),
1701     wxT("Watch"),
1702     wxT("Wait Arrow"),
1703     (const wxChar*) NULL
1704 };
1705 
1706 static const long gs_cp_es_syscursors_values[NUM_CURSORS] = {
1707     wxCURSOR_NONE,
1708     wxCURSOR_ARROW,
1709     wxCURSOR_RIGHT_ARROW,
1710     wxCURSOR_BLANK,
1711     wxCURSOR_BULLSEYE,
1712     wxCURSOR_CHAR,
1713     wxCURSOR_CROSS,
1714     wxCURSOR_HAND,
1715     wxCURSOR_IBEAM,
1716     wxCURSOR_LEFT_BUTTON,
1717     wxCURSOR_MAGNIFIER,
1718     wxCURSOR_MIDDLE_BUTTON,
1719     wxCURSOR_NO_ENTRY,
1720     wxCURSOR_PAINT_BRUSH,
1721     wxCURSOR_PENCIL,
1722     wxCURSOR_POINT_LEFT,
1723     wxCURSOR_POINT_RIGHT,
1724     wxCURSOR_QUESTION_ARROW,
1725     wxCURSOR_RIGHT_BUTTON,
1726     wxCURSOR_SIZENESW,
1727     wxCURSOR_SIZENS,
1728     wxCURSOR_SIZENWSE,
1729     wxCURSOR_SIZEWE,
1730     wxCURSOR_SIZING,
1731     wxCURSOR_SPRAYCAN,
1732     wxCURSOR_WAIT,
1733     wxCURSOR_WATCH,
1734     wxCURSOR_ARROWWAIT
1735 };
1736 
IMPLEMENT_DYNAMIC_CLASS(wxCursorProperty,wxEnumProperty)1737 IMPLEMENT_DYNAMIC_CLASS(wxCursorProperty, wxEnumProperty)
1738 
1739 wxCursorProperty::wxCursorProperty( const wxString& label, const wxString& name,
1740     int value )
1741     : wxEnumProperty( label,
1742                       name,
1743                       gs_cp_es_syscursors_labels,
1744                       gs_cp_es_syscursors_values,
1745                       value )
1746 {
1747     m_flags |= wxPG_PROP_STATIC_CHOICES; // Cursor selection cannot be changed.
1748 }
1749 
~wxCursorProperty()1750 wxCursorProperty::~wxCursorProperty()
1751 {
1752 }
1753 
OnMeasureImage(int item) const1754 wxSize wxCursorProperty::OnMeasureImage( int item ) const
1755 {
1756 #if wxPG_CAN_DRAW_CURSOR
1757     if ( item != -1 && item < NUM_CURSORS )
1758         return wxSize(wxPG_CURSOR_IMAGE_WIDTH,wxPG_CURSOR_IMAGE_WIDTH);
1759 #else
1760     wxUnusedVar(item);
1761 #endif
1762     return wxSize(0,0);
1763 }
1764 
1765 #if wxPG_CAN_DRAW_CURSOR
1766 
OnCustomPaint(wxDC & dc,const wxRect & rect,wxPGPaintData & paintdata)1767 void wxCursorProperty::OnCustomPaint( wxDC& dc,
1768                                       const wxRect& rect,
1769                                       wxPGPaintData& paintdata )
1770 {
1771     // Background brush
1772     dc.SetBrush( wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ) );
1773 
1774     if ( paintdata.m_choiceItem >= 0 )
1775     {
1776         dc.DrawRectangle( rect );
1777 
1778         if ( paintdata.m_choiceItem < NUM_CURSORS )
1779         {
1780             wxStockCursor cursorIndex =
1781                 (wxStockCursor) gs_cp_es_syscursors_values[paintdata.m_choiceItem];
1782 
1783             {
1784                 if ( cursorIndex == wxCURSOR_NONE )
1785                     cursorIndex = wxCURSOR_ARROW;
1786 
1787                 wxCursor cursor( cursorIndex );
1788 
1789             #ifdef __WXMSW__
1790                 HDC hDc = (HDC)((const wxMSWDCImpl *)dc.GetImpl())->GetHDC();
1791                 ::DrawIconEx( hDc,
1792                               rect.x,
1793                               rect.y,
1794                               (HICON)cursor.GetHandle(),
1795                               0,
1796                               0,
1797                               0,
1798                               NULL,
1799             #if !defined(__WXWINCE__)
1800                               DI_COMPAT | DI_DEFAULTSIZE |
1801             #endif
1802                               DI_NORMAL
1803                             );
1804             #endif
1805             }
1806         }
1807     }
1808 }
1809 
1810 #else
OnCustomPaint(wxDC &,const wxRect &,wxPGPaintData &)1811 void wxCursorProperty::OnCustomPaint( wxDC&, const wxRect&, wxPGPaintData& ) { }
1812 /*wxPGCellRenderer* wxCursorProperty::GetCellRenderer( int column ) const
1813 {
1814     return wxEnumProperty::GetCellRenderer(column);
1815 }*/
1816 #endif
1817 
1818 // -----------------------------------------------------------------------
1819 // wxImageFileProperty
1820 // -----------------------------------------------------------------------
1821 
1822 #if wxUSE_IMAGE
1823 
wxPGGetDefaultImageWildcard()1824 const wxString& wxPGGetDefaultImageWildcard()
1825 {
1826     // Form the wildcard, if not done yet
1827     if ( wxPGGlobalVars->m_pDefaultImageWildcard.empty() )
1828     {
1829 
1830         wxString str;
1831 
1832         // TODO: This section may require locking (using global).
1833 
1834         wxList& handlers = wxImage::GetHandlers();
1835 
1836         wxList::iterator node;
1837 
1838         // Let's iterate over the image handler list.
1839         //for ( wxList::Node *node = handlers.GetFirst(); node; node = node->GetNext() )
1840         for ( node = handlers.begin(); node != handlers.end(); ++node )
1841         {
1842             wxImageHandler *handler = (wxImageHandler*)*node;
1843 
1844             wxString ext_lo = handler->GetExtension();
1845             wxString ext_up = ext_lo.Upper();
1846 
1847             str.append( ext_up );
1848             str.append( wxT(" files (*.") );
1849             str.append( ext_up );
1850             str.append( wxT(")|*.") );
1851             str.append( ext_lo );
1852             str.append( wxT("|") );
1853         }
1854 
1855         str.append ( wxT("All files (*.*)|*.*") );
1856 
1857         wxPGGlobalVars->m_pDefaultImageWildcard = str;
1858     }
1859 
1860     return wxPGGlobalVars->m_pDefaultImageWildcard;
1861 }
1862 
IMPLEMENT_DYNAMIC_CLASS(wxImageFileProperty,wxFileProperty)1863 IMPLEMENT_DYNAMIC_CLASS(wxImageFileProperty, wxFileProperty)
1864 
1865 wxImageFileProperty::wxImageFileProperty( const wxString& label, const wxString& name,
1866     const wxString& value )
1867     : wxFileProperty(label,name,value)
1868 {
1869     SetAttribute( wxPG_FILE_WILDCARD, wxPGGetDefaultImageWildcard() );
1870 
1871     m_pImage = NULL;
1872     m_pBitmap = NULL;
1873 
1874     LoadImageFromFile();
1875 }
1876 
~wxImageFileProperty()1877 wxImageFileProperty::~wxImageFileProperty()
1878 {
1879     if ( m_pBitmap )
1880         delete m_pBitmap;
1881     if ( m_pImage )
1882         delete m_pImage;
1883 }
1884 
OnSetValue()1885 void wxImageFileProperty::OnSetValue()
1886 {
1887     wxFileProperty::OnSetValue();
1888 
1889     // Delete old image
1890     wxDELETE(m_pImage);
1891     wxDELETE(m_pBitmap);
1892 
1893     LoadImageFromFile();
1894 }
1895 
LoadImageFromFile()1896 void wxImageFileProperty::LoadImageFromFile()
1897 {
1898     wxFileName filename = GetFileName();
1899 
1900     // Create the image thumbnail
1901     if ( filename.FileExists() )
1902     {
1903         m_pImage = new wxImage( filename.GetFullPath() );
1904     }
1905 }
1906 
OnMeasureImage(int) const1907 wxSize wxImageFileProperty::OnMeasureImage( int ) const
1908 {
1909     return wxPG_DEFAULT_IMAGE_SIZE;
1910 }
1911 
OnCustomPaint(wxDC & dc,const wxRect & rect,wxPGPaintData &)1912 void wxImageFileProperty::OnCustomPaint( wxDC& dc,
1913                                          const wxRect& rect,
1914                                          wxPGPaintData& )
1915 {
1916     if ( m_pBitmap || (m_pImage && m_pImage->IsOk() ) )
1917     {
1918         // Draw the thumbnail
1919 
1920         // Create the bitmap here because required size is not known in OnSetValue().
1921         if ( !m_pBitmap )
1922         {
1923             m_pImage->Rescale( rect.width, rect.height );
1924             m_pBitmap = new wxBitmap( *m_pImage );
1925             wxDELETE(m_pImage);
1926         }
1927 
1928         dc.DrawBitmap( *m_pBitmap, rect.x, rect.y, false );
1929     }
1930     else
1931     {
1932         // No file - just draw a white box
1933         dc.SetBrush( *wxWHITE_BRUSH );
1934         dc.DrawRectangle ( rect );
1935     }
1936 }
1937 
1938 #endif // wxUSE_IMAGE
1939 
1940 // -----------------------------------------------------------------------
1941 // wxMultiChoiceProperty
1942 // -----------------------------------------------------------------------
1943 
1944 #if wxUSE_CHOICEDLG
1945 
1946 #include "wx/choicdlg.h"
1947 
WX_PG_IMPLEMENT_PROPERTY_CLASS(wxMultiChoiceProperty,wxPGProperty,wxArrayInt,const wxArrayInt &,TextCtrlAndButton)1948 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxMultiChoiceProperty,wxPGProperty,
1949                                wxArrayInt,const wxArrayInt&,TextCtrlAndButton)
1950 
1951 wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label,
1952                                               const wxString& name,
1953                                               const wxPGChoices& choices,
1954                                               const wxArrayString& value)
1955                                                 : wxPGProperty(label,name)
1956 {
1957     m_choices.Assign(choices);
1958     SetValue(value);
1959 }
1960 
wxMultiChoiceProperty(const wxString & label,const wxString & name,const wxArrayString & strings,const wxArrayString & value)1961 wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label,
1962                                               const wxString& name,
1963                                               const wxArrayString& strings,
1964                                               const wxArrayString& value)
1965                                                 : wxPGProperty(label,name)
1966 {
1967     m_choices.Set(strings);
1968     SetValue(value);
1969 }
1970 
wxMultiChoiceProperty(const wxString & label,const wxString & name,const wxArrayString & value)1971 wxMultiChoiceProperty::wxMultiChoiceProperty( const wxString& label,
1972                                               const wxString& name,
1973                                               const wxArrayString& value)
1974                                                 : wxPGProperty(label,name)
1975 {
1976     wxArrayString strings;
1977     m_choices.Set(strings);
1978     SetValue(value);
1979 }
1980 
~wxMultiChoiceProperty()1981 wxMultiChoiceProperty::~wxMultiChoiceProperty()
1982 {
1983 }
1984 
OnSetValue()1985 void wxMultiChoiceProperty::OnSetValue()
1986 {
1987     GenerateValueAsString(m_value, &m_display);
1988 }
1989 
ValueToString(wxVariant & value,int argFlags) const1990 wxString wxMultiChoiceProperty::ValueToString( wxVariant& value,
1991                                                int argFlags ) const
1992 {
1993     // If possible, use cached string
1994     if ( argFlags & wxPG_VALUE_IS_CURRENT )
1995         return m_display;
1996 
1997     wxString s;
1998     GenerateValueAsString(value, &s);
1999     return s;
2000 }
2001 
GenerateValueAsString(wxVariant & value,wxString * target) const2002 void wxMultiChoiceProperty::GenerateValueAsString( wxVariant& value,
2003                                                    wxString* target ) const
2004 {
2005     wxArrayString strings;
2006 
2007     if ( value.GetType() == wxPG_VARIANT_TYPE_ARRSTRING )
2008         strings = value.GetArrayString();
2009 
2010     wxString& tempStr = *target;
2011     unsigned int i;
2012     unsigned int itemCount = strings.size();
2013 
2014     tempStr.Empty();
2015 
2016     if ( itemCount )
2017         tempStr.append( wxT("\"") );
2018 
2019     for ( i = 0; i < itemCount; i++ )
2020     {
2021         tempStr.append( strings[i] );
2022         tempStr.append( wxT("\"") );
2023         if ( i < (itemCount-1) )
2024             tempStr.append ( wxT(" \"") );
2025     }
2026 }
2027 
GetValueAsIndices() const2028 wxArrayInt wxMultiChoiceProperty::GetValueAsIndices() const
2029 {
2030     wxVariant variant = GetValue();
2031     const wxArrayInt& valueArr = wxArrayIntRefFromVariant(variant);
2032     unsigned int i;
2033 
2034     // Translate values to string indices.
2035     wxArrayInt selections;
2036 
2037     if ( !m_choices.IsOk() || !m_choices.GetCount() || !(&valueArr) )
2038     {
2039         for ( i=0; i<valueArr.size(); i++ )
2040             selections.Add(-1);
2041     }
2042     else
2043     {
2044         for ( i=0; i<valueArr.size(); i++ )
2045         {
2046             int sIndex = m_choices.Index(valueArr[i]);
2047             if ( sIndex >= 0 )
2048                 selections.Add(sIndex);
2049         }
2050     }
2051 
2052     return selections;
2053 }
2054 
OnEvent(wxPropertyGrid * propgrid,wxWindow * WXUNUSED (primary),wxEvent & event)2055 bool wxMultiChoiceProperty::OnEvent( wxPropertyGrid* propgrid,
2056                                      wxWindow* WXUNUSED(primary),
2057                                      wxEvent& event )
2058 {
2059     if ( propgrid->IsMainButtonEvent(event) )
2060     {
2061         // Update the value
2062         wxVariant useValue = propgrid->GetUncommittedPropertyValue();
2063 
2064         wxArrayString labels = m_choices.GetLabels();
2065         unsigned int choiceCount;
2066 
2067         if ( m_choices.IsOk() )
2068             choiceCount = m_choices.GetCount();
2069         else
2070             choiceCount = 0;
2071 
2072         // launch editor dialog
2073         wxMultiChoiceDialog dlg( propgrid,
2074                                  _("Make a selection:"),
2075                                  m_label,
2076                                  choiceCount,
2077                                  choiceCount?&labels[0]:NULL,
2078                                  wxCHOICEDLG_STYLE );
2079 
2080         dlg.Move( propgrid->GetGoodEditorDialogPosition(this,dlg.GetSize()) );
2081 
2082         wxArrayString strings = useValue.GetArrayString();
2083         wxArrayString extraStrings;
2084 
2085         dlg.SetSelections(m_choices.GetIndicesForStrings(strings, &extraStrings));
2086 
2087         if ( dlg.ShowModal() == wxID_OK && choiceCount )
2088         {
2089             int userStringMode = GetAttributeAsLong(wxT("UserStringMode"), 0);
2090 
2091             wxArrayInt arrInt = dlg.GetSelections();
2092 
2093             wxVariant variant;
2094 
2095             // Strings that were not in list of choices
2096             wxArrayString value;
2097 
2098             // Translate string indices to strings
2099 
2100             unsigned int n;
2101             if ( userStringMode == 1 )
2102             {
2103                 for (n=0;n<extraStrings.size();n++)
2104                     value.push_back(extraStrings[n]);
2105             }
2106 
2107             unsigned int i;
2108             for ( i=0; i<arrInt.size(); i++ )
2109                 value.Add(m_choices.GetLabel(arrInt.Item(i)));
2110 
2111             if ( userStringMode == 2 )
2112             {
2113                 for (n=0;n<extraStrings.size();n++)
2114                     value.push_back(extraStrings[n]);
2115             }
2116 
2117             variant = WXVARIANT(value);
2118 
2119             SetValueInEvent(variant);
2120 
2121             return true;
2122         }
2123     }
2124     return false;
2125 }
2126 
StringToValue(wxVariant & variant,const wxString & text,int) const2127 bool wxMultiChoiceProperty::StringToValue( wxVariant& variant, const wxString& text, int ) const
2128 {
2129     wxArrayString arr;
2130 
2131     int userStringMode = GetAttributeAsLong(wxT("UserStringMode"), 0);
2132 
2133     WX_PG_TOKENIZER2_BEGIN(text,wxT('"'))
2134         if ( userStringMode > 0 || (m_choices.IsOk() && m_choices.Index( token ) != wxNOT_FOUND) )
2135             arr.Add(token);
2136     WX_PG_TOKENIZER2_END()
2137 
2138     wxVariant v( WXVARIANT(arr) );
2139     variant = v;
2140 
2141     return true;
2142 }
2143 
2144 #endif // wxUSE_CHOICEDLG
2145 
2146 
2147 // -----------------------------------------------------------------------
2148 // wxDateProperty
2149 // -----------------------------------------------------------------------
2150 
2151 #if wxUSE_DATETIME
2152 
2153 
2154 #if wxUSE_DATEPICKCTRL
2155     #define dtCtrl      DatePickerCtrl
2156 #else
2157     #define dtCtrl      TextCtrl
2158 #endif
2159 
2160 WX_PG_IMPLEMENT_PROPERTY_CLASS(wxDateProperty,
2161                                wxPGProperty,
2162                                wxDateTime,
2163                                const wxDateTime&,
2164                                dtCtrl)
2165 
2166 
2167 wxString wxDateProperty::ms_defaultDateFormat;
2168 
2169 
wxDateProperty(const wxString & label,const wxString & name,const wxDateTime & value)2170 wxDateProperty::wxDateProperty( const wxString& label,
2171                                 const wxString& name,
2172                                 const wxDateTime& value )
2173     : wxPGProperty(label,name)
2174 {
2175     //wxPGRegisterDefaultValueType(wxDateTime)
2176 
2177 #if wxUSE_DATEPICKCTRL
2178     wxPGRegisterEditorClass(DatePickerCtrl);
2179 
2180     m_dpStyle = wxDP_DEFAULT | wxDP_SHOWCENTURY;
2181 #else
2182     m_dpStyle = 0;
2183 #endif
2184 
2185     SetValue( value );
2186 }
2187 
~wxDateProperty()2188 wxDateProperty::~wxDateProperty()
2189 {
2190 }
2191 
OnSetValue()2192 void wxDateProperty::OnSetValue()
2193 {
2194     //
2195     // Convert invalid dates to unspecified value
2196     if ( m_value.GetType() == wxT("datetime") )
2197     {
2198         if ( !m_value.GetDateTime().IsValid() )
2199             m_value.MakeNull();
2200     }
2201 }
2202 
StringToValue(wxVariant & variant,const wxString & text,int WXUNUSED (argFlags)) const2203 bool wxDateProperty::StringToValue( wxVariant& variant, const wxString& text,
2204                                     int WXUNUSED(argFlags) ) const
2205 {
2206     wxDateTime dt;
2207 
2208     // FIXME: do we really want to return true from here if only part of the
2209     //        string was parsed?
2210     const char* c = dt.ParseFormat(text);
2211 
2212     if ( c )
2213     {
2214         variant = dt;
2215         return true;
2216     }
2217 
2218     return false;
2219 }
2220 
ValueToString(wxVariant & value,int argFlags) const2221 wxString wxDateProperty::ValueToString( wxVariant& value,
2222                                         int argFlags ) const
2223 {
2224     const wxChar* format = (const wxChar*) NULL;
2225 
2226     wxDateTime dateTime = value.GetDateTime();
2227 
2228     if ( !dateTime.IsValid() )
2229         return wxT("Invalid");
2230 
2231     if ( ms_defaultDateFormat.empty() )
2232     {
2233 #if wxUSE_DATEPICKCTRL
2234         bool showCentury = m_dpStyle & wxDP_SHOWCENTURY ? true : false;
2235 #else
2236         bool showCentury = true;
2237 #endif
2238         ms_defaultDateFormat = DetermineDefaultDateFormat( showCentury );
2239     }
2240 
2241     if ( !m_format.empty() &&
2242          !(argFlags & wxPG_FULL_VALUE) )
2243             format = m_format.c_str();
2244 
2245     // Determine default from locale
2246     // NB: This is really simple stuff, but can't figure anything
2247     //     better without proper support in wxLocale
2248     if ( !format )
2249         format = ms_defaultDateFormat.c_str();
2250 
2251     return dateTime.Format(format);
2252 }
2253 
DetermineDefaultDateFormat(bool showCentury)2254 wxString wxDateProperty::DetermineDefaultDateFormat( bool showCentury )
2255 {
2256     // This code is basically copied from datectlg.cpp's SetFormat
2257     //
2258     wxString format;
2259 
2260     wxDateTime dt;
2261     dt.ParseFormat(wxT("2003-10-13"), wxT("%Y-%m-%d"));
2262     wxString str(dt.Format(wxT("%x")));
2263 
2264     const wxChar *p = str.c_str();
2265     while ( *p )
2266     {
2267         int n=wxAtoi(p);
2268         if (n == dt.GetDay())
2269         {
2270             format.Append(wxT("%d"));
2271             p += 2;
2272         }
2273         else if (n == (int)dt.GetMonth()+1)
2274         {
2275             format.Append(wxT("%m"));
2276             p += 2;
2277         }
2278         else if (n == dt.GetYear())
2279         {
2280             format.Append(wxT("%Y"));
2281             p += 4;
2282         }
2283         else if (n == (dt.GetYear() % 100))
2284         {
2285             if (showCentury)
2286                 format.Append(wxT("%Y"));
2287             else
2288                 format.Append(wxT("%y"));
2289             p += 2;
2290         }
2291         else
2292             format.Append(*p++);
2293     }
2294 
2295     return format;
2296 }
2297 
DoSetAttribute(const wxString & name,wxVariant & value)2298 bool wxDateProperty::DoSetAttribute( const wxString& name, wxVariant& value )
2299 {
2300     if ( name == wxPG_DATE_FORMAT )
2301     {
2302         m_format = value.GetString();
2303         return true;
2304     }
2305     else if ( name == wxPG_DATE_PICKER_STYLE )
2306     {
2307         m_dpStyle = value.GetLong();
2308         ms_defaultDateFormat.clear();  // This may need recalculation
2309         return true;
2310     }
2311     return false;
2312 }
2313 
2314 #endif  // wxUSE_DATETIME
2315 
2316 
2317 // -----------------------------------------------------------------------
2318 // wxPropertyGridInterface
2319 // -----------------------------------------------------------------------
2320 
InitAllTypeHandlers()2321 void wxPropertyGridInterface::InitAllTypeHandlers()
2322 {
2323 }
2324 
2325 // -----------------------------------------------------------------------
2326 
RegisterAdditionalEditors()2327 void wxPropertyGridInterface::RegisterAdditionalEditors()
2328 {
2329     // Register editor classes, if necessary.
2330     if ( wxPGGlobalVars->m_mapEditorClasses.empty() )
2331         wxPropertyGrid::RegisterDefaultEditors();
2332 
2333 #if wxUSE_SPINBTN
2334     wxPGRegisterEditorClass(SpinCtrl);
2335 #endif
2336 #if wxUSE_DATEPICKCTRL
2337     wxPGRegisterEditorClass(DatePickerCtrl);
2338 #endif
2339 }
2340 
2341 // -----------------------------------------------------------------------
2342 
2343 #endif  // wxPG_INCLUDE_ADVPROPS
2344 
2345 #endif  // wxUSE_PROPGRID
2346 
2347