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