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