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"
21 #include "wx/object.h"
23 #include "wx/string.h"
26 #include "wx/window.h"
29 #include "wx/dcclient.h"
30 #include "wx/dcmemory.h"
31 #include "wx/button.h"
34 #include "wx/cursor.h"
35 #include "wx/dialog.h"
36 #include "wx/settings.h"
37 #include "wx/msgdlg.h"
38 #include "wx/choice.h"
39 #include "wx/stattext.h"
40 #include "wx/scrolwin.h"
41 #include "wx/dirdlg.h"
42 #include "wx/layout.h"
44 #include "wx/textdlg.h"
45 #include "wx/filedlg.h"
46 #include "wx/statusbr.h"
53 #include "wx/dcbuffer.h"
54 #include "wx/bmpbuttn.h"
57 // This define is necessary to prevent macro clearing
58 #define __wxPG_SOURCE_FILE__
60 #include <wx/propgrid/propgrid.h>
61 #include <wx/propgrid/editors.h>
62 #include <wx/propgrid/props.h>
64 #if wxPG_USE_RENDERER_NATIVE
65 #include <wx/renderer.h>
68 // How many pixels between textctrl and button
70 #define wxPG_TEXTCTRL_AND_BUTTON_SPACING 8
72 #define wxPG_TEXTCTRL_AND_BUTTON_SPACING 2
75 #define wxPG_BUTTON_SIZEDEC 0
77 #include <wx/odcombo.h>
80 #include <wx/msw/private.h>
83 // -----------------------------------------------------------------------
85 #if defined(__WXMSW__)
87 #define wxPG_NAT_TEXTCTRL_BORDER_X 0 // Unremovable border of native textctrl.
88 #define wxPG_NAT_TEXTCTRL_BORDER_Y 0 // Unremovable border of native textctrl.
90 #define wxPG_NAT_BUTTON_BORDER_ANY 1
91 #define wxPG_NAT_BUTTON_BORDER_X 1
92 #define wxPG_NAT_BUTTON_BORDER_Y 1
94 #define wxPG_CHECKMARK_XADJ 1
95 #define wxPG_CHECKMARK_YADJ (-1)
96 #define wxPG_CHECKMARK_WADJ 0
97 #define wxPG_CHECKMARK_HADJ 0
98 #define wxPG_CHECKMARK_DEFLATE 0
100 #define wxPG_TEXTCTRLYADJUST (m_spacingy+0)
102 #elif defined(__WXGTK__)
104 #define wxPG_CHECKMARK_XADJ 0
105 #define wxPG_CHECKMARK_YADJ 0
106 #define wxPG_CHECKMARK_WADJ (-1)
107 #define wxPG_CHECKMARK_HADJ (-1)
108 #define wxPG_CHECKMARK_DEFLATE 3
110 #define wxPG_NAT_TEXTCTRL_BORDER_X 3 // Unremovable border of native textctrl.
111 #define wxPG_NAT_TEXTCTRL_BORDER_Y 3 // Unremovable border of native textctrl.
113 #define wxPG_NAT_BUTTON_BORDER_ANY 1
114 #define wxPG_NAT_BUTTON_BORDER_X 1
115 #define wxPG_NAT_BUTTON_BORDER_Y 1
117 #define wxPG_TEXTCTRLYADJUST 0
119 #elif defined(__WXMAC__)
121 #define wxPG_CHECKMARK_XADJ 0
122 #define wxPG_CHECKMARK_YADJ 0
123 #define wxPG_CHECKMARK_WADJ 0
124 #define wxPG_CHECKMARK_HADJ 0
125 #define wxPG_CHECKMARK_DEFLATE 0
127 #define wxPG_NAT_TEXTCTRL_BORDER_X 0 // Unremovable border of native textctrl.
128 #define wxPG_NAT_TEXTCTRL_BORDER_Y 0 // Unremovable border of native textctrl.
130 #define wxPG_NAT_BUTTON_BORDER_ANY 0
131 #define wxPG_NAT_BUTTON_BORDER_X 0
132 #define wxPG_NAT_BUTTON_BORDER_Y 0
134 #define wxPG_TEXTCTRLYADJUST 3
138 #define wxPG_CHECKMARK_XADJ 0
139 #define wxPG_CHECKMARK_YADJ 0
140 #define wxPG_CHECKMARK_WADJ 0
141 #define wxPG_CHECKMARK_HADJ 0
142 #define wxPG_CHECKMARK_DEFLATE 0
144 #define wxPG_NAT_TEXTCTRL_BORDER_X 0 // Unremovable border of native textctrl.
145 #define wxPG_NAT_TEXTCTRL_BORDER_Y 0 // Unremovable border of native textctrl.
147 #define wxPG_NAT_BUTTON_BORDER_ANY 0
148 #define wxPG_NAT_BUTTON_BORDER_X 0
149 #define wxPG_NAT_BUTTON_BORDER_Y 0
151 #define wxPG_TEXTCTRLYADJUST 0
155 #if (!wxPG_NAT_TEXTCTRL_BORDER_X && !wxPG_NAT_TEXTCTRL_BORDER_Y)
156 #define wxPG_ENABLE_CLIPPER_WINDOW 0
158 #define wxPG_ENABLE_CLIPPER_WINDOW 1
163 #define wxPG_CHOICEXADJUST 0
164 #define wxPG_CHOICEYADJUST 0
166 #define ODCB_CUST_PAINT_MARGIN 6 // Number added to image width for SetCustomPaintWidth
168 // Milliseconds to wait for two mouse-ups after focus inorder
169 // to trigger a double-click.
170 #define DOUBLE_CLICK_CONVERSION_TRESHOLD 500
172 // -----------------------------------------------------------------------
174 // -----------------------------------------------------------------------
176 IMPLEMENT_ABSTRACT_CLASS(wxPGEditor
, wxObject
)
179 wxPGEditor::~wxPGEditor()
183 void wxPGEditor::DrawValue( wxDC
& dc
, const wxRect
& rect
, wxPGProperty
* property
, const wxString
& text
) const
185 if ( !property
->IsValueUnspecified() )
186 dc
.DrawText( text
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
189 bool wxPGEditor::GetValueFromControl( wxVariant
&, wxPGProperty
*, wxWindow
* ) const
194 void wxPGEditor::SetControlStringValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, const wxString
& ) const
199 void wxPGEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, int ) const
204 int wxPGEditor::InsertItem( wxWindow
*, const wxString
&, int ) const
210 void wxPGEditor::DeleteItem( wxWindow
*, int ) const
216 void wxPGEditor::OnFocus( wxPGProperty
*, wxWindow
* ) const
221 bool wxPGEditor::CanContainCustomImage() const
226 // -----------------------------------------------------------------------
228 // -----------------------------------------------------------------------
231 #if wxPG_ENABLE_CLIPPER_WINDOW
234 // Clipper window is used to "remove" borders from controls
235 // which otherwise insist on having them despite of supplied
236 // wxNO_BORDER window style.
238 class wxPGClipperWindow
: public wxWindow
240 DECLARE_CLASS(wxPGClipperWindow
)
246 wxPGClipperWindow::Init();
249 wxPGClipperWindow(wxWindow
* parent
,
251 const wxPoint
& pos
= wxDefaultPosition
,
252 const wxSize
& size
= wxDefaultSize
)
255 Create(parent
,id
,pos
,size
);
258 void Create(wxWindow
* parent
,
260 const wxPoint
& pos
= wxDefaultPosition
,
261 const wxSize
& size
= wxDefaultSize
);
263 virtual ~wxPGClipperWindow();
265 virtual bool ProcessEvent(wxEvent
& event
);
267 inline wxWindow
* GetControl() const { return m_ctrl
; }
269 // This is called before wxControl is constructed.
270 void GetControlRect( int xadj
, int yadj
, wxPoint
& pt
, wxSize
& sz
);
272 // This is caleed after wxControl has been constructed.
273 void SetControl( wxWindow
* ctrl
);
275 virtual void Refresh( bool eraseBackground
= true,
276 const wxRect
*rect
= (const wxRect
*) NULL
);
277 virtual void SetFocus();
279 virtual bool SetFont(const wxFont
& font
);
281 inline int GetXClip() const { return m_xadj
; }
283 inline int GetYClip() const { return m_yadj
; }
288 int m_xadj
; // Horizontal border clip.
290 int m_yadj
; // Vertical border clip.
295 m_ctrl
= (wxWindow
*) NULL
;
300 IMPLEMENT_CLASS(wxPGClipperWindow
,wxWindow
)
303 // This is called before wxControl is constructed.
304 void wxPGClipperWindow::GetControlRect( int xadj
, int yadj
, wxPoint
& pt
, wxSize
& sz
)
310 wxSize own_size
= GetSize();
311 sz
.x
= own_size
.x
+(xadj
*2);
312 sz
.y
= own_size
.y
+(yadj
*2);
316 // This is caleed after wxControl has been constructed.
317 void wxPGClipperWindow::SetControl( wxWindow
* ctrl
)
321 // GTK requires this.
322 ctrl
->SetSizeHints(3,3);
324 // Correct size of this window to match the child.
325 wxSize sz
= GetSize();
326 wxSize chsz
= ctrl
->GetSize();
328 int hei_adj
= chsz
.y
- (sz
.y
+(m_yadj
*2));
330 SetSize(sz
.x
,chsz
.y
-(m_yadj
*2));
335 void wxPGClipperWindow::Refresh( bool eraseBackground
, const wxRect
*rect
)
337 wxWindow::Refresh(false,rect
);
339 m_ctrl
->Refresh(eraseBackground
);
343 // Pass focus to control
344 void wxPGClipperWindow::SetFocus()
349 wxWindow::SetFocus();
353 bool wxPGClipperWindow::SetFont(const wxFont
& font
)
355 bool res
= wxWindow::SetFont(font
);
357 return m_ctrl
->SetFont(font
);
362 void wxPGClipperWindow::Create(wxWindow
* parent
,
367 wxWindow::Create(parent
,id
,pos
,size
);
371 wxPGClipperWindow::~wxPGClipperWindow()
376 bool wxPGClipperWindow::ProcessEvent(wxEvent
& event
)
378 if ( event
.GetEventType() == wxEVT_SIZE
)
382 // Maintain correct size relationship.
383 wxSize sz
= GetSize();
384 m_ctrl
->SetSize(sz
.x
+(m_xadj
*2),sz
.y
+(m_yadj
*2));
389 return wxWindow::ProcessEvent(event
);
392 #endif // wxPG_ENABLE_CLIPPER_WINDOW
394 /*wxWindow* wxPropertyGrid::GetActualEditorControl( wxWindow* ctrl )
396 #if wxPG_ENABLE_CLIPPER_WINDOW
397 // Pass real control instead of clipper window
398 if ( ctrl->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
400 return ((wxPGClipperWindow*)ctrl)->GetControl();
407 // -----------------------------------------------------------------------
408 // wxPGTextCtrlEditor
409 // -----------------------------------------------------------------------
411 // Clipper window support macro (depending on whether it is used
412 // for this editor or not)
413 #if wxPG_NAT_TEXTCTRL_BORDER_X || wxPG_NAT_TEXTCTRL_BORDER_Y
414 #define wxPG_NAT_TEXTCTRL_BORDER_ANY 1
416 #define wxPG_NAT_TEXTCTRL_BORDER_ANY 0
419 WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrl
,wxPGTextCtrlEditor
,wxPGEditor
)
422 wxPGWindowList
wxPGTextCtrlEditor::CreateControls( wxPropertyGrid
* propGrid
,
423 wxPGProperty
* property
,
425 const wxSize
& sz
) const
430 // If has children, and limited editing is specified, then don't create.
431 if ( (property
->GetFlags() & wxPG_PROP_NOEDITOR
) &&
432 property
->GetChildCount() )
433 return (wxWindow
*) NULL
;
435 if ( !property
->IsValueUnspecified() )
436 text
= property
->GetValueString(property
->HasFlag(wxPG_PROP_READONLY
)?0:wxPG_EDITABLE_VALUE
);
439 if ( (property
->GetFlags() & wxPG_PROP_PASSWORD
) &&
440 property
->IsKindOf(CLASSINFO(wxStringProperty
)) )
441 flags
|= wxTE_PASSWORD
;
443 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrl(pos
,sz
,text
,(wxWindow
*)NULL
,flags
,
444 property
->GetMaxLength());
450 void wxPGTextCtrlEditor::DrawValue( wxDC
& dc
, wxPGProperty
* property
, const wxRect
& rect
) const
452 if ( !property
->IsValueUnspecified() )
454 wxString drawStr
= property
->GetDisplayedString();
456 // Code below should no longer be needed, as the obfuscation
457 // is now done in GetValueAsString.
458 /*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
459 property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
461 size_t a = drawStr.length();
463 drawStr.Append(wxS('*'),a);
465 dc
.DrawText( drawStr
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
470 void wxPGTextCtrlEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
472 wxTextCtrl
* tc
= wxDynamicCast(ctrl
, wxTextCtrl
);
477 if ( tc
->HasFlag(wxTE_PASSWORD
) )
478 s
= property
->GetValueAsString(wxPG_FULL_VALUE
);
480 s
= property
->GetDisplayedString();
486 // Provided so that, for example, ComboBox editor can use the same code
487 // (multiple inheritance would get way too messy).
488 bool wxPGTextCtrlEditor::OnTextCtrlEvent( wxPropertyGrid
* propGrid
,
489 wxPGProperty
* WXUNUSED(property
),
496 if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER
)
498 if ( propGrid
->IsEditorsValueModified() )
503 else if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED
)
506 // Pass this event outside wxPropertyGrid so that,
507 // if necessary, program can tell when user is editing
509 // FIXME: Is it safe to change event id in the middle of event
510 // processing (seems to work, but...)?
512 event
.SetId(propGrid
->GetId());
514 propGrid
->EditorsValueWasModified();
520 bool wxPGTextCtrlEditor::OnEvent( wxPropertyGrid
* propGrid
,
521 wxPGProperty
* property
,
523 wxEvent
& event
) const
525 return wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid
,property
,ctrl
,event
);
529 bool wxPGTextCtrlEditor::GetTextCtrlValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
)
531 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
532 wxString textVal
= tc
->GetValue();
534 if ( property
->UsesAutoUnspecified() && !textVal
.length() )
540 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
542 // Changing unspecified always causes event (returning
543 // true here should be enough to trigger it).
544 // TODO: Move to propgrid.cpp
545 if ( !res
&& variant
.IsNull() )
552 bool wxPGTextCtrlEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
554 return wxPGTextCtrlEditor::GetTextCtrlValueFromControl(variant
, property
, ctrl
);
558 void wxPGTextCtrlEditor::SetValueToUnspecified( wxPGProperty
* property
, wxWindow
* ctrl
) const
560 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
562 wxPropertyGrid
* pg
= property
->GetGrid();
563 wxASSERT(pg
); // Really, property grid should exist if editor does
565 tc
->SetValue(wxEmptyString
);
569 void wxPGTextCtrlEditor::SetControlStringValue( wxPGProperty
* property
, wxWindow
* ctrl
, const wxString
& txt
) const
571 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
573 wxPropertyGrid
* pg
= property
->GetGrid();
574 wxASSERT(pg
); // Really, property grid should exist if editor does
580 void wxPGTextCtrlEditor::OnFocus( wxPGProperty
*, wxWindow
* wnd
) const
582 wxTextCtrl
* tc
= wxStaticCast(wnd
, wxTextCtrl
);
584 tc
->SetSelection(-1,-1);
588 wxPGTextCtrlEditor::~wxPGTextCtrlEditor() { }
591 // -----------------------------------------------------------------------
593 // -----------------------------------------------------------------------
596 WX_PG_IMPLEMENT_EDITOR_CLASS(Choice
,wxPGChoiceEditor
,wxPGEditor
)
599 // This is a special enhanced double-click processor class.
600 // In essence, it allows for double-clicks for which the
601 // first click "created" the control.
602 class wxPGDoubleClickProcessor
: public wxEvtHandler
606 wxPGDoubleClickProcessor( wxOwnerDrawnComboBox
* combo
, wxPGProperty
* property
)
609 m_timeLastMouseUp
= 0;
611 m_property
= property
;
612 m_downReceived
= false;
617 void OnMouseEvent( wxMouseEvent
& event
)
619 wxLongLong t
= ::wxGetLocalTimeMillis();
620 int evtType
= event
.GetEventType();
622 if ( m_property
->HasFlag(wxPG_PROP_USE_DCC
) &&
623 m_property
->IsKindOf(CLASSINFO(wxBoolProperty
)) &&
624 !m_combo
->IsPopupShown() )
626 // Just check that it is in the text area
627 wxPoint pt
= event
.GetPosition();
628 if ( m_combo
->GetTextRect().Contains(pt
) )
630 if ( evtType
== wxEVT_LEFT_DOWN
)
632 // Set value to avoid up-events without corresponding downs
633 m_downReceived
= true;
635 else if ( evtType
== wxEVT_LEFT_DCLICK
)
637 // We'll make our own double-clicks
638 event
.SetEventType(0);
641 else if ( evtType
== wxEVT_LEFT_UP
)
643 if ( m_downReceived
|| m_timeLastMouseUp
== 1 )
645 wxLongLong timeFromLastUp
= (t
-m_timeLastMouseUp
);
647 if ( timeFromLastUp
< DOUBLE_CLICK_CONVERSION_TRESHOLD
)
649 event
.SetEventType(wxEVT_LEFT_DCLICK
);
650 m_timeLastMouseUp
= 1;
654 m_timeLastMouseUp
= t
;
664 void OnSetFocus( wxFocusEvent
& event
)
666 m_timeLastMouseUp
= ::wxGetLocalTimeMillis();
671 wxLongLong m_timeLastMouseUp
;
672 wxOwnerDrawnComboBox
* m_combo
;
673 wxPGProperty
* m_property
; // Selected property
676 DECLARE_EVENT_TABLE()
679 BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor
, wxEvtHandler
)
680 EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor::OnMouseEvent
)
681 EVT_SET_FOCUS(wxPGDoubleClickProcessor::OnSetFocus
)
686 class wxPGComboBox
: public wxOwnerDrawnComboBox
691 : wxOwnerDrawnComboBox()
693 m_dclickProcessor
= (wxPGDoubleClickProcessor
*) NULL
;
694 m_sizeEventCalled
= false;
699 if ( m_dclickProcessor
)
701 RemoveEventHandler(m_dclickProcessor
);
702 delete m_dclickProcessor
;
706 bool Create(wxWindow
*parent
,
708 const wxString
& value
,
711 const wxArrayString
& choices
,
713 const wxValidator
& validator
= wxDefaultValidator
,
714 const wxString
& name
= wxS("wxOwnerDrawnComboBox"))
716 if ( !wxOwnerDrawnComboBox::Create( parent
,
727 m_dclickProcessor
= new wxPGDoubleClickProcessor(this, GetGrid()->GetSelection() );
729 PushEventHandler(m_dclickProcessor
);
734 virtual void OnDrawItem( wxDC
& dc
, const wxRect
& rect
, int item
, int flags
) const
736 wxPropertyGrid
* pg
= GetGrid();
737 pg
->OnComboItemPaint((wxPGCustomComboControl
*)this,item
,dc
,(wxRect
&)rect
,flags
);
739 virtual wxCoord
OnMeasureItem( size_t item
) const
741 wxPropertyGrid
* pg
= GetGrid();
745 pg
->OnComboItemPaint((wxPGCustomComboControl
*)this,item
,*((wxDC
*)NULL
),rect
,0);
749 wxPropertyGrid
* GetGrid() const
751 wxPropertyGrid
* pg
= wxDynamicCast(GetParent()->GetParent(),wxPropertyGrid
);
756 virtual wxCoord
OnMeasureItemWidth( size_t item
) const
758 wxPropertyGrid
* pg
= GetGrid();
762 pg
->OnComboItemPaint((wxPGCustomComboControl
*)this,item
,*((wxDC
*)NULL
),rect
,0);
766 virtual void PositionTextCtrl( int WXUNUSED(textCtrlXAdjust
), int WXUNUSED(textCtrlYAdjust
) )
768 wxPropertyGrid
* pg
= GetGrid();
769 wxOwnerDrawnComboBox::PositionTextCtrl(
770 wxPG_TEXTCTRLXADJUST
- (wxPG_XBEFOREWIDGET
+wxPG_CONTROL_MARGIN
+1) - 1,
771 pg
->GetSpacingY() + 2
776 wxPGDoubleClickProcessor
* m_dclickProcessor
;
777 bool m_sizeEventCalled
;
781 void wxPropertyGrid::OnComboItemPaint( wxPGCustomComboControl
* pCc
,
787 wxPGComboBox
* pCb
= (wxPGComboBox
*)pCc
;
790 wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid
)) );
792 wxPGProperty
* p
= m_selected
;
795 const wxPGChoices
* pChoices
= &p
->GetChoices();
796 const wxPGCommonValue
* comVal
= NULL
;
797 int choiceCount
= p
->GetChoiceCount();
798 int comVals
= p
->GetDisplayedCommonValueCount();
799 int comValIndex
= -1;
800 if ( item
>= choiceCount
&& comVals
> 0 )
802 comValIndex
= item
- choiceCount
;
803 comVal
= GetCommonValue(comValIndex
);
804 if ( !p
->IsValueUnspecified() )
805 text
= comVal
->GetLabel();
809 if ( !(flags
& wxODCB_PAINTING_CONTROL
) )
811 text
= pCb
->GetString(item
);
815 if ( !p
->IsValueUnspecified() )
816 text
= p
->GetValueString(0);
825 const wxBitmap
* itemBitmap
= NULL
;
827 if ( item
>= 0 && pChoices
&& pChoices
->Item(item
).GetBitmap().Ok() && comValIndex
== -1 )
828 itemBitmap
= &pChoices
->Item(item
).GetBitmap();
831 // Decide what custom image size to use
834 cis
.x
= itemBitmap
->GetWidth();
835 cis
.y
= itemBitmap
->GetHeight();
839 cis
= GetImageSize(p
, item
);
844 // Default measure behaviour (no flexible, custom paint image only)
845 if ( rect
.width
< 0 )
848 GetTextExtent(text
, &x
, &y
, 0, 0, &m_font
);
849 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9 + x
;
852 rect
.height
= cis
.y
+ 2;
856 wxPGPaintData paintdata
;
857 paintdata
.m_parent
= NULL
;
858 paintdata
.m_choiceItem
= item
;
860 // This is by the current (1.0.0b) spec - if painting control, item is -1
861 if ( (flags
& wxODCB_PAINTING_CONTROL
) )
862 paintdata
.m_choiceItem
= -1;
865 dc
.SetBrush(*wxWHITE_BRUSH
);
872 wxPoint
pt(rect
.x
+ wxPG_CONTROL_MARGIN
- wxPG_CHOICEXADJUST
- 1,
877 if ( flags
& wxODCB_PAINTING_CONTROL
)
878 renderFlags
|= wxPGCellRenderer::Control
;
880 if ( flags
& wxODCB_PAINTING_SELECTED
)
881 renderFlags
|= wxPGCellRenderer::Selected
;
883 if ( cis
.x
> 0 && (p
->HasFlag(wxPG_PROP_CUSTOMIMAGE
) || !(flags
& wxODCB_PAINTING_CONTROL
)) &&
884 ( !p
->m_valueBitmap
|| item
== pCb
->GetSelection() ) &&
885 ( item
>= 0 || (flags
& wxODCB_PAINTING_CONTROL
) ) &&
889 pt
.x
+= wxCC_CUSTOM_IMAGE_MARGIN1
;
890 wxRect
r(pt
.x
,pt
.y
,cis
.x
,cis
.y
);
892 if ( flags
& wxODCB_PAINTING_CONTROL
)
895 r
.height
= wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
);
898 paintdata
.m_drawnWidth
= r
.width
;
900 dc
.SetPen(m_colPropFore
);
901 if ( comValIndex
>= 0 )
903 const wxPGCommonValue
* cv
= GetCommonValue(comValIndex
);
904 wxPGCellRenderer
* renderer
= cv
->GetRenderer();
905 r
.width
= rect
.width
;
906 renderer
->Render( dc
, r
, this, p
, m_selColumn
, comValIndex
, renderFlags
);
909 else if ( item
>= 0 )
911 p
->OnCustomPaint( dc
, r
, paintdata
);
915 dc
.DrawRectangle( r
);
918 pt
.x
+= paintdata
.m_drawnWidth
+ wxCC_CUSTOM_IMAGE_MARGIN2
- 1;
922 // TODO: This aligns text so that it seems to be horizontally
923 // on the same line as property values. Not really
924 // sure if its needed, but seems to not cause any harm.
927 if ( item
< 0 && (flags
& wxODCB_PAINTING_CONTROL
) )
928 item
= pCb
->GetSelection();
930 if ( pChoices
&& item
>= 0 && comValIndex
< 0 )
932 const wxPGChoiceEntry
& cell
= pChoices
->Item(item
);
933 wxPGCellRenderer
* renderer
= wxPGGlobalVars
->m_defaultRenderer
;
934 int imageOffset
= renderer
->PreDrawCell( dc
, rect
, cell
, renderFlags
);
936 imageOffset
+= wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
;
945 pt
.y
+= (rect
.height
-m_fontHeight
)/2 - 1;
949 dc
.DrawText( text
, pt
.x
+ wxPG_XBEFORETEXT
, pt
.y
);
956 p
->OnCustomPaint( dc
, rect
, paintdata
);
957 rect
.height
= paintdata
.m_drawnHeight
+ 2;
958 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9;
962 bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid
* propGrid
, wxPGComboBox
* cb
, int cmnVal
)
964 wxPGProperty
* property
= propGrid
->GetSelectedProperty();
965 wxASSERT( property
);
969 // Yes, a common value is being selected
970 property
->SetCommonValue( cmnVal
);
971 wxSize imageSize
= propGrid
->GetCommonValue(cmnVal
)->
972 GetRenderer()->GetImageSize(property
, 1, cmnVal
);
973 if ( imageSize
.x
) imageSize
.x
+= ODCB_CUST_PAINT_MARGIN
;
974 cb
->SetCustomPaintWidth( imageSize
.x
);
979 wxSize imageSize
= propGrid
->GetImageSize(property
, -1);
980 if ( imageSize
.x
) imageSize
.x
+= ODCB_CUST_PAINT_MARGIN
;
981 cb
->SetCustomPaintWidth( imageSize
.x
);
986 // CreateControls calls this with CB_READONLY in extraStyle
987 wxWindow
* wxPGChoiceEditor::CreateControlsBase( wxPropertyGrid
* propGrid
,
988 wxPGProperty
* property
,
991 long extraStyle
) const
996 int index
= property
->GetChoiceInfo( NULL
);
998 bool isUnspecified
= property
->IsValueUnspecified();
1000 if ( isUnspecified
)
1003 defString
= property
->GetDisplayedString();
1005 const wxPGChoices
& choices
= property
->GetChoices();
1007 wxArrayString labels
= choices
.GetLabels();
1013 po
.y
+= wxPG_CHOICEYADJUST
;
1014 si
.y
-= (wxPG_CHOICEYADJUST
*2);
1016 po
.x
+= wxPG_CHOICEXADJUST
;
1017 si
.x
-= wxPG_CHOICEXADJUST
;
1018 wxWindow
* ctrlParent
= propGrid
->GetPanel();
1020 int odcbFlags
= extraStyle
| wxNO_BORDER
| wxTE_PROCESS_ENTER
;
1023 // If common value specified, use appropriate index
1024 unsigned int cmnVals
= property
->GetDisplayedCommonValueCount();
1027 if ( !isUnspecified
)
1029 int cmnVal
= property
->GetCommonValue();
1032 index
= labels
.size() + cmnVal
;
1037 for ( i
=0; i
<cmnVals
; i
++ )
1038 labels
.Add(propGrid
->GetCommonValueLabel(i
));
1041 cb
= new wxPGComboBox();
1045 cb
->Create(ctrlParent
,
1053 //int extRight = propGrid->GetClientSize().x - (po.x+si.x);
1054 //int extRight = - (po.x+si.x);
1056 cb
->SetButtonPosition(si
.y
,0,wxRIGHT
);
1057 //cb->SetPopupExtents( 1, extRight );
1058 cb
->SetTextIndent(wxPG_XBEFORETEXT
-1);
1060 wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
, property
->GetCommonValue() );
1061 /*if ( property->GetFlags() & wxPG_PROP_CUSTOMIMAGE )
1063 wxSize imageSize = propGrid->GetImageSize(property, index);
1064 if ( imageSize.x ) imageSize.x += ODCB_CUST_PAINT_MARGIN;
1065 cb->SetCustomPaintWidth( imageSize.x );
1068 if ( index
>= 0 && index
< (int)cb
->GetCount() )
1070 cb
->SetSelection( index
);
1071 if ( defString
.length() )
1072 cb
->SetText( defString
);
1074 else if ( !(extraStyle
& wxCB_READONLY
) && defString
.length() )
1075 cb
->SetValue( defString
);
1077 cb
->SetSelection( -1 );
1083 return (wxWindow
*) cb
;
1087 void wxPGChoiceEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1090 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1091 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
1092 int ind
= property
->GetChoiceInfo( (wxPGChoiceInfo
*)NULL
);
1093 cb
->SetSelection(ind
);
1096 wxPGWindowList
wxPGChoiceEditor::CreateControls( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
1097 const wxPoint
& pos
, const wxSize
& sz
) const
1099 return CreateControlsBase(propGrid
,property
,pos
,sz
,wxCB_READONLY
);
1103 int wxPGChoiceEditor::InsertItem( wxWindow
* ctrl
, const wxString
& label
, int index
) const
1106 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1107 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
1110 index
= cb
->GetCount();
1112 return cb
->Insert(label
,index
);
1116 void wxPGChoiceEditor::DeleteItem( wxWindow
* ctrl
, int index
) const
1119 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1120 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
1125 bool wxPGChoiceEditor::OnEvent( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
1126 wxWindow
* ctrl
, wxEvent
& event
) const
1128 if ( event
.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED
)
1130 wxPGComboBox
* cb
= (wxPGComboBox
*)ctrl
;
1131 int index
= cb
->GetSelection();
1132 int cmnValIndex
= -1;
1133 int cmnVals
= property
->GetDisplayedCommonValueCount();
1134 int items
= cb
->GetCount();
1136 if ( index
>= (items
-cmnVals
) )
1138 // Yes, a common value is being selected
1139 cmnValIndex
= index
- (items
-cmnVals
);
1140 property
->SetCommonValue( cmnValIndex
);
1142 // Truly set value to unspecified?
1143 if ( propGrid
->GetUnspecifiedCommonValue() == cmnValIndex
)
1145 if ( !property
->IsValueUnspecified() )
1146 propGrid
->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT
);
1147 property
->SetValueToUnspecified();
1148 if ( !cb
->HasFlag(wxCB_READONLY
) )
1149 cb
->GetTextCtrl()->SetValue(wxEmptyString
);
1153 return wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
, cmnValIndex
);
1159 bool wxPGChoiceEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1161 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1163 int index
= cb
->GetSelection();
1165 if ( index
!= property
->GetChoiceInfo( (wxPGChoiceInfo
*) NULL
) ||
1166 // Changing unspecified always causes event (returning
1167 // true here should be enough to trigger it).
1168 property
->IsValueUnspecified()
1171 return property
->IntToValue( variant
, index
, 0 );
1177 void wxPGChoiceEditor::SetControlStringValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, const wxString
& txt
) const
1179 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1185 void wxPGChoiceEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
1187 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1189 cb
->SetSelection(value
);
1193 void wxPGChoiceEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
) const
1195 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1196 cb
->SetSelection(-1);
1200 bool wxPGChoiceEditor::CanContainCustomImage() const
1206 wxPGChoiceEditor::~wxPGChoiceEditor() { }
1209 // -----------------------------------------------------------------------
1210 // wxPGComboBoxEditor
1211 // -----------------------------------------------------------------------
1214 WX_PG_IMPLEMENT_EDITOR_CLASS(ComboBox
,wxPGComboBoxEditor
,wxPGChoiceEditor
)
1217 void wxPGComboBoxEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1219 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1220 cb
->SetValue(property
->GetValueString(wxPG_EDITABLE_VALUE
));
1222 // TODO: If string matches any selection, then select that.
1226 wxPGWindowList
wxPGComboBoxEditor::CreateControls( wxPropertyGrid
* propGrid
,
1227 wxPGProperty
* property
,
1229 const wxSize
& sz
) const
1231 return CreateControlsBase(propGrid
,property
,pos
,sz
,0);
1235 bool wxPGComboBoxEditor::OnEvent( wxPropertyGrid
* propGrid
,
1236 wxPGProperty
* property
,
1238 wxEvent
& event
) const
1240 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*) NULL
;
1241 wxWindow
* textCtrl
= (wxWindow
*) NULL
;
1245 cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1246 textCtrl
= cb
->GetTextCtrl();
1249 if ( wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid
,property
,textCtrl
,event
) )
1252 return wxPGChoiceEditor::OnEvent(propGrid
,property
,ctrl
,event
);
1256 bool wxPGComboBoxEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1258 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1259 wxString textVal
= cb
->GetValue();
1261 if ( property
->UsesAutoUnspecified() && !textVal
.length() )
1267 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
1269 // Changing unspecified always causes event (returning
1270 // true here should be enough to trigger it).
1271 if ( !res
&& variant
.IsNull() )
1278 void wxPGComboBoxEditor::OnFocus( wxPGProperty
*, wxWindow
* ctrl
) const
1280 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1281 cb
->GetTextCtrl()->SetSelection(-1,-1);
1285 wxPGComboBoxEditor::~wxPGComboBoxEditor() { }
1288 // -----------------------------------------------------------------------
1289 // wxPGChoiceAndButtonEditor
1290 // -----------------------------------------------------------------------
1293 // This simpler implement_editor macro doesn't define class body.
1294 WX_PG_IMPLEMENT_EDITOR_CLASS(ChoiceAndButton
,wxPGChoiceAndButtonEditor
,wxPGChoiceEditor
)
1297 wxPGWindowList
wxPGChoiceAndButtonEditor::CreateControls( wxPropertyGrid
* propGrid
,
1298 wxPGProperty
* property
,
1300 const wxSize
& sz
) const
1302 // Use one two units smaller to match size of the combo's dropbutton.
1303 // (normally a bigger button is used because it looks better)
1306 wxSize
bt_sz(bt_wid
,bt_wid
);
1308 // Position of button.
1309 wxPoint
bt_pos(pos
.x
+sz
.x
-bt_sz
.x
,pos
.y
);
1316 wxWindow
* bt
= propGrid
->GenerateEditorButton( bt_pos
, bt_sz
);
1319 wxSize
ch_sz(sz
.x
-bt
->GetSize().x
,sz
.y
);
1322 ch_sz
.x
-= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1325 wxWindow
* ch
= wxPG_EDITOR(Choice
)->CreateControls(propGrid
,property
,
1326 pos
,ch_sz
).m_primary
;
1332 return wxPGWindowList(ch
, bt
);
1336 wxPGChoiceAndButtonEditor::~wxPGChoiceAndButtonEditor() { }
1339 // -----------------------------------------------------------------------
1340 // wxPGTextCtrlAndButtonEditor
1341 // -----------------------------------------------------------------------
1344 // This simpler implement_editor macro doesn't define class body.
1345 WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrlAndButton
,wxPGTextCtrlAndButtonEditor
,wxPGTextCtrlEditor
)
1348 wxPGWindowList
wxPGTextCtrlAndButtonEditor::CreateControls( wxPropertyGrid
* propGrid
,
1349 wxPGProperty
* property
,
1351 const wxSize
& sz
) const
1354 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrlAndButton( pos
, sz
, &wnd2
,
1355 property
->GetFlags() & wxPG_PROP_NOEDITOR
, property
);
1357 return wxPGWindowList(wnd
, wnd2
);
1361 wxPGTextCtrlAndButtonEditor::~wxPGTextCtrlAndButtonEditor() { }
1364 // -----------------------------------------------------------------------
1365 // wxPGCheckBoxEditor
1366 // -----------------------------------------------------------------------
1368 #if wxPG_INCLUDE_CHECKBOX
1370 WX_PG_IMPLEMENT_EDITOR_CLASS(CheckBox
,wxPGCheckBoxEditor
,wxPGEditor
)
1373 // state argument: 0x01 = set if checked
1374 // 0x02 = set if rectangle should be bold
1375 static void DrawSimpleCheckBox( wxDC
& dc
, const wxRect
& rect
, int box_hei
, int state
, const wxColour
& linecol
)
1379 wxRect
r(rect
.x
+wxPG_XBEFORETEXT
,rect
.y
+((rect
.height
-box_hei
)/2),box_hei
,box_hei
);
1381 // Draw check mark first because it is likely to overdraw the
1382 // surrounding rectangle.
1385 wxRect
r2(r
.x
+wxPG_CHECKMARK_XADJ
,
1386 r
.y
+wxPG_CHECKMARK_YADJ
,
1387 r
.width
+wxPG_CHECKMARK_WADJ
,
1388 r
.height
+wxPG_CHECKMARK_HADJ
);
1389 #if wxPG_CHECKMARK_DEFLATE
1390 r2
.Deflate(wxPG_CHECKMARK_DEFLATE
);
1392 dc
.DrawCheckMark(r2
);
1394 // This would draw a simple cross check mark.
1395 // dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
1396 // dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
1402 // Pen for thin rectangle.
1407 // Pen for bold rectangle.
1408 wxPen
linepen(linecol
,2,wxSOLID
);
1409 linepen
.SetJoin(wxJOIN_MITER
); // This prevents round edges.
1417 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1419 dc
.DrawRectangle(r
);
1420 dc
.SetPen(*wxTRANSPARENT_PEN
);
1424 // Real simple custom-drawn checkbox-without-label class.
1426 class wxSimpleCheckBox
: public wxControl
1430 void SetValue( int value
);
1432 wxSimpleCheckBox( wxWindow
* parent
,
1434 const wxPoint
& pos
= wxDefaultPosition
,
1435 const wxSize
& size
= wxDefaultSize
)
1436 : wxControl(parent
,id
,pos
,size
,wxNO_BORDER
|wxWANTS_CHARS
)
1438 // Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
1439 SetFont( parent
->GetFont() );
1442 wxPropertyGrid
* pg
= (wxPropertyGrid
*) parent
->GetParent();
1443 wxASSERT( pg
->IsKindOf(CLASSINFO(wxPropertyGrid
)) );
1444 m_boxHeight
= pg
->GetFontHeight();
1445 SetBackgroundStyle( wxBG_STYLE_COLOUR
);
1448 virtual ~wxSimpleCheckBox();
1450 virtual bool ProcessEvent(wxEvent
& event
);
1455 static wxBitmap
* ms_doubleBuffer
;
1459 wxSimpleCheckBox::~wxSimpleCheckBox()
1461 delete ms_doubleBuffer
;
1462 ms_doubleBuffer
= NULL
;
1466 wxBitmap
* wxSimpleCheckBox::ms_doubleBuffer
= (wxBitmap
*) NULL
;
1468 // value = 2 means toggle (sorry, too lazy to do constants)
1469 void wxSimpleCheckBox::SetValue( int value
)
1474 if ( m_state
> 1 ) m_state
= 0;
1482 wxCommandEvent
evt(wxEVT_COMMAND_CHECKBOX_CLICKED
,GetParent()->GetId());
1484 wxPropertyGrid
* propGrid
= (wxPropertyGrid
*) GetParent()->GetParent();
1485 wxASSERT( propGrid
->IsKindOf(CLASSINFO(wxPropertyGrid
)) );
1486 propGrid
->OnCustomEditorEvent(evt
);
1490 bool wxSimpleCheckBox::ProcessEvent(wxEvent
& event
)
1492 wxPropertyGrid
* propGrid
= (wxPropertyGrid
*) GetParent()->GetParent();
1493 wxASSERT( propGrid
->IsKindOf(CLASSINFO(wxPropertyGrid
)) );
1495 if ( event
.GetEventType() == wxEVT_NAVIGATION_KEY
)
1497 //wxLogDebug(wxT("wxEVT_NAVIGATION_KEY"));
1498 //SetFocusFromKbd();
1500 //return wxControl::ProcessEvent(event);
1503 if ( ( (event
.GetEventType() == wxEVT_LEFT_DOWN
|| event
.GetEventType() == wxEVT_LEFT_DCLICK
)
1504 && ((wxMouseEvent
&)event
).m_x
> (wxPG_XBEFORETEXT
-2)
1505 && ((wxMouseEvent
&)event
).m_x
<= (wxPG_XBEFORETEXT
-2+m_boxHeight
) )
1511 else if ( event
.GetEventType() == wxEVT_PAINT
)
1513 wxSize clientSize
= GetClientSize();
1517 // Buffered paint DC doesn't seem to do much good
1518 if ( !ms_doubleBuffer ||
1519 clientSize.x > ms_doubleBuffer->GetWidth() ||
1520 clientSize.y > ms_doubleBuffer->GetHeight() )
1522 delete ms_doubleBuffer;
1523 ms_doubleBuffer = new wxBitmap(clientSize.x+25,clientSize.y+25);
1526 wxBufferedPaintDC dc(this,*ms_doubleBuffer);
1529 wxRect
rect(0,0,clientSize
.x
,clientSize
.y
);
1534 m_boxHeight
= propGrid
->GetFontHeight();
1536 wxColour bgcol
= GetBackgroundColour();
1537 dc
.SetBrush( bgcol
);
1539 dc
.DrawRectangle( rect
);
1541 wxColour txcol
= GetForegroundColour();
1543 int state
= m_state
;
1544 if ( m_font
.GetWeight() == wxBOLD
)
1547 DrawSimpleCheckBox(dc
,rect
,m_boxHeight
,state
,txcol
);
1549 // If focused, indicate it somehow.
1551 if ( wxWindow::FindFocus() == this )
1556 wxPGDrawFocusRect(dc,rect);
1562 else if ( event
.GetEventType() == wxEVT_SIZE
||
1563 event
.GetEventType() == wxEVT_SET_FOCUS
||
1564 event
.GetEventType() == wxEVT_KILL_FOCUS
1569 else if ( event
.GetEventType() == wxEVT_KEY_DOWN
)
1571 wxKeyEvent
& keyEv
= (wxKeyEvent
&) event
;
1573 if ( keyEv
.GetKeyCode() == WXK_TAB
)
1575 propGrid
->SendNavigationKeyEvent( keyEv
.ShiftDown()?0:1 );
1579 if ( keyEv
.GetKeyCode() == WXK_SPACE
)
1585 return wxControl::ProcessEvent(event
);
1589 wxPGWindowList
wxPGCheckBoxEditor::CreateControls( wxPropertyGrid
* propGrid
,
1590 wxPGProperty
* property
,
1592 const wxSize
& size
) const
1595 pt
.x
-= wxPG_XBEFOREWIDGET
;
1597 sz
.x
= propGrid
->GetFontHeight() + (wxPG_XBEFOREWIDGET
*2) + 4;
1599 wxSimpleCheckBox
* cb
= new wxSimpleCheckBox(propGrid
->GetPanel(),wxPG_SUBID1
,pt
,sz
);
1601 cb
->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
1603 cb
->Connect( wxPG_SUBID1
, wxEVT_LEFT_DOWN
,
1604 (wxObjectEventFunction
) (wxEventFunction
) (wxCommandEventFunction
)
1605 &wxPropertyGrid::OnCustomEditorEvent
, NULL
, propGrid
);
1607 cb
->Connect( wxPG_SUBID1
, wxEVT_LEFT_DCLICK
,
1608 (wxObjectEventFunction
) (wxEventFunction
) (wxCommandEventFunction
)
1609 &wxPropertyGrid::OnCustomEditorEvent
, NULL
, propGrid
);
1611 if ( property
->GetChoiceInfo((wxPGChoiceInfo
*)NULL
) &&
1612 !property
->IsValueUnspecified() )
1615 // If mouse cursor was on the item, toggle the value now.
1616 if ( propGrid
->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK
)
1618 wxPoint pt
= cb
->ScreenToClient(::wxGetMousePosition());
1619 if ( pt
.x
<= (wxPG_XBEFORETEXT
-2+cb
->m_boxHeight
) )
1623 if ( cb
->m_state
> 1 )
1626 // Makes sure wxPG_EVT_CHANGING etc. is sent for this initial click
1627 propGrid
->ChangePropertyValue(property
, wxPGVariant_Bool(cb
->m_state
));
1631 propGrid
->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR
);
1637 class wxPGCheckBoxRenderer : public wxPGDefaultRenderer
1641 virtual void Render( wxDC& dc, const wxRect& rect,
1642 const wxPropertyGrid* WXUNUSED(propertyGrid), wxPGProperty* property,
1643 int WXUNUSED(column), int WXUNUSED(item), int WXUNUSED(flags) ) const
1646 if ( !(property->GetFlags() & wxPG_PROP_UNSPECIFIED) )
1648 state = ((wxPGProperty*)property)->GetChoiceInfo((wxPGChoiceInfo*)NULL);
1649 if ( dc.GetFont().GetWeight() == wxBOLD ) state |= 2;
1651 DrawSimpleCheckBox(dc,rect,dc.GetCharHeight(),state,dc.GetTextForeground());
1657 wxPGCheckBoxRenderer g_wxPGCheckBoxRenderer;
1659 wxPGCellRenderer* wxPGCheckBoxEditor::GetCellRenderer() const
1661 return &g_wxPGCheckBoxRenderer;
1665 void wxPGCheckBoxEditor::DrawValue( wxDC
& dc
, const wxRect
& rect
, wxPGProperty
* property
, const wxString
& WXUNUSED(text
) ) const
1668 if ( !property
->IsValueUnspecified() )
1670 state
= property
->GetChoiceInfo((wxPGChoiceInfo
*)NULL
);
1671 if ( dc
.GetFont().GetWeight() == wxBOLD
) state
|= 2;
1673 DrawSimpleCheckBox(dc
,rect
,dc
.GetCharHeight(),state
,dc
.GetTextForeground());
1676 void wxPGCheckBoxEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1679 ((wxSimpleCheckBox
*)ctrl
)->m_state
= property
->GetChoiceInfo((wxPGChoiceInfo
*)NULL
);
1684 bool wxPGCheckBoxEditor::OnEvent( wxPropertyGrid
* WXUNUSED(propGrid
), wxPGProperty
* WXUNUSED(property
),
1685 wxWindow
* WXUNUSED(ctrl
), wxEvent
& event
) const
1687 if ( event
.GetEventType() == wxEVT_COMMAND_CHECKBOX_CLICKED
)
1695 bool wxPGCheckBoxEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1697 wxSimpleCheckBox
* cb
= (wxSimpleCheckBox
*)ctrl
;
1699 int index
= cb
->m_state
;
1701 if ( index
!= property
->GetChoiceInfo( (wxPGChoiceInfo
*) NULL
) ||
1702 // Changing unspecified always causes event (returning
1703 // true here should be enough to trigger it).
1704 property
->IsValueUnspecified()
1707 return property
->IntToValue(variant
, index
, 0);
1713 void wxPGCheckBoxEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
1715 if ( value
!= 0 ) value
= 1;
1716 ((wxSimpleCheckBox
*)ctrl
)->m_state
= value
;
1721 void wxPGCheckBoxEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
) const
1723 ((wxSimpleCheckBox
*)ctrl
)->m_state
= 0;
1728 wxPGCheckBoxEditor::~wxPGCheckBoxEditor() { }
1731 #endif // wxPG_INCLUDE_CHECKBOX
1733 // -----------------------------------------------------------------------
1735 wxWindow
* wxPropertyGrid::GetEditorControl() const
1737 wxWindow
* ctrl
= m_wndEditor
;
1742 // If it's clipper window, return its child instead
1743 #if wxPG_ENABLE_CLIPPER_WINDOW
1744 if ( ctrl
->IsKindOf(CLASSINFO(wxPGClipperWindow
)) )
1746 return ((wxPGClipperWindow
*)ctrl
)->GetControl();
1753 // -----------------------------------------------------------------------
1755 void wxPropertyGrid::CorrectEditorWidgetSizeX()
1757 if ( m_selColumn
== -1 )
1761 int newSplitterx
= m_pState
->DoGetSplitterPosition(m_selColumn
-1);
1762 int newWidth
= newSplitterx
+ m_pState
->m_colWidths
[m_selColumn
];
1766 // if width change occurred, move secondary wnd by that amount
1767 wxRect r
= m_wndEditor2
->GetRect();
1769 r
.x
= newWidth
- secWid
;
1771 m_wndEditor2
->SetSize( r
);
1773 // if primary is textctrl, then we have to add some extra space
1777 if ( m_wndEditor
&& m_wndEditor
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
1779 secWid
+= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1784 wxRect r
= m_wndEditor
->GetRect();
1786 r
.x
= newSplitterx
+m_ctrlXAdjust
;
1788 if ( !(m_iFlags
& wxPG_FL_FIXED_WIDTH_EDITOR
) )
1789 r
.width
= newWidth
- r
.x
- secWid
;
1791 m_wndEditor
->SetSize(r
);
1795 m_wndEditor2
->Refresh();
1798 // -----------------------------------------------------------------------
1800 void wxPropertyGrid::CorrectEditorWidgetPosY()
1802 if ( m_selected
&& (m_wndEditor
|| m_wndEditor2
) )
1804 wxRect r
= GetEditorWidgetRect(m_selected
, m_selColumn
);
1808 wxPoint pos
= m_wndEditor
->GetPosition();
1810 // Calculate y offset
1811 int offset
= pos
.y
% m_lineHeight
;
1813 m_wndEditor
->Move(pos
.x
, r
.y
+ offset
);
1818 wxPoint pos
= m_wndEditor2
->GetPosition();
1820 m_wndEditor2
->Move(pos
.x
, r
.y
);
1825 // -----------------------------------------------------------------------
1827 bool wxPropertyGrid::AdjustPosForClipperWindow( wxWindow
* topCtrlWnd
, int* x
, int* y
)
1829 #if wxPG_ENABLE_CLIPPER_WINDOW
1830 // Take clipper window into account
1831 if (topCtrlWnd
->GetPosition().x
< 1 &&
1832 !topCtrlWnd
->IsKindOf(CLASSINFO(wxPGClipperWindow
)))
1834 topCtrlWnd
= topCtrlWnd
->GetParent();
1835 wxASSERT( topCtrlWnd
->IsKindOf(CLASSINFO(wxPGClipperWindow
)) );
1836 *x
-= ((wxPGClipperWindow
*)topCtrlWnd
)->GetXClip();
1837 *y
-= ((wxPGClipperWindow
*)topCtrlWnd
)->GetYClip();
1841 wxUnusedVar(topCtrlWnd
);
1848 // -----------------------------------------------------------------------
1850 // Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
1851 // fits into that category as well).
1852 void wxPropertyGrid::FixPosForTextCtrl( wxWindow
* ctrl
, const wxPoint
& offset
)
1854 // Center the control vertically
1855 wxRect finalPos
= ctrl
->GetRect();
1856 int y_adj
= (m_lineHeight
- finalPos
.height
)/2 + wxPG_TEXTCTRLYADJUST
;
1858 // Prevent over-sized control
1859 int sz_dec
= (y_adj
+ finalPos
.height
) - m_lineHeight
;
1860 if ( sz_dec
< 0 ) sz_dec
= 0;
1862 finalPos
.y
+= y_adj
;
1863 finalPos
.height
-= (y_adj
+sz_dec
);
1865 const int textCtrlXAdjust
= wxPG_TEXTCTRLXADJUST
;
1867 finalPos
.x
+= textCtrlXAdjust
;
1868 finalPos
.width
-= textCtrlXAdjust
;
1870 finalPos
.x
+= offset
.x
;
1871 finalPos
.y
+= offset
.y
;
1873 ctrl
->SetSize(finalPos
);
1876 // -----------------------------------------------------------------------
1878 wxWindow
* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint
& pos
,
1880 const wxString
& value
,
1881 wxWindow
* secondary
,
1885 wxPGProperty
* selected
= m_selected
;
1888 int tcFlags
= wxTE_PROCESS_ENTER
| extraStyle
;
1890 if ( selected
->HasFlag(wxPG_PROP_READONLY
) )
1891 tcFlags
|= wxTE_READONLY
;
1893 wxPoint
p(pos
.x
,pos
.y
);
1894 wxSize
s(sz
.x
,sz
.y
);
1896 // Need to reduce width of text control on Mac
1897 #if defined(__WXMAC__)
1901 // Take button into acccount
1904 s
.x
-= (secondary
->GetSize().x
+ wxPG_TEXTCTRL_AND_BUTTON_SPACING
);
1905 m_iFlags
&= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE
);
1908 // If the height is significantly higher, then use border, and fill the rect exactly.
1909 bool hasSpecialSize
= false;
1911 if ( (sz
.y
- m_lineHeight
) > 5 )
1912 hasSpecialSize
= true;
1914 #if wxPG_NAT_TEXTCTRL_BORDER_ANY
1916 // Create clipper window
1917 wxPGClipperWindow
* wnd
= new wxPGClipperWindow();
1918 #if defined(__WXMSW__)
1921 wnd
->Create(GetPanel(),wxPG_SUBID1
,p
,s
);
1923 // This generates rect of the control inside the clipper window
1924 if ( !hasSpecialSize
)
1925 wnd
->GetControlRect(wxPG_NAT_TEXTCTRL_BORDER_X
, wxPG_NAT_TEXTCTRL_BORDER_Y
, p
, s
);
1927 wnd
->GetControlRect(0, 0, p
, s
);
1929 wxWindow
* ctrlParent
= wnd
;
1933 wxWindow
* ctrlParent
= GetPanel();
1935 if ( !hasSpecialSize
)
1936 tcFlags
|= wxNO_BORDER
;
1940 wxTextCtrl
* tc
= new wxTextCtrl();
1942 #if defined(__WXMSW__) && !wxPG_NAT_TEXTCTRL_BORDER_ANY
1945 SetupTextCtrlValue(value
);
1946 tc
->Create(ctrlParent
,wxPG_SUBID1
,value
, p
, s
,tcFlags
);
1948 #if wxPG_NAT_TEXTCTRL_BORDER_ANY
1950 wnd
->SetControl(tc
);
1955 // Center the control vertically
1956 if ( !hasSpecialSize
)
1957 FixPosForTextCtrl(ed
);
1965 // Set maximum length
1967 tc
->SetMaxLength( maxLen
);
1969 return (wxWindow
*) ed
;
1972 // -----------------------------------------------------------------------
1974 wxWindow
* wxPropertyGrid::GenerateEditorButton( const wxPoint
& pos
, const wxSize
& sz
)
1976 wxPGProperty
* selected
= m_selected
;
1980 // Decorations are chunky on Mac, and we can't make the button square, so
1981 // do things a bit differently on this platform.
1983 wxPoint
p(pos
.x
+sz
.x
,
1984 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
1987 wxButton
* but
= new wxButton();
1988 but
->Create(GetPanel(),wxPG_SUBID2
,wxS("..."),p
,s
,wxWANTS_CHARS
);
1990 // Now that we know the size, move to the correct position
1991 p
.x
= pos
.x
+ sz
.x
- but
->GetSize().x
- 2;
1995 wxSize
s(sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2),
1996 sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2));
1998 // Reduce button width to lineheight
1999 if ( s
.x
> m_lineHeight
)
2003 // On wxGTK, take fixed button margins into account
2008 wxPoint
p(pos
.x
+sz
.x
-s
.x
,
2009 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
2011 wxButton
* but
= new wxButton();
2015 but
->Create(GetPanel(),wxPG_SUBID2
,wxS("..."),p
,s
,wxWANTS_CHARS
);
2018 wxFont font
= GetFont();
2019 font
.SetPointSize(font
.GetPointSize()-2);
2022 but
->SetFont(GetFont());
2026 if ( selected
->HasFlag(wxPG_PROP_READONLY
) )
2032 // -----------------------------------------------------------------------
2034 wxWindow
* wxPropertyGrid::GenerateEditorTextCtrlAndButton( const wxPoint
& pos
,
2036 wxWindow
** psecondary
,
2038 wxPGProperty
* property
)
2040 wxButton
* but
= (wxButton
*)GenerateEditorButton(pos
,sz
);
2041 *psecondary
= (wxWindow
*)but
;
2043 if ( limitedEditing
)
2046 // There is button Show in GenerateEditorTextCtrl as well
2049 return (wxWindow
*) NULL
;
2054 if ( !property
->IsValueUnspecified() )
2055 text
= property
->GetValueString(property
->HasFlag(wxPG_PROP_READONLY
)?0:wxPG_EDITABLE_VALUE
);
2057 return GenerateEditorTextCtrl(pos
,sz
,text
,but
,property
->m_maxLen
);
2060 // -----------------------------------------------------------------------
2062 wxTextCtrl
* wxPropertyGrid::GetEditorTextCtrl() const
2064 wxWindow
* wnd
= GetEditorControl();
2069 if ( wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
2070 return wxStaticCast(wnd
, wxTextCtrl
);
2072 if ( wnd
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) )
2074 wxOwnerDrawnComboBox
* cb
= wxStaticCast(wnd
, wxOwnerDrawnComboBox
);
2075 return cb
->GetTextCtrl();
2081 // -----------------------------------------------------------------------
2083 wxPGEditor
* wxPropertyGridInterface::GetEditorByName( const wxString
& editorName
)
2085 wxPGHashMapS2P::const_iterator it
;
2087 it
= wxPGGlobalVars
->m_mapEditorClasses
.find(editorName
);
2088 if ( it
== wxPGGlobalVars
->m_mapEditorClasses
.end() )
2090 return (wxPGEditor
*) it
->second
;
2093 // -----------------------------------------------------------------------
2094 // wxPGEditorDialogAdapter
2095 // -----------------------------------------------------------------------
2097 IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter
, wxObject
)
2099 bool wxPGEditorDialogAdapter::ShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
2101 if ( !propGrid
->EditorValidate() )
2104 bool res
= DoShowDialog( propGrid
, property
);
2108 propGrid
->ValueChangeInEvent( m_value
);
2115 // -----------------------------------------------------------------------
2117 // -----------------------------------------------------------------------
2119 wxPGMultiButton::wxPGMultiButton( wxPropertyGrid
* pg
, const wxSize
& sz
)
2120 : wxWindow( pg
->GetPanel(), wxPG_SUBID2
, wxPoint(-100,-100), wxSize(0, sz
.y
) ),
2121 m_fullEditorSize(sz
), m_buttonsWidth(0)
2123 SetBackgroundColour(pg
->GetCellBackgroundColour());
2126 int wxPGMultiButton::GenId( int id
) const
2130 if ( m_buttons
.size() )
2131 id
= GetButton(m_buttons
.size()-1)->GetId() + 1;
2139 void wxPGMultiButton::Add( const wxBitmap
& bitmap
, int id
)
2142 wxSize sz
= GetSize();
2143 wxButton
* button
= new wxBitmapButton( this, id
, bitmap
, wxPoint(sz
.x
, 0), wxSize(sz
.y
, sz
.y
) );
2144 m_buttons
.push_back(button
);
2145 int bw
= button
->GetSize().x
;
2146 SetSize(wxSize(sz
.x
+bw
,sz
.y
));
2147 m_buttonsWidth
+= bw
;
2151 void wxPGMultiButton::Add( const wxString
& label
, int id
)
2154 wxSize sz
= GetSize();
2155 wxButton
* button
= new wxButton( this, id
, label
, wxPoint(sz
.x
, 0), wxSize(sz
.y
, sz
.y
) );
2156 m_buttons
.push_back(button
);
2157 int bw
= button
->GetSize().x
;
2158 SetSize(wxSize(sz
.x
+bw
,sz
.y
));
2159 m_buttonsWidth
+= bw
;
2162 // -----------------------------------------------------------------------