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