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 8
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 3
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
145 #define wxPG_CHOICEXADJUST 0
146 #define wxPG_CHOICEYADJUST 0
148 #define ODCB_CUST_PAINT_MARGIN 6 // Number added to image width for SetCustomPaintWidth
150 // Milliseconds to wait for two mouse-ups after focus inorder
151 // to trigger a double-click.
152 #define DOUBLE_CLICK_CONVERSION_TRESHOLD 500
154 // -----------------------------------------------------------------------
156 // -----------------------------------------------------------------------
158 IMPLEMENT_ABSTRACT_CLASS(wxPGEditor
, wxObject
)
161 wxPGEditor::~wxPGEditor()
165 wxString
wxPGEditor::GetName() const
167 return GetClassInfo()->GetClassName();
170 void wxPGEditor::DrawValue( wxDC
& dc
, const wxRect
& rect
, wxPGProperty
* property
, const wxString
& text
) const
172 if ( !property
->IsValueUnspecified() )
173 dc
.DrawText( text
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
176 bool wxPGEditor::GetValueFromControl( wxVariant
&, wxPGProperty
*, wxWindow
* ) const
181 void wxPGEditor::SetControlStringValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, const wxString
& ) const
186 void wxPGEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, int ) const
191 int wxPGEditor::InsertItem( wxWindow
*, const wxString
&, int ) const
197 void wxPGEditor::DeleteItem( wxWindow
*, int ) const
203 void wxPGEditor::OnFocus( wxPGProperty
*, wxWindow
* ) const
208 bool wxPGEditor::CanContainCustomImage() const
213 // -----------------------------------------------------------------------
214 // wxPGTextCtrlEditor
215 // -----------------------------------------------------------------------
217 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrl
,wxPGTextCtrlEditor
,wxPGEditor
)
220 wxPGWindowList
wxPGTextCtrlEditor::CreateControls( wxPropertyGrid
* propGrid
,
221 wxPGProperty
* property
,
223 const wxSize
& sz
) const
228 // If has children, and limited editing is specified, then don't create.
229 if ( (property
->GetFlags() & wxPG_PROP_NOEDITOR
) &&
230 property
->GetChildCount() )
231 return (wxWindow
*) NULL
;
233 if ( !property
->IsValueUnspecified() )
234 text
= property
->GetValueString(property
->HasFlag(wxPG_PROP_READONLY
)?0:wxPG_EDITABLE_VALUE
);
237 if ( (property
->GetFlags() & wxPG_PROP_PASSWORD
) &&
238 property
->IsKindOf(CLASSINFO(wxStringProperty
)) )
239 flags
|= wxTE_PASSWORD
;
241 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrl(pos
,sz
,text
,(wxWindow
*)NULL
,flags
,
242 property
->GetMaxLength());
248 void wxPGTextCtrlEditor::DrawValue( wxDC
& dc
, wxPGProperty
* property
, const wxRect
& rect
) const
250 if ( !property
->IsValueUnspecified() )
252 wxString drawStr
= property
->GetDisplayedString();
254 // Code below should no longer be needed, as the obfuscation
255 // is now done in GetValueAsString.
256 /*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
257 property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
259 size_t a = drawStr.length();
261 drawStr.Append(wxS('*'),a);
263 dc
.DrawText( drawStr
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
268 void wxPGTextCtrlEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
270 wxTextCtrl
* tc
= wxDynamicCast(ctrl
, wxTextCtrl
);
275 if ( tc
->HasFlag(wxTE_PASSWORD
) )
276 s
= property
->GetValueAsString(wxPG_FULL_VALUE
);
278 s
= property
->GetDisplayedString();
284 // Provided so that, for example, ComboBox editor can use the same code
285 // (multiple inheritance would get way too messy).
286 bool wxPGTextCtrlEditor::OnTextCtrlEvent( wxPropertyGrid
* propGrid
,
287 wxPGProperty
* WXUNUSED(property
),
294 if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER
)
296 if ( propGrid
->IsEditorsValueModified() )
301 else if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED
)
304 // Pass this event outside wxPropertyGrid so that,
305 // if necessary, program can tell when user is editing
307 // FIXME: Is it safe to change event id in the middle of event
308 // processing (seems to work, but...)?
310 event
.SetId(propGrid
->GetId());
312 propGrid
->EditorsValueWasModified();
318 bool wxPGTextCtrlEditor::OnEvent( wxPropertyGrid
* propGrid
,
319 wxPGProperty
* property
,
321 wxEvent
& event
) const
323 return wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid
,property
,ctrl
,event
);
327 bool wxPGTextCtrlEditor::GetTextCtrlValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
)
329 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
330 wxString textVal
= tc
->GetValue();
332 if ( property
->UsesAutoUnspecified() && !textVal
.length() )
338 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
340 // Changing unspecified always causes event (returning
341 // true here should be enough to trigger it).
342 // TODO: Move to propgrid.cpp
343 if ( !res
&& variant
.IsNull() )
350 bool wxPGTextCtrlEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
352 return wxPGTextCtrlEditor::GetTextCtrlValueFromControl(variant
, property
, ctrl
);
356 void wxPGTextCtrlEditor::SetValueToUnspecified( wxPGProperty
* property
, wxWindow
* ctrl
) const
358 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
360 wxPropertyGrid
* pg
= property
->GetGrid();
361 wxASSERT(pg
); // Really, property grid should exist if editor does
363 tc
->SetValue(wxEmptyString
);
367 void wxPGTextCtrlEditor::SetControlStringValue( wxPGProperty
* property
, wxWindow
* ctrl
, const wxString
& txt
) const
369 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
371 wxPropertyGrid
* pg
= property
->GetGrid();
372 wxASSERT(pg
); // Really, property grid should exist if editor does
378 void wxPGTextCtrlEditor::OnFocus( wxPGProperty
*, wxWindow
* wnd
) const
380 wxTextCtrl
* tc
= wxStaticCast(wnd
, wxTextCtrl
);
382 tc
->SetSelection(-1,-1);
386 wxPGTextCtrlEditor::~wxPGTextCtrlEditor() { }
389 // -----------------------------------------------------------------------
391 // -----------------------------------------------------------------------
394 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(Choice
,wxPGChoiceEditor
,wxPGEditor
)
397 // This is a special enhanced double-click processor class.
398 // In essence, it allows for double-clicks for which the
399 // first click "created" the control.
400 class wxPGDoubleClickProcessor
: public wxEvtHandler
404 wxPGDoubleClickProcessor( wxOwnerDrawnComboBox
* combo
, wxPGProperty
* property
)
407 m_timeLastMouseUp
= 0;
409 m_property
= property
;
410 m_downReceived
= false;
415 void OnMouseEvent( wxMouseEvent
& event
)
417 wxLongLong t
= ::wxGetLocalTimeMillis();
418 int evtType
= event
.GetEventType();
420 if ( m_property
->HasFlag(wxPG_PROP_USE_DCC
) &&
421 m_property
->IsKindOf(CLASSINFO(wxBoolProperty
)) &&
422 !m_combo
->IsPopupShown() )
424 // Just check that it is in the text area
425 wxPoint pt
= event
.GetPosition();
426 if ( m_combo
->GetTextRect().Contains(pt
) )
428 if ( evtType
== wxEVT_LEFT_DOWN
)
430 // Set value to avoid up-events without corresponding downs
431 m_downReceived
= true;
433 else if ( evtType
== wxEVT_LEFT_DCLICK
)
435 // We'll make our own double-clicks
436 event
.SetEventType(0);
439 else if ( evtType
== wxEVT_LEFT_UP
)
441 if ( m_downReceived
|| m_timeLastMouseUp
== 1 )
443 wxLongLong timeFromLastUp
= (t
-m_timeLastMouseUp
);
445 if ( timeFromLastUp
< DOUBLE_CLICK_CONVERSION_TRESHOLD
)
447 event
.SetEventType(wxEVT_LEFT_DCLICK
);
448 m_timeLastMouseUp
= 1;
452 m_timeLastMouseUp
= t
;
462 void OnSetFocus( wxFocusEvent
& event
)
464 m_timeLastMouseUp
= ::wxGetLocalTimeMillis();
469 wxLongLong m_timeLastMouseUp
;
470 wxOwnerDrawnComboBox
* m_combo
;
471 wxPGProperty
* m_property
; // Selected property
474 DECLARE_EVENT_TABLE()
477 BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor
, wxEvtHandler
)
478 EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor::OnMouseEvent
)
479 EVT_SET_FOCUS(wxPGDoubleClickProcessor::OnSetFocus
)
484 class wxPGComboBox
: public wxOwnerDrawnComboBox
489 : wxOwnerDrawnComboBox()
491 m_dclickProcessor
= (wxPGDoubleClickProcessor
*) NULL
;
492 m_sizeEventCalled
= false;
497 if ( m_dclickProcessor
)
499 RemoveEventHandler(m_dclickProcessor
);
500 delete m_dclickProcessor
;
504 bool Create(wxWindow
*parent
,
506 const wxString
& value
,
509 const wxArrayString
& choices
,
511 const wxValidator
& validator
= wxDefaultValidator
,
512 const wxString
& name
= wxS("wxOwnerDrawnComboBox"))
514 if ( !wxOwnerDrawnComboBox::Create( parent
,
525 m_dclickProcessor
= new wxPGDoubleClickProcessor(this, GetGrid()->GetSelection() );
527 PushEventHandler(m_dclickProcessor
);
532 virtual void OnDrawItem( wxDC
& dc
, const wxRect
& rect
, int item
, int flags
) const
534 wxPropertyGrid
* pg
= GetGrid();
535 pg
->OnComboItemPaint((wxPGCustomComboControl
*)this,item
,dc
,(wxRect
&)rect
,flags
);
537 virtual wxCoord
OnMeasureItem( size_t item
) const
539 wxPropertyGrid
* pg
= GetGrid();
543 pg
->OnComboItemPaint((wxPGCustomComboControl
*)this,item
,*((wxDC
*)NULL
),rect
,0);
547 wxPropertyGrid
* GetGrid() const
549 wxPropertyGrid
* pg
= wxDynamicCast(GetParent()->GetParent(),wxPropertyGrid
);
554 virtual wxCoord
OnMeasureItemWidth( size_t item
) const
556 wxPropertyGrid
* pg
= GetGrid();
560 pg
->OnComboItemPaint((wxPGCustomComboControl
*)this,item
,*((wxDC
*)NULL
),rect
,0);
564 virtual void PositionTextCtrl( int WXUNUSED(textCtrlXAdjust
), int WXUNUSED(textCtrlYAdjust
) )
566 wxPropertyGrid
* pg
= GetGrid();
567 wxOwnerDrawnComboBox::PositionTextCtrl(
568 wxPG_TEXTCTRLXADJUST
- (wxPG_XBEFOREWIDGET
+wxPG_CONTROL_MARGIN
+1) - 1,
569 pg
->GetSpacingY() + 2
574 wxPGDoubleClickProcessor
* m_dclickProcessor
;
575 bool m_sizeEventCalled
;
579 void wxPropertyGrid::OnComboItemPaint( wxPGCustomComboControl
* pCc
,
585 wxPGComboBox
* pCb
= (wxPGComboBox
*)pCc
;
588 wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid
)) );
590 wxPGProperty
* p
= m_selected
;
593 const wxPGChoices
& choices
= p
->GetChoices();
594 const wxPGCommonValue
* comVal
= NULL
;
595 int comVals
= p
->GetDisplayedCommonValueCount();
596 int comValIndex
= -1;
599 if ( choices
.IsOk() )
600 choiceCount
= choices
.GetCount();
602 if ( item
>= choiceCount
&& comVals
> 0 )
604 comValIndex
= item
- choiceCount
;
605 comVal
= GetCommonValue(comValIndex
);
606 if ( !p
->IsValueUnspecified() )
607 text
= comVal
->GetLabel();
611 if ( !(flags
& wxODCB_PAINTING_CONTROL
) )
613 text
= pCb
->GetString(item
);
617 if ( !p
->IsValueUnspecified() )
618 text
= p
->GetValueString(0);
627 const wxBitmap
* itemBitmap
= NULL
;
629 if ( item
>= 0 && choices
.IsOk() && choices
.Item(item
).GetBitmap().Ok() && comValIndex
== -1 )
630 itemBitmap
= &choices
.Item(item
).GetBitmap();
633 // Decide what custom image size to use
636 cis
.x
= itemBitmap
->GetWidth();
637 cis
.y
= itemBitmap
->GetHeight();
641 cis
= GetImageSize(p
, item
);
646 // Default measure behaviour (no flexible, custom paint image only)
647 if ( rect
.width
< 0 )
650 GetTextExtent(text
, &x
, &y
, 0, 0, &m_font
);
651 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9 + x
;
654 rect
.height
= cis
.y
+ 2;
658 wxPGPaintData paintdata
;
659 paintdata
.m_parent
= NULL
;
660 paintdata
.m_choiceItem
= item
;
662 // This is by the current (1.0.0b) spec - if painting control, item is -1
663 if ( (flags
& wxODCB_PAINTING_CONTROL
) )
664 paintdata
.m_choiceItem
= -1;
667 dc
.SetBrush(*wxWHITE_BRUSH
);
674 wxPoint
pt(rect
.x
+ wxPG_CONTROL_MARGIN
- wxPG_CHOICEXADJUST
- 1,
679 if ( flags
& wxODCB_PAINTING_CONTROL
)
680 renderFlags
|= wxPGCellRenderer::Control
;
682 if ( flags
& wxODCB_PAINTING_SELECTED
)
683 renderFlags
|= wxPGCellRenderer::Selected
;
685 if ( cis
.x
> 0 && (p
->HasFlag(wxPG_PROP_CUSTOMIMAGE
) || !(flags
& wxODCB_PAINTING_CONTROL
)) &&
686 ( !p
->m_valueBitmap
|| item
== pCb
->GetSelection() ) &&
687 ( item
>= 0 || (flags
& wxODCB_PAINTING_CONTROL
) ) &&
691 pt
.x
+= wxCC_CUSTOM_IMAGE_MARGIN1
;
692 wxRect
r(pt
.x
,pt
.y
,cis
.x
,cis
.y
);
694 if ( flags
& wxODCB_PAINTING_CONTROL
)
697 r
.height
= wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
);
700 paintdata
.m_drawnWidth
= r
.width
;
702 dc
.SetPen(m_colPropFore
);
703 if ( comValIndex
>= 0 )
705 const wxPGCommonValue
* cv
= GetCommonValue(comValIndex
);
706 wxPGCellRenderer
* renderer
= cv
->GetRenderer();
707 r
.width
= rect
.width
;
708 renderer
->Render( dc
, r
, this, p
, m_selColumn
, comValIndex
, renderFlags
);
711 else if ( item
>= 0 )
713 p
->OnCustomPaint( dc
, r
, paintdata
);
717 dc
.DrawRectangle( r
);
720 pt
.x
+= paintdata
.m_drawnWidth
+ wxCC_CUSTOM_IMAGE_MARGIN2
- 1;
724 // TODO: This aligns text so that it seems to be horizontally
725 // on the same line as property values. Not really
726 // sure if its needed, but seems to not cause any harm.
729 if ( item
< 0 && (flags
& wxODCB_PAINTING_CONTROL
) )
730 item
= pCb
->GetSelection();
732 if ( choices
.IsOk() && item
>= 0 && comValIndex
< 0 )
734 const wxPGChoiceEntry
& cell
= choices
.Item(item
);
735 wxPGCellRenderer
* renderer
= wxPGGlobalVars
->m_defaultRenderer
;
736 int imageOffset
= renderer
->PreDrawCell( dc
, rect
, cell
, renderFlags
);
738 imageOffset
+= wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
;
747 pt
.y
+= (rect
.height
-m_fontHeight
)/2 - 1;
751 dc
.DrawText( text
, pt
.x
+ wxPG_XBEFORETEXT
, pt
.y
);
758 p
->OnCustomPaint( dc
, rect
, paintdata
);
759 rect
.height
= paintdata
.m_drawnHeight
+ 2;
760 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9;
764 bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid
* propGrid
, wxPGComboBox
* cb
, int cmnVal
)
766 wxPGProperty
* property
= propGrid
->GetSelectedProperty();
767 wxASSERT( property
);
771 // Yes, a common value is being selected
772 property
->SetCommonValue( cmnVal
);
773 wxSize imageSize
= propGrid
->GetCommonValue(cmnVal
)->
774 GetRenderer()->GetImageSize(property
, 1, cmnVal
);
775 if ( imageSize
.x
) imageSize
.x
+= ODCB_CUST_PAINT_MARGIN
;
776 cb
->SetCustomPaintWidth( imageSize
.x
);
781 wxSize imageSize
= propGrid
->GetImageSize(property
, -1);
782 if ( imageSize
.x
) imageSize
.x
+= ODCB_CUST_PAINT_MARGIN
;
783 cb
->SetCustomPaintWidth( imageSize
.x
);
788 // CreateControls calls this with CB_READONLY in extraStyle
789 wxWindow
* wxPGChoiceEditor::CreateControlsBase( wxPropertyGrid
* propGrid
,
790 wxPGProperty
* property
,
793 long extraStyle
) const
795 const wxPGChoices
& choices
= property
->GetChoices();
797 int index
= property
->GetChoiceSelection();
799 bool isUnspecified
= property
->IsValueUnspecified();
801 if ( !isUnspecified
)
802 defString
= property
->GetDisplayedString();
804 wxArrayString labels
= choices
.GetLabels();
810 po
.y
+= wxPG_CHOICEYADJUST
;
811 si
.y
-= (wxPG_CHOICEYADJUST
*2);
813 po
.x
+= wxPG_CHOICEXADJUST
;
814 si
.x
-= wxPG_CHOICEXADJUST
;
815 wxWindow
* ctrlParent
= propGrid
->GetPanel();
817 int odcbFlags
= extraStyle
| wxBORDER_NONE
| wxTE_PROCESS_ENTER
;
820 // If common value specified, use appropriate index
821 unsigned int cmnVals
= property
->GetDisplayedCommonValueCount();
824 if ( !isUnspecified
)
826 int cmnVal
= property
->GetCommonValue();
829 index
= labels
.size() + cmnVal
;
834 for ( i
=0; i
<cmnVals
; i
++ )
835 labels
.Add(propGrid
->GetCommonValueLabel(i
));
838 cb
= new wxPGComboBox();
842 cb
->Create(ctrlParent
,
850 cb
->SetButtonPosition(si
.y
,0,wxRIGHT
);
851 cb
->SetTextIndent(wxPG_XBEFORETEXT
-1);
853 wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
, property
->GetCommonValue() );
855 if ( index
>= 0 && index
< (int)cb
->GetCount() )
857 cb
->SetSelection( index
);
858 if ( defString
.length() )
859 cb
->SetText( defString
);
861 else if ( !(extraStyle
& wxCB_READONLY
) && defString
.length() )
862 cb
->SetValue( defString
);
864 cb
->SetSelection( -1 );
866 // Connect event handling
867 wxWindowID id
= cb
->GetId();
868 propGrid
->Connect(id
, wxEVT_COMMAND_COMBOBOX_SELECTED
,
869 wxCommandEventHandler(wxPropertyGrid::OnCustomEditorEvent
));
870 propGrid
->Connect(id
, wxEVT_COMMAND_TEXT_UPDATED
,
871 wxCommandEventHandler(wxPropertyGrid::OnCustomEditorEvent
));
872 propGrid
->Connect(id
, wxEVT_COMMAND_TEXT_ENTER
,
873 wxCommandEventHandler(wxPropertyGrid::OnCustomEditorEvent
));
879 return (wxWindow
*) cb
;
883 void wxPGChoiceEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
886 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
887 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
888 int ind
= property
->GetChoiceSelection();
889 cb
->SetSelection(ind
);
892 wxPGWindowList
wxPGChoiceEditor::CreateControls( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
893 const wxPoint
& pos
, const wxSize
& sz
) const
895 return CreateControlsBase(propGrid
,property
,pos
,sz
,wxCB_READONLY
);
899 int wxPGChoiceEditor::InsertItem( wxWindow
* ctrl
, const wxString
& label
, int index
) const
902 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
903 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
906 index
= cb
->GetCount();
908 return cb
->Insert(label
,index
);
912 void wxPGChoiceEditor::DeleteItem( wxWindow
* ctrl
, int index
) const
915 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
916 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
921 bool wxPGChoiceEditor::OnEvent( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
922 wxWindow
* ctrl
, wxEvent
& event
) const
924 if ( event
.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED
)
926 wxPGComboBox
* cb
= (wxPGComboBox
*)ctrl
;
927 int index
= cb
->GetSelection();
928 int cmnValIndex
= -1;
929 int cmnVals
= property
->GetDisplayedCommonValueCount();
930 int items
= cb
->GetCount();
932 if ( index
>= (items
-cmnVals
) )
934 // Yes, a common value is being selected
935 cmnValIndex
= index
- (items
-cmnVals
);
936 property
->SetCommonValue( cmnValIndex
);
938 // Truly set value to unspecified?
939 if ( propGrid
->GetUnspecifiedCommonValue() == cmnValIndex
)
941 if ( !property
->IsValueUnspecified() )
942 propGrid
->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT
);
943 property
->SetValueToUnspecified();
944 if ( !cb
->HasFlag(wxCB_READONLY
) )
945 cb
->GetTextCtrl()->SetValue(wxEmptyString
);
949 return wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
, cmnValIndex
);
955 bool wxPGChoiceEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
957 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
959 int index
= cb
->GetSelection();
961 if ( index
!= property
->GetChoiceSelection() ||
962 // Changing unspecified always causes event (returning
963 // true here should be enough to trigger it).
964 property
->IsValueUnspecified()
967 return property
->IntToValue( variant
, index
, 0 );
973 void wxPGChoiceEditor::SetControlStringValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, const wxString
& txt
) const
975 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
981 void wxPGChoiceEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
983 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
985 cb
->SetSelection(value
);
989 void wxPGChoiceEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
) const
991 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
992 cb
->SetSelection(-1);
996 bool wxPGChoiceEditor::CanContainCustomImage() const
1002 wxPGChoiceEditor::~wxPGChoiceEditor() { }
1005 // -----------------------------------------------------------------------
1006 // wxPGComboBoxEditor
1007 // -----------------------------------------------------------------------
1010 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ComboBox
,
1015 void wxPGComboBoxEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1017 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1018 cb
->SetValue(property
->GetValueString(wxPG_EDITABLE_VALUE
));
1020 // TODO: If string matches any selection, then select that.
1024 wxPGWindowList
wxPGComboBoxEditor::CreateControls( wxPropertyGrid
* propGrid
,
1025 wxPGProperty
* property
,
1027 const wxSize
& sz
) const
1029 return CreateControlsBase(propGrid
,property
,pos
,sz
,0);
1033 bool wxPGComboBoxEditor::OnEvent( wxPropertyGrid
* propGrid
,
1034 wxPGProperty
* property
,
1036 wxEvent
& event
) const
1038 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*) NULL
;
1039 wxWindow
* textCtrl
= (wxWindow
*) NULL
;
1043 cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1044 textCtrl
= cb
->GetTextCtrl();
1047 if ( wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid
,property
,textCtrl
,event
) )
1050 return wxPGChoiceEditor::OnEvent(propGrid
,property
,ctrl
,event
);
1054 bool wxPGComboBoxEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1056 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1057 wxString textVal
= cb
->GetValue();
1059 if ( property
->UsesAutoUnspecified() && !textVal
.length() )
1065 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
1067 // Changing unspecified always causes event (returning
1068 // true here should be enough to trigger it).
1069 if ( !res
&& variant
.IsNull() )
1076 void wxPGComboBoxEditor::OnFocus( wxPGProperty
*, wxWindow
* ctrl
) const
1078 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1079 cb
->GetTextCtrl()->SetSelection(-1,-1);
1083 wxPGComboBoxEditor::~wxPGComboBoxEditor() { }
1086 // -----------------------------------------------------------------------
1087 // wxPGChoiceAndButtonEditor
1088 // -----------------------------------------------------------------------
1091 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ChoiceAndButton
,
1092 wxPGChoiceAndButtonEditor
,
1096 wxPGWindowList
wxPGChoiceAndButtonEditor::CreateControls( wxPropertyGrid
* propGrid
,
1097 wxPGProperty
* property
,
1099 const wxSize
& sz
) const
1101 // Use one two units smaller to match size of the combo's dropbutton.
1102 // (normally a bigger button is used because it looks better)
1105 wxSize
bt_sz(bt_wid
,bt_wid
);
1107 // Position of button.
1108 wxPoint
bt_pos(pos
.x
+sz
.x
-bt_sz
.x
,pos
.y
);
1115 wxWindow
* bt
= propGrid
->GenerateEditorButton( bt_pos
, bt_sz
);
1118 wxSize
ch_sz(sz
.x
-bt
->GetSize().x
,sz
.y
);
1121 ch_sz
.x
-= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1124 wxWindow
* ch
= wxPGEditor_Choice
->CreateControls(propGrid
,property
,
1125 pos
,ch_sz
).m_primary
;
1131 return wxPGWindowList(ch
, bt
);
1135 wxPGChoiceAndButtonEditor::~wxPGChoiceAndButtonEditor() { }
1138 // -----------------------------------------------------------------------
1139 // wxPGTextCtrlAndButtonEditor
1140 // -----------------------------------------------------------------------
1142 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrlAndButton
,
1143 wxPGTextCtrlAndButtonEditor
,
1147 wxPGWindowList
wxPGTextCtrlAndButtonEditor::CreateControls( wxPropertyGrid
* propGrid
,
1148 wxPGProperty
* property
,
1150 const wxSize
& sz
) const
1153 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrlAndButton( pos
, sz
, &wnd2
,
1154 property
->GetFlags() & wxPG_PROP_NOEDITOR
, property
);
1156 return wxPGWindowList(wnd
, wnd2
);
1160 wxPGTextCtrlAndButtonEditor::~wxPGTextCtrlAndButtonEditor() { }
1163 // -----------------------------------------------------------------------
1164 // wxPGCheckBoxEditor
1165 // -----------------------------------------------------------------------
1167 #if wxPG_INCLUDE_CHECKBOX
1169 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(CheckBox
,
1174 // state argument: 0x01 = set if checked
1175 // 0x02 = set if rectangle should be bold
1176 static void DrawSimpleCheckBox( wxDC
& dc
, const wxRect
& rect
, int box_hei
, int state
, const wxColour
& linecol
)
1180 wxRect
r(rect
.x
+wxPG_XBEFORETEXT
,rect
.y
+((rect
.height
-box_hei
)/2),box_hei
,box_hei
);
1182 // Draw check mark first because it is likely to overdraw the
1183 // surrounding rectangle.
1186 wxRect
r2(r
.x
+wxPG_CHECKMARK_XADJ
,
1187 r
.y
+wxPG_CHECKMARK_YADJ
,
1188 r
.width
+wxPG_CHECKMARK_WADJ
,
1189 r
.height
+wxPG_CHECKMARK_HADJ
);
1190 #if wxPG_CHECKMARK_DEFLATE
1191 r2
.Deflate(wxPG_CHECKMARK_DEFLATE
);
1193 dc
.DrawCheckMark(r2
);
1195 // This would draw a simple cross check mark.
1196 // dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
1197 // dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
1203 // Pen for thin rectangle.
1208 // Pen for bold rectangle.
1209 wxPen
linepen(linecol
,2,wxSOLID
);
1210 linepen
.SetJoin(wxJOIN_MITER
); // This prevents round edges.
1218 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1220 dc
.DrawRectangle(r
);
1221 dc
.SetPen(*wxTRANSPARENT_PEN
);
1225 // Real simple custom-drawn checkbox-without-label class.
1227 class wxSimpleCheckBox
: public wxControl
1231 void SetValue( int value
);
1233 wxSimpleCheckBox( wxWindow
* parent
,
1235 const wxPoint
& pos
= wxDefaultPosition
,
1236 const wxSize
& size
= wxDefaultSize
)
1237 : wxControl(parent
,id
,pos
,size
,wxBORDER_NONE
|wxWANTS_CHARS
)
1239 // Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
1240 SetFont( parent
->GetFont() );
1243 wxPropertyGrid
* pg
= (wxPropertyGrid
*) parent
->GetParent();
1244 wxASSERT( pg
->IsKindOf(CLASSINFO(wxPropertyGrid
)) );
1245 m_boxHeight
= pg
->GetFontHeight();
1246 SetBackgroundStyle( wxBG_STYLE_COLOUR
);
1249 virtual ~wxSimpleCheckBox();
1251 virtual bool ProcessEvent(wxEvent
& event
);
1256 static wxBitmap
* ms_doubleBuffer
;
1260 wxSimpleCheckBox::~wxSimpleCheckBox()
1262 delete ms_doubleBuffer
;
1263 ms_doubleBuffer
= NULL
;
1267 wxBitmap
* wxSimpleCheckBox::ms_doubleBuffer
= (wxBitmap
*) NULL
;
1269 // value = 2 means toggle (sorry, too lazy to do constants)
1270 void wxSimpleCheckBox::SetValue( int value
)
1275 if ( m_state
> 1 ) m_state
= 0;
1283 wxCommandEvent
evt(wxEVT_COMMAND_CHECKBOX_CLICKED
,GetParent()->GetId());
1285 wxPropertyGrid
* propGrid
= (wxPropertyGrid
*) GetParent()->GetParent();
1286 wxASSERT( propGrid
->IsKindOf(CLASSINFO(wxPropertyGrid
)) );
1287 propGrid
->OnCustomEditorEvent(evt
);
1291 bool wxSimpleCheckBox::ProcessEvent(wxEvent
& event
)
1293 wxPropertyGrid
* propGrid
= (wxPropertyGrid
*) GetParent()->GetParent();
1294 wxASSERT( propGrid
->IsKindOf(CLASSINFO(wxPropertyGrid
)) );
1296 if ( ( (event
.GetEventType() == wxEVT_LEFT_DOWN
|| event
.GetEventType() == wxEVT_LEFT_DCLICK
)
1297 && ((wxMouseEvent
&)event
).m_x
> (wxPG_XBEFORETEXT
-2)
1298 && ((wxMouseEvent
&)event
).m_x
<= (wxPG_XBEFORETEXT
-2+m_boxHeight
) )
1304 else if ( event
.GetEventType() == wxEVT_PAINT
)
1306 wxSize clientSize
= GetClientSize();
1310 // Buffered paint DC doesn't seem to do much good
1311 if ( !ms_doubleBuffer ||
1312 clientSize.x > ms_doubleBuffer->GetWidth() ||
1313 clientSize.y > ms_doubleBuffer->GetHeight() )
1315 delete ms_doubleBuffer;
1316 ms_doubleBuffer = new wxBitmap(clientSize.x+25,clientSize.y+25);
1319 wxBufferedPaintDC dc(this,*ms_doubleBuffer);
1322 wxRect
rect(0,0,clientSize
.x
,clientSize
.y
);
1327 m_boxHeight
= propGrid
->GetFontHeight();
1329 wxColour bgcol
= GetBackgroundColour();
1330 dc
.SetBrush( bgcol
);
1332 dc
.DrawRectangle( rect
);
1334 wxColour txcol
= GetForegroundColour();
1336 int state
= m_state
;
1337 if ( m_font
.GetWeight() == wxBOLD
)
1340 DrawSimpleCheckBox(dc
,rect
,m_boxHeight
,state
,txcol
);
1342 // If focused, indicate it somehow.
1344 if ( wxWindow::FindFocus() == this )
1349 wxPGDrawFocusRect(dc,rect);
1355 else if ( event
.GetEventType() == wxEVT_SIZE
||
1356 event
.GetEventType() == wxEVT_SET_FOCUS
||
1357 event
.GetEventType() == wxEVT_KILL_FOCUS
1362 else if ( event
.GetEventType() == wxEVT_KEY_DOWN
)
1364 wxKeyEvent
& keyEv
= (wxKeyEvent
&) event
;
1366 if ( keyEv
.GetKeyCode() == WXK_SPACE
)
1372 return wxControl::ProcessEvent(event
);
1376 wxPGWindowList
wxPGCheckBoxEditor::CreateControls( wxPropertyGrid
* propGrid
,
1377 wxPGProperty
* property
,
1379 const wxSize
& size
) const
1382 pt
.x
-= wxPG_XBEFOREWIDGET
;
1384 sz
.x
= propGrid
->GetFontHeight() + (wxPG_XBEFOREWIDGET
*2) + 4;
1386 wxSimpleCheckBox
* cb
= new wxSimpleCheckBox(propGrid
->GetPanel(),wxPG_SUBID1
,pt
,sz
);
1388 cb
->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
1390 cb
->Connect( wxPG_SUBID1
, wxEVT_LEFT_DOWN
,
1391 (wxObjectEventFunction
) (wxEventFunction
) (wxCommandEventFunction
)
1392 &wxPropertyGrid::OnCustomEditorEvent
, NULL
, propGrid
);
1394 cb
->Connect( wxPG_SUBID1
, wxEVT_LEFT_DCLICK
,
1395 (wxObjectEventFunction
) (wxEventFunction
) (wxCommandEventFunction
)
1396 &wxPropertyGrid::OnCustomEditorEvent
, NULL
, propGrid
);
1398 if ( property
->GetChoiceSelection() > 0 &&
1399 !property
->IsValueUnspecified() )
1402 // If mouse cursor was on the item, toggle the value now.
1403 if ( propGrid
->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK
)
1405 wxPoint pt
= cb
->ScreenToClient(::wxGetMousePosition());
1406 if ( pt
.x
<= (wxPG_XBEFORETEXT
-2+cb
->m_boxHeight
) )
1410 if ( cb
->m_state
> 1 )
1413 // Makes sure wxPG_EVT_CHANGING etc. is sent for this initial click
1414 propGrid
->ChangePropertyValue(property
, wxPGVariant_Bool(cb
->m_state
));
1418 propGrid
->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR
);
1424 class wxPGCheckBoxRenderer : public wxPGDefaultRenderer
1428 virtual void Render( wxDC& dc, const wxRect& rect,
1429 const wxPropertyGrid* WXUNUSED(propertyGrid), wxPGProperty* property,
1430 int WXUNUSED(column), int WXUNUSED(item), int WXUNUSED(flags) ) const
1433 if ( !(property->GetFlags() & wxPG_PROP_UNSPECIFIED) )
1435 state = ((wxPGProperty*)property)->GetChoiceInfo((wxPGChoiceInfo*)NULL);
1436 if ( dc.GetFont().GetWeight() == wxBOLD ) state |= 2;
1438 DrawSimpleCheckBox(dc,rect,dc.GetCharHeight(),state,dc.GetTextForeground());
1444 wxPGCheckBoxRenderer g_wxPGCheckBoxRenderer;
1446 wxPGCellRenderer* wxPGCheckBoxEditor::GetCellRenderer() const
1448 return &g_wxPGCheckBoxRenderer;
1452 void wxPGCheckBoxEditor::DrawValue( wxDC
& dc
, const wxRect
& rect
, wxPGProperty
* property
, const wxString
& WXUNUSED(text
) ) const
1455 if ( !property
->IsValueUnspecified() )
1457 state
= property
->GetChoiceSelection();
1458 if ( dc
.GetFont().GetWeight() == wxBOLD
) state
|= 2;
1460 DrawSimpleCheckBox(dc
,rect
,dc
.GetCharHeight(),state
,dc
.GetTextForeground());
1463 void wxPGCheckBoxEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1466 ((wxSimpleCheckBox
*)ctrl
)->m_state
= property
->GetChoiceSelection();
1471 bool wxPGCheckBoxEditor::OnEvent( wxPropertyGrid
* WXUNUSED(propGrid
), wxPGProperty
* WXUNUSED(property
),
1472 wxWindow
* WXUNUSED(ctrl
), wxEvent
& event
) const
1474 if ( event
.GetEventType() == wxEVT_COMMAND_CHECKBOX_CLICKED
)
1482 bool wxPGCheckBoxEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1484 wxSimpleCheckBox
* cb
= (wxSimpleCheckBox
*)ctrl
;
1486 int index
= cb
->m_state
;
1488 if ( index
!= property
->GetChoiceSelection() ||
1489 // Changing unspecified always causes event (returning
1490 // true here should be enough to trigger it).
1491 property
->IsValueUnspecified()
1494 return property
->IntToValue(variant
, index
, 0);
1500 void wxPGCheckBoxEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
1502 if ( value
!= 0 ) value
= 1;
1503 ((wxSimpleCheckBox
*)ctrl
)->m_state
= value
;
1508 void wxPGCheckBoxEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
) const
1510 ((wxSimpleCheckBox
*)ctrl
)->m_state
= 0;
1515 wxPGCheckBoxEditor::~wxPGCheckBoxEditor() { }
1518 #endif // wxPG_INCLUDE_CHECKBOX
1520 // -----------------------------------------------------------------------
1522 wxWindow
* wxPropertyGrid::GetEditorControl() const
1524 wxWindow
* ctrl
= m_wndEditor
;
1532 // -----------------------------------------------------------------------
1534 void wxPropertyGrid::CorrectEditorWidgetSizeX()
1536 if ( m_selColumn
== -1 )
1540 int newSplitterx
= m_pState
->DoGetSplitterPosition(m_selColumn
-1);
1541 int newWidth
= newSplitterx
+ m_pState
->m_colWidths
[m_selColumn
];
1545 // if width change occurred, move secondary wnd by that amount
1546 wxRect r
= m_wndEditor2
->GetRect();
1548 r
.x
= newWidth
- secWid
;
1550 m_wndEditor2
->SetSize( r
);
1552 // if primary is textctrl, then we have to add some extra space
1556 if ( m_wndEditor
&& m_wndEditor
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
1558 secWid
+= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1563 wxRect r
= m_wndEditor
->GetRect();
1565 r
.x
= newSplitterx
+m_ctrlXAdjust
;
1567 if ( !(m_iFlags
& wxPG_FL_FIXED_WIDTH_EDITOR
) )
1568 r
.width
= newWidth
- r
.x
- secWid
;
1570 m_wndEditor
->SetSize(r
);
1574 m_wndEditor2
->Refresh();
1577 // -----------------------------------------------------------------------
1579 void wxPropertyGrid::CorrectEditorWidgetPosY()
1581 if ( m_selected
&& (m_wndEditor
|| m_wndEditor2
) )
1583 wxRect r
= GetEditorWidgetRect(m_selected
, m_selColumn
);
1587 wxPoint pos
= m_wndEditor
->GetPosition();
1589 // Calculate y offset
1590 int offset
= pos
.y
% m_lineHeight
;
1592 m_wndEditor
->Move(pos
.x
, r
.y
+ offset
);
1597 wxPoint pos
= m_wndEditor2
->GetPosition();
1599 m_wndEditor2
->Move(pos
.x
, r
.y
);
1604 // -----------------------------------------------------------------------
1606 // Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
1607 // fits into that category as well).
1608 void wxPropertyGrid::FixPosForTextCtrl( wxWindow
* ctrl
, const wxPoint
& offset
)
1610 // Center the control vertically
1611 wxRect finalPos
= ctrl
->GetRect();
1612 int y_adj
= (m_lineHeight
- finalPos
.height
)/2 + wxPG_TEXTCTRLYADJUST
;
1614 // Prevent over-sized control
1615 int sz_dec
= (y_adj
+ finalPos
.height
) - m_lineHeight
;
1616 if ( sz_dec
< 0 ) sz_dec
= 0;
1618 finalPos
.y
+= y_adj
;
1619 finalPos
.height
-= (y_adj
+sz_dec
);
1621 const int textCtrlXAdjust
= wxPG_TEXTCTRLXADJUST
;
1623 finalPos
.x
+= textCtrlXAdjust
;
1624 finalPos
.width
-= textCtrlXAdjust
;
1626 finalPos
.x
+= offset
.x
;
1627 finalPos
.y
+= offset
.y
;
1629 ctrl
->SetSize(finalPos
);
1632 // -----------------------------------------------------------------------
1634 wxWindow
* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint
& pos
,
1636 const wxString
& value
,
1637 wxWindow
* secondary
,
1641 wxWindowID id
= wxPG_SUBID1
;
1642 wxPGProperty
* selected
= m_selected
;
1645 int tcFlags
= wxTE_PROCESS_ENTER
| extraStyle
;
1647 if ( selected
->HasFlag(wxPG_PROP_READONLY
) )
1648 tcFlags
|= wxTE_READONLY
;
1650 wxPoint
p(pos
.x
,pos
.y
);
1651 wxSize
s(sz
.x
,sz
.y
);
1653 // Need to reduce width of text control on Mac
1654 #if defined(__WXMAC__)
1658 // Take button into acccount
1661 s
.x
-= (secondary
->GetSize().x
+ wxPG_TEXTCTRL_AND_BUTTON_SPACING
);
1662 m_iFlags
&= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE
);
1665 // If the height is significantly higher, then use border, and fill the rect exactly.
1666 bool hasSpecialSize
= false;
1668 if ( (sz
.y
- m_lineHeight
) > 5 )
1669 hasSpecialSize
= true;
1671 wxWindow
* ctrlParent
= GetPanel();
1673 if ( !hasSpecialSize
)
1674 tcFlags
|= wxBORDER_NONE
;
1676 wxTextCtrl
* tc
= new wxTextCtrl();
1678 #if defined(__WXMSW__)
1681 SetupTextCtrlValue(value
);
1682 tc
->Create(ctrlParent
,id
,value
, p
, s
,tcFlags
);
1686 // Center the control vertically
1687 if ( !hasSpecialSize
)
1688 FixPosForTextCtrl(ed
);
1696 // Set maximum length
1698 tc
->SetMaxLength( maxLen
);
1700 // Connect event handling
1702 this->Connect(id
, wxEVT_COMMAND_TEXT_UPDATED
,
1703 wxCommandEventHandler(wxPropertyGrid::OnCustomEditorEvent
));
1704 this->Connect(id
, wxEVT_COMMAND_TEXT_ENTER
,
1705 wxCommandEventHandler(wxPropertyGrid::OnCustomEditorEvent
));
1707 return (wxWindow
*) ed
;
1710 // -----------------------------------------------------------------------
1712 wxWindow
* wxPropertyGrid::GenerateEditorButton( const wxPoint
& pos
, const wxSize
& sz
)
1714 wxWindowID id
= wxPG_SUBID2
;
1715 wxPGProperty
* selected
= m_selected
;
1719 // Decorations are chunky on Mac, and we can't make the button square, so
1720 // do things a bit differently on this platform.
1722 wxPoint
p(pos
.x
+sz
.x
,
1723 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
1726 wxButton
* but
= new wxButton();
1727 but
->Create(GetPanel(),id
,wxS("..."),p
,s
,wxWANTS_CHARS
);
1729 // Now that we know the size, move to the correct position
1730 p
.x
= pos
.x
+ sz
.x
- but
->GetSize().x
- 2;
1734 wxSize
s(sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2),
1735 sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2));
1737 // Reduce button width to lineheight
1738 if ( s
.x
> m_lineHeight
)
1742 // On wxGTK, take fixed button margins into account
1747 wxPoint
p(pos
.x
+sz
.x
-s
.x
,
1748 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
1750 wxButton
* but
= new wxButton();
1754 but
->Create(GetPanel(),id
,wxS("..."),p
,s
,wxWANTS_CHARS
);
1757 wxFont font
= GetFont();
1758 font
.SetPointSize(font
.GetPointSize()-2);
1761 but
->SetFont(GetFont());
1765 if ( selected
->HasFlag(wxPG_PROP_READONLY
) )
1768 // Connect event handling
1770 this->Connect(id
, wxEVT_COMMAND_BUTTON_CLICKED
,
1771 wxCommandEventHandler(wxPropertyGrid::OnCustomEditorEvent
));
1776 // -----------------------------------------------------------------------
1778 wxWindow
* wxPropertyGrid::GenerateEditorTextCtrlAndButton( const wxPoint
& pos
,
1780 wxWindow
** psecondary
,
1782 wxPGProperty
* property
)
1784 wxButton
* but
= (wxButton
*)GenerateEditorButton(pos
,sz
);
1785 *psecondary
= (wxWindow
*)but
;
1787 if ( limitedEditing
)
1790 // There is button Show in GenerateEditorTextCtrl as well
1793 return (wxWindow
*) NULL
;
1798 if ( !property
->IsValueUnspecified() )
1799 text
= property
->GetValueString(property
->HasFlag(wxPG_PROP_READONLY
)?0:wxPG_EDITABLE_VALUE
);
1801 return GenerateEditorTextCtrl(pos
,sz
,text
,but
,property
->m_maxLen
);
1804 // -----------------------------------------------------------------------
1806 wxTextCtrl
* wxPropertyGrid::GetEditorTextCtrl() const
1808 wxWindow
* wnd
= GetEditorControl();
1813 if ( wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
1814 return wxStaticCast(wnd
, wxTextCtrl
);
1816 if ( wnd
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) )
1818 wxOwnerDrawnComboBox
* cb
= wxStaticCast(wnd
, wxOwnerDrawnComboBox
);
1819 return cb
->GetTextCtrl();
1825 // -----------------------------------------------------------------------
1827 wxPGEditor
* wxPropertyGridInterface::GetEditorByName( const wxString
& editorName
)
1829 wxPGHashMapS2P::const_iterator it
;
1831 it
= wxPGGlobalVars
->m_mapEditorClasses
.find(editorName
);
1832 if ( it
== wxPGGlobalVars
->m_mapEditorClasses
.end() )
1834 return (wxPGEditor
*) it
->second
;
1837 // -----------------------------------------------------------------------
1838 // wxPGEditorDialogAdapter
1839 // -----------------------------------------------------------------------
1841 IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter
, wxObject
)
1843 bool wxPGEditorDialogAdapter::ShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
1845 if ( !propGrid
->EditorValidate() )
1848 bool res
= DoShowDialog( propGrid
, property
);
1852 propGrid
->ValueChangeInEvent( m_value
);
1859 // -----------------------------------------------------------------------
1861 // -----------------------------------------------------------------------
1863 wxPGMultiButton::wxPGMultiButton( wxPropertyGrid
* pg
, const wxSize
& sz
)
1864 : wxWindow( pg
->GetPanel(), wxPG_SUBID2
, wxPoint(-100,-100), wxSize(0, sz
.y
) ),
1865 m_fullEditorSize(sz
), m_buttonsWidth(0)
1867 SetBackgroundColour(pg
->GetCellBackgroundColour());
1870 void wxPGMultiButton::Finalize( wxPropertyGrid
* propGrid
, const wxPoint
& pos
)
1872 Move( pos
.x
+ m_fullEditorSize
.x
- m_buttonsWidth
, pos
.y
);
1874 // Connect event handling
1875 for ( int i
=0; i
<GetCount(); i
++ )
1877 wxWindowID id
= GetButtonId(i
);
1878 propGrid
->Connect(id
, wxEVT_COMMAND_BUTTON_CLICKED
,
1879 wxCommandEventHandler(wxPropertyGrid::OnCustomEditorEvent
));
1883 int wxPGMultiButton::GenId( int id
) const
1887 if ( m_buttons
.size() )
1888 id
= GetButton(m_buttons
.size()-1)->GetId() + 1;
1896 void wxPGMultiButton::Add( const wxBitmap
& bitmap
, int id
)
1899 wxSize sz
= GetSize();
1900 wxButton
* button
= new wxBitmapButton( this, id
, bitmap
, wxPoint(sz
.x
, 0), wxSize(sz
.y
, sz
.y
) );
1901 m_buttons
.push_back(button
);
1902 int bw
= button
->GetSize().x
;
1903 SetSize(wxSize(sz
.x
+bw
,sz
.y
));
1904 m_buttonsWidth
+= bw
;
1908 void wxPGMultiButton::Add( const wxString
& label
, int id
)
1911 wxSize sz
= GetSize();
1912 wxButton
* button
= new wxButton( this, id
, label
, wxPoint(sz
.x
, 0), wxSize(sz
.y
, sz
.y
) );
1913 m_buttons
.push_back(button
);
1914 int bw
= button
->GetSize().x
;
1915 SetSize(wxSize(sz
.x
+bw
,sz
.y
));
1916 m_buttonsWidth
+= bw
;
1919 // -----------------------------------------------------------------------
1921 #endif // wxUSE_PROPGRID