1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/editors.cpp
3 // Purpose: wxPropertyGrid editors
4 // Author: Jaakko Salli
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
23 #include "wx/object.h"
25 #include "wx/string.h"
28 #include "wx/window.h"
31 #include "wx/dcclient.h"
32 #include "wx/dcmemory.h"
33 #include "wx/button.h"
36 #include "wx/cursor.h"
37 #include "wx/dialog.h"
38 #include "wx/settings.h"
39 #include "wx/msgdlg.h"
40 #include "wx/choice.h"
41 #include "wx/stattext.h"
42 #include "wx/scrolwin.h"
43 #include "wx/dirdlg.h"
45 #include "wx/textdlg.h"
46 #include "wx/filedlg.h"
47 #include "wx/statusbr.h"
54 #include "wx/dcbuffer.h"
55 #include "wx/bmpbuttn.h"
58 // This define is necessary to prevent macro clearing
59 #define __wxPG_SOURCE_FILE__
61 #include "wx/propgrid/propgrid.h"
62 #include "wx/propgrid/editors.h"
63 #include "wx/propgrid/props.h"
65 #if wxPG_USE_RENDERER_NATIVE
66 #include "wx/renderer.h"
69 // How many pixels between textctrl and button
71 #define wxPG_TEXTCTRL_AND_BUTTON_SPACING 4
73 #define wxPG_TEXTCTRL_AND_BUTTON_SPACING 2
76 #define wxPG_BUTTON_SIZEDEC 0
78 #include "wx/odcombo.h"
80 // -----------------------------------------------------------------------
82 #if defined(__WXMSW__)
84 #define wxPG_NAT_BUTTON_BORDER_ANY 1
85 #define wxPG_NAT_BUTTON_BORDER_X 1
86 #define wxPG_NAT_BUTTON_BORDER_Y 1
88 #define wxPG_CHECKMARK_XADJ 1
89 #define wxPG_CHECKMARK_YADJ (-1)
90 #define wxPG_CHECKMARK_WADJ 0
91 #define wxPG_CHECKMARK_HADJ 0
92 #define wxPG_CHECKMARK_DEFLATE 0
94 #define wxPG_TEXTCTRLYADJUST (m_spacingy+0)
96 #elif defined(__WXGTK__)
98 #define wxPG_CHECKMARK_XADJ 0
99 #define wxPG_CHECKMARK_YADJ 0
100 #define wxPG_CHECKMARK_WADJ (-1)
101 #define wxPG_CHECKMARK_HADJ (-1)
102 #define wxPG_CHECKMARK_DEFLATE 3
104 #define wxPG_NAT_BUTTON_BORDER_ANY 1
105 #define wxPG_NAT_BUTTON_BORDER_X 1
106 #define wxPG_NAT_BUTTON_BORDER_Y 1
108 #define wxPG_TEXTCTRLYADJUST 0
110 #elif defined(__WXMAC__)
112 #define wxPG_CHECKMARK_XADJ 0
113 #define wxPG_CHECKMARK_YADJ 0
114 #define wxPG_CHECKMARK_WADJ 0
115 #define wxPG_CHECKMARK_HADJ 0
116 #define wxPG_CHECKMARK_DEFLATE 0
118 #define wxPG_NAT_BUTTON_BORDER_ANY 0
119 #define wxPG_NAT_BUTTON_BORDER_X 0
120 #define wxPG_NAT_BUTTON_BORDER_Y 0
122 #define wxPG_TEXTCTRLYADJUST 0
126 #define wxPG_CHECKMARK_XADJ 0
127 #define wxPG_CHECKMARK_YADJ 0
128 #define wxPG_CHECKMARK_WADJ 0
129 #define wxPG_CHECKMARK_HADJ 0
130 #define wxPG_CHECKMARK_DEFLATE 0
132 #define wxPG_NAT_BUTTON_BORDER_ANY 0
133 #define wxPG_NAT_BUTTON_BORDER_X 0
134 #define wxPG_NAT_BUTTON_BORDER_Y 0
136 #define wxPG_TEXTCTRLYADJUST 0
142 #define wxPG_CHOICEXADJUST -3 // required because wxComboCtrl reserves 3pixels for wxTextCtrl's focus ring
143 #define wxPG_CHOICEYADJUST -3
145 #define wxPG_CHOICEXADJUST 0
146 #define wxPG_CHOICEYADJUST 0
149 // Number added to image width for SetCustomPaintWidth
150 #define ODCB_CUST_PAINT_MARGIN 6
152 // Milliseconds to wait for two mouse-ups after focus inorder
153 // to trigger a double-click.
154 #define DOUBLE_CLICK_CONVERSION_TRESHOLD 500
156 // -----------------------------------------------------------------------
158 // -----------------------------------------------------------------------
160 IMPLEMENT_ABSTRACT_CLASS(wxPGEditor
, wxObject
)
163 wxPGEditor
::~wxPGEditor()
167 wxString wxPGEditor
::GetName() const
169 return GetClassInfo()->GetClassName();
172 void wxPGEditor
::DrawValue( wxDC
& dc
, const wxRect
& rect
, wxPGProperty
* property
, const wxString
& text
) const
174 if ( !property
->IsValueUnspecified() )
175 dc
.DrawText( text
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
178 bool wxPGEditor
::GetValueFromControl( wxVariant
&, wxPGProperty
*, wxWindow
* ) const
183 void wxPGEditor
::SetControlStringValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, const wxString
& ) const
188 void wxPGEditor
::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, int ) const
193 int wxPGEditor
::InsertItem( wxWindow
*, const wxString
&, int ) const
199 void wxPGEditor
::DeleteItem( wxWindow
*, int ) const
205 void wxPGEditor
::OnFocus( wxPGProperty
*, wxWindow
* ) const
210 bool wxPGEditor
::CanContainCustomImage() const
215 // -----------------------------------------------------------------------
216 // wxPGTextCtrlEditor
217 // -----------------------------------------------------------------------
219 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrl
,wxPGTextCtrlEditor
,wxPGEditor
)
222 wxPGWindowList wxPGTextCtrlEditor
::CreateControls( wxPropertyGrid
* propGrid
,
223 wxPGProperty
* property
,
225 const wxSize
& sz
) const
230 // If has children, and limited editing is specified, then don't create.
231 if ( (property
->GetFlags() & wxPG_PROP_NOEDITOR
) &&
232 property
->GetChildCount() )
235 if ( !property
->IsValueUnspecified() )
236 text
= property
->GetValueAsString(property
->HasFlag(wxPG_PROP_READONLY
) ?
237 0 : wxPG_EDITABLE_VALUE
);
240 if ( (property
->GetFlags() & wxPG_PROP_PASSWORD
) &&
241 property
->IsKindOf(CLASSINFO(wxStringProperty
)) )
242 flags
|= wxTE_PASSWORD
;
244 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrl(pos
,sz
,text
,NULL
,flags
,
245 property
->GetMaxLength());
251 void wxPGTextCtrlEditor
::DrawValue( wxDC
& dc
, wxPGProperty
* property
, const wxRect
& rect
) const
253 if ( !property
->IsValueUnspecified() )
255 wxString drawStr
= property
->GetDisplayedString();
257 // Code below should no longer be needed, as the obfuscation
258 // is now done in GetValueAsString.
259 /*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
260 property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
262 size_t a = drawStr.length();
264 drawStr.Append(wxS('*'),a);
266 dc
.DrawText( drawStr
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
271 void wxPGTextCtrlEditor
::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
273 wxTextCtrl
* tc
= wxDynamicCast(ctrl
, wxTextCtrl
);
278 if ( tc
->HasFlag(wxTE_PASSWORD
) )
279 s
= property
->GetValueAsString(wxPG_FULL_VALUE
);
281 s
= property
->GetDisplayedString();
283 wxPropertyGrid
* pg
= property
->GetGrid();
285 pg
->SetupTextCtrlValue(s
);
289 // Fix indentation, just in case (change in font boldness is one good
294 // Provided so that, for example, ComboBox editor can use the same code
295 // (multiple inheritance would get way too messy).
296 bool wxPGTextCtrlEditor
::OnTextCtrlEvent( wxPropertyGrid
* propGrid
,
297 wxPGProperty
* WXUNUSED(property
),
304 if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER
)
306 if ( propGrid
->IsEditorsValueModified() )
311 else if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED
)
314 // Pass this event outside wxPropertyGrid so that,
315 // if necessary, program can tell when user is editing
317 // FIXME: Is it safe to change event id in the middle of event
318 // processing (seems to work, but...)?
320 event
.SetId(propGrid
->GetId());
322 propGrid
->EditorsValueWasModified();
328 bool wxPGTextCtrlEditor
::OnEvent( wxPropertyGrid
* propGrid
,
329 wxPGProperty
* property
,
331 wxEvent
& event
) const
333 return wxPGTextCtrlEditor
::OnTextCtrlEvent(propGrid
,property
,ctrl
,event
);
337 bool wxPGTextCtrlEditor
::GetTextCtrlValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
)
339 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
340 wxString textVal
= tc
->GetValue();
342 if ( property
->UsesAutoUnspecified() && !textVal
.length() )
348 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
350 // Changing unspecified always causes event (returning
351 // true here should be enough to trigger it).
352 // TODO: Move to propgrid.cpp
353 if ( !res
&& variant
.IsNull() )
360 bool wxPGTextCtrlEditor
::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
362 return wxPGTextCtrlEditor
::GetTextCtrlValueFromControl(variant
, property
, ctrl
);
366 void wxPGTextCtrlEditor
::SetValueToUnspecified( wxPGProperty
* property
, wxWindow
* ctrl
) const
368 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
370 wxPropertyGrid
* pg
= property
->GetGrid();
371 wxASSERT(pg
); // Really, property grid should exist if editor does
374 wxString unspecValueText
;
375 pg
->SetupTextCtrlValue(unspecValueText
);
376 tc
->SetValue(unspecValueText
);
381 void wxPGTextCtrlEditor
::SetControlStringValue( wxPGProperty
* property
, wxWindow
* ctrl
, const wxString
& txt
) const
383 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
385 wxPropertyGrid
* pg
= property
->GetGrid();
386 wxASSERT(pg
); // Really, property grid should exist if editor does
389 pg
->SetupTextCtrlValue(txt
);
395 void wxPGTextCtrlEditor
::OnFocus( wxPGProperty
*, wxWindow
* wnd
) const
397 wxTextCtrl
* tc
= wxStaticCast(wnd
, wxTextCtrl
);
399 tc
->SetSelection(-1,-1);
403 wxPGTextCtrlEditor
::~wxPGTextCtrlEditor() { }
406 // -----------------------------------------------------------------------
408 // -----------------------------------------------------------------------
411 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(Choice
,wxPGChoiceEditor
,wxPGEditor
)
414 // This is a special enhanced double-click processor class.
415 // In essence, it allows for double-clicks for which the
416 // first click "created" the control.
417 class wxPGDoubleClickProcessor
: public wxEvtHandler
421 wxPGDoubleClickProcessor( wxOwnerDrawnComboBox
* combo
, wxPGProperty
* property
)
424 m_timeLastMouseUp
= 0;
426 m_property
= property
;
427 m_downReceived
= false;
432 void OnMouseEvent( wxMouseEvent
& event
)
434 wxLongLong t
= ::wxGetLocalTimeMillis();
435 int evtType
= event
.GetEventType();
437 if ( m_property
->HasFlag(wxPG_PROP_USE_DCC
) &&
438 m_property
->IsKindOf(CLASSINFO(wxBoolProperty
)) &&
439 !m_combo
->IsPopupShown() )
441 // Just check that it is in the text area
442 wxPoint pt
= event
.GetPosition();
443 if ( m_combo
->GetTextRect().Contains(pt
) )
445 if ( evtType
== wxEVT_LEFT_DOWN
)
447 // Set value to avoid up-events without corresponding downs
448 m_downReceived
= true;
450 else if ( evtType
== wxEVT_LEFT_DCLICK
)
452 // We'll make our own double-clicks
453 event
.SetEventType(0);
456 else if ( evtType
== wxEVT_LEFT_UP
)
458 if ( m_downReceived
|| m_timeLastMouseUp
== 1 )
460 wxLongLong timeFromLastUp
= (t
-m_timeLastMouseUp
);
462 if ( timeFromLastUp
< DOUBLE_CLICK_CONVERSION_TRESHOLD
)
464 event
.SetEventType(wxEVT_LEFT_DCLICK
);
465 m_timeLastMouseUp
= 1;
469 m_timeLastMouseUp
= t
;
479 void OnSetFocus( wxFocusEvent
& event
)
481 m_timeLastMouseUp
= ::wxGetLocalTimeMillis();
486 wxLongLong m_timeLastMouseUp
;
487 wxOwnerDrawnComboBox
* m_combo
;
488 wxPGProperty
* m_property
; // Selected property
491 DECLARE_EVENT_TABLE()
494 BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor
, wxEvtHandler
)
495 EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor
::OnMouseEvent
)
496 EVT_SET_FOCUS(wxPGDoubleClickProcessor
::OnSetFocus
)
501 class wxPGComboBox
: public wxOwnerDrawnComboBox
506 : wxOwnerDrawnComboBox()
508 m_dclickProcessor
= NULL
;
509 m_sizeEventCalled
= false;
514 if ( m_dclickProcessor
)
516 RemoveEventHandler(m_dclickProcessor
);
517 delete m_dclickProcessor
;
521 bool Create(wxWindow
*parent
,
523 const wxString
& value
,
526 const wxArrayString
& choices
,
528 const wxValidator
& validator
= wxDefaultValidator
,
529 const wxString
& name
= wxS("wxOwnerDrawnComboBox"))
531 if ( !wxOwnerDrawnComboBox
::Create( parent
,
542 m_dclickProcessor
= new
543 wxPGDoubleClickProcessor( this, GetGrid()->GetSelection() );
545 PushEventHandler(m_dclickProcessor
);
550 virtual void OnDrawItem( wxDC
& dc
,
555 wxPropertyGrid
* pg
= GetGrid();
556 pg
->OnComboItemPaint( this, item
, &dc
, (wxRect
&)rect
, flags
);
559 virtual wxCoord
OnMeasureItem( size_t item
) const
561 wxPropertyGrid
* pg
= GetGrid();
565 pg
->OnComboItemPaint( this, item
, NULL
, rect
, 0 );
569 wxPropertyGrid
* GetGrid() const
571 wxPropertyGrid
* pg
= wxDynamicCast(GetParent(),
577 virtual wxCoord
OnMeasureItemWidth( size_t item
) const
579 wxPropertyGrid
* pg
= GetGrid();
583 pg
->OnComboItemPaint( this, item
, NULL
, rect
, 0 );
587 virtual void PositionTextCtrl( int textCtrlXAdjust
,
588 int WXUNUSED(textCtrlYAdjust
) )
590 wxPropertyGrid
* pg
= GetGrid();
591 #ifdef wxPG_TEXTCTRLXADJUST
592 textCtrlXAdjust
= wxPG_TEXTCTRLXADJUST
-
593 (wxPG_XBEFOREWIDGET
+wxPG_CONTROL_MARGIN
+1) - 1,
595 wxOwnerDrawnComboBox
::PositionTextCtrl(
597 pg
->GetSpacingY() + 2
602 wxPGDoubleClickProcessor
* m_dclickProcessor
;
603 bool m_sizeEventCalled
;
607 void wxPropertyGrid
::OnComboItemPaint( const wxPGComboBox
* pCb
,
614 wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid
)) );
616 wxPGProperty
* p
= GetSelection();
619 const wxPGChoices
& choices
= p
->GetChoices();
620 const wxPGCommonValue
* comVal
= NULL
;
621 int comVals
= p
->GetDisplayedCommonValueCount();
622 int comValIndex
= -1;
625 if ( choices
.IsOk() )
626 choiceCount
= choices
.GetCount();
628 if ( item
>= choiceCount
&& comVals
> 0 )
630 comValIndex
= item
- choiceCount
;
631 comVal
= GetCommonValue(comValIndex
);
632 if ( !p
->IsValueUnspecified() )
633 text
= comVal
->GetLabel();
637 if ( !(flags
& wxODCB_PAINTING_CONTROL
) )
639 text
= pCb
->GetString(item
);
643 if ( !p
->IsValueUnspecified() )
644 text
= p
->GetValueAsString(0);
653 const wxBitmap
* itemBitmap
= NULL
;
655 if ( item
>= 0 && choices
.IsOk() && choices
.Item(item
).GetBitmap().Ok() && comValIndex
== -1 )
656 itemBitmap
= &choices
.Item(item
).GetBitmap();
659 // Decide what custom image size to use
662 cis
.x
= itemBitmap
->GetWidth();
663 cis
.y
= itemBitmap
->GetHeight();
667 cis
= GetImageSize(p
, item
);
672 // Default measure behaviour (no flexible, custom paint image only)
673 if ( rect
.width
< 0 )
676 pCb
->GetTextExtent(text
, &x
, &y
, 0, 0);
677 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9 + x
;
680 rect
.height
= cis
.y
+ 2;
684 wxPGPaintData paintdata
;
685 paintdata
.m_parent
= NULL
;
686 paintdata
.m_choiceItem
= item
;
688 // This is by the current (1.0.0b) spec - if painting control, item is -1
689 if ( (flags
& wxODCB_PAINTING_CONTROL
) )
690 paintdata
.m_choiceItem
= -1;
693 pDc
->SetBrush(*wxWHITE_BRUSH
);
695 wxPGCellRenderer
* renderer
= NULL
;
696 const wxPGChoiceEntry
* cell
= NULL
;
704 wxPoint
pt(rect
.x
+ wxPG_CONTROL_MARGIN
- wxPG_CHOICEXADJUST
- 1,
707 int renderFlags
= wxPGCellRenderer
::DontUseCellColours
;
709 if ( flags
& wxODCB_PAINTING_CONTROL
)
710 renderFlags
|= wxPGCellRenderer
::Control
;
712 renderFlags
|= wxPGCellRenderer
::ChoicePopup
;
714 if ( flags
& wxODCB_PAINTING_SELECTED
)
715 renderFlags
|= wxPGCellRenderer
::Selected
;
717 if ( cis
.x
> 0 && (p
->HasFlag(wxPG_PROP_CUSTOMIMAGE
) || !(flags
& wxODCB_PAINTING_CONTROL
)) &&
718 ( !p
->m_valueBitmap
|| item
== pCb
->GetSelection() ) &&
719 ( item
>= 0 || (flags
& wxODCB_PAINTING_CONTROL
) ) &&
723 pt
.x
+= wxCC_CUSTOM_IMAGE_MARGIN1
;
724 wxRect
r(pt
.x
,pt
.y
,cis
.x
,cis
.y
);
726 if ( flags
& wxODCB_PAINTING_CONTROL
)
729 r
.height
= wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
);
732 paintdata
.m_drawnWidth
= r
.width
;
734 dc
.SetPen(m_colPropFore
);
735 if ( comValIndex
>= 0 )
737 const wxPGCommonValue
* cv
= GetCommonValue(comValIndex
);
738 wxPGCellRenderer
* renderer
= cv
->GetRenderer();
739 r
.width
= rect
.width
;
740 renderer
->Render( dc
, r
, this, p
, m_selColumn
, comValIndex
, renderFlags
);
743 else if ( item
>= 0 )
745 p
->OnCustomPaint( dc
, r
, paintdata
);
749 dc
.DrawRectangle( r
);
752 pt
.x
+= paintdata
.m_drawnWidth
+ wxCC_CUSTOM_IMAGE_MARGIN2
- 1;
756 // TODO: This aligns text so that it seems to be horizontally
757 // on the same line as property values. Not really
758 // sure if its needed, but seems to not cause any harm.
761 if ( item
< 0 && (flags
& wxODCB_PAINTING_CONTROL
) )
762 item
= pCb
->GetSelection();
764 if ( choices
.IsOk() && item
>= 0 && comValIndex
< 0 )
766 cell
= &choices
.Item(item
);
767 renderer
= wxPGGlobalVars
->m_defaultRenderer
;
768 int imageOffset
= renderer
->PreDrawCell(dc
, rect
, *cell
,
771 imageOffset
+= wxCC_CUSTOM_IMAGE_MARGIN1
+
772 wxCC_CUSTOM_IMAGE_MARGIN2
;
781 pt
.y
+= (rect
.height
-m_fontHeight
)/2 - 1;
785 dc
.DrawText( text
, pt
.x
+ wxPG_XBEFORETEXT
, pt
.y
);
788 renderer
->PostDrawCell(dc
, this, *cell
, renderFlags
);
796 p
->OnCustomPaint( dc
, rect
, paintdata
);
797 rect
.height
= paintdata
.m_drawnHeight
+ 2;
798 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9;
802 bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid
* propGrid
, wxPGComboBox
* cb
, int cmnVal
)
804 wxPGProperty
* property
= propGrid
->GetSelectedProperty();
805 wxASSERT( property
);
812 // Yes, a common value is being selected
813 property
->SetCommonValue( cmnVal
);
814 imageSize
= propGrid
->GetCommonValue(cmnVal
)->
815 GetRenderer()->GetImageSize(property
, 1, cmnVal
);
820 imageSize
= propGrid
->GetImageSize(property
, -1);
825 imageSize
.x
+= ODCB_CUST_PAINT_MARGIN
;
826 cb
->SetCustomPaintWidth( imageSize
.x
);
831 // CreateControls calls this with CB_READONLY in extraStyle
832 wxWindow
* wxPGChoiceEditor
::CreateControlsBase( wxPropertyGrid
* propGrid
,
833 wxPGProperty
* property
,
836 long extraStyle
) const
838 const wxPGChoices
& choices
= property
->GetChoices();
840 int index
= property
->GetChoiceSelection();
842 bool isUnspecified
= property
->IsValueUnspecified();
844 if ( !isUnspecified
)
845 defString
= property
->GetDisplayedString();
847 wxArrayString labels
= choices
.GetLabels();
853 po
.y
+= wxPG_CHOICEYADJUST
;
854 si
.y
-= (wxPG_CHOICEYADJUST
*2);
856 po
.x
+= wxPG_CHOICEXADJUST
;
857 si
.x
-= wxPG_CHOICEXADJUST
;
858 wxWindow
* ctrlParent
= propGrid
->GetPanel();
860 int odcbFlags
= extraStyle
| wxBORDER_NONE
| wxTE_PROCESS_ENTER
;
862 if ( (property
->GetFlags() & wxPG_PROP_USE_DCC
) &&
863 (property
->IsKindOf(CLASSINFO(wxBoolProperty
)) ) )
864 odcbFlags
|= wxODCB_DCLICK_CYCLES
;
867 // If common value specified, use appropriate index
868 unsigned int cmnVals
= property
->GetDisplayedCommonValueCount();
871 if ( !isUnspecified
)
873 int cmnVal
= property
->GetCommonValue();
876 index
= labels
.size() + cmnVal
;
881 for ( i
=0; i
<cmnVals
; i
++ )
882 labels
.Add(propGrid
->GetCommonValueLabel(i
));
885 cb
= new wxPGComboBox();
889 cb
->Create(ctrlParent
,
897 cb
->SetButtonPosition(si
.y
,0,wxRIGHT
);
898 cb
->SetMargins(wxPG_XBEFORETEXT
-1);
900 wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
, property
->GetCommonValue() );
902 if ( index
>= 0 && index
< (int)cb
->GetCount() )
904 cb
->SetSelection( index
);
905 if ( defString
.length() )
906 cb
->SetText( defString
);
908 else if ( !(extraStyle
& wxCB_READONLY
) && defString
.length() )
910 propGrid
->SetupTextCtrlValue(defString
);
911 cb
->SetValue( defString
);
915 cb
->SetSelection( -1 );
922 return (wxWindow
*) cb
;
926 void wxPGChoiceEditor
::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
929 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
930 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
931 int ind
= property
->GetChoiceSelection();
932 cb
->SetSelection(ind
);
935 wxPGWindowList wxPGChoiceEditor
::CreateControls( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
936 const wxPoint
& pos
, const wxSize
& sz
) const
938 return CreateControlsBase(propGrid
,property
,pos
,sz
,wxCB_READONLY
);
942 int wxPGChoiceEditor
::InsertItem( wxWindow
* ctrl
, const wxString
& label
, int index
) const
945 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
946 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
949 index
= cb
->GetCount();
951 return cb
->Insert(label
,index
);
955 void wxPGChoiceEditor
::DeleteItem( wxWindow
* ctrl
, int index
) const
958 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
959 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
964 bool wxPGChoiceEditor
::OnEvent( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
965 wxWindow
* ctrl
, wxEvent
& event
) const
967 if ( event
.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED
)
969 wxPGComboBox
* cb
= (wxPGComboBox
*)ctrl
;
970 int index
= cb
->GetSelection();
971 int cmnValIndex
= -1;
972 int cmnVals
= property
->GetDisplayedCommonValueCount();
973 int items
= cb
->GetCount();
975 if ( index
>= (items
-cmnVals
) )
977 // Yes, a common value is being selected
978 cmnValIndex
= index
- (items
-cmnVals
);
979 property
->SetCommonValue( cmnValIndex
);
981 // Truly set value to unspecified?
982 if ( propGrid
->GetUnspecifiedCommonValue() == cmnValIndex
)
984 if ( !property
->IsValueUnspecified() )
985 propGrid
->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT
);
986 property
->SetValueToUnspecified();
987 if ( !cb
->HasFlag(wxCB_READONLY
) )
989 wxString unspecValueText
;
990 propGrid
->SetupTextCtrlValue(unspecValueText
);
991 cb
->GetTextCtrl()->SetValue(unspecValueText
);
996 return wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
, cmnValIndex
);
1002 bool wxPGChoiceEditor
::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1004 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1006 int index
= cb
->GetSelection();
1008 if ( index
!= property
->GetChoiceSelection() ||
1009 // Changing unspecified always causes event (returning
1010 // true here should be enough to trigger it).
1011 property
->IsValueUnspecified()
1014 return property
->IntToValue( variant
, index
, 0 );
1020 void wxPGChoiceEditor
::SetControlStringValue( wxPGProperty
* property
,
1022 const wxString
& txt
) const
1024 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1026 property
->GetGrid()->SetupTextCtrlValue(txt
);
1031 void wxPGChoiceEditor
::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
1033 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1035 cb
->SetSelection(value
);
1039 void wxPGChoiceEditor
::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
) const
1041 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1042 cb
->SetSelection(-1);
1046 bool wxPGChoiceEditor
::CanContainCustomImage() const
1052 wxPGChoiceEditor
::~wxPGChoiceEditor() { }
1055 // -----------------------------------------------------------------------
1056 // wxPGComboBoxEditor
1057 // -----------------------------------------------------------------------
1060 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ComboBox
,
1065 void wxPGComboBoxEditor
::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1067 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1068 wxString s
= property
->GetValueAsString(wxPG_EDITABLE_VALUE
);
1069 property
->GetGrid()->SetupTextCtrlValue(s
);
1072 // TODO: If string matches any selection, then select that.
1076 wxPGWindowList wxPGComboBoxEditor
::CreateControls( wxPropertyGrid
* propGrid
,
1077 wxPGProperty
* property
,
1079 const wxSize
& sz
) const
1081 return CreateControlsBase(propGrid
,property
,pos
,sz
,0);
1085 bool wxPGComboBoxEditor
::OnEvent( wxPropertyGrid
* propGrid
,
1086 wxPGProperty
* property
,
1088 wxEvent
& event
) const
1090 wxOwnerDrawnComboBox
* cb
= NULL
;
1091 wxWindow
* textCtrl
= NULL
;
1095 cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1096 textCtrl
= cb
->GetTextCtrl();
1099 if ( wxPGTextCtrlEditor
::OnTextCtrlEvent(propGrid
,property
,textCtrl
,event
) )
1102 return wxPGChoiceEditor
::OnEvent(propGrid
,property
,ctrl
,event
);
1106 bool wxPGComboBoxEditor
::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1108 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1109 wxString textVal
= cb
->GetValue();
1111 if ( property
->UsesAutoUnspecified() && !textVal
.length() )
1117 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
1119 // Changing unspecified always causes event (returning
1120 // true here should be enough to trigger it).
1121 if ( !res
&& variant
.IsNull() )
1128 void wxPGComboBoxEditor
::OnFocus( wxPGProperty
*, wxWindow
* ctrl
) const
1130 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1131 cb
->GetTextCtrl()->SetSelection(-1,-1);
1135 wxPGComboBoxEditor
::~wxPGComboBoxEditor() { }
1138 // -----------------------------------------------------------------------
1139 // wxPGChoiceAndButtonEditor
1140 // -----------------------------------------------------------------------
1143 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ChoiceAndButton
,
1144 wxPGChoiceAndButtonEditor
,
1148 wxPGWindowList wxPGChoiceAndButtonEditor
::CreateControls( wxPropertyGrid
* propGrid
,
1149 wxPGProperty
* property
,
1151 const wxSize
& sz
) const
1153 // Use one two units smaller to match size of the combo's dropbutton.
1154 // (normally a bigger button is used because it looks better)
1157 wxSize
bt_sz(bt_wid
,bt_wid
);
1159 // Position of button.
1160 wxPoint
bt_pos(pos
.x
+sz
.x
-bt_sz
.x
,pos
.y
);
1167 wxWindow
* bt
= propGrid
->GenerateEditorButton( bt_pos
, bt_sz
);
1170 wxSize
ch_sz(sz
.x
-bt
->GetSize().x
,sz
.y
);
1173 ch_sz
.x
-= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1176 wxWindow
* ch
= wxPGEditor_Choice
->CreateControls(propGrid
,property
,
1177 pos
,ch_sz
).m_primary
;
1183 return wxPGWindowList(ch
, bt
);
1187 wxPGChoiceAndButtonEditor
::~wxPGChoiceAndButtonEditor() { }
1190 // -----------------------------------------------------------------------
1191 // wxPGTextCtrlAndButtonEditor
1192 // -----------------------------------------------------------------------
1194 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrlAndButton
,
1195 wxPGTextCtrlAndButtonEditor
,
1199 wxPGWindowList wxPGTextCtrlAndButtonEditor
::CreateControls( wxPropertyGrid
* propGrid
,
1200 wxPGProperty
* property
,
1202 const wxSize
& sz
) const
1205 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrlAndButton( pos
, sz
, &wnd2
,
1206 property
->GetFlags() & wxPG_PROP_NOEDITOR
, property
);
1208 return wxPGWindowList(wnd
, wnd2
);
1212 wxPGTextCtrlAndButtonEditor
::~wxPGTextCtrlAndButtonEditor() { }
1215 // -----------------------------------------------------------------------
1216 // wxPGCheckBoxEditor
1217 // -----------------------------------------------------------------------
1219 #if wxPG_INCLUDE_CHECKBOX
1221 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(CheckBox
,
1226 // Check box state flags
1229 wxSCB_STATE_UNCHECKED
= 0,
1230 wxSCB_STATE_CHECKED
= 1,
1231 wxSCB_STATE_BOLD
= 2,
1232 wxSCB_STATE_UNSPECIFIED
= 4
1235 const int wxSCB_SETVALUE_CYCLE
= 2;
1238 static void DrawSimpleCheckBox( wxDC
& dc
, const wxRect
& rect
, int box_hei
,
1239 int state
, const wxColour
& lineCol
)
1242 wxRect
r(rect
.x
+wxPG_XBEFORETEXT
,rect
.y
+((rect
.height
-box_hei
)/2),
1244 wxColour useCol
= lineCol
;
1246 if ( state
& wxSCB_STATE_UNSPECIFIED
)
1248 useCol
= wxColour(220, 220, 220);
1251 // Draw check mark first because it is likely to overdraw the
1252 // surrounding rectangle.
1253 if ( state
& wxSCB_STATE_CHECKED
)
1255 wxRect
r2(r
.x
+wxPG_CHECKMARK_XADJ
,
1256 r
.y
+wxPG_CHECKMARK_YADJ
,
1257 r
.width
+wxPG_CHECKMARK_WADJ
,
1258 r
.height
+wxPG_CHECKMARK_HADJ
);
1259 #if wxPG_CHECKMARK_DEFLATE
1260 r2
.Deflate(wxPG_CHECKMARK_DEFLATE
);
1262 dc
.DrawCheckMark(r2
);
1264 // This would draw a simple cross check mark.
1265 // dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
1266 // dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
1269 if ( !(state
& wxSCB_STATE_BOLD
) )
1271 // Pen for thin rectangle.
1276 // Pen for bold rectangle.
1277 wxPen
linepen(useCol
,2,wxSOLID
);
1278 linepen
.SetJoin(wxJOIN_MITER
); // This prevents round edges.
1286 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1288 dc
.DrawRectangle(r
);
1289 dc
.SetPen(*wxTRANSPARENT_PEN
);
1293 // Real simple custom-drawn checkbox-without-label class.
1295 class wxSimpleCheckBox
: public wxControl
1299 void SetValue( int value
);
1301 wxSimpleCheckBox( wxWindow
* parent
,
1303 const wxPoint
& pos
= wxDefaultPosition
,
1304 const wxSize
& size
= wxDefaultSize
)
1305 : wxControl(parent
,id
,pos
,size
,wxBORDER_NONE
|wxWANTS_CHARS
)
1307 // Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
1308 SetFont( parent
->GetFont() );
1313 SetBackgroundStyle( wxBG_STYLE_CUSTOM
);
1316 virtual ~wxSimpleCheckBox();
1322 void OnPaint( wxPaintEvent
& event
);
1323 void OnLeftClick( wxMouseEvent
& event
);
1324 void OnKeyDown( wxKeyEvent
& event
);
1326 void OnResize( wxSizeEvent
& event
)
1332 static wxBitmap
* ms_doubleBuffer
;
1334 DECLARE_EVENT_TABLE()
1337 BEGIN_EVENT_TABLE(wxSimpleCheckBox
, wxControl
)
1338 EVT_PAINT(wxSimpleCheckBox
::OnPaint
)
1339 EVT_LEFT_DOWN(wxSimpleCheckBox
::OnLeftClick
)
1340 EVT_LEFT_DCLICK(wxSimpleCheckBox
::OnLeftClick
)
1341 EVT_KEY_DOWN(wxSimpleCheckBox
::OnKeyDown
)
1342 EVT_SIZE(wxSimpleCheckBox
::OnResize
)
1345 wxSimpleCheckBox
::~wxSimpleCheckBox()
1347 delete ms_doubleBuffer
;
1348 ms_doubleBuffer
= NULL
;
1351 wxBitmap
* wxSimpleCheckBox
::ms_doubleBuffer
= NULL
;
1353 void wxSimpleCheckBox
::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1355 wxSize clientSize
= GetClientSize();
1356 wxAutoBufferedPaintDC
dc(this);
1359 wxRect
rect(0,0,clientSize
.x
,clientSize
.y
);
1363 wxColour bgcol
= GetBackgroundColour();
1364 dc
.SetBrush( bgcol
);
1366 dc
.DrawRectangle( rect
);
1368 wxColour txcol
= GetForegroundColour();
1370 int state
= m_state
;
1371 if ( !(state
& wxSCB_STATE_UNSPECIFIED
) &&
1372 GetFont().GetWeight() == wxBOLD
)
1373 state
|= wxSCB_STATE_BOLD
;
1375 DrawSimpleCheckBox(dc
,rect
,m_boxHeight
,state
,txcol
);
1378 void wxSimpleCheckBox
::OnLeftClick( wxMouseEvent
& event
)
1380 if ( (event
.m_x
> (wxPG_XBEFORETEXT
-2)) &&
1381 (event
.m_x
<= (wxPG_XBEFORETEXT
-2+m_boxHeight
)) )
1383 SetValue(wxSCB_SETVALUE_CYCLE
);
1387 void wxSimpleCheckBox
::OnKeyDown( wxKeyEvent
& event
)
1389 if ( event
.GetKeyCode() == WXK_SPACE
)
1391 SetValue(wxSCB_SETVALUE_CYCLE
);
1395 void wxSimpleCheckBox
::SetValue( int value
)
1397 if ( value
== wxSCB_SETVALUE_CYCLE
)
1399 if ( m_state
& wxSCB_STATE_CHECKED
)
1400 m_state
&= ~wxSCB_STATE_CHECKED
;
1402 m_state
|= wxSCB_STATE_CHECKED
;
1410 wxCommandEvent
evt(wxEVT_COMMAND_CHECKBOX_CLICKED
,GetParent()->GetId());
1412 wxPropertyGrid
* propGrid
= (wxPropertyGrid
*) GetParent();
1413 wxASSERT( propGrid
->IsKindOf(CLASSINFO(wxPropertyGrid
)) );
1414 propGrid
->HandleCustomEditorEvent(evt
);
1417 wxPGWindowList wxPGCheckBoxEditor
::CreateControls( wxPropertyGrid
* propGrid
,
1418 wxPGProperty
* property
,
1420 const wxSize
& size
) const
1423 pt
.x
-= wxPG_XBEFOREWIDGET
;
1425 sz
.x
= propGrid
->GetFontHeight() + (wxPG_XBEFOREWIDGET
*2) + 4;
1427 wxSimpleCheckBox
* cb
= new wxSimpleCheckBox(propGrid
->GetPanel(),
1428 wxPG_SUBID1
, pt
, sz
);
1430 cb
->SetBackgroundColour(wxSystemSettings
::GetColour(wxSYS_COLOUR_WINDOW
));
1432 UpdateControl(property
, cb
);
1434 if ( !property
->IsValueUnspecified() )
1436 // If mouse cursor was on the item, toggle the value now.
1437 if ( propGrid
->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK
)
1439 wxPoint pt
= cb
->ScreenToClient(::wxGetMousePosition());
1440 if ( pt
.x
<= (wxPG_XBEFORETEXT
-2+cb
->m_boxHeight
) )
1442 if ( cb
->m_state
& wxSCB_STATE_CHECKED
)
1443 cb
->m_state
&= ~wxSCB_STATE_CHECKED
;
1445 cb
->m_state
|= wxSCB_STATE_CHECKED
;
1447 // Makes sure wxPG_EVT_CHANGING etc. is sent for this initial
1449 propGrid
->ChangePropertyValue(property
,
1450 wxPGVariant_Bool(cb
->m_state
));
1455 propGrid
->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR
);
1460 void wxPGCheckBoxEditor
::DrawValue( wxDC
& dc
, const wxRect
& rect
,
1461 wxPGProperty
* property
,
1462 const wxString
& WXUNUSED(text
) ) const
1464 int state
= wxSCB_STATE_UNCHECKED
;
1465 wxColour rectCol
= dc
.GetTextForeground();
1467 if ( !property
->IsValueUnspecified() )
1469 state
= property
->GetChoiceSelection();
1470 if ( dc
.GetFont().GetWeight() == wxBOLD
)
1471 state
|= wxSCB_STATE_BOLD
;
1475 state
|= wxSCB_STATE_UNSPECIFIED
;
1478 DrawSimpleCheckBox(dc
, rect
, dc
.GetCharHeight(), state
, rectCol
);
1481 void wxPGCheckBoxEditor
::UpdateControl( wxPGProperty
* property
,
1482 wxWindow
* ctrl
) const
1484 wxSimpleCheckBox
* cb
= (wxSimpleCheckBox
*) ctrl
;
1487 if ( !property
->IsValueUnspecified() )
1488 cb
->m_state
= property
->GetChoiceSelection();
1490 cb
->m_state
= wxSCB_STATE_UNSPECIFIED
;
1492 wxPropertyGrid
* propGrid
= property
->GetGrid();
1493 cb
->m_boxHeight
= propGrid
->GetFontHeight();
1498 bool wxPGCheckBoxEditor
::OnEvent( wxPropertyGrid
* WXUNUSED(propGrid
), wxPGProperty
* WXUNUSED(property
),
1499 wxWindow
* WXUNUSED(ctrl
), wxEvent
& event
) const
1501 if ( event
.GetEventType() == wxEVT_COMMAND_CHECKBOX_CLICKED
)
1509 bool wxPGCheckBoxEditor
::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1511 wxSimpleCheckBox
* cb
= (wxSimpleCheckBox
*)ctrl
;
1513 int index
= cb
->m_state
;
1515 if ( index
!= property
->GetChoiceSelection() ||
1516 // Changing unspecified always causes event (returning
1517 // true here should be enough to trigger it).
1518 property
->IsValueUnspecified()
1521 return property
->IntToValue(variant
, index
, 0);
1527 void wxPGCheckBoxEditor
::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
1529 if ( value
!= 0 ) value
= 1;
1530 ((wxSimpleCheckBox
*)ctrl
)->m_state
= value
;
1535 void wxPGCheckBoxEditor
::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
) const
1537 ((wxSimpleCheckBox
*)ctrl
)->m_state
= wxSCB_STATE_UNSPECIFIED
;
1542 wxPGCheckBoxEditor
::~wxPGCheckBoxEditor() { }
1545 #endif // wxPG_INCLUDE_CHECKBOX
1547 // -----------------------------------------------------------------------
1549 wxWindow
* wxPropertyGrid
::GetEditorControl() const
1551 wxWindow
* ctrl
= m_wndEditor
;
1559 // -----------------------------------------------------------------------
1561 void wxPropertyGrid
::CorrectEditorWidgetSizeX()
1564 int newSplitterx
= m_pState
->DoGetSplitterPosition(m_selColumn
-1);
1565 int newWidth
= newSplitterx
+ m_pState
->m_colWidths
[m_selColumn
];
1569 // if width change occurred, move secondary wnd by that amount
1570 wxRect r
= m_wndEditor2
->GetRect();
1572 r
.x
= newWidth
- secWid
;
1574 m_wndEditor2
->SetSize( r
);
1576 // if primary is textctrl, then we have to add some extra space
1580 if ( m_wndEditor
&& m_wndEditor
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
1582 secWid
+= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1587 wxRect r
= m_wndEditor
->GetRect();
1589 r
.x
= newSplitterx
+m_ctrlXAdjust
;
1591 if ( !(m_iFlags
& wxPG_FL_FIXED_WIDTH_EDITOR
) )
1592 r
.width
= newWidth
- r
.x
- secWid
;
1594 m_wndEditor
->SetSize(r
);
1598 m_wndEditor2
->Refresh();
1601 // -----------------------------------------------------------------------
1603 void wxPropertyGrid
::CorrectEditorWidgetPosY()
1605 if ( GetSelection() && (m_wndEditor
|| m_wndEditor2
) )
1607 wxRect r
= GetEditorWidgetRect(GetSelection(), m_selColumn
);
1611 wxPoint pos
= m_wndEditor
->GetPosition();
1613 // Calculate y offset
1614 int offset
= pos
.y
% m_lineHeight
;
1616 m_wndEditor
->Move(pos
.x
, r
.y
+ offset
);
1621 wxPoint pos
= m_wndEditor2
->GetPosition();
1623 m_wndEditor2
->Move(pos
.x
, r
.y
);
1628 // -----------------------------------------------------------------------
1630 // Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
1631 // fits into that category as well).
1632 void wxPropertyGrid
::FixPosForTextCtrl( wxWindow
* ctrl
,
1633 unsigned int WXUNUSED(forColumn
),
1634 const wxPoint
& offset
)
1636 // Center the control vertically
1637 wxRect finalPos
= ctrl
->GetRect();
1638 int y_adj
= (m_lineHeight
- finalPos
.height
)/2 + wxPG_TEXTCTRLYADJUST
;
1640 // Prevent over-sized control
1641 int sz_dec
= (y_adj
+ finalPos
.height
) - m_lineHeight
;
1642 if ( sz_dec
< 0 ) sz_dec
= 0;
1644 finalPos
.y
+= y_adj
;
1645 finalPos
.height
-= (y_adj
+sz_dec
);
1647 #ifndef wxPG_TEXTCTRLXADJUST
1648 int textCtrlXAdjust
= wxPG_XBEFORETEXT
- 1;
1650 wxTextCtrl
* tc
= static_cast<wxTextCtrl
*>(ctrl
);
1653 int textCtrlXAdjust
= wxPG_TEXTCTRLXADJUST
;
1656 finalPos
.x
+= textCtrlXAdjust
;
1657 finalPos
.width
-= textCtrlXAdjust
;
1659 finalPos
.x
+= offset
.x
;
1660 finalPos
.y
+= offset
.y
;
1662 ctrl
->SetSize(finalPos
);
1665 // -----------------------------------------------------------------------
1667 wxWindow
* wxPropertyGrid
::GenerateEditorTextCtrl( const wxPoint
& pos
,
1669 const wxString
& value
,
1670 wxWindow
* secondary
,
1673 unsigned int forColumn
)
1675 wxWindowID id
= wxPG_SUBID1
;
1676 wxPGProperty
* prop
= GetSelection();
1679 int tcFlags
= wxTE_PROCESS_ENTER
| extraStyle
;
1681 if ( prop
->HasFlag(wxPG_PROP_READONLY
) && forColumn
== 1 )
1682 tcFlags
|= wxTE_READONLY
;
1684 wxPoint
p(pos
.x
,pos
.y
);
1685 wxSize
s(sz
.x
,sz
.y
);
1687 // Need to reduce width of text control on Mac
1688 #if defined(__WXMAC__)
1692 // For label editors, trim the size to allow better splitter grabbing
1693 if ( forColumn
!= 1 )
1696 // Take button into acccount
1699 s
.x
-= (secondary
->GetSize().x
+ wxPG_TEXTCTRL_AND_BUTTON_SPACING
);
1700 m_iFlags
&= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE
);
1703 // If the height is significantly higher, then use border, and fill the rect exactly.
1704 bool hasSpecialSize
= false;
1706 if ( (sz
.y
- m_lineHeight
) > 5 )
1707 hasSpecialSize
= true;
1709 wxWindow
* ctrlParent
= GetPanel();
1711 if ( !hasSpecialSize
)
1712 tcFlags
|= wxBORDER_NONE
;
1714 wxTextCtrl
* tc
= new wxTextCtrl();
1716 #if defined(__WXMSW__)
1719 SetupTextCtrlValue(value
);
1720 tc
->Create(ctrlParent
,id
,value
, p
, s
,tcFlags
);
1722 #if defined(__WXMSW__)
1723 // On Windows, we need to override read-only text ctrl's background
1724 // colour to white. One problem with native 'grey' background is that
1725 // tc->GetBackgroundColour() doesn't seem to return correct value
1727 if ( tcFlags
& wxTE_READONLY
)
1729 wxVisualAttributes vattrs
= tc
->GetDefaultAttributes();
1730 tc
->SetBackgroundColour(vattrs
.colBg
);
1734 // Center the control vertically
1735 if ( !hasSpecialSize
)
1736 FixPosForTextCtrl(tc
, forColumn
);
1738 if ( forColumn
!= 1 )
1740 tc
->SetBackgroundColour(m_colSelBack
);
1741 tc
->SetForegroundColour(m_colSelFore
);
1750 // Set maximum length
1752 tc
->SetMaxLength( maxLen
);
1754 wxVariant attrVal
= prop
->GetAttribute(wxPG_ATTR_AUTOCOMPLETE
);
1755 if ( !attrVal
.IsNull() )
1757 wxASSERT(attrVal
.GetType() == wxS("arrstring"));
1758 tc
->AutoComplete(attrVal
.GetArrayString());
1764 // -----------------------------------------------------------------------
1766 wxWindow
* wxPropertyGrid
::GenerateEditorButton( const wxPoint
& pos
, const wxSize
& sz
)
1768 wxWindowID id
= wxPG_SUBID2
;
1769 wxPGProperty
* selected
= GetSelection();
1773 // Decorations are chunky on Mac, and we can't make the button square, so
1774 // do things a bit differently on this platform.
1776 wxPoint
p(pos
.x
+sz
.x
,
1777 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
1780 wxButton
* but
= new wxButton();
1781 but
->Create(GetPanel(),id
,wxS("..."),p
,s
,wxWANTS_CHARS
);
1783 // Now that we know the size, move to the correct position
1784 p
.x
= pos
.x
+ sz
.x
- but
->GetSize().x
- 2;
1788 wxSize
s(sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2),
1789 sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2));
1791 // Reduce button width to lineheight
1792 if ( s
.x
> m_lineHeight
)
1796 // On wxGTK, take fixed button margins into account
1801 wxPoint
p(pos
.x
+sz
.x
-s
.x
,
1802 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
1804 wxButton
* but
= new wxButton();
1808 but
->Create(GetPanel(),id
,wxS("..."),p
,s
,wxWANTS_CHARS
);
1811 wxFont font
= GetFont();
1812 font
.SetPointSize(font
.GetPointSize()-2);
1815 but
->SetFont(GetFont());
1819 if ( selected
->HasFlag(wxPG_PROP_READONLY
) )
1825 // -----------------------------------------------------------------------
1827 wxWindow
* wxPropertyGrid
::GenerateEditorTextCtrlAndButton( const wxPoint
& pos
,
1829 wxWindow
** psecondary
,
1831 wxPGProperty
* property
)
1833 wxButton
* but
= (wxButton
*)GenerateEditorButton(pos
,sz
);
1834 *psecondary
= (wxWindow
*)but
;
1836 if ( limitedEditing
)
1839 // There is button Show in GenerateEditorTextCtrl as well
1847 if ( !property
->IsValueUnspecified() )
1848 text
= property
->GetValueAsString(property
->HasFlag(wxPG_PROP_READONLY
)?
0:wxPG_EDITABLE_VALUE
);
1850 return GenerateEditorTextCtrl(pos
,sz
,text
,but
,property
->m_maxLen
);
1853 // -----------------------------------------------------------------------
1855 wxTextCtrl
* wxPropertyGrid
::GetEditorTextCtrl() const
1857 wxWindow
* wnd
= GetEditorControl();
1862 if ( wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
1863 return wxStaticCast(wnd
, wxTextCtrl
);
1865 if ( wnd
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) )
1867 wxOwnerDrawnComboBox
* cb
= wxStaticCast(wnd
, wxOwnerDrawnComboBox
);
1868 return cb
->GetTextCtrl();
1874 // -----------------------------------------------------------------------
1876 wxPGEditor
* wxPropertyGridInterface
::GetEditorByName( const wxString
& editorName
)
1878 wxPGHashMapS2P
::const_iterator it
;
1880 it
= wxPGGlobalVars
->m_mapEditorClasses
.find(editorName
);
1881 if ( it
== wxPGGlobalVars
->m_mapEditorClasses
.end() )
1883 return (wxPGEditor
*) it
->second
;
1886 // -----------------------------------------------------------------------
1887 // wxPGEditorDialogAdapter
1888 // -----------------------------------------------------------------------
1890 IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter
, wxObject
)
1892 bool wxPGEditorDialogAdapter
::ShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1894 if ( !propGrid
->EditorValidate() )
1897 bool res
= DoShowDialog( propGrid
, property
);
1901 propGrid
->ValueChangeInEvent( m_value
);
1908 // -----------------------------------------------------------------------
1910 // -----------------------------------------------------------------------
1912 wxPGMultiButton
::wxPGMultiButton( wxPropertyGrid
* pg
, const wxSize
& sz
)
1913 : wxWindow( pg
->GetPanel(), wxPG_SUBID2
, wxPoint(-100,-100), wxSize(0, sz
.y
) ),
1914 m_fullEditorSize(sz
), m_buttonsWidth(0)
1916 SetBackgroundColour(pg
->GetCellBackgroundColour());
1919 void wxPGMultiButton
::Finalize( wxPropertyGrid
* WXUNUSED(propGrid
),
1920 const wxPoint
& pos
)
1922 Move( pos
.x
+ m_fullEditorSize
.x
- m_buttonsWidth
, pos
.y
);
1925 int wxPGMultiButton
::GenId( int id
) const
1929 if ( m_buttons
.size() )
1930 id
= GetButton(m_buttons
.size()-1)->GetId() + 1;
1938 void wxPGMultiButton
::Add( const wxBitmap
& bitmap
, int id
)
1941 wxSize sz
= GetSize();
1942 wxButton
* button
= new wxBitmapButton( this, id
, bitmap
,
1944 wxSize(sz
.y
, sz
.y
) );
1945 DoAddButton( button
, sz
);
1949 void wxPGMultiButton
::Add( const wxString
& label
, int id
)
1952 wxSize sz
= GetSize();
1953 wxButton
* button
= new wxButton( this, id
, label
, wxPoint(sz
.x
, 0),
1954 wxSize(sz
.y
, sz
.y
) );
1955 DoAddButton( button
, sz
);
1958 void wxPGMultiButton
::DoAddButton( wxWindow
* button
,
1961 m_buttons
.push_back(button
);
1962 int bw
= button
->GetSize().x
;
1963 SetSize(wxSize(sz
.x
+bw
,sz
.y
));
1964 m_buttonsWidth
+= bw
;
1967 // -----------------------------------------------------------------------
1969 #endif // wxUSE_PROPGRID