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