1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/propgrid/editors.cpp
3 // Purpose: wxPropertyGrid editors
4 // Author: Jaakko Salli
7 // Copyright: (c) Jaakko Salli
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx/wx.h".
12 #include "wx/wxprec.h"
22 #include "wx/object.h"
24 #include "wx/string.h"
27 #include "wx/window.h"
30 #include "wx/dcclient.h"
31 #include "wx/dcmemory.h"
32 #include "wx/button.h"
35 #include "wx/cursor.h"
36 #include "wx/dialog.h"
37 #include "wx/settings.h"
38 #include "wx/msgdlg.h"
39 #include "wx/choice.h"
40 #include "wx/stattext.h"
41 #include "wx/scrolwin.h"
42 #include "wx/dirdlg.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 4
72 #define wxPG_TEXTCTRL_AND_BUTTON_SPACING 2
75 #define wxPG_BUTTON_SIZEDEC 0
77 #include "wx/odcombo.h"
79 // -----------------------------------------------------------------------
81 #if defined(__WXMSW__)
83 #define wxPG_NAT_BUTTON_BORDER_ANY 1
84 #define wxPG_NAT_BUTTON_BORDER_X 1
85 #define wxPG_NAT_BUTTON_BORDER_Y 1
87 #define wxPG_CHECKMARK_XADJ 1
88 #define wxPG_CHECKMARK_YADJ (-1)
89 #define wxPG_CHECKMARK_WADJ 0
90 #define wxPG_CHECKMARK_HADJ 0
91 #define wxPG_CHECKMARK_DEFLATE 0
93 #define wxPG_TEXTCTRLYADJUST (m_spacingy+0)
95 #elif defined(__WXGTK__)
97 #define wxPG_CHECKMARK_XADJ 1
98 #define wxPG_CHECKMARK_YADJ 1
99 #define wxPG_CHECKMARK_WADJ (-2)
100 #define wxPG_CHECKMARK_HADJ (-2)
101 #define wxPG_CHECKMARK_DEFLATE 3
103 #define wxPG_NAT_BUTTON_BORDER_ANY 1
104 #define wxPG_NAT_BUTTON_BORDER_X 1
105 #define wxPG_NAT_BUTTON_BORDER_Y 1
107 #define wxPG_TEXTCTRLYADJUST 0
109 #elif defined(__WXMAC__)
111 #define wxPG_CHECKMARK_XADJ 4
112 #define wxPG_CHECKMARK_YADJ 4
113 #define wxPG_CHECKMARK_WADJ -6
114 #define wxPG_CHECKMARK_HADJ -6
115 #define wxPG_CHECKMARK_DEFLATE 0
117 #define wxPG_NAT_BUTTON_BORDER_ANY 0
118 #define wxPG_NAT_BUTTON_BORDER_X 0
119 #define wxPG_NAT_BUTTON_BORDER_Y 0
121 #define wxPG_TEXTCTRLYADJUST 0
125 #define wxPG_CHECKMARK_XADJ 0
126 #define wxPG_CHECKMARK_YADJ 0
127 #define wxPG_CHECKMARK_WADJ 0
128 #define wxPG_CHECKMARK_HADJ 0
129 #define wxPG_CHECKMARK_DEFLATE 0
131 #define wxPG_NAT_BUTTON_BORDER_ANY 0
132 #define wxPG_NAT_BUTTON_BORDER_X 0
133 #define wxPG_NAT_BUTTON_BORDER_Y 0
135 #define wxPG_TEXTCTRLYADJUST 0
141 #define wxPG_CHOICEXADJUST -3 // required because wxComboCtrl reserves 3pixels for wxTextCtrl's focus ring
142 #define wxPG_CHOICEYADJUST -3
144 #define wxPG_CHOICEXADJUST 0
145 #define wxPG_CHOICEYADJUST 0
148 // Number added to image width for SetCustomPaintWidth
149 #define ODCB_CUST_PAINT_MARGIN 6
151 // Milliseconds to wait for two mouse-ups after focus in order
152 // to trigger a double-click.
153 #define DOUBLE_CLICK_CONVERSION_TRESHOLD 500
155 // -----------------------------------------------------------------------
157 // -----------------------------------------------------------------------
159 IMPLEMENT_ABSTRACT_CLASS(wxPGEditor
, wxObject
)
162 wxPGEditor::~wxPGEditor()
166 wxString
wxPGEditor::GetName() const
168 return GetClassInfo()->GetClassName();
171 void wxPGEditor::DrawValue( wxDC
& dc
, const wxRect
& rect
,
172 wxPGProperty
* WXUNUSED(property
),
173 const wxString
& text
) const
175 dc
.DrawText( text
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
178 bool wxPGEditor::GetValueFromControl( wxVariant
&, wxPGProperty
*, wxWindow
* ) const
183 void wxPGEditor::SetControlStringValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, const wxString
& ) const
188 void wxPGEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
*, int ) const
193 int wxPGEditor::InsertItem( wxWindow
*, const wxString
&, int ) const
199 void wxPGEditor::DeleteItem( wxWindow
*, int ) const
205 void wxPGEditor::OnFocus( wxPGProperty
*, wxWindow
* ) const
209 void wxPGEditor::SetControlAppearance( wxPropertyGrid
* pg
,
210 wxPGProperty
* property
,
212 const wxPGCell
& cell
,
213 const wxPGCell
& oCell
,
214 bool unspecified
) const
216 // Get old editor appearance
217 wxTextCtrl
* tc
= NULL
;
218 wxComboCtrl
* cb
= NULL
;
219 if ( wxDynamicCast(ctrl
, wxTextCtrl
) )
221 tc
= (wxTextCtrl
*) ctrl
;
225 if ( wxDynamicCast(ctrl
, wxComboCtrl
) )
227 cb
= (wxComboCtrl
*) ctrl
;
228 tc
= cb
->GetTextCtrl();
235 bool changeText
= false;
237 if ( cell
.HasText() && !pg
->IsEditorFocused() )
239 tcText
= cell
.GetText();
242 else if ( oCell
.HasText() )
244 tcText
= property
->GetValueAsString(
245 property
->HasFlag(wxPG_PROP_READONLY
)?0:wxPG_EDITABLE_VALUE
);
251 // This prevents value from being modified
254 pg
->SetupTextCtrlValue(tcText
);
255 tc
->SetValue(tcText
);
264 // Do not make the mistake of calling GetClassDefaultAttributes()
265 // here. It is static, while GetDefaultAttributes() is virtual
266 // and the correct one to use.
267 wxVisualAttributes vattrs
= ctrl
->GetDefaultAttributes();
270 const wxColour
& fgCol
= cell
.GetFgCol();
273 ctrl
->SetForegroundColour(fgCol
);
275 else if ( oCell
.GetFgCol().IsOk() )
277 ctrl
->SetForegroundColour(vattrs
.colFg
);
281 const wxColour
& bgCol
= cell
.GetBgCol();
284 ctrl
->SetBackgroundColour(bgCol
);
286 else if ( oCell
.GetBgCol().IsOk() )
288 ctrl
->SetBackgroundColour(vattrs
.colBg
);
292 const wxFont
& font
= cell
.GetFont();
297 else if ( oCell
.GetFont().IsOk() )
299 ctrl
->SetFont(vattrs
.font
);
302 // Also call the old SetValueToUnspecified()
304 SetValueToUnspecified(property
, ctrl
);
307 void wxPGEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
),
308 wxWindow
* WXUNUSED(ctrl
) ) const
312 bool wxPGEditor::CanContainCustomImage() const
317 // -----------------------------------------------------------------------
318 // wxPGTextCtrlEditor
319 // -----------------------------------------------------------------------
321 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrl
,wxPGTextCtrlEditor
,wxPGEditor
)
324 wxPGWindowList
wxPGTextCtrlEditor::CreateControls( wxPropertyGrid
* propGrid
,
325 wxPGProperty
* property
,
327 const wxSize
& sz
) const
332 // If has children, and limited editing is specified, then don't create.
333 if ( (property
->GetFlags() & wxPG_PROP_NOEDITOR
) &&
334 property
->GetChildCount() )
338 if ( !property
->HasFlag(wxPG_PROP_READONLY
) &&
339 !property
->IsValueUnspecified() )
340 argFlags
|= wxPG_EDITABLE_VALUE
;
341 text
= property
->GetValueAsString(argFlags
);
344 if ( (property
->GetFlags() & wxPG_PROP_PASSWORD
) &&
345 wxDynamicCast(property
, wxStringProperty
) )
346 flags
|= wxTE_PASSWORD
;
348 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrl(pos
,sz
,text
,NULL
,flags
,
349 property
->GetMaxLength());
355 void wxPGTextCtrlEditor::DrawValue( wxDC
& dc
, wxPGProperty
* property
, const wxRect
& rect
) const
357 if ( !property
->IsValueUnspecified() )
359 wxString drawStr
= property
->GetDisplayedString();
361 // Code below should no longer be needed, as the obfuscation
362 // is now done in GetValueAsString.
363 /*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
364 property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
366 size_t a = drawStr.length();
368 drawStr.Append(wxS('*'),a);
370 dc
.DrawText( drawStr
, rect
.x
+wxPG_XBEFORETEXT
, rect
.y
);
375 void wxPGTextCtrlEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
377 wxTextCtrl
* tc
= wxDynamicCast(ctrl
, wxTextCtrl
);
382 if ( tc
->HasFlag(wxTE_PASSWORD
) )
383 s
= property
->GetValueAsString(wxPG_FULL_VALUE
);
385 s
= property
->GetDisplayedString();
387 wxPropertyGrid
* pg
= property
->GetGrid();
389 pg
->SetupTextCtrlValue(s
);
393 // Fix indentation, just in case (change in font boldness is one good
398 // Provided so that, for example, ComboBox editor can use the same code
399 // (multiple inheritance would get way too messy).
400 bool wxPGTextCtrlEditor::OnTextCtrlEvent( wxPropertyGrid
* propGrid
,
401 wxPGProperty
* WXUNUSED(property
),
408 if ( event
.GetEventType() == wxEVT_TEXT_ENTER
)
410 if ( propGrid
->IsEditorsValueModified() )
415 else if ( event
.GetEventType() == wxEVT_TEXT
)
418 // Pass this event outside wxPropertyGrid so that,
419 // if necessary, program can tell when user is editing
421 // FIXME: Is it safe to change event id in the middle of event
422 // processing (seems to work, but...)?
424 event
.SetId(propGrid
->GetId());
426 propGrid
->EditorsValueWasModified();
432 bool wxPGTextCtrlEditor::OnEvent( wxPropertyGrid
* propGrid
,
433 wxPGProperty
* property
,
435 wxEvent
& event
) const
437 return wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid
,property
,ctrl
,event
);
441 bool wxPGTextCtrlEditor::GetTextCtrlValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
)
443 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
444 wxString textVal
= tc
->GetValue();
446 if ( property
->UsesAutoUnspecified() && textVal
.empty() )
452 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
454 // Changing unspecified always causes event (returning
455 // true here should be enough to trigger it).
456 // TODO: Move to propgrid.cpp
457 if ( !res
&& variant
.IsNull() )
464 bool wxPGTextCtrlEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
466 return wxPGTextCtrlEditor::GetTextCtrlValueFromControl(variant
, property
, ctrl
);
470 void wxPGTextCtrlEditor::SetControlStringValue( wxPGProperty
* property
, wxWindow
* ctrl
, const wxString
& txt
) const
472 wxTextCtrl
* tc
= wxStaticCast(ctrl
, wxTextCtrl
);
474 wxPropertyGrid
* pg
= property
->GetGrid();
475 wxASSERT(pg
); // Really, property grid should exist if editor does
478 pg
->SetupTextCtrlValue(txt
);
484 void wxPGTextCtrlEditor_OnFocus( wxPGProperty
* property
,
487 // Make sure there is correct text (instead of unspecified value
488 // indicator or hint text)
489 int flags
= property
->HasFlag(wxPG_PROP_READONLY
) ?
490 0 : wxPG_EDITABLE_VALUE
;
491 wxString correctText
= property
->GetValueAsString(flags
);
493 if ( tc
->GetValue() != correctText
)
495 property
->GetGrid()->SetupTextCtrlValue(correctText
);
496 tc
->SetValue(correctText
);
502 void wxPGTextCtrlEditor::OnFocus( wxPGProperty
* property
,
503 wxWindow
* wnd
) const
505 wxTextCtrl
* tc
= wxStaticCast(wnd
, wxTextCtrl
);
506 wxPGTextCtrlEditor_OnFocus(property
, tc
);
509 wxPGTextCtrlEditor::~wxPGTextCtrlEditor()
511 // Reset the global pointer. Useful when wxPropertyGrid is accessed
512 // from an external main loop.
513 wxPG_EDITOR(TextCtrl
) = NULL
;
517 // -----------------------------------------------------------------------
519 // -----------------------------------------------------------------------
522 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(Choice
,wxPGChoiceEditor
,wxPGEditor
)
525 // This is a special enhanced double-click processor class.
526 // In essence, it allows for double-clicks for which the
527 // first click "created" the control.
528 class wxPGDoubleClickProcessor
: public wxEvtHandler
532 wxPGDoubleClickProcessor( wxOwnerDrawnComboBox
* combo
, wxPGProperty
* property
)
535 m_timeLastMouseUp
= 0;
537 m_property
= property
;
538 m_downReceived
= false;
543 void OnMouseEvent( wxMouseEvent
& event
)
545 wxLongLong t
= ::wxGetLocalTimeMillis();
546 int evtType
= event
.GetEventType();
548 if ( m_property
->HasFlag(wxPG_PROP_USE_DCC
) &&
549 wxDynamicCast(m_property
, wxBoolProperty
) &&
550 !m_combo
->IsPopupShown() )
552 // Just check that it is in the text area
553 wxPoint pt
= event
.GetPosition();
554 if ( m_combo
->GetTextRect().Contains(pt
) )
556 if ( evtType
== wxEVT_LEFT_DOWN
)
558 // Set value to avoid up-events without corresponding downs
559 m_downReceived
= true;
561 else if ( evtType
== wxEVT_LEFT_DCLICK
)
563 // We'll make our own double-clicks
564 event
.SetEventType(0);
567 else if ( evtType
== wxEVT_LEFT_UP
)
569 if ( m_downReceived
|| m_timeLastMouseUp
== 1 )
571 wxLongLong timeFromLastUp
= (t
-m_timeLastMouseUp
);
573 if ( timeFromLastUp
< DOUBLE_CLICK_CONVERSION_TRESHOLD
)
575 event
.SetEventType(wxEVT_LEFT_DCLICK
);
576 m_timeLastMouseUp
= 1;
580 m_timeLastMouseUp
= t
;
590 void OnSetFocus( wxFocusEvent
& event
)
592 m_timeLastMouseUp
= ::wxGetLocalTimeMillis();
597 wxLongLong m_timeLastMouseUp
;
598 wxOwnerDrawnComboBox
* m_combo
;
599 wxPGProperty
* m_property
; // Selected property
602 DECLARE_EVENT_TABLE()
605 BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor
, wxEvtHandler
)
606 EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor::OnMouseEvent
)
607 EVT_SET_FOCUS(wxPGDoubleClickProcessor::OnSetFocus
)
612 class wxPGComboBox
: public wxOwnerDrawnComboBox
617 : wxOwnerDrawnComboBox()
619 m_dclickProcessor
= NULL
;
620 m_sizeEventCalled
= false;
625 if ( m_dclickProcessor
)
627 RemoveEventHandler(m_dclickProcessor
);
628 delete m_dclickProcessor
;
632 bool Create(wxWindow
*parent
,
634 const wxString
& value
,
637 const wxArrayString
& choices
,
639 const wxValidator
& validator
= wxDefaultValidator
,
640 const wxString
& name
= wxS("wxOwnerDrawnComboBox"))
642 if ( !wxOwnerDrawnComboBox::Create( parent
,
653 m_dclickProcessor
= new
654 wxPGDoubleClickProcessor( this, GetGrid()->GetSelection() );
656 PushEventHandler(m_dclickProcessor
);
661 virtual void OnDrawItem( wxDC
& dc
,
666 wxPropertyGrid
* pg
= GetGrid();
668 // Handle hint text via super class
669 if ( (flags
& wxODCB_PAINTING_CONTROL
) &&
670 ShouldUseHintText(flags
) )
672 wxOwnerDrawnComboBox::OnDrawItem(dc
, rect
, item
, flags
);
676 pg
->OnComboItemPaint( this, item
, &dc
, (wxRect
&)rect
, flags
);
680 virtual wxCoord
OnMeasureItem( size_t item
) const
682 wxPropertyGrid
* pg
= GetGrid();
686 pg
->OnComboItemPaint( this, item
, NULL
, rect
, 0 );
690 wxPropertyGrid
* GetGrid() const
692 wxPropertyGrid
* pg
= wxDynamicCast(GetParent(),
698 virtual wxCoord
OnMeasureItemWidth( size_t item
) const
700 wxPropertyGrid
* pg
= GetGrid();
704 pg
->OnComboItemPaint( this, item
, NULL
, rect
, 0 );
708 virtual void PositionTextCtrl( int textCtrlXAdjust
,
709 int WXUNUSED(textCtrlYAdjust
) )
711 wxPropertyGrid
* pg
= GetGrid();
712 #ifdef wxPG_TEXTCTRLXADJUST
713 textCtrlXAdjust
= wxPG_TEXTCTRLXADJUST
-
714 (wxPG_XBEFOREWIDGET
+wxPG_CONTROL_MARGIN
+1) - 1,
716 wxOwnerDrawnComboBox::PositionTextCtrl(
718 pg
->GetSpacingY() + 2
723 wxPGDoubleClickProcessor
* m_dclickProcessor
;
724 bool m_sizeEventCalled
;
728 void wxPropertyGrid::OnComboItemPaint( const wxPGComboBox
* pCb
,
734 wxPGProperty
* p
= GetSelection();
737 const wxPGChoices
& choices
= p
->GetChoices();
738 const wxPGCommonValue
* comVal
= NULL
;
739 int comVals
= p
->GetDisplayedCommonValueCount();
740 int comValIndex
= -1;
743 if ( choices
.IsOk() )
744 choiceCount
= choices
.GetCount();
746 if ( item
>= choiceCount
&& comVals
> 0 )
748 comValIndex
= item
- choiceCount
;
749 comVal
= GetCommonValue(comValIndex
);
750 if ( !p
->IsValueUnspecified() )
751 text
= comVal
->GetLabel();
755 if ( !(flags
& wxODCB_PAINTING_CONTROL
) )
757 text
= pCb
->GetString(item
);
761 if ( !p
->IsValueUnspecified() )
762 text
= p
->GetValueAsString(0);
771 const wxBitmap
* itemBitmap
= NULL
;
773 if ( item
>= 0 && choices
.IsOk() && choices
.Item(item
).GetBitmap().IsOk() && comValIndex
== -1 )
774 itemBitmap
= &choices
.Item(item
).GetBitmap();
777 // Decide what custom image size to use
780 cis
.x
= itemBitmap
->GetWidth();
781 cis
.y
= itemBitmap
->GetHeight();
785 cis
= GetImageSize(p
, item
);
790 // Default measure behaviour (no flexible, custom paint image only)
791 if ( rect
.width
< 0 )
794 pCb
->GetTextExtent(text
, &x
, &y
, 0, 0);
795 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9 + x
;
798 rect
.height
= cis
.y
+ 2;
802 wxPGPaintData paintdata
;
803 paintdata
.m_parent
= NULL
;
804 paintdata
.m_choiceItem
= item
;
806 // This is by the current (1.0.0b) spec - if painting control, item is -1
807 if ( (flags
& wxODCB_PAINTING_CONTROL
) )
808 paintdata
.m_choiceItem
= -1;
811 pDc
->SetBrush(*wxWHITE_BRUSH
);
813 wxPGCellRenderer
* renderer
= NULL
;
814 const wxPGChoiceEntry
* cell
= NULL
;
822 wxPoint
pt(rect
.x
+ wxPG_CONTROL_MARGIN
- wxPG_CHOICEXADJUST
- 1,
825 int renderFlags
= wxPGCellRenderer::DontUseCellColours
;
826 bool useCustomPaintProcedure
;
828 // If custom image had some size, we will start from the assumption
829 // that custom paint procedure is required
831 useCustomPaintProcedure
= true;
833 useCustomPaintProcedure
= false;
835 if ( flags
& wxODCB_PAINTING_SELECTED
)
836 renderFlags
|= wxPGCellRenderer::Selected
;
838 if ( flags
& wxODCB_PAINTING_CONTROL
)
840 renderFlags
|= wxPGCellRenderer::Control
;
842 // If wxPG_PROP_CUSTOMIMAGE was set, then that means any custom
843 // image will not appear on the control row (it may be too
844 // large to fit, for instance). Also do not draw custom image
845 // if no choice was selected.
846 if ( !p
->HasFlag(wxPG_PROP_CUSTOMIMAGE
) || item
< 0 )
847 useCustomPaintProcedure
= false;
851 renderFlags
|= wxPGCellRenderer::ChoicePopup
;
853 // For consistency, always use normal font when drawing drop down
855 dc
.SetFont(GetFont());
858 // If not drawing a selected popup item, then give property's
859 // m_valueBitmap a chance.
860 if ( p
->m_valueBitmap
&& item
!= pCb
->GetSelection() )
861 useCustomPaintProcedure
= false;
862 // If current choice had a bitmap set by the application, then
863 // use it instead of any custom paint procedure.
864 else if ( itemBitmap
)
865 useCustomPaintProcedure
= false;
867 if ( useCustomPaintProcedure
)
869 pt
.x
+= wxCC_CUSTOM_IMAGE_MARGIN1
;
870 wxRect
r(pt
.x
,pt
.y
,cis
.x
,cis
.y
);
872 if ( flags
& wxODCB_PAINTING_CONTROL
)
875 r
.height
= wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
);
878 paintdata
.m_drawnWidth
= r
.width
;
880 dc
.SetPen(m_colPropFore
);
881 if ( comValIndex
>= 0 )
883 const wxPGCommonValue
* cv
= GetCommonValue(comValIndex
);
884 renderer
= cv
->GetRenderer();
885 r
.width
= rect
.width
;
886 renderer
->Render( dc
, r
, this, p
, m_selColumn
, comValIndex
, renderFlags
);
889 else if ( item
>= 0 )
891 p
->OnCustomPaint( dc
, r
, paintdata
);
895 dc
.DrawRectangle( r
);
898 pt
.x
+= paintdata
.m_drawnWidth
+ wxCC_CUSTOM_IMAGE_MARGIN2
- 1;
902 // TODO: This aligns text so that it seems to be horizontally
903 // on the same line as property values. Not really
904 // sure if its needed, but seems to not cause any harm.
907 if ( item
< 0 && (flags
& wxODCB_PAINTING_CONTROL
) )
908 item
= pCb
->GetSelection();
910 if ( choices
.IsOk() && item
>= 0 && comValIndex
< 0 )
912 cell
= &choices
.Item(item
);
913 renderer
= wxPGGlobalVars
->m_defaultRenderer
;
914 int imageOffset
= renderer
->PreDrawCell(dc
, rect
, *cell
,
917 imageOffset
+= wxCC_CUSTOM_IMAGE_MARGIN1
+
918 wxCC_CUSTOM_IMAGE_MARGIN2
;
927 pt
.y
+= (rect
.height
-m_fontHeight
)/2 - 1;
931 dc
.DrawText( text
, pt
.x
+ wxPG_XBEFORETEXT
, pt
.y
);
934 renderer
->PostDrawCell(dc
, this, *cell
, renderFlags
);
942 p
->OnCustomPaint( dc
, rect
, paintdata
);
943 rect
.height
= paintdata
.m_drawnHeight
+ 2;
944 rect
.width
= cis
.x
+ wxCC_CUSTOM_IMAGE_MARGIN1
+ wxCC_CUSTOM_IMAGE_MARGIN2
+ 9;
948 bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid
* propGrid
, wxPGComboBox
* cb
, int cmnVal
)
950 wxPGProperty
* property
= propGrid
->GetSelectedProperty();
951 wxASSERT( property
);
956 // TODO: Do this always when cell has custom text.
957 if ( property
->IsValueUnspecified() )
959 cb
->SetCustomPaintWidth( 0 );
965 // Yes, a common value is being selected
966 property
->SetCommonValue( cmnVal
);
967 imageSize
= propGrid
->GetCommonValue(cmnVal
)->
968 GetRenderer()->GetImageSize(property
, 1, cmnVal
);
973 imageSize
= propGrid
->GetImageSize(property
, -1);
978 imageSize
.x
+= ODCB_CUST_PAINT_MARGIN
;
979 cb
->SetCustomPaintWidth( imageSize
.x
);
984 // CreateControls calls this with CB_READONLY in extraStyle
985 wxWindow
* wxPGChoiceEditor::CreateControlsBase( wxPropertyGrid
* propGrid
,
986 wxPGProperty
* property
,
989 long extraStyle
) const
991 // Since it is not possible (yet) to create a read-only combo box in
992 // the same sense that wxTextCtrl is read-only, simply do not create
993 // the control in this case.
994 if ( property
->HasFlag(wxPG_PROP_READONLY
) )
997 const wxPGChoices
& choices
= property
->GetChoices();
999 int index
= property
->GetChoiceSelection();
1002 if ( !property
->HasFlag(wxPG_PROP_READONLY
) &&
1003 !property
->IsValueUnspecified() )
1004 argFlags
|= wxPG_EDITABLE_VALUE
;
1005 defString
= property
->GetValueAsString(argFlags
);
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
| wxBORDER_NONE
| wxTE_PROCESS_ENTER
;
1022 if ( (property
->GetFlags() & wxPG_PROP_USE_DCC
) &&
1023 wxDynamicCast(property
, wxBoolProperty
) )
1024 odcbFlags
|= wxODCB_DCLICK_CYCLES
;
1027 // If common value specified, use appropriate index
1028 unsigned int cmnVals
= property
->GetDisplayedCommonValueCount();
1031 if ( !property
->IsValueUnspecified() )
1033 int cmnVal
= property
->GetCommonValue();
1036 index
= labels
.size() + cmnVal
;
1041 for ( i
=0; i
<cmnVals
; i
++ )
1042 labels
.Add(propGrid
->GetCommonValueLabel(i
));
1045 cb
= new wxPGComboBox();
1049 cb
->Create(ctrlParent
,
1057 cb
->SetButtonPosition(si
.y
,0,wxRIGHT
);
1058 cb
->SetMargins(wxPG_XBEFORETEXT
-1);
1061 cb
->SetHint(property
->GetHintText());
1063 wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
,
1064 property
->GetCommonValue() );
1066 if ( index
>= 0 && index
< (int)cb
->GetCount() )
1068 cb
->SetSelection( index
);
1069 if ( !defString
.empty() )
1070 cb
->SetText( defString
);
1072 else if ( !(extraStyle
& wxCB_READONLY
) && !defString
.empty() )
1074 propGrid
->SetupTextCtrlValue(defString
);
1075 cb
->SetValue( defString
);
1079 cb
->SetSelection( -1 );
1086 return (wxWindow
*) cb
;
1090 void wxPGChoiceEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1093 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1094 wxASSERT( wxDynamicCast(cb
, wxOwnerDrawnComboBox
));
1095 int ind
= property
->GetChoiceSelection();
1096 cb
->SetSelection(ind
);
1099 wxPGWindowList
wxPGChoiceEditor::CreateControls( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
1100 const wxPoint
& pos
, const wxSize
& sz
) const
1102 return CreateControlsBase(propGrid
,property
,pos
,sz
,wxCB_READONLY
);
1106 int wxPGChoiceEditor::InsertItem( wxWindow
* ctrl
, const wxString
& label
, int index
) const
1109 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1110 wxASSERT( wxDynamicCast(cb
, wxOwnerDrawnComboBox
));
1113 index
= cb
->GetCount();
1115 return cb
->Insert(label
,index
);
1119 void wxPGChoiceEditor::DeleteItem( wxWindow
* ctrl
, int index
) const
1122 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1123 wxASSERT( wxDynamicCast(cb
, wxOwnerDrawnComboBox
));
1128 bool wxPGChoiceEditor::OnEvent( wxPropertyGrid
* propGrid
, wxPGProperty
* property
,
1129 wxWindow
* ctrl
, wxEvent
& event
) const
1131 if ( event
.GetEventType() == wxEVT_COMBOBOX
)
1133 wxPGComboBox
* cb
= (wxPGComboBox
*)ctrl
;
1134 int index
= cb
->GetSelection();
1135 int cmnValIndex
= -1;
1136 int cmnVals
= property
->GetDisplayedCommonValueCount();
1137 int items
= cb
->GetCount();
1139 if ( index
>= (items
-cmnVals
) )
1141 // Yes, a common value is being selected
1142 cmnValIndex
= index
- (items
-cmnVals
);
1143 property
->SetCommonValue( cmnValIndex
);
1145 // Truly set value to unspecified?
1146 if ( propGrid
->GetUnspecifiedCommonValue() == cmnValIndex
)
1148 if ( !property
->IsValueUnspecified() )
1149 propGrid
->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT
);
1150 property
->SetValueToUnspecified();
1151 if ( !cb
->HasFlag(wxCB_READONLY
) )
1153 wxString unspecValueText
;
1154 unspecValueText
= propGrid
->GetUnspecifiedValueText();
1155 propGrid
->SetupTextCtrlValue(unspecValueText
);
1156 cb
->GetTextCtrl()->SetValue(unspecValueText
);
1161 return wxPGChoiceEditor_SetCustomPaintWidth( propGrid
, cb
, cmnValIndex
);
1167 bool wxPGChoiceEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1169 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1171 int index
= cb
->GetSelection();
1173 if ( index
!= property
->GetChoiceSelection() ||
1174 // Changing unspecified always causes event (returning
1175 // true here should be enough to trigger it).
1176 property
->IsValueUnspecified()
1179 return property
->IntToValue( variant
, index
, 0 );
1185 void wxPGChoiceEditor::SetControlStringValue( wxPGProperty
* property
,
1187 const wxString
& txt
) const
1189 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1191 property
->GetGrid()->SetupTextCtrlValue(txt
);
1196 void wxPGChoiceEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
1198 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1200 cb
->SetSelection(value
);
1204 void wxPGChoiceEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
),
1205 wxWindow
* ctrl
) const
1207 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1209 if ( cb
->HasFlag(wxCB_READONLY
) )
1210 cb
->SetSelection(-1);
1214 bool wxPGChoiceEditor::CanContainCustomImage() const
1220 wxPGChoiceEditor::~wxPGChoiceEditor()
1222 wxPG_EDITOR(Choice
) = NULL
;
1226 // -----------------------------------------------------------------------
1227 // wxPGComboBoxEditor
1228 // -----------------------------------------------------------------------
1231 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ComboBox
,
1236 void wxPGComboBoxEditor::UpdateControl( wxPGProperty
* property
, wxWindow
* ctrl
) const
1238 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1239 wxString s
= property
->GetValueAsString(wxPG_EDITABLE_VALUE
);
1240 property
->GetGrid()->SetupTextCtrlValue(s
);
1243 // TODO: If string matches any selection, then select that.
1247 wxPGWindowList
wxPGComboBoxEditor::CreateControls( wxPropertyGrid
* propGrid
,
1248 wxPGProperty
* property
,
1250 const wxSize
& sz
) const
1252 return CreateControlsBase(propGrid
,property
,pos
,sz
,0);
1256 bool wxPGComboBoxEditor::OnEvent( wxPropertyGrid
* propGrid
,
1257 wxPGProperty
* property
,
1259 wxEvent
& event
) const
1261 wxOwnerDrawnComboBox
* cb
= NULL
;
1262 wxWindow
* textCtrl
= NULL
;
1266 cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1267 textCtrl
= cb
->GetTextCtrl();
1270 if ( wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid
,property
,textCtrl
,event
) )
1273 return wxPGChoiceEditor::OnEvent(propGrid
,property
,ctrl
,event
);
1277 bool wxPGComboBoxEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1279 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1280 wxString textVal
= cb
->GetValue();
1282 if ( property
->UsesAutoUnspecified() && textVal
.empty() )
1288 bool res
= property
->StringToValue(variant
, textVal
, wxPG_EDITABLE_VALUE
);
1290 // Changing unspecified always causes event (returning
1291 // true here should be enough to trigger it).
1292 if ( !res
&& variant
.IsNull() )
1299 void wxPGComboBoxEditor::OnFocus( wxPGProperty
* property
,
1300 wxWindow
* ctrl
) const
1302 wxOwnerDrawnComboBox
* cb
= (wxOwnerDrawnComboBox
*)ctrl
;
1303 wxPGTextCtrlEditor_OnFocus(property
, cb
->GetTextCtrl());
1307 wxPGComboBoxEditor::~wxPGComboBoxEditor()
1309 wxPG_EDITOR(ComboBox
) = NULL
;
1314 // -----------------------------------------------------------------------
1315 // wxPGChoiceAndButtonEditor
1316 // -----------------------------------------------------------------------
1319 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(ChoiceAndButton
,
1320 wxPGChoiceAndButtonEditor
,
1324 wxPGWindowList
wxPGChoiceAndButtonEditor::CreateControls( wxPropertyGrid
* propGrid
,
1325 wxPGProperty
* property
,
1327 const wxSize
& sz
) const
1329 // Use one two units smaller to match size of the combo's dropbutton.
1330 // (normally a bigger button is used because it looks better)
1333 wxSize
bt_sz(bt_wid
,bt_wid
);
1335 // Position of button.
1336 wxPoint
bt_pos(pos
.x
+sz
.x
-bt_sz
.x
,pos
.y
);
1343 wxWindow
* bt
= propGrid
->GenerateEditorButton( bt_pos
, bt_sz
);
1346 wxSize
ch_sz(sz
.x
-bt
->GetSize().x
,sz
.y
);
1349 ch_sz
.x
-= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1352 wxWindow
* ch
= wxPGEditor_Choice
->CreateControls(propGrid
,property
,
1353 pos
,ch_sz
).m_primary
;
1359 return wxPGWindowList(ch
, bt
);
1363 wxPGChoiceAndButtonEditor::~wxPGChoiceAndButtonEditor()
1365 wxPG_EDITOR(ChoiceAndButton
) = NULL
;
1368 // -----------------------------------------------------------------------
1369 // wxPGTextCtrlAndButtonEditor
1370 // -----------------------------------------------------------------------
1372 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(TextCtrlAndButton
,
1373 wxPGTextCtrlAndButtonEditor
,
1377 wxPGWindowList
wxPGTextCtrlAndButtonEditor::CreateControls( wxPropertyGrid
* propGrid
,
1378 wxPGProperty
* property
,
1380 const wxSize
& sz
) const
1383 wxWindow
* wnd
= propGrid
->GenerateEditorTextCtrlAndButton( pos
, sz
, &wnd2
,
1384 property
->GetFlags() & wxPG_PROP_NOEDITOR
, property
);
1386 return wxPGWindowList(wnd
, wnd2
);
1390 wxPGTextCtrlAndButtonEditor::~wxPGTextCtrlAndButtonEditor()
1392 wxPG_EDITOR(TextCtrlAndButton
) = NULL
;
1395 // -----------------------------------------------------------------------
1396 // wxPGCheckBoxEditor
1397 // -----------------------------------------------------------------------
1399 #if wxPG_INCLUDE_CHECKBOX
1401 WX_PG_IMPLEMENT_INTERNAL_EDITOR_CLASS(CheckBox
,
1406 // Check box state flags
1409 wxSCB_STATE_UNCHECKED
= 0,
1410 wxSCB_STATE_CHECKED
= 1,
1411 wxSCB_STATE_BOLD
= 2,
1412 wxSCB_STATE_UNSPECIFIED
= 4
1415 const int wxSCB_SETVALUE_CYCLE
= 2;
1418 static void DrawSimpleCheckBox( wxDC
& dc
, const wxRect
& rect
, int box_hei
,
1422 wxRect
r(rect
.x
+wxPG_XBEFORETEXT
,rect
.y
+((rect
.height
-box_hei
)/2),
1424 wxColour useCol
= dc
.GetTextForeground();
1426 if ( state
& wxSCB_STATE_UNSPECIFIED
)
1428 useCol
= wxColour(220, 220, 220);
1431 // Draw check mark first because it is likely to overdraw the
1432 // surrounding rectangle.
1433 if ( state
& wxSCB_STATE_CHECKED
)
1435 wxRect
r2(r
.x
+wxPG_CHECKMARK_XADJ
,
1436 r
.y
+wxPG_CHECKMARK_YADJ
,
1437 r
.width
+wxPG_CHECKMARK_WADJ
,
1438 r
.height
+wxPG_CHECKMARK_HADJ
);
1439 #if wxPG_CHECKMARK_DEFLATE
1440 r2
.Deflate(wxPG_CHECKMARK_DEFLATE
);
1442 dc
.DrawCheckMark(r2
);
1444 // This would draw a simple cross check mark.
1445 // dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
1446 // dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
1449 if ( !(state
& wxSCB_STATE_BOLD
) )
1451 // Pen for thin rectangle.
1456 // Pen for bold rectangle.
1457 wxPen
linepen(useCol
,2,wxSOLID
);
1458 linepen
.SetJoin(wxJOIN_MITER
); // This prevents round edges.
1466 dc
.SetBrush(*wxTRANSPARENT_BRUSH
);
1468 dc
.DrawRectangle(r
);
1469 dc
.SetPen(*wxTRANSPARENT_PEN
);
1473 // Real simple custom-drawn checkbox-without-label class.
1475 class wxSimpleCheckBox
: public wxControl
1479 void SetValue( int value
);
1481 wxSimpleCheckBox( wxWindow
* parent
,
1483 const wxPoint
& pos
= wxDefaultPosition
,
1484 const wxSize
& size
= wxDefaultSize
)
1485 : wxControl(parent
,id
,pos
,size
,wxBORDER_NONE
|wxWANTS_CHARS
)
1487 // Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
1488 SetFont( parent
->GetFont() );
1493 SetBackgroundStyle( wxBG_STYLE_CUSTOM
);
1496 virtual ~wxSimpleCheckBox();
1502 void OnPaint( wxPaintEvent
& event
);
1503 void OnLeftClick( wxMouseEvent
& event
);
1504 void OnKeyDown( wxKeyEvent
& event
);
1506 void OnResize( wxSizeEvent
& event
)
1512 static wxBitmap
* ms_doubleBuffer
;
1514 DECLARE_EVENT_TABLE()
1517 BEGIN_EVENT_TABLE(wxSimpleCheckBox
, wxControl
)
1518 EVT_PAINT(wxSimpleCheckBox::OnPaint
)
1519 EVT_LEFT_DOWN(wxSimpleCheckBox::OnLeftClick
)
1520 EVT_LEFT_DCLICK(wxSimpleCheckBox::OnLeftClick
)
1521 EVT_KEY_DOWN(wxSimpleCheckBox::OnKeyDown
)
1522 EVT_SIZE(wxSimpleCheckBox::OnResize
)
1525 wxSimpleCheckBox::~wxSimpleCheckBox()
1527 wxDELETE(ms_doubleBuffer
);
1530 wxBitmap
* wxSimpleCheckBox::ms_doubleBuffer
= NULL
;
1532 void wxSimpleCheckBox::OnPaint( wxPaintEvent
& WXUNUSED(event
) )
1534 wxSize clientSize
= GetClientSize();
1535 wxAutoBufferedPaintDC
dc(this);
1538 wxRect
rect(0,0,clientSize
.x
,clientSize
.y
);
1542 wxColour bgcol
= GetBackgroundColour();
1543 dc
.SetBrush( bgcol
);
1545 dc
.DrawRectangle( rect
);
1547 dc
.SetTextForeground(GetForegroundColour());
1549 int state
= m_state
;
1550 if ( !(state
& wxSCB_STATE_UNSPECIFIED
) &&
1551 GetFont().GetWeight() == wxBOLD
)
1552 state
|= wxSCB_STATE_BOLD
;
1554 DrawSimpleCheckBox(dc
, rect
, m_boxHeight
, state
);
1557 void wxSimpleCheckBox::OnLeftClick( wxMouseEvent
& event
)
1559 if ( (event
.m_x
> (wxPG_XBEFORETEXT
-2)) &&
1560 (event
.m_x
<= (wxPG_XBEFORETEXT
-2+m_boxHeight
)) )
1562 SetValue(wxSCB_SETVALUE_CYCLE
);
1566 void wxSimpleCheckBox::OnKeyDown( wxKeyEvent
& event
)
1568 if ( event
.GetKeyCode() == WXK_SPACE
)
1570 SetValue(wxSCB_SETVALUE_CYCLE
);
1574 void wxSimpleCheckBox::SetValue( int value
)
1576 if ( value
== wxSCB_SETVALUE_CYCLE
)
1578 if ( m_state
& wxSCB_STATE_CHECKED
)
1579 m_state
&= ~wxSCB_STATE_CHECKED
;
1581 m_state
|= wxSCB_STATE_CHECKED
;
1589 wxCommandEvent
evt(wxEVT_CHECKBOX
,GetParent()->GetId());
1591 wxPropertyGrid
* propGrid
= (wxPropertyGrid
*) GetParent();
1592 wxASSERT( wxDynamicCast(propGrid
, wxPropertyGrid
) );
1593 propGrid
->HandleCustomEditorEvent(evt
);
1596 wxPGWindowList
wxPGCheckBoxEditor::CreateControls( wxPropertyGrid
* propGrid
,
1597 wxPGProperty
* property
,
1599 const wxSize
& size
) const
1601 if ( property
->HasFlag(wxPG_PROP_READONLY
) )
1605 pt
.x
-= wxPG_XBEFOREWIDGET
;
1607 sz
.x
= propGrid
->GetFontHeight() + (wxPG_XBEFOREWIDGET
*2) + 4;
1609 wxSimpleCheckBox
* cb
= new wxSimpleCheckBox(propGrid
->GetPanel(),
1610 wxPG_SUBID1
, pt
, sz
);
1612 cb
->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW
));
1614 UpdateControl(property
, cb
);
1616 if ( !property
->IsValueUnspecified() )
1618 // If mouse cursor was on the item, toggle the value now.
1619 if ( propGrid
->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK
)
1621 wxPoint point
= cb
->ScreenToClient(::wxGetMousePosition());
1622 if ( point
.x
<= (wxPG_XBEFORETEXT
-2+cb
->m_boxHeight
) )
1624 if ( cb
->m_state
& wxSCB_STATE_CHECKED
)
1625 cb
->m_state
&= ~wxSCB_STATE_CHECKED
;
1627 cb
->m_state
|= wxSCB_STATE_CHECKED
;
1629 // Makes sure wxPG_EVT_CHANGING etc. is sent for this initial
1631 propGrid
->ChangePropertyValue(property
,
1632 wxPGVariant_Bool(cb
->m_state
));
1637 propGrid
->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR
);
1642 void wxPGCheckBoxEditor::DrawValue( wxDC
& dc
, const wxRect
& rect
,
1643 wxPGProperty
* property
,
1644 const wxString
& WXUNUSED(text
) ) const
1646 int state
= wxSCB_STATE_UNCHECKED
;
1648 if ( !property
->IsValueUnspecified() )
1650 state
= property
->GetChoiceSelection();
1651 if ( dc
.GetFont().GetWeight() == wxBOLD
)
1652 state
|= wxSCB_STATE_BOLD
;
1656 state
|= wxSCB_STATE_UNSPECIFIED
;
1659 DrawSimpleCheckBox(dc
, rect
, dc
.GetCharHeight(), state
);
1662 void wxPGCheckBoxEditor::UpdateControl( wxPGProperty
* property
,
1663 wxWindow
* ctrl
) const
1665 wxSimpleCheckBox
* cb
= (wxSimpleCheckBox
*) ctrl
;
1668 if ( !property
->IsValueUnspecified() )
1669 cb
->m_state
= property
->GetChoiceSelection();
1671 cb
->m_state
= wxSCB_STATE_UNSPECIFIED
;
1673 wxPropertyGrid
* propGrid
= property
->GetGrid();
1674 cb
->m_boxHeight
= propGrid
->GetFontHeight();
1679 bool wxPGCheckBoxEditor::OnEvent( wxPropertyGrid
* WXUNUSED(propGrid
), wxPGProperty
* WXUNUSED(property
),
1680 wxWindow
* WXUNUSED(ctrl
), wxEvent
& event
) const
1682 if ( event
.GetEventType() == wxEVT_CHECKBOX
)
1690 bool wxPGCheckBoxEditor::GetValueFromControl( wxVariant
& variant
, wxPGProperty
* property
, wxWindow
* ctrl
) const
1692 wxSimpleCheckBox
* cb
= (wxSimpleCheckBox
*)ctrl
;
1694 int index
= cb
->m_state
;
1696 if ( index
!= property
->GetChoiceSelection() ||
1697 // Changing unspecified always causes event (returning
1698 // true here should be enough to trigger it).
1699 property
->IsValueUnspecified()
1702 return property
->IntToValue(variant
, index
, 0);
1708 void wxPGCheckBoxEditor::SetControlIntValue( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
, int value
) const
1710 if ( value
!= 0 ) value
= 1;
1711 ((wxSimpleCheckBox
*)ctrl
)->m_state
= value
;
1716 void wxPGCheckBoxEditor::SetValueToUnspecified( wxPGProperty
* WXUNUSED(property
), wxWindow
* ctrl
) const
1718 ((wxSimpleCheckBox
*)ctrl
)->m_state
= wxSCB_STATE_UNSPECIFIED
;
1723 wxPGCheckBoxEditor::~wxPGCheckBoxEditor()
1725 wxPG_EDITOR(CheckBox
) = NULL
;
1728 #endif // wxPG_INCLUDE_CHECKBOX
1730 // -----------------------------------------------------------------------
1732 wxWindow
* wxPropertyGrid::GetEditorControl() const
1734 wxWindow
* ctrl
= m_wndEditor
;
1742 // -----------------------------------------------------------------------
1744 void wxPropertyGrid::CorrectEditorWidgetSizeX()
1748 // Use fixed selColumn 1 for main editor widgets
1749 int newSplitterx
= m_pState
->DoGetSplitterPosition(0);
1750 int newWidth
= newSplitterx
+ m_pState
->m_colWidths
[1];
1754 // if width change occurred, move secondary wnd by that amount
1755 wxRect r
= m_wndEditor2
->GetRect();
1757 r
.x
= newWidth
- secWid
;
1759 m_wndEditor2
->SetSize( r
);
1761 // if primary is textctrl, then we have to add some extra space
1765 if ( wxDynamicCast(m_wndEditor
, wxTextCtrl
) )
1767 secWid
+= wxPG_TEXTCTRL_AND_BUTTON_SPACING
;
1772 wxRect r
= m_wndEditor
->GetRect();
1774 r
.x
= newSplitterx
+m_ctrlXAdjust
;
1776 if ( !(m_iFlags
& wxPG_FL_FIXED_WIDTH_EDITOR
) )
1777 r
.width
= newWidth
- r
.x
- secWid
;
1779 m_wndEditor
->SetSize(r
);
1783 m_wndEditor2
->Refresh();
1786 // -----------------------------------------------------------------------
1788 void wxPropertyGrid::CorrectEditorWidgetPosY()
1790 wxPGProperty
* selected
= GetSelection();
1794 if ( m_labelEditor
)
1796 wxRect r
= GetEditorWidgetRect(selected
, m_selColumn
);
1797 wxPoint pos
= m_labelEditor
->GetPosition();
1799 // Calculate y offset
1800 int offset
= pos
.y
% m_lineHeight
;
1802 m_labelEditor
->Move(pos
.x
, r
.y
+ offset
);
1805 if ( m_wndEditor
|| m_wndEditor2
)
1807 wxRect r
= GetEditorWidgetRect(selected
, 1);
1811 wxPoint pos
= m_wndEditor
->GetPosition();
1813 // Calculate y offset
1814 int offset
= pos
.y
% m_lineHeight
;
1816 m_wndEditor
->Move(pos
.x
, r
.y
+ offset
);
1821 wxPoint pos
= m_wndEditor2
->GetPosition();
1823 m_wndEditor2
->Move(pos
.x
, r
.y
);
1829 // -----------------------------------------------------------------------
1831 // Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
1832 // fits into that category as well).
1833 void wxPropertyGrid::FixPosForTextCtrl( wxWindow
* ctrl
,
1834 unsigned int WXUNUSED(forColumn
),
1835 const wxPoint
& offset
)
1837 // Center the control vertically
1838 wxRect finalPos
= ctrl
->GetRect();
1839 int y_adj
= (m_lineHeight
- finalPos
.height
)/2 + wxPG_TEXTCTRLYADJUST
;
1841 // Prevent over-sized control
1842 int sz_dec
= (y_adj
+ finalPos
.height
) - m_lineHeight
;
1843 if ( sz_dec
< 0 ) sz_dec
= 0;
1845 finalPos
.y
+= y_adj
;
1846 finalPos
.height
-= (y_adj
+sz_dec
);
1848 #ifndef wxPG_TEXTCTRLXADJUST
1849 int textCtrlXAdjust
= wxPG_XBEFORETEXT
- 1;
1851 wxTextCtrl
* tc
= static_cast<wxTextCtrl
*>(ctrl
);
1854 int textCtrlXAdjust
= wxPG_TEXTCTRLXADJUST
;
1857 finalPos
.x
+= textCtrlXAdjust
;
1858 finalPos
.width
-= textCtrlXAdjust
;
1860 finalPos
.x
+= offset
.x
;
1861 finalPos
.y
+= offset
.y
;
1863 ctrl
->SetSize(finalPos
);
1866 // -----------------------------------------------------------------------
1868 wxWindow
* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint
& pos
,
1870 const wxString
& value
,
1871 wxWindow
* secondary
,
1874 unsigned int forColumn
)
1876 wxWindowID id
= wxPG_SUBID1
;
1877 wxPGProperty
* prop
= GetSelection();
1880 int tcFlags
= wxTE_PROCESS_ENTER
| extraStyle
;
1882 if ( prop
->HasFlag(wxPG_PROP_READONLY
) && forColumn
== 1 )
1883 tcFlags
|= wxTE_READONLY
;
1885 wxPoint
p(pos
.x
,pos
.y
);
1886 wxSize
s(sz
.x
,sz
.y
);
1888 // Need to reduce width of text control on Mac
1889 #if defined(__WXMAC__)
1893 // For label editors, trim the size to allow better splitter grabbing
1894 if ( forColumn
!= 1 )
1897 // Take button into acccount
1900 s
.x
-= (secondary
->GetSize().x
+ wxPG_TEXTCTRL_AND_BUTTON_SPACING
);
1901 m_iFlags
&= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE
);
1904 // If the height is significantly higher, then use border, and fill the rect exactly.
1905 bool hasSpecialSize
= false;
1907 if ( (sz
.y
- m_lineHeight
) > 5 )
1908 hasSpecialSize
= true;
1910 wxWindow
* ctrlParent
= GetPanel();
1912 if ( !hasSpecialSize
)
1913 tcFlags
|= wxBORDER_NONE
;
1915 wxTextCtrl
* tc
= new wxTextCtrl();
1917 #if defined(__WXMSW__)
1920 SetupTextCtrlValue(value
);
1921 tc
->Create(ctrlParent
,id
,value
, p
, s
,tcFlags
);
1923 #if defined(__WXMSW__)
1924 // On Windows, we need to override read-only text ctrl's background
1925 // colour to white. One problem with native 'grey' background is that
1926 // tc->GetBackgroundColour() doesn't seem to return correct value
1928 if ( tcFlags
& wxTE_READONLY
)
1930 wxVisualAttributes vattrs
= tc
->GetDefaultAttributes();
1931 tc
->SetBackgroundColour(vattrs
.colBg
);
1935 // This code is repeated from DoSelectProperty(). However, font boldness
1936 // must be set before margin is set up below in FixPosForTextCtrl().
1937 if ( forColumn
== 1 &&
1938 prop
->HasFlag(wxPG_PROP_MODIFIED
) &&
1939 HasFlag(wxPG_BOLD_MODIFIED
) )
1940 tc
->SetFont( m_captionFont
);
1942 // Center the control vertically
1943 if ( !hasSpecialSize
)
1944 FixPosForTextCtrl(tc
, forColumn
);
1946 if ( forColumn
!= 1 )
1948 tc
->SetBackgroundColour(m_colSelBack
);
1949 tc
->SetForegroundColour(m_colSelFore
);
1958 // Set maximum length
1960 tc
->SetMaxLength( maxLen
);
1962 wxVariant attrVal
= prop
->GetAttribute(wxPG_ATTR_AUTOCOMPLETE
);
1963 if ( !attrVal
.IsNull() )
1965 wxASSERT(attrVal
.GetType() == wxS("arrstring"));
1966 tc
->AutoComplete(attrVal
.GetArrayString());
1970 tc
->SetHint(prop
->GetHintText());
1975 // -----------------------------------------------------------------------
1977 wxWindow
* wxPropertyGrid::GenerateEditorButton( const wxPoint
& pos
, const wxSize
& sz
)
1979 wxWindowID id
= wxPG_SUBID2
;
1980 wxPGProperty
* selected
= GetSelection();
1984 // Decorations are chunky on Mac, and we can't make the button square, so
1985 // do things a bit differently on this platform.
1987 wxPoint
p(pos
.x
+sz
.x
,
1988 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
1991 wxButton
* but
= new wxButton();
1992 but
->Create(GetPanel(),id
,wxS("..."),p
,s
,wxWANTS_CHARS
);
1994 // Now that we know the size, move to the correct position
1995 p
.x
= pos
.x
+ sz
.x
- but
->GetSize().x
- 2;
1999 wxSize
s(sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2),
2000 sz
.y
-(wxPG_BUTTON_SIZEDEC
*2)+(wxPG_NAT_BUTTON_BORDER_Y
*2));
2002 // Reduce button width to lineheight
2003 if ( s
.x
> m_lineHeight
)
2007 // On wxGTK, take fixed button margins into account
2012 wxPoint
p(pos
.x
+sz
.x
-s
.x
,
2013 pos
.y
+wxPG_BUTTON_SIZEDEC
-wxPG_NAT_BUTTON_BORDER_Y
);
2015 wxButton
* but
= new wxButton();
2019 but
->Create(GetPanel(),id
,wxS("..."),p
,s
,wxWANTS_CHARS
);
2022 wxFont font
= GetFont();
2023 font
.SetPointSize(font
.GetPointSize()-2);
2026 but
->SetFont(GetFont());
2030 if ( selected
->HasFlag(wxPG_PROP_READONLY
) )
2036 // -----------------------------------------------------------------------
2038 wxWindow
* wxPropertyGrid::GenerateEditorTextCtrlAndButton( const wxPoint
& pos
,
2040 wxWindow
** psecondary
,
2042 wxPGProperty
* property
)
2044 wxButton
* but
= (wxButton
*)GenerateEditorButton(pos
,sz
);
2045 *psecondary
= (wxWindow
*)but
;
2047 if ( limitedEditing
)
2050 // There is button Show in GenerateEditorTextCtrl as well
2058 if ( !property
->IsValueUnspecified() )
2059 text
= property
->GetValueAsString(property
->HasFlag(wxPG_PROP_READONLY
)?0:wxPG_EDITABLE_VALUE
);
2061 return GenerateEditorTextCtrl(pos
,sz
,text
,but
,property
->m_maxLen
);
2064 // -----------------------------------------------------------------------
2066 void wxPropertyGrid::SetEditorAppearance( const wxPGCell
& cell
,
2069 wxPGProperty
* property
= GetSelection();
2072 wxWindow
* ctrl
= GetEditorControl();
2076 property
->GetEditorClass()->SetControlAppearance( this,
2083 m_editorAppearance
= cell
;
2086 // -----------------------------------------------------------------------
2088 wxTextCtrl
* wxPropertyGrid::GetEditorTextCtrl() const
2090 wxWindow
* wnd
= GetEditorControl();
2095 if ( wxDynamicCast(wnd
, wxTextCtrl
) )
2096 return wxStaticCast(wnd
, wxTextCtrl
);
2098 if ( wxDynamicCast(wnd
, wxOwnerDrawnComboBox
) )
2100 wxOwnerDrawnComboBox
* cb
= wxStaticCast(wnd
, wxOwnerDrawnComboBox
);
2101 return cb
->GetTextCtrl();
2107 // -----------------------------------------------------------------------
2109 wxPGEditor
* wxPropertyGridInterface::GetEditorByName( const wxString
& editorName
)
2111 wxPGHashMapS2P::const_iterator it
;
2113 it
= wxPGGlobalVars
->m_mapEditorClasses
.find(editorName
);
2114 if ( it
== wxPGGlobalVars
->m_mapEditorClasses
.end() )
2116 return (wxPGEditor
*) it
->second
;
2119 // -----------------------------------------------------------------------
2120 // wxPGEditorDialogAdapter
2121 // -----------------------------------------------------------------------
2123 IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter
, wxObject
)
2125 bool wxPGEditorDialogAdapter::ShowDialog( wxPropertyGrid
* propGrid
, wxPGProperty
* property
)
2127 if ( !propGrid
->EditorValidate() )
2130 bool res
= DoShowDialog( propGrid
, property
);
2134 propGrid
->ValueChangeInEvent( m_value
);
2141 // -----------------------------------------------------------------------
2143 // -----------------------------------------------------------------------
2145 wxPGMultiButton::wxPGMultiButton( wxPropertyGrid
* pg
, const wxSize
& sz
)
2146 : wxWindow( pg
->GetPanel(), wxPG_SUBID2
, wxPoint(-100,-100), wxSize(0, sz
.y
) ),
2147 m_fullEditorSize(sz
), m_buttonsWidth(0)
2149 SetBackgroundColour(pg
->GetCellBackgroundColour());
2152 void wxPGMultiButton::Finalize( wxPropertyGrid
* WXUNUSED(propGrid
),
2153 const wxPoint
& pos
)
2155 Move( pos
.x
+ m_fullEditorSize
.x
- m_buttonsWidth
, pos
.y
);
2158 int wxPGMultiButton::GenId( int itemid
) const
2162 if ( m_buttons
.size() )
2163 itemid
= GetButton(m_buttons
.size()-1)->GetId() + 1;
2165 itemid
= wxPG_SUBID2
;
2171 void wxPGMultiButton::Add( const wxBitmap
& bitmap
, int itemid
)
2173 itemid
= GenId(itemid
);
2174 wxSize sz
= GetSize();
2175 wxButton
* button
= new wxBitmapButton( this, itemid
, bitmap
,
2177 wxSize(sz
.y
, sz
.y
) );
2178 DoAddButton( button
, sz
);
2182 void wxPGMultiButton::Add( const wxString
& label
, int itemid
)
2184 itemid
= GenId(itemid
);
2185 wxSize sz
= GetSize();
2186 wxButton
* button
= new wxButton( this, itemid
, label
, wxPoint(sz
.x
, 0),
2187 wxSize(sz
.y
, sz
.y
) );
2188 DoAddButton( button
, sz
);
2191 void wxPGMultiButton::DoAddButton( wxWindow
* button
,
2194 m_buttons
.push_back(button
);
2195 int bw
= button
->GetSize().x
;
2196 SetSize(wxSize(sz
.x
+bw
,sz
.y
));
2197 m_buttonsWidth
+= bw
;
2200 // -----------------------------------------------------------------------
2202 #endif // wxUSE_PROPGRID