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