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