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