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
// Backported from wx2.9 by Julian Smart (old value was 8)
77
#define wxPG_TEXTCTRL_AND_BUTTON_SPACING 4
79
#define wxPG_TEXTCTRL_AND_BUTTON_SPACING 2
82
#define wxPG_BUTTON_SIZEDEC 0
84
#if wxPG_USING_WXOWNERDRAWNCOMBOBOX
85
#include <wx/odcombo.h>
87
#include <wx/propgrid/odcombo.h>
91
#include <wx/msw/private.h>
94
// -----------------------------------------------------------------------
96
#if defined(__WXMSW__)
98
#define wxPG_NAT_TEXTCTRL_BORDER_X 0 // Unremovable border of native textctrl.
99
#define wxPG_NAT_TEXTCTRL_BORDER_Y 0 // Unremovable border of native textctrl.
101
#define wxPG_NAT_BUTTON_BORDER_ANY 1
102
#define wxPG_NAT_BUTTON_BORDER_X 1
103
#define wxPG_NAT_BUTTON_BORDER_Y 1
105
#define wxPG_CHECKMARK_XADJ 1
106
#define wxPG_CHECKMARK_YADJ (-1)
107
#define wxPG_CHECKMARK_WADJ 0
108
#define wxPG_CHECKMARK_HADJ 0
109
#define wxPG_CHECKMARK_DEFLATE 0
111
#define wxPG_TEXTCTRLYADJUST (m_spacingy+0)
113
#elif defined(__WXGTK__)
115
#define wxPG_CHECKMARK_XADJ 0
116
#define wxPG_CHECKMARK_YADJ 0
117
#define wxPG_CHECKMARK_WADJ (-1)
118
#define wxPG_CHECKMARK_HADJ (-1)
119
#define wxPG_CHECKMARK_DEFLATE 3
121
#define wxPG_NAT_TEXTCTRL_BORDER_X 3 // Unremovable border of native textctrl.
122
#define wxPG_NAT_TEXTCTRL_BORDER_Y 3 // Unremovable border of native textctrl.
124
#define wxPG_NAT_BUTTON_BORDER_ANY 1
125
#define wxPG_NAT_BUTTON_BORDER_X 1
126
#define wxPG_NAT_BUTTON_BORDER_Y 1
128
#define wxPG_TEXTCTRLYADJUST 0
130
#elif defined(__WXMAC__)
132
#define wxPG_CHECKMARK_XADJ 0
133
#define wxPG_CHECKMARK_YADJ 0
134
#define wxPG_CHECKMARK_WADJ 0
135
#define wxPG_CHECKMARK_HADJ 0
136
#define wxPG_CHECKMARK_DEFLATE 0
138
#define wxPG_NAT_TEXTCTRL_BORDER_X 0 // Unremovable border of native textctrl.
139
#define wxPG_NAT_TEXTCTRL_BORDER_Y 0 // Unremovable border of native textctrl.
141
#define wxPG_NAT_BUTTON_BORDER_ANY 0
142
#define wxPG_NAT_BUTTON_BORDER_X 0
143
#define wxPG_NAT_BUTTON_BORDER_Y 0
145
// Backported from wx2.9 by Julian Smart (old value was 3)
146
#define wxPG_TEXTCTRLYADJUST 0
150
#define wxPG_CHECKMARK_XADJ 0
151
#define wxPG_CHECKMARK_YADJ 0
152
#define wxPG_CHECKMARK_WADJ 0
153
#define wxPG_CHECKMARK_HADJ 0
154
#define wxPG_CHECKMARK_DEFLATE 0
156
#define wxPG_NAT_TEXTCTRL_BORDER_X 0 // Unremovable border of native textctrl.
157
#define wxPG_NAT_TEXTCTRL_BORDER_Y 0 // Unremovable border of native textctrl.
159
#define wxPG_NAT_BUTTON_BORDER_ANY 0
160
#define wxPG_NAT_BUTTON_BORDER_X 0
161
#define wxPG_NAT_BUTTON_BORDER_Y 0
163
#define wxPG_TEXTCTRLYADJUST 0
167
#if (!wxPG_NAT_TEXTCTRL_BORDER_X && !wxPG_NAT_TEXTCTRL_BORDER_Y)
168
#define wxPG_ENABLE_CLIPPER_WINDOW 0
170
#define wxPG_ENABLE_CLIPPER_WINDOW 1
176
// Backported from wx2.9 by Julian Smart
177
// required because wxComboCtrl reserves 3pixels for wxTextCtrl's
179
#define wxPG_CHOICEXADJUST -3
180
#define wxPG_CHOICEYADJUST -3
182
#define wxPG_CHOICEXADJUST 0
183
#define wxPG_CHOICEYADJUST 0
187
// Number added to image width for SetCustomPaintWidth
188
// NOTE: Use different custom paint margin because of better textctrl spacing
189
#define ODCB_CUST_PAINT_MARGIN_RO 6
190
#define ODCB_CUST_PAINT_MARGIN 8
192
// Milliseconds to wait for two mouse-ups after focus inorder
193
// to trigger a double-click.
194
#define DOUBLE_CLICK_CONVERSION_TRESHOLD 500
196
// -----------------------------------------------------------------------
198
// -----------------------------------------------------------------------
200
IMPLEMENT_ABSTRACT_CLASS(wxPGEditor, wxObject)
202
wxPGEditor::~wxPGEditor()
207
/*wxPGCellRenderer* wxPGEditor::GetCellRenderer() const
209
return &g_wxPGDefaultRenderer;
212
void wxPGEditor::DrawValue( wxDC& dc, const wxRect& rect, wxPGProperty* property, const wxString& text ) const
214
if ( !property->IsValueUnspecified() )
215
dc.DrawText( text, rect.x+wxPG_XBEFORETEXT, rect.y );
219
bool wxPGEditor::GetValueFromControl( wxVariant&, wxPGProperty*, wxWindow* ) const
224
wxPGVariantAndBool wxPGEditor::PyGetValueFromControl( wxPGProperty* property, wxWindow* ctrl ) const
226
wxPGVariantAndBool vab;
227
vab.m_result = GetValueFromControl(vab.m_value, property, ctrl);
229
vab.m_valueValid = true;
234
void wxPGEditor::SetControlStringValue( wxPGProperty* WXUNUSED(property), wxWindow*, const wxString& ) const
239
void wxPGEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow*, int ) const
244
int wxPGEditor::InsertItem( wxWindow*, const wxString&, int ) const
250
void wxPGEditor::DeleteItem( wxWindow*, int ) const
256
void wxPGEditor::OnFocus( wxPGProperty*, wxWindow* ) const
261
bool wxPGEditor::CanContainCustomImage() const
266
// -----------------------------------------------------------------------
268
// -----------------------------------------------------------------------
270
#if wxPG_ENABLE_CLIPPER_WINDOW
273
// Clipper window is used to "remove" borders from controls
274
// which otherwise insist on having them despite of supplied
275
// wxNO_BORDER window style.
277
class wxPGClipperWindow : public wxWindow
279
DECLARE_CLASS(wxPGClipperWindow)
285
wxPGClipperWindow::Init();
288
wxPGClipperWindow(wxWindow* parent,
290
const wxPoint& pos = wxDefaultPosition,
291
const wxSize& size = wxDefaultSize)
294
Create(parent,id,pos,size);
297
void Create(wxWindow* parent,
299
const wxPoint& pos = wxDefaultPosition,
300
const wxSize& size = wxDefaultSize);
302
virtual ~wxPGClipperWindow();
304
virtual bool ProcessEvent(wxEvent& event);
306
inline wxWindow* GetControl() const { return m_ctrl; }
308
// This is called before wxControl is constructed.
309
void GetControlRect( int xadj, int yadj, wxPoint& pt, wxSize& sz );
311
// This is caleed after wxControl has been constructed.
312
void SetControl( wxWindow* ctrl );
314
virtual void Refresh( bool eraseBackground = true,
315
const wxRect *rect = (const wxRect *) NULL );
316
virtual void SetFocus();
318
virtual bool SetFont(const wxFont& font);
320
virtual bool SetForegroundColour(const wxColour& col)
322
bool res = wxWindow::SetForegroundColour(col);
324
m_ctrl->SetForegroundColour(col);
328
virtual bool SetBackgroundColour(const wxColour& col)
330
bool res = wxWindow::SetBackgroundColour(col);
332
m_ctrl->SetBackgroundColour(col);
336
inline int GetXClip() const { return m_xadj; }
338
inline int GetYClip() const { return m_yadj; }
343
int m_xadj; // Horizontal border clip.
345
int m_yadj; // Vertical border clip.
350
m_ctrl = (wxWindow*) NULL;
355
IMPLEMENT_CLASS(wxPGClipperWindow,wxWindow)
358
// This is called before wxControl is constructed.
359
void wxPGClipperWindow::GetControlRect( int xadj, int yadj, wxPoint& pt, wxSize& sz )
365
wxSize own_size = GetSize();
366
sz.x = own_size.x+(xadj*2);
367
sz.y = own_size.y+(yadj*2);
371
// This is caleed after wxControl has been constructed.
372
void wxPGClipperWindow::SetControl( wxWindow* ctrl )
376
// GTK requires this.
377
ctrl->SetSizeHints(3,3);
379
// Correct size of this window to match the child.
380
wxSize sz = GetSize();
381
wxSize chsz = ctrl->GetSize();
383
int hei_adj = chsz.y - (sz.y+(m_yadj*2));
385
SetSize(sz.x,chsz.y-(m_yadj*2));
390
void wxPGClipperWindow::Refresh( bool eraseBackground, const wxRect *rect )
392
wxWindow::Refresh(false,rect);
394
m_ctrl->Refresh(eraseBackground);
398
// Pass focus to control
399
void wxPGClipperWindow::SetFocus()
404
wxWindow::SetFocus();
408
bool wxPGClipperWindow::SetFont(const wxFont& font)
410
bool res = wxWindow::SetFont(font);
412
return m_ctrl->SetFont(font);
417
void wxPGClipperWindow::Create(wxWindow* parent,
422
wxWindow::Create(parent,id,pos,size);
426
wxPGClipperWindow::~wxPGClipperWindow()
431
bool wxPGClipperWindow::ProcessEvent(wxEvent& event)
433
if ( event.GetEventType() == wxEVT_SIZE )
437
// Maintain correct size relationship.
438
wxSize sz = GetSize();
439
m_ctrl->SetSize(sz.x+(m_xadj*2),sz.y+(m_yadj*2));
444
return wxWindow::ProcessEvent(event);
447
#endif // wxPG_ENABLE_CLIPPER_WINDOW
449
/*wxWindow* wxPropertyGrid::GetActualEditorControl( wxWindow* ctrl )
451
#if wxPG_ENABLE_CLIPPER_WINDOW
452
// Pass real control instead of clipper window
453
if ( ctrl->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
455
return ((wxPGClipperWindow*)ctrl)->GetControl();
462
// -----------------------------------------------------------------------
463
// wxPGTextCtrlEditor
464
// -----------------------------------------------------------------------
466
// Clipper window support macro (depending on whether it is used
467
// for this editor or not)
468
#if wxPG_NAT_TEXTCTRL_BORDER_X || wxPG_NAT_TEXTCTRL_BORDER_Y
469
#define wxPG_NAT_TEXTCTRL_BORDER_ANY 1
471
#define wxPG_NAT_TEXTCTRL_BORDER_ANY 0
475
WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrl,wxPGTextCtrlEditor,wxPGEditor)
478
wxPGWindowList wxPGTextCtrlEditor::CreateControls( wxPropertyGrid* propGrid,
479
wxPGProperty* property,
481
const wxSize& sz ) const
486
// If has children, and limited editing is specified, then don't create.
487
if ( (property->GetFlags() & wxPG_PROP_NOEDITOR) &&
488
property->GetChildCount() )
489
return (wxWindow*) NULL;
491
if ( !property->IsValueUnspecified() )
493
int flags = property->HasFlag(wxPG_PROP_READONLY) ?
494
0 : wxPG_EDITABLE_VALUE;
495
text = property->GetValueString(flags);
499
text = propGrid->GetUnspecifiedValueText();
503
if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
504
property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
505
flags |= wxTE_PASSWORD;
507
wxWindow* wnd = propGrid->GenerateEditorTextCtrl(pos,sz,text,(wxWindow*)NULL,flags,
508
property->GetMaxLength());
514
void wxPGTextCtrlEditor::DrawValue( wxDC& dc, wxPGProperty* property, const wxRect& rect ) const
516
if ( !property->IsValueUnspecified() )
518
wxString drawStr = property->GetDisplayedString();
520
// Code below should no longer be needed, as the obfuscation
521
// is now done in GetValueAsString.
522
/*if ( (property->GetFlags() & wxPG_PROP_PASSWORD) &&
523
property->IsKindOf(WX_PG_CLASSINFO(wxStringProperty)) )
525
size_t a = drawStr.length();
527
drawStr.Append(wxT('*'),a);
529
dc.DrawText( drawStr, rect.x+wxPG_XBEFORETEXT, rect.y );
534
void wxPGTextCtrlEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
536
wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
540
if ( tc->HasFlag(wxTE_PASSWORD) )
541
s = property->GetValueAsString(wxPG_FULL_VALUE);
543
s = property->GetDisplayedString();
545
wxPropertyGrid* pg = property->GetGrid();
547
pg->SetupTextCtrlValue(s);
550
// Must always fix indentation, just in case
551
#if defined(__WXMSW__) && !defined(__WXWINCE__)
552
::SendMessage(GetHwndOf(tc), EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0));
557
// Provided so that, for example, ComboBox editor can use the same code
558
// (multiple inheritance would get way too messy).
559
bool wxPGTextCtrlEditor::OnTextCtrlEvent( wxPropertyGrid* propGrid,
560
wxPGProperty* WXUNUSED(property),
567
if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER )
569
if ( propGrid->IsEditorsValueModified() )
574
else if ( event.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED )
577
// Pass this event outside wxPropertyGrid so that,
578
// if necessary, program can tell when user is editing
580
// FIXME: Is it safe to change event id in the middle of event
581
// processing (seems to work, but...)?
583
event.SetId(propGrid->GetId());
585
propGrid->EditorsValueWasModified();
591
bool wxPGTextCtrlEditor::OnEvent( wxPropertyGrid* propGrid,
592
wxPGProperty* property,
594
wxEvent& event ) const
596
return wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid,property,ctrl,event);
600
bool wxPGTextCtrlEditor::GetTextCtrlValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl )
602
wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
603
wxString textVal = tc->GetValue();
605
if ( property->UsesAutoUnspecified() && !textVal.length() )
611
bool res = property->ActualStringToValue(variant, textVal, wxPG_EDITABLE_VALUE);
613
// Changing unspecified always causes event (returning
614
// true here should be enough to trigger it).
615
// TODO: Move to propgrid.cpp
616
if ( !res && variant.IsNull() )
623
bool wxPGTextCtrlEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
625
return wxPGTextCtrlEditor::GetTextCtrlValueFromControl(variant, property, ctrl);
629
void wxPGTextCtrlEditor::SetValueToUnspecified( wxPGProperty* property, wxWindow* ctrl ) const
631
wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
633
wxPropertyGrid* pg = property->GetGrid();
634
wxASSERT(pg); // Really, property grid should exist if editor does
637
wxString tcText = pg->GetUnspecifiedValueText();
638
pg->SetupTextCtrlValue(tcText);
639
tc->SetValue(tcText);
644
void wxPGTextCtrlEditor::SetControlStringValue( wxPGProperty* property, wxWindow* ctrl, const wxString& txt ) const
646
wxTextCtrl* tc = wxStaticCast(ctrl, wxTextCtrl);
648
wxPropertyGrid* pg = property->GetGrid();
649
wxASSERT(pg); // Really, property grid should exist if editor does
654
void wxPGTextCtrlEditor_OnFocus( wxPGProperty* property,
657
// Make sure there is correct text (instead of unspecified value
658
// indicator or inline help)
659
int flags = property->HasFlag(wxPG_PROP_READONLY) ?
660
0 : wxPG_EDITABLE_VALUE;
661
wxString correctText = property->GetValueString(flags);
663
if ( tc->GetValue() != correctText )
665
property->GetGrid()->SetupTextCtrlValue(correctText);
666
tc->SetValue(correctText);
669
tc->SetSelection(-1,-1);
672
void wxPGTextCtrlEditor::OnFocus( wxPGProperty* property,
673
wxWindow* wnd ) const
675
wxTextCtrl* tc = wxStaticCast(wnd, wxTextCtrl);
676
wxPGTextCtrlEditor_OnFocus(property, tc);
680
wxPGTextCtrlEditor::~wxPGTextCtrlEditor() { }
683
// -----------------------------------------------------------------------
685
// -----------------------------------------------------------------------
688
WX_PG_IMPLEMENT_EDITOR_CLASS(Choice,wxPGChoiceEditor,wxPGEditor)
691
// This is a special enhanced double-click processor class.
692
// In essence, it allows for double-clicks for which the
693
// first click "created" the control.
694
class wxPGDoubleClickProcessor : public wxEvtHandler
698
wxPGDoubleClickProcessor( wxPGOwnerDrawnComboBox* combo )
701
m_timeLastMouseUp = 0;
703
m_downReceived = false;
708
void OnMouseEvent( wxMouseEvent& event )
710
wxLongLong t = ::wxGetLocalTimeMillis();
711
int evtType = event.GetEventType();
713
if ( m_combo->HasFlag(wxPGCC_DCLICK_CYCLES) &&
714
!m_combo->IsPopupShown() )
716
// Just check that it is in the text area
717
wxPoint pt = event.GetPosition();
718
if ( m_combo->GetTextRect().wxPGRectContains(pt) )
720
if ( evtType == wxEVT_LEFT_DOWN )
722
// Set value to avoid up-events without corresponding downs
723
m_downReceived = true;
725
else if ( evtType == wxEVT_LEFT_DCLICK )
727
// We'll make our own double-clicks
728
event.SetEventType(0);
731
else if ( evtType == wxEVT_LEFT_UP )
733
if ( m_downReceived || m_timeLastMouseUp == 1 )
735
wxLongLong timeFromLastUp = (t-m_timeLastMouseUp);
737
if ( timeFromLastUp < DOUBLE_CLICK_CONVERSION_TRESHOLD )
739
event.SetEventType(wxEVT_LEFT_DCLICK);
740
m_timeLastMouseUp = 1;
744
m_timeLastMouseUp = t;
754
void OnSetFocus( wxFocusEvent& event )
756
m_timeLastMouseUp = ::wxGetLocalTimeMillis();
761
wxLongLong m_timeLastMouseUp;
762
wxPGOwnerDrawnComboBox* m_combo;
765
DECLARE_EVENT_TABLE()
768
BEGIN_EVENT_TABLE(wxPGDoubleClickProcessor, wxEvtHandler)
769
EVT_MOUSE_EVENTS(wxPGDoubleClickProcessor::OnMouseEvent)
770
EVT_SET_FOCUS(wxPGDoubleClickProcessor::OnSetFocus)
775
class wxPGComboBox : public wxPGOwnerDrawnComboBox
780
: wxPGOwnerDrawnComboBox()
782
m_dclickProcessor = (wxPGDoubleClickProcessor*) NULL;
783
m_sizeEventCalled = false;
788
if ( m_dclickProcessor )
790
RemoveEventHandler(m_dclickProcessor);
791
delete m_dclickProcessor;
795
bool Create(wxWindow *parent,
797
const wxString& value,
800
const wxArrayString& choices,
802
const wxValidator& validator = wxDefaultValidator,
803
const wxString& name = wxT("wxOwnerDrawnComboBox"))
805
if ( !wxPGOwnerDrawnComboBox::Create( parent,
816
m_dclickProcessor = new wxPGDoubleClickProcessor(this);
818
PushEventHandler(m_dclickProcessor);
823
#if wxPG_USING_WXOWNERDRAWNCOMBOBOX
824
virtual void OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const
826
virtual bool OnDrawItem( wxDC& dc, const wxRect& rect, int item, int flags ) const
829
wxPropertyGrid* pg = GetGrid();
830
pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,dc,(wxRect&)rect,flags);
831
#if !wxPG_USING_WXOWNERDRAWNCOMBOBOX
835
virtual wxCoord OnMeasureItem( size_t item ) const
837
wxPropertyGrid* pg = GetGrid();
841
pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,*((wxDC*)NULL),rect,0);
845
wxPropertyGrid* GetGrid() const
847
wxPropertyGrid* pg = wxDynamicCast(GetParent()->GetParent(),wxPropertyGrid);
852
virtual wxCoord OnMeasureItemWidth( size_t item ) const
854
wxPropertyGrid* pg = GetGrid();
858
pg->OnComboItemPaint((wxPGCustomComboControl*)this,item,*((wxDC*)NULL),rect,0);
862
virtual void PositionTextCtrl( int WXUNUSED(textCtrlXAdjust), int WXUNUSED(textCtrlYAdjust) )
864
wxPropertyGrid* pg = GetGrid();
865
wxPGOwnerDrawnComboBox::PositionTextCtrl(
866
wxPG_TEXTCTRLXADJUST - (wxPG_XBEFOREWIDGET+wxPG_CONTROL_MARGIN+1) - 1,
867
pg->GetSpacingY() + 2
872
wxPGDoubleClickProcessor* m_dclickProcessor;
873
bool m_sizeEventCalled;
877
void wxPropertyGrid::OnComboItemPaint( wxPGCustomComboControl* pCc,
883
wxPGComboBox* pCb = (wxPGComboBox*)pCc;
886
wxASSERT( IsKindOf(CLASSINFO(wxPropertyGrid)) );
888
wxPGProperty* p = GetSelection();
891
const wxPGChoices* pChoices = &p->GetChoices();
892
const wxPGCommonValue* comVal = NULL;
893
int choiceCount = p->GetChoiceCount();
894
int comVals = p->GetDisplayedCommonValueCount();
895
int comValIndex = -1;
896
if ( item >= choiceCount && comVals > 0 )
898
comValIndex = item - choiceCount;
899
comVal = GetCommonValue(comValIndex);
900
if ( !p->IsValueUnspecified() )
901
text = comVal->GetLabel();
905
if ( !(flags & wxPGCC_PAINTING_CONTROL) )
907
text = pCb->GetString(item);
911
if ( !p->IsValueUnspecified() )
912
text = p->GetValueString(0);
919
#if !wxPG_USING_WXOWNERDRAWNCOMBOBOX
920
// Add wxPGCC_PAINTING_SELECTED
921
if ( !(flags & wxPGCC_PAINTING_CONTROL) &&
922
wxDynamicCast(pCb->GetPopup()->GetControl(),wxVListBox)->GetSelection() == item )
923
flags |= wxPGCC_PAINTING_SELECTED;
928
const wxBitmap* itemBitmap = NULL;
930
if ( item >= 0 && pChoices && pChoices->Item(item).GetBitmap().Ok() && comValIndex == -1 )
931
itemBitmap = &pChoices->Item(item).GetBitmap();
934
// Decide what custom image size to use
937
cis.x = itemBitmap->GetWidth();
938
cis.y = itemBitmap->GetHeight();
942
cis = GetImageSize(p, item);
947
// Default measure behaviour (no flexible, custom paint image only)
948
if ( rect.width < 0 )
951
GetTextExtent(text, &x, &y, 0, 0);
952
rect.width = cis.x + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2 + 9 + x;
955
rect.height = cis.y + 2;
959
wxPGPaintData paintdata;
960
paintdata.m_parent = NULL;
961
paintdata.m_choiceItem = item;
963
// This is by the current (1.0.0b) spec - if painting control, item is -1
964
if ( (flags & wxPGCC_PAINTING_CONTROL) )
965
paintdata.m_choiceItem = -1;
968
dc.SetBrush(*wxWHITE_BRUSH);
970
wxPGCellRenderer* renderer = NULL;
971
const wxPGCell* cell = NULL;
978
wxPoint pt(rect.x + wxPG_CONTROL_MARGIN - wxPG_CHOICEXADJUST - 1,
983
if ( flags & wxPGCC_PAINTING_CONTROL )
985
renderFlags |= wxPGCellRenderer::Control;
989
// For consistency, always use normal font when drawing drop down
991
dc.SetFont(GetFont());
994
if ( flags & wxPGCC_PAINTING_SELECTED )
995
renderFlags |= wxPGCellRenderer::Selected;
997
if ( cis.x > 0 && (p->HasFlag(wxPG_PROP_CUSTOMIMAGE) || !(flags & wxPGCC_PAINTING_CONTROL)) &&
998
( !p->m_valueBitmap || item == pCb->GetSelection() ) &&
999
( item >= 0 || (flags & wxPGCC_PAINTING_CONTROL) ) &&
1003
pt.x += wxCC_CUSTOM_IMAGE_MARGIN1;
1004
wxRect r(pt.x,pt.y,cis.x,cis.y);
1006
if ( flags & wxPGCC_PAINTING_CONTROL )
1009
r.height = wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight);
1012
paintdata.m_drawnWidth = r.width;
1014
dc.SetPen(m_colPropFore);
1015
if ( comValIndex >= 0 )
1017
const wxPGCommonValue* cv = GetCommonValue(comValIndex);
1018
wxPGCellRenderer* renderer = cv->GetRenderer();
1019
r.width = rect.width;
1020
renderer->Render( dc, r, this, p, m_selColumn, comValIndex, renderFlags );
1023
else if ( item >= 0 )
1025
p->OnCustomPaint( dc, r, paintdata );
1029
dc.DrawRectangle( r );
1032
pt.x += paintdata.m_drawnWidth + wxCC_CUSTOM_IMAGE_MARGIN2 - 1;
1036
// TODO: This aligns text so that it seems to be horizontally
1037
// on the same line as property values. Not really
1038
// sure if its needed, but seems to not cause any harm.
1041
if ( (flags & wxPGCC_PAINTING_CONTROL) )
1043
if ( p->IsValueUnspecified() )
1044
cell = &m_unspecifiedAppearance;
1045
else if ( item < 0 )
1046
item = pCb->GetSelection();
1049
if ( p->IsValueUnspecified() && item < 0 )
1051
cell = &m_unspecifiedAppearance;
1054
if ( pChoices && item >= 0 && comValIndex < 0 )
1056
cell = &pChoices->Item(item);
1057
renderer = wxPGGlobalVars->m_defaultRenderer;
1058
int imageOffset = renderer->PreDrawCell(dc, rect, *cell,
1061
imageOffset += wxCC_CUSTOM_IMAGE_MARGIN1 +
1062
wxCC_CUSTOM_IMAGE_MARGIN2;
1063
pt.x += imageOffset;
1071
pt.y += (rect.height-m_fontHeight)/2 - 1;
1075
dc.DrawText( text, pt.x + wxPG_XBEFORETEXT, pt.y );
1078
renderer->PostDrawCell(dc, this, *cell, renderFlags);
1085
p->OnCustomPaint( dc, rect, paintdata );
1086
rect.height = paintdata.m_drawnHeight + 2;
1087
rect.width = cis.x + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2 + 9;
1091
bool wxPGChoiceEditor_SetCustomPaintWidth( wxPropertyGrid* propGrid,
1093
wxPGProperty* property,
1096
// Must return true if value was not a common value
1097
int custPaintMargin;
1100
// Use different custom paint margin because of better textctrl spacing
1101
if ( cb->HasFlag(wxCB_READONLY) )
1102
custPaintMargin = ODCB_CUST_PAINT_MARGIN_RO;
1104
custPaintMargin = ODCB_CUST_PAINT_MARGIN;
1106
if ( property->IsValueUnspecified() )
1108
cb->SetCustomPaintWidth( 0 );
1114
// Yes, a common value is being selected
1115
property->SetCommonValue( cmnVal );
1116
wxSize imageSize = propGrid->GetCommonValue(cmnVal)->
1117
GetRenderer()->GetImageSize(property, 1, cmnVal);
1118
if ( imageSize.x ) imageSize.x += custPaintMargin;
1119
cb->SetCustomPaintWidth( imageSize.x );
1124
wxSize imageSize = propGrid->GetImageSize(property, -1);
1125
if ( imageSize.x ) imageSize.x += custPaintMargin;
1126
cb->SetCustomPaintWidth( imageSize.x );
1131
// CreateControls calls this with CB_READONLY in extraStyle
1132
wxWindow* wxPGChoiceEditor::CreateControlsBase( wxPropertyGrid* propGrid,
1133
wxPGProperty* property,
1136
long extraStyle ) const
1140
// Since it is not possible (yet) to create a read-only combo box in
1141
// the same sense that wxTextCtrl is read-only, simply do not create
1142
// the control in this case.
1143
if ( property->HasFlag(wxPG_PROP_READONLY) )
1147
int index = property->GetChoiceInfo( NULL );
1149
bool isUnspecified = property->IsValueUnspecified();
1151
if ( isUnspecified )
1154
defString = property->GetDisplayedString();
1156
const wxPGChoices& choices = property->GetChoices();
1158
wxArrayString labels = choices.GetLabels();
1164
po.y += wxPG_CHOICEYADJUST;
1165
si.y -= (wxPG_CHOICEYADJUST*2);
1167
po.x += wxPG_CHOICEXADJUST;
1168
si.x -= wxPG_CHOICEXADJUST;
1169
wxWindow* ctrlParent = propGrid->GetPanel();
1171
int odcbFlags = extraStyle | wxNO_BORDER | wxPGCC_PROCESS_ENTER | wxPGCC_ALT_KEYS;
1173
if ( (property->GetFlags() & wxPG_PROP_USE_DCC) &&
1174
(property->IsKindOf(CLASSINFO(wxBoolProperty)) ) )
1175
odcbFlags |= wxPGCC_DCLICK_CYCLES;
1178
// If common value specified, use appropriate index
1179
unsigned int cmnVals = property->GetDisplayedCommonValueCount();
1182
if ( !isUnspecified )
1184
int cmnVal = property->GetCommonValue();
1187
index = labels.size() + cmnVal;
1192
for ( i=0; i<cmnVals; i++ )
1193
labels.Add(propGrid->GetCommonValueLabel(i));
1196
cb = new wxPGComboBox();
1200
cb->Create(ctrlParent,
1208
//int extRight = propGrid->GetClientSize().x - (po.x+si.x);
1209
//int extRight = - (po.x+si.x);
1211
cb->SetButtonPosition(si.y,0,wxRIGHT);
1212
//cb->SetPopupExtents( 1, extRight );
1213
cb->SetTextIndent(wxPG_XBEFORETEXT-1);
1215
wxPGChoiceEditor_SetCustomPaintWidth( propGrid, cb, property,
1216
property->GetCommonValue() );
1217
/*if ( property->GetFlags() & wxPG_PROP_CUSTOMIMAGE )
1219
wxSize imageSize = propGrid->GetImageSize(property, index);
1220
if ( imageSize.x ) imageSize.x += ODCB_CUST_PAINT_MARGIN;
1221
cb->SetCustomPaintWidth( imageSize.x );
1224
if ( index >= 0 && index < (int)cb->GetCount() )
1226
cb->SetSelection( index );
1227
if ( defString.length() )
1228
cb->SetText( defString );
1230
else if ( !(extraStyle & wxCB_READONLY) && defString.length() )
1231
cb->SetValue( defString );
1233
cb->SetSelection( -1 );
1239
return (wxWindow*) cb;
1243
void wxPGChoiceEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
1246
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1247
wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
1248
int ind = property->GetChoiceInfo( (wxPGChoiceInfo*)NULL );
1249
cb->SetSelection(ind);
1252
wxPGWindowList wxPGChoiceEditor::CreateControls( wxPropertyGrid* propGrid, wxPGProperty* property,
1253
const wxPoint& pos, const wxSize& sz ) const
1255
return CreateControlsBase(propGrid,property,pos,sz,wxCB_READONLY);
1259
int wxPGChoiceEditor::InsertItem( wxWindow* ctrl, const wxString& label, int index ) const
1262
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1263
wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
1266
index = cb->GetCount();
1268
return cb->Insert(label,index);
1272
void wxPGChoiceEditor::DeleteItem( wxWindow* ctrl, int index ) const
1275
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1276
wxASSERT( cb->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)));
1281
bool wxPGChoiceEditor::OnEvent( wxPropertyGrid* propGrid, wxPGProperty* property,
1282
wxWindow* ctrl, wxEvent& event ) const
1284
if ( event.GetEventType() == wxEVT_COMMAND_COMBOBOX_SELECTED )
1286
wxPGComboBox* cb = (wxPGComboBox*)ctrl;
1287
int index = cb->GetSelection();
1288
int cmnValIndex = -1;
1289
int cmnVals = property->GetDisplayedCommonValueCount();
1290
int items = cb->GetCount();
1292
if ( index >= (items-cmnVals) )
1294
// Yes, a common value is being selected
1295
cmnValIndex = index - (items-cmnVals);
1296
property->SetCommonValue( cmnValIndex );
1298
// Truly set value to unspecified?
1299
if ( propGrid->GetUnspecifiedCommonValue() == cmnValIndex )
1301
if ( !property->IsValueUnspecified() )
1302
propGrid->SetInternalFlag(wxPG_FL_VALUE_CHANGE_IN_EVENT);
1303
property->SetValueToUnspecified();
1304
if ( !cb->HasFlag(wxCB_READONLY) )
1305
cb->GetTextCtrl()->SetValue(wxEmptyString);
1309
return wxPGChoiceEditor_SetCustomPaintWidth( propGrid, cb, property,
1316
bool wxPGChoiceEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1318
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1320
int index = cb->GetSelection();
1322
if ( index != property->GetChoiceInfo( (wxPGChoiceInfo*) NULL ) ||
1323
// Changing unspecified always causes event (returning
1324
// true here should be enough to trigger it).
1325
property->IsValueUnspecified()
1328
return property->ActualIntToValue( variant, index, 0 );
1334
void wxPGChoiceEditor::SetControlStringValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, const wxString& txt ) const
1336
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1342
void wxPGChoiceEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, int value ) const
1344
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1346
cb->SetSelection(value);
1350
void wxPGChoiceEditor::SetValueToUnspecified( wxPGProperty* property,
1351
wxWindow* ctrl ) const
1353
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1355
if ( !cb->HasFlag(wxCB_READONLY) )
1357
wxPropertyGrid* pg = property->GetGrid();
1360
wxString tcText = pg->GetUnspecifiedValueText();
1361
pg->SetupTextCtrlValue(tcText);
1362
cb->SetValue(tcText);
1367
cb->SetSelection(-1);
1372
bool wxPGChoiceEditor::CanContainCustomImage() const
1378
wxPGChoiceEditor::~wxPGChoiceEditor() { }
1381
// -----------------------------------------------------------------------
1382
// wxPGComboBoxEditor
1383
// -----------------------------------------------------------------------
1386
WX_PG_IMPLEMENT_EDITOR_CLASS(ComboBox,wxPGComboBoxEditor,wxPGChoiceEditor)
1389
void wxPGComboBoxEditor::UpdateControl( wxPGProperty* property, wxWindow* ctrl ) const
1391
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1392
cb->SetValue(property->GetValueString(wxPG_EDITABLE_VALUE));
1394
// TODO: If string matches any selection, then select that.
1398
wxPGWindowList wxPGComboBoxEditor::CreateControls( wxPropertyGrid* propGrid,
1399
wxPGProperty* property,
1401
const wxSize& sz ) const
1403
return CreateControlsBase(propGrid,property,pos,sz,0);
1407
bool wxPGComboBoxEditor::OnEvent( wxPropertyGrid* propGrid,
1408
wxPGProperty* property,
1410
wxEvent& event ) const
1412
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*) NULL;
1413
wxWindow* textCtrl = (wxWindow*) NULL;
1417
cb = (wxPGOwnerDrawnComboBox*)ctrl;
1418
textCtrl = cb->GetTextCtrl();
1421
if ( wxPGTextCtrlEditor::OnTextCtrlEvent(propGrid,property,textCtrl,event) )
1424
return wxPGChoiceEditor::OnEvent(propGrid,property,ctrl,event);
1428
bool wxPGComboBoxEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1430
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1431
wxString textVal = cb->GetValue();
1433
if ( property->UsesAutoUnspecified() && !textVal.length() )
1439
bool res = property->ActualStringToValue(variant, textVal, wxPG_EDITABLE_VALUE);
1441
// Changing unspecified always causes event (returning
1442
// true here should be enough to trigger it).
1443
if ( !res && variant.IsNull() )
1449
void wxPGComboBoxEditor::OnFocus( wxPGProperty* property,
1450
wxWindow* ctrl ) const
1452
wxPGOwnerDrawnComboBox* cb = (wxPGOwnerDrawnComboBox*)ctrl;
1453
wxPGTextCtrlEditor_OnFocus(property, cb->GetTextCtrl());
1457
wxPGComboBoxEditor::~wxPGComboBoxEditor() { }
1460
// -----------------------------------------------------------------------
1461
// wxPGChoiceAndButtonEditor
1462
// -----------------------------------------------------------------------
1465
// This simpler implement_editor macro doesn't define class body.
1466
WX_PG_IMPLEMENT_EDITOR_CLASS(ChoiceAndButton,wxPGChoiceAndButtonEditor,wxPGChoiceEditor)
1469
wxPGWindowList wxPGChoiceAndButtonEditor::CreateControls( wxPropertyGrid* propGrid,
1470
wxPGProperty* property,
1472
const wxSize& sz ) const
1474
// Use one two units smaller to match size of the combo's dropbutton.
1475
// (normally a bigger button is used because it looks better)
1478
wxSize bt_sz(bt_wid,bt_wid);
1480
// Position of button.
1481
wxPoint bt_pos(pos.x+sz.x-bt_sz.x,pos.y);
1488
wxWindow* bt = propGrid->GenerateEditorButton( bt_pos, bt_sz );
1491
wxSize ch_sz(sz.x-bt->GetSize().x,sz.y);
1494
ch_sz.x -= wxPG_TEXTCTRL_AND_BUTTON_SPACING;
1497
wxWindow* ch = wxPG_EDITOR(Choice)->CreateControls(propGrid,property,
1498
pos,ch_sz).m_primary;
1504
return wxPGWindowList(ch, bt);
1508
wxPGChoiceAndButtonEditor::~wxPGChoiceAndButtonEditor() { }
1511
// -----------------------------------------------------------------------
1512
// wxPGTextCtrlAndButtonEditor
1513
// -----------------------------------------------------------------------
1516
// This simpler implement_editor macro doesn't define class body.
1517
WX_PG_IMPLEMENT_EDITOR_CLASS(TextCtrlAndButton,wxPGTextCtrlAndButtonEditor,wxPGTextCtrlEditor)
1520
wxPGWindowList wxPGTextCtrlAndButtonEditor::CreateControls( wxPropertyGrid* propGrid,
1521
wxPGProperty* property,
1523
const wxSize& sz ) const
1526
wxWindow* wnd = propGrid->GenerateEditorTextCtrlAndButton( pos, sz, &wnd2,
1527
property->GetFlags() & wxPG_PROP_NOEDITOR, property);
1529
return wxPGWindowList(wnd, wnd2);
1533
wxPGTextCtrlAndButtonEditor::~wxPGTextCtrlAndButtonEditor() { }
1536
// -----------------------------------------------------------------------
1537
// wxPGCheckBoxEditor
1538
// -----------------------------------------------------------------------
1540
#if wxPG_INCLUDE_CHECKBOX
1542
WX_PG_IMPLEMENT_EDITOR_CLASS(CheckBox,wxPGCheckBoxEditor,wxPGEditor)
1545
// Check box state flags
1548
wxSCB_STATE_UNCHECKED = 0,
1549
wxSCB_STATE_CHECKED = 1,
1550
wxSCB_STATE_BOLD = 2,
1551
wxSCB_STATE_UNSPECIFIED = 4
1554
const int wxSCB_SETVALUE_CYCLE = 2;
1557
static void DrawSimpleCheckBox( wxDC& dc, const wxRect& rect, int box_hei,
1561
wxRect r(rect.x+wxPG_XBEFORETEXT,rect.y+((rect.height-box_hei)/2),
1563
wxColour useCol = dc.GetTextForeground();
1565
// Draw check mark first because it is likely to overdraw the
1566
// surrounding rectangle.
1567
if ( state & wxSCB_STATE_CHECKED )
1569
wxRect r2(r.x+wxPG_CHECKMARK_XADJ,
1570
r.y+wxPG_CHECKMARK_YADJ,
1571
r.width+wxPG_CHECKMARK_WADJ,
1572
r.height+wxPG_CHECKMARK_HADJ);
1573
#if wxPG_CHECKMARK_DEFLATE
1574
r2.Deflate(wxPG_CHECKMARK_DEFLATE);
1576
dc.DrawCheckMark(r2);
1578
// This would draw a simple cross check mark.
1579
// dc.DrawLine(r.x,r.y,r.x+r.width-1,r.y+r.height-1);
1580
// dc.DrawLine(r.x,r.y+r.height-1,r.x+r.width-1,r.y);
1584
if ( !(state & wxSCB_STATE_BOLD) )
1586
// Pen for thin rectangle.
1591
// Pen for bold rectangle.
1592
wxPen linepen(useCol,2,wxSOLID);
1593
linepen.SetJoin(wxJOIN_MITER); // This prevents round edges.
1601
dc.SetBrush(*wxTRANSPARENT_BRUSH);
1603
dc.DrawRectangle(r);
1604
dc.SetPen(*wxTRANSPARENT_PEN);
1608
// Real simple custom-drawn checkbox-without-label class.
1610
class wxSimpleCheckBox : public wxControl
1614
void SetValue( int value );
1616
wxSimpleCheckBox( wxWindow* parent,
1618
const wxPoint& pos = wxDefaultPosition,
1619
const wxSize& size = wxDefaultSize )
1620
: wxControl(parent,id,pos,size,wxNO_BORDER|wxWANTS_CHARS)
1622
// Due to SetOwnFont stuff necessary for GTK+ 1.2, we need to have this
1623
SetFont( parent->GetFont() );
1625
m_state = wxSCB_STATE_UNCHECKED;
1626
wxPropertyGrid* pg = (wxPropertyGrid*) parent->GetParent();
1627
wxASSERT( pg->IsKindOf(CLASSINFO(wxPropertyGrid)) );
1628
m_boxHeight = pg->GetFontHeight();
1629
SetBackgroundStyle( wxBG_STYLE_COLOUR );
1632
virtual ~wxSimpleCheckBox();
1634
virtual bool ProcessEvent(wxEvent& event);
1639
static wxBitmap* ms_doubleBuffer;
1643
wxSimpleCheckBox::~wxSimpleCheckBox()
1645
delete ms_doubleBuffer;
1646
ms_doubleBuffer = NULL;
1650
wxBitmap* wxSimpleCheckBox::ms_doubleBuffer = (wxBitmap*) NULL;
1652
void wxSimpleCheckBox::SetValue( int value )
1654
if ( value == wxSCB_SETVALUE_CYCLE )
1656
if ( m_state & wxSCB_STATE_CHECKED )
1657
m_state &= ~wxSCB_STATE_CHECKED;
1659
m_state |= wxSCB_STATE_CHECKED;
1667
wxCommandEvent evt(wxEVT_COMMAND_CHECKBOX_CLICKED,GetParent()->GetId());
1669
wxPropertyGrid* propGrid = (wxPropertyGrid*) GetParent()->GetParent();
1670
wxASSERT( propGrid->IsKindOf(CLASSINFO(wxPropertyGrid)) );
1671
propGrid->OnCustomEditorEvent(evt);
1675
bool wxSimpleCheckBox::ProcessEvent(wxEvent& event)
1677
wxPropertyGrid* propGrid = (wxPropertyGrid*) GetParent()->GetParent();
1678
wxASSERT( propGrid->IsKindOf(CLASSINFO(wxPropertyGrid)) );
1680
if ( event.GetEventType() == wxEVT_NAVIGATION_KEY )
1682
//wxLogDebug(wxT("wxEVT_NAVIGATION_KEY"));
1683
//SetFocusFromKbd();
1685
//return wxControl::ProcessEvent(event);
1688
if ( ( (event.GetEventType() == wxEVT_LEFT_DOWN || event.GetEventType() == wxEVT_LEFT_DCLICK)
1689
&& ((wxMouseEvent&)event).m_x > (wxPG_XBEFORETEXT-2)
1690
&& ((wxMouseEvent&)event).m_x <= (wxPG_XBEFORETEXT-2+m_boxHeight) )
1693
SetValue(wxSCB_SETVALUE_CYCLE);
1696
else if ( event.GetEventType() == wxEVT_PAINT )
1698
wxSize clientSize = GetClientSize();
1702
// Buffered paint DC doesn't seem to do much good
1703
if ( !ms_doubleBuffer ||
1704
clientSize.x > ms_doubleBuffer->GetWidth() ||
1705
clientSize.y > ms_doubleBuffer->GetHeight() )
1707
delete ms_doubleBuffer;
1708
ms_doubleBuffer = new wxBitmap(clientSize.x+25,clientSize.y+25);
1711
wxBufferedPaintDC dc(this,*ms_doubleBuffer);
1714
wxRect rect(0,0,clientSize.x,clientSize.y);
1719
m_boxHeight = propGrid->GetFontHeight();
1721
wxColour bgcol = GetBackgroundColour();
1722
dc.SetBrush( bgcol );
1724
dc.DrawRectangle( rect );
1726
dc.SetTextForeground(GetForegroundColour());
1728
int state = m_state;
1729
if ( !(state & wxSCB_STATE_UNSPECIFIED) &&
1730
GetFont().GetWeight() == wxBOLD )
1731
state |= wxSCB_STATE_BOLD;
1733
DrawSimpleCheckBox(dc, rect, m_boxHeight, state);
1737
else if ( event.GetEventType() == wxEVT_SIZE ||
1738
event.GetEventType() == wxEVT_SET_FOCUS ||
1739
event.GetEventType() == wxEVT_KILL_FOCUS
1744
else if ( event.GetEventType() == wxEVT_KEY_DOWN )
1746
wxKeyEvent& keyEv = (wxKeyEvent&) event;
1748
if ( keyEv.GetKeyCode() == WXK_TAB )
1750
propGrid->SendNavigationKeyEvent( keyEv.ShiftDown()?0:1 );
1754
if ( keyEv.GetKeyCode() == WXK_SPACE )
1756
SetValue(wxSCB_SETVALUE_CYCLE);
1760
return wxControl::ProcessEvent(event);
1764
wxPGWindowList wxPGCheckBoxEditor::CreateControls( wxPropertyGrid* propGrid,
1765
wxPGProperty* property,
1767
const wxSize& size ) const
1769
if ( property->HasFlag(wxPG_PROP_READONLY) )
1773
pt.x -= wxPG_XBEFOREWIDGET;
1775
sz.x = propGrid->GetFontHeight() + (wxPG_XBEFOREWIDGET*2) + 4;
1777
wxSimpleCheckBox* cb = new wxSimpleCheckBox(propGrid->GetPanel(),wxPG_SUBID1,pt,sz);
1779
cb->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));
1781
cb->Connect( wxPG_SUBID1, wxEVT_LEFT_DOWN,
1782
(wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
1783
&wxPropertyGrid::OnCustomEditorEvent, NULL, propGrid );
1785
cb->Connect( wxPG_SUBID1, wxEVT_LEFT_DCLICK,
1786
(wxObjectEventFunction) (wxEventFunction) (wxCommandEventFunction)
1787
&wxPropertyGrid::OnCustomEditorEvent, NULL, propGrid );
1789
if ( property->IsValueUnspecified() )
1791
cb->m_state = wxSCB_STATE_UNSPECIFIED;
1795
if ( property->GetChoiceInfo((wxPGChoiceInfo*)NULL) )
1796
cb->m_state = wxSCB_STATE_CHECKED;
1798
// If mouse cursor was on the item, toggle the value now.
1799
if ( propGrid->GetInternalFlags() & wxPG_FL_ACTIVATION_BY_CLICK )
1801
wxPoint pt = cb->ScreenToClient(::wxGetMousePosition());
1802
if ( pt.x <= (wxPG_XBEFORETEXT-2+cb->m_boxHeight) )
1804
if ( cb->m_state & wxSCB_STATE_CHECKED )
1805
cb->m_state &= ~wxSCB_STATE_CHECKED;
1807
cb->m_state |= wxSCB_STATE_CHECKED;
1809
// Makes sure wxPG_EVT_CHANGING etc. is sent for this initial
1811
propGrid->ChangePropertyValue(property,
1812
wxPGVariant_Bool(cb->m_state));
1817
propGrid->SetInternalFlag( wxPG_FL_FIXED_WIDTH_EDITOR );
1822
void wxPGCheckBoxEditor::DrawValue( wxDC& dc, const wxRect& rect,
1823
wxPGProperty* property,
1824
const wxString& WXUNUSED(text) ) const
1826
int state = wxSCB_STATE_UNCHECKED;
1828
if ( !property->IsValueUnspecified() )
1830
state = property->GetChoiceInfo((wxPGChoiceInfo*)NULL);
1831
if ( dc.GetFont().GetWeight() == wxBOLD )
1832
state |= wxSCB_STATE_BOLD;
1836
state |= wxSCB_STATE_UNSPECIFIED;
1839
DrawSimpleCheckBox(dc, rect, dc.GetCharHeight(), state);
1842
void wxPGCheckBoxEditor::UpdateControl( wxPGProperty* property,
1843
wxWindow* ctrl ) const
1845
wxSimpleCheckBox* cb = (wxSimpleCheckBox*) ctrl;
1848
if ( !property->IsValueUnspecified() )
1849
cb->m_state = property->GetChoiceInfo((wxPGChoiceInfo*)NULL);
1851
cb->m_state = wxSCB_STATE_UNSPECIFIED;
1856
bool wxPGCheckBoxEditor::OnEvent( wxPropertyGrid* WXUNUSED(propGrid), wxPGProperty* WXUNUSED(property),
1857
wxWindow* WXUNUSED(ctrl), wxEvent& event ) const
1859
if ( event.GetEventType() == wxEVT_COMMAND_CHECKBOX_CLICKED )
1867
bool wxPGCheckBoxEditor::GetValueFromControl( wxVariant& variant, wxPGProperty* property, wxWindow* ctrl ) const
1869
wxSimpleCheckBox* cb = (wxSimpleCheckBox*)ctrl;
1871
int index = cb->m_state;
1873
if ( index != property->GetChoiceInfo( (wxPGChoiceInfo*) NULL ) ||
1874
// Changing unspecified always causes event (returning
1875
// true here should be enough to trigger it).
1876
property->IsValueUnspecified()
1879
return property->ActualIntToValue(variant, index, 0);
1885
void wxPGCheckBoxEditor::SetControlIntValue( wxPGProperty* WXUNUSED(property), wxWindow* ctrl, int value ) const
1887
if ( value != 0 ) value = 1;
1888
((wxSimpleCheckBox*)ctrl)->m_state = value;
1893
void wxPGCheckBoxEditor::SetValueToUnspecified( wxPGProperty* WXUNUSED(property), wxWindow* ctrl ) const
1895
((wxSimpleCheckBox*)ctrl)->m_state = wxSCB_STATE_UNSPECIFIED;
1900
wxPGCheckBoxEditor::~wxPGCheckBoxEditor() { }
1903
#endif // wxPG_INCLUDE_CHECKBOX
1905
// -----------------------------------------------------------------------
1907
wxWindow* wxPropertyGrid::GetEditorControl() const
1909
wxWindow* ctrl = m_wndEditor;
1914
// If it's clipper window, return its child instead
1915
#if wxPG_ENABLE_CLIPPER_WINDOW
1916
if ( ctrl->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
1918
return ((wxPGClipperWindow*)ctrl)->GetControl();
1925
// -----------------------------------------------------------------------
1927
wxTextCtrl* wxPropertyGrid::GetLabelEditor() const
1929
wxWindow* tcWnd = m_labelEditor;
1934
#if wxPG_ENABLE_CLIPPER_WINDOW
1935
if ( tcWnd->IsKindOf(CLASSINFO(wxPGClipperWindow)) )
1937
tcWnd = ((wxPGClipperWindow*)tcWnd)->GetControl();
1941
return wxStaticCast(tcWnd, wxTextCtrl);
1944
// -----------------------------------------------------------------------
1946
void wxPropertyGrid::CorrectEditorWidgetSizeX()
1950
// Use fixed selColumn 1 for main editor widgets
1951
int newSplitterx = m_pState->DoGetSplitterPosition(0);
1952
int newWidth = newSplitterx + m_pState->m_colWidths[1];
1956
// if width change occurred, move secondary wnd by that amount
1957
wxRect r = m_wndEditor2->GetRect();
1959
r.x = newWidth - secWid;
1961
m_wndEditor2->SetSize( r );
1963
// if primary is textctrl, then we have to add some extra space
1967
if ( m_wndEditor && m_wndEditor->IsKindOf(CLASSINFO(wxTextCtrl)) )
1969
secWid += wxPG_TEXTCTRL_AND_BUTTON_SPACING;
1974
wxRect r = m_wndEditor->GetRect();
1976
r.x = newSplitterx+m_ctrlXAdjust;
1978
if ( !(m_iFlags & wxPG_FL_FIXED_WIDTH_EDITOR) )
1979
r.width = newWidth - r.x - secWid;
1981
m_wndEditor->SetSize(r);
1985
m_wndEditor2->Refresh();
1988
// -----------------------------------------------------------------------
1990
void wxPropertyGrid::CorrectEditorWidgetPosY()
1992
wxPGProperty* selected = GetSelection();
1996
if ( m_labelEditor )
1998
wxRect r = GetEditorWidgetRect(selected, m_selColumn);
1999
wxPoint pos = m_labelEditor->GetPosition();
2001
// Calculate y offset
2002
int offset = pos.y % m_lineHeight;
2004
m_labelEditor->Move(pos.x, r.y + offset);
2007
if ( m_wndEditor || m_wndEditor2 )
2009
wxRect r = GetEditorWidgetRect(selected, 1);
2013
wxPoint pos = m_wndEditor->GetPosition();
2015
// Calculate y offset
2016
int offset = pos.y % m_lineHeight;
2018
m_wndEditor->Move(pos.x, r.y + offset);
2023
wxPoint pos = m_wndEditor2->GetPosition();
2025
m_wndEditor2->Move(pos.x, r.y);
2031
// -----------------------------------------------------------------------
2033
bool wxPropertyGrid::AdjustPosForClipperWindow( wxWindow* topCtrlWnd, int* x, int* y )
2035
#if wxPG_ENABLE_CLIPPER_WINDOW
2036
// Take clipper window into account
2037
if (topCtrlWnd->GetPosition().x < 1 &&
2038
!topCtrlWnd->IsKindOf(CLASSINFO(wxPGClipperWindow)))
2040
topCtrlWnd = topCtrlWnd->GetParent();
2041
wxASSERT( topCtrlWnd->IsKindOf(CLASSINFO(wxPGClipperWindow)) );
2042
*x -= ((wxPGClipperWindow*)topCtrlWnd)->GetXClip();
2043
*y -= ((wxPGClipperWindow*)topCtrlWnd)->GetYClip();
2047
wxUnusedVar(topCtrlWnd);
2054
// -----------------------------------------------------------------------
2056
// Fixes position of wxTextCtrl-like control (wxSpinCtrl usually
2057
// fits into that category as well).
2058
void wxPropertyGrid::FixPosForTextCtrl( wxWindow* ctrl,
2059
unsigned int forColumn,
2060
const wxPoint& offset )
2062
// Center the control vertically
2063
wxRect finalPos = ctrl->GetRect();
2064
int y_adj = (m_lineHeight - finalPos.height)/2 + wxPG_TEXTCTRLYADJUST;
2066
// Prevent over-sized control
2067
int sz_dec = (y_adj + finalPos.height) - m_lineHeight;
2068
if ( sz_dec < 0 ) sz_dec = 0;
2070
finalPos.y += y_adj;
2071
finalPos.height -= (y_adj+sz_dec);
2073
int textCtrlXAdjust = wxPG_TEXTCTRLXADJUST;
2075
if ( forColumn != 1 )
2076
textCtrlXAdjust -= 3; // magic number!
2078
finalPos.x += textCtrlXAdjust;
2079
finalPos.width -= textCtrlXAdjust;
2081
finalPos.x += offset.x;
2082
finalPos.y += offset.y;
2084
ctrl->SetSize(finalPos);
2087
// -----------------------------------------------------------------------
2089
wxWindow* wxPropertyGrid::GenerateEditorTextCtrl( const wxPoint& pos,
2091
const wxString& value,
2092
wxWindow* secondary,
2095
unsigned int forColumn )
2097
wxPGProperty* selected = GetSelection();
2100
int tcFlags = wxTE_PROCESS_ENTER | extraStyle;
2102
if ( selected->HasFlag(wxPG_PROP_READONLY) && forColumn == 1 )
2103
tcFlags |= wxTE_READONLY;
2105
wxPoint p(pos.x,pos.y);
2106
wxSize s(sz.x,sz.y);
2108
// Need to reduce width of text control on Mac
2109
#if defined(__WXMAC__)
2113
// For label editors, trim the size to allow better splitter grabbing
2114
if ( forColumn != 1 )
2117
// Take button into acccount
2120
s.x -= (secondary->GetSize().x + wxPG_TEXTCTRL_AND_BUTTON_SPACING);
2121
m_iFlags &= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE);
2124
// If the height is significantly higher, then use border, and fill the rect exactly.
2125
bool hasSpecialSize = false;
2127
if ( (sz.y - m_lineHeight) > 5 )
2128
hasSpecialSize = true;
2130
#if wxPG_NAT_TEXTCTRL_BORDER_ANY
2132
// Create clipper window
2133
wxPGClipperWindow* wnd = new wxPGClipperWindow();
2134
#if defined(__WXMSW__)
2137
wnd->Create(GetPanel(),wxPG_SUBID1,p,s);
2139
// This generates rect of the control inside the clipper window
2140
if ( !hasSpecialSize )
2141
wnd->GetControlRect(wxPG_NAT_TEXTCTRL_BORDER_X, wxPG_NAT_TEXTCTRL_BORDER_Y, p, s);
2143
wnd->GetControlRect(0, 0, p, s);
2145
wxWindow* ctrlParent = wnd;
2149
wxWindow* ctrlParent = GetPanel();
2151
if ( !hasSpecialSize )
2152
tcFlags |= wxNO_BORDER;
2156
wxTextCtrl* tc = new wxTextCtrl();
2158
#if defined(__WXMSW__) && !wxPG_NAT_TEXTCTRL_BORDER_ANY
2161
SetupTextCtrlValue(value);
2162
tc->Create(ctrlParent,wxPG_SUBID1,value, p, s,tcFlags);
2164
#if wxPG_NAT_TEXTCTRL_BORDER_ANY
2166
wnd->SetControl(tc);
2171
// Center the control vertically
2172
if ( !hasSpecialSize )
2173
FixPosForTextCtrl(ed, forColumn);
2175
if ( forColumn != 1 )
2179
ed->SetBackgroundColour(m_colSelBack);
2180
ed->SetForegroundColour(m_colSelFore);
2182
tc->SetBackgroundColour(m_colSelBack);
2183
tc->SetForegroundColour(m_colSelFore);
2192
// Set maximum length
2194
tc->SetMaxLength( maxLen );
2196
return (wxWindow*) ed;
2199
// -----------------------------------------------------------------------
2201
wxWindow* wxPropertyGrid::GenerateEditorButton( const wxPoint& pos, const wxSize& sz )
2203
wxPGProperty* selected = GetSelection();
2207
// Decorations are chunky on Mac, and we can't make the button square, so
2208
// do things a bit differently on this platform.
2210
wxPoint p(pos.x+sz.x,
2211
pos.y+wxPG_BUTTON_SIZEDEC-wxPG_NAT_BUTTON_BORDER_Y);
2214
wxButton* but = new wxButton();
2215
but->Create(GetPanel(),wxPG_SUBID2,wxT("..."),p,s,wxWANTS_CHARS);
2217
// Now that we know the size, move to the correct position
2218
p.x = pos.x + sz.x - but->GetSize().x - 2;
2222
wxSize s(sz.y-(wxPG_BUTTON_SIZEDEC*2)+(wxPG_NAT_BUTTON_BORDER_Y*2),
2223
sz.y-(wxPG_BUTTON_SIZEDEC*2)+(wxPG_NAT_BUTTON_BORDER_Y*2));
2225
// Reduce button width to lineheight
2226
if ( s.x > m_lineHeight )
2230
// On wxGTK, take fixed button margins into account
2235
wxPoint p(pos.x+sz.x-s.x,
2236
pos.y+wxPG_BUTTON_SIZEDEC-wxPG_NAT_BUTTON_BORDER_Y);
2238
wxButton* but = new wxButton();
2242
but->Create(GetPanel(),wxPG_SUBID2,wxT("..."),p,s,wxWANTS_CHARS);
2245
wxFont font = GetFont();
2246
font.SetPointSize(font.GetPointSize()-2);
2249
but->SetFont(GetFont());
2253
if ( selected->HasFlag(wxPG_PROP_READONLY) )
2259
// -----------------------------------------------------------------------
2261
wxWindow* wxPropertyGrid::GenerateEditorTextCtrlAndButton( const wxPoint& pos,
2263
wxWindow** psecondary,
2265
wxPGProperty* property )
2267
wxButton* but = (wxButton*)GenerateEditorButton(pos,sz);
2268
*psecondary = (wxWindow*)but;
2270
if ( limitedEditing )
2273
// There is button Show in GenerateEditorTextCtrl as well
2276
return (wxWindow*) NULL;
2281
if ( !property->IsValueUnspecified() )
2282
text = property->GetValueString(property->HasFlag(wxPG_PROP_READONLY)?0:wxPG_EDITABLE_VALUE);
2284
return GenerateEditorTextCtrl(pos,sz,text,but,property->m_maxLen);
2287
// -----------------------------------------------------------------------
2289
void wxPropertyGrid::SetEditorAppearance( const wxPGCell& cell )
2291
wxWindow* editor = GetEditorControl();
2295
// Get old editor appearance
2296
const wxPGCell& oCell = m_editorAppearance;
2297
wxPGProperty* property = GetSelection();
2299
wxTextCtrl* tc = GetEditorTextCtrl();
2302
if ( editor->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)) )
2303
cb = (wxPGComboBox*) editor;
2310
bool changeText = false;
2312
if ( cell.HasText() && !IsEditorFocused() )
2314
tcText = cell.GetText();
2317
else if ( oCell.HasText() )
2319
tcText = GetSelection()->GetValueString(
2320
property->HasFlag(wxPG_PROP_READONLY)?0:wxPG_EDITABLE_VALUE);
2328
// The next line prevents spurious EVT_TEXT from being
2330
SetupTextCtrlValue(tcText);
2331
tc->SetValue(tcText);
2335
cb->SetText(tcText);
2340
// We used to obtain wxVisualAttributes via
2341
// editor->GetDefaultAttributes() here, but that is not
2342
// very consistently implemented in wx2.8, so it is safer
2343
// to just use colours from wxSystemSettings etc.
2345
const wxColour& fgCol = cell.GetFgCol();
2346
if ( wxGDI_IS_OK(fgCol) )
2348
editor->SetForegroundColour(fgCol);
2350
// Set for wxTextCtrl separately to work around bug in wx2.8
2351
// that may not be fixable due to ABI compatibility issues.
2352
if ( tc && tc != editor )
2353
tc->SetForegroundColour(fgCol);
2355
else if ( wxGDI_IS_OK(oCell.GetFgCol()) )
2358
wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
2359
editor->SetForegroundColour(vColFg);
2360
if ( tc && tc != editor )
2361
tc->SetForegroundColour(vColFg);
2364
const wxColour& bgCol = cell.GetBgCol();
2365
if ( wxGDI_IS_OK(bgCol) )
2367
editor->SetBackgroundColour(bgCol);
2368
if ( tc && tc != editor )
2369
tc->SetBackgroundColour(bgCol);
2371
else if ( wxGDI_IS_OK(oCell.GetBgCol()) )
2373
wxColour vColBg = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW);
2374
editor->SetBackgroundColour(vColBg);
2375
if ( tc && tc != editor )
2376
tc->SetBackgroundColour(vColBg);
2379
const wxFont& font = cell.GetFont();
2380
if ( wxGDI_IS_OK(font) )
2382
editor->SetFont(font);
2383
if ( tc && tc != editor )
2386
else if ( wxGDI_IS_OK(oCell.GetFont()) )
2388
wxFont vFont = wxSystemSettings::GetFont(wxSYS_DEFAULT_GUI_FONT);
2389
editor->SetFont(vFont);
2390
if ( tc && tc != editor )
2394
m_editorAppearance.Assign(cell);
2397
// -----------------------------------------------------------------------
2399
wxTextCtrl* wxPropertyGrid::GetEditorTextCtrl() const
2401
wxWindow* wnd = GetEditorControl();
2406
if ( wnd->IsKindOf(CLASSINFO(wxTextCtrl)) )
2407
return wxStaticCast(wnd, wxTextCtrl);
2409
if ( wnd->IsKindOf(CLASSINFO(wxPGOwnerDrawnComboBox)) )
2411
wxPGOwnerDrawnComboBox* cb = wxStaticCast(wnd, wxPGOwnerDrawnComboBox);
2412
return cb->GetTextCtrl();
2418
// -----------------------------------------------------------------------
2420
#if defined(__WXMSW__) && !defined(__WXWINCE__)
2422
bool wxPG_TextCtrl_SetMargins(wxWindow* tc, const wxPoint& margins)
2424
::SendMessage(GetHwndOf(tc),
2425
EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN,
2426
MAKELONG(margins.x, margins.x));
2430
/*#elif defined(__WXGTK20__)
2433
// NOTE: For this to work we need to somehow include gtk devel
2434
// in the bake/makefile.
2437
#include <gtk/gtk.h>
2439
bool wxPG_TextCtrl_SetMargins(wxWindow* tc, const wxPoint& margins)
2442
// NB: This code has been ported from wx2.9 SVN trunk
2445
#if GTK_CHECK_VERSION(2,10,0)
2446
GtkEntry *entry = NULL;
2448
entry = GTK_ENTRY( m_widget );
2453
const GtkBorder* oldBorder = gtk_entry_get_inner_border(entry);
2454
GtkBorder* newBorder;
2458
newBorder = gtk_border_copy(oldBorder);
2462
#if GTK_CHECK_VERSION(2,14,0)
2463
newBorder = gtk_border_new();
2465
newBorder = g_slice_new0(GtkBorder);
2467
// Use some reasonable defaults for initial margins
2468
newBorder->left = 2;
2469
newBorder->right = 2;
2471
// These numbers seem to let the text remain vertically centered
2472
// in common use scenarios when margins.y == -1.
2474
newBorder->bottom = 3;
2477
if ( margins.x != -1 )
2478
newBorder->left = (gint) margins.x;
2480
if ( margins.y != -1 )
2481
newBorder->top = (gint) margins.y;
2483
gtk_entry_set_inner_border(entry, newBorder);
2485
#if GTK_CHECK_VERSION(2,14,0)
2486
gtk_border_free(newBorder);
2488
g_slice_free(GtkBorder, newBorder);
2494
wxUnusedVar(margins);
2501
bool wxPG_TextCtrl_SetMargins(wxWindow* tc, const wxPoint& margins)
2504
wxUnusedVar(margins);
2510
// -----------------------------------------------------------------------
2511
// wxPGEditorDialogAdapter
2512
// -----------------------------------------------------------------------
2514
IMPLEMENT_ABSTRACT_CLASS(wxPGEditorDialogAdapter, wxObject)
2516
bool wxPGEditorDialogAdapter::ShowDialog( wxPropertyGrid* propGrid, wxPGProperty* property )
2518
if ( !propGrid->EditorValidate() )
2521
bool res = DoShowDialog( propGrid, property );
2525
propGrid->ValueChangeInEvent( m_value );
2532
// -----------------------------------------------------------------------
2534
// -----------------------------------------------------------------------
2536
wxPGMultiButton::wxPGMultiButton( wxPropertyGrid* pg, const wxSize& sz )
2537
: wxWindow( pg->GetPanel(), wxPG_SUBID2, wxPoint(-100,-100), wxSize(0, sz.y) ),
2538
m_fullEditorSize(sz), m_buttonsWidth(0)
2540
SetBackgroundColour(pg->GetCellBackgroundColour());
2543
int wxPGMultiButton::GenId( int id ) const
2547
if ( m_buttons.size() )
2548
id = GetButton(m_buttons.size()-1)->GetId() + 1;
2556
void wxPGMultiButton::Add( const wxBitmap& bitmap, int id )
2559
wxSize sz = GetSize();
2560
wxButton* button = new wxBitmapButton( this, id, bitmap, wxPoint(sz.x, 0), wxSize(sz.y, sz.y) );
2561
m_buttons.push_back(button);
2562
int bw = button->GetSize().x;
2563
SetSize(wxSize(sz.x+bw,sz.y));
2564
m_buttonsWidth += bw;
2568
void wxPGMultiButton::Add( const wxString& label, int id )
2571
wxSize sz = GetSize();
2572
wxButton* button = new wxButton( this, id, label, wxPoint(sz.x, 0), wxSize(sz.y, sz.y) );
2573
m_buttons.push_back(button);
2574
int bw = button->GetSize().x;
2575
SetSize(wxSize(sz.x+bw,sz.y));
2576
m_buttonsWidth += bw;
2579
// -----------------------------------------------------------------------