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