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