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