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"
81 #include "wx/msw/private.h"
84 // -----------------------------------------------------------------------
86 #if defined(__WXMSW__)
88 #define wxPG_NAT_BUTTON_BORDER_ANY 1
89 #define wxPG_NAT_BUTTON_BORDER_X 1
90 #define wxPG_NAT_BUTTON_BORDER_Y 1
92 #define wxPG_CHECKMARK_XADJ 1
93 #define wxPG_CHECKMARK_YADJ (-1)
94 #define wxPG_CHECKMARK_WADJ 0
95 #define wxPG_CHECKMARK_HADJ 0
96 #define wxPG_CHECKMARK_DEFLATE 0
98 #define wxPG_TEXTCTRLYADJUST (m_spacingy+0)
100 #elif defined(__WXGTK__)
102 #define wxPG_CHECKMARK_XADJ 0
103 #define wxPG_CHECKMARK_YADJ 0
104 #define wxPG_CHECKMARK_WADJ (-1)
105 #define wxPG_CHECKMARK_HADJ (-1)
106 #define wxPG_CHECKMARK_DEFLATE 3
108 #define wxPG_NAT_BUTTON_BORDER_ANY 1
109 #define wxPG_NAT_BUTTON_BORDER_X 1
110 #define wxPG_NAT_BUTTON_BORDER_Y 1
112 #define wxPG_TEXTCTRLYADJUST 0
114 #elif defined(__WXMAC__)
116 #define wxPG_CHECKMARK_XADJ 0
117 #define wxPG_CHECKMARK_YADJ 0
118 #define wxPG_CHECKMARK_WADJ 0
119 #define wxPG_CHECKMARK_HADJ 0
120 #define wxPG_CHECKMARK_DEFLATE 0
122 #define wxPG_NAT_BUTTON_BORDER_ANY 0
123 #define wxPG_NAT_BUTTON_BORDER_X 0
124 #define wxPG_NAT_BUTTON_BORDER_Y 0
126 #define wxPG_TEXTCTRLYADJUST 0
130 #define wxPG_CHECKMARK_XADJ 0
131 #define wxPG_CHECKMARK_YADJ 0
132 #define wxPG_CHECKMARK_WADJ 0
133 #define wxPG_CHECKMARK_HADJ 0
134 #define wxPG_CHECKMARK_DEFLATE 0
136 #define wxPG_NAT_BUTTON_BORDER_ANY 0
137 #define wxPG_NAT_BUTTON_BORDER_X 0
138 #define wxPG_NAT_BUTTON_BORDER_Y 0
140 #define wxPG_TEXTCTRLYADJUST 0
146 #define wxPG_CHOICEXADJUST -3 // required because wxComboCtrl reserves 3pixels for wxTextCtrl's focus ring
147 #define wxPG_CHOICEYADJUST -3
149 #define wxPG_CHOICEXADJUST 0
150 #define wxPG_CHOICEYADJUST 0
153 #define ODCB_CUST_PAINT_MARGIN 6 // Number added to image width for SetCustomPaintWidth
155 // Milliseconds to wait for two mouse-ups after focus inorder
156 // to trigger a double-click.
157 #define DOUBLE_CLICK_CONVERSION_TRESHOLD 500
159 // -----------------------------------------------------------------------
161 // -----------------------------------------------------------------------
163 IMPLEMENT_ABSTRACT_CLASS(wxPGEditor
, wxObject
)
166 wxPGEditor::~wxPGEditor()
170 wxString
wxPGEditor::GetName() const
172 return GetClassInfo()->GetClassName();
175 void wxPGEditor::DrawValue( wxDC
& dc
, const wxRect
& rect
, wxPGProperty
* property
, const wxString
& text
) const
177 if ( !property
->IsValueUnspecified() )
178 dc
.DrawText( text
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
181 bool wxPGEditor::GetValueFromControl( wxVariant
&, wxPGProperty
*, wxWindow
* ) const
186 void wxPGEditor::SetControlStringValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, const wxString
& ) const
191 void wxPGEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, int ) const
196 int wxPGEditor::InsertItem( wxWindow
*, const wxString
&, int ) const
202 void wxPGEditor::DeleteItem( wxWindow
*, int ) const
208 void wxPGEditor::OnFocus( wxPGProperty
*, wxWindow
* ) const
213 bool wxPGEditor::CanContainCustomImage() const
218 // -----------------------------------------------------------------------
219 // wxPGTextCtrlEditor
220 // -----------------------------------------------------------------------
222 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrl
,wxPGTextCtrlEditor
,wxPGEditor
)
225 wxPGWindowList
wxPGTextCtrlEditor::CreateControls( wxPropertyGrid
* propGrid
,
226 wxPGProperty
* property
,
228 const wxSize
& sz
) const
233 // If has children, and limited editing is specified, then don't create.
234 if ( (property
->GetFlags() & wxPG_PROP_NOEDITOR
) &&
235 property
->GetChildCount() )
236 return (wxWindow
*) NULL
;
238 if ( !property
->IsValueUnspecified() )
239 text
= property
->GetValueAsString(property
->HasFlag(wxPG_PROP_READONLY
) ?
240 0 : wxPG_EDITABLE_VALUE
);
243 if ( (property
->GetFlags() & wxPG_PROP_PASSWORD
) &&
244 property
->IsKindOf(CLASSINFO(wxStringProperty
)) )
245 flags
|= wxTE_PASSWORD
;
247 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrl(pos
,sz
,text
,(wxWindow
*)NULL
,flags
,
248 property
->GetMaxLength());
254 void wxPGTextCtrlEditor::DrawValue( wxDC
& dc
, wxPGProperty
* property
, const wxRect
& rect
) const
256 if ( !property
->IsValueUnspecified() )
258 wxString drawStr
= property
->GetDisplayedString();
260 // Code below should no longer be needed, as the obfuscation
261 // is now done in GetValueAsString.
262 /*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
263 property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
265 size_t a = drawStr.length();
267 drawStr.Append(wxS('*'),a);
269 dc
.DrawText( drawStr
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
274 void wxPGTextCtrlEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
276 wxTextCtrl
* tc
= wxDynamicCast(ctrl
, wxTextCtrl
);
281 if ( tc
->HasFlag(wxTE_PASSWORD
) )
282 s
= property
->GetValueAsString(wxPG_FULL_VALUE
);
284 s
= property
->GetDisplayedString();
289 // Fix indentation, just in case (change in font boldness is one good
291 #if defined(__WXMSW__) && !defined(__WXWINCE__)
292 ::SendMessage(GetHwndOf(tc
),
294 EC_LEFTMARGIN
| EC_RIGHTMARGIN
,
299 // Provided so that, for example, ComboBox editor can use the same code
300 // (multiple inheritance would get way too messy).
301 bool wxPGTextCtrlEditor::OnTextCtrlEvent( wxPropertyGrid
* propGrid
,
302 wxPGProperty
* WXUNUSED(property
),
309 if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER
)
311 if ( propGrid
->IsEditorsValueModified() )
316 else if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED
)
319 // Pass this event outside wxPropertyGrid so that,
320 // if necessary, program can tell when user is editing
322 // FIXME: Is it safe to change event id in the middle of event
323 // processing (seems to work, but...)?
325 event
.SetId(propGrid
->GetId());
327 propGrid
->EditorsValueWasModified();
333 bool wxPGTextCtrlEditor::OnEvent( wxPropertyGrid
* propGrid
,
334 wxPGProperty
* property
,
336 wxEvent
& event
) const
338 return wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid
,property
,ctrl
,event
);
342 bool wxPGTextCtrlEditor::GetTextCtrlValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
)
344 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
345 wxString textVal
= tc
->GetValue();
347 if ( property
->UsesAutoUnspecified() && !textVal
.length() )
353 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
355 // Changing unspecified always causes event (returning
356 // true here should be enough to trigger it).
357 // TODO: Move to propgrid.cpp
358 if ( !res
&& variant
.IsNull() )
365 bool wxPGTextCtrlEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
367 return wxPGTextCtrlEditor::GetTextCtrlValueFromControl(variant
, property
, ctrl
);
371 void wxPGTextCtrlEditor::SetValueToUnspecified( wxPGProperty
* property
, wxWindow
* ctrl
) const
373 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
375 wxPropertyGrid
* pg
= property
->GetGrid();
376 wxASSERT(pg
); // Really, property grid should exist if editor does
378 tc
->SetValue(wxEmptyString
);
382 void wxPGTextCtrlEditor::SetControlStringValue( wxPGProperty
* property
, wxWindow
* ctrl
, const wxString
& txt
) const
384 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
386 wxPropertyGrid
* pg
= property
->GetGrid();
387 wxASSERT(pg
); // Really, property grid should exist if editor does
393 void wxPGTextCtrlEditor::OnFocus( wxPGProperty
*, wxWindow
* wnd
) const
395 wxTextCtrl
* tc
= wxStaticCast(wnd
, wxTextCtrl
);
397 tc
->SetSelection(-1,-1);
401 wxPGTextCtrlEditor::~wxPGTextCtrlEditor() { }
404 // -----------------------------------------------------------------------
406 // -----------------------------------------------------------------------
409 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(Choice
,wxPGChoiceEditor
,wxPGEditor
)
412 // This is a special enhanced double-click processor class.
413 // In essence, it allows for double-clicks for which the
414 // first click "created" the control.
415 class wxPGDoubleClickProcessor
: public wxEvtHandler
419 wxPGDoubleClickProcessor( wxOwnerDrawnComboBox
* combo
, wxPGProperty
* property
)
422 m_timeLastMouseUp
= 0;
424 m_property
= property
;
425 m_downReceived
= false;
430 void OnMouseEvent( wxMouseEvent
& event
)
432 wxLongLong t
= ::wxGetLocalTimeMillis();
433 int evtType
= event
.GetEventType();
435 if ( m_property
->HasFlag(wxPG_PROP_USE_DCC
) &&
436 m_property
->IsKindOf(CLASSINFO(wxBoolProperty
)) &&
437 !m_combo
->IsPopupShown() )
439 // Just check that it is in the text area
440 wxPoint pt
= event
.GetPosition();
441 if ( m_combo
->GetTextRect().Contains(pt
) )
443 if ( evtType
== wxEVT_LEFT_DOWN
)
445 // Set value to avoid up-events without corresponding downs
446 m_downReceived
= true;
448 else if ( evtType
== wxEVT_LEFT_DCLICK
)
450 // We'll make our own double-clicks
451 event
.SetEventType(0);
454 else if ( evtType
== wxEVT_LEFT_UP
)
456 if ( m_downReceived
|| m_timeLastMouseUp
== 1 )
458 wxLongLong timeFromLastUp
= (t
-m_timeLastMouseUp
);
460 if ( timeFromLastUp
< DOUBLE_CLICK_CONVERSION_TRESHOLD
)
462 event
.SetEventType(wxEVT_LEFT_DCLICK
);
463 m_timeLastMouseUp
= 1;
467 m_timeLastMouseUp
= t
;
477 void OnSetFocus( wxFocusEvent
& event
)
479 m_timeLastMouseUp
= ::wxGetLocalTimeMillis();
484 wxLongLong m_timeLastMouseUp
;
485 wxOwnerDrawnComboBox
* m_combo
;
486 wxPGProperty
* m_property
; // Selected property
489 DECLARE_EVENT_TABLE()
492 BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor
, wxEvtHandler
)
493 EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor::OnMouseEvent
)
494 EVT_SET_FOCUS(wxPGDoubleClickProcessor::OnSetFocus
)
499 class wxPGComboBox
: public wxOwnerDrawnComboBox
504 : wxOwnerDrawnComboBox()
506 m_dclickProcessor
= (wxPGDoubleClickProcessor
*) NULL
;
507 m_sizeEventCalled
= false;
512 if ( m_dclickProcessor
)
514 RemoveEventHandler(m_dclickProcessor
);
515 delete m_dclickProcessor
;
519 bool Create(wxWindow
*parent
,
521 const wxString
& value
,
524 const wxArrayString
& choices
,
526 const wxValidator
& validator
= wxDefaultValidator
,
527 const wxString
& name
= wxS("wxOwnerDrawnComboBox"))
529 if ( !wxOwnerDrawnComboBox::Create( parent
,
540 m_dclickProcessor
= new
541 wxPGDoubleClickProcessor( this, GetGrid()->GetSelection() );
543 PushEventHandler(m_dclickProcessor
);
548 virtual void OnDrawItem( wxDC
& dc
,
553 wxPropertyGrid
* pg
= GetGrid();
554 pg
->OnComboItemPaint( this, item
, &dc
, (wxRect
&)rect
, flags
);
557 virtual wxCoord
OnMeasureItem( size_t item
) const
559 wxPropertyGrid
* pg
= GetGrid();
563 pg
->OnComboItemPaint( this, item
, NULL
, rect
, 0 );
567 wxPropertyGrid
* GetGrid() const
569 wxPropertyGrid
* pg
= wxDynamicCast(GetParent()->GetParent(),
575 virtual wxCoord
OnMeasureItemWidth( size_t item
) const
577 wxPropertyGrid
* pg
= GetGrid();
581 pg
->OnComboItemPaint( this, item
, NULL
, rect
, 0 );
585 virtual void PositionTextCtrl( int WXUNUSED(textCtrlXAdjust
),
586 int WXUNUSED(textCtrlYAdjust
) )
588 wxPropertyGrid
* pg
= GetGrid();
589 wxOwnerDrawnComboBox::PositionTextCtrl(
590 wxPG_TEXTCTRLXADJUST
-
591 (wxPG_XBEFOREWIDGET
+wxPG_CONTROL_MARGIN
+1) - 1,
592 pg
->GetSpacingY() + 2
597 wxPGDoubleClickProcessor
* m_dclickProcessor
;
598 bool m_sizeEventCalled
;
602 void wxPropertyGrid::OnComboItemPaint( const wxPGComboBox
* pCb
,
609 wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid
)) );
611 wxPGProperty
* p
= m_selected
;
614 const wxPGChoices
& choices
= p
->GetChoices();
615 const wxPGCommonValue
* comVal
= NULL
;
616 int comVals
= p
->GetDisplayedCommonValueCount();
617 int comValIndex
= -1;
620 if ( choices
.IsOk() )
621 choiceCount
= choices
.GetCount();
623 if ( item
>= choiceCount
&& comVals
> 0 )
625 comValIndex
= item
- choiceCount
;
626 comVal
= GetCommonValue(comValIndex
);
627 if ( !p
->IsValueUnspecified() )
628 text
= comVal
->GetLabel();
632 if ( !(flags
& wxODCB_PAINTING_CONTROL
) )
634 text
= pCb
->GetString(item
);
638 if ( !p
->IsValueUnspecified() )
639 text
= p
->GetValueAsString(0);
648 const wxBitmap
* itemBitmap
= NULL
;
650 if ( item
>= 0 && choices
.IsOk() && choices
.Item(item
).GetBitmap().Ok() && comValIndex
== -1 )
651 itemBitmap
= &choices
.Item(item
).GetBitmap();
654 // Decide what custom image size to use
657 cis
.x
= itemBitmap
->GetWidth();
658 cis
.y
= itemBitmap
->GetHeight();
662 cis
= GetImageSize(p
, item
);
667 // Default measure behaviour (no flexible, custom paint image only)
668 if ( rect
.width
< 0 )
671 GetTextExtent(text
, &x
, &y
, 0, 0, &m_font
);
672 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9 + x
;
675 rect
.height
= cis
.y
+ 2;
679 wxPGPaintData paintdata
;
680 paintdata
.m_parent
= NULL
;
681 paintdata
.m_choiceItem
= item
;
683 // This is by the current (1.0.0b) spec - if painting control, item is -1
684 if ( (flags
& wxODCB_PAINTING_CONTROL
) )
685 paintdata
.m_choiceItem
= -1;
688 pDc
->SetBrush(*wxWHITE_BRUSH
);
696 wxPoint
pt(rect
.x
+ wxPG_CONTROL_MARGIN
- wxPG_CHOICEXADJUST
- 1,
699 int renderFlags
= wxPGCellRenderer::DontUseCellColours
;
701 if ( flags
& wxODCB_PAINTING_CONTROL
)
702 renderFlags
|= wxPGCellRenderer::Control
;
704 renderFlags
|= wxPGCellRenderer::ChoicePopup
;
706 if ( flags
& wxODCB_PAINTING_SELECTED
)
707 renderFlags
|= wxPGCellRenderer::Selected
;
709 if ( cis
.x
> 0 && (p
->HasFlag(wxPG_PROP_CUSTOMIMAGE
) || !(flags
& wxODCB_PAINTING_CONTROL
)) &&
710 ( !p
->m_valueBitmap
|| item
== pCb
->GetSelection() ) &&
711 ( item
>= 0 || (flags
& wxODCB_PAINTING_CONTROL
) ) &&
715 pt
.x
+= wxCC_CUSTOM_IMAGE_MARGIN1
;
716 wxRect
r(pt
.x
,pt
.y
,cis
.x
,cis
.y
);
718 if ( flags
& wxODCB_PAINTING_CONTROL
)
721 r
.height
= wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
);
724 paintdata
.m_drawnWidth
= r
.width
;
726 dc
.SetPen(m_colPropFore
);
727 if ( comValIndex
>= 0 )
729 const wxPGCommonValue
* cv
= GetCommonValue(comValIndex
);
730 wxPGCellRenderer
* renderer
= cv
->GetRenderer();
731 r
.width
= rect
.width
;
732 renderer
->Render( dc
, r
, this, p
, m_selColumn
, comValIndex
, renderFlags
);
735 else if ( item
>= 0 )
737 p
->OnCustomPaint( dc
, r
, paintdata
);
741 dc
.DrawRectangle( r
);
744 pt
.x
+= paintdata
.m_drawnWidth
+ wxCC_CUSTOM_IMAGE_MARGIN2
- 1;
748 // TODO: This aligns text so that it seems to be horizontally
749 // on the same line as property values. Not really
750 // sure if its needed, but seems to not cause any harm.
753 if ( item
< 0 && (flags
& wxODCB_PAINTING_CONTROL
) )
754 item
= pCb
->GetSelection();
756 if ( choices
.IsOk() && item
>= 0 && comValIndex
< 0 )
758 const wxPGChoiceEntry
& cell
= choices
.Item(item
);
759 wxPGCellRenderer
* renderer
= wxPGGlobalVars
->m_defaultRenderer
;
760 int imageOffset
= renderer
->PreDrawCell( dc
, rect
, cell
, renderFlags
);
762 imageOffset
+= wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
;
771 pt
.y
+= (rect
.height
-m_fontHeight
)/2 - 1;
775 dc
.DrawText( text
, pt
.x
+ wxPG_XBEFORETEXT
, pt
.y
);
783 p
->OnCustomPaint( dc
, rect
, paintdata
);
784 rect
.height
= paintdata
.m_drawnHeight
+ 2;
785 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9;
789 bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid
* propGrid
, wxPGComboBox
* cb
, int cmnVal
)
791 wxPGProperty
* property
= propGrid
->GetSelectedProperty();
792 wxASSERT( property
);
796 // Yes, a common value is being selected
797 property
->SetCommonValue( cmnVal
);
798 wxSize imageSize
= propGrid
->GetCommonValue(cmnVal
)->
799 GetRenderer()->GetImageSize(property
, 1, cmnVal
);
800 if ( imageSize
.x
) imageSize
.x
+= ODCB_CUST_PAINT_MARGIN
;
801 cb
->SetCustomPaintWidth( imageSize
.x
);
806 wxSize imageSize
= propGrid
->GetImageSize(property
, -1);
807 if ( imageSize
.x
) imageSize
.x
+= ODCB_CUST_PAINT_MARGIN
;
808 cb
->SetCustomPaintWidth( imageSize
.x
);
813 // CreateControls calls this with CB_READONLY in extraStyle
814 wxWindow
* wxPGChoiceEditor::CreateControlsBase( wxPropertyGrid
* propGrid
,
815 wxPGProperty
* property
,
818 long extraStyle
) const
820 const wxPGChoices
& choices
= property
->GetChoices();
822 int index
= property
->GetChoiceSelection();
824 bool isUnspecified
= property
->IsValueUnspecified();
826 if ( !isUnspecified
)
827 defString
= property
->GetDisplayedString();
829 wxArrayString labels
= choices
.GetLabels();
835 po
.y
+= wxPG_CHOICEYADJUST
;
836 si
.y
-= (wxPG_CHOICEYADJUST
*2);
838 po
.x
+= wxPG_CHOICEXADJUST
;
839 si
.x
-= wxPG_CHOICEXADJUST
;
840 wxWindow
* ctrlParent
= propGrid
->GetPanel();
842 int odcbFlags
= extraStyle
| wxBORDER_NONE
| wxTE_PROCESS_ENTER
;
845 // If common value specified, use appropriate index
846 unsigned int cmnVals
= property
->GetDisplayedCommonValueCount();
849 if ( !isUnspecified
)
851 int cmnVal
= property
->GetCommonValue();
854 index
= labels
.size() + cmnVal
;
859 for ( i
=0; i
<cmnVals
; i
++ )
860 labels
.Add(propGrid
->GetCommonValueLabel(i
));
863 cb
= new wxPGComboBox();
867 cb
->Create(ctrlParent
,
875 cb
->SetButtonPosition(si
.y
,0,wxRIGHT
);
876 cb
->SetTextIndent(wxPG_XBEFORETEXT
-1);
878 wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
, property
->GetCommonValue() );
880 if ( index
>= 0 && index
< (int)cb
->GetCount() )
882 cb
->SetSelection( index
);
883 if ( defString
.length() )
884 cb
->SetText( defString
);
886 else if ( !(extraStyle
& wxCB_READONLY
) && defString
.length() )
887 cb
->SetValue( defString
);
889 cb
->SetSelection( -1 );
895 return (wxWindow
*) cb
;
899 void wxPGChoiceEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
902 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
903 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
904 int ind
= property
->GetChoiceSelection();
905 cb
->SetSelection(ind
);
908 wxPGWindowList
wxPGChoiceEditor::CreateControls( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
909 const wxPoint
& pos
, const wxSize
& sz
) const
911 return CreateControlsBase(propGrid
,property
,pos
,sz
,wxCB_READONLY
);
915 int wxPGChoiceEditor::InsertItem( wxWindow
* ctrl
, const wxString
& label
, int index
) const
918 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
919 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
922 index
= cb
->GetCount();
924 return cb
->Insert(label
,index
);
928 void wxPGChoiceEditor::DeleteItem( wxWindow
* ctrl
, int index
) const
931 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
932 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
937 bool wxPGChoiceEditor::OnEvent( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
938 wxWindow
* ctrl
, wxEvent
& event
) const
940 if ( event
.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED
)
942 wxPGComboBox
* cb
= (wxPGComboBox
*)ctrl
;
943 int index
= cb
->GetSelection();
944 int cmnValIndex
= -1;
945 int cmnVals
= property
->GetDisplayedCommonValueCount();
946 int items
= cb
->GetCount();
948 if ( index
>= (items
-cmnVals
) )
950 // Yes, a common value is being selected
951 cmnValIndex
= index
- (items
-cmnVals
);
952 property
->SetCommonValue( cmnValIndex
);
954 // Truly set value to unspecified?
955 if ( propGrid
->GetUnspecifiedCommonValue() == cmnValIndex
)
957 if ( !property
->IsValueUnspecified() )
958 propGrid
->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT
);
959 property
->SetValueToUnspecified();
960 if ( !cb
->HasFlag(wxCB_READONLY
) )
961 cb
->GetTextCtrl()->SetValue(wxEmptyString
);
965 return wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
, cmnValIndex
);
971 bool wxPGChoiceEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
973 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
975 int index
= cb
->GetSelection();
977 if ( index
!= property
->GetChoiceSelection() ||
978 // Changing unspecified always causes event (returning
979 // true here should be enough to trigger it).
980 property
->IsValueUnspecified()
983 return property
->IntToValue( variant
, index
, 0 );
989 void wxPGChoiceEditor::SetControlStringValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, const wxString
& txt
) const
991 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
997 void wxPGChoiceEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
999 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1001 cb
->SetSelection(value
);
1005 void wxPGChoiceEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
) const
1007 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1008 cb
->SetSelection(-1);
1012 bool wxPGChoiceEditor::CanContainCustomImage() const
1018 wxPGChoiceEditor::~wxPGChoiceEditor() { }
1021 // -----------------------------------------------------------------------
1022 // wxPGComboBoxEditor
1023 // -----------------------------------------------------------------------
1026 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ComboBox
,
1031 void wxPGComboBoxEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1033 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1034 cb
->SetValue(property
->GetValueAsString(wxPG_EDITABLE_VALUE
));
1036 // TODO: If string matches any selection, then select that.
1040 wxPGWindowList
wxPGComboBoxEditor::CreateControls( wxPropertyGrid
* propGrid
,
1041 wxPGProperty
* property
,
1043 const wxSize
& sz
) const
1045 return CreateControlsBase(propGrid
,property
,pos
,sz
,0);
1049 bool wxPGComboBoxEditor::OnEvent( wxPropertyGrid
* propGrid
,
1050 wxPGProperty
* property
,
1052 wxEvent
& event
) const
1054 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*) NULL
;
1055 wxWindow
* textCtrl
= (wxWindow
*) NULL
;
1059 cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1060 textCtrl
= cb
->GetTextCtrl();
1063 if ( wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid
,property
,textCtrl
,event
) )
1066 return wxPGChoiceEditor::OnEvent(propGrid
,property
,ctrl
,event
);
1070 bool wxPGComboBoxEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1072 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1073 wxString textVal
= cb
->GetValue();
1075 if ( property
->UsesAutoUnspecified() && !textVal
.length() )
1081 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
1083 // Changing unspecified always causes event (returning
1084 // true here should be enough to trigger it).
1085 if ( !res
&& variant
.IsNull() )
1092 void wxPGComboBoxEditor::OnFocus( wxPGProperty
*, wxWindow
* ctrl
) const
1094 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1095 cb
->GetTextCtrl()->SetSelection(-1,-1);
1099 wxPGComboBoxEditor::~wxPGComboBoxEditor() { }
1102 // -----------------------------------------------------------------------
1103 // wxPGChoiceAndButtonEditor
1104 // -----------------------------------------------------------------------
1107 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ChoiceAndButton
,
1108 wxPGChoiceAndButtonEditor
,
1112 wxPGWindowList
wxPGChoiceAndButtonEditor::CreateControls( wxPropertyGrid
* propGrid
,
1113 wxPGProperty
* property
,
1115 const wxSize
& sz
) const
1117 // Use one two units smaller to match size of the combo's dropbutton.
1118 // (normally a bigger button is used because it looks better)
1121 wxSize
bt_sz(bt_wid
,bt_wid
);
1123 // Position of button.
1124 wxPoint
bt_pos(pos
.x
+sz
.x
-bt_sz
.x
,pos
.y
);
1131 wxWindow
* bt
= propGrid
->GenerateEditorButton( bt_pos
, bt_sz
);
1134 wxSize
ch_sz(sz
.x
-bt
->GetSize().x
,sz
.y
);
1137 ch_sz
.x
-= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1140 wxWindow
* ch
= wxPGEditor_Choice
->CreateControls(propGrid
,property
,
1141 pos
,ch_sz
).m_primary
;
1147 return wxPGWindowList(ch
, bt
);
1151 wxPGChoiceAndButtonEditor::~wxPGChoiceAndButtonEditor() { }
1154 // -----------------------------------------------------------------------
1155 // wxPGTextCtrlAndButtonEditor
1156 // -----------------------------------------------------------------------
1158 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrlAndButton
,
1159 wxPGTextCtrlAndButtonEditor
,
1163 wxPGWindowList
wxPGTextCtrlAndButtonEditor::CreateControls( wxPropertyGrid
* propGrid
,
1164 wxPGProperty
* property
,
1166 const wxSize
& sz
) const
1169 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrlAndButton( pos
, sz
, &wnd2
,
1170 property
->GetFlags() & wxPG_PROP_NOEDITOR
, property
);
1172 return wxPGWindowList(wnd
, wnd2
);
1176 wxPGTextCtrlAndButtonEditor::~wxPGTextCtrlAndButtonEditor() { }
1179 // -----------------------------------------------------------------------
1180 // wxPGCheckBoxEditor
1181 // -----------------------------------------------------------------------
1183 #if wxPG_INCLUDE_CHECKBOX
1185 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(CheckBox
,
1190 // Check box state flags
1193 wxSCB_STATE_UNCHECKED
= 0,
1194 wxSCB_STATE_CHECKED
= 1,
1195 wxSCB_STATE_BOLD
= 2,
1196 wxSCB_STATE_UNSPECIFIED
= 4
1199 const int wxSCB_SETVALUE_CYCLE
= 2;
1202 static void DrawSimpleCheckBox( wxDC
& dc
, const wxRect
& rect
, int box_hei
,
1203 int state
, const wxColour
& lineCol
)
1206 wxRect
r(rect
.x
+wxPG_XBEFORETEXT
,rect
.y
+((rect
.height
-box_hei
)/2),
1208 wxColour useCol
= lineCol
;
1210 if ( state
& wxSCB_STATE_UNSPECIFIED
)
1212 useCol
= wxColour(220, 220, 220);
1215 // Draw check mark first because it is likely to overdraw the
1216 // surrounding rectangle.
1217 if ( state
& wxSCB_STATE_CHECKED
)
1219 wxRect
r2(r
.x
+wxPG_CHECKMARK_XADJ
,
1220 r
.y
+wxPG_CHECKMARK_YADJ
,
1221 r
.width
+wxPG_CHECKMARK_WADJ
,
1222 r
.height
+wxPG_CHECKMARK_HADJ
);
1223 #if wxPG_CHECKMARK_DEFLATE
1224 r2
.Deflate(wxPG_CHECKMARK_DEFLATE
);
1226 dc
.DrawCheckMark(r2
);
1228 // This would draw a simple cross check mark.
1229 // dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
1230 // dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
1233 if ( !(state
& wxSCB_STATE_BOLD
) )
1235 // Pen for thin rectangle.
1240 // Pen for bold rectangle.
1241 wxPen
linepen(useCol
,2,wxSOLID
);
1242 linepen
.SetJoin(wxJOIN_MITER
); // This prevents round edges.
1250 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1252 dc
.DrawRectangle(r
);
1253 dc
.SetPen(*wxTRANSPARENT_PEN
);
1257 // Real simple custom-drawn checkbox-without-label class.
1259 class wxSimpleCheckBox
: public wxControl
1263 void SetValue( int value
);
1265 wxSimpleCheckBox( wxWindow
* parent
,
1267 const wxPoint
& pos
= wxDefaultPosition
,
1268 const wxSize
& size
= wxDefaultSize
)
1269 : wxControl(parent
,id
,pos
,size
,wxBORDER_NONE
|wxWANTS_CHARS
)
1271 // Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
1272 SetFont( parent
->GetFont() );
1277 SetBackgroundStyle( wxBG_STYLE_CUSTOM
);
1280 virtual ~wxSimpleCheckBox();
1286 void OnPaint( wxPaintEvent
& event
);
1287 void OnLeftClick( wxMouseEvent
& event
);
1288 void OnKeyDown( wxKeyEvent
& event
);
1290 void OnResize( wxSizeEvent
& event
)
1296 static wxBitmap
* ms_doubleBuffer
;
1298 DECLARE_EVENT_TABLE()
1301 BEGIN_EVENT_TABLE(wxSimpleCheckBox
, wxControl
)
1302 EVT_PAINT(wxSimpleCheckBox::OnPaint
)
1303 EVT_LEFT_DOWN(wxSimpleCheckBox::OnLeftClick
)
1304 EVT_LEFT_DCLICK(wxSimpleCheckBox::OnLeftClick
)
1305 EVT_KEY_DOWN(wxSimpleCheckBox::OnKeyDown
)
1306 EVT_SIZE(wxSimpleCheckBox::OnResize
)
1309 wxSimpleCheckBox::~wxSimpleCheckBox()
1311 delete ms_doubleBuffer
;
1312 ms_doubleBuffer
= NULL
;
1315 wxBitmap
* wxSimpleCheckBox::ms_doubleBuffer
= (wxBitmap
*) NULL
;
1317 void wxSimpleCheckBox::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1319 wxSize clientSize
= GetClientSize();
1320 wxAutoBufferedPaintDC
dc(this);
1323 wxRect
rect(0,0,clientSize
.x
,clientSize
.y
);
1327 wxColour bgcol
= GetBackgroundColour();
1328 dc
.SetBrush( bgcol
);
1330 dc
.DrawRectangle( rect
);
1332 wxColour txcol
= GetForegroundColour();
1334 int state
= m_state
;
1335 if ( !(state
& wxSCB_STATE_UNSPECIFIED
) &&
1336 m_font
.GetWeight() == wxBOLD
)
1337 state
|= wxSCB_STATE_BOLD
;
1339 DrawSimpleCheckBox(dc
,rect
,m_boxHeight
,state
,txcol
);
1342 void wxSimpleCheckBox::OnLeftClick( wxMouseEvent
& event
)
1344 if ( (event
.m_x
> (wxPG_XBEFORETEXT
-2)) &&
1345 (event
.m_x
<= (wxPG_XBEFORETEXT
-2+m_boxHeight
)) )
1347 SetValue(wxSCB_SETVALUE_CYCLE
);
1351 void wxSimpleCheckBox::OnKeyDown( wxKeyEvent
& event
)
1353 if ( event
.GetKeyCode() == WXK_SPACE
)
1355 SetValue(wxSCB_SETVALUE_CYCLE
);
1359 void wxSimpleCheckBox::SetValue( int value
)
1361 if ( value
== wxSCB_SETVALUE_CYCLE
)
1363 if ( m_state
& wxSCB_STATE_CHECKED
)
1364 m_state
&= ~wxSCB_STATE_CHECKED
;
1366 m_state
|= wxSCB_STATE_CHECKED
;
1374 wxCommandEvent
evt(wxEVT_COMMAND_CHECKBOX_CLICKED
,GetParent()->GetId());
1376 wxPropertyGrid
* propGrid
= (wxPropertyGrid
*) GetParent()->GetParent();
1377 wxASSERT( propGrid
->IsKindOf(CLASSINFO(wxPropertyGrid
)) );
1378 propGrid
->HandleCustomEditorEvent(evt
);
1381 wxPGWindowList
wxPGCheckBoxEditor::CreateControls( wxPropertyGrid
* propGrid
,
1382 wxPGProperty
* property
,
1384 const wxSize
& size
) const
1387 pt
.x
-= wxPG_XBEFOREWIDGET
;
1389 sz
.x
= propGrid
->GetFontHeight() + (wxPG_XBEFOREWIDGET
*2) + 4;
1391 wxSimpleCheckBox
* cb
= new wxSimpleCheckBox(propGrid
->GetPanel(),
1392 wxPG_SUBID1
, pt
, sz
);
1394 cb
->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
1396 UpdateControl(property
, cb
);
1398 if ( !property
->IsValueUnspecified() )
1400 // If mouse cursor was on the item, toggle the value now.
1401 if ( propGrid
->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK
)
1403 wxPoint pt
= cb
->ScreenToClient(::wxGetMousePosition());
1404 if ( pt
.x
<= (wxPG_XBEFORETEXT
-2+cb
->m_boxHeight
) )
1406 if ( cb
->m_state
& wxSCB_STATE_CHECKED
)
1407 cb
->m_state
&= ~wxSCB_STATE_CHECKED
;
1409 cb
->m_state
|= wxSCB_STATE_CHECKED
;
1411 // Makes sure wxPG_EVT_CHANGING etc. is sent for this initial
1413 propGrid
->ChangePropertyValue(property
,
1414 wxPGVariant_Bool(cb
->m_state
));
1419 propGrid
->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR
);
1424 void wxPGCheckBoxEditor::DrawValue( wxDC
& dc
, const wxRect
& rect
,
1425 wxPGProperty
* property
,
1426 const wxString
& WXUNUSED(text
) ) const
1428 int state
= wxSCB_STATE_UNCHECKED
;
1429 wxColour rectCol
= dc
.GetTextForeground();
1431 if ( !property
->IsValueUnspecified() )
1433 state
= property
->GetChoiceSelection();
1434 if ( dc
.GetFont().GetWeight() == wxBOLD
)
1435 state
|= wxSCB_STATE_BOLD
;
1439 state
|= wxSCB_STATE_UNSPECIFIED
;
1442 DrawSimpleCheckBox(dc
, rect
, dc
.GetCharHeight(), state
, rectCol
);
1445 void wxPGCheckBoxEditor::UpdateControl( wxPGProperty
* property
,
1446 wxWindow
* ctrl
) const
1448 wxSimpleCheckBox
* cb
= (wxSimpleCheckBox
*) ctrl
;
1451 if ( !property
->IsValueUnspecified() )
1452 cb
->m_state
= property
->GetChoiceSelection();
1454 cb
->m_state
= wxSCB_STATE_UNSPECIFIED
;
1456 wxPropertyGrid
* propGrid
= property
->GetGrid();
1457 cb
->m_boxHeight
= propGrid
->GetFontHeight();
1462 bool wxPGCheckBoxEditor::OnEvent( wxPropertyGrid
* WXUNUSED(propGrid
), wxPGProperty
* WXUNUSED(property
),
1463 wxWindow
* WXUNUSED(ctrl
), wxEvent
& event
) const
1465 if ( event
.GetEventType() == wxEVT_COMMAND_CHECKBOX_CLICKED
)
1473 bool wxPGCheckBoxEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1475 wxSimpleCheckBox
* cb
= (wxSimpleCheckBox
*)ctrl
;
1477 int index
= cb
->m_state
;
1479 if ( index
!= property
->GetChoiceSelection() ||
1480 // Changing unspecified always causes event (returning
1481 // true here should be enough to trigger it).
1482 property
->IsValueUnspecified()
1485 return property
->IntToValue(variant
, index
, 0);
1491 void wxPGCheckBoxEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
1493 if ( value
!= 0 ) value
= 1;
1494 ((wxSimpleCheckBox
*)ctrl
)->m_state
= value
;
1499 void wxPGCheckBoxEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
) const
1501 ((wxSimpleCheckBox
*)ctrl
)->m_state
= 0;
1506 wxPGCheckBoxEditor::~wxPGCheckBoxEditor() { }
1509 #endif // wxPG_INCLUDE_CHECKBOX
1511 // -----------------------------------------------------------------------
1513 wxWindow
* wxPropertyGrid::GetEditorControl() const
1515 wxWindow
* ctrl
= m_wndEditor
;
1523 // -----------------------------------------------------------------------
1525 void wxPropertyGrid::CorrectEditorWidgetSizeX()
1527 if ( m_selColumn
== -1 )
1531 int newSplitterx
= m_pState
->DoGetSplitterPosition(m_selColumn
-1);
1532 int newWidth
= newSplitterx
+ m_pState
->m_colWidths
[m_selColumn
];
1536 // if width change occurred, move secondary wnd by that amount
1537 wxRect r
= m_wndEditor2
->GetRect();
1539 r
.x
= newWidth
- secWid
;
1541 m_wndEditor2
->SetSize( r
);
1543 // if primary is textctrl, then we have to add some extra space
1547 if ( m_wndEditor
&& m_wndEditor
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
1549 secWid
+= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1554 wxRect r
= m_wndEditor
->GetRect();
1556 r
.x
= newSplitterx
+m_ctrlXAdjust
;
1558 if ( !(m_iFlags
& wxPG_FL_FIXED_WIDTH_EDITOR
) )
1559 r
.width
= newWidth
- r
.x
- secWid
;
1561 m_wndEditor
->SetSize(r
);
1565 m_wndEditor2
->Refresh();
1568 // -----------------------------------------------------------------------
1570 void wxPropertyGrid::CorrectEditorWidgetPosY()
1572 if ( m_selColumn
== -1 )
1575 if ( m_selected
&& (m_wndEditor
|| m_wndEditor2
) )
1577 wxRect r
= GetEditorWidgetRect(m_selected
, m_selColumn
);
1581 wxPoint pos
= m_wndEditor
->GetPosition();
1583 // Calculate y offset
1584 int offset
= pos
.y
% m_lineHeight
;
1586 m_wndEditor
->Move(pos
.x
, r
.y
+ offset
);
1591 wxPoint pos
= m_wndEditor2
->GetPosition();
1593 m_wndEditor2
->Move(pos
.x
, r
.y
);
1598 // -----------------------------------------------------------------------
1600 // Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
1601 // fits into that category as well).
1602 void wxPropertyGrid::FixPosForTextCtrl( wxWindow
* ctrl
, const wxPoint
& offset
)
1604 // Center the control vertically
1605 wxRect finalPos
= ctrl
->GetRect();
1606 int y_adj
= (m_lineHeight
- finalPos
.height
)/2 + wxPG_TEXTCTRLYADJUST
;
1608 // Prevent over-sized control
1609 int sz_dec
= (y_adj
+ finalPos
.height
) - m_lineHeight
;
1610 if ( sz_dec
< 0 ) sz_dec
= 0;
1612 finalPos
.y
+= y_adj
;
1613 finalPos
.height
-= (y_adj
+sz_dec
);
1615 const int textCtrlXAdjust
= wxPG_TEXTCTRLXADJUST
;
1617 finalPos
.x
+= textCtrlXAdjust
;
1618 finalPos
.width
-= textCtrlXAdjust
;
1620 finalPos
.x
+= offset
.x
;
1621 finalPos
.y
+= offset
.y
;
1623 ctrl
->SetSize(finalPos
);
1626 // -----------------------------------------------------------------------
1628 wxWindow
* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint
& pos
,
1630 const wxString
& value
,
1631 wxWindow
* secondary
,
1635 wxWindowID id
= wxPG_SUBID1
;
1636 wxPGProperty
* selected
= m_selected
;
1639 int tcFlags
= wxTE_PROCESS_ENTER
| extraStyle
;
1641 if ( selected
->HasFlag(wxPG_PROP_READONLY
) )
1642 tcFlags
|= wxTE_READONLY
;
1644 wxPoint
p(pos
.x
,pos
.y
);
1645 wxSize
s(sz
.x
,sz
.y
);
1647 // Need to reduce width of text control on Mac
1648 #if defined(__WXMAC__)
1652 // Take button into acccount
1655 s
.x
-= (secondary
->GetSize().x
+ wxPG_TEXTCTRL_AND_BUTTON_SPACING
);
1656 m_iFlags
&= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE
);
1659 // If the height is significantly higher, then use border, and fill the rect exactly.
1660 bool hasSpecialSize
= false;
1662 if ( (sz
.y
- m_lineHeight
) > 5 )
1663 hasSpecialSize
= true;
1665 wxWindow
* ctrlParent
= GetPanel();
1667 if ( !hasSpecialSize
)
1668 tcFlags
|= wxBORDER_NONE
;
1670 wxTextCtrl
* tc
= new wxTextCtrl();
1672 #if defined(__WXMSW__)
1675 SetupTextCtrlValue(value
);
1676 tc
->Create(ctrlParent
,id
,value
, p
, s
,tcFlags
);
1680 // Center the control vertically
1681 if ( !hasSpecialSize
)
1682 FixPosForTextCtrl(ed
);
1690 // Set maximum length
1692 tc
->SetMaxLength( maxLen
);
1694 return (wxWindow
*) ed
;
1697 // -----------------------------------------------------------------------
1699 wxWindow
* wxPropertyGrid::GenerateEditorButton( const wxPoint
& pos
, const wxSize
& sz
)
1701 wxWindowID id
= wxPG_SUBID2
;
1702 wxPGProperty
* selected
= m_selected
;
1706 // Decorations are chunky on Mac, and we can't make the button square, so
1707 // do things a bit differently on this platform.
1709 wxPoint
p(pos
.x
+sz
.x
,
1710 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
1713 wxButton
* but
= new wxButton();
1714 but
->Create(GetPanel(),id
,wxS("..."),p
,s
,wxWANTS_CHARS
);
1716 // Now that we know the size, move to the correct position
1717 p
.x
= pos
.x
+ sz
.x
- but
->GetSize().x
- 2;
1721 wxSize
s(sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2),
1722 sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2));
1724 // Reduce button width to lineheight
1725 if ( s
.x
> m_lineHeight
)
1729 // On wxGTK, take fixed button margins into account
1734 wxPoint
p(pos
.x
+sz
.x
-s
.x
,
1735 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
1737 wxButton
* but
= new wxButton();
1741 but
->Create(GetPanel(),id
,wxS("..."),p
,s
,wxWANTS_CHARS
);
1744 wxFont font
= GetFont();
1745 font
.SetPointSize(font
.GetPointSize()-2);
1748 but
->SetFont(GetFont());
1752 if ( selected
->HasFlag(wxPG_PROP_READONLY
) )
1758 // -----------------------------------------------------------------------
1760 wxWindow
* wxPropertyGrid::GenerateEditorTextCtrlAndButton( const wxPoint
& pos
,
1762 wxWindow
** psecondary
,
1764 wxPGProperty
* property
)
1766 wxButton
* but
= (wxButton
*)GenerateEditorButton(pos
,sz
);
1767 *psecondary
= (wxWindow
*)but
;
1769 if ( limitedEditing
)
1772 // There is button Show in GenerateEditorTextCtrl as well
1775 return (wxWindow
*) NULL
;
1780 if ( !property
->IsValueUnspecified() )
1781 text
= property
->GetValueAsString(property
->HasFlag(wxPG_PROP_READONLY
)?0:wxPG_EDITABLE_VALUE
);
1783 return GenerateEditorTextCtrl(pos
,sz
,text
,but
,property
->m_maxLen
);
1786 // -----------------------------------------------------------------------
1788 wxTextCtrl
* wxPropertyGrid::GetEditorTextCtrl() const
1790 wxWindow
* wnd
= GetEditorControl();
1795 if ( wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
1796 return wxStaticCast(wnd
, wxTextCtrl
);
1798 if ( wnd
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) )
1800 wxOwnerDrawnComboBox
* cb
= wxStaticCast(wnd
, wxOwnerDrawnComboBox
);
1801 return cb
->GetTextCtrl();
1807 // -----------------------------------------------------------------------
1809 wxPGEditor
* wxPropertyGridInterface::GetEditorByName( const wxString
& editorName
)
1811 wxPGHashMapS2P::const_iterator it
;
1813 it
= wxPGGlobalVars
->m_mapEditorClasses
.find(editorName
);
1814 if ( it
== wxPGGlobalVars
->m_mapEditorClasses
.end() )
1816 return (wxPGEditor
*) it
->second
;
1819 // -----------------------------------------------------------------------
1820 // wxPGEditorDialogAdapter
1821 // -----------------------------------------------------------------------
1823 IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter
, wxObject
)
1825 bool wxPGEditorDialogAdapter::ShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1827 if ( !propGrid
->EditorValidate() )
1830 bool res
= DoShowDialog( propGrid
, property
);
1834 propGrid
->ValueChangeInEvent( m_value
);
1841 // -----------------------------------------------------------------------
1843 // -----------------------------------------------------------------------
1845 wxPGMultiButton::wxPGMultiButton( wxPropertyGrid
* pg
, const wxSize
& sz
)
1846 : wxWindow( pg
->GetPanel(), wxPG_SUBID2
, wxPoint(-100,-100), wxSize(0, sz
.y
) ),
1847 m_fullEditorSize(sz
), m_buttonsWidth(0)
1849 SetBackgroundColour(pg
->GetCellBackgroundColour());
1852 void wxPGMultiButton::Finalize( wxPropertyGrid
* WXUNUSED(propGrid
),
1853 const wxPoint
& pos
)
1855 Move( pos
.x
+ m_fullEditorSize
.x
- m_buttonsWidth
, pos
.y
);
1858 int wxPGMultiButton::GenId( int id
) const
1862 if ( m_buttons
.size() )
1863 id
= GetButton(m_buttons
.size()-1)->GetId() + 1;
1871 void wxPGMultiButton::Add( const wxBitmap
& bitmap
, int id
)
1874 wxSize sz
= GetSize();
1875 wxButton
* button
= new wxBitmapButton( this, id
, bitmap
, wxPoint(sz
.x
, 0), wxSize(sz
.y
, sz
.y
) );
1876 m_buttons
.push_back(button
);
1877 int bw
= button
->GetSize().x
;
1878 SetSize(wxSize(sz
.x
+bw
,sz
.y
));
1879 m_buttonsWidth
+= bw
;
1883 void wxPGMultiButton::Add( const wxString
& label
, int id
)
1886 wxSize sz
= GetSize();
1887 wxButton
* button
= new wxButton( this, id
, label
, wxPoint(sz
.x
, 0), wxSize(sz
.y
, sz
.y
) );
1888 m_buttons
.push_back(button
);
1889 int bw
= button
->GetSize().x
;
1890 SetSize(wxSize(sz
.x
+bw
,sz
.y
));
1891 m_buttonsWidth
+= bw
;
1894 // -----------------------------------------------------------------------
1896 #endif // wxUSE_PROPGRID