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