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