1
/////////////////////////////////////////////////////////////////////////////
3
// Purpose: wxPropertyGrid editors
4
// Author: Jaakko Salli
6
// Created: Apr-14-2007
8
// Copyright: (c) Jaakko Salli
9
// Licence: wxWindows license
10
/////////////////////////////////////////////////////////////////////////////
12
// For compilers that support precompilation, includes "wx/wx.h".
13
#include "wx/wxprec.h"
21
#include "wx/object.h"
23
#include "wx/string.h"
26
#include "wx/window.h"
29
#include "wx/dcclient.h"
30
#include "wx/dcmemory.h"
31
#include "wx/button.h"
34
#include "wx/cursor.h"
35
#include "wx/dialog.h"
36
#include "wx/settings.h"
37
#include "wx/msgdlg.h"
38
#include "wx/choice.h"
39
#include "wx/stattext.h"
40
#include "wx/scrolwin.h"
41
#include "wx/dirdlg.h"
42
#include "wx/layout.h"
44
#include "wx/textdlg.h"
45
#include "wx/filedlg.h"
46
#include "wx/statusbr.h"
53
#include "wx/dcbuffer.h"
54
#include "wx/bmpbuttn.h"
57
// This define is necessary to prevent macro clearing
58
#define __wxPG_SOURCE_FILE__
60
#include <wx/propgrid/propgrid.h>
61
#include <wx/propgrid/propdev.h>
62
#include <wx/propgrid/editors.h>
63
#include <wx/propgrid/props.h>
66
#include <wx/propgrid/advprops.h>
67
#include <wx/propgrid/extras.h>
70
#if wxPG_USE_RENDERER_NATIVE
71
#include <wx/renderer.h>
74
// How many pixels between textctrl and button
76
#define wxPG_TEXTCTRL_AND_BUTTON_SPACING 8
78
#define wxPG_TEXTCTRL_AND_BUTTON_SPACING 2
81
#define wxPG_BUTTON_SIZEDEC 0
83
#if wxPG_USING_WXOWNERDRAWNCOMBOBOX
84
#include <wx/odcombo.h>
86
#include <wx/propgrid/odcombo.h>
90
#include <wx/msw/private.h>
93
// -----------------------------------------------------------------------
95
#if defined(__WXMSW__)
97
#define wxPG_NAT_TEXTCTRL_BORDER_X 0 // Unremovable border of native textctrl.
98
#define wxPG_NAT_TEXTCTRL_BORDER_Y 0 // Unremovable border of native textctrl.
100
#define wxPG_NAT_BUTTON_BORDER_ANY 1
101
#define wxPG_NAT_BUTTON_BORDER_X 1
102
#define wxPG_NAT_BUTTON_BORDER_Y 1
104
#define wxPG_CHECKMARK_XADJ 1
105
#define wxPG_CHECKMARK_YADJ (-1)
106
#define wxPG_CHECKMARK_WADJ 0
107
#define wxPG_CHECKMARK_HADJ 0
108
#define wxPG_CHECKMARK_DEFLATE 0
110
#define wxPG_TEXTCTRLYADJUST (m_spacingy+0)
112
#elif defined(__WXGTK__)
114
#define wxPG_CHECKMARK_XADJ 0
115
#define wxPG_CHECKMARK_YADJ 0
116
#define wxPG_CHECKMARK_WADJ (-1)
117
#define wxPG_CHECKMARK_HADJ (-1)
118
#define wxPG_CHECKMARK_DEFLATE 3
120
#define wxPG_NAT_TEXTCTRL_BORDER_X 3 // Unremovable border of native textctrl.
121
#define wxPG_NAT_TEXTCTRL_BORDER_Y 3 // Unremovable border of native textctrl.
123
#define wxPG_NAT_BUTTON_BORDER_ANY 1
124
#define wxPG_NAT_BUTTON_BORDER_X 1
125
#define wxPG_NAT_BUTTON_BORDER_Y 1
127
#define wxPG_TEXTCTRLYADJUST 0
129
#elif defined(__WXMAC__)
131
#define wxPG_CHECKMARK_XADJ 0
132
#define wxPG_CHECKMARK_YADJ 0
133
#define wxPG_CHECKMARK_WADJ 0
134
#define wxPG_CHECKMARK_HADJ 0
135
#define wxPG_CHECKMARK_DEFLATE 0
137
#define wxPG_NAT_TEXTCTRL_BORDER_X 0 // Unremovable border of native textctrl.
138
#define wxPG_NAT_TEXTCTRL_BORDER_Y 0 // Unremovable border of native textctrl.
140
#define wxPG_NAT_BUTTON_BORDER_ANY 0
141
#define wxPG_NAT_BUTTON_BORDER_X 0
142
#define wxPG_NAT_BUTTON_BORDER_Y 0
144
#define wxPG_TEXTCTRLYADJUST 3
148
#define wxPG_CHECKMARK_XADJ 0
149
#define wxPG_CHECKMARK_YADJ 0
150
#define wxPG_CHECKMARK_WADJ 0
151
#define wxPG_CHECKMARK_HADJ 0
152
#define wxPG_CHECKMARK_DEFLATE 0
154
#define wxPG_NAT_TEXTCTRL_BORDER_X 0 // Unremovable border of native textctrl.
155
#define wxPG_NAT_TEXTCTRL_BORDER_Y 0 // Unremovable border of native textctrl.
157
#define wxPG_NAT_BUTTON_BORDER_ANY 0
158
#define wxPG_NAT_BUTTON_BORDER_X 0
159
#define wxPG_NAT_BUTTON_BORDER_Y 0
161
#define wxPG_TEXTCTRLYADJUST 0
165
#if (!wxPG_NAT_TEXTCTRL_BORDER_X && !wxPG_NAT_TEXTCTRL_BORDER_Y)
166
#define wxPG_ENABLE_CLIPPER_WINDOW 0
168
#define wxPG_ENABLE_CLIPPER_WINDOW 1
173
#define wxPG_CHOICEXADJUST 0
174
#define wxPG_CHOICEYADJUST 0
176
#define ODCB_CUST_PAINT_MARGIN 6 // Number added to image width for SetCustomPaintWidth
178
// Milliseconds to wait for two mouse-ups after focus inorder
179
// to trigger a double-click.
180
#define DOUBLE_CLICK_CONVERSION_TRESHOLD 500
182
// -----------------------------------------------------------------------
184
// -----------------------------------------------------------------------
186
IMPLEMENT_ABSTRACT_CLASS(wxPGEditor, wxObject)
188
wxPGEditor::~wxPGEditor()
193
/*wxPGCellRenderer* wxPGEditor::GetCellRenderer() const
195
return &g_wxPGDefaultRenderer;
198
void wxPGEditor::DrawValue( wxDC& dc, const wxRect& rect, wxPGProperty* property, const wxString& text ) const
200
if ( !property->IsValueUnspecified() )
201
dc.DrawText( text, rect.x+wxPG_XBEFORETEXT, rect.y );
205
bool wxPGEditor::GetValueFromControl( wxVariant&, wxPGProperty*, wxWindow* ) const
210
wxPGVariantAndBool wxPGEditor::PyGetValueFromControl( wxPGProperty* property, wxWindow* ctrl ) const
212
wxPGVariantAndBool vab;
213
vab.m_result = GetValueFromControl(vab.m_value, property, ctrl);
215
vab.m_valueValid = true;
220
void wxPGEditor::SetControlStringValue( wxPGProperty* WXUNUSED(property), wxWindow*, const wxString& ) const
225
void wxPGEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow*, int ) const
230
int wxPGEditor::InsertItem( wxWindow*, const wxString&, int ) const
236
void wxPGEditor::DeleteItem( wxWindow*, int ) const
242
void wxPGEditor::OnFocus( wxPGProperty*, wxWindow* ) const
247
bool wxPGEditor::CanContainCustomImage() const
252
// -----------------------------------------------------------------------
254
// -----------------------------------------------------------------------
257
#if wxPG_ENABLE_CLIPPER_WINDOW
260
// Clipper window is used to "remove" borders from controls
261
// which otherwise insist on having them despite of supplied
262
// wxNO_BORDER window style.
264
class wxPGClipperWindow : public wxWindow
266
DECLARE_CLASS(wxPGClipperWindow)
272
wxPGClipperWindow::Init();
275
wxPGClipperWindow(wxWindow* parent,
277
const wxPoint& pos = wxDefaultPosition,
278
const wxSize& size = wxDefaultSize)
281
Create(parent,id,pos,size);
284
void Create(wxWindow* parent,
286
const wxPoint& pos = wxDefaultPosition,
287
const wxSize& size = wxDefaultSize);
289
virtual ~wxPGClipperWindow();
291
virtual bool ProcessEvent(wxEvent& event);
293
inline wxWindow* GetControl() const { return m_ctrl; }
295
// This is called before wxControl is constructed.
296
void GetControlRect( int xadj, int yadj, wxPoint& pt, wxSize& sz );
298
// This is caleed after wxControl has been constructed.
299
void SetControl( wxWindow* ctrl );
301
virtual void Refresh( bool eraseBackground = true,
302
const wxRect *rect = (const wxRect *) NULL );
303
virtual void SetFocus();
305
virtual bool SetFont(const wxFont& font);
307
inline int GetXClip() const { return m_xadj; }
309
inline int GetYClip() const { return m_yadj; }
314
int m_xadj; // Horizontal border clip.
316
int m_yadj; // Vertical border clip.
321
m_ctrl = (wxWindow*) NULL;
326
IMPLEMENT_CLASS(wxPGClipperWindow,wxWindow)
329
// This is called before wxControl is constructed.
330
void wxPGClipperWindow::GetControlRect( int xadj, int yadj, wxPoint& pt, wxSize& sz )
336
wxSize own_size = GetSize();
337
sz.x = own_size.x+(xadj*2);
338
sz.y = own_size.y+(yadj*2);
342
// This is caleed after wxControl has been constructed.
343
void wxPGClipperWindow::SetControl( wxWindow* ctrl )
347
// GTK requires this.
348
ctrl->SetSizeHints(3,3);
350
// Correct size of this window to match the child.
351
wxSize sz = GetSize();
352
wxSize chsz = ctrl->GetSize();
354
int hei_adj = chsz.y - (sz.y+(m_yadj*2));
356
SetSize(sz.x,chsz.y-(m_yadj*2));
361
void wxPGClipperWindow::Refresh( bool eraseBackground, const wxRect *rect )
363
wxWindow::Refresh(false,rect);
365
m_ctrl->Refresh(eraseBackground);
369
// Pass focus to control
370
void wxPGClipperWindow::SetFocus()
375
wxWindow::SetFocus();
379
bool wxPGClipperWindow::SetFont(const wxFont& font)
381
bool res = wxWindow::SetFont(font);
383
return m_ctrl->SetFont(font);
388
void wxPGClipperWindow::Create(wxWindow* parent,
393
wxWindow::Create(parent,id,pos,size);
397
wxPGClipperWindow::~wxPGClipperWindow()
402
bool wxPGClipperWindow::ProcessEvent(wxEvent& event)
404
if ( event.GetEventType() == wxEVT_SIZE )
408
// Maintain correct size relationship.
409
wxSize sz = GetSize();
410
m_ctrl->SetSize(sz.x+(m_xadj*2),sz.y+(m_yadj*2));
415
return wxWindow::ProcessEvent(event);
418
#endif // wxPG_ENABLE_CLIPPER_WINDOW
420
/*wxWindow* wxPropertyGrid::GetActualEditorControl( wxWindow* ctrl )
422
#if wxPG_ENABLE_CLIPPER_WINDOW
423
// Pass real control instead of clipper window
424
if ( ctrl->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
426
return ((wxPGClipperWindow*)ctrl)->GetControl();
433
// -----------------------------------------------------------------------
434
// wxPGTextCtrlEditor
435
// -----------------------------------------------------------------------
437
// Clipper window support macro (depending on whether it is used
438
// for this editor or not)
439
#if wxPG_NAT_TEXTCTRL_BORDER_X || wxPG_NAT_TEXTCTRL_BORDER_Y
440
#define wxPG_NAT_TEXTCTRL_BORDER_ANY 1
442
#define wxPG_NAT_TEXTCTRL_BORDER_ANY 0
446
WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrl,wxPGTextCtrlEditor,wxPGEditor)
449
wxPGWindowList wxPGTextCtrlEditor::CreateControls( wxPropertyGrid* propGrid,
450
wxPGProperty* property,
452
const wxSize& sz ) const
457
// If has children, and limited editing is specified, then don't create.
458
if ( (property->GetFlags() & wxPG_PROP_NOEDITOR) &&
459
property->GetChildCount() )
460
return (wxWindow*) NULL;
462
if ( !property->IsValueUnspecified() )
463
text = property->GetValueString(property->HasFlag(wxPG_PROP_READONLY)?0:wxPG_EDITABLE_VALUE);
466
if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
467
property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
468
flags |= wxTE_PASSWORD;
470
wxWindow* wnd = propGrid->GenerateEditorTextCtrl(pos,sz,text,(wxWindow*)NULL,flags,
471
property->GetMaxLength());
477
void wxPGTextCtrlEditor::DrawValue( wxDC& dc, wxPGProperty* property, const wxRect& rect ) const
479
if ( !property->IsValueUnspecified() )
481
wxString drawStr = property->GetDisplayedString();
483
// Code below should no longer be needed, as the obfuscation
484
// is now done in GetValueAsString.
485
/*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
486
property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
488
size_t a = drawStr.length();
490
drawStr.Append(wxT('*'),a);
492
dc.DrawText( drawStr, rect.x+wxPG_XBEFORETEXT, rect.y );
497
void wxPGTextCtrlEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
499
wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
503
if ( tc->HasFlag(wxTE_PASSWORD) )
504
s = property->GetValueAsString(wxPG_FULL_VALUE);
506
s = property->GetDisplayedString();
512
// Provided so that, for example, ComboBox editor can use the same code
513
// (multiple inheritance would get way too messy).
514
bool wxPGTextCtrlEditor::OnTextCtrlEvent( wxPropertyGrid* propGrid,
515
wxPGProperty* WXUNUSED(property),
522
if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER )
524
if ( propGrid->IsEditorsValueModified() )
529
else if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED )
532
// Pass this event outside wxPropertyGrid so that,
533
// if necessary, program can tell when user is editing
535
// FIXME: Is it safe to change event id in the middle of event
536
// processing (seems to work, but...)?
538
event.SetId(propGrid->GetId());
540
propGrid->EditorsValueWasModified();
546
bool wxPGTextCtrlEditor::OnEvent( wxPropertyGrid* propGrid,
547
wxPGProperty* property,
549
wxEvent& event ) const
551
return wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid,property,ctrl,event);
555
bool wxPGTextCtrlEditor::GetTextCtrlValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl )
557
wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
558
wxString textVal = tc->GetValue();
560
if ( property->UsesAutoUnspecified() && !textVal.length() )
566
bool res = property->ActualStringToValue(variant, textVal, wxPG_EDITABLE_VALUE);
568
// Changing unspecified always causes event (returning
569
// true here should be enough to trigger it).
570
// TODO: Move to propgrid.cpp
571
if ( !res && variant.IsNull() )
578
bool wxPGTextCtrlEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
580
return wxPGTextCtrlEditor::GetTextCtrlValueFromControl(variant, property, ctrl);
584
void wxPGTextCtrlEditor::SetValueToUnspecified( wxPGProperty* property, wxWindow* ctrl ) const
586
wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
588
wxPropertyGrid* pg = property->GetGrid();
589
wxASSERT(pg); // Really, property grid should exist if editor does
591
tc->SetValue(wxT(""));
595
void wxPGTextCtrlEditor::SetControlStringValue( wxPGProperty* property, wxWindow* ctrl, const wxString& txt ) const
597
wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
599
wxPropertyGrid* pg = property->GetGrid();
600
wxASSERT(pg); // Really, property grid should exist if editor does
606
void wxPGTextCtrlEditor::OnFocus( wxPGProperty*, wxWindow* wnd ) const
608
wxTextCtrl* tc = wxStaticCast(wnd, wxTextCtrl);
610
tc->SetSelection(-1,-1);
614
wxPGTextCtrlEditor::~wxPGTextCtrlEditor() { }
617
// -----------------------------------------------------------------------
619
// -----------------------------------------------------------------------
622
WX_PG_IMPLEMENT_EDITOR_CLASS(Choice,wxPGChoiceEditor,wxPGEditor)
625
// This is a special enhanced double-click processor class.
626
// In essence, it allows for double-clicks for which the
627
// first click "created" the control.
628
class wxPGDoubleClickProcessor : public wxEvtHandler
632
wxPGDoubleClickProcessor( wxPGOwnerDrawnComboBox* combo )
635
m_timeLastMouseUp = 0;
637
m_downReceived = false;
642
void OnMouseEvent( wxMouseEvent& event )
644
wxLongLong t = ::wxGetLocalTimeMillis();
645
int evtType = event.GetEventType();
647
if ( m_combo->HasFlag(wxPGCC_DCLICK_CYCLES) &&
648
!m_combo->IsPopupShown() )
650
// Just check that it is in the text area
651
wxPoint pt = event.GetPosition();
652
if ( m_combo->GetTextRect().wxPGRectContains(pt) )
654
if ( evtType == wxEVT_LEFT_DOWN )
656
// Set value to avoid up-events without corresponding downs
657
m_downReceived = true;
659
else if ( evtType == wxEVT_LEFT_DCLICK )
661
// We'll make our own double-clicks
662
event.SetEventType(0);
665
else if ( evtType == wxEVT_LEFT_UP )
667
if ( m_downReceived || m_timeLastMouseUp == 1 )
669
wxLongLong timeFromLastUp = (t-m_timeLastMouseUp);
671
if ( timeFromLastUp < DOUBLE_CLICK_CONVERSION_TRESHOLD )
673
event.SetEventType(wxEVT_LEFT_DCLICK);
674
m_timeLastMouseUp = 1;
678
m_timeLastMouseUp = t;
688
void OnSetFocus( wxFocusEvent& event )
690
m_timeLastMouseUp = ::wxGetLocalTimeMillis();
695
wxLongLong m_timeLastMouseUp;
696
wxPGOwnerDrawnComboBox* m_combo;
699
DECLARE_EVENT_TABLE()
702
BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor, wxEvtHandler)
703
EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor::OnMouseEvent)
704
EVT_SET_FOCUS(wxPGDoubleClickProcessor::OnSetFocus)
709
class wxPGComboBox : public wxPGOwnerDrawnComboBox
714
: wxPGOwnerDrawnComboBox()
716
m_dclickProcessor = (wxPGDoubleClickProcessor*) NULL;
717
m_sizeEventCalled = false;
722
if ( m_dclickProcessor )
724
RemoveEventHandler(m_dclickProcessor);
725
delete m_dclickProcessor;
729
bool Create(wxWindow *parent,
731
const wxString& value,
734
const wxArrayString& choices,
736
const wxValidator& validator = wxDefaultValidator,
737
const wxString& name = wxT("wxOwnerDrawnComboBox"))
739
if ( !wxPGOwnerDrawnComboBox::Create( parent,
750
m_dclickProcessor = new wxPGDoubleClickProcessor(this);
752
PushEventHandler(m_dclickProcessor);
757
#if wxPG_USING_WXOWNERDRAWNCOMBOBOX
758
virtual void OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const
760
virtual bool OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const
763
wxPropertyGrid* pg = GetGrid();
764
pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,dc,(wxRect&)rect,flags);
765
#if !wxPG_USING_WXOWNERDRAWNCOMBOBOX
769
virtual wxCoord OnMeasureItem( size_t item ) const
771
wxPropertyGrid* pg = GetGrid();
775
pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,*((wxDC*)NULL),rect,0);
779
wxPropertyGrid* GetGrid() const
781
wxPropertyGrid* pg = wxDynamicCast(GetParent()->GetParent(),wxPropertyGrid);
786
virtual wxCoord OnMeasureItemWidth( size_t item ) const
788
wxPropertyGrid* pg = GetGrid();
792
pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,*((wxDC*)NULL),rect,0);
796
virtual void PositionTextCtrl( int WXUNUSED(textCtrlXAdjust), int WXUNUSED(textCtrlYAdjust) )
798
wxPropertyGrid* pg = GetGrid();
799
wxPGOwnerDrawnComboBox::PositionTextCtrl(
800
wxPG_TEXTCTRLXADJUST - (wxPG_XBEFOREWIDGET+wxPG_CONTROL_MARGIN+1) - 1,
801
pg->GetSpacingY() + 2
806
wxPGDoubleClickProcessor* m_dclickProcessor;
807
bool m_sizeEventCalled;
811
void wxPropertyGrid::OnComboItemPaint( wxPGCustomComboControl* pCc,
817
wxPGComboBox* pCb = (wxPGComboBox*)pCc;
820
wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid)) );
822
wxPGProperty* p = m_selected;
825
const wxPGChoices* pChoices = &p->GetChoices();
826
const wxPGCommonValue* comVal = NULL;
827
int choiceCount = p->GetChoiceCount();
828
int comVals = p->GetDisplayedCommonValueCount();
829
int comValIndex = -1;
830
if ( item >= choiceCount && comVals > 0 )
832
comValIndex = item - choiceCount;
833
comVal = GetCommonValue(comValIndex);
834
if ( !p->IsValueUnspecified() )
835
text = comVal->GetLabel();
839
if ( !(flags & wxPGCC_PAINTING_CONTROL) )
841
text = pCb->GetString(item);
845
if ( !p->IsValueUnspecified() )
846
text = p->GetValueString(0);
853
#if !wxPG_USING_WXOWNERDRAWNCOMBOBOX
854
// Add wxPGCC_PAINTING_SELECTED
855
if ( !(flags & wxPGCC_PAINTING_CONTROL) &&
856
wxDynamicCast(pCb->GetPopup()->GetControl(),wxVListBox)->GetSelection() == item )
857
flags |= wxPGCC_PAINTING_SELECTED;
862
const wxBitmap* itemBitmap = NULL;
864
if ( item >= 0 && pChoices && pChoices->Item(item).GetBitmap().Ok() && comValIndex == -1 )
865
itemBitmap = &pChoices->Item(item).GetBitmap();
868
// Decide what custom image size to use
871
cis.x = itemBitmap->GetWidth();
872
cis.y = itemBitmap->GetHeight();
876
cis = GetImageSize(p, item);
881
// Default measure behaviour (no flexible, custom paint image only)
882
if ( rect.width < 0 )
885
GetTextExtent(text, &x, &y, 0, 0, &m_font);
886
rect.width = cis.x + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2 + 9 + x;
889
rect.height = cis.y + 2;
893
wxPGPaintData paintdata;
894
paintdata.m_parent = NULL;
895
paintdata.m_choiceItem = item;
897
// This is by the current (1.0.0b) spec - if painting control, item is -1
898
if ( (flags & wxPGCC_PAINTING_CONTROL) )
899
paintdata.m_choiceItem = -1;
902
dc.SetBrush(*wxWHITE_BRUSH);
909
wxPoint pt(rect.x + wxPG_CONTROL_MARGIN - wxPG_CHOICEXADJUST - 1,
914
if ( flags & wxPGCC_PAINTING_CONTROL )
915
renderFlags |= wxPGCellRenderer::Control;
917
if ( flags & wxPGCC_PAINTING_SELECTED )
918
renderFlags |= wxPGCellRenderer::Selected;
920
if ( cis.x > 0 && (p->HasFlag(wxPG_PROP_CUSTOMIMAGE) || !(flags & wxPGCC_PAINTING_CONTROL)) &&
921
( !p->m_valueBitmap || item == pCb->GetSelection() ) &&
922
( item >= 0 || (flags & wxPGCC_PAINTING_CONTROL) ) &&
926
pt.x += wxCC_CUSTOM_IMAGE_MARGIN1;
927
wxRect r(pt.x,pt.y,cis.x,cis.y);
929
if ( flags & wxPGCC_PAINTING_CONTROL )
932
r.height = wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight);
935
paintdata.m_drawnWidth = r.width;
937
dc.SetPen(m_colPropFore);
938
if ( comValIndex >= 0 )
940
const wxPGCommonValue* cv = GetCommonValue(comValIndex);
941
wxPGCellRenderer* renderer = cv->GetRenderer();
942
r.width = rect.width;
943
renderer->Render( dc, r, this, p, m_selColumn, comValIndex, renderFlags );
946
else if ( item >= 0 )
948
p->OnCustomPaint( dc, r, paintdata );
952
dc.DrawRectangle( r );
955
pt.x += paintdata.m_drawnWidth + wxCC_CUSTOM_IMAGE_MARGIN2 - 1;
959
// TODO: This aligns text so that it seems to be horizontally
960
// on the same line as property values. Not really
961
// sure if its needed, but seems to not cause any harm.
964
if ( item < 0 && (flags & wxPGCC_PAINTING_CONTROL) )
965
item = pCb->GetSelection();
967
if ( pChoices && item >= 0 && comValIndex < 0 )
969
const wxPGChoiceEntry& cell = pChoices->Item(item);
970
wxPGCellRenderer* renderer = wxPGGlobalVars->m_defaultRenderer;
971
int imageOffset = renderer->PreDrawCell( dc, rect, cell, renderFlags );
973
imageOffset += wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2;
982
pt.y += (rect.height-m_fontHeight)/2 - 1;
986
dc.DrawText( text, pt.x + wxPG_XBEFORETEXT, pt.y );
993
p->OnCustomPaint( dc, rect, paintdata );
994
rect.height = paintdata.m_drawnHeight + 2;
995
rect.width = cis.x + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2 + 9;
999
bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid* propGrid, wxPGComboBox* cb, int cmnVal )
1001
wxPGProperty* property = propGrid->GetSelectedProperty();
1002
wxASSERT( property );
1006
// Yes, a common value is being selected
1007
property->SetCommonValue( cmnVal );
1008
wxSize imageSize = propGrid->GetCommonValue(cmnVal)->
1009
GetRenderer()->GetImageSize(property, 1, cmnVal);
1010
if ( imageSize.x ) imageSize.x += ODCB_CUST_PAINT_MARGIN;
1011
cb->SetCustomPaintWidth( imageSize.x );
1016
wxSize imageSize = propGrid->GetImageSize(property, -1);
1017
if ( imageSize.x ) imageSize.x += ODCB_CUST_PAINT_MARGIN;
1018
cb->SetCustomPaintWidth( imageSize.x );
1023
// CreateControls calls this with CB_READONLY in extraStyle
1024
wxWindow* wxPGChoiceEditor::CreateControlsBase( wxPropertyGrid* propGrid,
1025
wxPGProperty* property,
1028
long extraStyle ) const
1033
int index = property->GetChoiceInfo( NULL );
1035
bool isUnspecified = property->IsValueUnspecified();
1037
if ( isUnspecified )
1040
defString = property->GetDisplayedString();
1042
const wxPGChoices& choices = property->GetChoices();
1044
wxArrayString labels = choices.GetLabels();
1050
po.y += wxPG_CHOICEYADJUST;
1051
si.y -= (wxPG_CHOICEYADJUST*2);
1053
po.x += wxPG_CHOICEXADJUST;
1054
si.x -= wxPG_CHOICEXADJUST;
1055
wxWindow* ctrlParent = propGrid->GetPanel();
1057
int odcbFlags = extraStyle | wxNO_BORDER | wxPGCC_PROCESS_ENTER | wxPGCC_ALT_KEYS;
1059
if ( (property->GetFlags() & wxPG_PROP_USE_DCC) &&
1060
(property->IsKindOf(CLASSINFO(wxBoolProperty)) ) )
1061
odcbFlags |= wxPGCC_DCLICK_CYCLES;
1064
// If common value specified, use appropriate index
1065
unsigned int cmnVals = property->GetDisplayedCommonValueCount();
1068
if ( !isUnspecified )
1070
int cmnVal = property->GetCommonValue();
1073
index = labels.size() + cmnVal;
1078
for ( i=0; i<cmnVals; i++ )
1079
labels.Add(propGrid->GetCommonValueLabel(i));
1082
cb = new wxPGComboBox();
1086
cb->Create(ctrlParent,
1094
//int extRight = propGrid->GetClientSize().x - (po.x+si.x);
1095
//int extRight = - (po.x+si.x);
1097
cb->SetButtonPosition(si.y,0,wxRIGHT);
1098
//cb->SetPopupExtents( 1, extRight );
1099
cb->SetTextIndent(wxPG_XBEFORETEXT-1);
1101
wxPGChoiceEditor_SetCustomPaintWidth( propGrid, cb, property->GetCommonValue() );
1102
/*if ( property->GetFlags() & wxPG_PROP_CUSTOMIMAGE )
1104
wxSize imageSize = propGrid->GetImageSize(property, index);
1105
if ( imageSize.x ) imageSize.x += ODCB_CUST_PAINT_MARGIN;
1106
cb->SetCustomPaintWidth( imageSize.x );
1109
if ( index >= 0 && index < (int)cb->GetCount() )
1111
cb->SetSelection( index );
1112
if ( defString.length() )
1113
cb->SetText( defString );
1115
else if ( !(extraStyle & wxCB_READONLY) && defString.length() )
1116
cb->SetValue( defString );
1118
cb->SetSelection( -1 );
1124
return (wxWindow*) cb;
1128
void wxPGChoiceEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
1131
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1132
wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
1133
int ind = property->GetChoiceInfo( (wxPGChoiceInfo*)NULL );
1134
cb->SetSelection(ind);
1137
wxPGWindowList wxPGChoiceEditor::CreateControls( wxPropertyGrid* propGrid, wxPGProperty* property,
1138
const wxPoint& pos, const wxSize& sz ) const
1140
return CreateControlsBase(propGrid,property,pos,sz,wxCB_READONLY);
1144
int wxPGChoiceEditor::InsertItem( wxWindow* ctrl, const wxString& label, int index ) const
1147
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1148
wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
1151
index = cb->GetCount();
1153
return cb->Insert(label,index);
1157
void wxPGChoiceEditor::DeleteItem( wxWindow* ctrl, int index ) const
1160
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1161
wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
1166
bool wxPGChoiceEditor::OnEvent( wxPropertyGrid* propGrid, wxPGProperty* property,
1167
wxWindow* ctrl, wxEvent& event ) const
1169
if ( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED )
1171
wxPGComboBox* cb = (wxPGComboBox*)ctrl;
1172
int index = cb->GetSelection();
1173
int cmnValIndex = -1;
1174
int cmnVals = property->GetDisplayedCommonValueCount();
1175
int items = cb->GetCount();
1177
if ( index >= (items-cmnVals) )
1179
// Yes, a common value is being selected
1180
cmnValIndex = index - (items-cmnVals);
1181
property->SetCommonValue( cmnValIndex );
1183
// Truly set value to unspecified?
1184
if ( propGrid->GetUnspecifiedCommonValue() == cmnValIndex )
1186
if ( !property->IsValueUnspecified() )
1187
propGrid->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT);
1188
property->SetValueToUnspecified();
1189
if ( !cb->HasFlag(wxCB_READONLY) )
1190
cb->GetTextCtrl()->SetValue(wxEmptyString);
1194
return wxPGChoiceEditor_SetCustomPaintWidth( propGrid, cb, cmnValIndex );
1200
bool wxPGChoiceEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1202
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1204
int index = cb->GetSelection();
1206
if ( index != property->GetChoiceInfo( (wxPGChoiceInfo*) NULL ) ||
1207
// Changing unspecified always causes event (returning
1208
// true here should be enough to trigger it).
1209
property->IsValueUnspecified()
1212
return property->ActualIntToValue( variant, index, 0 );
1218
void wxPGChoiceEditor::SetControlStringValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, const wxString& txt ) const
1220
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1226
void wxPGChoiceEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, int value ) const
1228
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1230
cb->SetSelection(value);
1234
void wxPGChoiceEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* ctrl ) const
1236
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1237
cb->SetSelection(-1);
1241
bool wxPGChoiceEditor::CanContainCustomImage() const
1247
wxPGChoiceEditor::~wxPGChoiceEditor() { }
1250
// -----------------------------------------------------------------------
1251
// wxPGComboBoxEditor
1252
// -----------------------------------------------------------------------
1255
WX_PG_IMPLEMENT_EDITOR_CLASS(ComboBox,wxPGComboBoxEditor,wxPGChoiceEditor)
1258
void wxPGComboBoxEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
1260
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1261
cb->SetValue(property->GetValueString(wxPG_EDITABLE_VALUE));
1263
// TODO: If string matches any selection, then select that.
1267
wxPGWindowList wxPGComboBoxEditor::CreateControls( wxPropertyGrid* propGrid,
1268
wxPGProperty* property,
1270
const wxSize& sz ) const
1272
return CreateControlsBase(propGrid,property,pos,sz,0);
1276
bool wxPGComboBoxEditor::OnEvent( wxPropertyGrid* propGrid,
1277
wxPGProperty* property,
1279
wxEvent& event ) const
1281
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*) NULL;
1282
wxWindow* textCtrl = (wxWindow*) NULL;
1286
cb = (wxPGOwnerDrawnComboBox*)ctrl;
1287
textCtrl = cb->GetTextCtrl();
1290
if ( wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid,property,textCtrl,event) )
1293
return wxPGChoiceEditor::OnEvent(propGrid,property,ctrl,event);
1297
bool wxPGComboBoxEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1299
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1300
wxString textVal = cb->GetValue();
1302
if ( property->UsesAutoUnspecified() && !textVal.length() )
1308
bool res = property->ActualStringToValue(variant, textVal, wxPG_EDITABLE_VALUE);
1310
// Changing unspecified always causes event (returning
1311
// true here should be enough to trigger it).
1312
if ( !res && variant.IsNull() )
1319
void wxPGComboBoxEditor::OnFocus( wxPGProperty*, wxWindow* ctrl ) const
1321
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1322
cb->GetTextCtrl()->SetSelection(-1,-1);
1326
wxPGComboBoxEditor::~wxPGComboBoxEditor() { }
1329
// -----------------------------------------------------------------------
1330
// wxPGChoiceAndButtonEditor
1331
// -----------------------------------------------------------------------
1334
// This simpler implement_editor macro doesn't define class body.
1335
WX_PG_IMPLEMENT_EDITOR_CLASS(ChoiceAndButton,wxPGChoiceAndButtonEditor,wxPGChoiceEditor)
1338
wxPGWindowList wxPGChoiceAndButtonEditor::CreateControls( wxPropertyGrid* propGrid,
1339
wxPGProperty* property,
1341
const wxSize& sz ) const
1343
// Use one two units smaller to match size of the combo's dropbutton.
1344
// (normally a bigger button is used because it looks better)
1347
wxSize bt_sz(bt_wid,bt_wid);
1349
// Position of button.
1350
wxPoint bt_pos(pos.x+sz.x-bt_sz.x,pos.y);
1357
wxWindow* bt = propGrid->GenerateEditorButton( bt_pos, bt_sz );
1360
wxSize ch_sz(sz.x-bt->GetSize().x,sz.y);
1363
ch_sz.x -= wxPG_TEXTCTRL_AND_BUTTON_SPACING;
1366
wxWindow* ch = wxPG_EDITOR(Choice)->CreateControls(propGrid,property,
1367
pos,ch_sz).m_primary;
1373
return wxPGWindowList(ch, bt);
1377
wxPGChoiceAndButtonEditor::~wxPGChoiceAndButtonEditor() { }
1380
// -----------------------------------------------------------------------
1381
// wxPGTextCtrlAndButtonEditor
1382
// -----------------------------------------------------------------------
1385
// This simpler implement_editor macro doesn't define class body.
1386
WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrlAndButton,wxPGTextCtrlAndButtonEditor,wxPGTextCtrlEditor)
1389
wxPGWindowList wxPGTextCtrlAndButtonEditor::CreateControls( wxPropertyGrid* propGrid,
1390
wxPGProperty* property,
1392
const wxSize& sz ) const
1395
wxWindow* wnd = propGrid->GenerateEditorTextCtrlAndButton( pos, sz, &wnd2,
1396
property->GetFlags() & wxPG_PROP_NOEDITOR, property);
1398
return wxPGWindowList(wnd, wnd2);
1402
wxPGTextCtrlAndButtonEditor::~wxPGTextCtrlAndButtonEditor() { }
1405
// -----------------------------------------------------------------------
1406
// wxPGCheckBoxEditor
1407
// -----------------------------------------------------------------------
1409
#if wxPG_INCLUDE_CHECKBOX
1411
WX_PG_IMPLEMENT_EDITOR_CLASS(CheckBox,wxPGCheckBoxEditor,wxPGEditor)
1414
// state argument: 0x01 = set if checked
1415
// 0x02 = set if rectangle should be bold
1416
static void DrawSimpleCheckBox( wxDC& dc, const wxRect& rect, int box_hei, int state, const wxColour& linecol )
1420
wxRect r(rect.x+wxPG_XBEFORETEXT,rect.y+((rect.height-box_hei)/2),box_hei,box_hei);
1422
// Draw check mark first because it is likely to overdraw the
1423
// surrounding rectangle.
1426
wxRect r2(r.x+wxPG_CHECKMARK_XADJ,
1427
r.y+wxPG_CHECKMARK_YADJ,
1428
r.width+wxPG_CHECKMARK_WADJ,
1429
r.height+wxPG_CHECKMARK_HADJ);
1430
#if wxPG_CHECKMARK_DEFLATE
1431
r2.Deflate(wxPG_CHECKMARK_DEFLATE);
1433
dc.DrawCheckMark(r2);
1435
// This would draw a simple cross check mark.
1436
// dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
1437
// dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
1443
// Pen for thin rectangle.
1448
// Pen for bold rectangle.
1449
wxPen linepen(linecol,2,wxSOLID);
1450
linepen.SetJoin(wxJOIN_MITER); // This prevents round edges.
1458
dc.SetBrush(*wxTRANSPARENT_BRUSH);
1460
dc.DrawRectangle(r);
1461
dc.SetPen(*wxTRANSPARENT_PEN);
1465
// Real simple custom-drawn checkbox-without-label class.
1467
class wxSimpleCheckBox : public wxControl
1471
void SetValue( int value );
1473
wxSimpleCheckBox( wxWindow* parent,
1475
const wxPoint& pos = wxDefaultPosition,
1476
const wxSize& size = wxDefaultSize )
1477
: wxControl(parent,id,pos,size,wxNO_BORDER|wxWANTS_CHARS)
1479
// Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
1480
SetFont( parent->GetFont() );
1483
wxPropertyGrid* pg = (wxPropertyGrid*) parent->GetParent();
1484
wxASSERT( pg->IsKindOf(CLASSINFO(wxPropertyGrid)) );
1485
m_boxHeight = pg->GetFontHeight();
1486
SetBackgroundStyle( wxBG_STYLE_COLOUR );
1489
virtual ~wxSimpleCheckBox();
1491
virtual bool ProcessEvent(wxEvent& event);
1496
static wxBitmap* ms_doubleBuffer;
1500
wxSimpleCheckBox::~wxSimpleCheckBox()
1502
delete ms_doubleBuffer;
1503
ms_doubleBuffer = NULL;
1507
wxBitmap* wxSimpleCheckBox::ms_doubleBuffer = (wxBitmap*) NULL;
1509
// value = 2 means toggle (sorry, too lazy to do constants)
1510
void wxSimpleCheckBox::SetValue( int value )
1515
if ( m_state > 1 ) m_state = 0;
1523
wxCommandEvent evt(wxEVT_COMMAND_CHECKBOX_CLICKED,GetParent()->GetId());
1525
wxPropertyGrid* propGrid = (wxPropertyGrid*) GetParent()->GetParent();
1526
wxASSERT( propGrid->IsKindOf(CLASSINFO(wxPropertyGrid)) );
1527
propGrid->OnCustomEditorEvent(evt);
1531
bool wxSimpleCheckBox::ProcessEvent(wxEvent& event)
1533
wxPropertyGrid* propGrid = (wxPropertyGrid*) GetParent()->GetParent();
1534
wxASSERT( propGrid->IsKindOf(CLASSINFO(wxPropertyGrid)) );
1536
if ( event.GetEventType() == wxEVT_NAVIGATION_KEY )
1538
//wxLogDebug(wxT("wxEVT_NAVIGATION_KEY"));
1539
//SetFocusFromKbd();
1541
//return wxControl::ProcessEvent(event);
1544
if ( ( (event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_LEFT_DCLICK)
1545
&& ((wxMouseEvent&)event).m_x > (wxPG_XBEFORETEXT-2)
1546
&& ((wxMouseEvent&)event).m_x <= (wxPG_XBEFORETEXT-2+m_boxHeight) )
1552
else if ( event.GetEventType() == wxEVT_PAINT )
1554
wxSize clientSize = GetClientSize();
1558
// Buffered paint DC doesn't seem to do much good
1559
if ( !ms_doubleBuffer ||
1560
clientSize.x > ms_doubleBuffer->GetWidth() ||
1561
clientSize.y > ms_doubleBuffer->GetHeight() )
1563
delete ms_doubleBuffer;
1564
ms_doubleBuffer = new wxBitmap(clientSize.x+25,clientSize.y+25);
1567
wxBufferedPaintDC dc(this,*ms_doubleBuffer);
1570
wxRect rect(0,0,clientSize.x,clientSize.y);
1575
m_boxHeight = propGrid->GetFontHeight();
1577
wxColour bgcol = GetBackgroundColour();
1578
dc.SetBrush( bgcol );
1580
dc.DrawRectangle( rect );
1582
wxColour txcol = GetForegroundColour();
1584
int state = m_state;
1585
if ( m_font.GetWeight() == wxBOLD )
1588
DrawSimpleCheckBox(dc,rect,m_boxHeight,state,txcol);
1590
// If focused, indicate it somehow.
1592
if ( wxWindow::FindFocus() == this )
1597
wxPGDrawFocusRect(dc,rect);
1603
else if ( event.GetEventType() == wxEVT_SIZE ||
1604
event.GetEventType() == wxEVT_SET_FOCUS ||
1605
event.GetEventType() == wxEVT_KILL_FOCUS
1610
else if ( event.GetEventType() == wxEVT_KEY_DOWN )
1612
wxKeyEvent& keyEv = (wxKeyEvent&) event;
1614
if ( keyEv.GetKeyCode() == WXK_TAB )
1616
propGrid->SendNavigationKeyEvent( keyEv.ShiftDown()?0:1 );
1620
if ( keyEv.GetKeyCode() == WXK_SPACE )
1626
return wxControl::ProcessEvent(event);
1630
wxPGWindowList wxPGCheckBoxEditor::CreateControls( wxPropertyGrid* propGrid,
1631
wxPGProperty* property,
1633
const wxSize& size ) const
1636
pt.x -= wxPG_XBEFOREWIDGET;
1638
sz.x = propGrid->GetFontHeight() + (wxPG_XBEFOREWIDGET*2) + 4;
1640
wxSimpleCheckBox* cb = new wxSimpleCheckBox(propGrid->GetPanel(),wxPG_SUBID1,pt,sz);
1642
cb->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
1644
cb->Connect( wxPG_SUBID1, wxEVT_LEFT_DOWN,
1645
(wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
1646
&wxPropertyGrid::OnCustomEditorEvent, NULL, propGrid );
1648
cb->Connect( wxPG_SUBID1, wxEVT_LEFT_DCLICK,
1649
(wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
1650
&wxPropertyGrid::OnCustomEditorEvent, NULL, propGrid );
1652
if ( property->GetChoiceInfo((wxPGChoiceInfo*)NULL) &&
1653
!property->IsValueUnspecified() )
1656
// If mouse cursor was on the item, toggle the value now.
1657
if ( propGrid->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK )
1659
wxPoint pt = cb->ScreenToClient(::wxGetMousePosition());
1660
if ( pt.x <= (wxPG_XBEFORETEXT-2+cb->m_boxHeight) )
1664
if ( cb->m_state > 1 )
1667
// Makes sure wxPG_EVT_CHANGING etc. is sent for this initial click
1668
propGrid->ChangePropertyValue(property, wxPGVariant_Bool(cb->m_state));
1672
propGrid->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR );
1678
class wxPGCheckBoxRenderer : public wxPGDefaultRenderer
1682
virtual void Render( wxDC& dc, const wxRect& rect,
1683
const wxPropertyGrid* WXUNUSED(propertyGrid), wxPGProperty* property,
1684
int WXUNUSED(column), int WXUNUSED(item), int WXUNUSED(flags) ) const
1687
if ( !(property->GetFlags() & wxPG_PROP_UNSPECIFIED) )
1689
state = ((wxPGProperty*)property)->GetChoiceInfo((wxPGChoiceInfo*)NULL);
1690
if ( dc.GetFont().GetWeight() == wxBOLD ) state |= 2;
1692
DrawSimpleCheckBox(dc,rect,dc.GetCharHeight(),state,dc.GetTextForeground());
1698
wxPGCheckBoxRenderer g_wxPGCheckBoxRenderer;
1700
wxPGCellRenderer* wxPGCheckBoxEditor::GetCellRenderer() const
1702
return &g_wxPGCheckBoxRenderer;
1706
void wxPGCheckBoxEditor::DrawValue( wxDC& dc, const wxRect& rect, wxPGProperty* property, const wxString& WXUNUSED(text) ) const
1709
if ( !property->IsValueUnspecified() )
1711
state = property->GetChoiceInfo((wxPGChoiceInfo*)NULL);
1712
if ( dc.GetFont().GetWeight() == wxBOLD ) state |= 2;
1714
DrawSimpleCheckBox(dc,rect,dc.GetCharHeight(),state,dc.GetTextForeground());
1717
void wxPGCheckBoxEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
1720
((wxSimpleCheckBox*)ctrl)->m_state = property->GetChoiceInfo((wxPGChoiceInfo*)NULL);
1725
bool wxPGCheckBoxEditor::OnEvent( wxPropertyGrid* WXUNUSED(propGrid), wxPGProperty* WXUNUSED(property),
1726
wxWindow* WXUNUSED(ctrl), wxEvent& event ) const
1728
if ( event.GetEventType() == wxEVT_COMMAND_CHECKBOX_CLICKED )
1736
bool wxPGCheckBoxEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1738
wxSimpleCheckBox* cb = (wxSimpleCheckBox*)ctrl;
1740
int index = cb->m_state;
1742
if ( index != property->GetChoiceInfo( (wxPGChoiceInfo*) NULL ) ||
1743
// Changing unspecified always causes event (returning
1744
// true here should be enough to trigger it).
1745
property->IsValueUnspecified()
1748
return property->ActualIntToValue(variant, index, 0);
1754
void wxPGCheckBoxEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, int value ) const
1756
if ( value != 0 ) value = 1;
1757
((wxSimpleCheckBox*)ctrl)->m_state = value;
1762
void wxPGCheckBoxEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* ctrl ) const
1764
((wxSimpleCheckBox*)ctrl)->m_state = 0;
1769
wxPGCheckBoxEditor::~wxPGCheckBoxEditor() { }
1772
#endif // wxPG_INCLUDE_CHECKBOX
1774
// -----------------------------------------------------------------------
1776
wxWindow* wxPropertyGrid::GetEditorControl() const
1778
wxWindow* ctrl = m_wndEditor;
1783
// If it's clipper window, return its child instead
1784
#if wxPG_ENABLE_CLIPPER_WINDOW
1785
if ( ctrl->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
1787
return ((wxPGClipperWindow*)ctrl)->GetControl();
1794
// -----------------------------------------------------------------------
1796
void wxPropertyGrid::CorrectEditorWidgetSizeX()
1798
if ( m_selColumn == -1 )
1802
int newSplitterx = m_pState->DoGetSplitterPosition(m_selColumn-1);
1803
int newWidth = newSplitterx + m_pState->m_colWidths[m_selColumn];
1807
// if width change occurred, move secondary wnd by that amount
1808
wxRect r = m_wndEditor2->GetRect();
1810
r.x = newWidth - secWid;
1812
m_wndEditor2->SetSize( r );
1814
// if primary is textctrl, then we have to add some extra space
1818
if ( m_wndEditor && m_wndEditor->IsKindOf(CLASSINFO(wxTextCtrl)) )
1820
secWid += wxPG_TEXTCTRL_AND_BUTTON_SPACING;
1825
wxRect r = m_wndEditor->GetRect();
1827
r.x = newSplitterx+m_ctrlXAdjust;
1829
if ( !(m_iFlags & wxPG_FL_FIXED_WIDTH_EDITOR) )
1830
r.width = newWidth - r.x - secWid;
1832
m_wndEditor->SetSize(r);
1836
m_wndEditor2->Refresh();
1839
// -----------------------------------------------------------------------
1841
void wxPropertyGrid::CorrectEditorWidgetPosY()
1843
if ( m_selected && (m_wndEditor || m_wndEditor2) )
1845
wxRect r = GetEditorWidgetRect(m_selected, m_selColumn);
1849
wxPoint pos = m_wndEditor->GetPosition();
1851
// Calculate y offset
1852
int offset = pos.y % m_lineHeight;
1854
m_wndEditor->Move(pos.x, r.y + offset);
1859
wxPoint pos = m_wndEditor2->GetPosition();
1861
m_wndEditor2->Move(pos.x, r.y);
1866
// -----------------------------------------------------------------------
1868
bool wxPropertyGrid::AdjustPosForClipperWindow( wxWindow* topCtrlWnd, int* x, int* y )
1870
#if wxPG_ENABLE_CLIPPER_WINDOW
1871
// Take clipper window into account
1872
if (topCtrlWnd->GetPosition().x < 1 &&
1873
!topCtrlWnd->IsKindOf(CLASSINFO(wxPGClipperWindow)))
1875
topCtrlWnd = topCtrlWnd->GetParent();
1876
wxASSERT( topCtrlWnd->IsKindOf(CLASSINFO(wxPGClipperWindow)) );
1877
*x -= ((wxPGClipperWindow*)topCtrlWnd)->GetXClip();
1878
*y -= ((wxPGClipperWindow*)topCtrlWnd)->GetYClip();
1882
wxUnusedVar(topCtrlWnd);
1889
// -----------------------------------------------------------------------
1891
// Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
1892
// fits into that category as well).
1893
void wxPropertyGrid::FixPosForTextCtrl( wxWindow* ctrl, const wxPoint& offset )
1895
// Center the control vertically
1896
wxRect finalPos = ctrl->GetRect();
1897
int y_adj = (m_lineHeight - finalPos.height)/2 + wxPG_TEXTCTRLYADJUST;
1899
// Prevent over-sized control
1900
int sz_dec = (y_adj + finalPos.height) - m_lineHeight;
1901
if ( sz_dec < 0 ) sz_dec = 0;
1903
finalPos.y += y_adj;
1904
finalPos.height -= (y_adj+sz_dec);
1906
const int textCtrlXAdjust = wxPG_TEXTCTRLXADJUST;
1908
finalPos.x += textCtrlXAdjust;
1909
finalPos.width -= textCtrlXAdjust;
1911
finalPos.x += offset.x;
1912
finalPos.y += offset.y;
1914
ctrl->SetSize(finalPos);
1917
// -----------------------------------------------------------------------
1919
wxWindow* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint& pos,
1921
const wxString& value,
1922
wxWindow* secondary,
1926
wxPGProperty* selected = m_selected;
1929
int tcFlags = wxTE_PROCESS_ENTER | extraStyle;
1931
if ( selected->HasFlag(wxPG_PROP_READONLY) )
1932
tcFlags |= wxTE_READONLY;
1934
wxPoint p(pos.x,pos.y);
1935
wxSize s(sz.x,sz.y);
1937
// Need to reduce width of text control on Mac
1938
#if defined(__WXMAC__)
1942
// Take button into acccount
1945
s.x -= (secondary->GetSize().x + wxPG_TEXTCTRL_AND_BUTTON_SPACING);
1946
m_iFlags &= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE);
1949
// If the height is significantly higher, then use border, and fill the rect exactly.
1950
bool hasSpecialSize = false;
1952
if ( (sz.y - m_lineHeight) > 5 )
1953
hasSpecialSize = true;
1955
#if wxPG_NAT_TEXTCTRL_BORDER_ANY
1957
// Create clipper window
1958
wxPGClipperWindow* wnd = new wxPGClipperWindow();
1959
#if defined(__WXMSW__)
1962
wnd->Create(GetPanel(),wxPG_SUBID1,p,s);
1964
// This generates rect of the control inside the clipper window
1965
if ( !hasSpecialSize )
1966
wnd->GetControlRect(wxPG_NAT_TEXTCTRL_BORDER_X, wxPG_NAT_TEXTCTRL_BORDER_Y, p, s);
1968
wnd->GetControlRect(0, 0, p, s);
1970
wxWindow* ctrlParent = wnd;
1974
wxWindow* ctrlParent = GetPanel();
1976
if ( !hasSpecialSize )
1977
tcFlags |= wxNO_BORDER;
1981
wxTextCtrl* tc = new wxTextCtrl();
1983
#if defined(__WXMSW__) && !wxPG_NAT_TEXTCTRL_BORDER_ANY
1986
SetupTextCtrlValue(value);
1987
tc->Create(ctrlParent,wxPG_SUBID1,value, p, s,tcFlags);
1989
#if wxPG_NAT_TEXTCTRL_BORDER_ANY
1991
wnd->SetControl(tc);
1996
// Center the control vertically
1997
if ( !hasSpecialSize )
1998
FixPosForTextCtrl(ed);
2006
// Set maximum length
2008
tc->SetMaxLength( maxLen );
2010
return (wxWindow*) ed;
2013
// -----------------------------------------------------------------------
2015
wxWindow* wxPropertyGrid::GenerateEditorButton( const wxPoint& pos, const wxSize& sz )
2017
wxPGProperty* selected = m_selected;
2021
// Decorations are chunky on Mac, and we can't make the button square, so
2022
// do things a bit differently on this platform.
2024
wxPoint p(pos.x+sz.x,
2025
pos.y+wxPG_BUTTON_SIZEDEC-wxPG_NAT_BUTTON_BORDER_Y);
2028
wxButton* but = new wxButton();
2029
but->Create(GetPanel(),wxPG_SUBID2,wxT("..."),p,s,wxWANTS_CHARS);
2031
// Now that we know the size, move to the correct position
2032
p.x = pos.x + sz.x - but->GetSize().x - 2;
2036
wxSize s(sz.y-(wxPG_BUTTON_SIZEDEC*2)+(wxPG_NAT_BUTTON_BORDER_Y*2),
2037
sz.y-(wxPG_BUTTON_SIZEDEC*2)+(wxPG_NAT_BUTTON_BORDER_Y*2));
2039
// Reduce button width to lineheight
2040
if ( s.x > m_lineHeight )
2044
// On wxGTK, take fixed button margins into account
2049
wxPoint p(pos.x+sz.x-s.x,
2050
pos.y+wxPG_BUTTON_SIZEDEC-wxPG_NAT_BUTTON_BORDER_Y);
2052
wxButton* but = new wxButton();
2056
but->Create(GetPanel(),wxPG_SUBID2,wxT("..."),p,s,wxWANTS_CHARS);
2059
wxFont font = GetFont();
2060
font.SetPointSize(font.GetPointSize()-2);
2063
but->SetFont(GetFont());
2067
if ( selected->HasFlag(wxPG_PROP_READONLY) )
2073
// -----------------------------------------------------------------------
2075
wxWindow* wxPropertyGrid::GenerateEditorTextCtrlAndButton( const wxPoint& pos,
2077
wxWindow** psecondary,
2079
wxPGProperty* property )
2081
wxButton* but = (wxButton*)GenerateEditorButton(pos,sz);
2082
*psecondary = (wxWindow*)but;
2084
if ( limitedEditing )
2087
// There is button Show in GenerateEditorTextCtrl as well
2090
return (wxWindow*) NULL;
2095
if ( !property->IsValueUnspecified() )
2096
text = property->GetValueString(property->HasFlag(wxPG_PROP_READONLY)?0:wxPG_EDITABLE_VALUE);
2098
return GenerateEditorTextCtrl(pos,sz,text,but,property->m_maxLen);
2101
// -----------------------------------------------------------------------
2103
wxTextCtrl* wxPropertyGrid::GetEditorTextCtrl() const
2105
wxWindow* wnd = GetEditorControl();
2110
if ( wnd->IsKindOf(CLASSINFO(wxTextCtrl)) )
2111
return wxStaticCast(wnd, wxTextCtrl);
2113
if ( wnd->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)) )
2115
wxPGOwnerDrawnComboBox* cb = wxStaticCast(wnd, wxPGOwnerDrawnComboBox);
2116
return cb->GetTextCtrl();
2122
// -----------------------------------------------------------------------
2123
// wxPGEditorDialogAdapter
2124
// -----------------------------------------------------------------------
2126
IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter, wxObject)
2128
bool wxPGEditorDialogAdapter::ShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
2130
if ( !propGrid->EditorValidate() )
2133
bool res = DoShowDialog( propGrid, property );
2137
propGrid->ValueChangeInEvent( m_value );
2144
// -----------------------------------------------------------------------
2146
// -----------------------------------------------------------------------
2148
wxPGMultiButton::wxPGMultiButton( wxPropertyGrid* pg, const wxSize& sz )
2149
: wxWindow( pg->GetPanel(), wxPG_SUBID2, wxPoint(-100,-100), wxSize(0, sz.y) ),
2150
m_fullEditorSize(sz), m_buttonsWidth(0)
2152
SetBackgroundColour(pg->GetCellBackgroundColour());
2155
int wxPGMultiButton::GenId( int id ) const
2159
if ( m_buttons.size() )
2160
id = GetButton(m_buttons.size()-1)->GetId() + 1;
2168
void wxPGMultiButton::Add( const wxBitmap& bitmap, int id )
2171
wxSize sz = GetSize();
2172
wxButton* button = new wxBitmapButton( this, id, bitmap, wxPoint(sz.x, 0), wxSize(sz.y, sz.y) );
2173
m_buttons.push_back(button);
2174
int bw = button->GetSize().x;
2175
SetSize(wxSize(sz.x+bw,sz.y));
2176
m_buttonsWidth += bw;
2180
void wxPGMultiButton::Add( const wxString& label, int id )
2183
wxSize sz = GetSize();
2184
wxButton* button = new wxButton( this, id, label, wxPoint(sz.x, 0), wxSize(sz.y, sz.y) );
2185
m_buttons.push_back(button);
2186
int bw = button->GetSize().x;
2187
SetSize(wxSize(sz.x+bw,sz.y));
2188
m_buttonsWidth += bw;
2191
// -----------------------------------------------------------------------