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