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