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" 
  66 #include <wx/clipbrd.h> 
  67 #include <wx/dataobj.h> 
  70     #include <wx/msw/private.h> 
  73 // Two pics for the expand / collapse buttons. 
  74 // Files are not supplied with this project (since it is 
  75 // recommended to use either custom or native rendering). 
  76 // If you want them, get wxTreeMultiCtrl by Jorgen Bodde, 
  77 // and copy xpm files from archive to wxPropertyGrid src directory 
  78 // (and also comment/undef wxPG_ICON_WIDTH in propGrid.h 
  79 // and set wxPG_USE_RENDERER_NATIVE to 0). 
  80 #ifndef wxPG_ICON_WIDTH 
  81   #if defined(__WXMAC__) 
  82     #include "mac_collapse.xpm" 
  83     #include "mac_expand.xpm" 
  84   #elif defined(__WXGTK__) 
  85     #include "linux_collapse.xpm" 
  86     #include "linux_expand.xpm" 
  88     #include "default_collapse.xpm" 
  89     #include "default_expand.xpm" 
  94 //#define wxPG_TEXT_INDENT                4 // For the wxComboControl 
  95 #define wxPG_ALLOW_CLIPPING             1 // If 1, GetUpdateRegion() in OnPaint event handler is not ignored 
  96 #define wxPG_GUTTER_DIV                 3 // gutter is max(iconwidth/gutter_div,gutter_min) 
  97 #define wxPG_GUTTER_MIN                 3 // gutter before and after image of [+] or [-] 
  98 #define wxPG_YSPACING_MIN               1 
  99 #define wxPG_DEFAULT_VSPACING           2 // This matches .NET propertygrid's value, 
 100                                           // but causes normal combobox to spill out under MSW 
 102 #define wxPG_OPTIMAL_WIDTH              200 // Arbitrary 
 104 #define wxPG_MIN_SCROLLBAR_WIDTH        10 // Smallest scrollbar width on any platform 
 105                                            // Must be larger than largest control border 
 109 #define wxPG_DEFAULT_CURSOR             wxNullCursor 
 112 //#define wxPG_NAT_CHOICE_BORDER_ANY   0 
 114 #define wxPG_HIDER_BUTTON_HEIGHT        25 
 116 #define wxPG_PIXELS_PER_UNIT            m_lineHeight 
 118 #ifdef wxPG_ICON_WIDTH 
 119   #define m_iconHeight m_iconWidth 
 122 #define wxPG_TOOLTIP_DELAY              1000 
 124 // ----------------------------------------------------------------------- 
 127 void wxPropertyGrid::AutoGetTranslation ( bool enable 
) 
 129     wxPGGlobalVars
->m_autoGetTranslation 
= enable
; 
 132 void wxPropertyGrid::AutoGetTranslation ( bool ) { } 
 135 // ----------------------------------------------------------------------- 
 137 const wxChar 
*wxPropertyGridNameStr 
= wxT("wxPropertyGrid"); 
 139 // ----------------------------------------------------------------------- 
 140 // Statics in one class for easy destruction. 
 141 // ----------------------------------------------------------------------- 
 143 #include <wx/module.h> 
 145 class wxPGGlobalVarsClassManager 
: public wxModule
 
 147     DECLARE_DYNAMIC_CLASS(wxPGGlobalVarsClassManager
) 
 149     wxPGGlobalVarsClassManager() {} 
 150     virtual bool OnInit() { wxPGGlobalVars 
= new wxPGGlobalVarsClass(); return true; } 
 151     virtual void OnExit() { delete wxPGGlobalVars
; wxPGGlobalVars 
= NULL
; } 
 154 IMPLEMENT_DYNAMIC_CLASS(wxPGGlobalVarsClassManager
, wxModule
) 
 157 wxPGGlobalVarsClass
* wxPGGlobalVars 
= (wxPGGlobalVarsClass
*) NULL
; 
 160 wxPGGlobalVarsClass::wxPGGlobalVarsClass() 
 162     wxPGProperty::sm_wxPG_LABEL 
= new wxString(wxPG_LABEL_STRING
); 
 164     m_boolChoices
.Add(_("False")); 
 165     m_boolChoices
.Add(_("True")); 
 167     m_fontFamilyChoices 
= (wxPGChoices
*) NULL
; 
 169     m_defaultRenderer 
= new wxPGDefaultRenderer(); 
 171     m_autoGetTranslation 
= false; 
 179         // Prepare some shared variants 
 180     m_vEmptyString 
= wxString(); 
 182     m_vMinusOne 
= (long) -1; 
 186     // Prepare cached string constants 
 187     m_strstring 
= wxS("string"); 
 188     m_strlong 
= wxS("long"); 
 189     m_strbool 
= wxS("bool"); 
 190     m_strlist 
= wxS("list"); 
 191     m_strMin 
= wxS("Min"); 
 192     m_strMax 
= wxS("Max"); 
 193     m_strUnits 
= wxS("Units"); 
 194     m_strInlineHelp 
= wxS("InlineHelp"); 
 202 wxPGGlobalVarsClass::~wxPGGlobalVarsClass() 
 206     delete m_defaultRenderer
; 
 208     // This will always have one ref 
 209     delete m_fontFamilyChoices
; 
 212     for ( i
=0; i
<m_arrValidators
.size(); i
++ ) 
 213         delete ((wxValidator
*)m_arrValidators
[i
]); 
 217     // Destroy value type class instances. 
 218     wxPGHashMapS2P::iterator vt_it
; 
 220     // Destroy editor class instances. 
 221     // iterate over all the elements in the class 
 222     for( vt_it 
= m_mapEditorClasses
.begin(); vt_it 
!= m_mapEditorClasses
.end(); ++vt_it 
) 
 224         delete ((wxPGEditor
*)vt_it
->second
); 
 227     delete wxPGProperty::sm_wxPG_LABEL
; 
 230 void wxPropertyGridInitGlobalsIfNeeded() 
 234 // ----------------------------------------------------------------------- 
 236 // ----------------------------------------------------------------------- 
 239 // This class is a wxBrush derivative used in the background colour 
 240 // brush cache. It adds wxPG-type colour-in-long to the class. 
 241 // JMS: Yes I know wxBrush doesn't actually hold the value (refcounted 
 242 //   object does), but this is simpler implementation and equally 
 246 class wxPGBrush 
: public wxBrush
 
 249     wxPGBrush( const wxColour
& colour 
); 
 251     virtual ~wxPGBrush() { } 
 252     void SetColour2( const wxColour
& colour 
); 
 253     inline long GetColourAsLong() const { return m_colAsLong
; } 
 259 void wxPGBrush::SetColour2( const wxColour
& colour 
) 
 261     wxBrush::SetColour(colour
); 
 262     m_colAsLong 
= wxPG_COLOUR(colour
.Red(),colour
.Green(),colour
.Blue()); 
 266 wxPGBrush::wxPGBrush() : wxBrush() 
 272 wxPGBrush::wxPGBrush( const wxColour
& colour 
) : wxBrush(colour
) 
 274     m_colAsLong 
= wxPG_COLOUR(colour
.Red(),colour
.Green(),colour
.Blue()); 
 278 // ----------------------------------------------------------------------- 
 280 // ----------------------------------------------------------------------- 
 283 // Same as wxPGBrush, but for wxColour instead. 
 286 class wxPGColour 
: public wxColour
 
 289     wxPGColour( const wxColour
& colour 
); 
 291     virtual ~wxPGColour() { } 
 292     void SetColour2( const wxColour
& colour 
); 
 293     inline long GetColourAsLong() const { return m_colAsLong
; } 
 299 void wxPGColour::SetColour2( const wxColour
& colour 
) 
 302     m_colAsLong 
= wxPG_COLOUR(colour
.Red(),colour
.Green(),colour
.Blue()); 
 306 wxPGColour::wxPGColour() : wxColour() 
 312 wxPGColour::wxPGColour( const wxColour
& colour 
) : wxColour(colour
) 
 314     m_colAsLong 
= wxPG_COLOUR(colour
.Red(),colour
.Green(),colour
.Blue()); 
 318 // ----------------------------------------------------------------------- 
 320 //   Intercepts Close-events sent to wxPropertyGrid's top-level parent, 
 321 //   and tries to commit property value. 
 322 // ----------------------------------------------------------------------- 
 324 class wxPGTLWHandler 
: public wxEvtHandler
 
 328     wxPGTLWHandler( wxPropertyGrid
* pg 
) 
 336     void OnClose( wxCloseEvent
& event 
) 
 338         // ClearSelection forces value validation/commit. 
 339         if ( event
.CanVeto() && !m_pg
->ClearSelection() ) 
 349     wxPropertyGrid
*     m_pg
; 
 351     DECLARE_EVENT_TABLE() 
 354 BEGIN_EVENT_TABLE(wxPGTLWHandler
, wxEvtHandler
) 
 355     EVT_CLOSE(wxPGTLWHandler::OnClose
) 
 358 // ----------------------------------------------------------------------- 
 360 // ----------------------------------------------------------------------- 
 363 // wxPGCanvas acts as a graphics sub-window of the 
 364 // wxScrolledWindow that wxPropertyGrid is. 
 366 class wxPGCanvas 
: public wxPanel
 
 369     wxPGCanvas() : wxPanel() 
 372     virtual ~wxPGCanvas() { } 
 375     void OnMouseMove( wxMouseEvent 
&event 
) 
 377         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 378         pg
->OnMouseMove( event 
); 
 381     void OnMouseClick( wxMouseEvent 
&event 
) 
 383         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 384         pg
->OnMouseClick( event 
); 
 387     void OnMouseUp( wxMouseEvent 
&event 
) 
 389         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 390         pg
->OnMouseUp( event 
); 
 393     void OnMouseRightClick( wxMouseEvent 
&event 
) 
 395         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 396         pg
->OnMouseRightClick( event 
); 
 399     void OnMouseDoubleClick( wxMouseEvent 
&event 
) 
 401         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 402         pg
->OnMouseDoubleClick( event 
); 
 405     void OnKey( wxKeyEvent
& event 
) 
 407         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 411     void OnKeyUp( wxKeyEvent
& event 
) 
 413         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 414         pg
->OnKeyUp( event 
); 
 417     void OnNavigationKey( wxNavigationKeyEvent
& event 
) 
 419         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 420         pg
->OnNavigationKey( event 
); 
 423     void OnPaint( wxPaintEvent
& event 
); 
 425     // Always be focussable, even with child windows 
 426     virtual void SetCanFocus(bool WXUNUSED(canFocus
)) 
 427     {  wxPanel::SetCanFocus(true); } 
 431     DECLARE_EVENT_TABLE() 
 432     DECLARE_ABSTRACT_CLASS(wxPGCanvas
) 
 436 IMPLEMENT_ABSTRACT_CLASS(wxPGCanvas
,wxPanel
) 
 438 BEGIN_EVENT_TABLE(wxPGCanvas
, wxPanel
) 
 439     EVT_MOTION(wxPGCanvas::OnMouseMove
) 
 440     EVT_PAINT(wxPGCanvas::OnPaint
) 
 441     EVT_LEFT_DOWN(wxPGCanvas::OnMouseClick
) 
 442     EVT_LEFT_UP(wxPGCanvas::OnMouseUp
) 
 443     EVT_RIGHT_UP(wxPGCanvas::OnMouseRightClick
) 
 444     EVT_LEFT_DCLICK(wxPGCanvas::OnMouseDoubleClick
) 
 445     EVT_KEY_DOWN(wxPGCanvas::OnKey
) 
 446     EVT_KEY_UP(wxPGCanvas::OnKeyUp
) 
 447     EVT_CHAR(wxPGCanvas::OnKey
) 
 448     EVT_NAVIGATION_KEY(wxPGCanvas::OnNavigationKey
) 
 452 void wxPGCanvas::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
 454     wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 455     wxASSERT( pg
->IsKindOf(CLASSINFO(wxPropertyGrid
)) ); 
 459     // Don't paint after destruction has begun 
 460     if ( !(pg
->GetInternalFlags() & wxPG_FL_INITIALIZED
) ) 
 463     // Update everything inside the box 
 464     wxRect r 
= GetUpdateRegion().GetBox(); 
 466     // Repaint this rectangle 
 467     pg
->DrawItems( dc
, r
.y
, r
.y 
+ r
.height
, &r 
); 
 469     // We assume that the size set when grid is shown 
 470     // is what is desired. 
 471     pg
->SetInternalFlag(wxPG_FL_GOOD_SIZE_SET
); 
 474 // ----------------------------------------------------------------------- 
 476 // ----------------------------------------------------------------------- 
 478 IMPLEMENT_DYNAMIC_CLASS(wxPropertyGrid
, wxScrolledWindow
) 
 480 BEGIN_EVENT_TABLE(wxPropertyGrid
, wxScrolledWindow
) 
 481   EVT_IDLE(wxPropertyGrid::OnIdle
) 
 482   EVT_MOTION(wxPropertyGrid::OnMouseMoveBottom
) 
 483   EVT_PAINT(wxPropertyGrid::OnPaint
) 
 484   EVT_SIZE(wxPropertyGrid::OnResize
) 
 485   EVT_ENTER_WINDOW(wxPropertyGrid::OnMouseEntry
) 
 486   EVT_LEAVE_WINDOW(wxPropertyGrid::OnMouseEntry
) 
 487   EVT_MOUSE_CAPTURE_CHANGED(wxPropertyGrid::OnCaptureChange
) 
 488   EVT_SCROLLWIN(wxPropertyGrid::OnScrollEvent
) 
 489   EVT_CHILD_FOCUS(wxPropertyGrid::OnChildFocusEvent
) 
 490   EVT_SET_FOCUS(wxPropertyGrid::OnFocusEvent
) 
 491   EVT_KILL_FOCUS(wxPropertyGrid::OnFocusEvent
) 
 492   EVT_SYS_COLOUR_CHANGED(wxPropertyGrid::OnSysColourChanged
) 
 496 // ----------------------------------------------------------------------- 
 498 wxPropertyGrid::wxPropertyGrid() 
 504 // ----------------------------------------------------------------------- 
 506 wxPropertyGrid::wxPropertyGrid( wxWindow 
*parent
, 
 515     Create(parent
,id
,pos
,size
,style
,name
); 
 518 // ----------------------------------------------------------------------- 
 520 bool wxPropertyGrid::Create( wxWindow 
*parent
, 
 528     if ( !(style
&wxBORDER_MASK
) ) 
 529         style 
|= wxSIMPLE_BORDER
; 
 534     // This prevents crash under Win2K, but still 
 535     // enables keyboard navigation 
 536     if ( style 
& wxTAB_TRAVERSAL 
) 
 538         style 
&= ~(wxTAB_TRAVERSAL
); 
 539         style 
|= wxWANTS_CHARS
; 
 542     if ( style 
& wxTAB_TRAVERSAL 
) 
 543         style 
|= wxWANTS_CHARS
; 
 546     wxScrolledWindow::Create(parent
,id
,pos
,size
,style
,name
); 
 553 // ----------------------------------------------------------------------- 
 556 // Initialize values to defaults 
 558 void wxPropertyGrid::Init1() 
 560     // Register editor classes, if necessary. 
 561     if ( wxPGGlobalVars
->m_mapEditorClasses
.empty() ) 
 562         wxPropertyGrid::RegisterDefaultEditors(); 
 565     m_pState 
= (wxPropertyGridPageState
*) NULL
; 
 566     m_wndEditor 
= m_wndEditor2 
= (wxWindow
*) NULL
; 
 567     m_selected 
= (wxPGProperty
*) NULL
; 
 569     m_propHover 
= (wxPGProperty
*) NULL
; 
 570     m_eventObject 
= this; 
 571     m_curFocused 
= (wxWindow
*) NULL
; 
 573     m_inDoPropertyChanged 
= 0; 
 574     m_inCommitChangesFromEditor 
= 0; 
 575     m_inDoSelectProperty 
= 0; 
 576     m_permanentValidationFailureBehavior 
= wxPG_VFB_DEFAULT
; 
 582     AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY
, WXK_RIGHT 
); 
 583     AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY
, WXK_DOWN 
); 
 584     AddActionTrigger( wxPG_ACTION_PREV_PROPERTY
, WXK_LEFT 
); 
 585     AddActionTrigger( wxPG_ACTION_PREV_PROPERTY
, WXK_UP 
); 
 586     AddActionTrigger( wxPG_ACTION_EXPAND_PROPERTY
, WXK_RIGHT
); 
 587     AddActionTrigger( wxPG_ACTION_COLLAPSE_PROPERTY
, WXK_LEFT
); 
 588     AddActionTrigger( wxPG_ACTION_CANCEL_EDIT
, WXK_ESCAPE 
); 
 589     AddActionTrigger( wxPG_ACTION_CUT
, 'X', wxMOD_CONTROL 
); 
 590     AddActionTrigger( wxPG_ACTION_CUT
, WXK_DELETE
, wxMOD_SHIFT 
); 
 591     AddActionTrigger( wxPG_ACTION_COPY
, 'C', wxMOD_CONTROL
); 
 592     AddActionTrigger( wxPG_ACTION_COPY
, WXK_INSERT
, wxMOD_CONTROL 
); 
 593     AddActionTrigger( wxPG_ACTION_PASTE
, 'V', wxMOD_CONTROL 
); 
 594     AddActionTrigger( wxPG_ACTION_PASTE
, WXK_INSERT
, wxMOD_SHIFT 
); 
 596     m_coloursCustomized 
= 0; 
 601 #if wxPG_DOUBLE_BUFFER 
 602     m_doubleBuffer 
= (wxBitmap
*) NULL
; 
 605     m_windowsToDelete 
= NULL
; 
 607 #ifndef wxPG_ICON_WIDTH 
 613     m_iconWidth 
= wxPG_ICON_WIDTH
; 
 618     m_gutterWidth 
= wxPG_GUTTER_MIN
; 
 619     m_subgroup_extramargin 
= 10; 
 623     m_width 
= m_height 
= 0; 
 625     SetButtonShortcut(0); 
 627     m_keyComboConsumed 
= 0; 
 629     m_commonValues
.push_back(new wxPGCommonValue(_("Unspecified"), wxPGGlobalVars
->m_defaultRenderer
) ); 
 632     m_chgInfo_changedProperty 
= NULL
; 
 635 // ----------------------------------------------------------------------- 
 638 // Initialize after parent etc. set 
 640 void wxPropertyGrid::Init2() 
 642     wxASSERT( !(m_iFlags 
& wxPG_FL_INITIALIZED 
) ); 
 645    // Smaller controls on Mac 
 646    SetWindowVariant(wxWINDOW_VARIANT_SMALL
); 
 649     // Now create state, if one didn't exist already 
 650     // (wxPropertyGridManager might have created it for us). 
 653         m_pState 
= CreateState(); 
 654         m_pState
->m_pPropGrid 
= this; 
 655         m_iFlags 
|= wxPG_FL_CREATEDSTATE
; 
 658     if ( !(m_windowStyle 
& wxPG_SPLITTER_AUTO_CENTER
) ) 
 659         m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
 661     if ( m_windowStyle 
& wxPG_HIDE_CATEGORIES 
) 
 663         m_pState
->InitNonCatMode(); 
 665         m_pState
->m_properties 
= m_pState
->m_abcArray
; 
 668     GetClientSize(&m_width
,&m_height
); 
 670 #ifndef wxPG_ICON_WIDTH 
 671     // create two bitmap nodes for drawing 
 672         m_expandbmp 
= new wxBitmap(expand_xpm
); 
 673         m_collbmp 
= new wxBitmap(collapse_xpm
); 
 675         // calculate average font height for bitmap centering 
 677         m_iconWidth 
= m_expandbmp
->GetWidth(); 
 678         m_iconHeight 
= m_expandbmp
->GetHeight(); 
 681     m_curcursor 
= wxCURSOR_ARROW
; 
 682     m_cursorSizeWE 
= new wxCursor( wxCURSOR_SIZEWE 
); 
 684         // adjust bitmap icon y position so they are centered 
 685     m_vspacing 
= wxPG_DEFAULT_VSPACING
; 
 689         wxFont useFont 
= wxScrolledWindow::GetFont(); 
 690         wxScrolledWindow::SetOwnFont( useFont 
); 
 693         // This should be otherwise called by SetOwnFont 
 694             CalculateFontAndBitmapStuff( wxPG_DEFAULT_VSPACING 
); 
 696     // Add base brush item 
 697     m_arrBgBrushes
.Add((void*)new wxPGBrush()); 
 699     // Add base colour items 
 700     m_arrFgCols
.Add((void*)new wxPGColour()); 
 701     m_arrFgCols
.Add((void*)new wxPGColour()); 
 705     // This helps with flicker 
 706     SetBackgroundStyle( wxBG_STYLE_CUSTOM 
); 
 709     wxPGTLWHandler
* handler 
= new wxPGTLWHandler(this); 
 710     m_tlp 
= ::wxGetTopLevelParent(this); 
 711     m_tlwHandler 
= handler
; 
 712     m_tlp
->PushEventHandler(handler
); 
 714         // set virtual size to this window size 
 715     wxSize wndsize 
= GetSize(); 
 716         SetVirtualSize(wndsize
.GetWidth(), wndsize
.GetWidth()); 
 718     m_timeCreated 
= ::wxGetLocalTimeMillis(); 
 720     m_canvas 
= new wxPGCanvas(); 
 721     m_canvas
->Create(this, 1, wxPoint(0, 0), GetClientSize(), 
 722                      (GetWindowStyle() & wxTAB_TRAVERSAL
) | wxWANTS_CHARS 
| wxCLIP_CHILDREN
); 
 723     m_canvas
->SetBackgroundStyle( wxBG_STYLE_CUSTOM 
); 
 725     m_iFlags 
|= wxPG_FL_INITIALIZED
; 
 727     m_ncWidth 
= wndsize
.GetWidth(); 
 729     // Need to call OnResize handler or size given in constructor/Create 
 731     wxSizeEvent 
sizeEvent(wndsize
,0); 
 735 // ----------------------------------------------------------------------- 
 737 wxPropertyGrid::~wxPropertyGrid() 
 741     DoSelectProperty(NULL
); 
 743     // This should do prevent things from going too badly wrong 
 744     m_iFlags 
&= ~(wxPG_FL_INITIALIZED
); 
 746     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
 747         m_canvas
->ReleaseMouse(); 
 749     wxPGTLWHandler
* handler 
= (wxPGTLWHandler
*) m_tlwHandler
; 
 750     m_tlp
->RemoveEventHandler(handler
); 
 754     if ( IsEditorsValueModified() ) 
 755         ::wxMessageBox(wxS("Most recent change in property editor was lost!!!\n\n(if you don't want this to happen, close your frames and dialogs using Close(false).)"), 
 756                        wxS("wxPropertyGrid Debug Warning") ); 
 759 #if wxPG_DOUBLE_BUFFER 
 760     if ( m_doubleBuffer 
) 
 761         delete m_doubleBuffer
; 
 764     delete m_windowsToDelete
