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