1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/editors.cpp
3 // Purpose: wxPropertyGrid editors
4 // Author: Jaakko Salli
8 // Copyright: (c) Jaakko Salli
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
12 // For compilers that support precompilation, includes "wx/wx.h".
13 #include "wx/wxprec.h"
23 #include "wx/object.h"
25 #include "wx/string.h"
28 #include "wx/window.h"
31 #include "wx/dcclient.h"
32 #include "wx/dcmemory.h"
33 #include "wx/button.h"
36 #include "wx/cursor.h"
37 #include "wx/dialog.h"
38 #include "wx/settings.h"
39 #include "wx/msgdlg.h"
40 #include "wx/choice.h"
41 #include "wx/stattext.h"
42 #include "wx/scrolwin.h"
43 #include "wx/dirdlg.h"
45 #include "wx/textdlg.h"
46 #include "wx/filedlg.h"
47 #include "wx/statusbr.h"
54 #include "wx/dcbuffer.h"
55 #include "wx/bmpbuttn.h"
58 // This define is necessary to prevent macro clearing
59 #define __wxPG_SOURCE_FILE__
61 #include "wx/propgrid/propgrid.h"
62 #include "wx/propgrid/editors.h"
63 #include "wx/propgrid/props.h"
65 #if wxPG_USE_RENDERER_NATIVE
66 #include "wx/renderer.h"
69 // How many pixels between textctrl and button
71 #define wxPG_TEXTCTRL_AND_BUTTON_SPACING 4
73 #define wxPG_TEXTCTRL_AND_BUTTON_SPACING 2
76 #define wxPG_BUTTON_SIZEDEC 0
78 #include "wx/odcombo.h"
80 // -----------------------------------------------------------------------
82 #if defined(__WXMSW__)
84 #define wxPG_NAT_BUTTON_BORDER_ANY 1
85 #define wxPG_NAT_BUTTON_BORDER_X 1
86 #define wxPG_NAT_BUTTON_BORDER_Y 1
88 #define wxPG_CHECKMARK_XADJ 1
89 #define wxPG_CHECKMARK_YADJ (-1)
90 #define wxPG_CHECKMARK_WADJ 0
91 #define wxPG_CHECKMARK_HADJ 0
92 #define wxPG_CHECKMARK_DEFLATE 0
94 #define wxPG_TEXTCTRLYADJUST (m_spacingy+0)
96 #elif defined(__WXGTK__)
98 #define wxPG_CHECKMARK_XADJ 0
99 #define wxPG_CHECKMARK_YADJ 0
100 #define wxPG_CHECKMARK_WADJ (-1)
101 #define wxPG_CHECKMARK_HADJ (-1)
102 #define wxPG_CHECKMARK_DEFLATE 3
104 #define wxPG_NAT_BUTTON_BORDER_ANY 1
105 #define wxPG_NAT_BUTTON_BORDER_X 1
106 #define wxPG_NAT_BUTTON_BORDER_Y 1
108 #define wxPG_TEXTCTRLYADJUST 0
110 #elif defined(__WXMAC__)
112 #define wxPG_CHECKMARK_XADJ 0
113 #define wxPG_CHECKMARK_YADJ 0
114 #define wxPG_CHECKMARK_WADJ 0
115 #define wxPG_CHECKMARK_HADJ 0
116 #define wxPG_CHECKMARK_DEFLATE 0
118 #define wxPG_NAT_BUTTON_BORDER_ANY 0
119 #define wxPG_NAT_BUTTON_BORDER_X 0
120 #define wxPG_NAT_BUTTON_BORDER_Y 0
122 #define wxPG_TEXTCTRLYADJUST 0
126 #define wxPG_CHECKMARK_XADJ 0
127 #define wxPG_CHECKMARK_YADJ 0
128 #define wxPG_CHECKMARK_WADJ 0
129 #define wxPG_CHECKMARK_HADJ 0
130 #define wxPG_CHECKMARK_DEFLATE 0
132 #define wxPG_NAT_BUTTON_BORDER_ANY 0
133 #define wxPG_NAT_BUTTON_BORDER_X 0
134 #define wxPG_NAT_BUTTON_BORDER_Y 0
136 #define wxPG_TEXTCTRLYADJUST 0
142 #define wxPG_CHOICEXADJUST -3 // required because wxComboCtrl reserves 3pixels for wxTextCtrl's focus ring
143 #define wxPG_CHOICEYADJUST -3
145 #define wxPG_CHOICEXADJUST 0
146 #define wxPG_CHOICEYADJUST 0
149 // Number added to image width for SetCustomPaintWidth
150 #define ODCB_CUST_PAINT_MARGIN 6
152 // Milliseconds to wait for two mouse-ups after focus inorder
153 // to trigger a double-click.
154 #define DOUBLE_CLICK_CONVERSION_TRESHOLD 500
156 // -----------------------------------------------------------------------
158 // -----------------------------------------------------------------------
160 IMPLEMENT_ABSTRACT_CLASS(wxPGEditor
, wxObject
)
163 wxPGEditor::~wxPGEditor()
167 wxString
wxPGEditor::GetName() const
169 return GetClassInfo()->GetClassName();
172 void wxPGEditor::DrawValue( wxDC
& dc
, const wxRect
& rect
,
173 wxPGProperty
* WXUNUSED(property
),
174 const wxString
& text
) const
176 dc
.DrawText( text
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
179 bool wxPGEditor::GetValueFromControl( wxVariant
&, wxPGProperty
*, wxWindow
* ) const
184 void wxPGEditor::SetControlStringValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, const wxString
& ) const
189 void wxPGEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, int ) const
194 int wxPGEditor::InsertItem( wxWindow
*, const wxString
&, int ) const
200 void wxPGEditor::DeleteItem( wxWindow
*, int ) const
206 void wxPGEditor::OnFocus( wxPGProperty
*, wxWindow
* ) const
210 void wxPGEditor::SetControlAppearance( wxPropertyGrid
* pg
,
211 wxPGProperty
* property
,
213 const wxPGCell
& cell
,
214 const wxPGCell
& oCell
,
215 bool unspecified
) const
217 // Get old editor appearance
218 wxTextCtrl
* tc
= NULL
;
219 wxComboCtrl
* cb
= NULL
;
220 if ( ctrl
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
222 tc
= (wxTextCtrl
*) ctrl
;
226 if ( ctrl
->IsKindOf(CLASSINFO(wxComboCtrl
)) )
228 cb
= (wxComboCtrl
*) ctrl
;
229 tc
= cb
->GetTextCtrl();
236 bool changeText
= false;
238 if ( cell
.HasText() && !pg
->IsEditorFocused() )
240 tcText
= cell
.GetText();
243 else if ( oCell
.HasText() )
245 tcText
= property
->GetValueAsString(
246 property
->HasFlag(wxPG_PROP_READONLY
)?0:wxPG_EDITABLE_VALUE
);
252 // This prevents value from being modified
255 pg
->SetupTextCtrlValue(tcText
);
256 tc
->SetValue(tcText
);
265 // Do not make the mistake of calling GetClassDefaultAttributes()
266 // here. It is static, while GetDefaultAttributes() is virtual
267 // and the correct one to use.
268 wxVisualAttributes vattrs
= ctrl
->GetDefaultAttributes();
271 const wxColour
& fgCol
= cell
.GetFgCol();
274 ctrl
->SetForegroundColour(fgCol
);
276 else if ( oCell
.GetFgCol().IsOk() )
278 ctrl
->SetForegroundColour(vattrs
.colFg
);
282 const wxColour
& bgCol
= cell
.GetBgCol();
285 ctrl
->SetBackgroundColour(bgCol
);
287 else if ( oCell
.GetBgCol().IsOk() )
289 ctrl
->SetBackgroundColour(vattrs
.colBg
);
293 const wxFont
& font
= cell
.GetFont();
298 else if ( oCell
.GetFont().IsOk() )
300 ctrl
->SetFont(vattrs
.font
);
303 // Also call the old SetValueToUnspecified()
305 SetValueToUnspecified(property
, ctrl
);
308 void wxPGEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
),
309 wxWindow
* WXUNUSED(ctrl
) ) const
313 bool wxPGEditor::CanContainCustomImage() const
318 // -----------------------------------------------------------------------
319 // wxPGTextCtrlEditor
320 // -----------------------------------------------------------------------
322 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrl
,wxPGTextCtrlEditor
,wxPGEditor
)
325 wxPGWindowList
wxPGTextCtrlEditor::CreateControls( wxPropertyGrid
* propGrid
,
326 wxPGProperty
* property
,
328 const wxSize
& sz
) const
333 // If has children, and limited editing is specified, then don't create.
334 if ( (property
->GetFlags() & wxPG_PROP_NOEDITOR
) &&
335 property
->GetChildCount() )
339 if ( !property
->HasFlag(wxPG_PROP_READONLY
) &&
340 !property
->IsValueUnspecified() )
341 argFlags
|= wxPG_EDITABLE_VALUE
;
342 text
= property
->GetValueAsString(argFlags
);
345 if ( (property
->GetFlags() & wxPG_PROP_PASSWORD
) &&
346 property
->IsKindOf(CLASSINFO(wxStringProperty
)) )
347 flags
|= wxTE_PASSWORD
;
349 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrl(pos
,sz
,text
,NULL
,flags
,
350 property
->GetMaxLength());
356 void wxPGTextCtrlEditor::DrawValue( wxDC
& dc
, wxPGProperty
* property
, const wxRect
& rect
) const
358 if ( !property
->IsValueUnspecified() )
360 wxString drawStr
= property
->GetDisplayedString();
362 // Code below should no longer be needed, as the obfuscation
363 // is now done in GetValueAsString.
364 /*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
365 property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
367 size_t a = drawStr.length();
369 drawStr.Append(wxS('*'),a);
371 dc
.DrawText( drawStr
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
376 void wxPGTextCtrlEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
378 wxTextCtrl
* tc
= wxDynamicCast(ctrl
, wxTextCtrl
);
383 if ( tc
->HasFlag(wxTE_PASSWORD
) )
384 s
= property
->GetValueAsString(wxPG_FULL_VALUE
);
386 s
= property
->GetDisplayedString();
388 wxPropertyGrid
* pg
= property
->GetGrid();
390 pg
->SetupTextCtrlValue(s
);
394 // Fix indentation, just in case (change in font boldness is one good
399 // Provided so that, for example, ComboBox editor can use the same code
400 // (multiple inheritance would get way too messy).
401 bool wxPGTextCtrlEditor::OnTextCtrlEvent( wxPropertyGrid
* propGrid
,
402 wxPGProperty
* WXUNUSED(property
),
409 if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER
)
411 if ( propGrid
->IsEditorsValueModified() )
416 else if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED
)
419 // Pass this event outside wxPropertyGrid so that,
420 // if necessary, program can tell when user is editing
422 // FIXME: Is it safe to change event id in the middle of event
423 // processing (seems to work, but...)?
425 event
.SetId(propGrid
->GetId());
427 propGrid
->EditorsValueWasModified();
433 bool wxPGTextCtrlEditor::OnEvent( wxPropertyGrid
* propGrid
,
434 wxPGProperty
* property
,
436 wxEvent
& event
) const
438 return wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid
,property
,ctrl
,event
);
442 bool wxPGTextCtrlEditor::GetTextCtrlValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
)
444 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
445 wxString textVal
= tc
->GetValue();
447 if ( property
->UsesAutoUnspecified() && !textVal
.length() )
453 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
455 // Changing unspecified always causes event (returning
456 // true here should be enough to trigger it).
457 // TODO: Move to propgrid.cpp
458 if ( !res
&& variant
.IsNull() )
465 bool wxPGTextCtrlEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
467 return wxPGTextCtrlEditor::GetTextCtrlValueFromControl(variant
, property
, ctrl
);
471 void wxPGTextCtrlEditor::SetControlStringValue( wxPGProperty
* property
, wxWindow
* ctrl
, const wxString
& txt
) const
473 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
475 wxPropertyGrid
* pg
= property
->GetGrid();
476 wxASSERT(pg
); // Really, property grid should exist if editor does
479 pg
->SetupTextCtrlValue(txt
);
485 void wxPGTextCtrlEditor_OnFocus( wxPGProperty
* property
,
488 // Make sure there is correct text (instead of unspecified value
489 // indicator or hint text)
490 int flags
= property
->HasFlag(wxPG_PROP_READONLY
) ?
491 0 : wxPG_EDITABLE_VALUE
;
492 wxString correctText
= property
->GetValueAsString(flags
);
494 if ( tc
->GetValue() != correctText
)
496 property
->GetGrid()->SetupTextCtrlValue(correctText
);
497 tc
->SetValue(correctText
);
500 tc
->SetSelection(-1,-1);
503 void wxPGTextCtrlEditor::OnFocus( wxPGProperty
* property
,
504 wxWindow
* wnd
) const
506 wxTextCtrl
* tc
= wxStaticCast(wnd
, wxTextCtrl
);
507 wxPGTextCtrlEditor_OnFocus(property
, tc
);
510 wxPGTextCtrlEditor::~wxPGTextCtrlEditor() { }
513 // -----------------------------------------------------------------------
515 // -----------------------------------------------------------------------
518 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(Choice
,wxPGChoiceEditor
,wxPGEditor
)
521 // This is a special enhanced double-click processor class.
522 // In essence, it allows for double-clicks for which the
523 // first click "created" the control.
524 class wxPGDoubleClickProcessor
: public wxEvtHandler
528 wxPGDoubleClickProcessor( wxOwnerDrawnComboBox
* combo
, wxPGProperty
* property
)
531 m_timeLastMouseUp
= 0;
533 m_property
= property
;
534 m_downReceived
= false;
539 void OnMouseEvent( wxMouseEvent
& event
)
541 wxLongLong t
= ::wxGetLocalTimeMillis();
542 int evtType
= event
.GetEventType();
544 if ( m_property
->HasFlag(wxPG_PROP_USE_DCC
) &&
545 m_property
->IsKindOf(CLASSINFO(wxBoolProperty
)) &&
546 !m_combo
->IsPopupShown() )
548 // Just check that it is in the text area
549 wxPoint pt
= event
.GetPosition();
550 if ( m_combo
->GetTextRect().Contains(pt
) )
552 if ( evtType
== wxEVT_LEFT_DOWN
)
554 // Set value to avoid up-events without corresponding downs
555 m_downReceived
= true;
557 else if ( evtType
== wxEVT_LEFT_DCLICK
)
559 // We'll make our own double-clicks
560 event
.SetEventType(0);
563 else if ( evtType
== wxEVT_LEFT_UP
)
565 if ( m_downReceived
|| m_timeLastMouseUp
== 1 )
567 wxLongLong timeFromLastUp
= (t
-m_timeLastMouseUp
);
569 if ( timeFromLastUp
< DOUBLE_CLICK_CONVERSION_TRESHOLD
)
571 event
.SetEventType(wxEVT_LEFT_DCLICK
);
572 m_timeLastMouseUp
= 1;
576 m_timeLastMouseUp
= t
;
586 void OnSetFocus( wxFocusEvent
& event
)
588 m_timeLastMouseUp
= ::wxGetLocalTimeMillis();
593 wxLongLong m_timeLastMouseUp
;
594 wxOwnerDrawnComboBox
* m_combo
;
595 wxPGProperty
* m_property
; // Selected property
598 DECLARE_EVENT_TABLE()
601 BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor
, wxEvtHandler
)
602 EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor::OnMouseEvent
)
603 EVT_SET_FOCUS(wxPGDoubleClickProcessor::OnSetFocus
)
608 class wxPGComboBox
: public wxOwnerDrawnComboBox
613 : wxOwnerDrawnComboBox()
615 m_dclickProcessor
= NULL
;
616 m_sizeEventCalled
= false;
621 if ( m_dclickProcessor
)
623 RemoveEventHandler(m_dclickProcessor
);
624 delete m_dclickProcessor
;
628 bool Create(wxWindow
*parent
,
630 const wxString
& value
,
633 const wxArrayString
& choices
,
635 const wxValidator
& validator
= wxDefaultValidator
,
636 const wxString
& name
= wxS("wxOwnerDrawnComboBox"))
638 if ( !wxOwnerDrawnComboBox::Create( parent
,
649 m_dclickProcessor
= new
650 wxPGDoubleClickProcessor( this, GetGrid()->GetSelection() );
652 PushEventHandler(m_dclickProcessor
);
657 virtual void OnDrawItem( wxDC
& dc
,
662 wxPropertyGrid
* pg
= GetGrid();
664 // Handle hint text via super class
665 if ( (flags
& wxODCB_PAINTING_CONTROL
) &&
666 ShouldUseHintText(flags
) )
668 wxOwnerDrawnComboBox::OnDrawItem(dc
, rect
, item
, flags
);
672 pg
->OnComboItemPaint( this, item
, &dc
, (wxRect
&)rect
, flags
);
676 virtual wxCoord
OnMeasureItem( size_t item
) const
678 wxPropertyGrid
* pg
= GetGrid();
682 pg
->OnComboItemPaint( this, item
, NULL
, rect
, 0 );
686 wxPropertyGrid
* GetGrid() const
688 wxPropertyGrid
* pg
= wxDynamicCast(GetParent(),
694 virtual wxCoord
OnMeasureItemWidth( size_t item
) const
696 wxPropertyGrid
* pg
= GetGrid();
700 pg
->OnComboItemPaint( this, item
, NULL
, rect
, 0 );
704 virtual void PositionTextCtrl( int textCtrlXAdjust
,
705 int WXUNUSED(textCtrlYAdjust
) )
707 wxPropertyGrid
* pg
= GetGrid();
708 #ifdef wxPG_TEXTCTRLXADJUST
709 textCtrlXAdjust
= wxPG_TEXTCTRLXADJUST
-
710 (wxPG_XBEFOREWIDGET
+wxPG_CONTROL_MARGIN
+1) - 1,
712 wxOwnerDrawnComboBox::PositionTextCtrl(
714 pg
->GetSpacingY() + 2
719 wxPGDoubleClickProcessor
* m_dclickProcessor
;
720 bool m_sizeEventCalled
;
724 void wxPropertyGrid::OnComboItemPaint( const wxPGComboBox
* pCb
,
731 wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid
)) );
733 wxPGProperty
* p
= GetSelection();
736 const wxPGChoices
& choices
= p
->GetChoices();
737 const wxPGCommonValue
* comVal
= NULL
;
738 int comVals
= p
->GetDisplayedCommonValueCount();
739 int comValIndex
= -1;
742 if ( choices
.IsOk() )
743 choiceCount
= choices
.GetCount();
745 if ( item
>= choiceCount
&& comVals
> 0 )
747 comValIndex
= item
- choiceCount
;
748 comVal
= GetCommonValue(comValIndex
);
749 if ( !p
->IsValueUnspecified() )
750 text
= comVal
->GetLabel();
754 if ( !(flags
& wxODCB_PAINTING_CONTROL
) )
756 text
= pCb
->GetString(item
);
760 if ( !p
->IsValueUnspecified() )
761 text
= p
->GetValueAsString(0);
770 const wxBitmap
* itemBitmap
= NULL
;
772 if ( item
>= 0 && choices
.IsOk() && choices
.Item(item
).GetBitmap().Ok() && comValIndex
== -1 )
773 itemBitmap
= &choices
.Item(item
).GetBitmap();
776 // Decide what custom image size to use
779 cis
.x
= itemBitmap
->GetWidth();
780 cis
.y
= itemBitmap
->GetHeight();
784 cis
= GetImageSize(p
, item
);
789 // Default measure behaviour (no flexible, custom paint image only)
790 if ( rect
.width
< 0 )
793 pCb
->GetTextExtent(text
, &x
, &y
, 0, 0);
794 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9 + x
;
797 rect
.height
= cis
.y
+ 2;
801 wxPGPaintData paintdata
;
802 paintdata
.m_parent
= NULL
;
803 paintdata
.m_choiceItem
= item
;
805 // This is by the current (1.0.0b) spec - if painting control, item is -1
806 if ( (flags
& wxODCB_PAINTING_CONTROL
) )
807 paintdata
.m_choiceItem
= -1;
810 pDc
->SetBrush(*wxWHITE_BRUSH
);
812 wxPGCellRenderer
* renderer
= NULL
;
813 const wxPGChoiceEntry
* cell
= NULL
;
821 wxPoint
pt(rect
.x
+ wxPG_CONTROL_MARGIN
- wxPG_CHOICEXADJUST
- 1,
824 int renderFlags
= wxPGCellRenderer::DontUseCellColours
;
825 bool useCustomPaintProcedure
;
827 // If custom image had some size, we will start from the assumption
828 // that custom paint procedure is required
830 useCustomPaintProcedure
= true;
832 useCustomPaintProcedure
= false;
834 if ( flags
& wxODCB_PAINTING_SELECTED
)
835 renderFlags
|= wxPGCellRenderer::Selected
;
837 if ( flags
& wxODCB_PAINTING_CONTROL
)
839 renderFlags
|= wxPGCellRenderer::Control
;
841 // If wxPG_PROP_CUSTOMIMAGE was set, then that means any custom
842 // image will not appear on the control row (it may be too
843 // large to fit, for instance). Also do not draw custom image
844 // if no choice was selected.
845 if ( !p
->HasFlag(wxPG_PROP_CUSTOMIMAGE
) || item
< 0 )
846 useCustomPaintProcedure
= false;
850 renderFlags
|= wxPGCellRenderer::ChoicePopup
;
852 // For consistency, always use normal font when drawing drop down
854 dc
.SetFont(GetFont());
857 // If not drawing a selected popup item, then give property's
858 // m_valueBitmap a chance.
859 if ( p
->m_valueBitmap
&& item
!= pCb
->GetSelection() )
860 useCustomPaintProcedure
= false;
861 // If current choice had a bitmap set by the application, then
862 // use it instead of any custom paint procedure.
863 else if ( itemBitmap
)
864 useCustomPaintProcedure
= false;
866 if ( useCustomPaintProcedure
)
868 pt
.x
+= wxCC_CUSTOM_IMAGE_MARGIN1
;
869 wxRect
r(pt
.x
,pt
.y
,cis
.x
,cis
.y
);
871 if ( flags
& wxODCB_PAINTING_CONTROL
)
874 r
.height
= wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
);
877 paintdata
.m_drawnWidth
= r
.width
;
879 dc
.SetPen(m_colPropFore
);
880 if ( comValIndex
>= 0 )
882 const wxPGCommonValue
* cv
= GetCommonValue(comValIndex
);
883 wxPGCellRenderer
* renderer
= cv
->GetRenderer();
884 r
.width
= rect
.width
;
885 renderer
->Render( dc
, r
, this, p
, m_selColumn
, comValIndex
, renderFlags
);
888 else if ( item
>= 0 )
890 p
->OnCustomPaint( dc
, r
, paintdata
);
894 dc
.DrawRectangle( r
);
897 pt
.x
+= paintdata
.m_drawnWidth
+ wxCC_CUSTOM_IMAGE_MARGIN2
- 1;
901 // TODO: This aligns text so that it seems to be horizontally
902 // on the same line as property values. Not really
903 // sure if its needed, but seems to not cause any harm.
906 if ( item
< 0 && (flags
& wxODCB_PAINTING_CONTROL
) )
907 item
= pCb
->GetSelection();
909 if ( choices
.IsOk() && item
>= 0 && comValIndex
< 0 )
911 cell
= &choices
.Item(item
);
912 renderer
= wxPGGlobalVars
->m_defaultRenderer
;
913 int imageOffset
= renderer
->PreDrawCell(dc
, rect
, *cell
,
916 imageOffset
+= wxCC_CUSTOM_IMAGE_MARGIN1
+
917 wxCC_CUSTOM_IMAGE_MARGIN2
;
926 pt
.y
+= (rect
.height
-m_fontHeight
)/2 - 1;
930 dc
.DrawText( text
, pt
.x
+ wxPG_XBEFORETEXT
, pt
.y
);
933 renderer
->PostDrawCell(dc
, this, *cell
, renderFlags
);
941 p
->OnCustomPaint( dc
, rect
, paintdata
);
942 rect
.height
= paintdata
.m_drawnHeight
+ 2;
943 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9;
947 bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid
* propGrid
, wxPGComboBox
* cb
, int cmnVal
)
949 wxPGProperty
* property
= propGrid
->GetSelectedProperty();
950 wxASSERT( property
);
955 // TODO: Do this always when cell has custom text.
956 if ( property
->IsValueUnspecified() )
958 cb
->SetCustomPaintWidth( 0 );
964 // Yes, a common value is being selected
965 property
->SetCommonValue( cmnVal
);
966 imageSize
= propGrid
->GetCommonValue(cmnVal
)->
967 GetRenderer()->GetImageSize(property
, 1, cmnVal
);
972 imageSize
= propGrid
->GetImageSize(property
, -1);
977 imageSize
.x
+= ODCB_CUST_PAINT_MARGIN
;
978 cb
->SetCustomPaintWidth( imageSize
.x
);
983 // CreateControls calls this with CB_READONLY in extraStyle
984 wxWindow
* wxPGChoiceEditor::CreateControlsBase( wxPropertyGrid
* propGrid
,
985 wxPGProperty
* property
,
988 long extraStyle
) const
990 // Since it is not possible (yet) to create a read-only combo box in
991 // the same sense that wxTextCtrl is read-only, simply do not create
992 // the control in this case.
993 if ( property
->HasFlag(wxPG_PROP_READONLY
) )
996 const wxPGChoices
& choices
= property
->GetChoices();
998 int index
= property
->GetChoiceSelection();
1001 if ( !property
->HasFlag(wxPG_PROP_READONLY
) &&
1002 !property
->IsValueUnspecified() )
1003 argFlags
|= wxPG_EDITABLE_VALUE
;
1004 defString
= property
->GetValueAsString(argFlags
);
1006 wxArrayString labels
= choices
.GetLabels();
1012 po
.y
+= wxPG_CHOICEYADJUST
;
1013 si
.y
-= (wxPG_CHOICEYADJUST
*2);
1015 po
.x
+= wxPG_CHOICEXADJUST
;
1016 si
.x
-= wxPG_CHOICEXADJUST
;
1017 wxWindow
* ctrlParent
= propGrid
->GetPanel();
1019 int odcbFlags
= extraStyle
| wxBORDER_NONE
| wxTE_PROCESS_ENTER
;
1021 if ( (property
->GetFlags() & wxPG_PROP_USE_DCC
) &&
1022 (property
->IsKindOf(CLASSINFO(wxBoolProperty
)) ) )
1023 odcbFlags
|= wxODCB_DCLICK_CYCLES
;
1026 // If common value specified, use appropriate index
1027 unsigned int cmnVals
= property
->GetDisplayedCommonValueCount();
1030 if ( !property
->IsValueUnspecified() )
1032 int cmnVal
= property
->GetCommonValue();
1035 index
= labels
.size() + cmnVal
;
1040 for ( i
=0; i
<cmnVals
; i
++ )
1041 labels
.Add(propGrid
->GetCommonValueLabel(i
));
1044 cb
= new wxPGComboBox();
1048 cb
->Create(ctrlParent
,
1056 cb
->SetButtonPosition(si
.y
,0,wxRIGHT
);
1057 cb
->SetMargins(wxPG_XBEFORETEXT
-1);
1060 cb
->SetHint(property
->GetHintText());
1062 wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
,
1063 property
->GetCommonValue() );
1065 if ( index
>= 0 && index
< (int)cb
->GetCount() )
1067 cb
->SetSelection( index
);
1068 if ( defString
.length() )
1069 cb
->SetText( defString
);
1071 else if ( !(extraStyle
& wxCB_READONLY
) && defString
.length() )
1073 propGrid
->SetupTextCtrlValue(defString
);
1074 cb
->SetValue( defString
);
1078 cb
->SetSelection( -1 );
1085 return (wxWindow
*) cb
;
1089 void wxPGChoiceEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1092 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1093 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
1094 int ind
= property
->GetChoiceSelection();
1095 cb
->SetSelection(ind
);
1098 wxPGWindowList
wxPGChoiceEditor::CreateControls( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
1099 const wxPoint
& pos
, const wxSize
& sz
) const
1101 return CreateControlsBase(propGrid
,property
,pos
,sz
,wxCB_READONLY
);
1105 int wxPGChoiceEditor::InsertItem( wxWindow
* ctrl
, const wxString
& label
, int index
) const
1108 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1109 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
1112 index
= cb
->GetCount();
1114 return cb
->Insert(label
,index
);
1118 void wxPGChoiceEditor::DeleteItem( wxWindow
* ctrl
, int index
) const
1121 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1122 wxASSERT( cb
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)));
1127 bool wxPGChoiceEditor::OnEvent( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
1128 wxWindow
* ctrl
, wxEvent
& event
) const
1130 if ( event
.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED
)
1132 wxPGComboBox
* cb
= (wxPGComboBox
*)ctrl
;
1133 int index
= cb
->GetSelection();
1134 int cmnValIndex
= -1;
1135 int cmnVals
= property
->GetDisplayedCommonValueCount();
1136 int items
= cb
->GetCount();
1138 if ( index
>= (items
-cmnVals
) )
1140 // Yes, a common value is being selected
1141 cmnValIndex
= index
- (items
-cmnVals
);
1142 property
->SetCommonValue( cmnValIndex
);
1144 // Truly set value to unspecified?
1145 if ( propGrid
->GetUnspecifiedCommonValue() == cmnValIndex
)
1147 if ( !property
->IsValueUnspecified() )
1148 propGrid
->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT
);
1149 property
->SetValueToUnspecified();
1150 if ( !cb
->HasFlag(wxCB_READONLY
) )
1152 wxString unspecValueText
;
1153 unspecValueText
= propGrid
->GetUnspecifiedValueText();
1154 propGrid
->SetupTextCtrlValue(unspecValueText
);
1155 cb
->GetTextCtrl()->SetValue(unspecValueText
);
1160 return wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
, cmnValIndex
);
1166 bool wxPGChoiceEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1168 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1170 int index
= cb
->GetSelection();
1172 if ( index
!= property
->GetChoiceSelection() ||
1173 // Changing unspecified always causes event (returning
1174 // true here should be enough to trigger it).
1175 property
->IsValueUnspecified()
1178 return property
->IntToValue( variant
, index
, 0 );
1184 void wxPGChoiceEditor::SetControlStringValue( wxPGProperty
* property
,
1186 const wxString
& txt
) const
1188 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1190 property
->GetGrid()->SetupTextCtrlValue(txt
);
1195 void wxPGChoiceEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
1197 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1199 cb
->SetSelection(value
);
1203 void wxPGChoiceEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
),
1204 wxWindow
* ctrl
) const
1206 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1208 if ( cb
->HasFlag(wxCB_READONLY
) )
1209 cb
->SetSelection(-1);
1213 bool wxPGChoiceEditor::CanContainCustomImage() const
1219 wxPGChoiceEditor::~wxPGChoiceEditor() { }
1222 // -----------------------------------------------------------------------
1223 // wxPGComboBoxEditor
1224 // -----------------------------------------------------------------------
1227 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ComboBox
,
1232 void wxPGComboBoxEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1234 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1235 wxString s
= property
->GetValueAsString(wxPG_EDITABLE_VALUE
);
1236 property
->GetGrid()->SetupTextCtrlValue(s
);
1239 // TODO: If string matches any selection, then select that.
1243 wxPGWindowList
wxPGComboBoxEditor::CreateControls( wxPropertyGrid
* propGrid
,
1244 wxPGProperty
* property
,
1246 const wxSize
& sz
) const
1248 return CreateControlsBase(propGrid
,property
,pos
,sz
,0);
1252 bool wxPGComboBoxEditor::OnEvent( wxPropertyGrid
* propGrid
,
1253 wxPGProperty
* property
,
1255 wxEvent
& event
) const
1257 wxOwnerDrawnComboBox
* cb
= NULL
;
1258 wxWindow
* textCtrl
= NULL
;
1262 cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1263 textCtrl
= cb
->GetTextCtrl();
1266 if ( wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid
,property
,textCtrl
,event
) )
1269 return wxPGChoiceEditor::OnEvent(propGrid
,property
,ctrl
,event
);
1273 bool wxPGComboBoxEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1275 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1276 wxString textVal
= cb
->GetValue();
1278 if ( property
->UsesAutoUnspecified() && !textVal
.length() )
1284 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
1286 // Changing unspecified always causes event (returning
1287 // true here should be enough to trigger it).
1288 if ( !res
&& variant
.IsNull() )
1295 void wxPGComboBoxEditor::OnFocus( wxPGProperty
* property
,
1296 wxWindow
* ctrl
) const
1298 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1299 wxPGTextCtrlEditor_OnFocus(property
, cb
->GetTextCtrl());
1303 wxPGComboBoxEditor::~wxPGComboBoxEditor() { }
1306 // -----------------------------------------------------------------------
1307 // wxPGChoiceAndButtonEditor
1308 // -----------------------------------------------------------------------
1311 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ChoiceAndButton
,
1312 wxPGChoiceAndButtonEditor
,
1316 wxPGWindowList
wxPGChoiceAndButtonEditor::CreateControls( wxPropertyGrid
* propGrid
,
1317 wxPGProperty
* property
,
1319 const wxSize
& sz
) const
1321 // Use one two units smaller to match size of the combo's dropbutton.
1322 // (normally a bigger button is used because it looks better)
1325 wxSize
bt_sz(bt_wid
,bt_wid
);
1327 // Position of button.
1328 wxPoint
bt_pos(pos
.x
+sz
.x
-bt_sz
.x
,pos
.y
);
1335 wxWindow
* bt
= propGrid
->GenerateEditorButton( bt_pos
, bt_sz
);
1338 wxSize
ch_sz(sz
.x
-bt
->GetSize().x
,sz
.y
);
1341 ch_sz
.x
-= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1344 wxWindow
* ch
= wxPGEditor_Choice
->CreateControls(propGrid
,property
,
1345 pos
,ch_sz
).m_primary
;
1351 return wxPGWindowList(ch
, bt
);
1355 wxPGChoiceAndButtonEditor::~wxPGChoiceAndButtonEditor() { }
1358 // -----------------------------------------------------------------------
1359 // wxPGTextCtrlAndButtonEditor
1360 // -----------------------------------------------------------------------
1362 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrlAndButton
,
1363 wxPGTextCtrlAndButtonEditor
,
1367 wxPGWindowList
wxPGTextCtrlAndButtonEditor::CreateControls( wxPropertyGrid
* propGrid
,
1368 wxPGProperty
* property
,
1370 const wxSize
& sz
) const
1373 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrlAndButton( pos
, sz
, &wnd2
,
1374 property
->GetFlags() & wxPG_PROP_NOEDITOR
, property
);
1376 return wxPGWindowList(wnd
, wnd2
);
1380 wxPGTextCtrlAndButtonEditor::~wxPGTextCtrlAndButtonEditor() { }
1383 // -----------------------------------------------------------------------
1384 // wxPGCheckBoxEditor
1385 // -----------------------------------------------------------------------
1387 #if wxPG_INCLUDE_CHECKBOX
1389 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(CheckBox
,
1394 // Check box state flags
1397 wxSCB_STATE_UNCHECKED
= 0,
1398 wxSCB_STATE_CHECKED
= 1,
1399 wxSCB_STATE_BOLD
= 2,
1400 wxSCB_STATE_UNSPECIFIED
= 4
1403 const int wxSCB_SETVALUE_CYCLE
= 2;
1406 static void DrawSimpleCheckBox( wxDC
& dc
, const wxRect
& rect
, int box_hei
,
1410 wxRect
r(rect
.x
+wxPG_XBEFORETEXT
,rect
.y
+((rect
.height
-box_hei
)/2),
1412 wxColour useCol
= dc
.GetTextForeground();
1414 if ( state
& wxSCB_STATE_UNSPECIFIED
)
1416 useCol
= wxColour(220, 220, 220);
1419 // Draw check mark first because it is likely to overdraw the
1420 // surrounding rectangle.
1421 if ( state
& wxSCB_STATE_CHECKED
)
1423 wxRect
r2(r
.x
+wxPG_CHECKMARK_XADJ
,
1424 r
.y
+wxPG_CHECKMARK_YADJ
,
1425 r
.width
+wxPG_CHECKMARK_WADJ
,
1426 r
.height
+wxPG_CHECKMARK_HADJ
);
1427 #if wxPG_CHECKMARK_DEFLATE
1428 r2
.Deflate(wxPG_CHECKMARK_DEFLATE
);
1430 dc
.DrawCheckMark(r2
);
1432 // This would draw a simple cross check mark.
1433 // dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
1434 // dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
1437 if ( !(state
& wxSCB_STATE_BOLD
) )
1439 // Pen for thin rectangle.
1444 // Pen for bold rectangle.
1445 wxPen
linepen(useCol
,2,wxSOLID
);
1446 linepen
.SetJoin(wxJOIN_MITER
); // This prevents round edges.
1454 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1456 dc
.DrawRectangle(r
);
1457 dc
.SetPen(*wxTRANSPARENT_PEN
);
1461 // Real simple custom-drawn checkbox-without-label class.
1463 class wxSimpleCheckBox
: public wxControl
1467 void SetValue( int value
);
1469 wxSimpleCheckBox( wxWindow
* parent
,
1471 const wxPoint
& pos
= wxDefaultPosition
,
1472 const wxSize
& size
= wxDefaultSize
)
1473 : wxControl(parent
,id
,pos
,size
,wxBORDER_NONE
|wxWANTS_CHARS
)
1475 // Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
1476 SetFont( parent
->GetFont() );
1481 SetBackgroundStyle( wxBG_STYLE_CUSTOM
);
1484 virtual ~wxSimpleCheckBox();
1490 void OnPaint( wxPaintEvent
& event
);
1491 void OnLeftClick( wxMouseEvent
& event
);
1492 void OnKeyDown( wxKeyEvent
& event
);
1494 void OnResize( wxSizeEvent
& event
)
1500 static wxBitmap
* ms_doubleBuffer
;
1502 DECLARE_EVENT_TABLE()
1505 BEGIN_EVENT_TABLE(wxSimpleCheckBox
, wxControl
)
1506 EVT_PAINT(wxSimpleCheckBox::OnPaint
)
1507 EVT_LEFT_DOWN(wxSimpleCheckBox::OnLeftClick
)
1508 EVT_LEFT_DCLICK(wxSimpleCheckBox::OnLeftClick
)
1509 EVT_KEY_DOWN(wxSimpleCheckBox::OnKeyDown
)
1510 EVT_SIZE(wxSimpleCheckBox::OnResize
)
1513 wxSimpleCheckBox::~wxSimpleCheckBox()
1515 delete ms_doubleBuffer
;
1516 ms_doubleBuffer
= NULL
;
1519 wxBitmap
* wxSimpleCheckBox::ms_doubleBuffer
= NULL
;
1521 void wxSimpleCheckBox::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1523 wxSize clientSize
= GetClientSize();
1524 wxAutoBufferedPaintDC
dc(this);
1527 wxRect
rect(0,0,clientSize
.x
,clientSize
.y
);
1531 wxColour bgcol
= GetBackgroundColour();
1532 dc
.SetBrush( bgcol
);
1534 dc
.DrawRectangle( rect
);
1536 dc
.SetTextForeground(GetForegroundColour());
1538 int state
= m_state
;
1539 if ( !(state
& wxSCB_STATE_UNSPECIFIED
) &&
1540 GetFont().GetWeight() == wxBOLD
)
1541 state
|= wxSCB_STATE_BOLD
;
1543 DrawSimpleCheckBox(dc
, rect
, m_boxHeight
, state
);
1546 void wxSimpleCheckBox::OnLeftClick( wxMouseEvent
& event
)
1548 if ( (event
.m_x
> (wxPG_XBEFORETEXT
-2)) &&
1549 (event
.m_x
<= (wxPG_XBEFORETEXT
-2+m_boxHeight
)) )
1551 SetValue(wxSCB_SETVALUE_CYCLE
);
1555 void wxSimpleCheckBox::OnKeyDown( wxKeyEvent
& event
)
1557 if ( event
.GetKeyCode() == WXK_SPACE
)
1559 SetValue(wxSCB_SETVALUE_CYCLE
);
1563 void wxSimpleCheckBox::SetValue( int value
)
1565 if ( value
== wxSCB_SETVALUE_CYCLE
)
1567 if ( m_state
& wxSCB_STATE_CHECKED
)
1568 m_state
&= ~wxSCB_STATE_CHECKED
;
1570 m_state
|= wxSCB_STATE_CHECKED
;
1578 wxCommandEvent
evt(wxEVT_COMMAND_CHECKBOX_CLICKED
,GetParent()->GetId());
1580 wxPropertyGrid
* propGrid
= (wxPropertyGrid
*) GetParent();
1581 wxASSERT( propGrid
->IsKindOf(CLASSINFO(wxPropertyGrid
)) );
1582 propGrid
->HandleCustomEditorEvent(evt
);
1585 wxPGWindowList
wxPGCheckBoxEditor::CreateControls( wxPropertyGrid
* propGrid
,
1586 wxPGProperty
* property
,
1588 const wxSize
& size
) const
1590 if ( property
->HasFlag(wxPG_PROP_READONLY
) )
1594 pt
.x
-= wxPG_XBEFOREWIDGET
;
1596 sz
.x
= propGrid
->GetFontHeight() + (wxPG_XBEFOREWIDGET
*2) + 4;
1598 wxSimpleCheckBox
* cb
= new wxSimpleCheckBox(propGrid
->GetPanel(),
1599 wxPG_SUBID1
, pt
, sz
);
1601 cb
->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
1603 UpdateControl(property
, cb
);
1605 if ( !property
->IsValueUnspecified() )
1607 // If mouse cursor was on the item, toggle the value now.
1608 if ( propGrid
->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK
)
1610 wxPoint pt
= cb
->ScreenToClient(::wxGetMousePosition());
1611 if ( pt
.x
<= (wxPG_XBEFORETEXT
-2+cb
->m_boxHeight
) )
1613 if ( cb
->m_state
& wxSCB_STATE_CHECKED
)
1614 cb
->m_state
&= ~wxSCB_STATE_CHECKED
;
1616 cb
->m_state
|= wxSCB_STATE_CHECKED
;
1618 // Makes sure wxPG_EVT_CHANGING etc. is sent for this initial
1620 propGrid
->ChangePropertyValue(property
,
1621 wxPGVariant_Bool(cb
->m_state
));
1626 propGrid
->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR
);
1631 void wxPGCheckBoxEditor::DrawValue( wxDC
& dc
, const wxRect
& rect
,
1632 wxPGProperty
* property
,
1633 const wxString
& WXUNUSED(text
) ) const
1635 int state
= wxSCB_STATE_UNCHECKED
;
1637 if ( !property
->IsValueUnspecified() )
1639 state
= property
->GetChoiceSelection();
1640 if ( dc
.GetFont().GetWeight() == wxBOLD
)
1641 state
|= wxSCB_STATE_BOLD
;
1645 state
|= wxSCB_STATE_UNSPECIFIED
;
1648 DrawSimpleCheckBox(dc
, rect
, dc
.GetCharHeight(), state
);
1651 void wxPGCheckBoxEditor::UpdateControl( wxPGProperty
* property
,
1652 wxWindow
* ctrl
) const
1654 wxSimpleCheckBox
* cb
= (wxSimpleCheckBox
*) ctrl
;
1657 if ( !property
->IsValueUnspecified() )
1658 cb
->m_state
= property
->GetChoiceSelection();
1660 cb
->m_state
= wxSCB_STATE_UNSPECIFIED
;
1662 wxPropertyGrid
* propGrid
= property
->GetGrid();
1663 cb
->m_boxHeight
= propGrid
->GetFontHeight();
1668 bool wxPGCheckBoxEditor::OnEvent( wxPropertyGrid
* WXUNUSED(propGrid
), wxPGProperty
* WXUNUSED(property
),
1669 wxWindow
* WXUNUSED(ctrl
), wxEvent
& event
) const
1671 if ( event
.GetEventType() == wxEVT_COMMAND_CHECKBOX_CLICKED
)
1679 bool wxPGCheckBoxEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1681 wxSimpleCheckBox
* cb
= (wxSimpleCheckBox
*)ctrl
;
1683 int index
= cb
->m_state
;
1685 if ( index
!= property
->GetChoiceSelection() ||
1686 // Changing unspecified always causes event (returning
1687 // true here should be enough to trigger it).
1688 property
->IsValueUnspecified()
1691 return property
->IntToValue(variant
, index
, 0);
1697 void wxPGCheckBoxEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
1699 if ( value
!= 0 ) value
= 1;
1700 ((wxSimpleCheckBox
*)ctrl
)->m_state
= value
;
1705 void wxPGCheckBoxEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
) const
1707 ((wxSimpleCheckBox
*)ctrl
)->m_state
= wxSCB_STATE_UNSPECIFIED
;
1712 wxPGCheckBoxEditor::~wxPGCheckBoxEditor() { }
1715 #endif // wxPG_INCLUDE_CHECKBOX
1717 // -----------------------------------------------------------------------
1719 wxWindow
* wxPropertyGrid::GetEditorControl() const
1721 wxWindow
* ctrl
= m_wndEditor
;
1729 // -----------------------------------------------------------------------
1731 void wxPropertyGrid::CorrectEditorWidgetSizeX()
1735 // Use fixed selColumn 1 for main editor widgets
1736 int newSplitterx
= m_pState
->DoGetSplitterPosition(0);
1737 int newWidth
= newSplitterx
+ m_pState
->m_colWidths
[1];
1741 // if width change occurred, move secondary wnd by that amount
1742 wxRect r
= m_wndEditor2
->GetRect();
1744 r
.x
= newWidth
- secWid
;
1746 m_wndEditor2
->SetSize( r
);
1748 // if primary is textctrl, then we have to add some extra space
1752 if ( m_wndEditor
&& m_wndEditor
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
1754 secWid
+= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1759 wxRect r
= m_wndEditor
->GetRect();
1761 r
.x
= newSplitterx
+m_ctrlXAdjust
;
1763 if ( !(m_iFlags
& wxPG_FL_FIXED_WIDTH_EDITOR
) )
1764 r
.width
= newWidth
- r
.x
- secWid
;
1766 m_wndEditor
->SetSize(r
);
1770 m_wndEditor2
->Refresh();
1773 // -----------------------------------------------------------------------
1775 void wxPropertyGrid::CorrectEditorWidgetPosY()
1777 wxPGProperty
* selected
= GetSelection();
1781 if ( m_labelEditor
)
1783 wxRect r
= GetEditorWidgetRect(selected
, m_selColumn
);
1784 wxPoint pos
= m_labelEditor
->GetPosition();
1786 // Calculate y offset
1787 int offset
= pos
.y
% m_lineHeight
;
1789 m_labelEditor
->Move(pos
.x
, r
.y
+ offset
);
1792 if ( m_wndEditor
|| m_wndEditor2
)
1794 wxRect r
= GetEditorWidgetRect(selected
, 1);
1798 wxPoint pos
= m_wndEditor
->GetPosition();
1800 // Calculate y offset
1801 int offset
= pos
.y
% m_lineHeight
;
1803 m_wndEditor
->Move(pos
.x
, r
.y
+ offset
);
1808 wxPoint pos
= m_wndEditor2
->GetPosition();
1810 m_wndEditor2
->Move(pos
.x
, r
.y
);
1816 // -----------------------------------------------------------------------
1818 // Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
1819 // fits into that category as well).
1820 void wxPropertyGrid::FixPosForTextCtrl( wxWindow
* ctrl
,
1821 unsigned int WXUNUSED(forColumn
),
1822 const wxPoint
& offset
)
1824 // Center the control vertically
1825 wxRect finalPos
= ctrl
->GetRect();
1826 int y_adj
= (m_lineHeight
- finalPos
.height
)/2 + wxPG_TEXTCTRLYADJUST
;
1828 // Prevent over-sized control
1829 int sz_dec
= (y_adj
+ finalPos
.height
) - m_lineHeight
;
1830 if ( sz_dec
< 0 ) sz_dec
= 0;
1832 finalPos
.y
+= y_adj
;
1833 finalPos
.height
-= (y_adj
+sz_dec
);
1835 #ifndef wxPG_TEXTCTRLXADJUST
1836 int textCtrlXAdjust
= wxPG_XBEFORETEXT
- 1;
1838 wxTextCtrl
* tc
= static_cast<wxTextCtrl
*>(ctrl
);
1841 int textCtrlXAdjust
= wxPG_TEXTCTRLXADJUST
;
1844 finalPos
.x
+= textCtrlXAdjust
;
1845 finalPos
.width
-= textCtrlXAdjust
;
1847 finalPos
.x
+= offset
.x
;
1848 finalPos
.y
+= offset
.y
;
1850 ctrl
->SetSize(finalPos
);
1853 // -----------------------------------------------------------------------
1855 wxWindow
* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint
& pos
,
1857 const wxString
& value
,
1858 wxWindow
* secondary
,
1861 unsigned int forColumn
)
1863 wxWindowID id
= wxPG_SUBID1
;
1864 wxPGProperty
* prop
= GetSelection();
1867 int tcFlags
= wxTE_PROCESS_ENTER
| extraStyle
;
1869 if ( prop
->HasFlag(wxPG_PROP_READONLY
) && forColumn
== 1 )
1870 tcFlags
|= wxTE_READONLY
;
1872 wxPoint
p(pos
.x
,pos
.y
);
1873 wxSize
s(sz
.x
,sz
.y
);
1875 // Need to reduce width of text control on Mac
1876 #if defined(__WXMAC__)
1880 // For label editors, trim the size to allow better splitter grabbing
1881 if ( forColumn
!= 1 )
1884 // Take button into acccount
1887 s
.x
-= (secondary
->GetSize().x
+ wxPG_TEXTCTRL_AND_BUTTON_SPACING
);
1888 m_iFlags
&= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE
);
1891 // If the height is significantly higher, then use border, and fill the rect exactly.
1892 bool hasSpecialSize
= false;
1894 if ( (sz
.y
- m_lineHeight
) > 5 )
1895 hasSpecialSize
= true;
1897 wxWindow
* ctrlParent
= GetPanel();
1899 if ( !hasSpecialSize
)
1900 tcFlags
|= wxBORDER_NONE
;
1902 wxTextCtrl
* tc
= new wxTextCtrl();
1904 #if defined(__WXMSW__)
1907 SetupTextCtrlValue(value
);
1908 tc
->Create(ctrlParent
,id
,value
, p
, s
,tcFlags
);
1910 #if defined(__WXMSW__)
1911 // On Windows, we need to override read-only text ctrl's background
1912 // colour to white. One problem with native 'grey' background is that
1913 // tc->GetBackgroundColour() doesn't seem to return correct value
1915 if ( tcFlags
& wxTE_READONLY
)
1917 wxVisualAttributes vattrs
= tc
->GetDefaultAttributes();
1918 tc
->SetBackgroundColour(vattrs
.colBg
);
1922 // Center the control vertically
1923 if ( !hasSpecialSize
)
1924 FixPosForTextCtrl(tc
, forColumn
);
1926 if ( forColumn
!= 1 )
1928 tc
->SetBackgroundColour(m_colSelBack
);
1929 tc
->SetForegroundColour(m_colSelFore
);
1938 // Set maximum length
1940 tc
->SetMaxLength( maxLen
);
1942 wxVariant attrVal
= prop
->GetAttribute(wxPG_ATTR_AUTOCOMPLETE
);
1943 if ( !attrVal
.IsNull() )
1945 wxASSERT(attrVal
.GetType() == wxS("arrstring"));
1946 tc
->AutoComplete(attrVal
.GetArrayString());
1950 tc
->SetHint(prop
->GetHintText());
1955 // -----------------------------------------------------------------------
1957 wxWindow
* wxPropertyGrid::GenerateEditorButton( const wxPoint
& pos
, const wxSize
& sz
)
1959 wxWindowID id
= wxPG_SUBID2
;
1960 wxPGProperty
* selected
= GetSelection();
1964 // Decorations are chunky on Mac, and we can't make the button square, so
1965 // do things a bit differently on this platform.
1967 wxPoint
p(pos
.x
+sz
.x
,
1968 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
1971 wxButton
* but
= new wxButton();
1972 but
->Create(GetPanel(),id
,wxS("..."),p
,s
,wxWANTS_CHARS
);
1974 // Now that we know the size, move to the correct position
1975 p
.x
= pos
.x
+ sz
.x
- but
->GetSize().x
- 2;
1979 wxSize
s(sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2),
1980 sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2));
1982 // Reduce button width to lineheight
1983 if ( s
.x
> m_lineHeight
)
1987 // On wxGTK, take fixed button margins into account
1992 wxPoint
p(pos
.x
+sz
.x
-s
.x
,
1993 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
1995 wxButton
* but
= new wxButton();
1999 but
->Create(GetPanel(),id
,wxS("..."),p
,s
,wxWANTS_CHARS
);
2002 wxFont font
= GetFont();
2003 font
.SetPointSize(font
.GetPointSize()-2);
2006 but
->SetFont(GetFont());
2010 if ( selected
->HasFlag(wxPG_PROP_READONLY
) )
2016 // -----------------------------------------------------------------------
2018 wxWindow
* wxPropertyGrid::GenerateEditorTextCtrlAndButton( const wxPoint
& pos
,
2020 wxWindow
** psecondary
,
2022 wxPGProperty
* property
)
2024 wxButton
* but
= (wxButton
*)GenerateEditorButton(pos
,sz
);
2025 *psecondary
= (wxWindow
*)but
;
2027 if ( limitedEditing
)
2030 // There is button Show in GenerateEditorTextCtrl as well
2038 if ( !property
->IsValueUnspecified() )
2039 text
= property
->GetValueAsString(property
->HasFlag(wxPG_PROP_READONLY
)?0:wxPG_EDITABLE_VALUE
);
2041 return GenerateEditorTextCtrl(pos
,sz
,text
,but
,property
->m_maxLen
);
2044 // -----------------------------------------------------------------------
2046 void wxPropertyGrid::SetEditorAppearance( const wxPGCell
& cell
,
2049 wxPGProperty
* property
= GetSelection();
2052 wxWindow
* ctrl
= GetEditorControl();
2056 property
->GetEditorClass()->SetControlAppearance( this,
2063 m_editorAppearance
= cell
;
2066 // -----------------------------------------------------------------------
2068 wxTextCtrl
* wxPropertyGrid::GetEditorTextCtrl() const
2070 wxWindow
* wnd
= GetEditorControl();
2075 if ( wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) )
2076 return wxStaticCast(wnd
, wxTextCtrl
);
2078 if ( wnd
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) )
2080 wxOwnerDrawnComboBox
* cb
= wxStaticCast(wnd
, wxOwnerDrawnComboBox
);
2081 return cb
->GetTextCtrl();
2087 // -----------------------------------------------------------------------
2089 wxPGEditor
* wxPropertyGridInterface::GetEditorByName( const wxString
& editorName
)
2091 wxPGHashMapS2P::const_iterator it
;
2093 it
= wxPGGlobalVars
->m_mapEditorClasses
.find(editorName
);
2094 if ( it
== wxPGGlobalVars
->m_mapEditorClasses
.end() )
2096 return (wxPGEditor
*) it
->second
;
2099 // -----------------------------------------------------------------------
2100 // wxPGEditorDialogAdapter
2101 // -----------------------------------------------------------------------
2103 IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter
, wxObject
)
2105 bool wxPGEditorDialogAdapter::ShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
2107 if ( !propGrid
->EditorValidate() )
2110 bool res
= DoShowDialog( propGrid
, property
);
2114 propGrid
->ValueChangeInEvent( m_value
);
2121 // -----------------------------------------------------------------------
2123 // -----------------------------------------------------------------------
2125 wxPGMultiButton::wxPGMultiButton( wxPropertyGrid
* pg
, const wxSize
& sz
)
2126 : wxWindow( pg
->GetPanel(), wxPG_SUBID2
, wxPoint(-100,-100), wxSize(0, sz
.y
) ),
2127 m_fullEditorSize(sz
), m_buttonsWidth(0)
2129 SetBackgroundColour(pg
->GetCellBackgroundColour());
2132 void wxPGMultiButton::Finalize( wxPropertyGrid
* WXUNUSED(propGrid
),
2133 const wxPoint
& pos
)
2135 Move( pos
.x
+ m_fullEditorSize
.x
- m_buttonsWidth
, pos
.y
);
2138 int wxPGMultiButton::GenId( int id
) const
2142 if ( m_buttons
.size() )
2143 id
= GetButton(m_buttons
.size()-1)->GetId() + 1;
2151 void wxPGMultiButton::Add( const wxBitmap
& bitmap
, int id
)
2154 wxSize sz
= GetSize();
2155 wxButton
* button
= new wxBitmapButton( this, id
, bitmap
,
2157 wxSize(sz
.y
, sz
.y
) );
2158 DoAddButton( button
, sz
);
2162 void wxPGMultiButton::Add( const wxString
& label
, int id
)
2165 wxSize sz
= GetSize();
2166 wxButton
* button
= new wxButton( this, id
, label
, wxPoint(sz
.x
, 0),
2167 wxSize(sz
.y
, sz
.y
) );
2168 DoAddButton( button
, sz
);
2171 void wxPGMultiButton::DoAddButton( wxWindow
* button
,
2174 m_buttons
.push_back(button
);
2175 int bw
= button
->GetSize().x
;
2176 SetSize(wxSize(sz
.x
+bw
,sz
.y
));
2177 m_buttonsWidth
+= bw
;
2180 // -----------------------------------------------------------------------
2182 #endif // wxUSE_PROPGRID