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