; 
 766     //m_selected = (wxPGProperty*) NULL; 
 768     if ( m_iFlags 
& wxPG_FL_CREATEDSTATE 
) 
 771     delete m_cursorSizeWE
; 
 773 #ifndef wxPG_ICON_WIDTH 
 778     // Delete cached text colours. 
 779     for ( i
=0; i
<m_arrFgCols
.size(); i
++ ) 
 781         delete (wxPGColour
*)m_arrFgCols
.Item(i
); 
 784     // Delete cached brushes. 
 785     for ( i
=0; i
<m_arrBgBrushes
.size(); i
++ ) 
 787         delete (wxPGBrush
*)m_arrBgBrushes
.Item(i
); 
 790     // Delete common value records 
 791     for ( i
=0; i
<m_commonValues
.size(); i
++ ) 
 793         delete GetCommonValue(i
); 
 797 // ----------------------------------------------------------------------- 
 799 bool wxPropertyGrid::Destroy() 
 801     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
 802         m_canvas
->ReleaseMouse(); 
 804     return wxScrolledWindow::Destroy(); 
 807 // ----------------------------------------------------------------------- 
 809 wxPropertyGridPageState
* wxPropertyGrid::CreateState() const 
 811     return new wxPropertyGridPageState(); 
 814 // ----------------------------------------------------------------------- 
 815 // wxPropertyGrid overridden wxWindow methods 
 816 // ----------------------------------------------------------------------- 
 818 void wxPropertyGrid::SetWindowStyleFlag( long style 
) 
 820     long old_style 
= m_windowStyle
; 
 822     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
 824         wxASSERT( m_pState 
); 
 826         if ( !(style 
& wxPG_HIDE_CATEGORIES
) && (old_style 
& wxPG_HIDE_CATEGORIES
) ) 
 829             EnableCategories( true ); 
 831         else if ( (style 
& wxPG_HIDE_CATEGORIES
) && !(old_style 
& wxPG_HIDE_CATEGORIES
) ) 
 833         // Disable categories 
 834             EnableCategories( false ); 
 836         if ( !(old_style 
& wxPG_AUTO_SORT
) && (style 
& wxPG_AUTO_SORT
) ) 
 842                 PrepareAfterItemsAdded(); 
 844                 m_pState
->m_itemsAdded 
= 1; 
 846     #if wxPG_SUPPORT_TOOLTIPS 
 847         if ( !(old_style 
& wxPG_TOOLTIPS
) && (style 
& wxPG_TOOLTIPS
) ) 
 853             wxToolTip* tooltip = new wxToolTip ( wxEmptyString ); 
 854             SetToolTip ( tooltip ); 
 855             tooltip->SetDelay ( wxPG_TOOLTIP_DELAY ); 
 858         else if ( (old_style 
& wxPG_TOOLTIPS
) && !(style 
& wxPG_TOOLTIPS
) ) 
 863             m_canvas
->SetToolTip( (wxToolTip
*) NULL 
); 
 868     wxScrolledWindow::SetWindowStyleFlag ( style 
); 
 870     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
 872         if ( (old_style 
& wxPG_HIDE_MARGIN
) != (style 
& wxPG_HIDE_MARGIN
) ) 
 874             CalculateFontAndBitmapStuff( m_vspacing 
); 
 880 // ----------------------------------------------------------------------- 
 882 void wxPropertyGrid::Freeze() 
 886         wxScrolledWindow::Freeze(); 
 891 // ----------------------------------------------------------------------- 
 893 void wxPropertyGrid::Thaw() 
 899         wxScrolledWindow::Thaw(); 
 900         RecalculateVirtualSize(); 
 901     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
 905         // Force property re-selection 
 907             DoSelectProperty(m_selected
, wxPG_SEL_FORCE
); 
 911 // ----------------------------------------------------------------------- 
 913 void wxPropertyGrid::SetExtraStyle( long exStyle 
) 
 915     if ( exStyle 
& wxPG_EX_NATIVE_DOUBLE_BUFFERING 
) 
 917 #if defined(__WXMSW__) 
 920         // Don't use WS_EX_COMPOSITED just now. 
 923         if ( m_iFlags & wxPG_FL_IN_MANAGER ) 
 924             hWnd = (HWND)GetParent()->GetHWND(); 
 926             hWnd = (HWND)GetHWND(); 
 928         ::SetWindowLong( hWnd, GWL_EXSTYLE, 
 929                          ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED ); 
 932 //#elif defined(__WXGTK20__) 
 934         // Only apply wxPG_EX_NATIVE_DOUBLE_BUFFERING if the window 
 935         // truly was double-buffered. 
 936         if ( !this->IsDoubleBuffered() ) 
 938             exStyle 
&= ~(wxPG_EX_NATIVE_DOUBLE_BUFFERING
); 
 942         #if wxPG_DOUBLE_BUFFER 
 943             delete m_doubleBuffer
; 
 944             m_doubleBuffer 
= NULL
; 
 949     wxScrolledWindow::SetExtraStyle( exStyle 
); 
 951     if ( exStyle 
& wxPG_EX_INIT_NOCAT 
) 
 952         m_pState
->InitNonCatMode(); 
 954     if ( exStyle 
& wxPG_EX_HELP_AS_TOOLTIPS 
) 
 955         m_windowStyle 
|= wxPG_TOOLTIPS
; 
 958     wxPGGlobalVars
->m_extraStyle 
= exStyle
; 
 961 // ----------------------------------------------------------------------- 
 963 // returns the best acceptable minimal size 
 964 wxSize 
wxPropertyGrid::DoGetBestSize() const 
 967     if ( m_lineHeight 
> hei 
) 
 969     wxSize sz 
= wxSize( 60, hei
+40 ); 
 975 // ----------------------------------------------------------------------- 
 976 // wxPropertyGrid Font and Colour Methods 
 977 // ----------------------------------------------------------------------- 
 979 void wxPropertyGrid::CalculateFontAndBitmapStuff( int vspacing 
) 
 983     m_captionFont 
= wxScrolledWindow::GetFont(); 
 985         GetTextExtent(wxS("jG"), &x
, &y
, 0, 0, &m_captionFont
); 
 986     m_subgroup_extramargin 
= x 
+ (x
/2); 
 989 #if wxPG_USE_RENDERER_NATIVE 
 990     m_iconWidth 
= wxPG_ICON_WIDTH
; 
 991 #elif wxPG_ICON_WIDTH 
 993     m_iconWidth 
= (m_fontHeight 
* wxPG_ICON_WIDTH
) / 13; 
 994     if ( m_iconWidth 
< 5 ) m_iconWidth 
= 5; 
 995     else if ( !(m_iconWidth 
& 0x01) ) m_iconWidth
++; // must be odd 
 999     m_gutterWidth 
