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