1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/propgrid/propgrid.cpp 
   3 // Purpose:     wxPropertyGrid 
   4 // Author:      Jaakko Salli 
   8 // Copyright:   (c) Jaakko Salli 
   9 // Licence:     wxWindows license 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx/wx.h". 
  13 #include "wx/wxprec.h" 
  23     #include "wx/object.h" 
  25     #include "wx/string.h" 
  28     #include "wx/window.h" 
  31     #include "wx/dcmemory.h" 
  32     #include "wx/button.h" 
  35     #include "wx/cursor.h" 
  36     #include "wx/dialog.h" 
  37     #include "wx/settings.h" 
  38     #include "wx/msgdlg.h" 
  39     #include "wx/choice.h" 
  40     #include "wx/stattext.h" 
  41     #include "wx/scrolwin.h" 
  42     #include "wx/dirdlg.h" 
  44     #include "wx/textdlg.h" 
  45     #include "wx/filedlg.h" 
  46     #include "wx/statusbr.h" 
  52 // This define is necessary to prevent macro clearing 
  53 #define __wxPG_SOURCE_FILE__ 
  55 #include "wx/propgrid/propgrid.h" 
  56 #include "wx/propgrid/editors.h" 
  58 #if wxPG_USE_RENDERER_NATIVE 
  59     #include "wx/renderer.h" 
  62 #include "wx/odcombo.h" 
  65 #include "wx/dcbuffer.h" 
  68     #include "wx/msw/private.h" 
  71 // Two pics for the expand / collapse buttons. 
  72 // Files are not supplied with this project (since it is 
  73 // recommended to use either custom or native rendering). 
  74 // If you want them, get wxTreeMultiCtrl by Jorgen Bodde, 
  75 // and copy xpm files from archive to wxPropertyGrid src directory 
  76 // (and also comment/undef wxPG_ICON_WIDTH in propGrid.h 
  77 // and set wxPG_USE_RENDERER_NATIVE to 0). 
  78 #ifndef wxPG_ICON_WIDTH 
  79   #if defined(__WXMAC__) 
  80     #include "mac_collapse.xpm" 
  81     #include "mac_expand.xpm" 
  82   #elif defined(__WXGTK__) 
  83     #include "linux_collapse.xpm" 
  84     #include "linux_expand.xpm" 
  86     #include "default_collapse.xpm" 
  87     #include "default_expand.xpm" 
  92 //#define wxPG_TEXT_INDENT                4 // For the wxComboControl 
  93 //#define wxPG_ALLOW_CLIPPING             1 // If 1, GetUpdateRegion() in OnPaint event handler is not ignored 
  94 #define wxPG_GUTTER_DIV                 3 // gutter is max(iconwidth/gutter_div,gutter_min) 
  95 #define wxPG_GUTTER_MIN                 3 // gutter before and after image of [+] or [-] 
  96 #define wxPG_YSPACING_MIN               1 
  97 #define wxPG_DEFAULT_VSPACING           2 // This matches .NET propertygrid's value, 
  98                                           // but causes normal combobox to spill out under MSW 
 100 //#define wxPG_OPTIMAL_WIDTH              200 // Arbitrary 
 102 //#define wxPG_MIN_SCROLLBAR_WIDTH        10 // Smallest scrollbar width on any platform 
 103                                            // Must be larger than largest control border 
 107 #define wxPG_DEFAULT_CURSOR             wxNullCursor 
 110 //#define wxPG_NAT_CHOICE_BORDER_ANY   0 
 112 //#define wxPG_HIDER_BUTTON_HEIGHT        25 
 114 #define wxPG_PIXELS_PER_UNIT            m_lineHeight 
 116 #ifdef wxPG_ICON_WIDTH 
 117   #define m_iconHeight m_iconWidth 
 120 //#define wxPG_TOOLTIP_DELAY              1000 
 122 // ----------------------------------------------------------------------- 
 125 void wxPropertyGrid::AutoGetTranslation ( bool enable 
) 
 127     wxPGGlobalVars
->m_autoGetTranslation 
= enable
; 
 130 void wxPropertyGrid::AutoGetTranslation ( bool ) { } 
 133 // ----------------------------------------------------------------------- 
 135 const char wxPropertyGridNameStr
[] = "wxPropertyGrid"; 
 137 // ----------------------------------------------------------------------- 
 138 // Statics in one class for easy destruction. 
 139 // ----------------------------------------------------------------------- 
 141 #include "wx/module.h" 
 143 class wxPGGlobalVarsClassManager 
: public wxModule
 
 145     DECLARE_DYNAMIC_CLASS(wxPGGlobalVarsClassManager
) 
 147     wxPGGlobalVarsClassManager() {} 
 148     virtual bool OnInit() { wxPGGlobalVars 
= new wxPGGlobalVarsClass(); return true; } 
 149     virtual void OnExit() { delete wxPGGlobalVars
; wxPGGlobalVars 
= NULL
; } 
 152 IMPLEMENT_DYNAMIC_CLASS(wxPGGlobalVarsClassManager
, wxModule
) 
 155 // When wxPG is loaded dynamically after the application is already running 
 156 // then the built-in module system won't pick this one up.  Add it manually. 
 157 void wxPGInitResourceModule() 
 159     wxModule
* module = new wxPGGlobalVarsClassManager
; 
 161     wxModule::RegisterModule(module); 
 164 wxPGGlobalVarsClass
* wxPGGlobalVars 
= NULL
; 
 167 wxPGGlobalVarsClass::wxPGGlobalVarsClass() 
 169     wxPGProperty::sm_wxPG_LABEL 
= new wxString(wxPG_LABEL_STRING
); 
 171     m_boolChoices
.Add(_("False")); 
 172     m_boolChoices
.Add(_("True")); 
 174     m_fontFamilyChoices 
= NULL
; 
 176     m_defaultRenderer 
= new wxPGDefaultRenderer(); 
 178     m_autoGetTranslation 
= false; 
 186     // Prepare some shared variants 
 187     m_vEmptyString 
= wxString(); 
 189     m_vMinusOne 
= (long) -1; 
 193     // Prepare cached string constants 
 194     m_strstring 
= wxS("string"); 
 195     m_strlong 
= wxS("long"); 
 196     m_strbool 
= wxS("bool"); 
 197     m_strlist 
= wxS("list"); 
 198     m_strDefaultValue 
= wxS("DefaultValue"); 
 199     m_strMin 
= wxS("Min"); 
 200     m_strMax 
= wxS("Max"); 
 201     m_strUnits 
= wxS("Units"); 
 202     m_strInlineHelp 
= wxS("InlineHelp"); 
 208 wxPGGlobalVarsClass::~wxPGGlobalVarsClass() 
 212     delete m_defaultRenderer
; 
 214     // This will always have one ref 
 215     delete m_fontFamilyChoices
; 
 218     for ( i
=0; i
<m_arrValidators
.size(); i
++ ) 
 219         delete ((wxValidator
*)m_arrValidators
[i
]); 
 223     // Destroy value type class instances. 
 224     wxPGHashMapS2P::iterator vt_it
; 
 226     // Destroy editor class instances. 
 227     // iterate over all the elements in the class 
 228     for( vt_it 
= m_mapEditorClasses
.begin(); vt_it 
!= m_mapEditorClasses
.end(); ++vt_it 
) 
 230         delete ((wxPGEditor
*)vt_it
->second
); 
 233     delete wxPGProperty::sm_wxPG_LABEL
; 
 236 void wxPropertyGridInitGlobalsIfNeeded() 
 240 // ----------------------------------------------------------------------- 
 242 // ----------------------------------------------------------------------- 
 245 // wxPGCanvas acts as a graphics sub-window of the 
 246 // wxScrolledWindow that wxPropertyGrid is. 
 248 class wxPGCanvas 
: public wxPanel
 
 251     wxPGCanvas() : wxPanel() 
 254     virtual ~wxPGCanvas() { } 
 257     void OnMouseMove( wxMouseEvent 
&event 
) 
 259         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 260         pg
->OnMouseMove( event 
); 
 263     void OnMouseClick( wxMouseEvent 
&event 
) 
 265         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 266         pg
->OnMouseClick( event 
); 
 269     void OnMouseUp( wxMouseEvent 
&event 
) 
 271         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 272         pg
->OnMouseUp( event 
); 
 275     void OnMouseRightClick( wxMouseEvent 
&event 
) 
 277         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 278         pg
->OnMouseRightClick( event 
); 
 281     void OnMouseDoubleClick( wxMouseEvent 
&event 
) 
 283         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 284         pg
->OnMouseDoubleClick( event 
); 
 287     void OnKey( wxKeyEvent
& event 
) 
 289         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 293     void OnPaint( wxPaintEvent
& event 
); 
 295     // Always be focussable, even with child windows 
 296     virtual void SetCanFocus(bool WXUNUSED(canFocus
)) 
 297     {  wxPanel::SetCanFocus(true); } 
 301     DECLARE_EVENT_TABLE() 
 302     DECLARE_ABSTRACT_CLASS(wxPGCanvas
) 
 306 IMPLEMENT_ABSTRACT_CLASS(wxPGCanvas
,wxPanel
) 
 308 BEGIN_EVENT_TABLE(wxPGCanvas
, wxPanel
) 
 309     EVT_MOTION(wxPGCanvas::OnMouseMove
) 
 310     EVT_PAINT(wxPGCanvas::OnPaint
) 
 311     EVT_LEFT_DOWN(wxPGCanvas::OnMouseClick
) 
 312     EVT_LEFT_UP(wxPGCanvas::OnMouseUp
) 
 313     EVT_RIGHT_UP(wxPGCanvas::OnMouseRightClick
) 
 314     EVT_LEFT_DCLICK(wxPGCanvas::OnMouseDoubleClick
) 
 315     EVT_KEY_DOWN(wxPGCanvas::OnKey
) 
 319 void wxPGCanvas::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
 321     wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 322     wxASSERT( pg
->IsKindOf(CLASSINFO(wxPropertyGrid
)) ); 
 326     // Don't paint after destruction has begun 
 327     if ( !(pg
->GetInternalFlags() & wxPG_FL_INITIALIZED
) ) 
 330     // Update everything inside the box 
 331     wxRect r 
= GetUpdateRegion().GetBox(); 
 333     // FIXME: This is just a workaround for a bug that causes splitters not 
 334     //        to paint when other windows are being dragged over the grid. 
 335     wxRect fullRect 
= GetRect(); 
 337     r
.width 
= fullRect
.width
; 
 339     // Repaint this rectangle 
 340     pg
->DrawItems( dc
, r
.y
, r
.y 
+ r
.height
, &r 
); 
 342     // We assume that the size set when grid is shown 
 343     // is what is desired. 
 344     pg
->SetInternalFlag(wxPG_FL_GOOD_SIZE_SET
); 
 347 // ----------------------------------------------------------------------- 
 349 // ----------------------------------------------------------------------- 
 351 IMPLEMENT_DYNAMIC_CLASS(wxPropertyGrid
, wxScrolledWindow
) 
 353 BEGIN_EVENT_TABLE(wxPropertyGrid
, wxScrolledWindow
) 
 354   EVT_IDLE(wxPropertyGrid::OnIdle
) 
 355   EVT_MOTION(wxPropertyGrid::OnMouseMoveBottom
) 
 356   EVT_PAINT(wxPropertyGrid::OnPaint
) 
 357   EVT_SIZE(wxPropertyGrid::OnResize
) 
 358   EVT_ENTER_WINDOW(wxPropertyGrid::OnMouseEntry
) 
 359   EVT_LEAVE_WINDOW(wxPropertyGrid::OnMouseEntry
) 
 360   EVT_MOUSE_CAPTURE_CHANGED(wxPropertyGrid::OnCaptureChange
) 
 361   EVT_SCROLLWIN(wxPropertyGrid::OnScrollEvent
) 
 362   EVT_CHILD_FOCUS(wxPropertyGrid::OnChildFocusEvent
) 
 363   EVT_SET_FOCUS(wxPropertyGrid::OnFocusEvent
) 
 364   EVT_KILL_FOCUS(wxPropertyGrid::OnFocusEvent
) 
 365   EVT_SYS_COLOUR_CHANGED(wxPropertyGrid::OnSysColourChanged
) 
 369 // ----------------------------------------------------------------------- 
 371 wxPropertyGrid::wxPropertyGrid() 
 377 // ----------------------------------------------------------------------- 
 379 wxPropertyGrid::wxPropertyGrid( wxWindow 
*parent
, 
 384                                 const wxString
& name 
) 
 388     Create(parent
,id
,pos
,size
,style
,name
); 
 391 // ----------------------------------------------------------------------- 
 393 bool wxPropertyGrid::Create( wxWindow 
*parent
, 
 398                              const wxString
& name 
) 
 401     if ( !(style
&wxBORDER_MASK
) ) 
 402         style 
|= wxSIMPLE_BORDER
; 
 406     // Filter out wxTAB_TRAVERSAL - we will handle TABs manually 
 407     style 
&= ~(wxTAB_TRAVERSAL
); 
 408     style 
|= wxWANTS_CHARS
; 
 410     wxScrolledWindow::Create(parent
,id
,pos
,size
,style
,name
); 
 417 // ----------------------------------------------------------------------- 
 420 // Initialize values to defaults 
 422 void wxPropertyGrid::Init1() 
 424     // Register editor classes, if necessary. 
 425     if ( wxPGGlobalVars
->m_mapEditorClasses
.empty() ) 
 426         wxPropertyGrid::RegisterDefaultEditors(); 
 430     m_wndEditor 
= m_wndEditor2 
= NULL
; 
 434     m_labelEditor 
= NULL
; 
 435     m_labelEditorProperty 
= NULL
; 
 436     m_eventObject 
= this; 
 438     m_sortFunction 
= NULL
; 
 439     m_inDoPropertyChanged 
= 0; 
 440     m_inCommitChangesFromEditor 
= 0; 
 441     m_inDoSelectProperty 
= 0; 
 442     m_permanentValidationFailureBehavior 
= wxPG_VFB_DEFAULT
; 
 448     AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY
, WXK_RIGHT 
); 
 449     AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY
, WXK_DOWN 
); 
 450     AddActionTrigger( wxPG_ACTION_PREV_PROPERTY
, WXK_LEFT 
); 
 451     AddActionTrigger( wxPG_ACTION_PREV_PROPERTY
, WXK_UP 
); 
 452     AddActionTrigger( wxPG_ACTION_EXPAND_PROPERTY
, WXK_RIGHT
); 
 453     AddActionTrigger( wxPG_ACTION_COLLAPSE_PROPERTY
, WXK_LEFT
); 
 454     AddActionTrigger( wxPG_ACTION_CANCEL_EDIT
, WXK_ESCAPE 
); 
 455     AddActionTrigger( wxPG_ACTION_PRESS_BUTTON
, WXK_DOWN
, wxMOD_ALT 
); 
 456     AddActionTrigger( wxPG_ACTION_PRESS_BUTTON
, WXK_F4 
); 
 458     m_coloursCustomized 
= 0; 
 463 #if wxPG_DOUBLE_BUFFER 
 464     m_doubleBuffer 
= NULL
; 
 467 #ifndef wxPG_ICON_WIDTH 
 473     m_iconWidth 
= wxPG_ICON_WIDTH
; 
 478     m_gutterWidth 
= wxPG_GUTTER_MIN
; 
 479     m_subgroup_extramargin 
= 10; 
 483     m_width 
= m_height 
= 0; 
 485     m_commonValues
.push_back(new wxPGCommonValue(_("Unspecified"), wxPGGlobalVars
->m_defaultRenderer
) ); 
 488     m_chgInfo_changedProperty 
= NULL
; 
 491 // ----------------------------------------------------------------------- 
 494 // Initialize after parent etc. set 
 496 void wxPropertyGrid::Init2() 
 498     wxASSERT( !(m_iFlags 
& wxPG_FL_INITIALIZED 
) ); 
 501    // Smaller controls on Mac 
 502    SetWindowVariant(wxWINDOW_VARIANT_SMALL
); 
 505     // Now create state, if one didn't exist already 
 506     // (wxPropertyGridManager might have created it for us). 
 509         m_pState 
= CreateState(); 
 510         m_pState
->m_pPropGrid 
= this; 
 511         m_iFlags 
|= wxPG_FL_CREATEDSTATE
; 
 514     if ( !(m_windowStyle 
& wxPG_SPLITTER_AUTO_CENTER
) ) 
 515         m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
 517     if ( m_windowStyle 
& wxPG_HIDE_CATEGORIES 
) 
 519         m_pState
->InitNonCatMode(); 
 521         m_pState
->m_properties 
= m_pState
->m_abcArray
; 
 524     GetClientSize(&m_width
,&m_height
); 
 526 #ifndef wxPG_ICON_WIDTH 
 527     // create two bitmap nodes for drawing 
 528     m_expandbmp 
= new wxBitmap(expand_xpm
); 
 529     m_collbmp 
= new wxBitmap(collapse_xpm
); 
 531     // calculate average font height for bitmap centering 
 533     m_iconWidth 
= m_expandbmp
->GetWidth(); 
 534     m_iconHeight 
= m_expandbmp
->GetHeight(); 
 537     m_curcursor 
= wxCURSOR_ARROW
; 
 538     m_cursorSizeWE 
= new wxCursor( wxCURSOR_SIZEWE 
); 
 540     // adjust bitmap icon y position so they are centered 
 541     m_vspacing 
= wxPG_DEFAULT_VSPACING
; 
 543     CalculateFontAndBitmapStuff( wxPG_DEFAULT_VSPACING 
); 
 545     // Allocate cell datas indirectly by calling setter 
 546     m_propertyDefaultCell
.SetBgCol(*wxBLACK
); 
 547     m_categoryDefaultCell
.SetBgCol(*wxBLACK
); 
 551     // This helps with flicker 
 552     SetBackgroundStyle( wxBG_STYLE_CUSTOM 
); 
 554     // Hook the top-level parent 
 558     OnTLPChanging(::wxGetTopLevelParent(this)); 
 560     // set virtual size to this window size 
 561     wxSize wndsize 
= GetSize(); 
 562     SetVirtualSize(wndsize
.GetWidth(), wndsize
.GetWidth()); 
 564     m_timeCreated 
= ::wxGetLocalTimeMillis(); 
 566     m_canvas 
= new wxPGCanvas(); 
 567     m_canvas
->Create(this, 1, wxPoint(0, 0), GetClientSize(), 
 568                      wxWANTS_CHARS 
| wxCLIP_CHILDREN
); 
 569     m_canvas
->SetBackgroundStyle( wxBG_STYLE_CUSTOM 
); 
 571     m_iFlags 
|= wxPG_FL_INITIALIZED
; 
 573     m_ncWidth 
= wndsize
.GetWidth(); 
 575     // Need to call OnResize handler or size given in constructor/Create 
 577     wxSizeEvent 
sizeEvent(wndsize
,0); 
 581 // ----------------------------------------------------------------------- 
 583 wxPropertyGrid::~wxPropertyGrid() 
 587     DoSelectProperty(NULL
, wxPG_SEL_NOVALIDATE
|wxPG_SEL_DONT_SEND_EVENT
); 
 589     // This should do prevent things from going too badly wrong 
 590     m_iFlags 
&= ~(wxPG_FL_INITIALIZED
); 
 592     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
 593         m_canvas
->ReleaseMouse(); 
 595     // Call with NULL to disconnect event handling 
 598     wxASSERT_MSG( !IsEditorsValueModified(), 
 599                   wxS("Most recent change in property editor was lost!!! ") 
 600                   wxS("(if you don't want this to happen, close your frames ") 
 601                   wxS("and dialogs using Close(false).)") ); 
 603 #if wxPG_DOUBLE_BUFFER 
 604     if ( m_doubleBuffer 
) 
 605         delete m_doubleBuffer
; 
 608     if ( m_iFlags 
& wxPG_FL_CREATEDSTATE 
) 
 611     delete m_cursorSizeWE
; 
 613 #ifndef wxPG_ICON_WIDTH 
 618     // Delete common value records 
 619     for ( i
=0; i
<m_commonValues
.size(); i
++ ) 
 621         delete GetCommonValue(i
); 
 625 // ----------------------------------------------------------------------- 
 627 bool wxPropertyGrid::Destroy() 
 629     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
 630         m_canvas
->ReleaseMouse(); 
 632     return wxScrolledWindow::Destroy(); 
 635 // ----------------------------------------------------------------------- 
 637 wxPropertyGridPageState
* wxPropertyGrid::CreateState() const 
 639     return new wxPropertyGridPageState(); 
 642 // ----------------------------------------------------------------------- 
 643 // wxPropertyGrid overridden wxWindow methods 
 644 // ----------------------------------------------------------------------- 
 646 void wxPropertyGrid::SetWindowStyleFlag( long style 
) 
 648     long old_style 
= m_windowStyle
; 
 650     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
 652         wxASSERT( m_pState 
); 
 654         if ( !(style 
& wxPG_HIDE_CATEGORIES
) && (old_style 
& wxPG_HIDE_CATEGORIES
) ) 
 657             EnableCategories( true ); 
 659         else if ( (style 
& wxPG_HIDE_CATEGORIES
) && !(old_style 
& wxPG_HIDE_CATEGORIES
) ) 
 661         // Disable categories 
 662             EnableCategories( false ); 
 664         if ( !(old_style 
& wxPG_AUTO_SORT
) && (style 
& wxPG_AUTO_SORT
) ) 
 670                 PrepareAfterItemsAdded(); 
 672                 m_pState
->m_itemsAdded 
= 1; 
 674     #if wxPG_SUPPORT_TOOLTIPS 
 675         if ( !(old_style 
& wxPG_TOOLTIPS
) && (style 
& wxPG_TOOLTIPS
) ) 
 681             wxToolTip* tooltip = new wxToolTip ( wxEmptyString ); 
 682             SetToolTip ( tooltip ); 
 683             tooltip->SetDelay ( wxPG_TOOLTIP_DELAY ); 
 686         else if ( (old_style 
& wxPG_TOOLTIPS
) && !(style 
& wxPG_TOOLTIPS
) ) 
 691             m_canvas