= m_iconWidth 
/ wxPG_GUTTER_DIV
; 
1000     if ( m_gutterWidth 
< wxPG_GUTTER_MIN 
) 
1001         m_gutterWidth 
= wxPG_GUTTER_MIN
; 
1004     if ( vspacing 
<= 1 ) vdiv 
= 12; 
1005     else if ( vspacing 
>= 3 ) vdiv 
= 3; 
1007     m_spacingy 
= m_fontHeight 
/ vdiv
; 
1008     if ( m_spacingy 
< wxPG_YSPACING_MIN 
) 
1009         m_spacingy 
= wxPG_YSPACING_MIN
; 
1012     if ( !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
1013         m_marginWidth 
= m_gutterWidth
*2 + m_iconWidth
; 
1015     m_captionFont
.SetWeight(wxBOLD
); 
1016         GetTextExtent(wxS("jG"), &x
, &y
, 0, 0, &m_captionFont
); 
1018     m_lineHeight 
= m_fontHeight
+(2*m_spacingy
)+1; 
1021     m_buttonSpacingY 
= (m_lineHeight 
- m_iconHeight
) / 2; 
1022     if ( m_buttonSpacingY 
< 0 ) m_buttonSpacingY 
= 0; 
1025         m_pState
->CalculateFontAndBitmapStuff(vspacing
); 
1027     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
1028         RecalculateVirtualSize(); 
1030     InvalidateBestSize(); 
1033 // ----------------------------------------------------------------------- 
1035 void wxPropertyGrid::OnSysColourChanged( wxSysColourChangedEvent 
&WXUNUSED(event
) ) 
1041 // ----------------------------------------------------------------------- 
1043 static wxColour 
wxPGAdjustColour(const wxColour
& src
, int ra
, 
1044                                  int ga 
= 1000, int ba 
= 1000, 
1045                                  bool forceDifferent 
= false) 
1052     // Recursion guard (allow 2 max) 
1053     static int isinside 
= 0; 
1055     wxCHECK_MSG( isinside 
< 3, 
1057                  wxT("wxPGAdjustColour should not be recursively called more than once") ); 
1062     int g 
= src
.Green(); 
1065     if ( r2
>255 ) r2 
= 255; 
1066     else if ( r2
<0) r2 
= 0; 
1068     if ( g2
>255 ) g2 
= 255; 
1069     else if ( g2
<0) g2 
= 0; 
1071     if ( b2
>255 ) b2 
= 255; 
1072     else if ( b2
<0) b2 
= 0; 
1074     // Make sure they are somewhat different 
1075     if ( forceDifferent 
&& (abs((r
+g
+b
)-(r2
+g2
+b2
)) < abs(ra
/2)) ) 
1076         dst 
= wxPGAdjustColour(src
,-(ra
*2)); 
1078         dst 
= wxColour(r2
,g2
,b2
); 
1080     // Recursion guard (allow 2 max) 
1087 static int wxPGGetColAvg( const wxColour
& col 
) 
1089     return (col
.Red() + col
.Green() + col
.Blue()) / 3; 
1093 void wxPropertyGrid::RegainColours() 
1095     wxColour def_bgcol 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
1097     if ( !(m_coloursCustomized 
& 0x0002) ) 
1099         wxColour col 
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE 
); 
1101         // Make sure colour is dark enough 
1103         int colDec 
= wxPGGetColAvg(col
) - 230; 
1105         int colDec 
= wxPGGetColAvg(col
) - 200; 
1108             m_colCapBack 
= wxPGAdjustColour(col
,-colDec
); 
1113     if ( !(m_coloursCustomized 
& 0x0001) ) 
1114         m_colMargin 
= m_colCapBack
; 
1116     if ( !(m_coloursCustomized 
& 0x0004) ) 
1123         wxColour capForeCol 
= wxPGAdjustColour(m_colCapBack
,colDec
,5000,5000,true); 
1124         m_colCapFore 
= capForeCol
; 
1126         // Set the cached colour as well. 
1127         ((wxPGColour
*)m_arrFgCols
.Item(1))->SetColour2(capForeCol
); 
1130     if ( !(m_coloursCustomized 
& 0x0008) ) 
1132         wxColour bgCol 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
1133         m_colPropBack 
= bgCol
; 
1135         // Set the cached brush as well. 
1136         ((wxPGBrush
*)m_arrBgBrushes
.Item(0))->SetColour2(bgCol
); 
1139     if ( !(m_coloursCustomized 
& 0x0010) ) 
1141         wxColour fgCol 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
1142         m_colPropFore 
= fgCol
; 
1144         // Set the cached colour as well. 
1145         ((wxPGColour
*)m_arrFgCols
.Item(0))->SetColour2(fgCol
); 
1148     if ( !(m_coloursCustomized 
& 0x0020) ) 
1149         m_colSelBack 
= wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT 
); 
1151     if ( !(m_coloursCustomized 
& 0x0040) ) 
1152         m_colSelFore 
= wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
); 
1154     if ( !(m_coloursCustomized 
& 0x0080) ) 
1155         m_colLine 
= m_colCapBack
; 
1157     if ( !(m_coloursCustomized 
& 0x0100) ) 
1158         m_colDisPropFore 
= m_colCapFore
; 
1160     m_colEmptySpace 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
1163 // ----------------------------------------------------------------------- 
1165 void wxPropertyGrid::ResetColours() 
1167     m_coloursCustomized 
= 0; 
1174 // ----------------------------------------------------------------------- 
1176 bool wxPropertyGrid::SetFont( const wxFont
& font 
) 
1178     // Must disable active editor. 
1181         bool selRes 
= ClearSelection(); 
1182         wxPG_CHECK_MSG_DBG( selRes
, 
1184                             wxT("failed to deselect a property (editor probably had invalid value)") ); 
1187     // TODO: Following code is disabled with wxMac because 
1188     //   it is reported to fail. I (JMS) cannot debug it 
1189     //   personally right now. 
1190 #if !defined(__WXMAC__) 
1191     bool res 
= wxScrolledWindow::SetFont( font 
); 
1194         CalculateFontAndBitmapStuff( m_vspacing 
); 
1197             m_pState
->CalculateFontAndBitmapStuff(m_vspacing
); 
1205     // TODO: Remove after SetFont crash fixed. 
1206     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
1208         wxLogDebug(wxT("WARNING: propGrid.cpp: wxPropertyGrid::SetFont has been disabled on wxMac since there has been crash reported in it. If you are willing to debug the cause, replace line '#if !defined(__WXMAC__)' with line '#if 1' in wxPropertyGrid::SetFont.")); 
1214 // ----------------------------------------------------------------------- 
1216 void wxPropertyGrid::SetLineColour( const wxColour
& col 
) 
1219     m_coloursCustomized 
|= 0x80; 
1223 // ----------------------------------------------------------------------- 
1225 void wxPropertyGrid::SetMarginColour( const wxColour
& col 
) 
1228     m_coloursCustomized 
|= 0x01; 
1232 // ----------------------------------------------------------------------- 
1234 void wxPropertyGrid::SetCellBackgroundColour( const wxColour
& col 
) 
1236     m_colPropBack 
= col
; 
1237     m_coloursCustomized 
|= 0x08; 
1239     // Set the cached brush as well. 
1240     ((wxPGBrush
*)m_arrBgBrushes
.Item(0))->SetColour2(col
); 
1245 // ----------------------------------------------------------------------- 
1247 void wxPropertyGrid::SetCellTextColour( const wxColour
& col 
) 
1249     m_colPropFore 
= col
; 
1250     m_coloursCustomized 
|= 0x10; 
1252     // Set the cached colour as well. 
1253     ((wxPGColour
*)m_arrFgCols
.Item(0))->SetColour2(col
); 
1258 // ----------------------------------------------------------------------- 
1260 void wxPropertyGrid::SetEmptySpaceColour( const wxColour
& col 
) 
1262     m_colEmptySpace 
= col
; 
1267 // ----------------------------------------------------------------------- 
1269 void wxPropertyGrid::SetCellDisabledTextColour( const wxColour
& col 
) 
1271     m_colDisPropFore 
= col
; 
1272     m_coloursCustomized 
|= 0x100; 
1276 // ----------------------------------------------------------------------- 
1278 void wxPropertyGrid::SetSelectionBackgroundColour( const wxColour
& col 
) 
1281     m_coloursCustomized 
|= 0x20; 
1285 // ----------------------------------------------------------------------- 
1287 void wxPropertyGrid::SetSelectionTextColour( const wxColour
& col 
) 
1290     m_coloursCustomized 
|= 0x40; 
1294 // ----------------------------------------------------------------------- 
1296 void wxPropertyGrid::SetCaptionBackgroundColour( const wxColour
& col 
) 
1299     m_coloursCustomized 
|= 0x02; 
1303 // ----------------------------------------------------------------------- 
1305 void wxPropertyGrid::SetCaptionTextColour( const wxColour
& col 
) 
1308     m_coloursCustomized 
|= 0x04; 
1310     // Set the cached colour as well. 
1311     ((wxPGColour
*)m_arrFgCols
.Item(1))->SetColour2(col
); 
1316 // ----------------------------------------------------------------------- 
1318 void wxPropertyGrid::SetBackgroundColourIndex( wxPGProperty
* p
, int index 
) 
1320     unsigned char ind 
= index
; 
1322     p
->m_bgColIndex 
= ind
; 
1325     for ( i
=0; i
<p
->GetChildCount(); i
++ ) 
1326         SetBackgroundColourIndex(p
->Item(i
),index
); 
1329 // ----------------------------------------------------------------------- 
1331 void wxPropertyGrid::SetPropertyBackgroundColour( wxPGPropArg id
, const wxColour
& colour 
) 
1333     wxPG_PROP_ARG_CALL_PROLOG() 
1338     long colAsLong 
= wxPG_COLOUR(colour
.Red(),colour
.Green(),colour
.Blue()); 
1340     // As it is most likely that the previous colour is used, start comparison 
1342     for ( i
=(m_arrBgBrushes
.size()-1); i
>0; i
-- ) 
1344         if ( ((wxPGBrush
*)m_arrBgBrushes
.Item(i
))->GetColourAsLong() == colAsLong 
) 
1353         colInd 
= m_arrBgBrushes
.size(); 
1354         wxCHECK_RET( colInd 
< 256, wxT("wxPropertyGrid: Warning - Only 255 different property background colours allowed.") ); 
1355         m_arrBgBrushes
.Add( (void*)new wxPGBrush(colour
) ); 
1359     SetBackgroundColourIndex(p
,colInd
); 
1361     // If this was on a visible grid, then draw it. 
1362     DrawItemAndChildren(p
); 
1365 // ----------------------------------------------------------------------- 
1367 wxColour 
wxPropertyGrid::GetPropertyBackgroundColour( wxPGPropArg id 
) const 
1369     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxColour()) 
1371     return ((wxPGBrush
*)m_arrBgBrushes
.Item(p
->m_bgColIndex
))->GetColour(); 
1374 // ----------------------------------------------------------------------- 
1376 void wxPropertyGrid::SetTextColourIndex( wxPGProperty
* p
, int index
, int flags 
) 
1378     unsigned char ind 
= index
; 
1380     p
->m_fgColIndex 
= ind
; 
1382     if ( p
->GetChildCount() && (flags 
& wxPG_RECURSE
) ) 
1385         for ( i
=0; i
<p
->GetChildCount(); i
++ ) 
1386             SetTextColourIndex( p
->Item(i
), index
, flags 
); 
1390 // ----------------------------------------------------------------------- 
1392 int wxPropertyGrid::CacheColour( const wxColour
& colour 
) 
1397     long colAsLong 
= wxPG_COLOUR(colour
.Red(),colour
.Green(),colour
.Blue()); 
1399     // As it is most likely that the previous colour is used, start comparison 
1401     for ( i
=(m_arrFgCols
.size()-1); i
>0; i
-- ) 
1403         if ( ((wxPGColour
*)m_arrFgCols
.Item(i
))->GetColourAsLong() == colAsLong 
) 
1412         colInd 
= m_arrFgCols
.size(); 
1413         wxCHECK_MSG( colInd 
< 256, 0, wxT("wxPropertyGrid: Warning - Only 255 different property foreground colours allowed.") ); 
1414         m_arrFgCols
.Add( (void*)new wxPGColour(colour
) ); 
1420 // ----------------------------------------------------------------------- 
1422 void wxPropertyGrid::SetPropertyTextColour( wxPGPropArg id
, const wxColour
& colour
, 
1425     wxPG_PROP_ARG_CALL_PROLOG() 
1427     if ( p
->IsCategory() ) 
1429         wxPropertyCategory
* cat 
= (wxPropertyCategory
*) p
; 
1430         cat
->SetTextColIndex(CacheColour(colour
)); 
1436         flags 
|= wxPG_RECURSE
; 
1437     SetTextColourIndex(p
, CacheColour(colour
), flags
); 
1439     DrawItemAndChildren(p
); 
1442 // ----------------------------------------------------------------------- 
1444 wxColour 
wxPropertyGrid::GetPropertyTextColour( wxPGPropArg id 
) const 
1446     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxColour()) 
1448     return wxColour(*((wxPGColour
*)m_arrFgCols
.Item(p
->m_fgColIndex
))); 
1451 void wxPropertyGrid::SetPropertyColoursToDefault( wxPGPropArg id 
) 
1453     wxPG_PROP_ARG_CALL_PROLOG() 
1455     SetBackgroundColourIndex( p
, 0 ); 
1456     SetTextColourIndex( p
, 0, wxPG_RECURSE 
); 
1458     if ( p
->IsCategory() ) 
1460         wxPropertyCategory
* cat 
= (wxPropertyCategory
*) p
; 
1461         cat
->SetTextColIndex(1); 
1465 // ----------------------------------------------------------------------- 
1466 // wxPropertyGrid property adding and removal 
1467 // ----------------------------------------------------------------------- 
1469 void wxPropertyGrid::PrepareAfterItemsAdded() 
1471     if ( !m_pState 
|| !m_pState
->m_itemsAdded 
) return; 
1473     m_pState
->m_itemsAdded 
= 0; 
1475     if ( m_windowStyle 
& wxPG_AUTO_SORT 
) 
1478     RecalculateVirtualSize(); 
1481 // ----------------------------------------------------------------------- 
1482 // wxPropertyGrid property value setting and getting 
1483 // ----------------------------------------------------------------------- 
1485 void wxPropertyGrid::DoSetPropertyValueUnspecified( wxPGProperty
* p 
) 
1487     m_pState
->DoSetPropertyValueUnspecified(p
); 
1488     DrawItemAndChildren(p
); 
1490     wxPGProperty
* parent 
= p
->GetParent(); 
1491     while ( (parent
->GetFlags() & wxPG_PROP_PARENTAL_FLAGS
) == wxPG_PROP_MISC_PARENT 
) 
1494         parent 
= parent
->GetParent(); 
1498 // ----------------------------------------------------------------------- 
1499 // wxPropertyGrid property operations 
1500 // ----------------------------------------------------------------------- 
1502 bool wxPropertyGrid::EnsureVisible( wxPGPropArg id 
) 
1504     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) 
1508     bool changed 
= false; 
1510     // Is it inside collapsed section? 
1511     if ( !p
->IsVisible() ) 
1514         wxPGProperty
* parent 
= p
->GetParent(); 
1515         wxPGProperty
* grandparent 
= parent
->GetParent(); 
1517         if ( grandparent 
&& grandparent 
!= m_pState
->m_properties 
) 
1518             Expand( grandparent 
); 
1526     GetViewStart(&vx
,&vy
); 
1527     vy
*=wxPG_PIXELS_PER_UNIT
; 
1533         Scroll(vx
, y
/wxPG_PIXELS_PER_UNIT 
); 
1534         m_iFlags 
|= wxPG_FL_SCROLLED
; 
1537     else if ( (y
+m_lineHeight
) > (vy
+m_height
) ) 
1539         Scroll(vx
, (y
-m_height
+(m_lineHeight
*2))/wxPG_PIXELS_PER_UNIT 
); 
1540         m_iFlags 
|= wxPG_FL_SCROLLED
; 
1550 // ----------------------------------------------------------------------- 
1551 // wxPropertyGrid helper methods called by properties 
1552 // ----------------------------------------------------------------------- 
1554 // Control font changer helper. 
1555 void wxPropertyGrid::SetCurControlBoldFont() 
1557     wxASSERT( m_wndEditor 
); 
1558     m_wndEditor
->SetFont( m_captionFont 
); 
1561 // ----------------------------------------------------------------------- 
1563 wxPoint 
wxPropertyGrid::GetGoodEditorDialogPosition( wxPGProperty
* p
, 
1566 #if wxPG_SMALL_SCREEN 
1567     // On small-screen devices, always show dialogs with default position and size. 
1568     return wxDefaultPosition
; 
1570     int splitterX 
= GetSplitterPosition(); 
1574     wxCHECK_MSG( y 
>= 0, wxPoint(-1,-1), wxT("invalid y?") ); 
1576     ImprovedClientToScreen( &x
, &y 
); 
1578     int sw 
= wxSystemSettings::GetMetric( ::wxSYS_SCREEN_X 
); 
1579     int sh 
= wxSystemSettings::GetMetric( ::wxSYS_SCREEN_Y 
); 
1586         new_x 
= x 
+ (m_width
-splitterX
) - sz
.x
; 
1596         new_y 
= y 
+ m_lineHeight
; 
1598     return wxPoint(new_x
,new_y
); 
1602 // ----------------------------------------------------------------------- 
1604 wxString
& wxPropertyGrid::ExpandEscapeSequences( wxString
& dst_str
, wxString
& src_str 
) 
1606     if ( src_str
.length() == 0 ) 
1612     bool prev_is_slash 
= false; 
1614     wxString::const_iterator i 
= src_str
.begin(); 
1618     for ( ; i 
!= src_str
.end(); i
++ ) 
1622         if ( a 
!= wxS('\\') ) 
1624             if ( !prev_is_slash 
) 
1630                 if ( a 
== wxS('n') ) 
1633                     dst_str 
<< wxS('\n'); 
1635                     dst_str 
<< wxS('\n'); 
1638                 else if ( a 
== wxS('t') ) 
1639                     dst_str 
<< wxS('\t'); 
1643             prev_is_slash 
= false; 
1647             if ( prev_is_slash 
) 
1649                 dst_str 
<< wxS('\\'); 
1650                 prev_is_slash 
= false; 
1654                 prev_is_slash 
= true; 
1661 // ----------------------------------------------------------------------- 
1663 wxString
& wxPropertyGrid::CreateEscapeSequences( wxString
& dst_str
, wxString
& src_str 
) 
1665     if ( src_str
.length() == 0 ) 
1671     wxString::const_iterator i 
= src_str
.begin(); 
1672     wxUniChar prev_a 
= wxS('\0'); 
1676     for ( ; i 
!= src_str
.end(); i
++ ) 
1680         if ( a 
>= wxS(' ') ) 
1682             // This surely is not something that requires an escape sequence. 
1687             // This might need... 
1688             if ( a 
== wxS('\r')  ) 
1690                 // DOS style line end. 
1691                 // Already taken care below 
1693             else if ( a 
== wxS('\n') ) 
1694                 // UNIX style line end. 
1695                 dst_str 
<< wxS("\\n"); 
1696             else if ( a 
== wxS('\t') ) 
1698                 dst_str 
<< wxS('\t'); 
1701                 //wxLogDebug(wxT("WARNING: Could not create escape sequence for character #%i"),(int)a); 
1711 // ----------------------------------------------------------------------- 
1713 wxPGProperty
* wxPropertyGrid::DoGetItemAtY( int y 
) const 
1717         return (wxPGProperty
*) NULL
; 
1720     return m_pState
->m_properties
->GetItemAtY(y
, m_lineHeight
, &a
); 
1723 // ----------------------------------------------------------------------- 
1724 // wxPropertyGrid graphics related methods 
1725 // ----------------------------------------------------------------------- 
1727 void wxPropertyGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
1731     // Update everything inside the box 
1732     wxRect r 
= GetUpdateRegion().GetBox(); 
1734     dc
.SetPen(m_colEmptySpace
); 
1735     dc
.SetBrush(m_colEmptySpace
); 
1736     dc
.DrawRectangle(r
); 
1739 // ----------------------------------------------------------------------- 
1741 void wxPropertyGrid::DrawExpanderButton( wxDC
& dc
, const wxRect
& rect
, 
1742                                          wxPGProperty
* property 
) const 
1744     // Prepare rectangle to be used 
1746     r
.x 
+= m_gutterWidth
; r
.y 
+= m_buttonSpacingY
; 
1747     r
.width 
= m_iconWidth
; r
.height 
= m_iconHeight
; 
1749 #if (wxPG_USE_RENDERER_NATIVE) 
1751 #elif wxPG_ICON_WIDTH 
1752     // Drawing expand/collapse button manually 
1753     dc
.SetPen(m_colPropFore
); 
1754     if ( property
->IsCategory() ) 
1755         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1757         dc
.SetBrush(m_colPropBack
); 
1759     dc
.DrawRectangle( r 
); 
1760     int _y 
= r
.y
+(m_iconWidth
/2); 
1761     dc
.DrawLine(r
.x
+2,_y
,r
.x
+m_iconWidth
-2,_y
); 
1766     if ( property
->IsExpanded() ) 
1768     // wxRenderer functions are non-mutating in nature, so it 
1769     // should be safe to cast "const wxPropertyGrid*" to "wxWindow*". 
1770     // Hopefully this does not cause problems. 
1771     #if (wxPG_USE_RENDERER_NATIVE) 
1772         wxRendererNative::Get().DrawTreeItemButton( 
1778     #elif wxPG_ICON_WIDTH 
1787     #if (wxPG_USE_RENDERER_NATIVE) 
1788         wxRendererNative::Get().DrawTreeItemButton( 
1794     #elif wxPG_ICON_WIDTH 
1795         int _x 
= r
.x
+(m_iconWidth
/2); 
1796         dc
.DrawLine(_x
,r
.y
+2,_x
,r
.y
+m_iconWidth
-2); 
1802 #if (wxPG_USE_RENDERER_NATIVE) 
1804 #elif wxPG_ICON_WIDTH 
1807     dc
.DrawBitmap( *bmp
, r
.x
, r
.y
, true ); 
1811 // ----------------------------------------------------------------------- 
1814 // This is the one called by OnPaint event handler and others. 
1815 // topy and bottomy are already unscrolled (ie. physical) 
1817 void wxPropertyGrid::DrawItems( wxDC
& dc
, 
1819                                 unsigned int bottomy
, 
1820                                 const wxRect
* clipRect 
) 
1822     if ( m_frozen 
|| m_height 
< 1 || bottomy 
< topy 
|| !m_pState 
) return; 
1824     m_pState
->EnsureVirtualHeight(); 
1826     wxRect tempClipRect
; 
1829         tempClipRect 
= wxRect(0,topy
,m_pState
->m_width
,bottomy
); 
1830         clipRect 
= &tempClipRect
; 
1833     // items added check 
1834     if ( m_pState
->m_itemsAdded 
) PrepareAfterItemsAdded(); 
1836     int paintFinishY 
= 0; 
1838     if ( m_pState
->m_properties
->GetChildCount() > 0 ) 
1841         bool isBuffered 
= false; 
1843     #if wxPG_DOUBLE_BUFFER 
1844         wxMemoryDC
* bufferDC 
= NULL
; 
1846         if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING
) ) 
1848             if ( !m_doubleBuffer 
) 
1850                 paintFinishY 
= clipRect
->y
; 
1855                 bufferDC 
= new wxMemoryDC(); 
1857                 // If nothing was changed, then just copy from double-buffer 
1858                 bufferDC
->SelectObject( *m_doubleBuffer 
); 
1868             dc
.SetClippingRegion( *clipRect 
); 
1869             paintFinishY 
= DoDrawItems( *dcPtr
, NULL
, NULL
, clipRect
, isBuffered 
); 
1872     #if wxPG_DOUBLE_BUFFER 
1875             dc
.Blit( clipRect
->x
, clipRect
->y
, clipRect
->width
, clipRect
->height
, 
1876                 bufferDC
, 0, 0, wxCOPY 
); 
1877             dc
.DestroyClippingRegion(); // Is this really necessary? 
1883     // Clear area beyond bottomY? 
1884     if ( paintFinishY 
< (clipRect
->y
+clipRect
->height
) ) 
1886         dc
.SetPen(m_colEmptySpace
); 
1887         dc
.SetBrush(m_colEmptySpace
); 
1888         dc
.DrawRectangle( 0, paintFinishY
, m_width
, (clipRect
->y
+clipRect
->height
) ); 
1892 // ----------------------------------------------------------------------- 
1894 int wxPropertyGrid::DoDrawItems( wxDC
& dc
, 
1895                                  const wxPGProperty
* firstItem
, 
1896                                  const wxPGProperty
* lastItem
, 
1897                                  const wxRect
* clipRect
, 
1898                                  bool isBuffered 
) const 
1900     // TODO: This should somehow be eliminated. 
1901     wxRect tempClipRect
; 
1904         wxASSERT(firstItem
); 
1906         tempClipRect 
= GetPropertyRect(firstItem
, lastItem
); 
1907         clipRect 
= &tempClipRect
; 
1911         firstItem 
= DoGetItemAtY(clipRect
->y
); 
1915         lastItem 
= DoGetItemAtY(clipRect
->y
+clipRect
->height
-1); 
1917             lastItem 
= GetLastItem( wxPG_ITERATE_VISIBLE 
); 
1920     if ( m_frozen 
|| m_height 
< 1 || firstItem 
== NULL 
) 
1923     wxCHECK_MSG( !m_pState
->m_itemsAdded
, clipRect
->y
, wxT("no items added") ); 
1924     wxASSERT( m_pState
->m_properties
->GetChildCount() ); 
1926     int lh 
= m_lineHeight
; 
1929     int lastItemBottomY
; 
1931     firstItemTopY 
= clipRect
->y
; 
1932     lastItemBottomY 
= clipRect
->y 
+ clipRect
->height
; 
1934     // Align y coordinates to item boundaries 
1935     firstItemTopY 
-= firstItemTopY 
% lh
; 
1936     lastItemBottomY 
+= lh 
- (lastItemBottomY 
% lh
); 
1937     lastItemBottomY 
-= 1; 
1939     // Entire range outside scrolled, visible area? 
1940     if ( firstItemTopY 
>= (int)m_pState
->GetVirtualHeight() || lastItemBottomY 
<= 0 ) 
1943     wxCHECK_MSG( firstItemTopY 
< lastItemBottomY
, clipRect
->y
, wxT("invalid y values") ); 
1947     wxLogDebug(wxT("  -> DoDrawItems ( \"%s\" -> \"%s\", height=%i (ch=%i), clipRect = 0x%lX )"), 
1948         firstItem->GetLabel().c_str(), 
1949         lastItem->GetLabel().c_str(), 
1950         (int)(lastItemBottomY - firstItemTopY), 
1952         (unsigned long)clipRect ); 
1957     long windowStyle 
= m_windowStyle
; 
1963     // With wxPG_DOUBLE_BUFFER, do double buffering 
1964     // - buffer's y = 0, so align cliprect and coordinates to that 
1966 #if wxPG_DOUBLE_BUFFER 
1972         xRelMod 
= clipRect
->x
; 
1973         yRelMod 
= clipRect
->y
; 
1976         // clipRect conversion 
1984         firstItemTopY 
-= yRelMod
; 
1985         lastItemBottomY 
-= yRelMod
; 
1988     wxUnusedVar(isBuffered
); 
1991     int x 
= m_marginWidth 
- xRelMod
; 
1993     const wxFont
& normalfont 
= m_font
; 
1995     bool reallyFocused 
= (m_iFlags 
& wxPG_FL_FOCUSED
) ? true : false; 
1997     bool isEnabled 
= IsEnabled(); 
2000     // Prepare some pens and brushes that are often changed to. 
2003     wxBrush 
marginBrush(m_colMargin
); 
2004     wxPen 
marginPen(m_colMargin
); 
2005     wxBrush 
capbgbrush(m_colCapBack
,wxSOLID
); 
2006     wxPen 
linepen(m_colLine
,1,wxSOLID
); 
2008     // pen that has same colour as text 
2009     wxPen 
outlinepen(m_colPropFore
,1,wxSOLID
); 
2012     // Clear margin with background colour 
2014     dc
.SetBrush( marginBrush 
); 
2015     if ( !(windowStyle 
& wxPG_HIDE_MARGIN
) ) 
2017         dc
.SetPen( *wxTRANSPARENT_PEN 
); 
2018         dc
.DrawRectangle(-1-xRelMod
,firstItemTopY
-1,x
+2,lastItemBottomY
-firstItemTopY
+2); 
2021     const wxPGProperty
* selected 
= m_selected
; 
2022     const wxPropertyGridPageState
* state 
= m_pState
; 
2024 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2025     bool wasSelectedPainted 
= false; 
2028     // TODO: Only render columns that are within clipping region. 
2030     dc
.SetFont(normalfont
); 
2032     wxPropertyGridConstIterator 
it( state
, wxPG_ITERATE_VISIBLE
, firstItem 
); 
2033     int endScanBottomY 
= lastItemBottomY 
+ lh
; 
2034     int y 
= firstItemTopY
; 
2037     // Pregenerate list of visible properties. 
2038     wxArrayPGProperty visPropArray
; 
2039     visPropArray
.reserve((m_height
/m_lineHeight
)+6); 
2041     for ( ; !it
.AtEnd(); it
.Next() ) 
2043         const wxPGProperty
* p 
= *it
; 
2045         if ( !p
->HasFlag(wxPG_PROP_HIDDEN
) ) 
2047             visPropArray
.push_back((wxPGProperty
*)p
); 
2049             if ( y 
> endScanBottomY 
) 
2056     visPropArray
.push_back(NULL
); 
2058     wxPGProperty
* nextP 
= visPropArray
[0]; 
2060     int gridWidth 
= state
->m_width
; 
2063     for ( unsigned int arrInd
=1; 
2064           nextP 
&& y 
<= lastItemBottomY
; 
2067         wxPGProperty
* p 
= nextP
; 
2068         nextP 
= visPropArray
[arrInd
]; 
2070         int rowHeight 
= m_fontHeight
+(m_spacingy
*2)+1; 
2071         int textMarginHere 
= x
; 
2072         int renderFlags 
= wxPGCellRenderer::Control
; 
2074         int greyDepth 
= m_marginWidth
; 
2075         if ( !(windowStyle 
& wxPG_HIDE_CATEGORIES
) ) 
2076             greyDepth 
= (((int)p
->m_depthBgCol
)-1) * m_subgroup_extramargin 
+ m_marginWidth
; 
2078         int greyDepthX 
= greyDepth 
- xRelMod
; 
2080         // Use basic depth if in non-categoric mode and parent is base array. 
2081         if ( !(windowStyle 
& wxPG_HIDE_CATEGORIES
) || p
->GetParent() != m_pState
->m_properties 
) 
2083             textMarginHere 
+= ((unsigned int)((p
->m_depth
-1)*m_subgroup_extramargin
)); 
2086         // Paint margin area 
2087         dc
.SetBrush(marginBrush
); 
2088         dc
.SetPen(marginPen
); 
2089         dc
.DrawRectangle( -xRelMod
, y
, greyDepth
, lh 
); 
2091         dc
.SetPen( linepen 
); 
2096         dc
.DrawLine( greyDepthX
, y
, greyDepthX
, y2 
); 
2102         for ( si
=0; si
<state
->m_colWidths
.size(); si
++ ) 
2104             sx 
+= state
->m_colWidths
[si
]; 
2105             dc
.DrawLine( sx
, y
, sx
, y2 
); 
2108         // Horizontal Line, below 
2109         //   (not if both this and next is category caption) 
2110         if ( p
->IsCategory() && 
2111              nextP 
&& nextP
->IsCategory() ) 
2112             dc
.SetPen(m_colCapBack
); 
2114         dc
.DrawLine( greyDepthX
, y2
-1, gridWidth
-xRelMod
, y2
-1 ); 
2116         if ( p 
== selected 
) 
2118             renderFlags 
|= wxPGCellRenderer::Selected
; 
2119 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2120             wasSelectedPainted 
= true; 
2128         if ( p
->IsCategory() ) 
2130             if ( p
->m_fgColIndex 
== 0 ) 
2131                 rowFgCol 
= m_colCapFore
; 
2133                 rowFgCol 
= *(wxPGColour
*)m_arrFgCols
[p
->m_fgColIndex
]; 
2134             rowBgBrush 
= wxBrush(m_colCapBack
); 
2136         else if ( p 
!= selected 
) 
2138             // Disabled may get different colour. 
2139             if ( !p
->IsEnabled() ) 
2140                 rowFgCol 
= m_colDisPropFore
; 
2142                 rowFgCol 
= *(wxPGColour
*)m_arrFgCols
[p
->m_fgColIndex
]; 
2144             rowBgBrush 
= *(wxPGBrush
*)m_arrBgBrushes
[p
->m_bgColIndex
]; 
2148             // Selected gets different colour. 
2149             if ( reallyFocused 
) 
2151                 rowFgCol 
= m_colSelFore
; 
2152                 rowBgBrush 
= wxBrush(m_colSelBack
); 
2154             else if ( isEnabled 
) 
2156                 rowFgCol 
= *(wxPGColour
*)m_arrFgCols
[p
->m_fgColIndex
]; 
2157                 rowBgBrush 
= marginBrush
; 
2161                 rowFgCol 
= m_colDisPropFore
; 
2162                 rowBgBrush 
= wxBrush(m_colSelBack
); 
2166         bool fontChanged 
= false; 
2168         wxRect 
butRect( ((p
->m_depth 
- 1) * m_subgroup_extramargin
) - xRelMod
, 
2173         if ( p
->IsCategory() ) 
2175             // Captions are all cells merged as one 
2176             dc
.SetFont(m_captionFont
); 
2178             wxRect 
cellRect(greyDepthX
, y
, gridWidth 
- greyDepth 
+ 2, rowHeight
-1 ); 
2180             dc
.SetBrush(rowBgBrush
); 
2181             dc
.SetPen(rowBgBrush
.GetColour()); 
2182             dc
.SetTextForeground(rowFgCol
); 
2184             dc
.DrawRectangle(cellRect
); 
2187             wxPGCellRenderer
* renderer 
= p
->GetCellRenderer(0); 
2188             renderer
->Render( dc
, cellRect
, this, p
, 0, -1, renderFlags 
); 
2191             if ( !HasFlag(wxPG_HIDE_MARGIN
) && p
->HasVisibleChildren() ) 
2192                 DrawExpanderButton( dc
, butRect
, p 
); 
2196             if ( p
->m_flags 
& wxPG_PROP_MODIFIED 
&& (windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
2198                 dc
.SetFont(m_captionFont
); 
2204             int nextCellWidth 
= state
->m_colWidths
[0]; 
2205             wxRect 
cellRect(greyDepthX
+1, y
, 0, rowHeight
-1); 
2206             int textXAdd 
= textMarginHere 
- greyDepthX
; 
2208             for ( ci
=0; ci
<state
->m_colWidths
.size(); ci
++ ) 
2210                 cellRect
.width 
= nextCellWidth 
- 1; 
2212                 bool ctrlCell 
= false; 
2215                 if ( p 
== selected 
&& m_wndEditor 
&& ci 
== 1 ) 
2217                     wxColour editorBgCol 
= GetEditorControl()->GetBackgroundColour(); 
2218                     dc
.SetBrush(editorBgCol
); 
2219                     dc
.SetPen(editorBgCol
); 
2220                     dc
.SetTextForeground(m_colPropFore
); 
2222                     if ( m_dragStatus 
== 0 && !(m_iFlags 
& wxPG_FL_CUR_USES_CUSTOM_IMAGE
) ) 
2227                     dc
.SetBrush(rowBgBrush
); 
2228                     dc
.SetPen(rowBgBrush
.GetColour()); 
2229                     dc
.SetTextForeground(rowFgCol
); 
2232                 dc
.DrawRectangle(cellRect
); 
2235                 if ( ci 
== 0 && !HasFlag(wxPG_HIDE_MARGIN
) && p
->HasVisibleChildren() ) 
2236                     DrawExpanderButton( dc
, butRect
, p 
); 
2238                 dc
.SetClippingRegion(cellRect
); 
2240                 cellRect
.x 
+= textXAdd
; 
2241                 cellRect
.width 
-= textXAdd
; 
2246                     wxPGCellRenderer
* renderer
; 
2247                     int cmnVal 
= p
->GetCommonValue(); 
2248                     if ( cmnVal 
== -1 || ci 
!= 1 ) 
2250                         renderer 
= p
->GetCellRenderer(ci
); 
2251                         renderer
->Render( dc
, cellRect
, this, p
, ci
, -1, renderFlags 
); 
2255                         renderer 
= GetCommonValue(cmnVal
)->GetRenderer(); 
2256                         renderer
->Render( dc
, cellRect
, this, p
, ci
, -1, renderFlags 
); 
2260                 cellX 
+= state
->m_colWidths
[ci
]; 
2261                 if ( ci 
< (state
->m_colWidths
.size()-1) ) 
2262                     nextCellWidth 
= state
->m_colWidths
[ci
+1]; 
2264                 dc
.DestroyClippingRegion(); // Is this really necessary? 
2270             dc
.SetFont(normalfont
); 
2275     // Refresh editor controls (seems not needed on msw) 
2276     // NOTE: This code is mandatory for GTK! 
2277 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2278     if ( wasSelectedPainted 
) 
2281             m_wndEditor
->Refresh(); 
2283             m_wndEditor2
->Refresh(); 
2290 // ----------------------------------------------------------------------- 
2292 wxRect 
wxPropertyGrid::GetPropertyRect( const wxPGProperty
* p1
, const wxPGProperty
* p2 
) const 
2296     if ( m_width 
< 10 || m_height 
< 10 || 
2297          !m_pState
->m_properties
->GetChildCount() || 
2298          p1 
== (wxPGProperty
*) NULL 
) 
2299         return wxRect(0,0,0,0); 
2304     // Return rect which encloses the given property range 
2306     int visTop 
= p1
->GetY(); 
2309         visBottom 
= p2
->GetY() + m_lineHeight
; 
2311         visBottom 
= m_height 
+ visTop
; 
2313     // If seleced property is inside the range, we'll extend the range to include 
2315     wxPGProperty
* selected 
= m_selected
; 
2318         int selectedY 
= selected
->GetY(); 
2319         if ( selectedY 
>= visTop 
&& selectedY 
< visBottom 
) 
2321             wxWindow
* editor 
= GetEditorControl(); 
2324                 int visBottom2 
= selectedY 
+ editor
->GetSize().y
; 
2325                 if ( visBottom2 
> visBottom 
) 
2326                     visBottom 
= visBottom2
; 
2331     return wxRect(0,visTop
-vy
,m_pState
->m_width
,visBottom
-visTop
); 
2334 // ----------------------------------------------------------------------- 
2336 void wxPropertyGrid::DrawItems( const wxPGProperty
* p1
, const wxPGProperty
* p2 
) 
2341     if ( m_pState
->m_itemsAdded 
) 
2342         PrepareAfterItemsAdded(); 
2344     wxRect r 
= GetPropertyRect(p1
, p2
); 
2347         m_canvas
->RefreshRect(r
); 
2351 // ----------------------------------------------------------------------- 
2353 void wxPropertyGrid::RefreshProperty( wxPGProperty
* p 
) 
2355     if ( p 
== m_selected 
) 
2356         DoSelectProperty(p
, wxPG_SEL_FORCE
); 
2358     DrawItemAndChildren(p
); 
2361 // ----------------------------------------------------------------------- 
2363 void wxPropertyGrid::DrawItemAndValueRelated( wxPGProperty
* p 
) 
2368     // Draw item, children, and parent too, if it is not category 
2369     wxPGProperty
* parent 
= p
->GetParent(); 
2372             !parent
->IsCategory() && 
2373             parent
->GetParent() ) 
2376          parent 
= parent
->GetParent(); 
2379     DrawItemAndChildren(p
); 
2382 void wxPropertyGrid::DrawItemAndChildren( wxPGProperty
* p 
) 
2384     wxCHECK_RET( p
, wxT("invalid property id") ); 
2386     // Do not draw if in non-visible page 
2387     if ( p
->GetParentState() != m_pState 
) 
2390     // do not draw a single item if multiple pending 
2391     if ( m_pState
->m_itemsAdded 
|| m_frozen 
) 
2394     wxWindow
* wndPrimary 
= GetEditorControl(); 
2396     // Update child control. 
2397     if ( m_selected 
&& m_selected
->GetParent() == p 
) 
2398         m_selected
->UpdateControl(wndPrimary
); 
2400     const wxPGProperty
* lastDrawn 
= p
->GetLastVisibleSubItem(); 
2402     DrawItems(p
, lastDrawn
); 
2405 // ----------------------------------------------------------------------- 
2407 void wxPropertyGrid::Refresh( bool WXUNUSED(eraseBackground
), 
2408                               const wxRect 
*rect 
) 
2410     PrepareAfterItemsAdded(); 
2412     wxWindow::Refresh(false); 
2414         // TODO: Coordinate translation 
2415         m_canvas
->Refresh(false, rect
); 
2417 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2418     // I think this really helps only GTK+1.2 
2419     if ( m_wndEditor 
) m_wndEditor
->Refresh(); 
2420     if ( m_wndEditor2 
) m_wndEditor2
->Refresh(); 
2424 // ----------------------------------------------------------------------- 
2425 // wxPropertyGrid global operations 
2426 // ----------------------------------------------------------------------- 
2428 void wxPropertyGrid::Clear() 
2432         bool selRes 
= DoSelectProperty(NULL
, wxPG_SEL_DELETING
);  // This must be before state clear 
2433         wxPG_CHECK_RET_DBG( selRes
, 
2434                             wxT("failed to deselect a property (editor probably had invalid value)") ); 
2437     m_pState
->DoClear(); 
2443     RecalculateVirtualSize(); 
2445     // Need to clear some area at the end 
2447         RefreshRect(wxRect(0, 0, m_width
, m_height
)); 
2450 // ----------------------------------------------------------------------- 
2452 bool wxPropertyGrid::EnableCategories( bool enable 
) 
2454     if ( !ClearSelection() ) 
2460         // Enable categories 
2463         m_windowStyle 
&= ~(wxPG_HIDE_CATEGORIES
); 
2468         // Disable categories 
2470         m_windowStyle 
|= wxPG_HIDE_CATEGORIES
; 
2473     if ( !m_pState
->EnableCategories(enable
) ) 
2478         if ( m_windowStyle 
& wxPG_AUTO_SORT 
) 
2480             m_pState
->m_itemsAdded 
= 1; // force 
2481             PrepareAfterItemsAdded(); 
2485         m_pState
->m_itemsAdded 
= 1; 
2487     // No need for RecalculateVirtualSize() here - it is already called in 
2488     // wxPropertyGridPageState method above. 
2495 // ----------------------------------------------------------------------- 
2497 void wxPropertyGrid::SwitchState( wxPropertyGridPageState
* pNewState 
) 
2499     wxASSERT( pNewState 
); 
2500     wxASSERT( pNewState
->GetGrid() ); 
2502     if ( pNewState 
== m_pState 
) 
2505     wxPGProperty
* oldSelection 
= m_selected
; 
2510         bool selRes 
= ClearSelection(); 
2511         wxPG_CHECK_RET_DBG( selRes
, 
2512                             wxT("failed to deselect a property (editor probably had invalid value)") ); 
2515     m_pState
->m_selected 
= oldSelection
; 
2517     bool orig_mode 
= m_pState
->IsInNonCatMode(); 
2518     bool new_state_mode 
= pNewState
->IsInNonCatMode(); 
2520     m_pState 
= pNewState
; 
2523     int pgWidth 
= GetClientSize().x
; 
2524     if ( HasVirtualWidth() ) 
2526         int minWidth 
= pgWidth
; 
2527         if ( pNewState
->m_width 
< minWidth 
) 
2529             pNewState
->m_width 
= minWidth
; 
2530             pNewState
->CheckColumnWidths(); 
2536         // Just in case, fully re-center splitter 
2537         if ( HasFlag( wxPG_SPLITTER_AUTO_CENTER 
) ) 
2538             pNewState
->m_fSplitterX 
= -1.0; 
2540         pNewState
->OnClientWidthChange( pgWidth
, pgWidth 
- pNewState
->m_width 
); 
2543     m_propHover 
= (wxPGProperty
*) NULL
; 
2545     // If necessary, convert state to correct mode. 
2546     if ( orig_mode 
!= new_state_mode 
) 
2548         // This should refresh as well. 
2549         EnableCategories( orig_mode
?false:true ); 
2551     else if ( !m_frozen 
) 
2553         // Refresh, if not frozen. 
2554         if ( m_pState
->m_itemsAdded 
) 
2555             PrepareAfterItemsAdded(); 
2558         if ( m_pState
->m_selected 
) 
2559             DoSelectProperty( m_pState
->m_selected 
); 
2561         RecalculateVirtualSize(0); 
2565         m_pState
->m_itemsAdded 
= 1; 
2568 // ----------------------------------------------------------------------- 
2570 void wxPropertyGrid::SortChildren( wxPGPropArg id 
) 
2572     wxPG_PROP_ARG_CALL_PROLOG() 
2574     m_pState
->SortChildren( p 
); 
2577 // ----------------------------------------------------------------------- 
2579 void wxPropertyGrid::Sort() 
2581     bool selRes 
= ClearSelection();  // This must be before state clear 
2582     wxPG_CHECK_RET_DBG( selRes
, 
2583                         wxT("failed to deselect a property (editor probably had invalid value)") ); 
2588 // ----------------------------------------------------------------------- 
2590 // Call to SetSplitterPosition will always disable splitter auto-centering 
2591 // if parent window is shown. 
2592 void wxPropertyGrid::DoSetSplitterPosition_( int newxpos
, bool refresh
, int splitterIndex
, bool allPages 
) 
2594     if ( ( newxpos 
< wxPG_DRAG_MARGIN 
) ) 
2597     wxPropertyGridPageState
* state 
= m_pState
; 
2599     state
->DoSetSplitterPosition( newxpos
, splitterIndex
, allPages 
); 
2604             CorrectEditorWidgetSizeX(); 
2610 // ----------------------------------------------------------------------- 
2612 void wxPropertyGrid::CenterSplitter( bool enableAutoCentering 
) 
2614     SetSplitterPosition( m_width
/2, true ); 
2615     if ( enableAutoCentering 
&& ( m_windowStyle 
& wxPG_SPLITTER_AUTO_CENTER 
) ) 
2616         m_iFlags 
&= ~(wxPG_FL_DONT_CENTER_SPLITTER
); 
2619 // ----------------------------------------------------------------------- 
2620 // wxPropertyGrid item iteration (GetNextProperty etc.) methods 
2621 // ----------------------------------------------------------------------- 
2623 // Returns nearest paint visible property (such that will be painted unless 
2624 // window is scrolled or resized). If given property is paint visible, then 
2625 // it itself will be returned 
2626 wxPGProperty
* wxPropertyGrid::GetNearestPaintVisible( wxPGProperty
* p 
) const 
2628     int vx
,vy1
;// Top left corner of client 
2629     GetViewStart(&vx
,&vy1
); 
2630     vy1 
*= wxPG_PIXELS_PER_UNIT
; 
2632     int vy2 
= vy1 
+ m_height
; 
2633     int propY 
= p
->GetY2(m_lineHeight
); 
2635     if ( (propY 
+ m_lineHeight
) < vy1 
) 
2638         return DoGetItemAtY( vy1 
); 
2640     else if ( propY 
> vy2 
) 
2643         return DoGetItemAtY( vy2 
); 
2646     // Itself paint visible 
2651 // ----------------------------------------------------------------------- 
2653 void wxPropertyGrid::SetButtonShortcut( int keycode
, bool ctrlDown
, bool altDown 
) 
2657         m_pushButKeyCode 
= keycode
; 
2658         m_pushButKeyCodeNeedsCtrl 
= ctrlDown 
? 1 : 0; 
2659         m_pushButKeyCodeNeedsAlt 
= altDown 
? 1 : 0; 
2663         m_pushButKeyCode 
= WXK_DOWN
; 
2664         m_pushButKeyCodeNeedsCtrl 
= 0; 
2665         m_pushButKeyCodeNeedsAlt 
= 1; 
2669 // ----------------------------------------------------------------------- 
2670 // Methods related to change in value, value modification and sending events 
2671 // ----------------------------------------------------------------------- 
2673 // commits any changes in editor of selected property 
2674 // return true if validation did not fail 
2675 // flags are same as with DoSelectProperty 
2676 bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags 
) 
2678     // Committing already? 
2679     if ( m_inCommitChangesFromEditor 
) 
2682     // Don't do this if already processing editor event. It might 
2683     // induce recursive dialogs and crap like that. 
2684     if ( m_iFlags 
& wxPG_FL_IN_ONCUSTOMEDITOREVENT 
) 
2686         if ( m_inDoPropertyChanged 
) 
2693          IsEditorsValueModified() && 
2694          (m_iFlags 
& wxPG_FL_INITIALIZED
) && 
2697         m_inCommitChangesFromEditor 
= 1; 
2699         wxVariant 
variant(m_selected
->GetValueRef()); 
2700         bool valueIsPending 
= false; 
2702         // JACS - necessary to avoid new focus being found spuriously within OnIdle 
2703         // due to another window getting focus 
2704         wxWindow
* oldFocus 
= m_curFocused
; 
2706         bool validationFailure 
= false; 
2707         bool forceSuccess 
= (flags 
& (wxPG_SEL_NOVALIDATE
|wxPG_SEL_FORCE
)) ? true : false; 
2709         m_chgInfo_changedProperty 
= NULL
; 
2711         // If truly modified, schedule value as pending. 
2712         if ( m_selected
->GetEditorClass()->GetValueFromControl( variant
, m_selected
, GetEditorControl() ) ) 
2714             if ( DoEditorValidate() && 
2715                  PerformValidation(m_selected
, variant
) ) 
2717                 valueIsPending 
= true; 
2721                 validationFailure 
= true; 
2726             EditorsValueWasNotModified(); 
2731         m_inCommitChangesFromEditor 
= 0; 
2733         if ( validationFailure 
&& !forceSuccess 
) 
2737                 oldFocus
->SetFocus(); 
2738                 m_curFocused 
= oldFocus
; 
2741             res 
= OnValidationFailure(m_selected
, variant
); 
2743             // Now prevent further validation failure messages 
2746                 EditorsValueWasNotModified(); 
2747                 OnValidationFailureReset(m_selected
); 
2750         else if ( valueIsPending 
) 
2752             DoPropertyChanged( m_selected
, flags 
); 
2753             EditorsValueWasNotModified(); 
2762 // ----------------------------------------------------------------------- 
2764 bool wxPropertyGrid::PerformValidation( wxPGProperty
* p
, wxVariant
& pendingValue 
) 
2767     // Runs all validation functionality. 
2768     // Returns true if value passes all tests. 
2771     m_validationInfo
.m_failureBehavior 
= m_permanentValidationFailureBehavior
; 
2773     if ( pendingValue
.GetType() == wxPG_VARIANT_TYPE_LIST 
) 
2775         if ( !p
->ValidateValue(pendingValue
, m_validationInfo
) ) 
2780     // Adapt list to child values, if necessary 
2781     wxVariant listValue 
= pendingValue
; 
2782     wxVariant
* pPendingValue 
= &pendingValue
; 
2783     wxVariant
* pList 
= NULL
; 
2785     // If parent has wxPG_PROP_AGGREGATE flag, or uses composite 
2786     // string value, then we need treat as it was changed instead 
2787     // (or, in addition, as is the case with composite string parent). 
2788     // This includes creating list variant for child values. 
2790     wxPGProperty
* pwc 
= p
->GetParent(); 
2791     wxPGProperty
* changedProperty 
= p
; 
2792     wxPGProperty
* baseChangedProperty 
= changedProperty
; 
2793     wxVariant bcpPendingList
; 
2795     listValue 
= pendingValue
; 
2796     listValue
.SetName(p
->GetBaseName()); 
2799             (pwc
->HasFlag(wxPG_PROP_AGGREGATE
) || pwc
->HasFlag(wxPG_PROP_COMPOSED_VALUE
)) ) 
2801         wxVariantList tempList
; 
2802         wxVariant 
lv(tempList
, pwc
->GetBaseName()); 
2803         lv
.Append(listValue
); 
2805         pPendingValue 
= &listValue
; 
2807         if ( pwc
->HasFlag(wxPG_PROP_AGGREGATE
) ) 
2809             baseChangedProperty 
= pwc
; 
2810             bcpPendingList 
= lv
; 
2813         changedProperty 
= pwc
; 
2814         pwc 
= pwc
->GetParent(); 
2818     wxPGProperty
* evtChangingProperty 
= changedProperty
; 
2820     if ( pPendingValue
->GetType() != wxPG_VARIANT_TYPE_LIST 
) 
2822         value 
= *pPendingValue
; 
2826         // Convert list to child values 
2827         pList 
= pPendingValue
; 
2828         changedProperty
->AdaptListToValue( *pPendingValue
, &value 
); 
2831     wxVariant evtChangingValue 
= value
; 
2833     // FIXME: After proper ValueToString()s added, remove 
2834     // this. It is just a temporary fix, as evt_changing 
2835     // will simply not work for wxPG_PROP_COMPOSED_VALUE 
2836     // (unless it is selected, and textctrl editor is open). 
2837     if ( changedProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
2839         evtChangingProperty 
= baseChangedProperty
; 
2840         if ( evtChangingProperty 
!= p 
) 
2842             evtChangingProperty
->AdaptListToValue( bcpPendingList
, &evtChangingValue 
); 
2846             evtChangingValue 
= pendingValue
; 
2850     if ( evtChangingProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
2852         if ( changedProperty 
== m_selected 
) 
2854             wxASSERT( m_wndEditor
->IsKindOf(CLASSINFO(wxTextCtrl
)) ); 
2855             evtChangingValue 
= ((wxTextCtrl
*)m_wndEditor
)->GetValue(); 
2859             wxLogDebug(wxT("WARNING: wxEVT_PG_CHANGING is about to happen with old value.")); 
2863     wxASSERT( m_chgInfo_changedProperty 
== NULL 
); 
2864     m_chgInfo_changedProperty 
= changedProperty
; 
2865     m_chgInfo_baseChangedProperty 
= baseChangedProperty
; 
2866     m_chgInfo_pendingValue 
= value
; 
2869         m_chgInfo_valueList 
= *pList
; 
2871         m_chgInfo_valueList
.MakeNull(); 
2873     // If changedProperty is not property which value was edited, 
2874     // then call wxPGProperty::ValidateValue() for that as well. 
2875     if ( p 
!= changedProperty 
&& value
.GetType() != wxPG_VARIANT_TYPE_LIST 
) 
2877         if ( !changedProperty
->ValidateValue(value
, m_validationInfo
) ) 
2881     // SendEvent returns true if event was vetoed 
2882     if ( SendEvent( wxEVT_PG_CHANGING
, evtChangingProperty
, &evtChangingValue
, 0 ) ) 
2888 // ----------------------------------------------------------------------- 
2890 void wxPropertyGrid::DoShowPropertyError( wxPGProperty
* WXUNUSED(property
), const wxString
& msg 
) 
2892     if ( !msg
.length() ) 
2896     if ( !wxPGGlobalVars
->m_offline 
) 
2898         wxWindow
* topWnd 
= ::wxGetTopLevelParent(this); 
2901             wxFrame
* pFrame 
= wxDynamicCast(topWnd
, wxFrame
); 
2904                 wxStatusBar
* pStatusBar 
= pFrame
->GetStatusBar(); 
2907                     pStatusBar
->SetStatusText(msg
); 
2915     ::wxMessageBox(msg
, _T("Property Error")); 
2918 // ----------------------------------------------------------------------- 
2920 bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty
* property
, wxVariant
& WXUNUSED(invalidValue
) ) 
2922     int vfb 
= m_validationInfo
.m_failureBehavior
; 
2924     if ( vfb 
& wxPG_VFB_BEEP 
) 
2927     if ( (vfb 
& wxPG_VFB_MARK_CELL
) && 
2928          !property
->HasFlag(wxPG_PROP_INVALID_VALUE
) ) 
2930         wxASSERT_MSG( !property
->GetCell(0) && !property
->GetCell(1), 
2931                       wxT("Currently wxPG_VFB_MARK_CELL only works with properties with standard first two cells") ); 
2933         if ( !property
->GetCell(0) && !property
->GetCell(1) ) 
2935             wxColour vfbFg 
= *wxWHITE
; 
2936             wxColour vfbBg 
= *wxRED
; 
2937             property
->SetCell(0, new wxPGCell(property
->GetLabel(), wxNullBitmap
, vfbFg
, vfbBg
)); 
2938             property
->SetCell(1, new wxPGCell(property
->GetDisplayedString(), wxNullBitmap
, vfbFg
, vfbBg
)); 
2940             DrawItemAndChildren(property
); 
2942             if ( property 
== m_selected 
) 
2944                 SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
); 
2946                 wxWindow
* editor 
= GetEditorControl(); 
2949                     editor
->SetForegroundColour(vfbFg
); 
2950                     editor
->SetBackgroundColour(vfbBg
); 
2956     if ( vfb 
& wxPG_VFB_SHOW_MESSAGE 
) 
2958         wxString msg 
= m_validationInfo
.m_failureMessage
; 
2960         if ( !msg
.length() ) 
2961             msg 
= _T("You have entered invalid value. Press ESC to cancel editing."); 
2963         DoShowPropertyError(property
, msg
); 
2966     return (vfb 
& wxPG_VFB_STAY_IN_PROPERTY
) ? false : true; 
2969 // ----------------------------------------------------------------------- 
2971 void wxPropertyGrid::DoOnValidationFailureReset( wxPGProperty
* property 
) 
2973     int vfb 
= m_validationInfo
.m_failureBehavior
; 
2975     if ( vfb 
& wxPG_VFB_MARK_CELL 
) 
2977         property
->SetCell(0, NULL
); 
2978         property
->SetCell(1, NULL
); 
2980         ClearInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
); 
2982         if ( property 
== m_selected 
&& GetEditorControl() ) 
2984             // Calling this will recreate the control, thus resetting its colour 
2985             RefreshProperty(property
); 
2989             DrawItemAndChildren(property
); 
2994 // ----------------------------------------------------------------------- 
2996 // flags are same as with DoSelectProperty 
2997 bool wxPropertyGrid::DoPropertyChanged( wxPGProperty
* p
, unsigned int selFlags 
) 
2999     if ( m_inDoPropertyChanged 
) 
3002     wxWindow
* editor 
= GetEditorControl(); 
3004     m_pState
->m_anyModified 
= 1; 
3006     m_inDoPropertyChanged 
= 1; 
3008     // Maybe need to update control 
3009     wxASSERT( m_chgInfo_changedProperty 
!= NULL 
); 
3011     // These values were calculated in PerformValidation() 
3012     wxPGProperty
* changedProperty 
= m_chgInfo_changedProperty
; 
3013     wxVariant value 
= m_chgInfo_pendingValue
; 
3015     wxPGProperty
* topPaintedProperty 
= changedProperty
; 
3017     while ( !topPaintedProperty
->IsCategory() && 
3018             !topPaintedProperty
->IsRoot() ) 
3020         topPaintedProperty 
= topPaintedProperty
->GetParent(); 
3023     changedProperty
->SetValue(value
, &m_chgInfo_valueList
, wxPG_SETVAL_BY_USER
); 
3025     // Set as Modified (not if dragging just began) 
3026     if ( !(p
->m_flags 
& wxPG_PROP_MODIFIED
) ) 
3028         p
->m_flags 
|= wxPG_PROP_MODIFIED
; 
3029         if ( p 
== m_selected 
&& (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
3032                 SetCurControlBoldFont(); 
3038     // Propagate updates to parent(s) 
3040     wxPGProperty
* prevPwc 
= NULL
; 
3042     while ( prevPwc 
!= topPaintedProperty 
) 
3044         pwc
->m_flags 
|= wxPG_PROP_MODIFIED
; 
3046         if ( pwc 
== m_selected 
&& (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
3049                 SetCurControlBoldFont(); 
3053         pwc 
= pwc
->GetParent(); 
3056     // Draw the actual property 
3057     DrawItemAndChildren( topPaintedProperty 
); 
3060     // If value was set by wxPGProperty::OnEvent, then update the editor 
3062     if ( selFlags 
& wxPG_SEL_DIALOGVAL 
) 
3065             p
->GetEditorClass()->UpdateControl(p
, editor
); 
3069 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
3070         if ( m_wndEditor 
) m_wndEditor
->Refresh(); 
3071         if ( m_wndEditor2 
) m_wndEditor2
->Refresh(); 
3076     wxASSERT( !changedProperty
->GetParent()->HasFlag(wxPG_PROP_AGGREGATE
) ); 
3078     // If top parent has composite string value, then send to child parents, 
3079     // starting from baseChangedProperty. 
3080     if ( changedProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
3082         pwc 
= m_chgInfo_baseChangedProperty
; 
3084         while ( pwc 
!= changedProperty 
) 
3086             SendEvent( wxEVT_PG_CHANGED
, pwc
, NULL
, selFlags 
); 
3087             pwc 
= pwc
->GetParent(); 
3091     SendEvent( wxEVT_PG_CHANGED
, changedProperty
, NULL
, selFlags 
); 
3093     m_inDoPropertyChanged 
= 0; 
3098 // ----------------------------------------------------------------------- 
3100 bool wxPropertyGrid::ChangePropertyValue( wxPGPropArg id
, wxVariant newValue 
) 
3102     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) 
3104     m_chgInfo_changedProperty 
= NULL
; 
3106     if ( PerformValidation(p
, newValue
) ) 
3108         DoPropertyChanged(p
); 
3113         OnValidationFailure(p
, newValue
); 
3119 // ----------------------------------------------------------------------- 
3121 // Runs wxValidator for the selected property 
3122 bool wxPropertyGrid::DoEditorValidate() 
3127 // ----------------------------------------------------------------------- 
3129 bool wxPropertyGrid::ProcessEvent(wxEvent
& event
) 
3131     wxWindow
* wnd 
= (wxWindow
*) event
.GetEventObject(); 
3132     if ( wnd 
&& wnd
->IsKindOf(CLASSINFO(wxWindow
)) ) 
3134         wxWindow
* parent 
= wnd
->GetParent(); 
3137              (parent 
== m_canvas 
|| 
3138               parent
->GetParent() == m_canvas
) ) 
3140             OnCustomEditorEvent((wxCommandEvent
&)event
); 
3144     return wxPanel::ProcessEvent(event
); 
3147 // ----------------------------------------------------------------------- 
3149 // NB: It may really not be wxCommandEvent - must check if necessary 
3151 void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent 
&event 
) 
3153     wxPGProperty
* selected 
= m_selected
; 
3156     // Somehow, event is handled after property has been deselected. 
3157     // Possibly, but very rare. 
3161     if ( m_iFlags 
& wxPG_FL_IN_ONCUSTOMEDITOREVENT 
) 
3164     wxVariant 
pendingValue(selected
->GetValueRef()); 
3165     wxWindow
* wnd 
= GetEditorControl(); 
3167     bool wasUnspecified 
= selected
->IsValueUnspecified(); 
3168     int usesAutoUnspecified 
= selected
->UsesAutoUnspecified(); 
3170     bool valueIsPending 
= false; 
3172     m_chgInfo_changedProperty 
= NULL
; 
3174     m_iFlags 
&= ~(wxPG_FL_VALIDATION_FAILED
|wxPG_FL_VALUE_CHANGE_IN_EVENT
); 
3177     // Filter out excess wxTextCtrl modified events 
3178     if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED 
&& 
3180          wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) ) 
3182         wxTextCtrl
* tc 
= (wxTextCtrl
*) wnd
; 
3184         wxString newTcValue 
= tc
->GetValue(); 
3185         if ( m_prevTcValue 
== newTcValue 
) 
3188         m_prevTcValue 
= newTcValue
; 
3191     SetInternalFlag(wxPG_FL_IN_ONCUSTOMEDITOREVENT
); 
3193     bool validationFailure 
= false; 
3194     bool buttonWasHandled 
= false; 
3197     // Try common button handling 
3198     if ( m_wndEditor2 
&& event
.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED 
) 
3200         wxPGEditorDialogAdapter
* adapter 
= selected
->GetEditorDialog(); 
3204             buttonWasHandled 
= true; 
3205             // Store as res2, as previously (and still currently alternatively) 
3206             // dialogs can be shown by handling wxEVT_COMMAND_BUTTON_CLICKED 
3207             // in wxPGProperty::OnEvent(). 
3208             adapter
->ShowDialog( this, selected 
); 
3213     if ( !buttonWasHandled 
) 
3217             // First call editor class' event handler. 
3218             const wxPGEditor
* editor 
= selected
->GetEditorClass(); 
3220             if ( editor
->OnEvent( this, selected
, wnd
, event 
) ) 
3222                 // If changes, validate them 
3223                 if ( DoEditorValidate() ) 
3225                     if ( editor
->GetValueFromControl( pendingValue
, m_selected
, wnd 
) ) 
3226                         valueIsPending 
= true; 
3230                     validationFailure 
= true; 
3235         // Then the property's custom handler (must be always called, unless 
3236         // validation failed). 
3237         if ( !validationFailure 
) 
3238             buttonWasHandled 
= selected
->OnEvent( this, wnd
, event 
); 
3241     // SetValueInEvent(), as called in one of the functions referred above 
3242     // overrides editor's value. 
3243     if ( m_iFlags 
& wxPG_FL_VALUE_CHANGE_IN_EVENT 
) 
3245         valueIsPending 
= true; 
3246         pendingValue 
= m_changeInEventValue
; 
3247         selFlags 
|= wxPG_SEL_DIALOGVAL
; 
3250     if ( !validationFailure 
&& valueIsPending 
) 
3251         if ( !PerformValidation(m_selected
, pendingValue
) ) 
3252             validationFailure 
= true; 
3254     if ( validationFailure 
) 
3256         OnValidationFailure(selected
, pendingValue
); 
3258     else if ( valueIsPending 
) 
3260         selFlags 
|= ( !wasUnspecified 
&& selected
->IsValueUnspecified() && usesAutoUnspecified 
) ? wxPG_SEL_SETUNSPEC 
: 0; 
3262         DoPropertyChanged(selected
, selFlags
); 
3263         EditorsValueWasNotModified(); 
3267         // No value after all 
3269         // Let unhandled button click events go to the parent 
3270         if ( !buttonWasHandled 
&& event
.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED 
) 
3272             wxCommandEvent 
evt(wxEVT_COMMAND_BUTTON_CLICKED
,GetId()); 
3273             GetEventHandler()->AddPendingEvent(evt
); 
3277     ClearInternalFlag(wxPG_FL_IN_ONCUSTOMEDITOREVENT
); 
3280 // ----------------------------------------------------------------------- 
3281 // wxPropertyGrid editor control helper methods 
3282 // ----------------------------------------------------------------------- 
3284 wxRect 
wxPropertyGrid::GetEditorWidgetRect( wxPGProperty
* p
, int column 
) const 
3286     int itemy 
= p
->GetY2(m_lineHeight
); 
3288     int cust_img_space 
= 0; 
3289     int splitterX 
= m_pState
->DoGetSplitterPosition(column
-1); 
3290     int colEnd 
= splitterX 
+ m_pState
->m_colWidths
[column
]; 
3292     // TODO: If custom image detection changes from current, change this. 
3293     if ( m_iFlags 
& wxPG_FL_CUR_USES_CUSTOM_IMAGE 
/*p->m_flags & wxPG_PROP_CUSTOMIMAGE*/ ) 
3295         //m_iFlags |= wxPG_FL_CUR_USES_CUSTOM_IMAGE; 
3296         int imwid 
= p
->OnMeasureImage().x
; 
3297         if ( imwid 
< 1 ) imwid 
= wxPG_CUSTOM_IMAGE_WIDTH
; 
3298         cust_img_space 
= imwid 
+ wxCC_CUSTOM_IMAGE_MARGIN1 
+ wxCC_CUSTOM_IMAGE_MARGIN2
; 
3303         splitterX
+cust_img_space
+wxPG_XBEFOREWIDGET
+wxPG_CONTROL_MARGIN
+1, 
3305         colEnd
-splitterX
-wxPG_XBEFOREWIDGET
-wxPG_CONTROL_MARGIN
-cust_img_space
-1, 
3310 // ----------------------------------------------------------------------- 
3312 wxRect 
wxPropertyGrid::GetImageRect( wxPGProperty
* p
, int item 
) const 
3314     wxSize sz 
= GetImageSize(p
, item
); 
3315     return wxRect(wxPG_CONTROL_MARGIN 
+ wxCC_CUSTOM_IMAGE_MARGIN1
, 
3316                   wxPG_CUSTOM_IMAGE_SPACINGY
, 
3321 // return size of custom paint image 
3322 wxSize 
wxPropertyGrid::GetImageSize( wxPGProperty
* p
, int item 
) const 
3324     // If called with NULL property, then return default image 
3325     // size for properties that use image. 
3327         return wxSize(wxPG_CUSTOM_IMAGE_WIDTH
,wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
)); 
3329     wxSize cis 
= p
->OnMeasureImage(item
); 
3331     int choiceCount 
= p
->m_choices
.GetCount(); 
3332     int comVals 
= p
->GetDisplayedCommonValueCount(); 
3333     if ( item 
>= choiceCount 
&& comVals 
> 0 ) 
3335         unsigned int cvi 
= item
-choiceCount
; 
3336         cis 
= GetCommonValue(cvi
)->GetRenderer()->GetImageSize(NULL
, 1, cvi
); 
3338     else if ( item 
>= 0 && choiceCount 
== 0 ) 
3339         return wxSize(0, 0); 
3344             cis
.x 
= wxPG_CUSTOM_IMAGE_WIDTH
; 
3349             cis
.y 
= wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
); 
3356 // ----------------------------------------------------------------------- 
3358 // takes scrolling into account 
3359 void wxPropertyGrid::ImprovedClientToScreen( int* px
, int* py 
) 
3362     GetViewStart(&vx
,&vy
); 
3363     vy
*=wxPG_PIXELS_PER_UNIT
; 
3364     vx
*=wxPG_PIXELS_PER_UNIT
; 
3367     ClientToScreen( px
, py 
); 
3370 // ----------------------------------------------------------------------- 
3372 wxPropertyGridHitTestResult 
wxPropertyGrid::HitTest( const wxPoint
& pt 
) const 
3375     GetViewStart(&pt2
.x
,&pt2
.y
); 
3376     pt2
.x 
*= wxPG_PIXELS_PER_UNIT
; 
3377     pt2
.y 
*= wxPG_PIXELS_PER_UNIT
; 
3381     return m_pState
->HitTest(pt2
); 
3384 // ----------------------------------------------------------------------- 
3386 // custom set cursor 
3387 void wxPropertyGrid::CustomSetCursor( int type
, bool override 
) 
3389     if ( type 
== m_curcursor 
&& !override 
) return; 
3391     wxCursor
* cursor 
= &wxPG_DEFAULT_CURSOR
; 
3393     if ( type 
== wxCURSOR_SIZEWE 
) 
3394         cursor 
= m_cursorSizeWE
; 
3396     m_canvas
->SetCursor( *cursor 
); 
3401 // ----------------------------------------------------------------------- 
3402 // wxPropertyGrid property selection 
3403 // ----------------------------------------------------------------------- 
3405 // Setups event handling for child control 
3406 void wxPropertyGrid::SetupChildEventHandling( wxWindow
* argWnd
, int id 
) 
3408     if ( argWnd 
== m_wndEditor 
) 
3410         this->Connect(id
, wxEVT_MOTION
, 
3411             wxMouseEventHandler(wxPropertyGrid::OnMouseMoveChild
)); 
3412         this->Connect(id
, wxEVT_LEFT_UP
, 
3413             wxMouseEventHandler(wxPropertyGrid::OnMouseUpChild
)); 
3414         this->Connect(id
, wxEVT_LEFT_DOWN
, 
3415             wxMouseEventHandler(wxPropertyGrid::OnMouseClickChild
)); 
3416         this->Connect(id
, wxEVT_RIGHT_UP
, 
3417             wxMouseEventHandler(wxPropertyGrid::OnMouseRightClickChild
)); 
3418         this->Connect(id
, wxEVT_ENTER_WINDOW
, 
3419             wxMouseEventHandler(wxPropertyGrid::OnMouseEntry
)); 
3420         this->Connect(id
, wxEVT_LEAVE_WINDOW
, 
3421             wxMouseEventHandler(wxPropertyGrid::OnMouseEntry
)); 
3425         this->Connect(id
, wxEVT_NAVIGATION_KEY
, 
3426             wxNavigationKeyEventHandler(wxPropertyGrid::OnNavigationKey
)); 
3429     this->Connect(id
, wxEVT_KEY_DOWN
, 
3430         wxKeyEventHandler(wxPropertyGrid::OnChildKeyDown
)); 
3431     this->Connect(id
, wxEVT_KEY_UP
, 
3432         wxKeyEventHandler(wxPropertyGrid::OnChildKeyUp
)); 
3433     this->Connect(id
, wxEVT_KILL_FOCUS
, 
3434         wxFocusEventHandler(wxPropertyGrid::OnFocusEvent
)); 
3437 void wxPropertyGrid::FreeEditors() 
3439     // Do not free editors immediately if processing events 
3440     if ( !m_windowsToDelete 
) 
3441         m_windowsToDelete 
= new wxArrayPtrVoid
; 
3445         m_windowsToDelete
->push_back(m_wndEditor2
); 
3446         m_wndEditor2
->Hide(); 
3447         m_wndEditor2 
= (wxWindow
*) NULL
; 
3452         m_windowsToDelete
->push_back(m_wndEditor
); 
3453         m_wndEditor
->Hide(); 
3454         m_wndEditor 
= (wxWindow
*) NULL
; 
3458 // Call with NULL to de-select property 
3459 bool wxPropertyGrid::DoSelectProperty( wxPGProperty
* p
, unsigned int flags 
) 
3461     wxPanel
* canvas 
= GetPanel(); 
3465         wxLogDebug(wxT("SelectProperty( %s (%s[%i]) )"),p->m_label.c_str(), 
3466             p->m_parent->m_label.c_str(),p->GetIndexInParent()); 
3468         wxLogDebug(wxT("SelectProperty( NULL, -1 )")); 
3471     if ( m_inDoSelectProperty 
) 
3474     m_inDoSelectProperty 
= 1; 
3476     wxPGProperty
* prev 
= m_selected
; 
3479     // Delete windows pending for deletion 
3480     if ( m_windowsToDelete 
&& !m_inDoPropertyChanged 
&& m_windowsToDelete
->size() ) 
3484         for ( i
=0; i
<m_windowsToDelete
->size(); i
++ ) 
3485             delete ((wxWindow
*)((*m_windowsToDelete
)[i
])); 
3487         m_windowsToDelete
->clear(); 
3492         m_inDoSelectProperty 
= 0; 
3497     // If we are frozen, then just set the values. 
3500         m_iFlags 
&= ~(wxPG_FL_ABNORMAL_EDITOR
); 
3501         m_editorFocused 
= 0; 
3504         m_pState
->m_selected 
= p
; 
3506         // If frozen, always free controls. But don't worry, as Thaw will 
3507         // recall SelectProperty to recreate them. 
3510         // Prevent any further selection measures in this call 
3511         p 
= (wxPGProperty
*) NULL
; 
3516         if ( m_selected 
== p 
&& !(flags 
& wxPG_SEL_FORCE
) ) 
3518             // Only set focus if not deselecting 
3521                 if ( flags 
& wxPG_SEL_FOCUS 
) 
3525                         m_wndEditor
->SetFocus(); 
3526                         m_editorFocused 
= 1; 
3535             m_inDoSelectProperty 
= 0; 
3540         // First, deactivate previous 
3544             OnValidationFailureReset(m_selected
); 
3546             // Must double-check if this is an selected in case of forceswitch 
3549                 if ( !CommitChangesFromEditor(flags
) ) 
3551                     // Validation has failed, so we can't exit the previous editor 
3552                     //::wxMessageBox(_("Please correct the value or press ESC to cancel the edit."), 
3553                     //               _("Invalid Value"),wxOK|wxICON_ERROR); 
3554                     m_inDoSelectProperty 
= 0; 
3562             m_selected 
= (wxPGProperty
*) NULL
; 
3563             m_pState
->m_selected 
= (wxPGProperty
*) NULL
; 
3565             // We need to always fully refresh the grid here 
3568             m_iFlags 
&= ~(wxPG_FL_ABNORMAL_EDITOR
); 
3569             EditorsValueWasNotModified(); 
3572         SetInternalFlag(wxPG_FL_IN_SELECT_PROPERTY
); 
3575         // Then, activate the one given. 
3578             int propY 
= p
->GetY2(m_lineHeight
); 
3580             int splitterX 
= GetSplitterPosition(); 
3581             m_editorFocused 
= 0; 
3583             m_pState
->m_selected 
= p
; 
3584             m_iFlags 
|= wxPG_FL_PRIMARY_FILLS_ENTIRE
; 
3586                 m_iFlags 
&= ~(wxPG_FL_VALIDATION_FAILED
); 
3588             wxASSERT( m_wndEditor 
== (wxWindow
*) NULL 
); 
3590             // Do we need OnMeasureCalls? 
3591             wxSize imsz 
= p
->OnMeasureImage(); 
3594             // Only create editor for non-disabled non-caption 
3595             if ( !p
->IsCategory() && !(p
->m_flags 
& wxPG_PROP_DISABLED
) ) 
3597             // do this for non-caption items 
3601                 // Do we need to paint the custom image, if any? 
3602                 m_iFlags 
&= ~(wxPG_FL_CUR_USES_CUSTOM_IMAGE
); 
3603                 if ( (p
->m_flags 
& wxPG_PROP_CUSTOMIMAGE
) && 
3604                      !p
->GetEditorClass()->CanContainCustomImage() 
3606                     m_iFlags 
|= wxPG_FL_CUR_USES_CUSTOM_IMAGE
; 
3608                 wxRect grect 
= GetEditorWidgetRect(p
, m_selColumn
); 
3609                 wxPoint goodPos 
= grect
.GetPosition(); 
3610             #if wxPG_CREATE_CONTROLS_HIDDEN 
3611                 int coord_adjust 
= m_height 
- goodPos
.y
; 
3612                 goodPos
.y 
+= coord_adjust
; 
3615                 const wxPGEditor
* editor 
= p
->GetEditorClass(); 
3616                 wxCHECK_MSG(editor
, false, 
3617                     wxT("NULL editor class not allowed")); 
3619                 m_iFlags 
&= ~wxPG_FL_FIXED_WIDTH_EDITOR
; 
3621                 wxPGWindowList wndList 
= editor
->CreateControls(this, 
3626                 m_wndEditor 
= wndList
.m_primary
; 
3627                 m_wndEditor2 
= wndList
.m_secondary
; 
3629                 // NOTE: It is allowed for m_wndEditor to be NULL - in this case 
3630                 //       value is drawn as normal, and m_wndEditor2 is assumed 
3631                 //       to be a right-aligned button that triggers a separate editor 
3636                     wxASSERT_MSG( m_wndEditor
->GetParent() == canvas
, 
3637                                   wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") ); 
3639                     // Set validator, if any 
3640                 #if wxUSE_VALIDATORS 
3641                     wxValidator
* validator 
= p
->GetValidator(); 
3643                         m_wndEditor
->SetValidator(*validator
); 
3646                     if ( m_wndEditor
->GetSize().y 
> (m_lineHeight
+6) ) 
3647                         m_iFlags 
|= wxPG_FL_ABNORMAL_EDITOR
; 
3649                     // If it has modified status, use bold font 
3650                     // (must be done before capturing m_ctrlXAdjust) 
3651                     if ( (p
->m_flags 
& wxPG_PROP_MODIFIED
) && (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
3652                         SetCurControlBoldFont(); 
3655                     // Fix TextCtrl indentation 
3656                 #if defined(__WXMSW__) && !defined(__WXWINCE__) 
3657                     wxTextCtrl
* tc 
= NULL
; 
3658                     if ( m_wndEditor
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) ) 
3659                         tc 
= ((wxOwnerDrawnComboBox
*)m_wndEditor
)->GetTextCtrl(); 
3661                         tc 
= wxDynamicCast(m_wndEditor
, wxTextCtrl
); 
3663                         ::SendMessage(GetHwndOf(tc
), EM_SETMARGINS
, EC_LEFTMARGIN 
| EC_RIGHTMARGIN
, MAKELONG(0, 0)); 
3666                     // Store x relative to splitter (we'll need it). 
3667                     m_ctrlXAdjust 
= m_wndEditor
->GetPosition().x 
- splitterX
; 
3669                     // Check if background clear is not necessary 
3670                     wxPoint pos 
= m_wndEditor
->GetPosition(); 
3671                     if ( pos
.x 
> (splitterX
+1) || pos
.y 
> propY 
) 
3673                         m_iFlags 
&= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE
); 
3676                     m_wndEditor
->SetSizeHints(3, 3); 
3678                 #if wxPG_CREATE_CONTROLS_HIDDEN 
3679                     m_wndEditor
->Show(false); 
3680                     m_wndEditor
->Freeze(); 
3682                     goodPos 
= m_wndEditor
->GetPosition(); 
3683                     goodPos
.y 
-= coord_adjust
; 
3684                     m_wndEditor
->Move( goodPos 
); 
3687                     wxWindow
* primaryCtrl 
= GetEditorControl(); 
3688                     SetupChildEventHandling(primaryCtrl
, wxPG_SUBID1
); 
3690                     // Focus and select all (wxTextCtrl, wxComboBox etc) 
3691                     if ( flags 
& wxPG_SEL_FOCUS 
) 
3693                         primaryCtrl
->SetFocus(); 
3695                         p
->GetEditorClass()->OnFocus(p
, primaryCtrl
); 
3701                     wxASSERT_MSG( m_wndEditor2
->GetParent() == canvas
, 
3702                                   wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") ); 
3704                     // Get proper id for wndSecondary 
3705                     m_wndSecId 
= m_wndEditor2
->GetId(); 
3706                     wxWindowList children 
= m_wndEditor2
->GetChildren(); 
3707                     wxWindowList::iterator node 
= children
.begin(); 
3708                     if ( node 
!= children
.end() ) 
3709                         m_wndSecId 
= ((wxWindow
*)*node
)->GetId(); 
3711                     m_wndEditor2
->SetSizeHints(3,3); 
3713                 #if wxPG_CREATE_CONTROLS_HIDDEN 
3714                     wxRect sec_rect 
= m_wndEditor2
->GetRect(); 
3715                     sec_rect
.y 
-= coord_adjust
; 
3717                     // Fine tuning required to fix "oversized" 
3718                     // button disappearance bug. 
3719                     if ( sec_rect
.y 
< 0 ) 
3721                         sec_rect
.height 
+= sec_rect
.y
; 
3724                     m_wndEditor2
->SetSize( sec_rect 
); 
3726                     m_wndEditor2
->Show(); 
3728                     SetupChildEventHandling(m_wndEditor2
,wxPG_SUBID2
); 
3730                     // If no primary editor, focus to button to allow 
3731                     // it to interprete ENTER etc. 
3732                     // NOTE: Due to problems focusing away from it, this 
3733                     //       has been disabled. 
3735                     if ( (flags & wxPG_SEL_FOCUS) && !m_wndEditor ) 
3736                         m_wndEditor2->SetFocus(); 
3740                 if ( flags 
& wxPG_SEL_FOCUS 
) 
3741                     m_editorFocused 
= 1; 
3746                 // Make sure focus is in grid canvas (important for wxGTK, at least) 
3750             EditorsValueWasNotModified(); 
3752             // If it's inside collapsed section, expand parent, scroll, etc. 
3753             // Also, if it was partially visible, scroll it into view. 
3754             if ( !(flags 
& wxPG_SEL_NONVISIBLE
) ) 
3759             #if wxPG_CREATE_CONTROLS_HIDDEN 
3760                 m_wndEditor
->Thaw(); 
3762                 m_wndEditor
->Show(true); 
3769             // Make sure focus is in grid canvas 
3773         ClearInternalFlag(wxPG_FL_IN_SELECT_PROPERTY
); 
3779     // Show help text in status bar. 
3780     //   (if found and grid not embedded in manager with help box and 
3781     //    style wxPG_EX_HELP_AS_TOOLTIPS is not used). 
3784     if ( !(GetExtraStyle() & wxPG_EX_HELP_AS_TOOLTIPS
) ) 
3786         wxStatusBar
* statusbar 
= (wxStatusBar
*) NULL
; 
3787         if ( !(m_iFlags 
& wxPG_FL_NOSTATUSBARHELP
) ) 
3789             wxFrame
* frame 
= wxDynamicCast(::wxGetTopLevelParent(this),wxFrame
); 
3791                 statusbar 
= frame
->GetStatusBar(); 
3796             const wxString
* pHelpString 
= (const wxString
*) NULL
; 
3800                 pHelpString 
= &p
->GetHelpString(); 
3801                 if ( pHelpString
->length() ) 
3803                     // Set help box text. 
3804                     statusbar
->SetStatusText( *pHelpString 
); 
3805                     m_iFlags 
|= wxPG_FL_STRING_IN_STATUSBAR
; 
3809             if ( (!pHelpString 
|| !pHelpString
->length()) && 
3810                  (m_iFlags 
& wxPG_FL_STRING_IN_STATUSBAR
) ) 
3812                 // Clear help box - but only if it was written 
3813                 // by us at previous time. 
3814                 statusbar
->SetStatusText( m_emptyString 
); 
3815                 m_iFlags 
&= ~(wxPG_FL_STRING_IN_STATUSBAR
); 
3821     m_inDoSelectProperty 
= 0; 
3823     // call wx event handler (here so that it also occurs on deselection) 
3824     SendEvent( wxEVT_PG_SELECTED
, m_selected
, NULL
, flags 
); 
3829 // ----------------------------------------------------------------------- 
3831 bool wxPropertyGrid::UnfocusEditor() 
3833     if ( !m_selected 
|| !m_wndEditor 
|| m_frozen 
) 
3836     if ( !CommitChangesFromEditor(0) ) 
3840     DrawItem(m_selected
); 
3845 // ----------------------------------------------------------------------- 
3847 // This method is not inline because it called dozens of times 
3848 // (i.e. two-arg function calls create smaller code size). 
3849 bool wxPropertyGrid::DoClearSelection() 
3851     return DoSelectProperty((wxPGProperty
*)NULL
); 
3854 // ----------------------------------------------------------------------- 
3855 // wxPropertyGrid expand/collapse state 
3856 // ----------------------------------------------------------------------- 
3858 bool wxPropertyGrid::DoCollapse( wxPGProperty
* p
, bool sendEvents 
) 
3860     wxPGProperty
* pwc 
= wxStaticCast(p
, wxPGProperty
); 
3862     // If active editor was inside collapsed section, then disable it 
3863     if ( m_selected 
&& m_selected
->IsSomeParent (p
) ) 
3865         if ( !ClearSelection() ) 
3869     // Store dont-center-splitter flag 'cause we need to temporarily set it 
3870     wxUint32 old_flag 
= m_iFlags 
& wxPG_FL_DONT_CENTER_SPLITTER
; 
3871     m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
3873     bool res 
= m_pState
->DoCollapse(pwc
); 
3878             SendEvent( wxEVT_PG_ITEM_COLLAPSED
, p 
); 
3880         RecalculateVirtualSize(); 
3882         // Redraw etc. only if collapsed was visible. 
3883         if (pwc
->IsVisible() && 
3885             ( !pwc
->IsCategory() || !(m_windowStyle 
& wxPG_HIDE_CATEGORIES
) ) ) 
3887             // When item is collapsed so that scrollbar would move, 
3888             // graphics mess is about (unless we redraw everything). 
3893     // Clear dont-center-splitter flag if it wasn't set 
3894     m_iFlags 
= (m_iFlags 
& ~wxPG_FL_DONT_CENTER_SPLITTER
) | old_flag
; 
3899 // ----------------------------------------------------------------------- 
3901 bool wxPropertyGrid::DoExpand( wxPGProperty
* p
, bool sendEvents 
) 
3903     wxCHECK_MSG( p
, false, wxT("invalid property id") ); 
3905     wxPGProperty
* pwc 
= (wxPGProperty
*)p
; 
3907     // Store dont-center-splitter flag 'cause we need to temporarily set it 
3908     wxUint32 old_flag 
= m_iFlags 
& wxPG_FL_DONT_CENTER_SPLITTER
; 
3909     m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
3911     bool res 
= m_pState
->DoExpand(pwc
); 
3916             SendEvent( wxEVT_PG_ITEM_EXPANDED
, p 
); 
3918         RecalculateVirtualSize(); 
3920         // Redraw etc. only if expanded was visible. 
3921         if ( pwc
->IsVisible() && !m_frozen 
&& 
3922              ( !pwc
->IsCategory() || !(m_windowStyle 
& wxPG_HIDE_CATEGORIES
) ) 
3926         #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
3929             DrawItems(pwc
, NULL
); 
3934     // Clear dont-center-splitter flag if it wasn't set 
3935     m_iFlags 
= m_iFlags 
& ~(wxPG_FL_DONT_CENTER_SPLITTER
) | old_flag
; 
3940 // ----------------------------------------------------------------------- 
3942 bool wxPropertyGrid::DoHideProperty( wxPGProperty
* p
, bool hide
, int flags 
) 
3945         return m_pState
->DoHideProperty(p
, hide
, flags
); 
3948          ( m_selected 
== p 
|| m_selected
->IsSomeParent(p
) ) 
3951             if ( !ClearSelection() ) 
3955     m_pState
->DoHideProperty(p
, hide
, flags
); 
3957     RecalculateVirtualSize(); 
3964 // ----------------------------------------------------------------------- 
3965 // wxPropertyGrid size related methods 
3966 // ----------------------------------------------------------------------- 
3968 void wxPropertyGrid::RecalculateVirtualSize( int forceXPos 
) 
3970     if ( (m_iFlags 
& wxPG_FL_RECALCULATING_VIRTUAL_SIZE
) || m_frozen 
) 
3974     // If virtual height was changed, then recalculate editor control position(s) 
3975     if ( m_pState
->m_vhCalcPending 
) 
3976         CorrectEditorWidgetPosY(); 
3978     m_pState
->EnsureVirtualHeight(); 
3981     int by1 
= m_pState
->GetVirtualHeight(); 
3982     int by2 
= m_pState
->GetActualVirtualHeight(); 
3985         wxString s 
= wxString::Format(wxT("VirtualHeight=%i, ActualVirtualHeight=%i, should match!"), by1
, by2
); 
3986         wxASSERT_MSG( false, 
3992     m_iFlags 
|= wxPG_FL_RECALCULATING_VIRTUAL_SIZE
; 
3994     int x 
= m_pState
->m_width
; 
3995     int y 
= m_pState
->m_virtualHeight
; 
3998     GetClientSize(&width
,&height
); 
4000     // Now adjust virtual size. 
4001         SetVirtualSize(x
, y
); 
4007     // Adjust scrollbars 
4008     if ( HasVirtualWidth() ) 
4010         xAmount 
= x
/wxPG_PIXELS_PER_UNIT
; 
4011         xPos 
= GetScrollPos( wxHORIZONTAL 
); 
4014     if ( forceXPos 
!= -1 ) 
4017     else if ( xPos 
> (xAmount
-(width
/wxPG_PIXELS_PER_UNIT
)) ) 
4020     int yAmount 
= (y
+wxPG_PIXELS_PER_UNIT
+2)/wxPG_PIXELS_PER_UNIT
; 
4021     int yPos 
= GetScrollPos( wxVERTICAL 
); 
4023     SetScrollbars( wxPG_PIXELS_PER_UNIT
, wxPG_PIXELS_PER_UNIT
, 
4024                    xAmount
, yAmount
, xPos
, yPos
, true ); 
4026     // Must re-get size now 
4027     GetClientSize(&width
,&height
); 
4029     if ( !HasVirtualWidth() ) 
4031         m_pState
->SetVirtualWidth(width
); 
4038     m_canvas
->SetSize( x
, y 
); 
4040     m_pState
->CheckColumnWidths(); 
4043         CorrectEditorWidgetSizeX(); 
4045     m_iFlags 
&= ~wxPG_FL_RECALCULATING_VIRTUAL_SIZE
; 
4048 // ----------------------------------------------------------------------- 
4050 void wxPropertyGrid::OnResize( wxSizeEvent
& event 
) 
4052     if ( !(m_iFlags 
& wxPG_FL_INITIALIZED
) ) 
4056     GetClientSize(&width
,&height
); 
4061 #if wxPG_DOUBLE_BUFFER 
4062     if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING
) ) 
4064         int dblh 
= (m_lineHeight
*2); 
4065         if ( !m_doubleBuffer 
) 
4067             // Create double buffer bitmap to draw on, if none 
4068             int w 
= (width
>250)?width
:250; 
4069             int h 
= height 
+ dblh
; 
4071             m_doubleBuffer 
= new wxBitmap( w
, h 
); 
4075             int w 
= m_doubleBuffer
->GetWidth(); 
4076             int h 
= m_doubleBuffer
->GetHeight(); 
4078             // Double buffer must be large enough 
4079             if ( w 
< width 
|| h 
< (height
+dblh
) ) 
4081                 if ( w 
< width 
) w 
= width
; 
4082                 if ( h 
< (height
+dblh
) ) h 
= height 
+ dblh
; 
4083                 delete m_doubleBuffer
; 
4084                 m_doubleBuffer 
= new wxBitmap( w
, h 
); 
4091     m_pState
->OnClientWidthChange( width
, event
.GetSize().x 
- m_ncWidth
, true ); 
4092     m_ncWidth 
= event
.GetSize().x
; 
4096         if ( m_pState
->m_itemsAdded 
) 
4097             PrepareAfterItemsAdded(); 
4099             // Without this, virtual size (atleast under wxGTK) will be skewed 
4100             RecalculateVirtualSize(); 
4106 // ----------------------------------------------------------------------- 
4108 void wxPropertyGrid::SetVirtualWidth( int width 
) 
4112         // Disable virtual width 
4113         width 
= GetClientSize().x
; 
4114         ClearInternalFlag(wxPG_FL_HAS_VIRTUAL_WIDTH
); 
4118         // Enable virtual width 
4119         SetInternalFlag(wxPG_FL_HAS_VIRTUAL_WIDTH
); 
4121     m_pState
->SetVirtualWidth( width 
); 
4124 void wxPropertyGrid::SetFocusOnCanvas() 
4126     m_canvas
->SetFocusIgnoringChildren(); 
4127     m_editorFocused 
= 0; 
4130 // ----------------------------------------------------------------------- 
4131 // wxPropertyGrid mouse event handling 
4132 // ----------------------------------------------------------------------- 
4134 // selFlags uses same values DoSelectProperty's flags 
4135 // Returns true if event was vetoed. 
4136 bool wxPropertyGrid::SendEvent( int eventType
, wxPGProperty
* p
, wxVariant
* pValue
, unsigned int WXUNUSED(selFlags
) ) 
4138     // Send property grid event of specific type and with specific property 
4139     wxPropertyGridEvent 
evt( eventType
, m_eventObject
->GetId() ); 
4140     evt
.SetPropertyGrid(this); 
4141     evt
.SetEventObject(m_eventObject
); 
4145         evt
.SetCanVeto(true); 
4146         evt
.SetupValidationInfo(); 
4147         m_validationInfo
.m_pValue 
= pValue
; 
4149     wxEvtHandler
* evtHandler 
= m_eventObject
->GetEventHandler(); 
4151     evtHandler
->ProcessEvent(evt
); 
4153     return evt
.WasVetoed(); 
4156 // ----------------------------------------------------------------------- 
4158 // Return false if should be skipped 
4159 bool wxPropertyGrid::HandleMouseClick( int x
, unsigned int y
, wxMouseEvent 
&event 
) 
4163     // Need to set focus? 
4164     if ( !(m_iFlags 
& wxPG_FL_FOCUSED
) ) 
4169     wxPropertyGridPageState
* state 
= m_pState
; 
4171     int splitterHitOffset
; 
4172     int columnHit 
= state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
4174     wxPGProperty
* p 
= DoGetItemAtY(y
); 
4178         int depth 
= (int)p
->GetDepth() - 1; 
4180         int marginEnds 
= m_marginWidth 
+ ( depth 
* m_subgroup_extramargin 
); 
4182         if ( x 
>= marginEnds 
) 
4186             if ( p
->IsCategory() ) 
4188                 // This is category. 
4189                 wxPropertyCategory
* pwc 
= (wxPropertyCategory
*)p
; 
4191                 int textX 
= m_marginWidth 
+ ((unsigned int)((pwc
->m_depth
-1)*m_subgroup_extramargin
)); 
4193                 // Expand, collapse, activate etc. if click on text or left of splitter. 
4196                      ( x 
< (textX
+pwc
->GetTextExtent(this, m_captionFont
)+(wxPG_CAPRECTXMARGIN
*2)) || 
4201                     if ( !DoSelectProperty( p 
) ) 
4204                     // On double-click, expand/collapse. 
4205                     if ( event
.ButtonDClick() && !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
4207                         if ( pwc
->IsExpanded() ) DoCollapse( p
, true ); 
4208                         else DoExpand( p
, true ); 
4212             else if ( splitterHit 
== -1 ) 
4215                 unsigned int selFlag 
= 0; 
4216                 if ( columnHit 
== 1 ) 
4218                     m_iFlags 
|= wxPG_FL_ACTIVATION_BY_CLICK
; 
4219                     selFlag 
= wxPG_SEL_FOCUS
; 
4221                 if ( !DoSelectProperty( p
, selFlag 
) ) 
4224                 m_iFlags 
&= ~(wxPG_FL_ACTIVATION_BY_CLICK
); 
4226                 if ( p
->GetChildCount() && !p
->IsCategory() ) 
4227                     // On double-click, expand/collapse. 
4228                     if ( event
.ButtonDClick() && !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
4230                         wxPGProperty
* pwc 
= (wxPGProperty
*)p
; 
4231                         if ( pwc
->IsExpanded() ) DoCollapse( p
, true ); 
4232                         else DoExpand( p
, true ); 
4239             // click on splitter 
4240                 if ( !(m_windowStyle 
& wxPG_STATIC_SPLITTER
) ) 
4242                     if ( event
.GetEventType() == wxEVT_LEFT_DCLICK 
) 
4244                         // Double-clicking the splitter causes auto-centering 
4245                         CenterSplitter( true ); 
4247                     else if ( m_dragStatus 
== 0 ) 
4250                     // Begin draggin the splitter 
4254                             // Changes must be committed here or the 
4255                             // value won't be drawn correctly 
4256                             if ( !CommitChangesFromEditor() ) 
4259                             m_wndEditor
->Show ( false ); 
4262                         if ( !(m_iFlags 
& wxPG_FL_MOUSE_CAPTURED
) ) 
4264                             m_canvas
->CaptureMouse(); 
4265                             m_iFlags 
|= wxPG_FL_MOUSE_CAPTURED
; 
4269                         m_draggedSplitter 
= splitterHit
; 
4270                         m_dragOffset 
= splitterHitOffset
; 
4272                         wxClientDC 
dc(m_canvas
); 
4274                     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
4275                         // Fixes button disappearance bug 
4277                             m_wndEditor2
->Show ( false ); 
4280                         m_startingSplitterX 
= x 
- splitterHitOffset
; 
4288             if ( p
->GetChildCount() ) 
4290                 int nx 
= x 
+ m_marginWidth 
- marginEnds
; // Normalize x. 
4292                 if ( (nx 
>= m_gutterWidth 
&& nx 
< (m_gutterWidth
+m_iconWidth
)) ) 
4294                     int y2 
= y 
% m_lineHeight
; 
4295                     if ( (y2 
>= m_buttonSpacingY 
&& y2 
< (m_buttonSpacingY
+m_iconHeight
)) ) 
4297                         // On click on expander button, expand/collapse 
4298                         if ( ((wxPGProperty
*)p
)->IsExpanded() ) 
4299                             DoCollapse( p
, true ); 
4301                             DoExpand( p
, true ); 
4310 // ----------------------------------------------------------------------- 
4312 bool wxPropertyGrid::HandleMouseRightClick( int WXUNUSED(x
), unsigned int WXUNUSED(y
), 
4313                                             wxMouseEvent
& WXUNUSED(event
) ) 
4317         // Select property here as well 
4318         wxPGProperty
* p 
= m_propHover
; 
4319         if ( p 
!= m_selected 
) 
4320             DoSelectProperty( p 
); 
4322         // Send right click event. 
4323         SendEvent( wxEVT_PG_RIGHT_CLICK
, p 
); 
4330 // ----------------------------------------------------------------------- 
4332 bool wxPropertyGrid::HandleMouseDoubleClick( int WXUNUSED(x
), unsigned int WXUNUSED(y
), 
4333                                              wxMouseEvent
& WXUNUSED(event
) ) 
4337         // Select property here as well 
4338         wxPGProperty
* p 
= m_propHover
; 
4340         if ( p 
!= m_selected 
) 
4341             DoSelectProperty( p 
); 
4343         // Send double-click event. 
4344         SendEvent( wxEVT_PG_DOUBLE_CLICK
, m_propHover 
); 
4351 // ----------------------------------------------------------------------- 
4353 #if wxPG_SUPPORT_TOOLTIPS 
4355 void wxPropertyGrid::SetToolTip( const wxString
& tipString 
) 
4357     if ( tipString
.length() ) 
4359         m_canvas
->SetToolTip(tipString
); 
4363     #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4364         m_canvas
->SetToolTip( m_emptyString 
); 
4366         m_canvas
->SetToolTip( NULL 
); 
4371 #endif // #if wxPG_SUPPORT_TOOLTIPS 
4373 // ----------------------------------------------------------------------- 
4375 // Return false if should be skipped 
4376 bool wxPropertyGrid::HandleMouseMove( int x
, unsigned int y
, wxMouseEvent 
&event 
) 
4378     // Safety check (needed because mouse capturing may 
4379     // otherwise freeze the control) 
4380     if ( m_dragStatus 
> 0 && !event
.Dragging() ) 
4382         HandleMouseUp(x
,y
,event
); 
4385     wxPropertyGridPageState
* state 
= m_pState
; 
4387     int splitterHitOffset
; 
4388     int columnHit 
= state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
4389     int splitterX 
= x 
- splitterHitOffset
; 
4391     if ( m_dragStatus 
> 0 ) 
4393         if ( x 
> (m_marginWidth 
+ wxPG_DRAG_MARGIN
) && 
4394              x 
< (m_pState
->m_width 
- wxPG_DRAG_MARGIN
) ) 
4397             int newSplitterX 
= x 
- m_dragOffset
; 
4398             int splitterX 
= x 
- splitterHitOffset
; 
4400             // Splitter redraw required? 
4401             if ( newSplitterX 
!= splitterX 
) 
4404                 SetInternalFlag(wxPG_FL_DONT_CENTER_SPLITTER
); 
4405                 state
->DoSetSplitterPosition( newSplitterX
, m_draggedSplitter
, false ); 
4406                 state
->m_fSplitterX 
= (float) newSplitterX
; 
4409                     CorrectEditorWidgetSizeX(); 
4423         int ih 
= m_lineHeight
; 
4426     #if wxPG_SUPPORT_TOOLTIPS 
4427         wxPGProperty
* prevHover 
= m_propHover
; 
4428         unsigned char prevSide 
= m_mouseSide
; 
4430         int curPropHoverY 
= y 
- (y 
% ih
); 
4432         // On which item it hovers 
4433         if ( ( !m_propHover 
) 
4435              ( m_propHover 
&& ( sy 
< m_propHoverY 
|| sy 
>= (m_propHoverY
+ih
) ) ) 
4438             // Mouse moves on another property 
4440             m_propHover 
= DoGetItemAtY(y
); 
4441             m_propHoverY 
= curPropHoverY
; 
4444             SendEvent( wxEVT_PG_HIGHLIGHTED
, m_propHover 
); 
4447     #if wxPG_SUPPORT_TOOLTIPS 
4448         // Store which side we are on 
4450         if ( columnHit 
== 1 ) 
4452         else if ( columnHit 
== 0 ) 
4456         // If tooltips are enabled, show label or value as a tip 
4457         // in case it doesn't otherwise show in full length. 
4459         if ( m_windowStyle 
& wxPG_TOOLTIPS 
) 
4461             wxToolTip
* tooltip 
= m_canvas
->GetToolTip(); 
4463             if ( m_propHover 
!= prevHover 
|| prevSide 
!= m_mouseSide 
) 
4465                 if ( m_propHover 
&& !m_propHover
->IsCategory() ) 
4468                     if ( GetExtraStyle() & wxPG_EX_HELP_AS_TOOLTIPS 
) 
4470                         // Show help string as a tooltip 
4471                         wxString tipString 
= m_propHover
->GetHelpString(); 
4473                         SetToolTip(tipString
); 
4477                         // Show cropped value string as a tooltip 
4481                         if ( m_mouseSide 
== 1 ) 
4483                             tipString 
= m_propHover
->m_label
; 
4484                             space 
= splitterX
-m_marginWidth
-3; 
4486                         else if ( m_mouseSide 
== 2 ) 
4488                             tipString 
= m_propHover
->GetDisplayedString(); 
4490                             space 
= m_width 
- splitterX
; 
4491                             if ( m_propHover
->m_flags 
& wxPG_PROP_CUSTOMIMAGE 
) 
4492                                 space 
-= wxPG_CUSTOM_IMAGE_WIDTH 
+ wxCC_CUSTOM_IMAGE_MARGIN1 
+ wxCC_CUSTOM_IMAGE_MARGIN2
; 
4498                             GetTextExtent( tipString
, &tw
, &th
, 0, 0, &m_font 
); 
4501                                 SetToolTip( tipString 
); 
4508                             #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4509                                 m_canvas
->SetToolTip( m_emptyString 
); 
4511                                 m_canvas
->SetToolTip( NULL 
); 
4522                     #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4523                         m_canvas
->SetToolTip( m_emptyString 
); 
4525                         m_canvas
->SetToolTip( NULL 
); 
4533         if ( splitterHit 
== -1 || 
4535              HasFlag(wxPG_STATIC_SPLITTER
) ) 
4537             // hovering on something else 
4538             if ( m_curcursor 
!= wxCURSOR_ARROW 
) 
4539                 CustomSetCursor( wxCURSOR_ARROW 
); 
4543             // Do not allow splitter cursor on caption items. 
4544             // (also not if we were dragging and its started 
4545             // outside the splitter region) 
4548                  !m_propHover
->IsCategory() && 
4552                 // hovering on splitter 
4554                 // NB: Condition disabled since MouseLeave event (from the editor control) cannot be 
4555                 //     reliably detected. 
4556                 //if ( m_curcursor != wxCURSOR_SIZEWE ) 
4557                 CustomSetCursor( wxCURSOR_SIZEWE
, true ); 
4563                 // hovering on something else 
4564                 if ( m_curcursor 
!= wxCURSOR_ARROW 
) 
4565                     CustomSetCursor( wxCURSOR_ARROW 
); 
4572 // ----------------------------------------------------------------------- 
4574 // Also handles Leaving event 
4575 bool wxPropertyGrid::HandleMouseUp( int x
, unsigned int WXUNUSED(y
), 
4576                                     wxMouseEvent 
&WXUNUSED(event
) ) 
4578     wxPropertyGridPageState
* state 
= m_pState
; 
4582     int splitterHitOffset
; 
4583     state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
4585     // No event type check - basicly calling this method should 
4586     // just stop dragging. 
4587     // Left up after dragged? 
4588     if ( m_dragStatus 
>= 1 ) 
4591     // End Splitter Dragging 
4593         // DO NOT ENABLE FOLLOWING LINE! 
4594         // (it is only here as a reminder to not to do it) 
4597         // Disable splitter auto-centering 
4598         m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
4600         // This is necessary to return cursor 
4601         if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
4603             m_canvas
->ReleaseMouse(); 
4604             m_iFlags 
&= ~(wxPG_FL_MOUSE_CAPTURED
); 
4607         // Set back the default cursor, if necessary 
4608         if ( splitterHit 
== -1 || 
4611             CustomSetCursor( wxCURSOR_ARROW 
); 
4616         // Control background needs to be cleared 
4617         if ( !(m_iFlags 
& wxPG_FL_PRIMARY_FILLS_ENTIRE
) && m_selected 
) 
4618             DrawItem( m_selected 
); 
4622             m_wndEditor
->Show ( true ); 
4625     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
4626         // Fixes button disappearance bug 
4628             m_wndEditor2
->Show ( true ); 
4631         // This clears the focus. 
4632         m_editorFocused 
= 0; 
4638 // ----------------------------------------------------------------------- 
4640 bool wxPropertyGrid::OnMouseCommon( wxMouseEvent
& event
, int* px
, int* py 
) 
4642     int splitterX 
= GetSplitterPosition(); 
4645     //CalcUnscrolledPosition( event.m_x, event.m_y, &ux, &uy ); 
4649     wxWindow
* wnd 
= m_wndEditor
; 
4651     // Hide popup on clicks 
4652     if ( event
.GetEventType() != wxEVT_MOTION 
) 
4653         if ( wnd 
&& wnd
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) ) 
4655             ((wxOwnerDrawnComboBox
*)m_wndEditor
)->HidePopup(); 
4661     if ( wnd 
== (wxWindow
*) NULL 
|| m_dragStatus 
|| 
4663            ux 
<= (splitterX 
+ wxPG_SPLITTERX_DETECTMARGIN2
) || 
4664            ux 
>= (r
.x
+r
.width
) || 
4666            event
.m_y 
>= (r
.y
+r
.height
) 
4676         if ( m_curcursor 
!= wxCURSOR_ARROW 
) CustomSetCursor ( wxCURSOR_ARROW 
); 
4681 // ----------------------------------------------------------------------- 
4683 void wxPropertyGrid::OnMouseClick( wxMouseEvent 
&event 
) 
4686     if ( OnMouseCommon( event
, &x
, &y 
) ) 
4688         HandleMouseClick(x
,y
,event
); 
4693 // ----------------------------------------------------------------------- 
4695 void wxPropertyGrid::OnMouseRightClick( wxMouseEvent 
&event 
) 
4698     CalcUnscrolledPosition( event
.m_x
, event
.m_y
, &x
, &y 
); 
4699     HandleMouseRightClick(x
,y
,event
); 
4703 // ----------------------------------------------------------------------- 
4705 void wxPropertyGrid::OnMouseDoubleClick( wxMouseEvent 
&event 
) 
4707     // Always run standard mouse-down handler as well 
4708     OnMouseClick(event
); 
4711     CalcUnscrolledPosition( event
.m_x
, event
.m_y
, &x
, &y 
); 
4712     HandleMouseDoubleClick(x
,y
,event
); 
4716 // ----------------------------------------------------------------------- 
4718 void wxPropertyGrid::OnMouseMove( wxMouseEvent 
&event 
) 
4721     if ( OnMouseCommon( event
, &x
, &y 
) ) 
4723         HandleMouseMove(x
,y
,event
); 
4728 // ----------------------------------------------------------------------- 
4730 void wxPropertyGrid::OnMouseMoveBottom( wxMouseEvent
& WXUNUSED(event
) ) 
4732     // Called when mouse moves in the empty space below the properties. 
4733     CustomSetCursor( wxCURSOR_ARROW 
); 
4736 // ----------------------------------------------------------------------- 
4738 void wxPropertyGrid::OnMouseUp( wxMouseEvent 
&event 
) 
4741     if ( OnMouseCommon( event
, &x
, &y 
) ) 
4743         HandleMouseUp(x
,y
,event
); 
4748 // ----------------------------------------------------------------------- 
4750 void wxPropertyGrid::OnMouseEntry( wxMouseEvent 
&event 
) 
4752     // This may get called from child control as well, so event's 
4753     // mouse position cannot be relied on. 
4755     if ( event
.Entering() ) 
4757         if ( !(m_iFlags 
& wxPG_FL_MOUSE_INSIDE
) ) 
4759             // TODO: Fix this (detect parent and only do 
4760             //   cursor trick if it is a manager). 
4761             wxASSERT( GetParent() ); 
4762             GetParent()->SetCursor(wxNullCursor
); 
4764             m_iFlags 
|= wxPG_FL_MOUSE_INSIDE
; 
4767             GetParent()->SetCursor(wxNullCursor
); 
4769     else if ( event
.Leaving() ) 
4771         // Without this, wxSpinCtrl editor will sometimes have wrong cursor 
4772         m_canvas
->SetCursor( wxNullCursor 
); 
4774         // Get real cursor position 
4775         wxPoint pt 
= ScreenToClient(::wxGetMousePosition()); 
4777         if ( ( pt
.x 
<= 0 || pt
.y 
<= 0 || pt
.x 
>= m_width 
|| pt
.y 
>= m_height 
) ) 
4780                 if ( (m_iFlags 
& wxPG_FL_MOUSE_INSIDE
) ) 
4782                     m_iFlags 
&= ~(wxPG_FL_MOUSE_INSIDE
); 
4786                     wxPropertyGrid::HandleMouseUp ( -1, 10000, event 
); 
4794 // ----------------------------------------------------------------------- 
4796 // Common code used by various OnMouseXXXChild methods. 
4797 bool wxPropertyGrid::OnMouseChildCommon( wxMouseEvent 
&event
, int* px
, int *py 
) 
4799     wxWindow
* topCtrlWnd 
= (wxWindow
*)event
.GetEventObject(); 
4800     wxASSERT( topCtrlWnd 
); 
4802     event
.GetPosition(&x
,&y
); 
4804     AdjustPosForClipperWindow( topCtrlWnd
, &x
, &y 
); 
4806     int splitterX 
= GetSplitterPosition(); 
4808     wxRect r 
= topCtrlWnd
->GetRect(); 
4809     if ( !m_dragStatus 
&& 
4810          x 
> (splitterX
-r
.x
+wxPG_SPLITTERX_DETECTMARGIN2
) && 
4811          y 
>= 0 && y 
< r
.height \
 
4814         if ( m_curcursor 
!= wxCURSOR_ARROW 
) CustomSetCursor ( wxCURSOR_ARROW 
); 
4819         CalcUnscrolledPosition( event
.m_x 
+ r
.x
, event
.m_y 
+ r
.y
, \
 
4826 void wxPropertyGrid::OnMouseClickChild( wxMouseEvent 
&event 
) 
4829     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
4831         bool res 
= HandleMouseClick(x
,y
,event
); 
4832         if ( !res 
) event
.Skip(); 
4836 void wxPropertyGrid::OnMouseRightClickChild( wxMouseEvent 
&event 
) 
4839     wxASSERT( m_wndEditor 
); 
4840     // These coords may not be exact (about +-2), 
4841     // but that should not matter (right click is about item, not position). 
4842     wxPoint pt 
= m_wndEditor
->GetPosition(); 
4843     CalcUnscrolledPosition( event
.m_x 
+ pt
.x
, event
.m_y 
+ pt
.y
, &x
, &y 
); 
4844     wxASSERT( m_selected 
); 
4845     m_propHover 
= m_selected
; 
4846     bool res 
= HandleMouseRightClick(x
,y
,event
); 
4847     if ( !res 
) event
.Skip(); 
4850 void wxPropertyGrid::OnMouseMoveChild( wxMouseEvent 
&event 
) 
4853     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
4855         bool res 
= HandleMouseMove(x
,y
,event
); 
4856         if ( !res 
) event
.Skip(); 
4860 void wxPropertyGrid::OnMouseUpChild( wxMouseEvent 
&event 
) 
4863     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
4865         bool res 
= HandleMouseUp(x
,y
,event
); 
4866         if ( !res 
) event
.Skip(); 
4870 // ----------------------------------------------------------------------- 
4871 // wxPropertyGrid keyboard event handling 
4872 // ----------------------------------------------------------------------- 
4874 void wxPropertyGrid::SendNavigationKeyEvent( int dir 
) 
4876     wxNavigationKeyEvent evt
; 
4877     evt
.SetFlags(wxNavigationKeyEvent::FromTab
| 
4878                  (dir
?wxNavigationKeyEvent::IsForward
: 
4879                       wxNavigationKeyEvent::IsBackward
)); 
4880     evt
.SetEventObject(this); 
4881     m_canvas
->GetEventHandler()->AddPendingEvent(evt
); 
4885 int wxPropertyGrid::KeyEventToActions(wxKeyEvent 
&event
, int* pSecond
) const 
4887     // Translates wxKeyEvent to wxPG_ACTION_XXX 
4889     int keycode 
= event
.GetKeyCode(); 
4890     int modifiers 
= event
.GetModifiers(); 
4892     wxASSERT( !(modifiers
&~(0xFFFF)) ); 
4894     int hashMapKey 
= (keycode 
& 0xFFFF) | ((modifiers 
& 0xFFFF) << 16); 
4896     wxPGHashMapI2I::const_iterator it 
= m_actionTriggers
.find(hashMapKey
); 
4898     if ( it 
== m_actionTriggers
.end() ) 
4903         int second 
= (it
->second
>>16) & 0xFFFF; 
4907     return (it
->second 
& 0xFFFF); 
4910 void wxPropertyGrid::AddActionTrigger( int action
, int keycode
, int modifiers 
) 
4912     wxASSERT( !(modifiers
&~(0xFFFF)) ); 
4914     int hashMapKey 
= (keycode 
& 0xFFFF) | ((modifiers 
& 0xFFFF) << 16); 
4916     wxPGHashMapI2I::iterator it 
= m_actionTriggers
.find(hashMapKey
); 
4918     if ( it 
!= m_actionTriggers
.end() ) 
4920         // This key combination is already used 
4922         // Can add secondary? 
4923         wxASSERT_MSG( !(it
->second
&~(0xFFFF)), 
4924                       wxT("You can only add up to two separate actions per key combination.") ); 
4926         action 
= it
->second 
| (action
<<16); 
4929     m_actionTriggers
[hashMapKey
] = action
; 
4932 void wxPropertyGrid::ClearActionTriggers( int action 
) 
4934     wxPGHashMapI2I::iterator it
; 
4936     for ( it 
= m_actionTriggers
.begin(); it 
!= m_actionTriggers
.end(); it
++ ) 
4938         if ( it
->second 
== action 
) 
4940             m_actionTriggers
.erase(it
); 
4945 static void CopyTextToClipboard( const wxString
& text 
) 
4947     if ( wxTheClipboard
->Open() ) 
4949         // This data objects are held by the clipboard,  
4950         // so do not delete them in the app. 
4951         wxTheClipboard
->SetData( new wxTextDataObject(text
) ); 
4952         wxTheClipboard
->Close(); 
4956 void wxPropertyGrid::HandleKeyEvent(wxKeyEvent 
&event
) 
4959     // Handles key event when editor control is not focused. 
4962     wxASSERT( !m_frozen 
); 
4966     // Travelsal between items, collapsing/expanding, etc. 
4967     int keycode 
= event
.GetKeyCode(); 
4969     if ( keycode 
== WXK_TAB 
) 
4971         SendNavigationKeyEvent( event
.ShiftDown()?0:1 ); 
4975     // Ignore Alt and Control when they are down alone 
4976     if ( keycode 
== WXK_ALT 
|| 
4977          keycode 
== WXK_CONTROL 
) 
4984     int action 
= KeyEventToActions(event
, &secondAction
); 
4990         if ( ButtonTriggerKeyTest(event
) ) 
4993         wxPGProperty
* p 
= m_selected
; 
4995         if ( action 
== wxPG_ACTION_COPY 
) 
4997             CopyTextToClipboard(p
->GetDisplayedString()); 
5001             // Travel and expand/collapse 
5004             if ( p
->GetChildCount() && 
5005                  !(p
->m_flags 
& wxPG_PROP_DISABLED
) 
5008                 if ( action 
== wxPG_ACTION_COLLAPSE_PROPERTY 
|| secondAction 
== wxPG_ACTION_COLLAPSE_PROPERTY 
) 
5010                     if ( (m_windowStyle 
& wxPG_HIDE_MARGIN
) || Collapse(p
) ) 
5013                 else if ( action 
== wxPG_ACTION_EXPAND_PROPERTY 
|| secondAction 
== wxPG_ACTION_EXPAND_PROPERTY 
) 
5015                     if ( (m_windowStyle 
& wxPG_HIDE_MARGIN
) || Expand(p
) ) 
5022                 if ( action 
== wxPG_ACTION_PREV_PROPERTY 
|| secondAction 
== wxPG_ACTION_PREV_PROPERTY 
) 
5026                 else if ( action 
== wxPG_ACTION_NEXT_PROPERTY 
|| secondAction 
== wxPG_ACTION_NEXT_PROPERTY 
) 
5037             if ( selectDir 
>= -1 ) 
5039                 p 
= wxPropertyGridIterator::OneStep( m_pState
, wxPG_ITERATE_VISIBLE
, p
, selectDir 
); 
5041                     DoSelectProperty(p
); 
5047         // If nothing was selected, select the first item now 
5048         // (or navigate out of tab). 
5049         if ( action 
!= wxPG_ACTION_CANCEL_EDIT 
&& secondAction 
!= wxPG_ACTION_CANCEL_EDIT 
) 
5051             wxPGProperty
* p 
= wxPropertyGridInterface::GetFirst(); 
5052             if ( p 
) DoSelectProperty(p
); 
5057 // ----------------------------------------------------------------------- 
5059 // Potentially handles a keyboard event for editor controls. 
5060 // Returns false if event should *not* be skipped (on true it can 
5061 // be optionally skipped). 
5062 // Basicly, false means that SelectProperty was called (or was about 
5063 // to be called, if canDestroy was false). 
5064 bool wxPropertyGrid::HandleChildKey( wxKeyEvent
& event 
) 
5068     if ( !m_selected 
|| !m_wndEditor 
) 
5073     int action 
= KeyEventToAction(event
); 
5076     if ( action 
== wxPG_ACTION_CANCEL_EDIT 
) 
5079         // Esc cancels any changes 
5080         if ( IsEditorsValueModified() ) 
5082             EditorsValueWasNotModified(); 
5084             // Update the control as well 
5085             m_selected
->GetEditorClass()->SetControlStringValue( m_selected
, 
5087                                                                  m_selected
->GetDisplayedString() ); 
5090         OnValidationFailureReset(m_selected
); 
5096     else if ( action 
== wxPG_ACTION_COPY 
) 
5098         // NB: There is some problem with getting native cut-copy-paste keys to go through 
5099         //     for embedded editor wxTextCtrl. This is why we emulate. 
5101         wxTextCtrl
* tc 
= GetEditorTextCtrl(); 
5104             wxString sel 
= tc
->GetStringSelection(); 
5106                 CopyTextToClipboard(sel
); 
5110             CopyTextToClipboard(m_selected
->GetDisplayedString()); 
5113     else if ( action 
== wxPG_ACTION_CUT 
) 
5115         wxTextCtrl
* tc 
= GetEditorTextCtrl(); 
5119             tc
->GetSelection(&from
, &to
); 
5122                 CopyTextToClipboard(tc
->GetStringSelection()); 
5123                 tc
->Remove(from
, to
); 
5127     else if ( action 
== wxPG_ACTION_PASTE 
) 
5129         wxTextCtrl
* tc 
= GetEditorTextCtrl(); 
5132             if (wxTheClipboard
->Open()) 
5134                 if (wxTheClipboard
->IsSupported( wxDF_TEXT 
)) 
5136                     wxTextDataObject data
; 
5137                     wxTheClipboard
->GetData( data 
); 
5139                     tc
->GetSelection(&from
, &to
); 
5142                         tc
->Remove(from
, to
); 
5143                         tc
->WriteText(data
.GetText()); 
5147                         tc
->WriteText(data
.GetText()); 
5150                 wxTheClipboard
->Close(); 
5158 // ----------------------------------------------------------------------- 
5160 void wxPropertyGrid::OnKey( wxKeyEvent 
&event 
) 
5164     // Events to editor controls should get relayed here. 
5166     wxWindow
* focused 
= wxWindow::FindFocus(); 
5168     wxWindow
* primaryCtrl 
= GetEditorControl(); 
5171          (focused
==primaryCtrl
 
5172           || m_editorFocused
) ) 
5174         // Child key must be processed here, since it can 
5175         // destroy the control which is referred by its own 
5177         HandleChildKey( event 
); 
5180         HandleKeyEvent( event 
); 
5183 // ----------------------------------------------------------------------- 
5185 void wxPropertyGrid::OnKeyUp(wxKeyEvent 
&event
) 
5187     m_keyComboConsumed 
= 0; 
5192 // ----------------------------------------------------------------------- 
5194 void wxPropertyGrid::OnNavigationKey( wxNavigationKeyEvent
& event 
) 
5196     // Ignore events that occur very close to focus set 
5197     if ( m_iFlags 
& wxPG_FL_IGNORE_NEXT_NAVKEY 
) 
5199         m_iFlags 
&= ~(wxPG_FL_IGNORE_NEXT_NAVKEY
); 
5204     wxPGProperty
* next 
= (wxPGProperty
*) NULL
; 
5206     int dir 
= event
.GetDirection()?1:-1; 
5210         if ( dir 
== 1 && (m_wndEditor 
|| m_wndEditor2
) ) 
5212             wxWindow
* focused 
= wxWindow::FindFocus(); 
5214             wxWindow
* wndToCheck 
= GetEditorControl(); 
5216             // ODComboBox focus goes to its text ctrl, so we need to use it instead 
5217             if ( wndToCheck 
&& wndToCheck
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) ) 
5219                 wxTextCtrl
* comboTextCtrl 
= ((wxOwnerDrawnComboBox
*)wndToCheck
)->GetTextCtrl(); 
5220                 if ( comboTextCtrl 
) 
5221                     wndToCheck 
= comboTextCtrl
; 
5225             // Because of problems navigating from wxButton, do not go to it. 
5228                 // No primary, use secondary 
5229                 wndToCheck = m_wndEditor2; 
5231             // If it has editor button, focus to it after the primary editor. 
5232             // NB: Doesn't work since wxButton on wxMSW doesn't seem to propagate 
5233             //     key events (yes, I'm using wxWANTS_CHARS with it, and yes I 
5234             //     have somewhat debugged in window.cpp itself). 
5235             else if ( focused == wndToCheck && 
5237                       !(GetExtraStyle() & wxPG_EX_NO_TAB_TO_BUTTON) ) 
5239                 wndToCheck = m_wndEditor2; 
5240                 wxLogDebug(wxT("Exp1")); 
5244             if ( focused 
!= wndToCheck 
&& 
5247                 wndToCheck
->SetFocus(); 
5249                 // Select all text in wxTextCtrl etc. 
5250                 if ( m_wndEditor 
&& wndToCheck 
== m_wndEditor 
) 
5251                     m_selected
->GetEditorClass()->OnFocus(m_selected
,wndToCheck
); 
5253                 m_editorFocused 
= 1; 
5260             next 
= wxPropertyGridIterator::OneStep(m_pState
, wxPG_ITERATE_VISIBLE
, m_selected
, dir
); 
5264                 // This allows preventing NavigateOut to occur 
5265                 DoSelectProperty( next
, wxPG_SEL_FOCUS 
); 
5274 // ----------------------------------------------------------------------- 
5276 bool wxPropertyGrid::ButtonTriggerKeyTest( wxKeyEvent 
&event 
) 
5278     int keycode 
= event
.GetKeyCode(); 
5280     // Does the keycode trigger button? 
5281     if ( keycode 
== m_pushButKeyCode 
&& 
5283          (!m_pushButKeyCodeNeedsAlt 
|| event
.AltDown()) && 
5284          (!m_pushButKeyCodeNeedsCtrl 
|| event
.ControlDown()) ) 
5286         m_keyComboConsumed 
= 1; 
5288         wxCommandEvent 
evt(wxEVT_COMMAND_BUTTON_CLICKED
,m_wndEditor2
->GetId()); 
5289         GetEventHandler()->AddPendingEvent(evt
); 
5296 // ----------------------------------------------------------------------- 
5298 void wxPropertyGrid::OnChildKeyDown( wxKeyEvent 
&event 
) 
5300     int keycode 
= event
.GetKeyCode(); 
5302     // Ignore Alt and Control when they are down alone 
5303     if ( keycode 
== WXK_ALT 
|| 
5304          keycode 
== WXK_CONTROL 
) 
5310     if ( ButtonTriggerKeyTest(event
) ) 
5313     if ( HandleChildKey(event
) == true ) 
5316     GetEventHandler()->AddPendingEvent(event
); 
5319 void wxPropertyGrid::OnChildKeyUp( wxKeyEvent 
&event 
) 
5321     m_keyComboConsumed 
= 0; 
5323     GetEventHandler()->AddPendingEvent(event
); 
5328 // ----------------------------------------------------------------------- 
5329 // wxPropertyGrid miscellaneous event handling 
5330 // ----------------------------------------------------------------------- 
5332 void wxPropertyGrid::OnIdle( wxIdleEvent
& WXUNUSED(event
) ) 
5335     // Check if the focus is in this control or one of its children 
5336     wxWindow
* newFocused 
= wxWindow::FindFocus(); 
5338     if ( newFocused 
!= m_curFocused 
) 
5339         HandleFocusChange( newFocused 
); 
5342 // Called by focus event handlers. newFocused is the window that becomes focused. 
5343 void wxPropertyGrid::HandleFocusChange( wxWindow
* newFocused 
) 
5345     unsigned int oldFlags 
= m_iFlags
; 
5347     m_iFlags 
&= ~(wxPG_FL_FOCUSED
); 
5349     wxWindow
* parent 
= newFocused
; 
5351     // This must be one of nextFocus' parents. 
5354         // Use m_eventObject, which is either wxPropertyGrid or 
5355         // wxPropertyGridManager, as appropriate. 
5356         if ( parent 
== m_eventObject 
) 
5358             m_iFlags 
|= wxPG_FL_FOCUSED
; 
5361         parent 
= parent
->GetParent(); 
5364     m_curFocused 
= newFocused
; 
5366     if ( (m_iFlags 
& wxPG_FL_FOCUSED
) != 
5367          (oldFlags 
& wxPG_FL_FOCUSED
) ) 
5369         // On each focus kill, mark the next nav key event 
5370         // to be ignored (can't do on set focus since the 
5371         // event would occur before it). 
5372         if ( !(m_iFlags 
& wxPG_FL_FOCUSED
) ) 
5374             m_iFlags 
|= wxPG_FL_IGNORE_NEXT_NAVKEY
; 
5376             // Need to store changed value 
5377             CommitChangesFromEditor(); 
5383             // Preliminary code for tab-order respecting 
5384             // tab-traversal (but should be moved to 
5387             wxWindow* prevFocus = event.GetWindow(); 
5388             wxWindow* useThis = this; 
5389             if ( m_iFlags & wxPG_FL_IN_MANAGER ) 
5390                 useThis = GetParent(); 
5393                  prevFocus->GetParent() == useThis->GetParent() ) 
5395                 wxList& children = useThis->GetParent()->GetChildren(); 
5397                 wxNode* node = children.Find(prevFocus); 
5399                 if ( node->GetNext() && 
5400                      useThis == node->GetNext()->GetData() ) 
5401                     DoSelectProperty(GetFirst()); 
5402                 else if ( node->GetPrevious () && 
5403                           useThis == node->GetPrevious()->GetData() ) 
5404                     DoSelectProperty(GetLastProperty()); 
5409             m_iFlags 
&= ~(wxPG_FL_IGNORE_NEXT_NAVKEY
); 
5413         if ( m_selected 
&& (m_iFlags 
& wxPG_FL_INITIALIZED
) ) 
5414             DrawItem( m_selected 
); 
5418 void wxPropertyGrid::OnFocusEvent( wxFocusEvent
& event 
) 
5420     if ( event
.GetEventType() == wxEVT_SET_FOCUS 
) 
5421         HandleFocusChange((wxWindow
*)event
.GetEventObject()); 
5422     // Line changed to "else" when applying wxPropertyGrid patch #1675902 
5423     //else if ( event.GetWindow() ) 
5425         HandleFocusChange(event
.GetWindow()); 
5430 // ----------------------------------------------------------------------- 
5432 void wxPropertyGrid::OnChildFocusEvent( wxChildFocusEvent
& event 
) 
5434     HandleFocusChange((wxWindow
*)event
.GetEventObject()); 
5437     // event.Skip() being commented out is aworkaround for bug reported 
5438     // in ticket #4840 (wxScrolledWindow problem with automatic scrolling). 
5442 // ----------------------------------------------------------------------- 
5444 void wxPropertyGrid::OnScrollEvent( wxScrollWinEvent 
&event 
) 
5446     m_iFlags 
|= wxPG_FL_SCROLLED
; 
5451 // ----------------------------------------------------------------------- 
5453 void wxPropertyGrid::OnCaptureChange( wxMouseCaptureChangedEvent
& WXUNUSED(event
) ) 
5455     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
5457         m_iFlags 
&= ~(wxPG_FL_MOUSE_CAPTURED
); 
5461 // ----------------------------------------------------------------------- 
5462 // Property editor related functions 
5463 // ----------------------------------------------------------------------- 
5465 // noDefCheck = true prevents infinite recursion. 
5466 wxPGEditor
* wxPropertyGrid::RegisterEditorClass( wxPGEditor
* editorClass
, 
5469     wxASSERT( editorClass 
); 
5471     if ( !noDefCheck 
&& wxPGGlobalVars
->m_mapEditorClasses
.empty() ) 
5472         RegisterDefaultEditors(); 
5474     wxString name 
= editorClass
->GetName(); 
5476     // Existing editor under this name? 
5477     wxPGHashMapS2P::iterator vt_it 
= wxPGGlobalVars
->m_mapEditorClasses
.find(name
); 
5479     wxCHECK_MSG( vt_it 
== wxPGGlobalVars
->m_mapEditorClasses
.end(), 
5480                  (wxPGEditor
*) vt_it
->second
, 
5481                  "Editor with given name was already registered" ); 
5483     wxPGGlobalVars
->m_mapEditorClasses
[name
] = (void*)editorClass
; 
5488 // Registers all default editor classes 
5489 void wxPropertyGrid::RegisterDefaultEditors() 
5491     wxPGRegisterDefaultEditorClass( TextCtrl 
); 
5492     wxPGRegisterDefaultEditorClass( Choice 
); 
5493     wxPGRegisterDefaultEditorClass( ComboBox 
); 
5494     wxPGRegisterDefaultEditorClass( TextCtrlAndButton 
); 
5495 #if wxPG_INCLUDE_CHECKBOX 
5496     wxPGRegisterDefaultEditorClass( CheckBox 
); 
5498     wxPGRegisterDefaultEditorClass( ChoiceAndButton 
); 
5500     // Register SpinCtrl etc. editors before use 
5501     RegisterAdditionalEditors(); 
5504 // ----------------------------------------------------------------------- 
5505 // wxPGStringTokenizer 
5506 //   Needed to handle C-style string lists (e.g. "str1" "str2") 
5507 // ----------------------------------------------------------------------- 
5509 wxPGStringTokenizer::wxPGStringTokenizer( const wxString
& str
, wxChar delimeter 
) 
5510     : m_str(&str
), m_curPos(str
.begin()), m_delimeter(delimeter
) 
5514 wxPGStringTokenizer::~wxPGStringTokenizer() 
5518 bool wxPGStringTokenizer::HasMoreTokens() 
5520     const wxString
& str 
= *m_str
; 
5522     wxString::const_iterator i 
= m_curPos
; 
5524     wxUniChar delim 
= m_delimeter
; 
5526     wxUniChar prev_a 
= wxT('\0'); 
5528     bool inToken 
= false; 
5530     while ( i 
!= str
.end() ) 
5539                 m_readyToken
.clear(); 
5544             if ( prev_a 
!= wxT('\\') ) 
5548                     if ( a 
!= wxT('\\') ) 
5568     m_curPos 
= str
.end(); 
5576 wxString 
wxPGStringTokenizer::GetNextToken() 
5578     return m_readyToken
; 
5581 // ----------------------------------------------------------------------- 
5583 // ----------------------------------------------------------------------- 
5585 wxPGChoiceEntry::wxPGChoiceEntry() 
5586     : wxPGCell(), m_value(wxPG_INVALID_VALUE
) 
5590 wxPGChoiceEntry::wxPGChoiceEntry( const wxPGChoiceEntry
& entry 
) 
5591     : wxPGCell( entry
.GetText(), entry
.GetBitmap(), 
5592         entry
.GetFgCol(), entry
.GetBgCol() ), m_value(entry
.GetValue()) 
5596 // ----------------------------------------------------------------------- 
5598 // ----------------------------------------------------------------------- 
5600 wxPGChoicesData::wxPGChoicesData() 
5605 wxPGChoicesData::~wxPGChoicesData() 
5610 void wxPGChoicesData::Clear() 
5614     for ( i
=0; i
<m_items
.size(); i
++ ) 
5626 void wxPGChoicesData::CopyDataFrom( wxPGChoicesData
* data 
) 
5628     wxASSERT( m_items
.size() == 0 ); 
5632     for ( i
=0; i
<data
->GetCount(); i
++ ) 
5633         m_items
.push_back( new wxPGChoiceEntry(*data
->Item(i
)) ); 
5636 // ----------------------------------------------------------------------- 
5638 // ----------------------------------------------------------------------- 
5640 wxPGChoiceEntry
& wxPGChoices::Add( const wxString
& label
, int value 
) 
5644     wxPGChoiceEntry
* p 
= new wxPGChoiceEntry(label
, value
); 
5645     m_data
->Insert( -1, p 
); 
5649 // ----------------------------------------------------------------------- 
5651 wxPGChoiceEntry
& wxPGChoices::Add( const wxString
& label
, const wxBitmap
& bitmap
, int value 
) 
5655     wxPGChoiceEntry
* p 
= new wxPGChoiceEntry(label
, value
); 
5656     p
->SetBitmap(bitmap
); 
5657     m_data
->Insert( -1, p 
); 
5661 // ----------------------------------------------------------------------- 
5663 wxPGChoiceEntry
& wxPGChoices::Insert( const wxPGChoiceEntry
& entry
, int index 
) 
5667     wxPGChoiceEntry
* p 
= new wxPGChoiceEntry(entry
); 
5668     m_data
->Insert(index
, p
); 
5672 // ----------------------------------------------------------------------- 
5674 wxPGChoiceEntry
& wxPGChoices::Insert( const wxString
& label
, int index
, int value 
) 
5678     wxPGChoiceEntry
* p 
= new wxPGChoiceEntry(label
, value
); 
5679     m_data
->Insert( index
, p 
); 
5683 // ----------------------------------------------------------------------- 
5685 wxPGChoiceEntry
& wxPGChoices::AddAsSorted( const wxString
& label
, int value 
) 
5691     while ( index 
< GetCount() ) 
5693         int cmpRes 
= GetLabel(index
).Cmp(label
); 
5699     wxPGChoiceEntry
* p 
= new wxPGChoiceEntry(label
, value
); 
5700     m_data
->Insert( index
, p 
); 
5704 // ----------------------------------------------------------------------- 
5706 void wxPGChoices::Add( const wxChar
** labels
, const ValArrItem
* values 
) 
5710     unsigned int itemcount 
= 0; 
5711     const wxChar
** p 
= &labels
[0]; 
5712     while ( *p 
) { p
++; itemcount
++; } 
5715     for ( i 
= 0; i 
< itemcount
; i
++ ) 
5717         int value 
= wxPG_INVALID_VALUE
; 
5720         m_data
->Insert( -1, new wxPGChoiceEntry(labels
[i
], value
) ); 
5724 // ----------------------------------------------------------------------- 
5726 void wxPGChoices::Add( const wxArrayString
& arr
, const ValArrItem
* values 
) 
5731     unsigned int itemcount 
= arr
.size(); 
5733     for ( i 
= 0; i 
< itemcount
; i
++ ) 
5735         int value 
= wxPG_INVALID_VALUE
; 
5738         m_data
->Insert( -1, new wxPGChoiceEntry(arr
[i
], value
) ); 
5742 // ----------------------------------------------------------------------- 
5744 void wxPGChoices::Add( const wxArrayString
& arr
, const wxArrayInt
& arrint 
) 
5749     unsigned int itemcount 
= arr
.size(); 
5751     for ( i 
= 0; i 
< itemcount
; i
++ ) 
5753         int value 
= wxPG_INVALID_VALUE
; 
5754         if ( &arrint 
&& arrint
.size() ) 
5756         m_data
->Insert( -1, new wxPGChoiceEntry(arr
[i
], value
) ); 
5760 // ----------------------------------------------------------------------- 
5762 void wxPGChoices::RemoveAt(size_t nIndex
, size_t count
) 
5764     wxASSERT( m_data
->m_refCount 
!= 0xFFFFFFF ); 
5766     for ( i
=nIndex
; i
<(nIndex
+count
); i
++) 
5767         delete m_data
->Item(i
); 
5768     m_data
->m_items
.RemoveAt(nIndex
, count
); 
5771 // ----------------------------------------------------------------------- 
5773 int wxPGChoices::Index( const wxString
& str 
) const 
5778         for ( i
=0; i
< m_data
->GetCount(); i
++ ) 
5780             if ( m_data
->Item(i
)->GetText() == str 
) 
5787 // ----------------------------------------------------------------------- 
5789 int wxPGChoices::Index( int val 
) const 
5794         for ( i
=0; i
< m_data
->GetCount(); i
++ ) 
5796             if ( m_data
->Item(i
)->GetValue() == val 
) 
5803 // ----------------------------------------------------------------------- 
5805 wxArrayString 
wxPGChoices::GetLabels() const 
5810     if ( this && IsOk() ) 
5811         for ( i
=0; i
<GetCount(); i
++ ) 
5812             arr
.push_back(GetLabel(i
)); 
5817 // ----------------------------------------------------------------------- 
5819 bool wxPGChoices::HasValues() const 
5824 // ----------------------------------------------------------------------- 
5826 wxArrayInt 
wxPGChoices::GetValuesForStrings( const wxArrayString
& strings 
) const 
5833         for ( i
=0; i
< strings
.size(); i
++ ) 
5835             int index 
= Index(strings
[i
]); 
5837                 arr
.Add(GetValue(index
)); 
5839                 arr
.Add(wxPG_INVALID_VALUE
); 
5846 // ----------------------------------------------------------------------- 
5848 wxArrayInt 
wxPGChoices::GetIndicesForStrings( const wxArrayString
& strings
,  
5849                                               wxArrayString
* unmatched 
) const 
5856         for ( i
=0; i
< strings
.size(); i
++ ) 
5858             const wxString
& str 
= strings
[i
]; 
5859             int index 
= Index(str
); 
5862             else if ( unmatched 
) 
5863                 unmatched
->Add(str
); 
5870 // ----------------------------------------------------------------------- 
5872 void wxPGChoices::AssignData( wxPGChoicesData
* data 
) 
5876     if ( data 
!= wxPGChoicesEmptyData 
) 
5883 // ----------------------------------------------------------------------- 
5885 void wxPGChoices::Init() 
5887     m_data 
= wxPGChoicesEmptyData
; 
5890 // ----------------------------------------------------------------------- 
5892 void wxPGChoices::Free() 
5894     if ( m_data 
!= wxPGChoicesEmptyData 
) 
5897         m_data 
= wxPGChoicesEmptyData
; 
5901 // ----------------------------------------------------------------------- 
5902 // wxPropertyGridEvent 
5903 // ----------------------------------------------------------------------- 
5905 IMPLEMENT_DYNAMIC_CLASS(wxPropertyGridEvent
, wxCommandEvent
) 
5908 DEFINE_EVENT_TYPE( wxEVT_PG_SELECTED 
) 
5909 DEFINE_EVENT_TYPE( wxEVT_PG_CHANGING 
) 
5910 DEFINE_EVENT_TYPE( wxEVT_PG_CHANGED 
) 
5911 DEFINE_EVENT_TYPE( wxEVT_PG_HIGHLIGHTED 
) 
5912 DEFINE_EVENT_TYPE( wxEVT_PG_RIGHT_CLICK 
) 
5913 DEFINE_EVENT_TYPE( wxEVT_PG_PAGE_CHANGED 
) 
5914 DEFINE_EVENT_TYPE( wxEVT_PG_ITEM_EXPANDED 
) 
5915 DEFINE_EVENT_TYPE( wxEVT_PG_ITEM_COLLAPSED 
) 
5916 DEFINE_EVENT_TYPE( wxEVT_PG_DOUBLE_CLICK 
) 
5919 // ----------------------------------------------------------------------- 
5921 void wxPropertyGridEvent::Init() 
5923     m_validationInfo 
= NULL
; 
5925     m_wasVetoed 
= false; 
5928 // ----------------------------------------------------------------------- 
5930 wxPropertyGridEvent::wxPropertyGridEvent(wxEventType commandType
, int id
) 
5931     : wxCommandEvent(commandType
,id
) 
5937 // ----------------------------------------------------------------------- 
5939 wxPropertyGridEvent::wxPropertyGridEvent(const wxPropertyGridEvent
& event
) 
5940     : wxCommandEvent(event
) 
5942     m_eventType 
= event
.GetEventType(); 
5943     m_eventObject 
= event
.m_eventObject
; 
5945     m_property 
= event
.m_property
; 
5946     m_validationInfo 
= event
.m_validationInfo
; 
5947     m_canVeto 
= event
.m_canVeto
; 
5948     m_wasVetoed 
= event
.m_wasVetoed
; 
5951 // ----------------------------------------------------------------------- 
5953 wxPropertyGridEvent::~wxPropertyGridEvent() 
5957 // ----------------------------------------------------------------------- 
5959 wxEvent
* wxPropertyGridEvent::Clone() const 
5961     return new wxPropertyGridEvent( *this ); 
5964 // ----------------------------------------------------------------------- 
5965 // wxPropertyGridPopulator 
5966 // ----------------------------------------------------------------------- 
5968 wxPropertyGridPopulator::wxPropertyGridPopulator() 
5972     wxPGGlobalVars
->m_offline
++; 
5975 // ----------------------------------------------------------------------- 
5977 void wxPropertyGridPopulator::SetState( wxPropertyGridPageState
* state 
) 
5980     m_propHierarchy
.clear(); 
5983 // ----------------------------------------------------------------------- 
5985 void wxPropertyGridPopulator::SetGrid( wxPropertyGrid
* pg 
) 
5991 // ----------------------------------------------------------------------- 
5993 wxPropertyGridPopulator::~wxPropertyGridPopulator() 
5996     // Free unused sets of choices 
5997     wxPGHashMapS2P::iterator it
; 
5999     for( it 
= m_dictIdChoices
.begin(); it 
!= m_dictIdChoices
.end(); ++it 
) 
6001         wxPGChoicesData
* data 
= (wxPGChoicesData
*) it
->second
; 
6008         m_pg
->GetPanel()->Refresh(); 
6010     wxPGGlobalVars
->m_offline
--; 
6013 // ----------------------------------------------------------------------- 
6015 wxPGProperty
* wxPropertyGridPopulator::Add( const wxString
& propClass
, 
6016                                             const wxString
& propLabel
, 
6017                                             const wxString
& propName
, 
6018                                             const wxString
* propValue
, 
6019                                             wxPGChoices
* pChoices 
) 
6021     wxClassInfo
* classInfo 
= wxClassInfo::FindClass(propClass
); 
6022     wxPGProperty
* parent 
= GetCurParent(); 
6024     if ( parent
->HasFlag(wxPG_PROP_AGGREGATE
) ) 
6026         ProcessError(wxString::Format(wxT("new children cannot be added to '%s'"),parent
->GetName().c_str())); 
6030     if ( !classInfo 
|| !classInfo
->IsKindOf(CLASSINFO(wxPGProperty
)) ) 
6032         ProcessError(wxString::Format(wxT("'%s' is not valid property class"),propClass
.c_str())); 
6036     wxPGProperty
* property 
= (wxPGProperty
*) classInfo
->CreateObject(); 
6038     property
->SetLabel(propLabel
); 
6039     property
->DoSetName(propName
); 
6041     if ( pChoices 
&& pChoices
->IsOk() ) 
6042         property
->SetChoices(*pChoices
); 
6044     m_state
->DoInsert(parent
, -1, property
); 
6047         property
->SetValueFromString( *propValue
, wxPG_FULL_VALUE 
); 
6052 // ----------------------------------------------------------------------- 
6054 void wxPropertyGridPopulator::AddChildren( wxPGProperty
* property 
) 
6056     m_propHierarchy
.push_back(property
); 
6057     DoScanForChildren(); 
6058     m_propHierarchy
.pop_back(); 
6061 // ----------------------------------------------------------------------- 
6063 wxPGChoices 
wxPropertyGridPopulator::ParseChoices( const wxString
& choicesString
, 
6064                                                    const wxString
& idString 
) 
6066     wxPGChoices choices
; 
6069     if ( choicesString
[0] == wxT('@') ) 
6071         wxString ids 
= choicesString
.substr(1); 
6072         wxPGHashMapS2P::iterator it 
= m_dictIdChoices
.find(ids
); 
6073         if ( it 
== m_dictIdChoices
.end() ) 
6074             ProcessError(wxString::Format(wxT("No choices defined for id '%s'"),ids
.c_str())); 
6076             choices
.AssignData((wxPGChoicesData
*)it
->second
); 
6081         if ( idString
.length() ) 
6083             wxPGHashMapS2P::iterator it 
= m_dictIdChoices
.find(idString
); 
6084             if ( it 
!= m_dictIdChoices
.end() ) 
6086                 choices
.AssignData((wxPGChoicesData
*)it
->second
); 
6093             // Parse choices string 
6094             wxString::const_iterator it 
= choicesString
.begin(); 
6098             bool labelValid 
= false; 
6100             for ( ; it 
!= choicesString
.end(); it
++ ) 
6106                     if ( c 
== wxT('"') ) 
6111                             if ( !value
.ToLong(&l
, 0) ) l 
= wxPG_INVALID_VALUE
; 
6112                             choices
.Add(label
, l
); 
6115                         //wxLogDebug(wxT("%s, %s"),label.c_str(),value.c_str()); 
6120                     else if ( c 
== wxT('=') ) 
6127                     else if ( state 
== 2 && (wxIsalnum(c
) || c 
== wxT('x')) ) 
6134                     if ( c 
== wxT('"') ) 
6147                 if ( !value
.ToLong(&l
, 0) ) l 
= wxPG_INVALID_VALUE
; 
6148                 choices
.Add(label
, l
); 
6151             if ( !choices
.IsOk() ) 
6153                 choices
.EnsureData(); 
6157             if ( idString
.length() ) 
6158                 m_dictIdChoices
[idString
] = choices
.GetData(); 
6165 // ----------------------------------------------------------------------- 
6167 bool wxPropertyGridPopulator::ToLongPCT( const wxString
& s
, long* pval
, long max 
) 
6169     if ( s
.Last() == wxT('%') ) 
6171         wxString s2 
= s
.substr(0,s
.length()-1); 
6173         if ( s2
.ToLong(&val
, 10) ) 
6175             *pval 
= (val
*max
)/100; 
6181     return s
.ToLong(pval
, 10); 
6184 // ----------------------------------------------------------------------- 
6186 bool wxPropertyGridPopulator::AddAttribute( const wxString
& name
, 
6187                                             const wxString
& type
, 
6188                                             const wxString
& value 
) 
6190     int l 
= m_propHierarchy
.size(); 
6194     wxPGProperty
* p 
= m_propHierarchy
[l
-1]; 
6195     wxString valuel 
= value
.Lower(); 
6198     if ( type
.length() == 0 ) 
6203         if ( valuel 
== wxT("true") || valuel 
== wxT("yes") || valuel 
== wxT("1") ) 
6205         else if ( valuel 
== wxT("false") || valuel 
== wxT("no") || valuel 
== wxT("0") ) 
6207         else if ( value
.ToLong(&v
, 0) ) 
6214         if ( type 
== wxT("string") ) 
6218         else if ( type 
== wxT("int") ) 
6221             value
.ToLong(&v
, 0); 
6224         else if ( type 
== wxT("bool") ) 
6226             if ( valuel 
== wxT("true") || valuel 
== wxT("yes") || valuel 
== wxT("1") ) 
6233             ProcessError(wxString::Format(wxT("Invalid attribute type '%s'"),type
.c_str())); 
6238     p
->SetAttribute( name
, variant 
); 
6243 // ----------------------------------------------------------------------- 
6245 void wxPropertyGridPopulator::ProcessError( const wxString
& msg 
) 
6247     wxLogError(_("Error in resource: %s"),msg
.c_str()); 
6250 // ----------------------------------------------------------------------- 
6252 #endif  // wxUSE_PROPGRID