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