->SetToolTip( NULL 
); 
 696     wxScrolledWindow::SetWindowStyleFlag ( style 
); 
 698     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
 700         if ( (old_style 
& wxPG_HIDE_MARGIN
) != (style 
& wxPG_HIDE_MARGIN
) ) 
 702             CalculateFontAndBitmapStuff( m_vspacing 
); 
 708 // ----------------------------------------------------------------------- 
 710 void wxPropertyGrid::Freeze() 
 714         wxScrolledWindow::Freeze(); 
 719 // ----------------------------------------------------------------------- 
 721 void wxPropertyGrid::Thaw() 
 727         wxScrolledWindow::Thaw(); 
 728         RecalculateVirtualSize(); 
 729     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
 733         // Force property re-selection 
 734         // NB: We must copy the selection. 
 735         wxArrayPGProperty selection 
= m_pState
->m_selection
; 
 736         DoSetSelection(selection
, wxPG_SEL_FORCE
); 
 740 // ----------------------------------------------------------------------- 
 742 bool wxPropertyGrid::DoAddToSelection( wxPGProperty
* prop
, int selFlags 
) 
 744     wxCHECK( prop
, false ); 
 746     if ( !(GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION
) ) 
 747         return DoSelectProperty(prop
, selFlags
); 
 749     wxArrayPGProperty
& selection 
= m_pState
->m_selection
; 
 751     if ( !selection
.size() ) 
 753         return DoSelectProperty(prop
, selFlags
); 
 757         // For categories, only one can be selected at a time 
 758         if ( prop
->IsCategory() || selection
[0]->IsCategory() ) 
 761         selection
.push_back(prop
); 
 763         if ( !(selFlags 
& wxPG_SEL_DONT_SEND_EVENT
) ) 
 765             SendEvent( wxEVT_PG_SELECTED
, prop
, NULL 
); 
 774 // ----------------------------------------------------------------------- 
 776 bool wxPropertyGrid::DoRemoveFromSelection( wxPGProperty
* prop
, int selFlags 
) 
 778     wxCHECK( prop
, false ); 
 781     wxArrayPGProperty
& selection 
= m_pState
->m_selection
; 
 782     if ( selection
.size() <= 1 ) 
 784         res 
= DoSelectProperty(NULL
, selFlags
); 
 788         m_pState
->DoRemoveFromSelection(prop
); 
 796 // ----------------------------------------------------------------------- 
 798 bool wxPropertyGrid::DoSelectAndEdit( wxPGProperty
* prop
, 
 799                                       unsigned int colIndex
, 
 800                                       unsigned int selFlags 
) 
 803     // NB: Enable following if label editor background colour is 
 804     //     ever changed to any other than m_colSelBack. 
 806     // We use this workaround to prevent visible flicker when editing 
 807     // a cell. Atleast on wxMSW, there is a difficult to find 
 808     // (and perhaps prevent) redraw somewhere between making property 
 809     // selected and enabling label editing. 
 811     //wxColour prevColSelBack = m_colSelBack; 
 812     //m_colSelBack = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ); 
 818         res 
= DoSelectProperty(prop
, selFlags
); 
 823         DoClearSelection(false, wxPG_SEL_NO_REFRESH
); 
 825         if ( m_pState
->m_editableColumns
.Index(colIndex
) == wxNOT_FOUND 
) 
 827             res 
= DoAddToSelection(prop
, selFlags
); 
 831             res 
