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