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