= DoAddToSelection(prop
, selFlags
|wxPG_SEL_NO_REFRESH
); 
 833             DoBeginLabelEdit(colIndex
, selFlags
); 
 837     //m_colSelBack = prevColSelBack; 
 841 // ----------------------------------------------------------------------- 
 843 bool wxPropertyGrid::AddToSelectionFromInputEvent( wxPGProperty
* prop
, 
 844                                                    unsigned int colIndex
, 
 845                                                    wxMouseEvent
* mouseEvent
, 
 848     bool alreadySelected 
= m_pState
->DoIsPropertySelected(prop
); 
 850     bool addToExistingSelection
; 
 852     if ( GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION 
) 
 856             if ( mouseEvent
->GetEventType() == wxEVT_RIGHT_DOWN 
|| 
 857                  mouseEvent
->GetEventType() == wxEVT_RIGHT_UP 
) 
 859                 // Allow right-click for context menu without 
 860                 // disturbing the selection. 
 861                 if ( GetSelectedProperties().size() <= 1 || 
 863                     return DoSelectAndEdit(prop
, colIndex
, selFlags
); 
 868                 addToExistingSelection 
= mouseEvent
->ShiftDown(); 
 873             addToExistingSelection 
= false; 
 878         addToExistingSelection 
= false; 
 881     if ( addToExistingSelection 
) 
 883         if ( !alreadySelected 
) 
 885             res 
= DoAddToSelection(prop
, selFlags
); 
 887         else if ( GetSelectedProperties().size() > 1 ) 
 889             res 
= DoRemoveFromSelection(prop
, selFlags
); 
 894         res 
= DoSelectAndEdit(prop
, colIndex
, selFlags
); 
 900 // ----------------------------------------------------------------------- 
 902 void wxPropertyGrid::DoSetSelection( const wxArrayPGProperty
& newSelection
, 
 905     if ( newSelection
.size() > 0 ) 
 907         if ( !DoSelectProperty(newSelection
[0], selFlags
) ) 
 912         DoClearSelection(false, selFlags
); 
 915     for ( unsigned int i 
= 1; i 
< newSelection
.size(); i
++ ) 
 917         DoAddToSelection(newSelection
[i
], selFlags
); 
 923 // ----------------------------------------------------------------------- 
 925 void wxPropertyGrid::DoBeginLabelEdit( unsigned int colIndex
, 
 928     wxPGProperty
* selected 
= GetSelection(); 
 929     wxCHECK_RET(selected
, wxT("No property selected")); 
 930     wxCHECK_RET(colIndex 
!= 1, wxT("Do not use this for column 1")); 
 932     if ( !(selFlags 
& wxPG_SEL_DONT_SEND_EVENT
) ) 
 934         if ( SendEvent( wxEVT_PG_LABEL_EDIT_BEGIN
, 
 941     const wxPGCell
* cell 
= NULL
; 
 942     if ( selected
->HasCell(colIndex
) ) 
 944         cell 
= &selected
->GetCell(colIndex
); 
 945         if ( !cell
->HasText() && colIndex 
== 0 ) 
 946             text 
= selected
->GetLabel(); 
 952             text 
= selected
->GetLabel(); 
 954             cell 
= &selected
->GetOrCreateCell(colIndex
); 
 957     if ( cell 
&& cell
->HasText() ) 
 958         text 
= cell
->GetText(); 
 960     DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE
);  // send event 
 962     m_selColumn 
= colIndex
; 
 964     wxRect r 
= GetEditorWidgetRect(selected
, m_selColumn
); 
 966     wxWindow
* tc 
= GenerateEditorTextCtrl(r
.GetPosition(), 
 974     wxWindowID id 
= tc
->GetId(); 
 975     tc
->Connect(id
, wxEVT_COMMAND_TEXT_ENTER
, 
 976         wxCommandEventHandler(wxPropertyGrid::OnLabelEditorEnterPress
), 
 978     tc
->Connect(id
, wxEVT_KEY_DOWN
, 
 979         wxKeyEventHandler(wxPropertyGrid::OnLabelEditorKeyPress
), 
 984     m_labelEditor 
= wxStaticCast(tc
, wxTextCtrl
); 
 985     m_labelEditorProperty 
= selected
; 
 988 // ----------------------------------------------------------------------- 
 991 wxPropertyGrid::OnLabelEditorEnterPress( wxCommandEvent
& WXUNUSED(event
) ) 
 993     DoEndLabelEdit(true); 
 996 // ----------------------------------------------------------------------- 
 998 void wxPropertyGrid::OnLabelEditorKeyPress( wxKeyEvent
& event 
) 
1000     int keycode 
= event
.GetKeyCode(); 
1002     if ( keycode 
== WXK_ESCAPE 
) 
1004         DoEndLabelEdit(false); 
1012 // ----------------------------------------------------------------------- 
1014 void wxPropertyGrid::DoEndLabelEdit( bool commit
, int selFlags 
) 
1016     if ( !m_labelEditor 
) 
1019     wxPGProperty
* prop 
= m_labelEditorProperty
; 
1024         if ( !(selFlags 
& wxPG_SEL_DONT_SEND_EVENT
) ) 
1026             // wxPG_SEL_NOVALIDATE is passed correctly in selFlags 
1027             if ( SendEvent( wxEVT_PG_LABEL_EDIT_ENDING
, 
1028                             prop
, NULL
, selFlags
, 
1033         wxString text 
= m_labelEditor
->GetValue(); 
1034         wxPGCell
* cell 
= NULL
; 
1035         if ( prop
->HasCell(m_selColumn
) ) 
1037             cell 
= &prop
->GetCell(m_selColumn
); 
1041             if ( m_selColumn 
== 0 ) 
1042                 prop
->SetLabel(text
); 
1044                 cell 
= &prop
->GetOrCreateCell(m_selColumn
); 
1048             cell
->SetText(text
); 
1053     DestroyEditorWnd(m_labelEditor
); 
1054     m_labelEditor 
= NULL
; 
1055     m_labelEditorProperty 
= NULL
; 
1060 // ----------------------------------------------------------------------- 
1062 void wxPropertyGrid::SetExtraStyle( long exStyle 
) 
1064     if ( exStyle 
& wxPG_EX_NATIVE_DOUBLE_BUFFERING 
) 
1066 #if defined(__WXMSW__) 
1069         // Don't use WS_EX_COMPOSITED just now. 
1072         if ( m_iFlags & wxPG_FL_IN_MANAGER ) 
1073             hWnd = (HWND)GetParent()->GetHWND(); 
1075             hWnd = (HWND)GetHWND(); 
1077         ::SetWindowLong( hWnd, GWL_EXSTYLE, 
1078                          ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED ); 
1081 //#elif defined(__WXGTK20__) 
1083         // Only apply wxPG_EX_NATIVE_DOUBLE_BUFFERING if the window 
1084         // truly was double-buffered. 
1085         if ( !this->IsDoubleBuffered() ) 
1087             exStyle 
&= ~(wxPG_EX_NATIVE_DOUBLE_BUFFERING
); 
1091         #if wxPG_DOUBLE_BUFFER 
1092             delete m_doubleBuffer
; 
1093             m_doubleBuffer 
= NULL
; 
1098     wxScrolledWindow::SetExtraStyle( exStyle 
); 
1100     if ( exStyle 
& wxPG_EX_INIT_NOCAT 
) 
1101         m_pState
->InitNonCatMode(); 
1103     if ( exStyle 
& wxPG_EX_HELP_AS_TOOLTIPS 
) 
1104         m_windowStyle 
|= wxPG_TOOLTIPS
; 
1107     wxPGGlobalVars
->m_extraStyle 
= exStyle
; 
1110 // ----------------------------------------------------------------------- 
1112 // returns the best acceptable minimal size 
1113 wxSize 
wxPropertyGrid::DoGetBestSize() const 
1115     int lineHeight 
= wxMax(15, m_lineHeight
); 
1117     // don't make the grid too tall (limit height to 10 items) but don't 
1118     // make it too small neither 
1119     int numLines 
= wxMin
 
1121                     wxMax(m_pState
->m_properties
->GetChildCount(), 3), 
1125     const wxSize sz 
= wxSize(60, lineHeight
*numLines 
+ 40); 
1130 // ----------------------------------------------------------------------- 
1132 void wxPropertyGrid::OnTLPChanging( wxWindow
* newTLP 
) 
1134     wxLongLong currentTime 
= ::wxGetLocalTimeMillis(); 
1137     // Parent changed so let's redetermine and re-hook the 
1138     // correct top-level window. 
1141         m_tlp
->Disconnect( wxEVT_CLOSE_WINDOW
, 
1142                            wxCloseEventHandler(wxPropertyGrid::OnTLPClose
), 
1144         m_tlpClosed 
= m_tlp
; 
1145         m_tlpClosedTime 
= currentTime
; 
1150         // Only accept new tlp if same one was not just dismissed. 
1151         if ( newTLP 
!= m_tlpClosed 
|| 
1152              m_tlpClosedTime
+250 < currentTime 
) 
1154             newTLP
->Connect( wxEVT_CLOSE_WINDOW
, 
1155                              wxCloseEventHandler(wxPropertyGrid::OnTLPClose
), 
1168 // ----------------------------------------------------------------------- 
1170 void wxPropertyGrid::OnTLPClose( wxCloseEvent
& event 
) 
1172     // ClearSelection forces value validation/commit. 
1173     if ( event
.CanVeto() && !DoClearSelection() ) 
1179     // Ok, it can close, set tlp pointer to NULL. Some other event 
1180     // handler can of course veto the close, but our OnIdle() should 
1181     // then be able to regain the tlp pointer. 
1182     OnTLPChanging(NULL
); 
1187 // ----------------------------------------------------------------------- 
1189 bool wxPropertyGrid::Reparent( wxWindowBase 
*newParent 
) 
1191     OnTLPChanging((wxWindow
*)newParent
); 
1193     bool res 
= wxScrolledWindow::Reparent(newParent
); 
1198 // ----------------------------------------------------------------------- 
1199 // wxPropertyGrid Font and Colour Methods 
1200 // ----------------------------------------------------------------------- 
1202 void wxPropertyGrid::CalculateFontAndBitmapStuff( int vspacing 
) 
1206     m_captionFont 
= wxScrolledWindow::GetFont(); 
1208     GetTextExtent(wxS("jG"), &x
, &y
, 0, 0, &m_captionFont
); 
1209     m_subgroup_extramargin 
= x 
+ (x
/2); 
1212 #if wxPG_USE_RENDERER_NATIVE 
1213     m_iconWidth 
= wxPG_ICON_WIDTH
; 
1214 #elif wxPG_ICON_WIDTH 
1216     m_iconWidth 
= (m_fontHeight 
* wxPG_ICON_WIDTH
) / 13; 
1217     if ( m_iconWidth 
< 5 ) m_iconWidth 
= 5; 
1218     else if ( !(m_iconWidth 
& 0x01) ) m_iconWidth
++; // must be odd 
1222     m_gutterWidth 
= m_iconWidth 
/ wxPG_GUTTER_DIV
; 
1223     if ( m_gutterWidth 
< wxPG_GUTTER_MIN 
) 
1224         m_gutterWidth 
= wxPG_GUTTER_MIN
; 
1227     if ( vspacing 
<= 1 ) vdiv 
= 12; 
1228     else if ( vspacing 
>= 3 ) vdiv 
= 3; 
1230     m_spacingy 
= m_fontHeight 
/ vdiv
; 
1231     if ( m_spacingy 
< wxPG_YSPACING_MIN 
) 
1232         m_spacingy 
= wxPG_YSPACING_MIN
; 
1235     if ( !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
1236         m_marginWidth 
= m_gutterWidth
*2 + m_iconWidth
; 
1238     m_captionFont
.SetWeight(wxBOLD
); 
1239     GetTextExtent(wxS("jG"), &x
, &y
, 0, 0, &m_captionFont
); 
1241     m_lineHeight 
= m_fontHeight
+(2*m_spacingy
)+1; 
1244     m_buttonSpacingY 
= (m_lineHeight 
- m_iconHeight
) / 2; 
1245     if ( m_buttonSpacingY 
< 0 ) m_buttonSpacingY 
= 0; 
1248         m_pState
->CalculateFontAndBitmapStuff(vspacing
); 
1250     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
1251         RecalculateVirtualSize(); 
1253     InvalidateBestSize(); 
1256 // ----------------------------------------------------------------------- 
1258 void wxPropertyGrid::OnSysColourChanged( wxSysColourChangedEvent 
&WXUNUSED(event
) ) 
1264 // ----------------------------------------------------------------------- 
1266 static wxColour 
wxPGAdjustColour(const wxColour
& src
, int ra
, 
1267                                  int ga 
= 1000, int ba 
= 1000, 
1268                                  bool forceDifferent 
= false) 
1275     // Recursion guard (allow 2 max) 
1276     static int isinside 
= 0; 
1278     wxCHECK_MSG( isinside 
< 3, 
1280                  wxT("wxPGAdjustColour should not be recursively called more than once") ); 
1285     int g 
= src
.Green(); 
1288     if ( r2
>255 ) r2 
= 255; 
1289     else if ( r2
<0) r2 
= 0; 
1291     if ( g2
>255 ) g2 
= 255; 
1292     else if ( g2
<0) g2 
= 0; 
1294     if ( b2
>255 ) b2 
= 255; 
1295     else if ( b2
<0) b2 
= 0; 
1297     // Make sure they are somewhat different 
1298     if ( forceDifferent 
&& (abs((r
+g
+b
)-(r2
+g2
+b2
)) < abs(ra
/2)) ) 
1299         dst 
= wxPGAdjustColour(src
,-(ra
*2)); 
1301         dst 
= wxColour(r2
,g2
,b2
); 
1303     // Recursion guard (allow 2 max) 
1310 static int wxPGGetColAvg( const wxColour
& col 
) 
1312     return (col
.Red() + col
.Green() + col
.Blue()) / 3; 
1316 void wxPropertyGrid::RegainColours() 
1318     if ( !(m_coloursCustomized 
& 0x0002) ) 
1320         wxColour col 
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE 
); 
1322         // Make sure colour is dark enough 
1324         int colDec 
= wxPGGetColAvg(col
) - 230; 
1326         int colDec 
= wxPGGetColAvg(col
) - 200; 
1329             m_colCapBack 
= wxPGAdjustColour(col
,-colDec
); 
1332         m_categoryDefaultCell
.GetData()->SetBgCol(m_colCapBack
); 
1335     if ( !(m_coloursCustomized 
& 0x0001) ) 
1336         m_colMargin 
= m_colCapBack
; 
1338     if ( !(m_coloursCustomized 
& 0x0004) ) 
1345         wxColour capForeCol 
= wxPGAdjustColour(m_colCapBack
,colDec
,5000,5000,true); 
1346         m_colCapFore 
= capForeCol
; 
1347         m_categoryDefaultCell
.GetData()->SetFgCol(capForeCol
); 
1350     if ( !(m_coloursCustomized 
& 0x0008) ) 
1352         wxColour bgCol 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
1353         m_colPropBack 
= bgCol
; 
1354         m_propertyDefaultCell
.GetData()->SetBgCol(bgCol
); 
1357     if ( !(m_coloursCustomized 
& 0x0010) ) 
1359         wxColour fgCol 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
1360         m_colPropFore 
= fgCol
; 
1361         m_propertyDefaultCell
.GetData()->SetFgCol(fgCol
); 
1364     if ( !(m_coloursCustomized 
& 0x0020) ) 
1365         m_colSelBack 
= wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT 
); 
1367     if ( !(m_coloursCustomized 
& 0x0040) ) 
1368         m_colSelFore 
= wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
); 
1370     if ( !(m_coloursCustomized 
& 0x0080) ) 
1371         m_colLine 
= m_colCapBack
; 
1373     if ( !(m_coloursCustomized 
& 0x0100) ) 
1374         m_colDisPropFore 
= m_colCapFore
; 
1376     m_colEmptySpace 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
1379 // ----------------------------------------------------------------------- 
1381 void wxPropertyGrid::ResetColours() 
1383     m_coloursCustomized 
= 0; 
1390 // ----------------------------------------------------------------------- 
1392 bool wxPropertyGrid::SetFont( const wxFont
& font 
) 
1394     // Must disable active editor. 
1397     bool res 
= wxScrolledWindow::SetFont( font 
); 
1398     if ( res 
&& GetParent()) // may not have been Create()ed yet 
1400         CalculateFontAndBitmapStuff( m_vspacing 
); 
1407 // ----------------------------------------------------------------------- 
1409 void wxPropertyGrid::SetLineColour( const wxColour
& col 
) 
1412     m_coloursCustomized 
|= 0x80; 
1416 // ----------------------------------------------------------------------- 
1418 void wxPropertyGrid::SetMarginColour( const wxColour
& col 
) 
1421     m_coloursCustomized 
|= 0x01; 
1425 // ----------------------------------------------------------------------- 
1427 void wxPropertyGrid::SetCellBackgroundColour( const wxColour
& col 
) 
1429     m_colPropBack 
= col
; 
1430     m_coloursCustomized 
|= 0x08; 
1432     m_propertyDefaultCell
.GetData()->SetBgCol(col
); 
1437 // ----------------------------------------------------------------------- 
1439 void wxPropertyGrid::SetCellTextColour( const wxColour
& col 
) 
1441     m_colPropFore 
= col
; 
1442     m_coloursCustomized 
|= 0x10; 
1444     m_propertyDefaultCell
.GetData()->SetFgCol(col
); 
1449 // ----------------------------------------------------------------------- 
1451 void wxPropertyGrid::SetEmptySpaceColour( const wxColour
& col 
) 
1453     m_colEmptySpace 
= col
; 
1458 // ----------------------------------------------------------------------- 
1460 void wxPropertyGrid::SetCellDisabledTextColour( const wxColour
& col 
) 
1462     m_colDisPropFore 
= col
; 
1463     m_coloursCustomized 
|= 0x100; 
1467 // ----------------------------------------------------------------------- 
1469 void wxPropertyGrid::SetSelectionBackgroundColour( const wxColour
& col 
) 
1472     m_coloursCustomized 
|= 0x20; 
1476 // ----------------------------------------------------------------------- 
1478 void wxPropertyGrid::SetSelectionTextColour( const wxColour
& col 
) 
1481     m_coloursCustomized 
|= 0x40; 
1485 // ----------------------------------------------------------------------- 
1487 void wxPropertyGrid::SetCaptionBackgroundColour( const wxColour
& col 
) 
1490     m_coloursCustomized 
|= 0x02; 
1492     m_categoryDefaultCell
.GetData()->SetBgCol(col
); 
1497 // ----------------------------------------------------------------------- 
1499 void wxPropertyGrid::SetCaptionTextColour( const wxColour
& col 
) 
1502     m_coloursCustomized 
|= 0x04; 
1504     m_categoryDefaultCell
.GetData()->SetFgCol(col
); 
1509 // ----------------------------------------------------------------------- 
1510 // wxPropertyGrid property adding and removal 
1511 // ----------------------------------------------------------------------- 
1513 void wxPropertyGrid::PrepareAfterItemsAdded() 
1515     if ( !m_pState 
|| !m_pState
->m_itemsAdded 
) return; 
1517     m_pState
->m_itemsAdded 
= 0; 
1519     if ( m_windowStyle 
& wxPG_AUTO_SORT 
) 
1520         Sort(wxPG_SORT_TOP_LEVEL_ONLY
); 
1522     RecalculateVirtualSize(); 
1525 // ----------------------------------------------------------------------- 
1526 // wxPropertyGrid property operations 
1527 // ----------------------------------------------------------------------- 
1529 bool wxPropertyGrid::EnsureVisible( wxPGPropArg id 
) 
1531     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) 
1535     bool changed 
= false; 
1537     // Is it inside collapsed section? 
1538     if ( !p
->IsVisible() ) 
1541         wxPGProperty
* parent 
= p
->GetParent(); 
1542         wxPGProperty
* grandparent 
= parent
->GetParent(); 
1544         if ( grandparent 
&& grandparent 
!= m_pState
->m_properties 
) 
1545             Expand( grandparent 
); 
1553     GetViewStart(&vx
,&vy
); 
1554     vy
*=wxPG_PIXELS_PER_UNIT
; 
1560         Scroll(vx
, y
/wxPG_PIXELS_PER_UNIT 
); 
1561         m_iFlags 
|= wxPG_FL_SCROLLED
; 
1564     else if ( (y
+m_lineHeight
) > (vy
+m_height
) ) 
1566         Scroll(vx
, (y
-m_height
+(m_lineHeight
*2))/wxPG_PIXELS_PER_UNIT 
); 
1567         m_iFlags 
|= wxPG_FL_SCROLLED
; 
1577 // ----------------------------------------------------------------------- 
1578 // wxPropertyGrid helper methods called by properties 
1579 // ----------------------------------------------------------------------- 
1581 // Control font changer helper. 
1582 void wxPropertyGrid::SetCurControlBoldFont() 
1584     wxASSERT( m_wndEditor 
); 
1585     m_wndEditor
->SetFont( m_captionFont 
); 
1588 // ----------------------------------------------------------------------- 
1590 wxPoint 
wxPropertyGrid::GetGoodEditorDialogPosition( wxPGProperty
* p
, 
1593 #if wxPG_SMALL_SCREEN 
1594     // On small-screen devices, always show dialogs with default position and size. 
1595     return wxDefaultPosition
; 
1597     int splitterX 
= GetSplitterPosition(); 
1601     wxCHECK_MSG( y 
>= 0, wxPoint(-1,-1), wxT("invalid y?") ); 
1603     ImprovedClientToScreen( &x
, &y 
); 
1605     int sw 
= wxSystemSettings::GetMetric( ::wxSYS_SCREEN_X 
); 
1606     int sh 
= wxSystemSettings::GetMetric( ::wxSYS_SCREEN_Y 
); 
1613         new_x 
= x 
+ (m_width
-splitterX
) - sz
.x
; 
1623         new_y 
= y 
+ m_lineHeight
; 
1625     return wxPoint(new_x
,new_y
); 
1629 // ----------------------------------------------------------------------- 
1631 wxString
& wxPropertyGrid::ExpandEscapeSequences( wxString
& dst_str
, wxString
& src_str 
) 
1633     if ( src_str
.length() == 0 ) 
1639     bool prev_is_slash 
= false; 
1641     wxString::const_iterator i 
= src_str
.begin(); 
1645     for ( ; i 
!= src_str
.end(); ++i 
) 
1649         if ( a 
!= wxS('\\') ) 
1651             if ( !prev_is_slash 
) 
1657                 if ( a 
== wxS('n') ) 
1660                     dst_str 
<< wxS('\n'); 
1662                     dst_str 
<< wxS('\n'); 
1665                 else if ( a 
== wxS('t') ) 
1666                     dst_str 
<< wxS('\t'); 
1670             prev_is_slash 
= false; 
1674             if ( prev_is_slash 
) 
1676                 dst_str 
<< wxS('\\'); 
1677                 prev_is_slash 
= false; 
1681                 prev_is_slash 
= true; 
1688 // ----------------------------------------------------------------------- 
1690 wxString
& wxPropertyGrid::CreateEscapeSequences( wxString
& dst_str
, wxString
& src_str 
) 
1692     if ( src_str
.length() == 0 ) 
1698     wxString::const_iterator i 
= src_str
.begin(); 
1699     wxUniChar prev_a 
= wxS('\0'); 
1703     for ( ; i 
!= src_str
.end(); ++i 
) 
1707         if ( a 
>= wxS(' ') ) 
1709             // This surely is not something that requires an escape sequence. 
1714             // This might need... 
1715             if ( a 
== wxS('\r')  ) 
1717                 // DOS style line end. 
1718                 // Already taken care below 
1720             else if ( a 
== wxS('\n') ) 
1721                 // UNIX style line end. 
1722                 dst_str 
<< wxS("\\n"); 
1723             else if ( a 
== wxS('\t') ) 
1725                 dst_str 
<< wxS('\t'); 
1728                 //wxLogDebug(wxT("WARNING: Could not create escape sequence for character #%i"),(int)a); 
1738 // ----------------------------------------------------------------------- 
1740 wxPGProperty
* wxPropertyGrid::DoGetItemAtY( int y 
) const 
1747     return m_pState
->m_properties
->GetItemAtY(y
, m_lineHeight
, &a
); 
1750 // ----------------------------------------------------------------------- 
1751 // wxPropertyGrid graphics related methods 
1752 // ----------------------------------------------------------------------- 
1754 void wxPropertyGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
1758     // Update everything inside the box 
1759     wxRect r 
= GetUpdateRegion().GetBox(); 
1761     dc
.SetPen(m_colEmptySpace
); 
1762     dc
.SetBrush(m_colEmptySpace
); 
1763     dc
.DrawRectangle(r
); 
1766 // ----------------------------------------------------------------------- 
1768 void wxPropertyGrid::DrawExpanderButton( wxDC
& dc
, const wxRect
& rect
, 
1769                                          wxPGProperty
* property 
) const 
1771     // Prepare rectangle to be used 
1773     r
.x 
+= m_gutterWidth
; r
.y 
+= m_buttonSpacingY
; 
1774     r
.width 
= m_iconWidth
; r
.height 
= m_iconHeight
; 
1776 #if (wxPG_USE_RENDERER_NATIVE) 
1778 #elif wxPG_ICON_WIDTH 
1779     // Drawing expand/collapse button manually 
1780     dc
.SetPen(m_colPropFore
); 
1781     if ( property
->IsCategory() ) 
1782         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1784         dc
.SetBrush(m_colPropBack
); 
1786     dc
.DrawRectangle( r 
); 
1787     int _y 
= r
.y
+(m_iconWidth
/2); 
1788     dc
.DrawLine(r
.x
+2,_y
,r
.x
+m_iconWidth
-2,_y
); 
1793     if ( property
->IsExpanded() ) 
1795     // wxRenderer functions are non-mutating in nature, so it 
1796     // should be safe to cast "const wxPropertyGrid*" to "wxWindow*". 
1797     // Hopefully this does not cause problems. 
1798     #if (wxPG_USE_RENDERER_NATIVE) 
1799         wxRendererNative::Get().DrawTreeItemButton( 
1805     #elif wxPG_ICON_WIDTH 
1814     #if (wxPG_USE_RENDERER_NATIVE) 
1815         wxRendererNative::Get().DrawTreeItemButton( 
1821     #elif wxPG_ICON_WIDTH 
1822         int _x 
= r
.x
+(m_iconWidth
/2); 
1823         dc
.DrawLine(_x
,r
.y
+2,_x
,r
.y
+m_iconWidth
-2); 
1829 #if (wxPG_USE_RENDERER_NATIVE) 
1831 #elif wxPG_ICON_WIDTH 
1834     dc
.DrawBitmap( *bmp
, r
.x
, r
.y
, true ); 
1838 // ----------------------------------------------------------------------- 
1841 // This is the one called by OnPaint event handler and others. 
1842 // topy and bottomy are already unscrolled (ie. physical) 
1844 void wxPropertyGrid::DrawItems( wxDC
& dc
, 
1846                                 unsigned int bottomy
, 
1847                                 const wxRect
* clipRect 
) 
1849     if ( m_frozen 
|| m_height 
< 1 || bottomy 
< topy 
|| !m_pState 
) return; 
1851     m_pState
->EnsureVirtualHeight(); 
1853     wxRect tempClipRect
; 
1856         tempClipRect 
= wxRect(0,topy
,m_pState
->m_width
,bottomy
); 
1857         clipRect 
= &tempClipRect
; 
1860     // items added check 
1861     if ( m_pState
->m_itemsAdded 
) PrepareAfterItemsAdded(); 
1863     int paintFinishY 
= 0; 
1865     if ( m_pState
->m_properties
->GetChildCount() > 0 ) 
1868         bool isBuffered 
= false; 
1870     #if wxPG_DOUBLE_BUFFER 
1871         wxMemoryDC
* bufferDC 
= NULL
; 
1873         if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING
) ) 
1875             if ( !m_doubleBuffer 
) 
1877                 paintFinishY 
= clipRect
->y
; 
1882                 bufferDC 
= new wxMemoryDC(); 
1884                 // If nothing was changed, then just copy from double-buffer 
1885                 bufferDC
->SelectObject( *m_doubleBuffer 
); 
1895             dc
.SetClippingRegion( *clipRect 
); 
1896             paintFinishY 
= DoDrawItems( *dcPtr
, clipRect
, isBuffered 
); 
1899     #if wxPG_DOUBLE_BUFFER 
1902             dc
.Blit( clipRect
->x
, clipRect
->y
, clipRect
->width
, clipRect
->height
, 
1903                 bufferDC
, 0, 0, wxCOPY 
); 
1904             dc
.DestroyClippingRegion(); // Is this really necessary? 
1910     // Clear area beyond bottomY? 
1911     if ( paintFinishY 
< (clipRect
->y
+clipRect
->height
) ) 
1913         dc
.SetPen(m_colEmptySpace
); 
1914         dc
.SetBrush(m_colEmptySpace
); 
1915         dc
.DrawRectangle( 0, paintFinishY
, m_width
, (clipRect
->y
+clipRect
->height
) ); 
1919 // ----------------------------------------------------------------------- 
1921 int wxPropertyGrid::DoDrawItems( wxDC
& dc
, 
1922                                  const wxRect
* clipRect
, 
1923                                  bool isBuffered 
) const 
1925     const wxPGProperty
* firstItem
; 
1926     const wxPGProperty
* lastItem
; 
1928     firstItem 
= DoGetItemAtY(clipRect
->y
); 
1929     lastItem 
= DoGetItemAtY(clipRect
->y
+clipRect
->height
-1); 
1932         lastItem 
= GetLastItem( wxPG_ITERATE_VISIBLE 
); 
1934     if ( m_frozen 
|| m_height 
< 1 || firstItem 
== NULL 
) 
1937     wxCHECK_MSG( !m_pState
->m_itemsAdded
, clipRect
->y
, wxT("no items added") ); 
1938     wxASSERT( m_pState
->m_properties
->GetChildCount() ); 
1940     int lh 
= m_lineHeight
; 
1943     int lastItemBottomY
; 
1945     firstItemTopY 
= clipRect
->y
; 
1946     lastItemBottomY 
= clipRect
->y 
+ clipRect
->height
; 
1948     // Align y coordinates to item boundaries 
1949     firstItemTopY 
-= firstItemTopY 
% lh
; 
1950     lastItemBottomY 
+= lh 
- (lastItemBottomY 
% lh
); 
1951     lastItemBottomY 
-= 1; 
1953     // Entire range outside scrolled, visible area? 
1954     if ( firstItemTopY 
>= (int)m_pState
->GetVirtualHeight() || lastItemBottomY 
<= 0 ) 
1957     wxCHECK_MSG( firstItemTopY 
< lastItemBottomY
, clipRect
->y
, wxT("invalid y values") ); 
1961     wxLogDebug(wxT("  -> DoDrawItems ( \"%s\" -> \"%s\", height=%i (ch=%i), clipRect = 0x%lX )"), 
1962         firstItem->GetLabel().c_str(), 
1963         lastItem->GetLabel().c_str(), 
1964         (int)(lastItemBottomY - firstItemTopY), 
1966         (unsigned long)clipRect ); 
1971     long windowStyle 
= m_windowStyle
; 
1977     // With wxPG_DOUBLE_BUFFER, do double buffering 
1978     // - buffer's y = 0, so align cliprect and coordinates to that 
1980 #if wxPG_DOUBLE_BUFFER 
1986         xRelMod 
= clipRect
->x
; 
1987         yRelMod 
= clipRect
->y
; 
1990         // clipRect conversion 
1995         firstItemTopY 
-= yRelMod
; 
1996         lastItemBottomY 
-= yRelMod
; 
1999     wxUnusedVar(isBuffered
); 
2002     int x 
= m_marginWidth 
- xRelMod
; 
2004     wxFont normalFont 
= GetFont(); 
2006     bool reallyFocused 
= (m_iFlags 
& wxPG_FL_FOCUSED
) != 0; 
2008     bool isPgEnabled 
= IsEnabled(); 
2011     // Prepare some pens and brushes that are often changed to. 
2014     wxBrush 
marginBrush(m_colMargin
); 
2015     wxPen 
marginPen(m_colMargin
); 
2016     wxBrush 
capbgbrush(m_colCapBack
,wxSOLID
); 
2017     wxPen 
linepen(m_colLine
,1,wxSOLID
); 
2019     wxColour selBackCol
; 
2021         selBackCol 
= m_colSelBack
; 
2023         selBackCol 
= m_colMargin
; 
2025     // pen that has same colour as text 
2026     wxPen 
outlinepen(m_colPropFore
,1,wxSOLID
); 
2029     // Clear margin with background colour 
2031     dc
.SetBrush( marginBrush 
); 
2032     if ( !(windowStyle 
& wxPG_HIDE_MARGIN
) ) 
2034         dc
.SetPen( *wxTRANSPARENT_PEN 
); 
2035         dc
.DrawRectangle(-1-xRelMod
,firstItemTopY
-1,x
+2,lastItemBottomY
-firstItemTopY
+2); 
2038     const wxPGProperty
* firstSelected 
= GetSelection(); 
2039     const wxPropertyGridPageState
* state 
= m_pState
; 
2041 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2042     bool wasSelectedPainted 
= false; 
2045     // TODO: Only render columns that are within clipping region. 
2047     dc
.SetFont(normalFont
); 
2049     wxPropertyGridConstIterator 
it( state
, wxPG_ITERATE_VISIBLE
, firstItem 
); 
2050     int endScanBottomY 
= lastItemBottomY 
+ lh
; 
2051     int y 
= firstItemTopY
; 
2054     // Pregenerate list of visible properties. 
2055     wxArrayPGProperty visPropArray
; 
2056     visPropArray
.reserve((m_height
/m_lineHeight
)+6); 
2058     for ( ; !it
.AtEnd(); it
.Next() ) 
2060         const wxPGProperty
* p 
= *it
; 
2062         if ( !p
->HasFlag(wxPG_PROP_HIDDEN
) ) 
2064             visPropArray
.push_back((wxPGProperty
*)p
); 
2066             if ( y 
> endScanBottomY 
) 
2073     visPropArray
.push_back(NULL
); 
2075     wxPGProperty
* nextP 
= visPropArray
[0]; 
2077     int gridWidth 
= state
->m_width
; 
2080     for ( unsigned int arrInd
=1; 
2081           nextP 
&& y 
<= lastItemBottomY
; 
2084         wxPGProperty
* p 
= nextP
; 
2085         nextP 
= visPropArray
[arrInd
]; 
2087         int rowHeight 
= m_fontHeight
+(m_spacingy
*2)+1; 
2088         int textMarginHere 
= x
; 
2089         int renderFlags 
= 0; 
2091         int greyDepth 
= m_marginWidth
; 
2092         if ( !(windowStyle 
& wxPG_HIDE_CATEGORIES
) ) 
2093             greyDepth 
= (((int)p
->m_depthBgCol
)-1) * m_subgroup_extramargin 
+ m_marginWidth
; 
2095         int greyDepthX 
= greyDepth 
- xRelMod
; 
2097         // Use basic depth if in non-categoric mode and parent is base array. 
2098         if ( !(windowStyle 
& wxPG_HIDE_CATEGORIES
) || p
->GetParent() != m_pState
->m_properties 
) 
2100             textMarginHere 
+= ((unsigned int)((p
->m_depth
-1)*m_subgroup_extramargin
)); 
2103         // Paint margin area 
2104         dc
.SetBrush(marginBrush
); 
2105         dc
.SetPen(marginPen
); 
2106         dc
.DrawRectangle( -xRelMod
, y
, greyDepth
, lh 
); 
2108         dc
.SetPen( linepen 
); 
2113         dc
.DrawLine( greyDepthX
, y
, greyDepthX
, y2 
); 
2119         for ( si
=0; si
<state
->m_colWidths
.size(); si
++ ) 
2121             sx 
+= state
->m_colWidths
[si
]; 
2122             dc
.DrawLine( sx
, y
, sx
, y2 
); 
2125         // Horizontal Line, below 
2126         //   (not if both this and next is category caption) 
2127         if ( p
->IsCategory() && 
2128              nextP 
&& nextP
->IsCategory() ) 
2129             dc
.SetPen(m_colCapBack
); 
2131         dc
.DrawLine( greyDepthX
, y2
-1, gridWidth
-xRelMod
, y2
-1 ); 
2134         // Need to override row colours? 
2138         bool isSelected 
= state
->DoIsPropertySelected(p
); 
2142             // Disabled may get different colour. 
2143             if ( !p
->IsEnabled() ) 
2145                 renderFlags 
|= wxPGCellRenderer::Disabled 
| 
2146                                wxPGCellRenderer::DontUseCellFgCol
; 
2147                 rowFgCol 
= m_colDisPropFore
; 
2152 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2153             if ( p 
== firstSelected 
) 
2154                 wasSelectedPainted 
= true; 
2157             renderFlags 
|= wxPGCellRenderer::Selected
; 
2159             if ( !p
->IsCategory() ) 
2161                 renderFlags 
|= wxPGCellRenderer::DontUseCellFgCol 
| 
2162                                wxPGCellRenderer::DontUseCellBgCol
; 
2164                 if ( reallyFocused 
&& p 
== firstSelected 
) 
2166                     rowFgCol 
= m_colSelFore
; 
2167                     rowBgCol 
= selBackCol
; 
2169                 else if ( isPgEnabled 
) 
2171                     rowFgCol 
= m_colPropFore
; 
2172                     if ( p 
== firstSelected 
) 
2173                         rowBgCol 
= m_colMargin
; 
2175                         rowBgCol 
= selBackCol
; 
2179                     rowFgCol 
= m_colDisPropFore
; 
2180                     rowBgCol 
= selBackCol
; 
2187         if ( rowBgCol
.IsOk() ) 
2188             rowBgBrush 
= wxBrush(rowBgCol
); 
2190         if ( HasInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
) ) 
2191             renderFlags 
= renderFlags 
& ~wxPGCellRenderer::DontUseCellColours
; 
2194         // Fill additional margin area with background colour of first cell 
2195         if ( greyDepthX 
< textMarginHere 
) 
2197             if ( !(renderFlags 
& wxPGCellRenderer::DontUseCellBgCol
) ) 
2199                 wxPGCell
& cell 
= p
->GetCell(0); 
2200                 rowBgCol 
= cell
.GetBgCol(); 
2201                 rowBgBrush 
= wxBrush(rowBgCol
); 
2203             dc
.SetBrush(rowBgBrush
); 
2204             dc
.SetPen(rowBgCol
); 
2205             dc
.DrawRectangle(greyDepthX
+1, y
, 
2206                              textMarginHere
-greyDepthX
, lh
-1); 
2209         bool fontChanged 
= false; 
2211         // Expander button rectangle 
2212         wxRect 
butRect( ((p
->m_depth 
- 1) * m_subgroup_extramargin
) - xRelMod
, 
2217         if ( p
->IsCategory() ) 
2219             // Captions have their cell areas merged as one 
2220             dc
.SetFont(m_captionFont
); 
2222             wxRect 
cellRect(greyDepthX
, y
, gridWidth 
- greyDepth 
+ 2, rowHeight
-1 ); 
2224             if ( renderFlags 
& wxPGCellRenderer::DontUseCellBgCol 
) 
2226                 dc
.SetBrush(rowBgBrush
); 
2227                 dc
.SetPen(rowBgCol
); 
2230             if ( renderFlags 
& wxPGCellRenderer::DontUseCellFgCol 
) 
2232                 dc
.SetTextForeground(rowFgCol
); 
2235             wxPGCellRenderer
* renderer 
= p
->GetCellRenderer(0); 
2236             renderer
->Render( dc
, cellRect
, this, p
, 0, -1, renderFlags 
); 
2239             if ( !HasFlag(wxPG_HIDE_MARGIN
) && p
->HasVisibleChildren() ) 
2240                 DrawExpanderButton( dc
, butRect
, p 
); 
2244             if ( p
->m_flags 
& wxPG_PROP_MODIFIED 
&& (windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
2246                 dc
.SetFont(m_captionFont
); 
2252             int nextCellWidth 
= state
->m_colWidths
[0] - 
2253                                 (greyDepthX 
- m_marginWidth
); 
2254             wxRect 
cellRect(greyDepthX
+1, y
, 0, rowHeight
-1); 
2255             int textXAdd 
= textMarginHere 
- greyDepthX
; 
2257             for ( ci
=0; ci
<state
->m_colWidths
.size(); ci
++ ) 
2259                 cellRect
.width 
= nextCellWidth 
- 1; 
2261                 wxWindow
* cellEditor 
= NULL
; 
2262                 int cellRenderFlags 
= renderFlags
; 
2264                 // Tree Item Button (must be drawn before clipping is set up) 
2265                 if ( ci 
== 0 && !HasFlag(wxPG_HIDE_MARGIN
) && p
->HasVisibleChildren() ) 
2266                     DrawExpanderButton( dc
, butRect
, p 
); 
2269                 if ( isSelected 
&& (ci 
== 1 || ci 
== m_selColumn
) ) 
2271                     if ( p 
== firstSelected 
) 
2273                         if ( ci 
== 1 && m_wndEditor 
) 
2274                             cellEditor 
= m_wndEditor
; 
2275                         else if ( ci 
== m_selColumn 
&& m_labelEditor 
) 
2276                             cellEditor 
= m_labelEditor
; 
2281                         wxColour editorBgCol 
= 
2282                             cellEditor
->GetBackgroundColour(); 
2283                         dc
.SetBrush(editorBgCol
); 
2284                         dc
.SetPen(editorBgCol
); 
2285                         dc
.SetTextForeground(m_colPropFore
); 
2286                         dc
.DrawRectangle(cellRect
); 
2288                         if ( m_dragStatus 
!= 0 || 
2289                              (m_iFlags 
& wxPG_FL_CUR_USES_CUSTOM_IMAGE
) ) 
2294                         dc
.SetBrush(m_colPropBack
); 
2295                         dc
.SetPen(m_colPropBack
); 
2296                         dc
.SetTextForeground(m_colDisPropFore
); 
2297                         if ( p
->IsEnabled() ) 
2298                             dc
.SetTextForeground(rowFgCol
); 
2300                             dc
.SetTextForeground(m_colDisPropFore
); 
2305                     if ( renderFlags 
& wxPGCellRenderer::DontUseCellBgCol 
) 
2307                         dc
.SetBrush(rowBgBrush
); 
2308                         dc
.SetPen(rowBgCol
); 
2311                     if ( renderFlags 
& wxPGCellRenderer::DontUseCellFgCol 
) 
2313                         dc
.SetTextForeground(rowFgCol
); 
2317                 dc
.SetClippingRegion(cellRect
); 
2319                 cellRect
.x 
+= textXAdd
; 
2320                 cellRect
.width 
-= textXAdd
; 
2325                     wxPGCellRenderer
* renderer
; 
2326                     int cmnVal 
= p
->GetCommonValue(); 
2327                     if ( cmnVal 
== -1 || ci 
!= 1 ) 
2329                         renderer 
= p
->GetCellRenderer(ci
); 
2330                         renderer
->Render( dc
, cellRect
, this, p
, ci
, -1, 
2335                         renderer 
= GetCommonValue(cmnVal
)->GetRenderer(); 
2336                         renderer
->Render( dc
, cellRect
, this, p
, ci
, -1, 
2341                 cellX 
+= state
->m_colWidths
[ci
]; 
2342                 if ( ci 
< (state
->m_colWidths
.size()-1) ) 
2343                     nextCellWidth 
= state
->m_colWidths
[ci
+1]; 
2345                 dc
.DestroyClippingRegion(); // Is this really necessary? 
2351             dc
.SetFont(normalFont
); 
2356     // Refresh editor controls (seems not needed on msw) 
2357     // NOTE: This code is mandatory for GTK! 
2358 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2359     if ( wasSelectedPainted 
) 
2362             m_wndEditor
->Refresh(); 
2364             m_wndEditor2
->Refresh(); 
2371 // ----------------------------------------------------------------------- 
2373 wxRect 
wxPropertyGrid::GetPropertyRect( const wxPGProperty
* p1
, const wxPGProperty
* p2 
) const 
2377     if ( m_width 
< 10 || m_height 
< 10 || 
2378          !m_pState
->m_properties
->GetChildCount() || 
2380         return wxRect(0,0,0,0); 
2385     // Return rect which encloses the given property range 
2387     int visTop 
= p1
->GetY(); 
2390         visBottom 
= p2
->GetY() + m_lineHeight
; 
2392         visBottom 
= m_height 
+ visTop
; 
2394     // If seleced property is inside the range, we'll extend the range to include 
2396     wxPGProperty
* selected 
= GetSelection(); 
2399         int selectedY 
= selected
->GetY(); 
2400         if ( selectedY 
>= visTop 
&& selectedY 
< visBottom 
) 
2402             wxWindow
* editor 
= GetEditorControl(); 
2405                 int visBottom2 
= selectedY 
+ editor
->GetSize().y
; 
2406                 if ( visBottom2 
> visBottom 
) 
2407                     visBottom 
= visBottom2
; 
2412     return wxRect(0,visTop
-vy
,m_pState
->m_width
,visBottom
-visTop
); 
2415 // ----------------------------------------------------------------------- 
2417 void wxPropertyGrid::DrawItems( const wxPGProperty
* p1
, const wxPGProperty
* p2 
) 
2422     if ( m_pState
->m_itemsAdded 
) 
2423         PrepareAfterItemsAdded(); 
2425     wxRect r 
= GetPropertyRect(p1
, p2
); 
2428         m_canvas
->RefreshRect(r
); 
2432 // ----------------------------------------------------------------------- 
2434 void wxPropertyGrid::RefreshProperty( wxPGProperty
* p 
) 
2436     if ( m_pState
->DoIsPropertySelected(p
) ) 
2438         // NB: We must copy the selection. 
2439         wxArrayPGProperty selection 
= m_pState
->m_selection
; 
2440         DoSetSelection(selection
, wxPG_SEL_FORCE
); 
2443     DrawItemAndChildren(p
); 
2446 // ----------------------------------------------------------------------- 
2448 void wxPropertyGrid::DrawItemAndValueRelated( wxPGProperty
* p 
) 
2453     // Draw item, children, and parent too, if it is not category 
2454     wxPGProperty
* parent 
= p
->GetParent(); 
2457             !parent
->IsCategory() && 
2458             parent
->GetParent() ) 
2461          parent 
= parent
->GetParent(); 
2464     DrawItemAndChildren(p
); 
2467 void wxPropertyGrid::DrawItemAndChildren( wxPGProperty
* p 
) 
2469     wxCHECK_RET( p
, wxT("invalid property id") ); 
2471     // Do not draw if in non-visible page 
2472     if ( p
->GetParentState() != m_pState 
) 
2475     // do not draw a single item if multiple pending 
2476     if ( m_pState
->m_itemsAdded 
|| m_frozen 
) 
2479     // Update child control. 
2480     wxPGProperty
* selected 
= GetSelection(); 
2481     if ( selected 
&& selected
->GetParent() == p 
) 
2484     const wxPGProperty
* lastDrawn 
= p
->GetLastVisibleSubItem(); 
2486     DrawItems(p
, lastDrawn
); 
2489 // ----------------------------------------------------------------------- 
2491 void wxPropertyGrid::Refresh( bool WXUNUSED(eraseBackground
), 
2492                               const wxRect 
*rect 
) 
2494     PrepareAfterItemsAdded(); 
2496     wxWindow::Refresh(false); 
2498         // TODO: Coordinate translation 
2499         m_canvas
->Refresh(false, rect
); 
2501 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2502     // I think this really helps only GTK+1.2 
2503     if ( m_wndEditor 
) m_wndEditor
->Refresh(); 
2504     if ( m_wndEditor2 
) m_wndEditor2
->Refresh(); 
2508 // ----------------------------------------------------------------------- 
2509 // wxPropertyGrid global operations 
2510 // ----------------------------------------------------------------------- 
2512 void wxPropertyGrid::Clear() 
2514     m_pState
->DoClear(); 
2520     RecalculateVirtualSize(); 
2522     // Need to clear some area at the end 
2524         RefreshRect(wxRect(0, 0, m_width
, m_height
)); 
2527 // ----------------------------------------------------------------------- 
2529 bool wxPropertyGrid::EnableCategories( bool enable 
) 
2536         // Enable categories 
2539         m_windowStyle 
&= ~(wxPG_HIDE_CATEGORIES
); 
2544         // Disable categories 
2546         m_windowStyle 
|= wxPG_HIDE_CATEGORIES
; 
2549     if ( !m_pState
->EnableCategories(enable
) ) 
2554         if ( m_windowStyle 
& wxPG_AUTO_SORT 
) 
2556             m_pState
->m_itemsAdded 
= 1; // force 
2557             PrepareAfterItemsAdded(); 
2561         m_pState
->m_itemsAdded 
= 1; 
2563     // No need for RecalculateVirtualSize() here - it is already called in 
2564     // wxPropertyGridPageState method above. 
2571 // ----------------------------------------------------------------------- 
2573 void wxPropertyGrid::SwitchState( wxPropertyGridPageState
* pNewState 
) 
2575     wxASSERT( pNewState 
); 
2576     wxASSERT( pNewState
->GetGrid() ); 
2578     if ( pNewState 
== m_pState 
) 
2581     wxArrayPGProperty oldSelection 
= m_pState
->m_selection
; 
2583     // Call ClearSelection() instead of DoClearSelection() 
2584     // so that selection clear events are not sent. 
2587     m_pState
->m_selection 
= oldSelection
; 
2589     bool orig_mode 
= m_pState
->IsInNonCatMode(); 
2590     bool new_state_mode 
= pNewState
->IsInNonCatMode(); 
2592     m_pState 
= pNewState
; 
2595     int pgWidth 
= GetClientSize().x
; 
2596     if ( HasVirtualWidth() ) 
2598         int minWidth 
= pgWidth
; 
2599         if ( pNewState
->m_width 
< minWidth 
) 
2601             pNewState
->m_width 
= minWidth
; 
2602             pNewState
->CheckColumnWidths(); 
2608         // Just in case, fully re-center splitter 
2609         if ( HasFlag( wxPG_SPLITTER_AUTO_CENTER 
) ) 
2610             pNewState
->m_fSplitterX 
= -1.0; 
2612         pNewState
->OnClientWidthChange( pgWidth
, pgWidth 
- pNewState
->m_width 
); 
2617     // If necessary, convert state to correct mode. 
2618     if ( orig_mode 
!= new_state_mode 
) 
2620         // This should refresh as well. 
2621         EnableCategories( orig_mode
?false:true ); 
2623     else if ( !m_frozen 
) 
2625         // Refresh, if not frozen. 
2626         m_pState
->PrepareAfterItemsAdded(); 
2628         // Reselect (Use SetSelection() instead of Do-variant so that 
2629         // events won't be sent). 
2630         SetSelection(m_pState
->m_selection
); 
2632         RecalculateVirtualSize(0); 
2636         m_pState
->m_itemsAdded 
= 1; 
2639 // ----------------------------------------------------------------------- 
2641 // Call to SetSplitterPosition will always disable splitter auto-centering 
2642 // if parent window is shown. 
2643 void wxPropertyGrid::DoSetSplitterPosition_( int newxpos
, bool refresh
, int splitterIndex
, bool allPages 
) 
2645     if ( ( newxpos 
< wxPG_DRAG_MARGIN 
) ) 
2648     wxPropertyGridPageState
* state 
= m_pState
; 
2650     state
->DoSetSplitterPosition( newxpos
, splitterIndex
, allPages 
); 
2654         if ( GetSelection() ) 
2655             CorrectEditorWidgetSizeX(); 
2661 // ----------------------------------------------------------------------- 
2663 void wxPropertyGrid::CenterSplitter( bool enableAutoCentering 
) 
2665     SetSplitterPosition( m_width
/2, true ); 
2666     if ( enableAutoCentering 
&& ( m_windowStyle 
& wxPG_SPLITTER_AUTO_CENTER 
) ) 
2667         m_iFlags 
&= ~(wxPG_FL_DONT_CENTER_SPLITTER
); 
2670 // ----------------------------------------------------------------------- 
2671 // wxPropertyGrid item iteration (GetNextProperty etc.) methods 
2672 // ----------------------------------------------------------------------- 
2674 // Returns nearest paint visible property (such that will be painted unless 
2675 // window is scrolled or resized). If given property is paint visible, then 
2676 // it itself will be returned 
2677 wxPGProperty
* wxPropertyGrid::GetNearestPaintVisible( wxPGProperty
* p 
) const 
2679     int vx
,vy1
;// Top left corner of client 
2680     GetViewStart(&vx
,&vy1
); 
2681     vy1 
*= wxPG_PIXELS_PER_UNIT
; 
2683     int vy2 
= vy1 
+ m_height
; 
2684     int propY 
= p
->GetY2(m_lineHeight
); 
2686     if ( (propY 
+ m_lineHeight
) < vy1 
) 
2689         return DoGetItemAtY( vy1 
); 
2691     else if ( propY 
> vy2 
) 
2694         return DoGetItemAtY( vy2 
); 
2697     // Itself paint visible 
2702 // ----------------------------------------------------------------------- 
2703 // Methods related to change in value, value modification and sending events 
2704 // ----------------------------------------------------------------------- 
2706 // commits any changes in editor of selected property 
2707 // return true if validation did not fail 
2708 // flags are same as with DoSelectProperty 
2709 bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags 
) 
2711     // Committing already? 
2712     if ( m_inCommitChangesFromEditor 
) 
2715     // Don't do this if already processing editor event. It might 
2716     // induce recursive dialogs and crap like that. 
2717     if ( m_iFlags 
& wxPG_FL_IN_HANDLECUSTOMEDITOREVENT 
) 
2719         if ( m_inDoPropertyChanged 
) 
2725     wxPGProperty
* selected 
= GetSelection(); 
2728          IsEditorsValueModified() && 
2729          (m_iFlags 
& wxPG_FL_INITIALIZED
) && 
2732         m_inCommitChangesFromEditor 
= 1; 
2734         wxVariant 
variant(selected
->GetValueRef()); 
2735         bool valueIsPending 
= false; 
2737         // JACS - necessary to avoid new focus being found spuriously within OnIdle 
2738         // due to another window getting focus 
2739         wxWindow
* oldFocus 
= m_curFocused
; 
2741         bool validationFailure 
= false; 
2742         bool forceSuccess 
= (flags 
& (wxPG_SEL_NOVALIDATE
|wxPG_SEL_FORCE
)) ? true : false; 
2744         m_chgInfo_changedProperty 
= NULL
; 
2746         // If truly modified, schedule value as pending. 
2747         if ( selected
->GetEditorClass()-> 
2748                 GetValueFromControl( variant
, 
2750                                      GetEditorControl() ) ) 
2752             if ( DoEditorValidate() && 
2753                  PerformValidation(selected
, variant
) ) 
2755                 valueIsPending 
= true; 
2759                 validationFailure 
= true; 
2764             EditorsValueWasNotModified(); 
2769         m_inCommitChangesFromEditor 
= 0; 
2771         if ( validationFailure 
&& !forceSuccess 
) 
2775                 oldFocus
->SetFocus(); 
2776                 m_curFocused 
= oldFocus
; 
2779             res 
= OnValidationFailure(selected
, variant
); 
2781             // Now prevent further validation failure messages 
2784                 EditorsValueWasNotModified(); 
2785                 OnValidationFailureReset(selected
); 
2788         else if ( valueIsPending 
) 
2790             DoPropertyChanged( selected
, flags 
); 
2791             EditorsValueWasNotModified(); 
2800 // ----------------------------------------------------------------------- 
2802 bool wxPropertyGrid::PerformValidation( wxPGProperty
* p
, wxVariant
& pendingValue
, 
2806     // Runs all validation functionality. 
2807     // Returns true if value passes all tests. 
2810     m_validationInfo
.m_failureBehavior 
= m_permanentValidationFailureBehavior
; 
2812     if ( pendingValue
.GetType() == wxPG_VARIANT_TYPE_LIST 
) 
2814         if ( !p
->ValidateValue(pendingValue
, m_validationInfo
) ) 
2819     // Adapt list to child values, if necessary 
2820     wxVariant listValue 
= pendingValue
; 
2821     wxVariant
* pPendingValue 
= &pendingValue
; 
2822     wxVariant
* pList 
= NULL
; 
2824     // If parent has wxPG_PROP_AGGREGATE flag, or uses composite 
2825     // string value, then we need treat as it was changed instead 
2826     // (or, in addition, as is the case with composite string parent). 
2827     // This includes creating list variant for child values. 
2829     wxPGProperty
* pwc 
= p
->GetParent(); 
2830     wxPGProperty
* changedProperty 
= p
; 
2831     wxPGProperty
* baseChangedProperty 
= changedProperty
; 
2832     wxVariant bcpPendingList
; 
2834     listValue 
= pendingValue
; 
2835     listValue
.SetName(p
->GetBaseName()); 
2838             (pwc
->HasFlag(wxPG_PROP_AGGREGATE
) || pwc
->HasFlag(wxPG_PROP_COMPOSED_VALUE
)) ) 
2840         wxVariantList tempList
; 
2841         wxVariant 
lv(tempList
, pwc
->GetBaseName()); 
2842         lv
.Append(listValue
); 
2844         pPendingValue 
= &listValue
; 
2846         if ( pwc
->HasFlag(wxPG_PROP_AGGREGATE
) ) 
2848             baseChangedProperty 
= pwc
; 
2849             bcpPendingList 
= lv
; 
2852         changedProperty 
= pwc
; 
2853         pwc 
= pwc
->GetParent(); 
2857     wxPGProperty
* evtChangingProperty 
= changedProperty
; 
2859     if ( pPendingValue
->GetType() != wxPG_VARIANT_TYPE_LIST 
) 
2861         value 
= *pPendingValue
; 
2865         // Convert list to child values 
2866         pList 
= pPendingValue
; 
2867         changedProperty
->AdaptListToValue( *pPendingValue
, &value 
); 
2870     wxVariant evtChangingValue 
= value
; 
2872     if ( flags 
& SendEvtChanging 
) 
2874         // FIXME: After proper ValueToString()s added, remove 
2875         // this. It is just a temporary fix, as evt_changing 
2876         // will simply not work for wxPG_PROP_COMPOSED_VALUE 
2877         // (unless it is selected, and textctrl editor is open). 
2878         if ( changedProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
2880             evtChangingProperty 
= baseChangedProperty
; 
2881             if ( evtChangingProperty 
!= p 
) 
2883                 evtChangingProperty
->AdaptListToValue( bcpPendingList
, &evtChangingValue 
); 
2887                 evtChangingValue 
= pendingValue
; 
2891         if ( evtChangingProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
2893             if ( changedProperty 
== GetSelection() ) 
2895                 wxWindow
* editor 
= GetEditorControl(); 
2896                 wxASSERT( editor
->IsKindOf(CLASSINFO(wxTextCtrl
)) ); 
2897                 evtChangingValue 
= wxStaticCast(editor
, wxTextCtrl
)->GetValue(); 
2901                 wxLogDebug(wxT("WARNING: wxEVT_PG_CHANGING is about to happen with old value.")); 
2906     wxASSERT( m_chgInfo_changedProperty 
== NULL 
); 
2907     m_chgInfo_changedProperty 
= changedProperty
; 
2908     m_chgInfo_baseChangedProperty 
= baseChangedProperty
; 
2909     m_chgInfo_pendingValue 
= value
; 
2912         m_chgInfo_valueList 
= *pList
; 
2914         m_chgInfo_valueList
.MakeNull(); 
2916     // If changedProperty is not property which value was edited, 
2917     // then call wxPGProperty::ValidateValue() for that as well. 
2918     if ( p 
!= changedProperty 
&& value
.GetType() != wxPG_VARIANT_TYPE_LIST 
) 
2920         if ( !changedProperty
->ValidateValue(value
, m_validationInfo
) ) 
2924     if ( flags 
& SendEvtChanging 
) 
2926         // SendEvent returns true if event was vetoed 
2927         if ( SendEvent( wxEVT_PG_CHANGING
, evtChangingProperty
, 
2928                         &evtChangingValue 
) ) 
2932     if ( flags 
& IsStandaloneValidation 
) 
2934         // If called in 'generic' context, we need to reset 
2935         // m_chgInfo_changedProperty and write back translated value. 
2936         m_chgInfo_changedProperty 
= NULL
; 
2937         pendingValue 
= value
; 
2943 // ----------------------------------------------------------------------- 
2945 void wxPropertyGrid::DoShowPropertyError( wxPGProperty
* WXUNUSED(property
), const wxString
& msg 
) 
2947     if ( !msg
.length() ) 
2951     if ( !wxPGGlobalVars
->m_offline 
) 
2953         wxWindow
* topWnd 
= ::wxGetTopLevelParent(this); 
2956             wxFrame
* pFrame 
= wxDynamicCast(topWnd
, wxFrame
); 
2959                 wxStatusBar
* pStatusBar 
= pFrame
->GetStatusBar(); 
2962                     pStatusBar
->SetStatusText(msg
); 
2970     ::wxMessageBox(msg
, wxT("Property Error")); 
2973 // ----------------------------------------------------------------------- 
2975 bool wxPropertyGrid::OnValidationFailure( wxPGProperty
* property
, 
2976                                           wxVariant
& invalidValue 
) 
2978     wxWindow
* editor 
= GetEditorControl(); 
2980     // First call property's handler 
2981     property
->OnValidationFailure(invalidValue
); 
2983     bool res 
= DoOnValidationFailure(property
, invalidValue
); 
2986     // For non-wxTextCtrl editors, we do need to revert the value 
2987     if ( !editor
->IsKindOf(CLASSINFO(wxTextCtrl
)) && 
2988          property 
== GetSelection() ) 
2990         property
->GetEditorClass()->UpdateControl(property
, editor
); 
2993     property
->SetFlag(wxPG_PROP_INVALID_VALUE
); 
2998 bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty
* property
, wxVariant
& WXUNUSED(invalidValue
) ) 
3000     int vfb 
= m_validationInfo
.m_failureBehavior
; 
3002     if ( vfb 
& wxPG_VFB_BEEP 
) 
3005     if ( (vfb 
& wxPG_VFB_MARK_CELL
) && 
3006          !property
->HasFlag(wxPG_PROP_INVALID_VALUE
) ) 
3008         unsigned int colCount 
= m_pState
->GetColumnCount(); 
3010         // We need backup marked property's cells 
3011         m_propCellsBackup 
= property
->m_cells
; 
3013         wxColour vfbFg 
= *wxWHITE
; 
3014         wxColour vfbBg 
= *wxRED
; 
3016         property
->EnsureCells(colCount
); 
3018         for ( unsigned int i
=0; i
<colCount
; i
++ ) 
3020             wxPGCell
& cell 
= property
->m_cells
[i
]; 
3021             cell
.SetFgCol(vfbFg
); 
3022             cell
.SetBgCol(vfbBg
); 
3025         DrawItemAndChildren(property
); 
3027         if ( property 
== GetSelection() ) 
3029             SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
); 
3031             wxWindow
* editor 
= GetEditorControl(); 
3034                 editor
->SetForegroundColour(vfbFg
); 
3035                 editor
->SetBackgroundColour(vfbBg
); 
3040     if ( vfb 
& wxPG_VFB_SHOW_MESSAGE 
) 
3042         wxString msg 
= m_validationInfo
.m_failureMessage
; 
3044         if ( !msg
.length() ) 
3045             msg 
= wxT("You have entered invalid value. Press ESC to cancel editing."); 
3047         DoShowPropertyError(property
, msg
); 
3050     return (vfb 
& wxPG_VFB_STAY_IN_PROPERTY
) ? false : true; 
3053 // ----------------------------------------------------------------------- 
3055 void wxPropertyGrid::DoOnValidationFailureReset( wxPGProperty
* property 
) 
3057     int vfb 
= m_validationInfo
.m_failureBehavior
; 
3059     if ( vfb 
& wxPG_VFB_MARK_CELL 
) 
3062         property
->m_cells 
= m_propCellsBackup
; 
3064         ClearInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
); 
3066         if ( property 
== GetSelection() && GetEditorControl() ) 
3068             // Calling this will recreate the control, thus resetting its colour 
3069             RefreshProperty(property
); 
3073             DrawItemAndChildren(property
); 
3078 // ----------------------------------------------------------------------- 
3080 // flags are same as with DoSelectProperty 
3081 bool wxPropertyGrid::DoPropertyChanged( wxPGProperty
* p
, unsigned int selFlags 
) 
3083     if ( m_inDoPropertyChanged 
) 
3086     wxWindow
* editor 
= GetEditorControl(); 
3087     wxPGProperty
* selected 
= GetSelection(); 
3089     m_pState
->m_anyModified 
= 1; 
3091     m_inDoPropertyChanged 
= 1; 
3093     // Maybe need to update control 
3094     wxASSERT( m_chgInfo_changedProperty 
!= NULL 
); 
3096     // These values were calculated in PerformValidation() 
3097     wxPGProperty
* changedProperty 
= m_chgInfo_changedProperty
; 
3098     wxVariant value 
= m_chgInfo_pendingValue
; 
3100     wxPGProperty
* topPaintedProperty 
= changedProperty
; 
3102     while ( !topPaintedProperty
->IsCategory() && 
3103             !topPaintedProperty
->IsRoot() ) 
3105         topPaintedProperty 
= topPaintedProperty
->GetParent(); 
3108     changedProperty
->SetValue(value
, &m_chgInfo_valueList
, wxPG_SETVAL_BY_USER
); 
3110     // Set as Modified (not if dragging just began) 
3111     if ( !(p
->m_flags 
& wxPG_PROP_MODIFIED
) ) 
3113         p
->m_flags 
|= wxPG_PROP_MODIFIED
; 
3114         if ( p 
== selected 
&& (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
3117                 SetCurControlBoldFont(); 
3123     // Propagate updates to parent(s) 
3125     wxPGProperty
* prevPwc 
= NULL
; 
3127     while ( prevPwc 
!= topPaintedProperty 
) 
3129         pwc
->m_flags 
|= wxPG_PROP_MODIFIED
; 
3131         if ( pwc 
== selected 
&& (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
3134                 SetCurControlBoldFont(); 
3138         pwc 
= pwc
->GetParent(); 
3141     // Draw the actual property 
3142     DrawItemAndChildren( topPaintedProperty 
); 
3145     // If value was set by wxPGProperty::OnEvent, then update the editor 
3147     if ( selFlags 
& wxPG_SEL_DIALOGVAL 
) 
3153 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
3154         if ( m_wndEditor 
) m_wndEditor
->Refresh(); 
3155         if ( m_wndEditor2 
) m_wndEditor2
->Refresh(); 
3160     wxASSERT( !changedProperty
->GetParent()->HasFlag(wxPG_PROP_AGGREGATE
) ); 
3162     // If top parent has composite string value, then send to child parents, 
3163     // starting from baseChangedProperty. 
3164     if ( changedProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
3166         pwc 
= m_chgInfo_baseChangedProperty
; 
3168         while ( pwc 
!= changedProperty 
) 
3170             SendEvent( wxEVT_PG_CHANGED
, pwc
, NULL 
); 
3171             pwc 
= pwc
->GetParent(); 
3175     SendEvent( wxEVT_PG_CHANGED
, changedProperty
, NULL 
); 
3177     m_inDoPropertyChanged 
= 0; 
3182 // ----------------------------------------------------------------------- 
3184 bool wxPropertyGrid::ChangePropertyValue( wxPGPropArg id
, wxVariant newValue 
) 
3186     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) 
3188     m_chgInfo_changedProperty 
= NULL
; 
3190     if ( PerformValidation(p
, newValue
) ) 
3192         DoPropertyChanged(p
); 
3197         OnValidationFailure(p
, newValue
); 
3203 // ----------------------------------------------------------------------- 
3205 wxVariant 
wxPropertyGrid::GetUncommittedPropertyValue() 
3207     wxPGProperty
* prop 
= GetSelectedProperty(); 
3210         return wxNullVariant
; 
3212     wxTextCtrl
* tc 
= GetEditorTextCtrl(); 
3213     wxVariant value 
= prop
->GetValue(); 
3215     if ( !tc 
|| !IsEditorsValueModified() ) 
3218     if ( !prop
->StringToValue(value
, tc
->GetValue()) ) 
3221     if ( !PerformValidation(prop
, value
, IsStandaloneValidation
) ) 
3222         return prop
->GetValue(); 
3227 // ----------------------------------------------------------------------- 
3229 // Runs wxValidator for the selected property 
3230 bool wxPropertyGrid::DoEditorValidate() 
3235 // ----------------------------------------------------------------------- 
3237 void wxPropertyGrid::HandleCustomEditorEvent( wxEvent 
&event 
) 
3239     wxPGProperty
* selected 
= GetSelection(); 
3241     // Somehow, event is handled after property has been deselected. 
3242     // Possibly, but very rare. 
3243     if ( !selected 
|| selected
->HasFlag(wxPG_PROP_BEING_DELETED
) ) 
3246     if ( m_iFlags 
& wxPG_FL_IN_HANDLECUSTOMEDITOREVENT 
) 
3249     wxVariant 
pendingValue(selected
->GetValueRef()); 
3250     wxWindow
* wnd 
= GetEditorControl(); 
3251     wxWindow
* editorWnd 
= wxDynamicCast(event
.GetEventObject(), wxWindow
); 
3253     bool wasUnspecified 
= selected
->IsValueUnspecified(); 
3254     int usesAutoUnspecified 
= selected
->UsesAutoUnspecified(); 
3255     bool valueIsPending 
= false; 
3257     m_chgInfo_changedProperty 
= NULL
; 
3259     m_iFlags 
&= ~(wxPG_FL_VALIDATION_FAILED
|wxPG_FL_VALUE_CHANGE_IN_EVENT
); 
3262     // Filter out excess wxTextCtrl modified events 
3263     if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED 
&& 
3265          wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) ) 
3267         wxTextCtrl
* tc 
= (wxTextCtrl
*) wnd
; 
3269         wxString newTcValue 
= tc
->GetValue(); 
3270         if ( m_prevTcValue 
== newTcValue 
) 
3273         m_prevTcValue 
= newTcValue
; 
3276     SetInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT
); 
3278     bool validationFailure 
= false; 
3279     bool buttonWasHandled 
= false; 
3282     // Try common button handling 
3283     if ( m_wndEditor2 
&& event
.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED 
) 
3285         wxPGEditorDialogAdapter
* adapter 
= selected
->GetEditorDialog(); 
3289             buttonWasHandled 
= true; 
3290             // Store as res2, as previously (and still currently alternatively) 
3291             // dialogs can be shown by handling wxEVT_COMMAND_BUTTON_CLICKED 
3292             // in wxPGProperty::OnEvent(). 
3293             adapter
->ShowDialog( this, selected 
); 
3298     if ( !buttonWasHandled 
) 
3300         if ( wnd 
|| m_wndEditor2 
) 
3302             // First call editor class' event handler. 
3303             const wxPGEditor
* editor 
= selected
->GetEditorClass(); 
3305             if ( editor
->OnEvent( this, selected
, editorWnd
, event 
) ) 
3307                 // If changes, validate them 
3308                 if ( DoEditorValidate() ) 
3310                     if ( editor
->GetValueFromControl( pendingValue
, 
3313                         valueIsPending 
= true; 
3317                     validationFailure 
= true; 
3322         // Then the property's custom handler (must be always called, unless 
3323         // validation failed). 
3324         if ( !validationFailure 
) 
3325             buttonWasHandled 
= selected
->OnEvent( this, editorWnd
, event 
); 
3328     // SetValueInEvent(), as called in one of the functions referred above 
3329     // overrides editor's value. 
3330     if ( m_iFlags 
& wxPG_FL_VALUE_CHANGE_IN_EVENT 
) 
3332         valueIsPending 
= true; 
3333         pendingValue 
= m_changeInEventValue
; 
3334         selFlags 
|= wxPG_SEL_DIALOGVAL
; 
3337     if ( !validationFailure 
&& valueIsPending 
) 
3338         if ( !PerformValidation(selected
, pendingValue
) ) 
3339             validationFailure 
= true; 
3341     if ( validationFailure
) 
3343         OnValidationFailure(selected
, pendingValue
); 
3345     else if ( valueIsPending 
) 
3347         selFlags 
|= ( !wasUnspecified 
&& selected
->IsValueUnspecified() && usesAutoUnspecified 
) ? wxPG_SEL_SETUNSPEC 
: 0; 
3349         DoPropertyChanged(selected
, selFlags
); 
3350         EditorsValueWasNotModified(); 
3352         // Regardless of editor type, unfocus editor on 
3353         // text-editing related enter press. 
3354         if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER 
) 
3361         // No value after all 
3363         // Regardless of editor type, unfocus editor on 
3364         // text-editing related enter press. 
3365         if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER 
) 
3370         // Let unhandled button click events go to the parent 
3371         if ( !buttonWasHandled 
&& event
.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED 
) 
3373             wxCommandEvent 
evt(wxEVT_COMMAND_BUTTON_CLICKED
,GetId()); 
3374             GetEventHandler()->AddPendingEvent(evt
); 
3378     ClearInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT
); 
3381 // ----------------------------------------------------------------------- 
3382 // wxPropertyGrid editor control helper methods 
3383 // ----------------------------------------------------------------------- 
3385 wxRect 
wxPropertyGrid::GetEditorWidgetRect( wxPGProperty
* p
, int column 
) const 
3387     int itemy 
= p
->GetY2(m_lineHeight
); 
3389     int splitterX 
= m_pState
->DoGetSplitterPosition(column
-1); 
3390     int colEnd 
= splitterX 
+ m_pState
->m_colWidths
[column
]; 
3391     int imageOffset 
= 0; 
3393     // TODO: If custom image detection changes from current, change this. 
3394     if ( m_iFlags 
& wxPG_FL_CUR_USES_CUSTOM_IMAGE 
) 
3396         //m_iFlags |= wxPG_FL_CUR_USES_CUSTOM_IMAGE; 
3397         int iw 
= p
->OnMeasureImage().x
; 
3399             iw 
= wxPG_CUSTOM_IMAGE_WIDTH
; 
3400         imageOffset 
= p
->GetImageOffset(iw
); 
3405         splitterX
+imageOffset
+wxPG_XBEFOREWIDGET
+wxPG_CONTROL_MARGIN
+1, 
3407         colEnd
-splitterX
-wxPG_XBEFOREWIDGET
-wxPG_CONTROL_MARGIN
-imageOffset
-1, 
3412 // ----------------------------------------------------------------------- 
3414 wxRect 
wxPropertyGrid::GetImageRect( wxPGProperty
* p
, int item 
) const 
3416     wxSize sz 
= GetImageSize(p
, item
); 
3417     return wxRect(wxPG_CONTROL_MARGIN 
+ wxCC_CUSTOM_IMAGE_MARGIN1
, 
3418                   wxPG_CUSTOM_IMAGE_SPACINGY
, 
3423 // return size of custom paint image 
3424 wxSize 
wxPropertyGrid::GetImageSize( wxPGProperty
* p
, int item 
) const 
3426     // If called with NULL property, then return default image 
3427     // size for properties that use image. 
3429         return wxSize(wxPG_CUSTOM_IMAGE_WIDTH
,wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
)); 
3431     wxSize cis 
= p
->OnMeasureImage(item
); 
3433     int choiceCount 
= p
->m_choices
.GetCount(); 
3434     int comVals 
= p
->GetDisplayedCommonValueCount(); 
3435     if ( item 
>= choiceCount 
&& comVals 
> 0 ) 
3437         unsigned int cvi 
= item
-choiceCount
; 
3438         cis 
= GetCommonValue(cvi
)->GetRenderer()->GetImageSize(NULL
, 1, cvi
); 
3440     else if ( item 
>= 0 && choiceCount 
== 0 ) 
3441         return wxSize(0, 0); 
3446             cis
.x 
= wxPG_CUSTOM_IMAGE_WIDTH
; 
3451             cis
.y 
= wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
); 
3458 // ----------------------------------------------------------------------- 
3460 // takes scrolling into account 
3461 void wxPropertyGrid::ImprovedClientToScreen( int* px
, int* py 
) 
3464     GetViewStart(&vx
,&vy
); 
3465     vy
*=wxPG_PIXELS_PER_UNIT
; 
3466     vx
*=wxPG_PIXELS_PER_UNIT
; 
3469     ClientToScreen( px
, py 
); 
3472 // ----------------------------------------------------------------------- 
3474 wxPropertyGridHitTestResult 
wxPropertyGrid::HitTest( const wxPoint
& pt 
) const 
3477     GetViewStart(&pt2
.x
,&pt2
.y
); 
3478     pt2
.x 
*= wxPG_PIXELS_PER_UNIT
; 
3479     pt2
.y 
*= wxPG_PIXELS_PER_UNIT
; 
3483     return m_pState
->HitTest(pt2
); 
3486 // ----------------------------------------------------------------------- 
3488 // custom set cursor 
3489 void wxPropertyGrid::CustomSetCursor( int type
, bool override 
) 
3491     if ( type 
== m_curcursor 
&& !override 
) return; 
3493     wxCursor
* cursor 
= &wxPG_DEFAULT_CURSOR
; 
3495     if ( type 
== wxCURSOR_SIZEWE 
) 
3496         cursor 
= m_cursorSizeWE
; 
3498     m_canvas
->SetCursor( *cursor 
); 
3503 // ----------------------------------------------------------------------- 
3504 // wxPropertyGrid property selection, editor creation 
3505 // ----------------------------------------------------------------------- 
3508 // This class forwards events from property editor controls to wxPropertyGrid. 
3509 class wxPropertyGridEditorEventForwarder 
: public wxEvtHandler
 
3512     wxPropertyGridEditorEventForwarder( wxPropertyGrid
* propGrid 
) 
3513         : wxEvtHandler(), m_propGrid(propGrid
) 
3517     virtual ~wxPropertyGridEditorEventForwarder() 
3522     bool ProcessEvent( wxEvent
& event 
) 
3527         m_propGrid
->HandleCustomEditorEvent(event
); 
3529         return wxEvtHandler::ProcessEvent(event
); 
3532     wxPropertyGrid
*         m_propGrid
; 
3535 // Setups event handling for child control 
3536 void wxPropertyGrid::SetupChildEventHandling( wxWindow
* argWnd 
) 
3538     wxWindowID id 
= argWnd
->GetId(); 
3540     if ( argWnd 
== m_wndEditor 
) 
3542         argWnd
->Connect(id
, wxEVT_MOTION
, 
3543             wxMouseEventHandler(wxPropertyGrid::OnMouseMoveChild
), 
3545         argWnd
->Connect(id
, wxEVT_LEFT_UP
, 
3546             wxMouseEventHandler(wxPropertyGrid::OnMouseUpChild
), 
3548         argWnd
->Connect(id
, wxEVT_LEFT_DOWN
, 
3549             wxMouseEventHandler(wxPropertyGrid::OnMouseClickChild
), 
3551         argWnd
->Connect(id
, wxEVT_RIGHT_UP
, 
3552             wxMouseEventHandler(wxPropertyGrid::OnMouseRightClickChild
), 
3554         argWnd
->Connect(id
, wxEVT_ENTER_WINDOW
, 
3555             wxMouseEventHandler(wxPropertyGrid::OnMouseEntry
), 
3557         argWnd
->Connect(id
, wxEVT_LEAVE_WINDOW
, 
3558             wxMouseEventHandler(wxPropertyGrid::OnMouseEntry
), 
3562     wxPropertyGridEditorEventForwarder
* forwarder
; 
3563     forwarder 
= new wxPropertyGridEditorEventForwarder(this); 
3564     argWnd
->PushEventHandler(forwarder
); 
3566     argWnd
->Connect(id
, wxEVT_KEY_DOWN
, 
3567         wxCharEventHandler(wxPropertyGrid::OnChildKeyDown
), 
3571 void wxPropertyGrid::DestroyEditorWnd( wxWindow
* wnd 
) 
3578     // Do not free editors immediately (for sake of processing events) 
3579     wxPendingDelete
.Append(wnd
); 
3582 void wxPropertyGrid::FreeEditors() 
3585     // Return focus back to canvas from children (this is required at least for 
3586     // GTK+, which, unlike Windows, clears focus when control is destroyed 
3587     // instead of moving it to closest parent). 
3588     wxWindow
* focus 
= wxWindow::FindFocus(); 
3591         wxWindow
* parent 
= focus
->GetParent(); 
3594             if ( parent 
== m_canvas 
) 
3599             parent 
= parent
->GetParent(); 
3603     // Do not free editors immediately if processing events 
3606         wxEvtHandler
* handler 
= m_wndEditor2
->PopEventHandler(false); 
3607         m_wndEditor2
->Hide(); 
3608         wxPendingDelete
.Append( handler 
); 
3609         DestroyEditorWnd(m_wndEditor2
); 
3610         m_wndEditor2 
= NULL
; 
3615         wxEvtHandler
* handler 
= m_wndEditor
->PopEventHandler(false); 
3616         m_wndEditor
->Hide(); 
3617         wxPendingDelete
.Append( handler 
); 
3618         DestroyEditorWnd(m_wndEditor
); 
3623 // Call with NULL to de-select property 
3624 bool wxPropertyGrid::DoSelectProperty( wxPGProperty
* p
, unsigned int flags 
) 
3629         wxLogDebug(wxT("SelectProperty( %s (%s[%i]) )"),p->m_label.c_str(), 
3630             p->m_parent->m_label.c_str(),p->GetIndexInParent()); 
3634         wxLogDebug(wxT("SelectProperty( NULL, -1 )")); 
3638     if ( m_inDoSelectProperty 
) 
3641     m_inDoSelectProperty 
= 1; 
3645         m_inDoSelectProperty 
= 0; 
3649     wxArrayPGProperty prevSelection 
= m_pState
->m_selection
; 
3650     wxPGProperty
* prevFirstSel
; 
3652     if ( prevSelection
.size() > 0 ) 
3653         prevFirstSel 
= prevSelection
[0]; 
3655         prevFirstSel 
= NULL
; 
3657     if ( prevFirstSel 
&& prevFirstSel
->HasFlag(wxPG_PROP_BEING_DELETED
) ) 
3658         prevFirstSel 
= NULL
; 
3660     // Always send event, as this is indirect call 
3661     DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE
); 
3665         wxPrintf( "Selected %s\n", prevFirstSel->GetClassInfo()->GetClassName() ); 
3667         wxPrintf( "None selected\n" ); 
3670         wxPrintf( "P =  %s\n", p->GetClassInfo()->GetClassName() ); 
3672         wxPrintf( "P = NULL\n" ); 
3675     // If we are frozen, then just set the values. 
3678         m_iFlags 
&= ~(wxPG_FL_ABNORMAL_EDITOR
); 
3679         m_editorFocused 
= 0; 
3680         m_pState
->DoSetSelection(p
); 
3682         // If frozen, always free controls. But don't worry, as Thaw will 
3683         // recall SelectProperty to recreate them. 
3686         // Prevent any further selection measures in this call 
3692         if ( prevFirstSel 
== p 
&& 
3693              prevSelection
.size() <= 1 && 
3694              !(flags 
& wxPG_SEL_FORCE
) ) 
3696             // Only set focus if not deselecting 
3699                 if ( flags 
& wxPG_SEL_FOCUS 
) 
3703                         m_wndEditor
->SetFocus(); 
3704                         m_editorFocused 
= 1; 
3713             m_inDoSelectProperty 
= 0; 
3718         // First, deactivate previous 
3721             OnValidationFailureReset(prevFirstSel
); 
3723             // Must double-check if this is an selected in case of forceswitch 
3724             if ( p 
!= prevFirstSel 
) 
3726                 if ( !CommitChangesFromEditor(flags
) ) 
3728                     // Validation has failed, so we can't exit the previous editor 
3729                     //::wxMessageBox(_("Please correct the value or press ESC to cancel the edit."), 
3730                     //               _("Invalid Value"),wxOK|wxICON_ERROR); 
3731                     m_inDoSelectProperty 
= 0; 
3738             m_iFlags 
&= ~(wxPG_FL_ABNORMAL_EDITOR
); 
3739             EditorsValueWasNotModified(); 
3742         SetInternalFlag(wxPG_FL_IN_SELECT_PROPERTY
); 
3744         m_pState
->DoSetSelection(p
); 
3746         // Redraw unselected 
3747         for ( unsigned int i
=0; i
<prevSelection
.size(); i
++ ) 
3749             DrawItem(prevSelection
[i
]); 
3753         // Then, activate the one given. 
3756             int propY 
= p
->GetY2(m_lineHeight
); 
3758             int splitterX 
= GetSplitterPosition(); 
3759             m_editorFocused 
= 0; 
3760             m_iFlags 
|= wxPG_FL_PRIMARY_FILLS_ENTIRE
; 
3761             if ( p 
!= prevFirstSel 
) 
3762                 m_iFlags 
&= ~(wxPG_FL_VALIDATION_FAILED
); 
3764             wxASSERT( m_wndEditor 
== NULL 
); 
3767             // Only create editor for non-disabled non-caption 
3768             if ( !p
->IsCategory() && !(p
->m_flags 
& wxPG_PROP_DISABLED
) ) 
3770             // do this for non-caption items 
3774                 // Do we need to paint the custom image, if any? 
3775                 m_iFlags 
&= ~(wxPG_FL_CUR_USES_CUSTOM_IMAGE
); 
3776                 if ( (p
->m_flags 
& wxPG_PROP_CUSTOMIMAGE
) && 
3777                      !p
->GetEditorClass()->CanContainCustomImage() 
3779                     m_iFlags 
|= wxPG_FL_CUR_USES_CUSTOM_IMAGE
; 
3781                 wxRect grect 
= GetEditorWidgetRect(p
, m_selColumn
); 
3782                 wxPoint goodPos 
= grect
.GetPosition(); 
3784                 const wxPGEditor
* editor 
= p
->GetEditorClass(); 
3785                 wxCHECK_MSG(editor
, false, 
3786                     wxT("NULL editor class not allowed")); 
3788                 m_iFlags 
&= ~wxPG_FL_FIXED_WIDTH_EDITOR
; 
3790                 wxPGWindowList wndList 
= editor
->CreateControls(this, 
3795                 m_wndEditor 
= wndList
.m_primary
; 
3796                 m_wndEditor2 
= wndList
.m_secondary
; 
3797                 wxWindow
* primaryCtrl 
= GetEditorControl(); 
3800                 // Essentially, primaryCtrl == m_wndEditor 
3803                 // NOTE: It is allowed for m_wndEditor to be NULL - in this case 
3804                 //       value is drawn as normal, and m_wndEditor2 is assumed 
3805                 //       to be a right-aligned button that triggers a separate editorCtrl 
3810                     wxASSERT_MSG( m_wndEditor
->GetParent() == GetPanel(), 
3811                                   wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") ); 
3813                     // Set validator, if any 
3814                 #if wxUSE_VALIDATORS 
3815                     wxValidator
* validator 
= p
->GetValidator(); 
3817                         primaryCtrl
->SetValidator(*validator
); 
3820                     if ( m_wndEditor
->GetSize().y 
> (m_lineHeight
+6) ) 
3821                         m_iFlags 
|= wxPG_FL_ABNORMAL_EDITOR
; 
3823                     // If it has modified status, use bold font 
3824                     // (must be done before capturing m_ctrlXAdjust) 
3825                     if ( (p
->m_flags 
& wxPG_PROP_MODIFIED
) && (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
3826                         SetCurControlBoldFont(); 
3829                     // Fix TextCtrl indentation 
3830                 #if defined(__WXMSW__) && !defined(__WXWINCE__) 
3831                     wxTextCtrl
* tc 
= NULL
; 
3832                     if ( primaryCtrl
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) ) 
3833                         tc 
= ((wxOwnerDrawnComboBox
*)primaryCtrl
)->GetTextCtrl(); 
3835                         tc 
= wxDynamicCast(primaryCtrl
, wxTextCtrl
); 
3837                         ::SendMessage(GetHwndOf(tc
), EM_SETMARGINS
, EC_LEFTMARGIN 
| EC_RIGHTMARGIN
, MAKELONG(0, 0)); 
3840                     // Store x relative to splitter (we'll need it). 
3841                     m_ctrlXAdjust 
= m_wndEditor
->GetPosition().x 
- splitterX
; 
3843                     // Check if background clear is not necessary 
3844                     wxPoint pos 
= m_wndEditor
->GetPosition(); 
3845                     if ( pos
.x 
> (splitterX
+1) || pos
.y 
> propY 
) 
3847                         m_iFlags 
&= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE
); 
3850                     m_wndEditor
->SetSizeHints(3, 3); 
3852                     SetupChildEventHandling(primaryCtrl
); 
3854                     // Focus and select all (wxTextCtrl, wxComboBox etc) 
3855                     if ( flags 
& wxPG_SEL_FOCUS 
) 
3857                         primaryCtrl
->SetFocus(); 
3859                         p
->GetEditorClass()->OnFocus(p
, primaryCtrl
); 
3865                     wxASSERT_MSG( m_wndEditor2
->GetParent() == GetPanel(), 
3866                                   wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") ); 
3868                     // Get proper id for wndSecondary 
3869                     m_wndSecId 
= m_wndEditor2
->GetId(); 
3870                     wxWindowList children 
= m_wndEditor2
->GetChildren(); 
3871                     wxWindowList::iterator node 
= children
.begin(); 
3872                     if ( node 
!= children
.end() ) 
3873                         m_wndSecId 
= ((wxWindow
*)*node
)->GetId(); 
3875                     m_wndEditor2
->SetSizeHints(3,3); 
3877                     m_wndEditor2
->Show(); 
3879                     SetupChildEventHandling(m_wndEditor2
); 
3881                     // If no primary editor, focus to button to allow 
3882                     // it to interprete ENTER etc. 
3883                     // NOTE: Due to problems focusing away from it, this 
3884                     //       has been disabled. 
3886                     if ( (flags & wxPG_SEL_FOCUS) && !m_wndEditor ) 
3887                         m_wndEditor2->SetFocus(); 
3891                 if ( flags 
& wxPG_SEL_FOCUS 
) 
3892                     m_editorFocused 
= 1; 
3897                 // Make sure focus is in grid canvas (important for wxGTK, at least) 
3901             EditorsValueWasNotModified(); 
3903             // If it's inside collapsed section, expand parent, scroll, etc. 
3904             // Also, if it was partially visible, scroll it into view. 
3905             if ( !(flags 
& wxPG_SEL_NONVISIBLE
) ) 
3910                 m_wndEditor
->Show(true); 
3913             if ( !(flags 
& wxPG_SEL_NO_REFRESH
) ) 
3918             // Make sure focus is in grid canvas 
3922         ClearInternalFlag(wxPG_FL_IN_SELECT_PROPERTY
); 
3928     // Show help text in status bar. 
3929     //   (if found and grid not embedded in manager with help box and 
3930     //    style wxPG_EX_HELP_AS_TOOLTIPS is not used). 
3933     if ( !(GetExtraStyle() & wxPG_EX_HELP_AS_TOOLTIPS
) ) 
3935         wxStatusBar
* statusbar 
= NULL
; 
3936         if ( !(m_iFlags 
& wxPG_FL_NOSTATUSBARHELP
) ) 
3938             wxFrame
* frame 
= wxDynamicCast(::wxGetTopLevelParent(this),wxFrame
); 
3940                 statusbar 
= frame
->GetStatusBar(); 
3945             const wxString
* pHelpString 
= (const wxString
*) NULL
; 
3949                 pHelpString 
= &p
->GetHelpString(); 
3950                 if ( pHelpString
->length() ) 
3952                     // Set help box text. 
3953                     statusbar
->SetStatusText( *pHelpString 
); 
3954                     m_iFlags 
|= wxPG_FL_STRING_IN_STATUSBAR
; 
3958             if ( (!pHelpString 
|| !pHelpString
->length()) && 
3959                  (m_iFlags 
& wxPG_FL_STRING_IN_STATUSBAR
) ) 
3961                 // Clear help box - but only if it was written 
3962                 // by us at previous time. 
3963                 statusbar
->SetStatusText( m_emptyString 
); 
3964                 m_iFlags 
&= ~(wxPG_FL_STRING_IN_STATUSBAR
); 
3970     m_inDoSelectProperty 
= 0; 
3972     // call wx event handler (here so that it also occurs on deselection) 
3973     if ( !(flags 
& wxPG_SEL_DONT_SEND_EVENT
) ) 
3974         SendEvent( wxEVT_PG_SELECTED
, p
, NULL 
); 
3979 // ----------------------------------------------------------------------- 
3981 bool wxPropertyGrid::UnfocusEditor() 
3983     wxPGProperty
* selected 
= GetSelection(); 
3985     if ( !selected 
|| !m_wndEditor 
|| m_frozen 
) 
3988     if ( !CommitChangesFromEditor(0) ) 
3997 // ----------------------------------------------------------------------- 
3999 void wxPropertyGrid::RefreshEditor() 
4001     wxPGProperty
* p 
= GetSelection(); 
4005     wxWindow
* wnd 
= GetEditorControl(); 
4009     // Set editor font boldness - must do this before 
4010     // calling UpdateControl(). 
4011     if ( HasFlag(wxPG_BOLD_MODIFIED
) ) 
4013         if ( p
->HasFlag(wxPG_PROP_MODIFIED
) ) 
4014             wnd
->SetFont(GetCaptionFont()); 
4016             wnd
->SetFont(GetFont()); 
4019     const wxPGEditor
* editorClass 
= p
->GetEditorClass(); 
4021     editorClass
->UpdateControl(p
, wnd
); 
4023     if ( p
->IsValueUnspecified() ) 
4024         editorClass 
->SetValueToUnspecified(p
, wnd
); 
4027 // ----------------------------------------------------------------------- 
4029 bool wxPropertyGrid::SelectProperty( wxPGPropArg id
, bool focus 
) 
4031     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) 
4033     int flags 
= wxPG_SEL_DONT_SEND_EVENT
; 
4035         flags 
|= wxPG_SEL_FOCUS
; 
4037     return DoSelectProperty(p
, flags
); 
4040 // ----------------------------------------------------------------------- 
4041 // wxPropertyGrid expand/collapse state 
4042 // ----------------------------------------------------------------------- 
4044 bool wxPropertyGrid::DoCollapse( wxPGProperty
* p
, bool sendEvents 
) 
4046     wxPGProperty
* pwc 
= wxStaticCast(p
, wxPGProperty
); 
4047     wxPGProperty
* selected 
= GetSelection(); 
4049     // If active editor was inside collapsed section, then disable it 
4050     if ( selected 
&& selected
->IsSomeParent(p
) ) 
4055     // Store dont-center-splitter flag 'cause we need to temporarily set it 
4056     wxUint32 old_flag 
= m_iFlags 
& wxPG_FL_DONT_CENTER_SPLITTER
; 
4057     m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
4059     bool res 
= m_pState
->DoCollapse(pwc
); 
4064             SendEvent( wxEVT_PG_ITEM_COLLAPSED
, p 
); 
4066         RecalculateVirtualSize(); 
4068         // Redraw etc. only if collapsed was visible. 
4069         if (pwc
->IsVisible() && 
4071             ( !pwc
->IsCategory() || !(m_windowStyle 
& wxPG_HIDE_CATEGORIES
) ) ) 
4073             // When item is collapsed so that scrollbar would move, 
4074             // graphics mess is about (unless we redraw everything). 
4079     // Clear dont-center-splitter flag if it wasn't set 
4080     m_iFlags 
= (m_iFlags 
& ~wxPG_FL_DONT_CENTER_SPLITTER
) | old_flag
; 
4085 // ----------------------------------------------------------------------- 
4087 bool wxPropertyGrid::DoExpand( wxPGProperty
* p
, bool sendEvents 
) 
4089     wxCHECK_MSG( p
, false, wxT("invalid property id") ); 
4091     wxPGProperty
* pwc 
= (wxPGProperty
*)p
; 
4093     // Store dont-center-splitter flag 'cause we need to temporarily set it 
4094     wxUint32 old_flag 
= m_iFlags 
& wxPG_FL_DONT_CENTER_SPLITTER
; 
4095     m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
4097     bool res 
= m_pState
->DoExpand(pwc
); 
4102             SendEvent( wxEVT_PG_ITEM_EXPANDED
, p 
); 
4104         RecalculateVirtualSize(); 
4106         // Redraw etc. only if expanded was visible. 
4107         if ( pwc
->IsVisible() && !m_frozen 
&& 
4108              ( !pwc
->IsCategory() || !(m_windowStyle 
& wxPG_HIDE_CATEGORIES
) ) 
4112         #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
4115             DrawItems(pwc
, NULL
); 
4120     // Clear dont-center-splitter flag if it wasn't set 
4121     m_iFlags 
= (m_iFlags 
& ~wxPG_FL_DONT_CENTER_SPLITTER
) | old_flag
; 
4126 // ----------------------------------------------------------------------- 
4128 bool wxPropertyGrid::DoHideProperty( wxPGProperty
* p
, bool hide
, int flags 
) 
4131         return m_pState
->DoHideProperty(p
, hide
, flags
); 
4133     wxArrayPGProperty selection 
= m_pState
->m_selection
;  // Must use a copy 
4134     int selRemoveCount 
= 0; 
4135     for ( unsigned int i
=0; i
<selection
.size(); i
++ ) 
4137         wxPGProperty
* selected 
= selection
[i
]; 
4138         if ( selected 
== p 
|| selected
->IsSomeParent(p
) ) 
4140             if ( !DoRemoveFromSelection(p
, flags
) ) 
4142             selRemoveCount 
+= 1; 
4146     m_pState
->DoHideProperty(p
, hide
, flags
); 
4148     RecalculateVirtualSize(); 
4155 // ----------------------------------------------------------------------- 
4156 // wxPropertyGrid size related methods 
4157 // ----------------------------------------------------------------------- 
4159 void wxPropertyGrid::RecalculateVirtualSize( int forceXPos 
) 
4161     if ( (m_iFlags 
& wxPG_FL_RECALCULATING_VIRTUAL_SIZE
) || m_frozen 
) 
4165     // If virtual height was changed, then recalculate editor control position(s) 
4166     if ( m_pState
->m_vhCalcPending 
) 
4167         CorrectEditorWidgetPosY(); 
4169     m_pState
->EnsureVirtualHeight(); 
4171     wxASSERT_LEVEL_2_MSG( 
4172         m_pState
->GetVirtualHeight() == m_pState
->GetActualVirtualHeight(), 
4173         "VirtualHeight and ActualVirtualHeight should match" 
4176     m_iFlags 
|= wxPG_FL_RECALCULATING_VIRTUAL_SIZE
; 
4178     int x 
= m_pState
->m_width
; 
4179     int y 
= m_pState
->m_virtualHeight
; 
4182     GetClientSize(&width
,&height
); 
4184     // Now adjust virtual size. 
4185     SetVirtualSize(x
, y
); 
4191     // Adjust scrollbars 
4192     if ( HasVirtualWidth() ) 
4194         xAmount 
= x
/wxPG_PIXELS_PER_UNIT
; 
4195         xPos 
= GetScrollPos( wxHORIZONTAL 
); 
4198     if ( forceXPos 
!= -1 ) 
4201     else if ( xPos 
> (xAmount
-(width
/wxPG_PIXELS_PER_UNIT
)) ) 
4204     int yAmount 
= y 
/ wxPG_PIXELS_PER_UNIT
; 
4205     int yPos 
= GetScrollPos( wxVERTICAL 
); 
4207     SetScrollbars( wxPG_PIXELS_PER_UNIT
, wxPG_PIXELS_PER_UNIT
, 
4208                    xAmount
, yAmount
, xPos
, yPos
, true ); 
4210     // Must re-get size now 
4211     GetClientSize(&width
,&height
); 
4213     if ( !HasVirtualWidth() ) 
4215         m_pState
->SetVirtualWidth(width
); 
4222     m_canvas
->SetSize( x
, y 
); 
4224     m_pState
->CheckColumnWidths(); 
4226     if ( GetSelection() ) 
4227         CorrectEditorWidgetSizeX(); 
4229     m_iFlags 
&= ~wxPG_FL_RECALCULATING_VIRTUAL_SIZE
; 
4232 // ----------------------------------------------------------------------- 
4234 void wxPropertyGrid::OnResize( wxSizeEvent
& event 
) 
4236     if ( !(m_iFlags 
& wxPG_FL_INITIALIZED
) ) 
4240     GetClientSize(&width
,&height
); 
4245 #if wxPG_DOUBLE_BUFFER 
4246     if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING
) ) 
4248         int dblh 
= (m_lineHeight
*2); 
4249         if ( !m_doubleBuffer 
) 
4251             // Create double buffer bitmap to draw on, if none 
4252             int w 
= (width
>250)?width
:250; 
4253             int h 
= height 
+ dblh
; 
4255             m_doubleBuffer 
= new wxBitmap( w
, h 
); 
4259             int w 
= m_doubleBuffer
->GetWidth(); 
4260             int h 
= m_doubleBuffer
->GetHeight(); 
4262             // Double buffer must be large enough 
4263             if ( w 
< width 
|| h 
< (height
+dblh
) ) 
4265                 if ( w 
< width 
) w 
= width
; 
4266                 if ( h 
< (height
+dblh
) ) h 
= height 
+ dblh
; 
4267                 delete m_doubleBuffer
; 
4268                 m_doubleBuffer 
= new wxBitmap( w
, h 
); 
4275     m_pState
->OnClientWidthChange( width
, event
.GetSize().x 
- m_ncWidth
, true ); 
4276     m_ncWidth 
= event
.GetSize().x
; 
4280         if ( m_pState
->m_itemsAdded 
) 
4281             PrepareAfterItemsAdded(); 
4283             // Without this, virtual size (atleast under wxGTK) will be skewed 
4284             RecalculateVirtualSize(); 
4290 // ----------------------------------------------------------------------- 
4292 void wxPropertyGrid::SetVirtualWidth( int width 
) 
4296         // Disable virtual width 
4297         width 
= GetClientSize().x
; 
4298         ClearInternalFlag(wxPG_FL_HAS_VIRTUAL_WIDTH
); 
4302         // Enable virtual width 
4303         SetInternalFlag(wxPG_FL_HAS_VIRTUAL_WIDTH
); 
4305     m_pState
->SetVirtualWidth( width 
); 
4308 void wxPropertyGrid::SetFocusOnCanvas() 
4310     m_canvas
->SetFocusIgnoringChildren(); 
4311     m_editorFocused 
= 0; 
4314 // ----------------------------------------------------------------------- 
4315 // wxPropertyGrid mouse event handling 
4316 // ----------------------------------------------------------------------- 
4318 // selFlags uses same values DoSelectProperty's flags 
4319 // Returns true if event was vetoed. 
4320 bool wxPropertyGrid::SendEvent( int eventType
, wxPGProperty
* p
, 
4322                                 unsigned int selFlags
, 
4323                                 unsigned int column 
) 
4325     // Send property grid event of specific type and with specific property 
4326     wxPropertyGridEvent 
evt( eventType
, m_eventObject
->GetId() ); 
4327     evt
.SetPropertyGrid(this); 
4328     evt
.SetEventObject(m_eventObject
); 
4330     evt
.SetColumn(column
); 
4333         evt
.SetCanVeto(true); 
4334         evt
.SetupValidationInfo(); 
4335         m_validationInfo
.m_pValue 
= pValue
; 
4337     else if ( !(selFlags 
& wxPG_SEL_NOVALIDATE
) ) 
4339         evt
.SetCanVeto(true); 
4342     wxEvtHandler
* evtHandler 
= m_eventObject
->GetEventHandler(); 
4344     evtHandler
->ProcessEvent(evt
); 
4346     return evt
.WasVetoed(); 
4349 // ----------------------------------------------------------------------- 
4351 // Return false if should be skipped 
4352 bool wxPropertyGrid::HandleMouseClick( int x
, unsigned int y
, wxMouseEvent 
&event 
) 
4356     // Need to set focus? 
4357     if ( !(m_iFlags 
& wxPG_FL_FOCUSED
) ) 
4362     wxPropertyGridPageState
* state 
= m_pState
; 
4364     int splitterHitOffset
; 
4365     int columnHit 
= state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
4367     wxPGProperty
* p 
= DoGetItemAtY(y
); 
4371         int depth 
= (int)p
->GetDepth() - 1; 
4373         int marginEnds 
= m_marginWidth 
+ ( depth 
* m_subgroup_extramargin 
); 
4375         if ( x 
>= marginEnds 
) 
4379             if ( p
->IsCategory() ) 
4381                 // This is category. 
4382                 wxPropertyCategory
* pwc 
= (wxPropertyCategory
*)p
; 
4384                 int textX 
= m_marginWidth 
+ ((unsigned int)((pwc
->m_depth
-1)*m_subgroup_extramargin
)); 
4386                 // Expand, collapse, activate etc. if click on text or left of splitter. 
4389                      ( x 
< (textX
+pwc
->GetTextExtent(this, m_captionFont
)+(wxPG_CAPRECTXMARGIN
*2)) || 
4394                     if ( !AddToSelectionFromInputEvent( p
, 
4399                     // On double-click, expand/collapse. 
4400                     if ( event
.ButtonDClick() && !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
4402                         if ( pwc
->IsExpanded() ) DoCollapse( p
, true ); 
4403                         else DoExpand( p
, true ); 
4407             else if ( splitterHit 
== -1 ) 
4410                 unsigned int selFlag 
= 0; 
4411                 if ( columnHit 
== 1 ) 
4413                     m_iFlags 
|= wxPG_FL_ACTIVATION_BY_CLICK
; 
4414                     selFlag 
= wxPG_SEL_FOCUS
; 
4416                 if ( !AddToSelectionFromInputEvent( p
, 
4422                 m_iFlags 
&= ~(wxPG_FL_ACTIVATION_BY_CLICK
); 
4424                 if ( p
->GetChildCount() && !p
->IsCategory() ) 
4425                     // On double-click, expand/collapse. 
4426                     if ( event
.ButtonDClick() && !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
4428                         wxPGProperty
* pwc 
= (wxPGProperty
*)p
; 
4429                         if ( pwc
->IsExpanded() ) DoCollapse( p
, true ); 
4430                         else DoExpand( p
, true ); 
4437             // click on splitter 
4438                 if ( !(m_windowStyle 
& wxPG_STATIC_SPLITTER
) ) 
4440                     if ( event
.GetEventType() == wxEVT_LEFT_DCLICK 
) 
4442                         // Double-clicking the splitter causes auto-centering 
4443                         CenterSplitter( true ); 
4445                     else if ( m_dragStatus 
== 0 ) 
4448                         // Begin draggin the splitter 
4452                         DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE
); 
4456                             // Changes must be committed here or the 
4457                             // value won't be drawn correctly 
4458                             if ( !CommitChangesFromEditor() ) 
4461                             m_wndEditor
->Show ( false ); 
4464                         if ( !(m_iFlags 
& wxPG_FL_MOUSE_CAPTURED
) ) 
4466                             m_canvas
->CaptureMouse(); 
4467                             m_iFlags 
|= wxPG_FL_MOUSE_CAPTURED
; 
4471                         m_draggedSplitter 
= splitterHit
; 
4472                         m_dragOffset 
= splitterHitOffset
; 
4474                         wxClientDC 
dc(m_canvas
); 
4476                     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
4477                         // Fixes button disappearance bug 
4479                             m_wndEditor2
->Show ( false ); 
4482                         m_startingSplitterX 
= x 
- splitterHitOffset
; 
4490             if ( p
->GetChildCount() ) 
4492                 int nx 
= x 
+ m_marginWidth 
- marginEnds
; // Normalize x. 
4494                 if ( (nx 
>= m_gutterWidth 
&& nx 
< (m_gutterWidth
+m_iconWidth
)) ) 
4496                     int y2 
= y 
% m_lineHeight
; 
4497                     if ( (y2 
>= m_buttonSpacingY 
&& y2 
< (m_buttonSpacingY
+m_iconHeight
)) ) 
4499                         // On click on expander button, expand/collapse 
4500                         if ( ((wxPGProperty
*)p
)->IsExpanded() ) 
4501                             DoCollapse( p
, true ); 
4503                             DoExpand( p
, true ); 
4512 // ----------------------------------------------------------------------- 
4514 bool wxPropertyGrid::HandleMouseRightClick( int WXUNUSED(x
), 
4515                                             unsigned int WXUNUSED(y
), 
4516                                             wxMouseEvent
& event 
) 
4520         // Select property here as well 
4521         wxPGProperty
* p 
= m_propHover
; 
4522         AddToSelectionFromInputEvent(p
, m_colHover
, &event
); 
4524         // Send right click event. 
4525         SendEvent( wxEVT_PG_RIGHT_CLICK
, p 
); 
4532 // ----------------------------------------------------------------------- 
4534 bool wxPropertyGrid::HandleMouseDoubleClick( int WXUNUSED(x
), 
4535                                              unsigned int WXUNUSED(y
), 
4536                                              wxMouseEvent
& event 
) 
4540         // Select property here as well 
4541         wxPGProperty
* p 
= m_propHover
; 
4543         AddToSelectionFromInputEvent(p
, m_colHover
, &event
); 
4545         // Send double-click event. 
4546         SendEvent( wxEVT_PG_DOUBLE_CLICK
, m_propHover 
); 
4553 // ----------------------------------------------------------------------- 
4555 #if wxPG_SUPPORT_TOOLTIPS 
4557 void wxPropertyGrid::SetToolTip( const wxString
& tipString 
) 
4559     if ( tipString
.length() ) 
4561         m_canvas
->SetToolTip(tipString
); 
4565     #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4566         m_canvas
->SetToolTip( m_emptyString 
); 
4568         m_canvas
->SetToolTip( NULL 
); 
4573 #endif // #if wxPG_SUPPORT_TOOLTIPS 
4575 // ----------------------------------------------------------------------- 
4577 // Return false if should be skipped 
4578 bool wxPropertyGrid::HandleMouseMove( int x
, unsigned int y
, wxMouseEvent 
&event 
) 
4580     // Safety check (needed because mouse capturing may 
4581     // otherwise freeze the control) 
4582     if ( m_dragStatus 
> 0 && !event
.Dragging() ) 
4584         HandleMouseUp(x
,y
,event
); 
4587     wxPropertyGridPageState
* state 
= m_pState
; 
4589     int splitterHitOffset
; 
4590     int columnHit 
= state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
4591     int splitterX 
= x 
- splitterHitOffset
; 
4593     m_colHover 
= columnHit
; 
4595     if ( m_dragStatus 
> 0 ) 
4597         if ( x 
> (m_marginWidth 
+ wxPG_DRAG_MARGIN
) && 
4598              x 
< (m_pState
->m_width 
- wxPG_DRAG_MARGIN
) ) 
4601             int newSplitterX 
= x 
- m_dragOffset
; 
4602             int splitterX 
= x 
- splitterHitOffset
; 
4604             // Splitter redraw required? 
4605             if ( newSplitterX 
!= splitterX 
) 
4608                 SetInternalFlag(wxPG_FL_DONT_CENTER_SPLITTER
); 
4609                 state
->DoSetSplitterPosition( newSplitterX
, m_draggedSplitter
, false ); 
4610                 state
->m_fSplitterX 
= (float) newSplitterX
; 
4612                 if ( GetSelection() ) 
4613                     CorrectEditorWidgetSizeX(); 
4627         int ih 
= m_lineHeight
; 
4630     #if wxPG_SUPPORT_TOOLTIPS 
4631         wxPGProperty
* prevHover 
= m_propHover
; 
4632         unsigned char prevSide 
= m_mouseSide
; 
4634         int curPropHoverY 
= y 
- (y 
% ih
); 
4636         // On which item it hovers 
4639              ( sy 
< m_propHoverY 
|| sy 
>= (m_propHoverY
+ih
) ) 
4642             // Mouse moves on another property 
4644             m_propHover 
= DoGetItemAtY(y
); 
4645             m_propHoverY 
= curPropHoverY
; 
4648             SendEvent( wxEVT_PG_HIGHLIGHTED
, m_propHover 
); 
4651     #if wxPG_SUPPORT_TOOLTIPS 
4652         // Store which side we are on 
4654         if ( columnHit 
== 1 ) 
4656         else if ( columnHit 
== 0 ) 
4660         // If tooltips are enabled, show label or value as a tip 
4661         // in case it doesn't otherwise show in full length. 
4663         if ( m_windowStyle 
& wxPG_TOOLTIPS 
) 
4665             wxToolTip
* tooltip 
= m_canvas
->GetToolTip(); 
4667             if ( m_propHover 
!= prevHover 
|| prevSide 
!= m_mouseSide 
) 
4669                 if ( m_propHover 
&& !m_propHover
->IsCategory() ) 
4672                     if ( GetExtraStyle() & wxPG_EX_HELP_AS_TOOLTIPS 
) 
4674                         // Show help string as a tooltip 
4675                         wxString tipString 
= m_propHover
->GetHelpString(); 
4677                         SetToolTip(tipString
); 
4681                         // Show cropped value string as a tooltip 
4685                         if ( m_mouseSide 
== 1 ) 
4687                             tipString 
= m_propHover
->m_label
; 
4688                             space 
= splitterX
-m_marginWidth
-3; 
4690                         else if ( m_mouseSide 
== 2 ) 
4692                             tipString 
= m_propHover
->GetDisplayedString(); 
4694                             space 
= m_width 
- splitterX
; 
4695                             if ( m_propHover
->m_flags 
& wxPG_PROP_CUSTOMIMAGE 
) 
4696                                 space 
-= wxPG_CUSTOM_IMAGE_WIDTH 
+ wxCC_CUSTOM_IMAGE_MARGIN1 
+ wxCC_CUSTOM_IMAGE_MARGIN2
; 
4702                             GetTextExtent( tipString
, &tw
, &th
, 0, 0 ); 
4705                                 SetToolTip( tipString 
); 
4712                             #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4713                                 m_canvas
->SetToolTip( m_emptyString 
); 
4715                                 m_canvas
->SetToolTip( NULL 
); 
4726                     #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4727                         m_canvas
->SetToolTip( m_emptyString 
); 
4729                         m_canvas
->SetToolTip( NULL 
); 
4737         if ( splitterHit 
== -1 || 
4739              HasFlag(wxPG_STATIC_SPLITTER
) ) 
4741             // hovering on something else 
4742             if ( m_curcursor 
!= wxCURSOR_ARROW 
) 
4743                 CustomSetCursor( wxCURSOR_ARROW 
); 
4747             // Do not allow splitter cursor on caption items. 
4748             // (also not if we were dragging and its started 
4749             // outside the splitter region) 
4751             if ( !m_propHover
->IsCategory() && 
4755                 // hovering on splitter 
4757                 // NB: Condition disabled since MouseLeave event (from the editor control) cannot be 
4758                 //     reliably detected. 
4759                 //if ( m_curcursor != wxCURSOR_SIZEWE ) 
4760                 CustomSetCursor( wxCURSOR_SIZEWE
, true ); 
4766                 // hovering on something else 
4767                 if ( m_curcursor 
!= wxCURSOR_ARROW 
) 
4768                     CustomSetCursor( wxCURSOR_ARROW 
); 
4773         // Multi select by dragging 
4775         if ( GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION 
&& 
4776              event
.LeftIsDown() && 
4779              !state
->DoIsPropertySelected(m_propHover
) ) 
4781             DoAddToSelection(m_propHover
); 
4787 // ----------------------------------------------------------------------- 
4789 // Also handles Leaving event 
4790 bool wxPropertyGrid::HandleMouseUp( int x
, unsigned int WXUNUSED(y
), 
4791                                     wxMouseEvent 
&WXUNUSED(event
) ) 
4793     wxPropertyGridPageState
* state 
= m_pState
; 
4797     int splitterHitOffset
; 
4798     state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
4800     // No event type check - basicly calling this method should 
4801     // just stop dragging. 
4802     // Left up after dragged? 
4803     if ( m_dragStatus 
>= 1 ) 
4806     // End Splitter Dragging 
4808         // DO NOT ENABLE FOLLOWING LINE! 
4809         // (it is only here as a reminder to not to do it) 
4812         // Disable splitter auto-centering 
4813         m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
4815         // This is necessary to return cursor 
4816         if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
4818             m_canvas
->ReleaseMouse(); 
4819             m_iFlags 
&= ~(wxPG_FL_MOUSE_CAPTURED
); 
4822         // Set back the default cursor, if necessary 
4823         if ( splitterHit 
== -1 || 
4826             CustomSetCursor( wxCURSOR_ARROW 
); 
4831         // Control background needs to be cleared 
4832         wxPGProperty
* selected 
= GetSelection(); 
4833         if ( !(m_iFlags 
& wxPG_FL_PRIMARY_FILLS_ENTIRE
) && selected 
) 
4834             DrawItem( selected 
); 
4838             m_wndEditor
->Show ( true ); 
4841     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
4842         // Fixes button disappearance bug 
4844             m_wndEditor2
->Show ( true ); 
4847         // This clears the focus. 
4848         m_editorFocused 
= 0; 
4854 // ----------------------------------------------------------------------- 
4856 bool wxPropertyGrid::OnMouseCommon( wxMouseEvent
& event
, int* px
, int* py 
) 
4858     int splitterX 
= GetSplitterPosition(); 
4861     //CalcUnscrolledPosition( event.m_x, event.m_y, &ux, &uy ); 
4865     wxWindow
* wnd 
= GetEditorControl(); 
4867     // Hide popup on clicks 
4868     if ( event
.GetEventType() != wxEVT_MOTION 
) 
4869         if ( wnd 
&& wnd
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) ) 
4871             ((wxOwnerDrawnComboBox
*)wnd
)->HidePopup(); 
4877     if ( wnd 
== NULL 
|| m_dragStatus 
|| 
4879            ux 
<= (splitterX 
+ wxPG_SPLITTERX_DETECTMARGIN2
) || 
4880            ux 
>= (r
.x
+r
.width
) || 
4882            event
.m_y 
>= (r
.y
+r
.height
) 
4892         if ( m_curcursor 
!= wxCURSOR_ARROW 
) CustomSetCursor ( wxCURSOR_ARROW 
); 
4897 // ----------------------------------------------------------------------- 
4899 void wxPropertyGrid::OnMouseClick( wxMouseEvent 
&event 
) 
4902     if ( OnMouseCommon( event
, &x
, &y 
) ) 
4904         HandleMouseClick(x
,y
,event
); 
4909 // ----------------------------------------------------------------------- 
4911 void wxPropertyGrid::OnMouseRightClick( wxMouseEvent 
&event 
) 
4914     CalcUnscrolledPosition( event
.m_x
, event
.m_y
, &x
, &y 
); 
4915     HandleMouseRightClick(x
,y
,event
); 
4919 // ----------------------------------------------------------------------- 
4921 void wxPropertyGrid::OnMouseDoubleClick( wxMouseEvent 
&event 
) 
4923     // Always run standard mouse-down handler as well 
4924     OnMouseClick(event
); 
4927     CalcUnscrolledPosition( event
.m_x
, event
.m_y
, &x
, &y 
); 
4928     HandleMouseDoubleClick(x
,y
,event
); 
4932 // ----------------------------------------------------------------------- 
4934 void wxPropertyGrid::OnMouseMove( wxMouseEvent 
&event 
) 
4937     if ( OnMouseCommon( event
, &x
, &y 
) ) 
4939         HandleMouseMove(x
,y
,event
); 
4944 // ----------------------------------------------------------------------- 
4946 void wxPropertyGrid::OnMouseMoveBottom( wxMouseEvent
& WXUNUSED(event
) ) 
4948     // Called when mouse moves in the empty space below the properties. 
4949     CustomSetCursor( wxCURSOR_ARROW 
); 
4952 // ----------------------------------------------------------------------- 
4954 void wxPropertyGrid::OnMouseUp( wxMouseEvent 
&event 
) 
4957     if ( OnMouseCommon( event
, &x
, &y 
) ) 
4959         HandleMouseUp(x
,y
,event
); 
4964 // ----------------------------------------------------------------------- 
4966 void wxPropertyGrid::OnMouseEntry( wxMouseEvent 
&event 
) 
4968     // This may get called from child control as well, so event's 
4969     // mouse position cannot be relied on. 
4971     if ( event
.Entering() ) 
4973         if ( !(m_iFlags 
& wxPG_FL_MOUSE_INSIDE
) ) 
4975             // TODO: Fix this (detect parent and only do 
4976             //   cursor trick if it is a manager). 
4977             wxASSERT( GetParent() ); 
4978             GetParent()->SetCursor(wxNullCursor
); 
4980             m_iFlags 
|= wxPG_FL_MOUSE_INSIDE
; 
4983             GetParent()->SetCursor(wxNullCursor
); 
4985     else if ( event
.Leaving() ) 
4987         // Without this, wxSpinCtrl editor will sometimes have wrong cursor 
4988         m_canvas
->SetCursor( wxNullCursor 
); 
4990         // Get real cursor position 
4991         wxPoint pt 
= ScreenToClient(::wxGetMousePosition()); 
4993         if ( ( pt
.x 
<= 0 || pt
.y 
<= 0 || pt
.x 
>= m_width 
|| pt
.y 
>= m_height 
) ) 
4996                 if ( (m_iFlags 
& wxPG_FL_MOUSE_INSIDE
) ) 
4998                     m_iFlags 
&= ~(wxPG_FL_MOUSE_INSIDE
); 
5002                     wxPropertyGrid::HandleMouseUp ( -1, 10000, event 
); 
5010 // ----------------------------------------------------------------------- 
5012 // Common code used by various OnMouseXXXChild methods. 
5013 bool wxPropertyGrid::OnMouseChildCommon( wxMouseEvent 
&event
, int* px
, int *py 
) 
5015     wxWindow
* topCtrlWnd 
= (wxWindow
*)event
.GetEventObject(); 
5016     wxASSERT( topCtrlWnd 
); 
5018     event
.GetPosition(&x
,&y
); 
5020     int splitterX 
= GetSplitterPosition(); 
5022     wxRect r 
= topCtrlWnd
->GetRect(); 
5023     if ( !m_dragStatus 
&& 
5024          x 
> (splitterX
-r
.x
+wxPG_SPLITTERX_DETECTMARGIN2
) && 
5025          y 
>= 0 && y 
< r
.height \
 
5028         if ( m_curcursor 
!= wxCURSOR_ARROW 
) CustomSetCursor ( wxCURSOR_ARROW 
); 
5033         CalcUnscrolledPosition( event
.m_x 
+ r
.x
, event
.m_y 
+ r
.y
, \
 
5040 void wxPropertyGrid::OnMouseClickChild( wxMouseEvent 
&event 
) 
5043     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
5045         bool res 
= HandleMouseClick(x
,y
,event
); 
5046         if ( !res 
) event
.Skip(); 
5050 void wxPropertyGrid::OnMouseRightClickChild( wxMouseEvent 
&event 
) 
5053     wxASSERT( m_wndEditor 
); 
5054     // These coords may not be exact (about +-2), 
5055     // but that should not matter (right click is about item, not position). 
5056     wxPoint pt 
= m_wndEditor
->GetPosition(); 
5057     CalcUnscrolledPosition( event
.m_x 
+ pt
.x
, event
.m_y 
+ pt
.y
, &x
, &y 
); 
5059     // FIXME: Used to set m_propHover to selection here. Was it really 
5062     bool res 
= HandleMouseRightClick(x
,y
,event
); 
5063     if ( !res 
) event
.Skip(); 
5066 void wxPropertyGrid::OnMouseMoveChild( wxMouseEvent 
&event 
) 
5069     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
5071         bool res 
= HandleMouseMove(x
,y
,event
); 
5072         if ( !res 
) event
.Skip(); 
5076 void wxPropertyGrid::OnMouseUpChild( wxMouseEvent 
&event 
) 
5079     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
5081         bool res 
= HandleMouseUp(x
,y
,event
); 
5082         if ( !res 
) event
.Skip(); 
5086 // ----------------------------------------------------------------------- 
5087 // wxPropertyGrid keyboard event handling 
5088 // ----------------------------------------------------------------------- 
5090 int wxPropertyGrid::KeyEventToActions(wxKeyEvent 
&event
, int* pSecond
) const 
5092     // Translates wxKeyEvent to wxPG_ACTION_XXX 
5094     int keycode 
= event
.GetKeyCode(); 
5095     int modifiers 
= event
.GetModifiers(); 
5097     wxASSERT( !(modifiers
&~(0xFFFF)) ); 
5099     int hashMapKey 
= (keycode 
& 0xFFFF) | ((modifiers 
& 0xFFFF) << 16); 
5101     wxPGHashMapI2I::const_iterator it 
= m_actionTriggers
.find(hashMapKey
); 
5103     if ( it 
== m_actionTriggers
.end() ) 
5108         int second 
= (it
->second
>>16) & 0xFFFF; 
5112     return (it
->second 
& 0xFFFF); 
5115 void wxPropertyGrid::AddActionTrigger( int action
, int keycode
, int modifiers 
) 
5117     wxASSERT( !(modifiers
&~(0xFFFF)) ); 
5119     int hashMapKey 
= (keycode 
& 0xFFFF) | ((modifiers 
& 0xFFFF) << 16); 
5121     wxPGHashMapI2I::iterator it 
= m_actionTriggers
.find(hashMapKey
); 
5123     if ( it 
!= m_actionTriggers
.end() ) 
5125         // This key combination is already used 
5127         // Can add secondary? 
5128         wxASSERT_MSG( !(it
->second
&~(0xFFFF)), 
5129                       wxT("You can only add up to two separate actions per key combination.") ); 
5131         action 
= it
->second 
| (action
<<16); 
5134     m_actionTriggers
[hashMapKey
] = action
; 
5137 void wxPropertyGrid::ClearActionTriggers( int action 
) 
5139     wxPGHashMapI2I::iterator it
; 
5141     for ( it 
= m_actionTriggers
.begin(); it 
!= m_actionTriggers
.end(); ++it 
) 
5143         if ( it
->second 
== action 
) 
5145             m_actionTriggers
.erase(it
); 
5150 void wxPropertyGrid::HandleKeyEvent( wxKeyEvent 
&event
, bool fromChild 
) 
5153     // Handles key event when editor control is not focused. 
5156     wxCHECK2(!m_frozen
, return); 
5158     // Travelsal between items, collapsing/expanding, etc. 
5159     wxPGProperty
* selected 
= GetSelection(); 
5160     int keycode 
= event
.GetKeyCode(); 
5161     bool editorFocused 
= IsEditorFocused(); 
5163     if ( keycode 
== WXK_TAB 
) 
5165         wxWindow
* mainControl
; 
5167         if ( HasInternalFlag(wxPG_FL_IN_MANAGER
) ) 
5168             mainControl 
= GetParent(); 
5172         if ( !event
.ShiftDown() ) 
5174             if ( !editorFocused 
&& m_wndEditor 
) 
5176                 DoSelectProperty( selected
, wxPG_SEL_FOCUS 
); 
5180                 // Tab traversal workaround for platforms on which 
5181                 // wxWindow::Navigate() may navigate into first child 
5182                 // instead of next sibling. Does not work perfectly 
5183                 // in every scenario (for instance, when property grid 
5184                 // is either first or last control). 
5185             #if defined(__WXGTK__) 
5186                 wxWindow
* sibling 
= mainControl
->GetNextSibling(); 
5188                     sibling
->SetFocusFromKbd(); 
5190                 Navigate(wxNavigationKeyEvent::IsForward
); 
5196             if ( editorFocused 
) 
5202             #if defined(__WXGTK__) 
5203                 wxWindow
* sibling 
= mainControl
->GetPrevSibling(); 
5205                     sibling
->SetFocusFromKbd(); 
5207                 Navigate(wxNavigationKeyEvent::IsBackward
); 
5215     // Ignore Alt and Control when they are down alone 
5216     if ( keycode 
== WXK_ALT 
|| 
5217          keycode 
== WXK_CONTROL 
) 
5224     int action 
= KeyEventToActions(event
, &secondAction
); 
5226     if ( editorFocused 
&& action 
== wxPG_ACTION_CANCEL_EDIT 
) 
5229         // Esc cancels any changes 
5230         if ( IsEditorsValueModified() ) 
5232             EditorsValueWasNotModified(); 
5234             // Update the control as well 
5235             selected
->GetEditorClass()-> 
5236                 SetControlStringValue( selected
, 
5238                                        selected
->GetDisplayedString() ); 
5241         OnValidationFailureReset(selected
); 
5247     // Except for TAB and ESC, handle child control events in child control 
5250         // Only propagate event if it had modifiers 
5251         if ( !event
.HasModifiers() ) 
5253             event
.StopPropagation(); 
5259     bool wasHandled 
= false; 
5264         if ( ButtonTriggerKeyTest(action
, event
) ) 
5267         wxPGProperty
* p 
= selected
; 
5269         // Travel and expand/collapse 
5272         if ( p
->GetChildCount() ) 
5274             if ( action 
== wxPG_ACTION_COLLAPSE_PROPERTY 
|| secondAction 
== wxPG_ACTION_COLLAPSE_PROPERTY 
) 
5276                 if ( (m_windowStyle 
& wxPG_HIDE_MARGIN
) || Collapse(p
) ) 
5279             else if ( action 
== wxPG_ACTION_EXPAND_PROPERTY 
|| secondAction 
== wxPG_ACTION_EXPAND_PROPERTY 
) 
5281                 if ( (m_windowStyle 
& wxPG_HIDE_MARGIN
) || Expand(p
) ) 
5288             if ( action 
== wxPG_ACTION_PREV_PROPERTY 
|| secondAction 
== wxPG_ACTION_PREV_PROPERTY 
) 
5292             else if ( action 
== wxPG_ACTION_NEXT_PROPERTY 
|| secondAction 
== wxPG_ACTION_NEXT_PROPERTY 
) 
5298         if ( selectDir 
>= -1 ) 
5300             p 
= wxPropertyGridIterator::OneStep( m_pState
, wxPG_ITERATE_VISIBLE
, p
, selectDir 
); 
5302                 DoSelectProperty(p
); 
5308         // If nothing was selected, select the first item now 
5309         // (or navigate out of tab). 
5310         if ( action 
!= wxPG_ACTION_CANCEL_EDIT 
&& secondAction 
!= wxPG_ACTION_CANCEL_EDIT 
) 
5312             wxPGProperty
* p 
= wxPropertyGridInterface::GetFirst(); 
5313             if ( p 
) DoSelectProperty(p
); 
5322 // ----------------------------------------------------------------------- 
5324 void wxPropertyGrid::OnKey( wxKeyEvent 
&event 
) 
5326     // If there was editor open and focused, then this event should not 
5327     // really be processed here. 
5328     if ( IsEditorFocused() ) 
5330         // However, if event had modifiers, it is probably still best 
5332         if ( event
.HasModifiers() ) 
5335             event
.StopPropagation(); 
5339     HandleKeyEvent(event
, false); 
5342 // ----------------------------------------------------------------------- 
5344 bool wxPropertyGrid::ButtonTriggerKeyTest( int action
, wxKeyEvent
& event 
) 
5349         action 
= KeyEventToActions(event
, &secondAction
); 
5352     // Does the keycode trigger button? 
5353     if ( action 
== wxPG_ACTION_PRESS_BUTTON 
&& 
5356         wxCommandEvent 
evt(wxEVT_COMMAND_BUTTON_CLICKED
, m_wndEditor2
->GetId()); 
5357         GetEventHandler()->AddPendingEvent(evt
); 
5364 // ----------------------------------------------------------------------- 
5366 void wxPropertyGrid::OnChildKeyDown( wxKeyEvent 
&event 
) 
5368     HandleKeyEvent(event
, true); 
5371 // ----------------------------------------------------------------------- 
5372 // wxPropertyGrid miscellaneous event handling 
5373 // ----------------------------------------------------------------------- 
5375 void wxPropertyGrid::OnIdle( wxIdleEvent
& WXUNUSED(event
) ) 
5378     // Check if the focus is in this control or one of its children 
5379     wxWindow
* newFocused 
= wxWindow::FindFocus(); 
5381     if ( newFocused 
!= m_curFocused 
) 
5382         HandleFocusChange( newFocused 
); 
5385     // Check if top-level parent has changed 
5386     wxWindow
* tlp 
= ::wxGetTopLevelParent(this); 
5393 bool wxPropertyGrid::IsEditorFocused() const 
5395     wxWindow
* focus 
= wxWindow::FindFocus(); 
5397     if ( focus 
== m_wndEditor 
|| focus 
== m_wndEditor2 
|| 
5398          focus 
== GetEditorControl() ) 
5404 // Called by focus event handlers. newFocused is the window that becomes focused. 
5405 void wxPropertyGrid::HandleFocusChange( wxWindow
* newFocused 
) 
5407     unsigned int oldFlags 
= m_iFlags
; 
5409     m_iFlags 
&= ~(wxPG_FL_FOCUSED
); 
5411     wxWindow
* parent 
= newFocused
; 
5413     // This must be one of nextFocus' parents. 
5416         // Use m_eventObject, which is either wxPropertyGrid or 
5417         // wxPropertyGridManager, as appropriate. 
5418         if ( parent 
== m_eventObject 
) 
5420             m_iFlags 
|= wxPG_FL_FOCUSED
; 
5423         parent 
= parent
->GetParent(); 
5426     m_curFocused 
= newFocused
; 
5428     if ( (m_iFlags 
& wxPG_FL_FOCUSED
) != 
5429          (oldFlags 
& wxPG_FL_FOCUSED
) ) 
5431         if ( !(m_iFlags 
& wxPG_FL_FOCUSED
) ) 
5433             // Need to store changed value 
5434             CommitChangesFromEditor(); 
5440             // Preliminary code for tab-order respecting 
5441             // tab-traversal (but should be moved to 
5444             wxWindow* prevFocus = event.GetWindow(); 
5445             wxWindow* useThis = this; 
5446             if ( m_iFlags & wxPG_FL_IN_MANAGER ) 
5447                 useThis = GetParent(); 
5450                  prevFocus->GetParent() == useThis->GetParent() ) 
5452                 wxList& children = useThis->GetParent()->GetChildren(); 
5454                 wxNode* node = children.Find(prevFocus); 
5456                 if ( node->GetNext() && 
5457                      useThis == node->GetNext()->GetData() ) 
5458                     DoSelectProperty(GetFirst()); 
5459                 else if ( node->GetPrevious () && 
5460                           useThis == node->GetPrevious()->GetData() ) 
5461                     DoSelectProperty(GetLastProperty()); 
5468         wxPGProperty
* selected 
= GetSelection(); 
5469         if ( selected 
&& (m_iFlags 
& wxPG_FL_INITIALIZED
) ) 
5470             DrawItem( selected 
); 
5474 void wxPropertyGrid::OnFocusEvent( wxFocusEvent
& event 
) 
5476     if ( event
.GetEventType() == wxEVT_SET_FOCUS 
) 
5477         HandleFocusChange((wxWindow
*)event
.GetEventObject()); 
5478     // Line changed to "else" when applying wxPropertyGrid patch #1675902 
5479     //else if ( event.GetWindow() ) 
5481         HandleFocusChange(event
.GetWindow()); 
5486 // ----------------------------------------------------------------------- 
5488 void wxPropertyGrid::OnChildFocusEvent( wxChildFocusEvent
& event 
) 
5490     HandleFocusChange((wxWindow
*)event
.GetEventObject()); 
5494 // ----------------------------------------------------------------------- 
5496 void wxPropertyGrid::OnScrollEvent( wxScrollWinEvent 
&event 
) 
5498     m_iFlags 
|= wxPG_FL_SCROLLED
; 
5503 // ----------------------------------------------------------------------- 
5505 void wxPropertyGrid::OnCaptureChange( wxMouseCaptureChangedEvent
& WXUNUSED(event
) ) 
5507     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
5509         m_iFlags 
&= ~(wxPG_FL_MOUSE_CAPTURED
); 
5513 // ----------------------------------------------------------------------- 
5514 // Property editor related functions 
5515 // ----------------------------------------------------------------------- 
5517 // noDefCheck = true prevents infinite recursion. 
5518 wxPGEditor
* wxPropertyGrid::DoRegisterEditorClass( wxPGEditor
* editorClass
, 
5519                                                    const wxString
& editorName
, 
5522     wxASSERT( editorClass 
); 
5524     if ( !noDefCheck 
&& wxPGGlobalVars
->m_mapEditorClasses
.empty() ) 
5525         RegisterDefaultEditors(); 
5527     wxString name 
= editorName
; 
5528     if ( name
.length() == 0 ) 
5529         name 
= editorClass
->GetName(); 
5531     // Existing editor under this name? 
5532     wxPGHashMapS2P::iterator vt_it 
= wxPGGlobalVars
->m_mapEditorClasses
.find(name
); 
5534     if ( vt_it 
!= wxPGGlobalVars
->m_mapEditorClasses
.end() ) 
5536         // If this name was already used, try class name. 
5537         name 
= editorClass
->GetClassInfo()->GetClassName(); 
5538         vt_it 
= wxPGGlobalVars
->m_mapEditorClasses
.find(name
); 
5541     wxCHECK_MSG( vt_it 
== wxPGGlobalVars
->m_mapEditorClasses
.end(), 
5542                  (wxPGEditor
*) vt_it
->second
, 
5543                  "Editor with given name was already registered" ); 
5545     wxPGGlobalVars
->m_mapEditorClasses
[name
] = (void*)editorClass
; 
5550 // Use this in RegisterDefaultEditors. 
5551 #define wxPGRegisterDefaultEditorClass(EDITOR) \ 
5552     if ( wxPGEditor_##EDITOR == NULL ) \ 
5554         wxPGEditor_##EDITOR = wxPropertyGrid::RegisterEditorClass( \ 
5555             new wxPG##EDITOR##Editor, true ); \ 
5558 // Registers all default editor classes 
5559 void wxPropertyGrid::RegisterDefaultEditors() 
5561     wxPGRegisterDefaultEditorClass( TextCtrl 
); 
5562     wxPGRegisterDefaultEditorClass( Choice 
); 
5563     wxPGRegisterDefaultEditorClass( ComboBox 
); 
5564     wxPGRegisterDefaultEditorClass( TextCtrlAndButton 
); 
5565 #if wxPG_INCLUDE_CHECKBOX 
5566     wxPGRegisterDefaultEditorClass( CheckBox 
); 
5568     wxPGRegisterDefaultEditorClass( ChoiceAndButton 
); 
5570     // Register SpinCtrl etc. editors before use 
5571     RegisterAdditionalEditors(); 
5574 // ----------------------------------------------------------------------- 
5575 // wxPGStringTokenizer 
5576 //   Needed to handle C-style string lists (e.g. "str1" "str2") 
5577 // ----------------------------------------------------------------------- 
5579 wxPGStringTokenizer::wxPGStringTokenizer( const wxString
& str
, wxChar delimeter 
) 
5580     : m_str(&str
), m_curPos(str
.begin()), m_delimeter(delimeter
) 
5584 wxPGStringTokenizer::~wxPGStringTokenizer() 
5588 bool wxPGStringTokenizer::HasMoreTokens() 
5590     const wxString
& str 
= *m_str
; 
5592     wxString::const_iterator i 
= m_curPos
; 
5594     wxUniChar delim 
= m_delimeter
; 
5596     wxUniChar prev_a 
= wxT('\0'); 
5598     bool inToken 
= false; 
5600     while ( i 
!= str
.end() ) 
5609                 m_readyToken
.clear(); 
5614             if ( prev_a 
!= wxT('\\') ) 
5618                     if ( a 
!= wxT('\\') ) 
5638     m_curPos 
= str
.end(); 
5646 wxString 
wxPGStringTokenizer::GetNextToken() 
5648     return m_readyToken
; 
5651 // ----------------------------------------------------------------------- 
5653 // ----------------------------------------------------------------------- 
5655 wxPGChoiceEntry::wxPGChoiceEntry() 
5656     : wxPGCell(), m_value(wxPG_INVALID_VALUE
) 
5660 // ----------------------------------------------------------------------- 
5662 // ----------------------------------------------------------------------- 
5664 wxPGChoicesData::wxPGChoicesData() 
5668 wxPGChoicesData::~wxPGChoicesData() 
5673 void wxPGChoicesData::Clear() 
5678 void wxPGChoicesData::CopyDataFrom( wxPGChoicesData
* data 
) 
5680     wxASSERT( m_items
.size() == 0 ); 
5682     m_items 
= data
->m_items
; 
5685 wxPGChoiceEntry
& wxPGChoicesData::Insert( int index
, 
5686                                           const wxPGChoiceEntry
& item 
) 
5688     wxVector
<wxPGChoiceEntry
>::iterator it
; 
5692         index 
= (int) m_items
.size(); 
5696         it 
= m_items
.begin() + index
; 
5699     m_items
.insert(it
, item
); 
5701     wxPGChoiceEntry
& ownEntry 
= m_items
[index
]; 
5703     // Need to fix value? 
5704     if ( ownEntry
.GetValue() == wxPG_INVALID_VALUE 
) 
5705         ownEntry
.SetValue(index
); 
5710 // ----------------------------------------------------------------------- 
5711 // wxPropertyGridEvent 
5712 // ----------------------------------------------------------------------- 
5714 IMPLEMENT_DYNAMIC_CLASS(wxPropertyGridEvent
, wxCommandEvent
) 
5717 wxDEFINE_EVENT( wxEVT_PG_SELECTED
, wxPropertyGridEvent 
); 
5718 wxDEFINE_EVENT( wxEVT_PG_CHANGING
, wxPropertyGridEvent 
); 
5719 wxDEFINE_EVENT( wxEVT_PG_CHANGED
, wxPropertyGridEvent 
); 
5720 wxDEFINE_EVENT( wxEVT_PG_HIGHLIGHTED
, wxPropertyGridEvent 
); 
5721 wxDEFINE_EVENT( wxEVT_PG_RIGHT_CLICK
, wxPropertyGridEvent 
); 
5722 wxDEFINE_EVENT( wxEVT_PG_PAGE_CHANGED
, wxPropertyGridEvent 
); 
5723 wxDEFINE_EVENT( wxEVT_PG_ITEM_EXPANDED
, wxPropertyGridEvent 
); 
5724 wxDEFINE_EVENT( wxEVT_PG_ITEM_COLLAPSED
, wxPropertyGridEvent 
); 
5725 wxDEFINE_EVENT( wxEVT_PG_DOUBLE_CLICK
, wxPropertyGridEvent 
); 
5726 wxDEFINE_EVENT( wxEVT_PG_LABEL_EDIT_BEGIN
, wxPropertyGridEvent 
); 
5727 wxDEFINE_EVENT( wxEVT_PG_LABEL_EDIT_ENDING
, wxPropertyGridEvent 
); 
5729 // ----------------------------------------------------------------------- 
5731 void wxPropertyGridEvent::Init() 
5733     m_validationInfo 
= NULL
; 
5736     m_wasVetoed 
= false; 
5739 // ----------------------------------------------------------------------- 
5741 wxPropertyGridEvent::wxPropertyGridEvent(wxEventType commandType
, int id
) 
5742     : wxCommandEvent(commandType
,id
) 
5748 // ----------------------------------------------------------------------- 
5750 wxPropertyGridEvent::wxPropertyGridEvent(const wxPropertyGridEvent
& event
) 
5751     : wxCommandEvent(event
) 
5753     m_eventType 
= event
.GetEventType(); 
5754     m_eventObject 
= event
.m_eventObject
; 
5756     m_property 
= event
.m_property
; 
5757     m_validationInfo 
= event
.m_validationInfo
; 
5758     m_canVeto 
= event
.m_canVeto
; 
5759     m_wasVetoed 
= event
.m_wasVetoed
; 
5762 // ----------------------------------------------------------------------- 
5764 wxPropertyGridEvent::~wxPropertyGridEvent() 
5768 // ----------------------------------------------------------------------- 
5770 wxEvent
* wxPropertyGridEvent::Clone() const 
5772     return new wxPropertyGridEvent( *this ); 
5775 // ----------------------------------------------------------------------- 
5776 // wxPropertyGridPopulator 
5777 // ----------------------------------------------------------------------- 
5779 wxPropertyGridPopulator::wxPropertyGridPopulator() 
5783     wxPGGlobalVars
->m_offline
++; 
5786 // ----------------------------------------------------------------------- 
5788 void wxPropertyGridPopulator::SetState( wxPropertyGridPageState
* state 
) 
5791     m_propHierarchy
.clear(); 
5794 // ----------------------------------------------------------------------- 
5796 void wxPropertyGridPopulator::SetGrid( wxPropertyGrid
* pg 
) 
5802 // ----------------------------------------------------------------------- 
5804 wxPropertyGridPopulator::~wxPropertyGridPopulator() 
5807     // Free unused sets of choices 
5808     wxPGHashMapS2P::iterator it
; 
5810     for( it 
= m_dictIdChoices
.begin(); it 
!= m_dictIdChoices
.end(); ++it 
) 
5812         wxPGChoicesData
* data 
= (wxPGChoicesData
*) it
->second
; 
5819         m_pg
->GetPanel()->Refresh(); 
5821     wxPGGlobalVars
->m_offline
--; 
5824 // ----------------------------------------------------------------------- 
5826 wxPGProperty
* wxPropertyGridPopulator::Add( const wxString
& propClass
, 
5827                                             const wxString
& propLabel
, 
5828                                             const wxString
& propName
, 
5829                                             const wxString
* propValue
, 
5830                                             wxPGChoices
* pChoices 
) 
5832     wxClassInfo
* classInfo 
= wxClassInfo::FindClass(propClass
); 
5833     wxPGProperty
* parent 
= GetCurParent(); 
5835     if ( parent
->HasFlag(wxPG_PROP_AGGREGATE
) ) 
5837         ProcessError(wxString::Format(wxT("new children cannot be added to '%s'"),parent
->GetName().c_str())); 
5841     if ( !classInfo 
|| !classInfo
->IsKindOf(CLASSINFO(wxPGProperty
)) ) 
5843         ProcessError(wxString::Format(wxT("'%s' is not valid property class"),propClass
.c_str())); 
5847     wxPGProperty
* property 
= (wxPGProperty
*) classInfo
->CreateObject(); 
5849     property
->SetLabel(propLabel
); 
5850     property
->DoSetName(propName
); 
5852     if ( pChoices 
&& pChoices
->IsOk() ) 
5853         property
->SetChoices(*pChoices
); 
5855     m_state
->DoInsert(parent
, -1, property
); 
5858         property
->SetValueFromString( *propValue
, wxPG_FULL_VALUE
| 
5859                                                   wxPG_PROGRAMMATIC_VALUE 
); 
5864 // ----------------------------------------------------------------------- 
5866 void wxPropertyGridPopulator::AddChildren( wxPGProperty
* property 
) 
5868     m_propHierarchy
.push_back(property
); 
5869     DoScanForChildren(); 
5870     m_propHierarchy
.pop_back(); 
5873 // ----------------------------------------------------------------------- 
5875 wxPGChoices 
wxPropertyGridPopulator::ParseChoices( const wxString
& choicesString
, 
5876                                                    const wxString
& idString 
) 
5878     wxPGChoices choices
; 
5881     if ( choicesString
[0] == wxT('@') ) 
5883         wxString ids 
= choicesString
.substr(1); 
5884         wxPGHashMapS2P::iterator it 
= m_dictIdChoices
.find(ids
); 
5885         if ( it 
== m_dictIdChoices
.end() ) 
5886             ProcessError(wxString::Format(wxT("No choices defined for id '%s'"),ids
.c_str())); 
5888             choices
.AssignData((wxPGChoicesData
*)it
->second
); 
5893         if ( idString
.length() ) 
5895             wxPGHashMapS2P::iterator it 
= m_dictIdChoices
.find(idString
); 
5896             if ( it 
!= m_dictIdChoices
.end() ) 
5898                 choices
.AssignData((wxPGChoicesData
*)it
->second
); 
5905             // Parse choices string 
5906             wxString::const_iterator it 
= choicesString
.begin(); 
5910             bool labelValid 
= false; 
5912             for ( ; it 
!= choicesString
.end(); ++it 
) 
5918                     if ( c 
== wxT('"') ) 
5923                             if ( !value
.ToLong(&l
, 0) ) l 
= wxPG_INVALID_VALUE
; 
5924                             choices
.Add(label
, l
); 
5927                         //wxLogDebug(wxT("%s, %s"),label.c_str(),value.c_str()); 
5932                     else if ( c 
== wxT('=') ) 
5939                     else if ( state 
== 2 && (wxIsalnum(c
) || c 
== wxT('x')) ) 
5946                     if ( c 
== wxT('"') ) 
5959                 if ( !value
.ToLong(&l
, 0) ) l 
= wxPG_INVALID_VALUE
; 
5960                 choices
.Add(label
, l
); 
5963             if ( !choices
.IsOk() ) 
5965                 choices
.EnsureData(); 
5969             if ( idString
.length() ) 
5970                 m_dictIdChoices
[idString
] = choices
.GetData(); 
5977 // ----------------------------------------------------------------------- 
5979 bool wxPropertyGridPopulator::ToLongPCT( const wxString
& s
, long* pval
, long max 
) 
5981     if ( s
.Last() == wxT('%') ) 
5983         wxString s2 
= s
.substr(0,s
.length()-1); 
5985         if ( s2
.ToLong(&val
, 10) ) 
5987             *pval 
= (val
*max
)/100; 
5993     return s
.ToLong(pval
, 10); 
5996 // ----------------------------------------------------------------------- 
5998 bool wxPropertyGridPopulator::AddAttribute( const wxString
& name
, 
5999                                             const wxString
& type
, 
6000                                             const wxString
& value 
) 
6002     int l 
= m_propHierarchy
.size(); 
6006     wxPGProperty
* p 
= m_propHierarchy
[l
-1]; 
6007     wxString valuel 
= value
.Lower(); 
6010     if ( type
.length() == 0 ) 
6015         if ( valuel 
== wxT("true") || valuel 
== wxT("yes") || valuel 
== wxT("1") ) 
6017         else if ( valuel 
== wxT("false") || valuel 
== wxT("no") || valuel 
== wxT("0") ) 
6019         else if ( value
.ToLong(&v
, 0) ) 
6026         if ( type 
== wxT("string") ) 
6030         else if ( type 
== wxT("int") ) 
6033             value
.ToLong(&v
, 0); 
6036         else if ( type 
== wxT("bool") ) 
6038             if ( valuel 
== wxT("true") || valuel 
== wxT("yes") || valuel 
== wxT("1") ) 
6045             ProcessError(wxString::Format(wxT("Invalid attribute type '%s'"),type
.c_str())); 
6050     p
->SetAttribute( name
, variant 
); 
6055 // ----------------------------------------------------------------------- 
6057 void wxPropertyGridPopulator::ProcessError( const wxString
& msg 
) 
6059     wxLogError(_("Error in resource: %s"),msg
.c_str()); 
6062 // ----------------------------------------------------------------------- 
6064 #endif  // wxUSE_PROPGRID