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 char wxPropertyGridNameStr
[] = "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 
= 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 
= 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 //   Intercepts Close-events sent to wxPropertyGrid's top-level parent, 
 237 //   and tries to commit property value. 
 238 // ----------------------------------------------------------------------- 
 240 class wxPGTLWHandler 
: public wxEvtHandler
 
 244     wxPGTLWHandler( wxPropertyGrid
* pg 
) 
 252     void OnClose( wxCloseEvent
& event 
) 
 254         // ClearSelection forces value validation/commit. 
 255         if ( event
.CanVeto() && !m_pg
->ClearSelection() ) 
 265     wxPropertyGrid
*     m_pg
; 
 267     DECLARE_EVENT_TABLE() 
 270 BEGIN_EVENT_TABLE(wxPGTLWHandler
, wxEvtHandler
) 
 271     EVT_CLOSE(wxPGTLWHandler::OnClose
) 
 274 // ----------------------------------------------------------------------- 
 276 // ----------------------------------------------------------------------- 
 279 // wxPGCanvas acts as a graphics sub-window of the 
 280 // wxScrolledWindow that wxPropertyGrid is. 
 282 class wxPGCanvas 
: public wxPanel
 
 285     wxPGCanvas() : wxPanel() 
 288     virtual ~wxPGCanvas() { } 
 291     void OnMouseMove( wxMouseEvent 
&event 
) 
 293         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 294         pg
->OnMouseMove( event 
); 
 297     void OnMouseClick( wxMouseEvent 
&event 
) 
 299         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 300         pg
->OnMouseClick( event 
); 
 303     void OnMouseUp( wxMouseEvent 
&event 
) 
 305         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 306         pg
->OnMouseUp( event 
); 
 309     void OnMouseRightClick( wxMouseEvent 
&event 
) 
 311         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 312         pg
->OnMouseRightClick( event 
); 
 315     void OnMouseDoubleClick( wxMouseEvent 
&event 
) 
 317         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 318         pg
->OnMouseDoubleClick( event 
); 
 321     void OnKey( wxKeyEvent
& event 
) 
 323         wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 327     void OnPaint( wxPaintEvent
& event 
); 
 329     // Always be focussable, even with child windows 
 330     virtual void SetCanFocus(bool WXUNUSED(canFocus
)) 
 331     {  wxPanel::SetCanFocus(true); } 
 335     DECLARE_EVENT_TABLE() 
 336     DECLARE_ABSTRACT_CLASS(wxPGCanvas
) 
 340 IMPLEMENT_ABSTRACT_CLASS(wxPGCanvas
,wxPanel
) 
 342 BEGIN_EVENT_TABLE(wxPGCanvas
, wxPanel
) 
 343     EVT_MOTION(wxPGCanvas::OnMouseMove
) 
 344     EVT_PAINT(wxPGCanvas::OnPaint
) 
 345     EVT_LEFT_DOWN(wxPGCanvas::OnMouseClick
) 
 346     EVT_LEFT_UP(wxPGCanvas::OnMouseUp
) 
 347     EVT_RIGHT_UP(wxPGCanvas::OnMouseRightClick
) 
 348     EVT_LEFT_DCLICK(wxPGCanvas::OnMouseDoubleClick
) 
 349     EVT_KEY_DOWN(wxPGCanvas::OnKey
) 
 353 void wxPGCanvas::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
 355     wxPropertyGrid
* pg 
= wxStaticCast(GetParent(), wxPropertyGrid
); 
 356     wxASSERT( pg
->IsKindOf(CLASSINFO(wxPropertyGrid
)) ); 
 360     // Don't paint after destruction has begun 
 361     if ( !(pg
->GetInternalFlags() & wxPG_FL_INITIALIZED
) ) 
 364     // Update everything inside the box 
 365     wxRect r 
= GetUpdateRegion().GetBox(); 
 367     // Repaint this rectangle 
 368     pg
->DrawItems( dc
, r
.y
, r
.y 
+ r
.height
, &r 
); 
 370     // We assume that the size set when grid is shown 
 371     // is what is desired. 
 372     pg
->SetInternalFlag(wxPG_FL_GOOD_SIZE_SET
); 
 375 // ----------------------------------------------------------------------- 
 377 // ----------------------------------------------------------------------- 
 379 IMPLEMENT_DYNAMIC_CLASS(wxPropertyGrid
, wxScrolledWindow
) 
 381 BEGIN_EVENT_TABLE(wxPropertyGrid
, wxScrolledWindow
) 
 382   EVT_IDLE(wxPropertyGrid::OnIdle
) 
 383   EVT_MOTION(wxPropertyGrid::OnMouseMoveBottom
) 
 384   EVT_PAINT(wxPropertyGrid::OnPaint
) 
 385   EVT_SIZE(wxPropertyGrid::OnResize
) 
 386   EVT_ENTER_WINDOW(wxPropertyGrid::OnMouseEntry
) 
 387   EVT_LEAVE_WINDOW(wxPropertyGrid::OnMouseEntry
) 
 388   EVT_MOUSE_CAPTURE_CHANGED(wxPropertyGrid::OnCaptureChange
) 
 389   EVT_SCROLLWIN(wxPropertyGrid::OnScrollEvent
) 
 390   EVT_CHILD_FOCUS(wxPropertyGrid::OnChildFocusEvent
) 
 391   EVT_SET_FOCUS(wxPropertyGrid::OnFocusEvent
) 
 392   EVT_KILL_FOCUS(wxPropertyGrid::OnFocusEvent
) 
 393   EVT_SYS_COLOUR_CHANGED(wxPropertyGrid::OnSysColourChanged
) 
 397 // ----------------------------------------------------------------------- 
 399 wxPropertyGrid::wxPropertyGrid() 
 405 // ----------------------------------------------------------------------- 
 407 wxPropertyGrid::wxPropertyGrid( wxWindow 
*parent
, 
 412                                 const wxString
& name 
) 
 416     Create(parent
,id
,pos
,size
,style
,name
); 
 419 // ----------------------------------------------------------------------- 
 421 bool wxPropertyGrid::Create( wxWindow 
*parent
, 
 426                              const wxString
& name 
) 
 429     if ( !(style
&wxBORDER_MASK
) ) 
 430         style 
|= wxSIMPLE_BORDER
; 
 434     // Filter out wxTAB_TRAVERSAL - we will handle TABs manually 
 435     style 
&= ~(wxTAB_TRAVERSAL
); 
 436     style 
|= wxWANTS_CHARS
; 
 438     wxScrolledWindow::Create(parent
,id
,pos
,size
,style
,name
); 
 445 // ----------------------------------------------------------------------- 
 448 // Initialize values to defaults 
 450 void wxPropertyGrid::Init1() 
 452     // Register editor classes, if necessary. 
 453     if ( wxPGGlobalVars
->m_mapEditorClasses
.empty() ) 
 454         wxPropertyGrid::RegisterDefaultEditors(); 
 458     m_wndEditor 
= m_wndEditor2 
= NULL
; 
 462     m_eventObject 
= this; 
 465     m_sortFunction 
= NULL
; 
 466     m_inDoPropertyChanged 
= 0; 
 467     m_inCommitChangesFromEditor 
= 0; 
 468     m_inDoSelectProperty 
= 0; 
 469     m_permanentValidationFailureBehavior 
= wxPG_VFB_DEFAULT
; 
 475     AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY
, WXK_RIGHT 
); 
 476     AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY
, WXK_DOWN 
); 
 477     AddActionTrigger( wxPG_ACTION_PREV_PROPERTY
, WXK_LEFT 
); 
 478     AddActionTrigger( wxPG_ACTION_PREV_PROPERTY
, WXK_UP 
); 
 479     AddActionTrigger( wxPG_ACTION_EXPAND_PROPERTY
, WXK_RIGHT
); 
 480     AddActionTrigger( wxPG_ACTION_COLLAPSE_PROPERTY
, WXK_LEFT
); 
 481     AddActionTrigger( wxPG_ACTION_CANCEL_EDIT
, WXK_ESCAPE 
); 
 482     AddActionTrigger( wxPG_ACTION_PRESS_BUTTON
, WXK_DOWN
, wxMOD_ALT 
); 
 483     AddActionTrigger( wxPG_ACTION_PRESS_BUTTON
, WXK_F4 
); 
 485     m_coloursCustomized 
= 0; 
 490 #if wxPG_DOUBLE_BUFFER 
 491     m_doubleBuffer 
= NULL
; 
 494 #ifndef wxPG_ICON_WIDTH 
 500     m_iconWidth 
= wxPG_ICON_WIDTH
; 
 505     m_gutterWidth 
= wxPG_GUTTER_MIN
; 
 506     m_subgroup_extramargin 
= 10; 
 510     m_width 
= m_height 
= 0; 
 512     m_commonValues
.push_back(new wxPGCommonValue(_("Unspecified"), wxPGGlobalVars
->m_defaultRenderer
) ); 
 515     m_chgInfo_changedProperty 
= NULL
; 
 518 // ----------------------------------------------------------------------- 
 521 // Initialize after parent etc. set 
 523 void wxPropertyGrid::Init2() 
 525     wxASSERT( !(m_iFlags 
& wxPG_FL_INITIALIZED 
) ); 
 528    // Smaller controls on Mac 
 529    SetWindowVariant(wxWINDOW_VARIANT_SMALL
); 
 532     // Now create state, if one didn't exist already 
 533     // (wxPropertyGridManager might have created it for us). 
 536         m_pState 
= CreateState(); 
 537         m_pState
->m_pPropGrid 
= this; 
 538         m_iFlags 
|= wxPG_FL_CREATEDSTATE
; 
 541     if ( !(m_windowStyle 
& wxPG_SPLITTER_AUTO_CENTER
) ) 
 542         m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
 544     if ( m_windowStyle 
& wxPG_HIDE_CATEGORIES 
) 
 546         m_pState
->InitNonCatMode(); 
 548         m_pState
->m_properties 
= m_pState
->m_abcArray
; 
 551     GetClientSize(&m_width
,&m_height
); 
 553 #ifndef wxPG_ICON_WIDTH 
 554     // create two bitmap nodes for drawing 
 555         m_expandbmp 
= new wxBitmap(expand_xpm
); 
 556         m_collbmp 
= new wxBitmap(collapse_xpm
); 
 558         // calculate average font height for bitmap centering 
 560         m_iconWidth 
= m_expandbmp
->GetWidth(); 
 561         m_iconHeight 
= m_expandbmp
->GetHeight(); 
 564     m_curcursor 
= wxCURSOR_ARROW
; 
 565     m_cursorSizeWE 
= new wxCursor( wxCURSOR_SIZEWE 
); 
 567         // adjust bitmap icon y position so they are centered 
 568     m_vspacing 
= wxPG_DEFAULT_VSPACING
; 
 572         wxFont useFont 
= wxScrolledWindow::GetFont(); 
 573         wxScrolledWindow::SetOwnFont( useFont 
); 
 577         // This should be otherwise called by SetOwnFont 
 578             CalculateFontAndBitmapStuff( wxPG_DEFAULT_VSPACING 
); 
 581     // Allocate cell datas indirectly by calling setter 
 582     m_propertyDefaultCell
.SetBgCol(*wxBLACK
); 
 583     m_categoryDefaultCell
.SetBgCol(*wxBLACK
); 
 587     // This helps with flicker 
 588     SetBackgroundStyle( wxBG_STYLE_CUSTOM 
); 
 591     wxPGTLWHandler
* handler 
= new wxPGTLWHandler(this); 
 592     m_tlp 
= ::wxGetTopLevelParent(this); 
 593     m_tlwHandler 
= handler
; 
 594     m_tlp
->PushEventHandler(handler
); 
 596         // set virtual size to this window size 
 597     wxSize wndsize 
= GetSize(); 
 598         SetVirtualSize(wndsize
.GetWidth(), wndsize
.GetWidth()); 
 600     m_timeCreated 
= ::wxGetLocalTimeMillis(); 
 602     m_canvas 
= new wxPGCanvas(); 
 603     m_canvas
->Create(this, 1, wxPoint(0, 0), GetClientSize(), 
 604                      wxWANTS_CHARS 
| wxCLIP_CHILDREN
); 
 605     m_canvas
->SetBackgroundStyle( wxBG_STYLE_CUSTOM 
); 
 607     m_iFlags 
|= wxPG_FL_INITIALIZED
; 
 609     m_ncWidth 
= wndsize
.GetWidth(); 
 611     // Need to call OnResize handler or size given in constructor/Create 
 613     wxSizeEvent 
sizeEvent(wndsize
,0); 
 617 // ----------------------------------------------------------------------- 
 619 wxPropertyGrid::~wxPropertyGrid() 
 623     DoSelectProperty(NULL
); 
 625     // This should do prevent things from going too badly wrong 
 626     m_iFlags 
&= ~(wxPG_FL_INITIALIZED
); 
 628     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
 629         m_canvas
->ReleaseMouse(); 
 631     wxPGTLWHandler
* handler 
= (wxPGTLWHandler
*) m_tlwHandler
; 
 632     m_tlp
->RemoveEventHandler(handler
); 
 636     if ( IsEditorsValueModified() ) 
 637         ::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).)"), 
 638                        wxS("wxPropertyGrid Debug Warning") ); 
 641 #if wxPG_DOUBLE_BUFFER 
 642     if ( m_doubleBuffer 
) 
 643         delete m_doubleBuffer
; 
 648     if ( m_iFlags 
& wxPG_FL_CREATEDSTATE 
) 
 651     delete m_cursorSizeWE
; 
 653 #ifndef wxPG_ICON_WIDTH 
 658     // Delete common value records 
 659     for ( i
=0; i
<m_commonValues
.size(); i
++ ) 
 661         delete GetCommonValue(i
); 
 665 // ----------------------------------------------------------------------- 
 667 bool wxPropertyGrid::Destroy() 
 669     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
 670         m_canvas
->ReleaseMouse(); 
 672     return wxScrolledWindow::Destroy(); 
 675 // ----------------------------------------------------------------------- 
 677 wxPropertyGridPageState
* wxPropertyGrid::CreateState() const 
 679     return new wxPropertyGridPageState(); 
 682 // ----------------------------------------------------------------------- 
 683 // wxPropertyGrid overridden wxWindow methods 
 684 // ----------------------------------------------------------------------- 
 686 void wxPropertyGrid::SetWindowStyleFlag( long style 
) 
 688     long old_style 
= m_windowStyle
; 
 690     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
 692         wxASSERT( m_pState 
); 
 694         if ( !(style 
& wxPG_HIDE_CATEGORIES
) && (old_style 
& wxPG_HIDE_CATEGORIES
) ) 
 697             EnableCategories( true ); 
 699         else if ( (style 
& wxPG_HIDE_CATEGORIES
) && !(old_style 
& wxPG_HIDE_CATEGORIES
) ) 
 701         // Disable categories 
 702             EnableCategories( false ); 
 704         if ( !(old_style 
& wxPG_AUTO_SORT
) && (style 
& wxPG_AUTO_SORT
) ) 
 710                 PrepareAfterItemsAdded(); 
 712                 m_pState
->m_itemsAdded 
= 1; 
 714     #if wxPG_SUPPORT_TOOLTIPS 
 715         if ( !(old_style 
& wxPG_TOOLTIPS
) && (style 
& wxPG_TOOLTIPS
) ) 
 721             wxToolTip* tooltip = new wxToolTip ( wxEmptyString ); 
 722             SetToolTip ( tooltip ); 
 723             tooltip->SetDelay ( wxPG_TOOLTIP_DELAY ); 
 726         else if ( (old_style 
& wxPG_TOOLTIPS
) && !(style 
& wxPG_TOOLTIPS
) ) 
 731             m_canvas
->SetToolTip( NULL 
); 
 736     wxScrolledWindow::SetWindowStyleFlag ( style 
); 
 738     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
 740         if ( (old_style 
& wxPG_HIDE_MARGIN
) != (style 
& wxPG_HIDE_MARGIN
) ) 
 742             CalculateFontAndBitmapStuff( m_vspacing 
); 
 748 // ----------------------------------------------------------------------- 
 750 void wxPropertyGrid::Freeze() 
 754         wxScrolledWindow::Freeze(); 
 759 // ----------------------------------------------------------------------- 
 761 void wxPropertyGrid::Thaw() 
 767         wxScrolledWindow::Thaw(); 
 768         RecalculateVirtualSize(); 
 769     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
 773         // Force property re-selection 
 775             DoSelectProperty(m_selected
, wxPG_SEL_FORCE
); 
 779 // ----------------------------------------------------------------------- 
 781 void wxPropertyGrid::SetExtraStyle( long exStyle 
) 
 783     if ( exStyle 
& wxPG_EX_NATIVE_DOUBLE_BUFFERING 
) 
 785 #if defined(__WXMSW__) 
 788         // Don't use WS_EX_COMPOSITED just now. 
 791         if ( m_iFlags & wxPG_FL_IN_MANAGER ) 
 792             hWnd = (HWND)GetParent()->GetHWND(); 
 794             hWnd = (HWND)GetHWND(); 
 796         ::SetWindowLong( hWnd, GWL_EXSTYLE, 
 797                          ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED ); 
 800 //#elif defined(__WXGTK20__) 
 802         // Only apply wxPG_EX_NATIVE_DOUBLE_BUFFERING if the window 
 803         // truly was double-buffered. 
 804         if ( !this->IsDoubleBuffered() ) 
 806             exStyle 
&= ~(wxPG_EX_NATIVE_DOUBLE_BUFFERING
); 
 810         #if wxPG_DOUBLE_BUFFER 
 811             delete m_doubleBuffer
; 
 812             m_doubleBuffer 
= NULL
; 
 817     wxScrolledWindow::SetExtraStyle( exStyle 
); 
 819     if ( exStyle 
& wxPG_EX_INIT_NOCAT 
) 
 820         m_pState
->InitNonCatMode(); 
 822     if ( exStyle 
& wxPG_EX_HELP_AS_TOOLTIPS 
) 
 823         m_windowStyle 
|= wxPG_TOOLTIPS
; 
 826     wxPGGlobalVars
->m_extraStyle 
= exStyle
; 
 829 // ----------------------------------------------------------------------- 
 831 // returns the best acceptable minimal size 
 832 wxSize 
wxPropertyGrid::DoGetBestSize() const 
 835     if ( m_lineHeight 
> hei 
) 
 837     wxSize sz 
= wxSize( 60, hei
+40 ); 
 843 // ----------------------------------------------------------------------- 
 844 // wxPropertyGrid Font and Colour Methods 
 845 // ----------------------------------------------------------------------- 
 847 void wxPropertyGrid::CalculateFontAndBitmapStuff( int vspacing 
) 
 851     m_captionFont 
= wxScrolledWindow::GetFont(); 
 853         GetTextExtent(wxS("jG"), &x
, &y
, 0, 0, &m_captionFont
); 
 854     m_subgroup_extramargin 
= x 
+ (x
/2); 
 857 #if wxPG_USE_RENDERER_NATIVE 
 858     m_iconWidth 
= wxPG_ICON_WIDTH
; 
 859 #elif wxPG_ICON_WIDTH 
 861     m_iconWidth 
= (m_fontHeight 
* wxPG_ICON_WIDTH
) / 13; 
 862     if ( m_iconWidth 
< 5 ) m_iconWidth 
= 5; 
 863     else if ( !(m_iconWidth 
& 0x01) ) m_iconWidth
++; // must be odd 
 867     m_gutterWidth 
= m_iconWidth 
/ wxPG_GUTTER_DIV
; 
 868     if ( m_gutterWidth 
< wxPG_GUTTER_MIN 
) 
 869         m_gutterWidth 
= wxPG_GUTTER_MIN
; 
 872     if ( vspacing 
<= 1 ) vdiv 
= 12; 
 873     else if ( vspacing 
>= 3 ) vdiv 
= 3; 
 875     m_spacingy 
= m_fontHeight 
/ vdiv
; 
 876     if ( m_spacingy 
< wxPG_YSPACING_MIN 
) 
 877         m_spacingy 
= wxPG_YSPACING_MIN
; 
 880     if ( !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
 881         m_marginWidth 
= m_gutterWidth
*2 + m_iconWidth
; 
 883     m_captionFont
.SetWeight(wxBOLD
); 
 884         GetTextExtent(wxS("jG"), &x
, &y
, 0, 0, &m_captionFont
); 
 886     m_lineHeight 
= m_fontHeight
+(2*m_spacingy
)+1; 
 889     m_buttonSpacingY 
= (m_lineHeight 
- m_iconHeight
) / 2; 
 890     if ( m_buttonSpacingY 
< 0 ) m_buttonSpacingY 
= 0; 
 893         m_pState
->CalculateFontAndBitmapStuff(vspacing
); 
 895     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
 896         RecalculateVirtualSize(); 
 898     InvalidateBestSize(); 
 901 // ----------------------------------------------------------------------- 
 903 void wxPropertyGrid::OnSysColourChanged( wxSysColourChangedEvent 
&WXUNUSED(event
) ) 
 909 // ----------------------------------------------------------------------- 
 911 static wxColour 
wxPGAdjustColour(const wxColour
& src
, int ra
, 
 912                                  int ga 
= 1000, int ba 
= 1000, 
 913                                  bool forceDifferent 
= false) 
 920     // Recursion guard (allow 2 max) 
 921     static int isinside 
= 0; 
 923     wxCHECK_MSG( isinside 
< 3, 
 925                  wxT("wxPGAdjustColour should not be recursively called more than once") ); 
 933     if ( r2
>255 ) r2 
= 255; 
 934     else if ( r2
<0) r2 
= 0; 
 936     if ( g2
>255 ) g2 
= 255; 
 937     else if ( g2
<0) g2 
= 0; 
 939     if ( b2
>255 ) b2 
= 255; 
 940     else if ( b2
<0) b2 
= 0; 
 942     // Make sure they are somewhat different 
 943     if ( forceDifferent 
&& (abs((r
+g
+b
)-(r2
+g2
+b2
)) < abs(ra
/2)) ) 
 944         dst 
= wxPGAdjustColour(src
,-(ra
*2)); 
 946         dst 
= wxColour(r2
,g2
,b2
); 
 948     // Recursion guard (allow 2 max) 
 955 static int wxPGGetColAvg( const wxColour
& col 
) 
 957     return (col
.Red() + col
.Green() + col
.Blue()) / 3; 
 961 void wxPropertyGrid::RegainColours() 
 963     if ( !(m_coloursCustomized 
& 0x0002) ) 
 965         wxColour col 
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE 
); 
 967         // Make sure colour is dark enough 
 969         int colDec 
= wxPGGetColAvg(col
) - 230; 
 971         int colDec 
= wxPGGetColAvg(col
) - 200; 
 974             m_colCapBack 
= wxPGAdjustColour(col
,-colDec
); 
 977         m_categoryDefaultCell
.GetData()->SetBgCol(m_colCapBack
); 
 980     if ( !(m_coloursCustomized 
& 0x0001) ) 
 981         m_colMargin 
= m_colCapBack
; 
 983     if ( !(m_coloursCustomized 
& 0x0004) ) 
 990         wxColour capForeCol 
= wxPGAdjustColour(m_colCapBack
,colDec
,5000,5000,true); 
 991         m_colCapFore 
= capForeCol
; 
 992         m_categoryDefaultCell
.GetData()->SetFgCol(capForeCol
); 
 995     if ( !(m_coloursCustomized 
& 0x0008) ) 
 997         wxColour bgCol 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
 998         m_colPropBack 
= bgCol
; 
 999         m_propertyDefaultCell
.GetData()->SetBgCol(bgCol
); 
1002     if ( !(m_coloursCustomized 
& 0x0010) ) 
1004         wxColour fgCol 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
1005         m_colPropFore 
= fgCol
; 
1006         m_propertyDefaultCell
.GetData()->SetFgCol(fgCol
); 
1009     if ( !(m_coloursCustomized 
& 0x0020) ) 
1010         m_colSelBack 
= wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT 
); 
1012     if ( !(m_coloursCustomized 
& 0x0040) ) 
1013         m_colSelFore 
= wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
); 
1015     if ( !(m_coloursCustomized 
& 0x0080) ) 
1016         m_colLine 
= m_colCapBack
; 
1018     if ( !(m_coloursCustomized 
& 0x0100) ) 
1019         m_colDisPropFore 
= m_colCapFore
; 
1021     m_colEmptySpace 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
1024 // ----------------------------------------------------------------------- 
1026 void wxPropertyGrid::ResetColours() 
1028     m_coloursCustomized 
= 0; 
1035 // ----------------------------------------------------------------------- 
1037 bool wxPropertyGrid::SetFont( const wxFont
& font 
) 
1039     // Must disable active editor. 
1040     ClearSelection(false); 
1042     // TODO: Following code is disabled with wxMac because 
1043     //   it is reported to fail. I (JMS) cannot debug it 
1044     //   personally right now. 
1045     // CS: should be fixed now, leaving old code in just in case, TODO: REMOVE 
1046 #if 1 // !defined(__WXMAC__) 
1047     bool res 
= wxScrolledWindow::SetFont( font 
); 
1050         CalculateFontAndBitmapStuff( m_vspacing 
); 
1053             m_pState
->CalculateFontAndBitmapStuff(m_vspacing
); 
1061     // TODO: Remove after SetFont crash fixed. 
1062     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
1064         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.")); 
1070 // ----------------------------------------------------------------------- 
1072 void wxPropertyGrid::SetLineColour( const wxColour
& col 
) 
1075     m_coloursCustomized 
|= 0x80; 
1079 // ----------------------------------------------------------------------- 
1081 void wxPropertyGrid::SetMarginColour( const wxColour
& col 
) 
1084     m_coloursCustomized 
|= 0x01; 
1088 // ----------------------------------------------------------------------- 
1090 void wxPropertyGrid::SetCellBackgroundColour( const wxColour
& col 
) 
1092     m_colPropBack 
= col
; 
1093     m_coloursCustomized 
|= 0x08; 
1095     m_propertyDefaultCell
.GetData()->SetBgCol(col
); 
1100 // ----------------------------------------------------------------------- 
1102 void wxPropertyGrid::SetCellTextColour( const wxColour
& col 
) 
1104     m_colPropFore 
= col
; 
1105     m_coloursCustomized 
|= 0x10; 
1107     m_propertyDefaultCell
.GetData()->SetFgCol(col
); 
1112 // ----------------------------------------------------------------------- 
1114 void wxPropertyGrid::SetEmptySpaceColour( const wxColour
& col 
) 
1116     m_colEmptySpace 
= col
; 
1121 // ----------------------------------------------------------------------- 
1123 void wxPropertyGrid::SetCellDisabledTextColour( const wxColour
& col 
) 
1125     m_colDisPropFore 
= col
; 
1126     m_coloursCustomized 
|= 0x100; 
1130 // ----------------------------------------------------------------------- 
1132 void wxPropertyGrid::SetSelectionBackgroundColour( const wxColour
& col 
) 
1135     m_coloursCustomized 
|= 0x20; 
1139 // ----------------------------------------------------------------------- 
1141 void wxPropertyGrid::SetSelectionTextColour( const wxColour
& col 
) 
1144     m_coloursCustomized 
|= 0x40; 
1148 // ----------------------------------------------------------------------- 
1150 void wxPropertyGrid::SetCaptionBackgroundColour( const wxColour
& col 
) 
1153     m_coloursCustomized 
|= 0x02; 
1155     m_categoryDefaultCell
.GetData()->SetBgCol(col
); 
1160 // ----------------------------------------------------------------------- 
1162 void wxPropertyGrid::SetCaptionTextColour( const wxColour
& col 
) 
1165     m_coloursCustomized 
|= 0x04; 
1167     m_categoryDefaultCell
.GetData()->SetFgCol(col
); 
1172 // ----------------------------------------------------------------------- 
1173 // wxPropertyGrid property adding and removal 
1174 // ----------------------------------------------------------------------- 
1176 void wxPropertyGrid::PrepareAfterItemsAdded() 
1178     if ( !m_pState 
|| !m_pState
->m_itemsAdded 
) return; 
1180     m_pState
->m_itemsAdded 
= 0; 
1182     if ( m_windowStyle 
& wxPG_AUTO_SORT 
) 
1183         Sort(wxPG_SORT_TOP_LEVEL_ONLY
); 
1185     RecalculateVirtualSize(); 
1188 // ----------------------------------------------------------------------- 
1189 // wxPropertyGrid property operations 
1190 // ----------------------------------------------------------------------- 
1192 bool wxPropertyGrid::EnsureVisible( wxPGPropArg id 
) 
1194     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) 
1198     bool changed 
= false; 
1200     // Is it inside collapsed section? 
1201     if ( !p
->IsVisible() ) 
1204         wxPGProperty
* parent 
= p
->GetParent(); 
1205         wxPGProperty
* grandparent 
= parent
->GetParent(); 
1207         if ( grandparent 
&& grandparent 
!= m_pState
->m_properties 
) 
1208             Expand( grandparent 
); 
1216     GetViewStart(&vx
,&vy
); 
1217     vy
*=wxPG_PIXELS_PER_UNIT
; 
1223         Scroll(vx
, y
/wxPG_PIXELS_PER_UNIT 
); 
1224         m_iFlags 
|= wxPG_FL_SCROLLED
; 
1227     else if ( (y
+m_lineHeight
) > (vy
+m_height
) ) 
1229         Scroll(vx
, (y
-m_height
+(m_lineHeight
*2))/wxPG_PIXELS_PER_UNIT 
); 
1230         m_iFlags 
|= wxPG_FL_SCROLLED
; 
1240 // ----------------------------------------------------------------------- 
1241 // wxPropertyGrid helper methods called by properties 
1242 // ----------------------------------------------------------------------- 
1244 // Control font changer helper. 
1245 void wxPropertyGrid::SetCurControlBoldFont() 
1247     wxASSERT( m_wndEditor 
); 
1248     m_wndEditor
->SetFont( m_captionFont 
); 
1251 // ----------------------------------------------------------------------- 
1253 wxPoint 
wxPropertyGrid::GetGoodEditorDialogPosition( wxPGProperty
* p
, 
1256 #if wxPG_SMALL_SCREEN 
1257     // On small-screen devices, always show dialogs with default position and size. 
1258     return wxDefaultPosition
; 
1260     int splitterX 
= GetSplitterPosition(); 
1264     wxCHECK_MSG( y 
>= 0, wxPoint(-1,-1), wxT("invalid y?") ); 
1266     ImprovedClientToScreen( &x
, &y 
); 
1268     int sw 
= wxSystemSettings::GetMetric( ::wxSYS_SCREEN_X 
); 
1269     int sh 
= wxSystemSettings::GetMetric( ::wxSYS_SCREEN_Y 
); 
1276         new_x 
= x 
+ (m_width
-splitterX
) - sz
.x
; 
1286         new_y 
= y 
+ m_lineHeight
; 
1288     return wxPoint(new_x
,new_y
); 
1292 // ----------------------------------------------------------------------- 
1294 wxString
& wxPropertyGrid::ExpandEscapeSequences( wxString
& dst_str
, wxString
& src_str 
) 
1296     if ( src_str
.length() == 0 ) 
1302     bool prev_is_slash 
= false; 
1304     wxString::const_iterator i 
= src_str
.begin(); 
1308     for ( ; i 
!= src_str
.end(); ++i 
) 
1312         if ( a 
!= wxS('\\') ) 
1314             if ( !prev_is_slash 
) 
1320                 if ( a 
== wxS('n') ) 
1323                     dst_str 
<< wxS('\n'); 
1325                     dst_str 
<< wxS('\n'); 
1328                 else if ( a 
== wxS('t') ) 
1329                     dst_str 
<< wxS('\t'); 
1333             prev_is_slash 
= false; 
1337             if ( prev_is_slash 
) 
1339                 dst_str 
<< wxS('\\'); 
1340                 prev_is_slash 
= false; 
1344                 prev_is_slash 
= true; 
1351 // ----------------------------------------------------------------------- 
1353 wxString
& wxPropertyGrid::CreateEscapeSequences( wxString
& dst_str
, wxString
& src_str 
) 
1355     if ( src_str
.length() == 0 ) 
1361     wxString::const_iterator i 
= src_str
.begin(); 
1362     wxUniChar prev_a 
= wxS('\0'); 
1366     for ( ; i 
!= src_str
.end(); ++i 
) 
1370         if ( a 
>= wxS(' ') ) 
1372             // This surely is not something that requires an escape sequence. 
1377             // This might need... 
1378             if ( a 
== wxS('\r')  ) 
1380                 // DOS style line end. 
1381                 // Already taken care below 
1383             else if ( a 
== wxS('\n') ) 
1384                 // UNIX style line end. 
1385                 dst_str 
<< wxS("\\n"); 
1386             else if ( a 
== wxS('\t') ) 
1388                 dst_str 
<< wxS('\t'); 
1391                 //wxLogDebug(wxT("WARNING: Could not create escape sequence for character #%i"),(int)a); 
1401 // ----------------------------------------------------------------------- 
1403 wxPGProperty
* wxPropertyGrid::DoGetItemAtY( int y 
) const 
1410     return m_pState
->m_properties
->GetItemAtY(y
, m_lineHeight
, &a
); 
1413 // ----------------------------------------------------------------------- 
1414 // wxPropertyGrid graphics related methods 
1415 // ----------------------------------------------------------------------- 
1417 void wxPropertyGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
1421     // Update everything inside the box 
1422     wxRect r 
= GetUpdateRegion().GetBox(); 
1424     dc
.SetPen(m_colEmptySpace
); 
1425     dc
.SetBrush(m_colEmptySpace
); 
1426     dc
.DrawRectangle(r
); 
1429 // ----------------------------------------------------------------------- 
1431 void wxPropertyGrid::DrawExpanderButton( wxDC
& dc
, const wxRect
& rect
, 
1432                                          wxPGProperty
* property 
) const 
1434     // Prepare rectangle to be used 
1436     r
.x 
+= m_gutterWidth
; r
.y 
+= m_buttonSpacingY
; 
1437     r
.width 
= m_iconWidth
; r
.height 
= m_iconHeight
; 
1439 #if (wxPG_USE_RENDERER_NATIVE) 
1441 #elif wxPG_ICON_WIDTH 
1442     // Drawing expand/collapse button manually 
1443     dc
.SetPen(m_colPropFore
); 
1444     if ( property
->IsCategory() ) 
1445         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1447         dc
.SetBrush(m_colPropBack
); 
1449     dc
.DrawRectangle( r 
); 
1450     int _y 
= r
.y
+(m_iconWidth
/2); 
1451     dc
.DrawLine(r
.x
+2,_y
,r
.x
+m_iconWidth
-2,_y
); 
1456     if ( property
->IsExpanded() ) 
1458     // wxRenderer functions are non-mutating in nature, so it 
1459     // should be safe to cast "const wxPropertyGrid*" to "wxWindow*". 
1460     // Hopefully this does not cause problems. 
1461     #if (wxPG_USE_RENDERER_NATIVE) 
1462         wxRendererNative::Get().DrawTreeItemButton( 
1468     #elif wxPG_ICON_WIDTH 
1477     #if (wxPG_USE_RENDERER_NATIVE) 
1478         wxRendererNative::Get().DrawTreeItemButton( 
1484     #elif wxPG_ICON_WIDTH 
1485         int _x 
= r
.x
+(m_iconWidth
/2); 
1486         dc
.DrawLine(_x
,r
.y
+2,_x
,r
.y
+m_iconWidth
-2); 
1492 #if (wxPG_USE_RENDERER_NATIVE) 
1494 #elif wxPG_ICON_WIDTH 
1497     dc
.DrawBitmap( *bmp
, r
.x
, r
.y
, true ); 
1501 // ----------------------------------------------------------------------- 
1504 // This is the one called by OnPaint event handler and others. 
1505 // topy and bottomy are already unscrolled (ie. physical) 
1507 void wxPropertyGrid::DrawItems( wxDC
& dc
, 
1509                                 unsigned int bottomy
, 
1510                                 const wxRect
* clipRect 
) 
1512     if ( m_frozen 
|| m_height 
< 1 || bottomy 
< topy 
|| !m_pState 
) return; 
1514     m_pState
->EnsureVirtualHeight(); 
1516     wxRect tempClipRect
; 
1519         tempClipRect 
= wxRect(0,topy
,m_pState
->m_width
,bottomy
); 
1520         clipRect 
= &tempClipRect
; 
1523     // items added check 
1524     if ( m_pState
->m_itemsAdded 
) PrepareAfterItemsAdded(); 
1526     int paintFinishY 
= 0; 
1528     if ( m_pState
->m_properties
->GetChildCount() > 0 ) 
1531         bool isBuffered 
= false; 
1533     #if wxPG_DOUBLE_BUFFER 
1534         wxMemoryDC
* bufferDC 
= NULL
; 
1536         if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING
) ) 
1538             if ( !m_doubleBuffer 
) 
1540                 paintFinishY 
= clipRect
->y
; 
1545                 bufferDC 
= new wxMemoryDC(); 
1547                 // If nothing was changed, then just copy from double-buffer 
1548                 bufferDC
->SelectObject( *m_doubleBuffer 
); 
1558             dc
.SetClippingRegion( *clipRect 
); 
1559             paintFinishY 
= DoDrawItems( *dcPtr
, NULL
, NULL
, clipRect
, isBuffered 
); 
1562     #if wxPG_DOUBLE_BUFFER 
1565             dc
.Blit( clipRect
->x
, clipRect
->y
, clipRect
->width
, clipRect
->height
, 
1566                 bufferDC
, 0, 0, wxCOPY 
); 
1567             dc
.DestroyClippingRegion(); // Is this really necessary? 
1573     // Clear area beyond bottomY? 
1574     if ( paintFinishY 
< (clipRect
->y
+clipRect
->height
) ) 
1576         dc
.SetPen(m_colEmptySpace
); 
1577         dc
.SetBrush(m_colEmptySpace
); 
1578         dc
.DrawRectangle( 0, paintFinishY
, m_width
, (clipRect
->y
+clipRect
->height
) ); 
1582 // ----------------------------------------------------------------------- 
1584 int wxPropertyGrid::DoDrawItems( wxDC
& dc
, 
1585                                  const wxPGProperty
* firstItem
, 
1586                                  const wxPGProperty
* lastItem
, 
1587                                  const wxRect
* clipRect
, 
1588                                  bool isBuffered 
) const 
1590     // TODO: This should somehow be eliminated. 
1591     wxRect tempClipRect
; 
1594         wxASSERT(firstItem
); 
1596         tempClipRect 
= GetPropertyRect(firstItem
, lastItem
); 
1597         clipRect 
= &tempClipRect
; 
1601         firstItem 
= DoGetItemAtY(clipRect
->y
); 
1605         lastItem 
= DoGetItemAtY(clipRect
->y
+clipRect
->height
-1); 
1607             lastItem 
= GetLastItem( wxPG_ITERATE_VISIBLE 
); 
1610     if ( m_frozen 
|| m_height 
< 1 || firstItem 
== NULL 
) 
1613     wxCHECK_MSG( !m_pState
->m_itemsAdded
, clipRect
->y
, wxT("no items added") ); 
1614     wxASSERT( m_pState
->m_properties
->GetChildCount() ); 
1616     int lh 
= m_lineHeight
; 
1619     int lastItemBottomY
; 
1621     firstItemTopY 
= clipRect
->y
; 
1622     lastItemBottomY 
= clipRect
->y 
+ clipRect
->height
; 
1624     // Align y coordinates to item boundaries 
1625     firstItemTopY 
-= firstItemTopY 
% lh
; 
1626     lastItemBottomY 
+= lh 
- (lastItemBottomY 
% lh
); 
1627     lastItemBottomY 
-= 1; 
1629     // Entire range outside scrolled, visible area? 
1630     if ( firstItemTopY 
>= (int)m_pState
->GetVirtualHeight() || lastItemBottomY 
<= 0 ) 
1633     wxCHECK_MSG( firstItemTopY 
< lastItemBottomY
, clipRect
->y
, wxT("invalid y values") ); 
1637     wxLogDebug(wxT("  -> DoDrawItems ( \"%s\" -> \"%s\", height=%i (ch=%i), clipRect = 0x%lX )"), 
1638         firstItem->GetLabel().c_str(), 
1639         lastItem->GetLabel().c_str(), 
1640         (int)(lastItemBottomY - firstItemTopY), 
1642         (unsigned long)clipRect ); 
1647     long windowStyle 
= m_windowStyle
; 
1653     // With wxPG_DOUBLE_BUFFER, do double buffering 
1654     // - buffer's y = 0, so align cliprect and coordinates to that 
1656 #if wxPG_DOUBLE_BUFFER 
1662         xRelMod 
= clipRect
->x
; 
1663         yRelMod 
= clipRect
->y
; 
1666         // clipRect conversion 
1671         firstItemTopY 
-= yRelMod
; 
1672         lastItemBottomY 
-= yRelMod
; 
1675     wxUnusedVar(isBuffered
); 
1678     int x 
= m_marginWidth 
- xRelMod
; 
1680     const wxFont
& normalfont 
= m_font
; 
1682     bool reallyFocused 
= (m_iFlags 
& wxPG_FL_FOCUSED
) != 0; 
1684     bool isEnabled 
= IsEnabled(); 
1687     // Prepare some pens and brushes that are often changed to. 
1690     wxBrush 
marginBrush(m_colMargin
); 
1691     wxPen 
marginPen(m_colMargin
); 
1692     wxBrush 
capbgbrush(m_colCapBack
,wxSOLID
); 
1693     wxPen 
linepen(m_colLine
,1,wxSOLID
); 
1695     // pen that has same colour as text 
1696     wxPen 
outlinepen(m_colPropFore
,1,wxSOLID
); 
1699     // Clear margin with background colour 
1701     dc
.SetBrush( marginBrush 
); 
1702     if ( !(windowStyle 
& wxPG_HIDE_MARGIN
) ) 
1704         dc
.SetPen( *wxTRANSPARENT_PEN 
); 
1705         dc
.DrawRectangle(-1-xRelMod
,firstItemTopY
-1,x
+2,lastItemBottomY
-firstItemTopY
+2); 
1708     const wxPGProperty
* selected 
= m_selected
; 
1709     const wxPropertyGridPageState
* state 
= m_pState
; 
1711 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
1712     bool wasSelectedPainted 
= false; 
1715     // TODO: Only render columns that are within clipping region. 
1717     dc
.SetFont(normalfont
); 
1719     wxPropertyGridConstIterator 
it( state
, wxPG_ITERATE_VISIBLE
, firstItem 
); 
1720     int endScanBottomY 
= lastItemBottomY 
+ lh
; 
1721     int y 
= firstItemTopY
; 
1724     // Pregenerate list of visible properties. 
1725     wxArrayPGProperty visPropArray
; 
1726     visPropArray
.reserve((m_height
/m_lineHeight
)+6); 
1728     for ( ; !it
.AtEnd(); it
.Next() ) 
1730         const wxPGProperty
* p 
= *it
; 
1732         if ( !p
->HasFlag(wxPG_PROP_HIDDEN
) ) 
1734             visPropArray
.push_back((wxPGProperty
*)p
); 
1736             if ( y 
> endScanBottomY 
) 
1743     visPropArray
.push_back(NULL
); 
1745     wxPGProperty
* nextP 
= visPropArray
[0]; 
1747     int gridWidth 
= state
->m_width
; 
1750     for ( unsigned int arrInd
=1; 
1751           nextP 
&& y 
<= lastItemBottomY
; 
1754         wxPGProperty
* p 
= nextP
; 
1755         nextP 
= visPropArray
[arrInd
]; 
1757         int rowHeight 
= m_fontHeight
+(m_spacingy
*2)+1; 
1758         int textMarginHere 
= x
; 
1759         int renderFlags 
= 0; 
1761         int greyDepth 
= m_marginWidth
; 
1762         if ( !(windowStyle 
& wxPG_HIDE_CATEGORIES
) ) 
1763             greyDepth 
= (((int)p
->m_depthBgCol
)-1) * m_subgroup_extramargin 
+ m_marginWidth
; 
1765         int greyDepthX 
= greyDepth 
- xRelMod
; 
1767         // Use basic depth if in non-categoric mode and parent is base array. 
1768         if ( !(windowStyle 
& wxPG_HIDE_CATEGORIES
) || p
->GetParent() != m_pState
->m_properties 
) 
1770             textMarginHere 
+= ((unsigned int)((p
->m_depth
-1)*m_subgroup_extramargin
)); 
1773         // Paint margin area 
1774         dc
.SetBrush(marginBrush
); 
1775         dc
.SetPen(marginPen
); 
1776         dc
.DrawRectangle( -xRelMod
, y
, greyDepth
, lh 
); 
1778         dc
.SetPen( linepen 
); 
1783         dc
.DrawLine( greyDepthX
, y
, greyDepthX
, y2 
); 
1789         for ( si
=0; si
<state
->m_colWidths
.size(); si
++ ) 
1791             sx 
+= state
->m_colWidths
[si
]; 
1792             dc
.DrawLine( sx
, y
, sx
, y2 
); 
1795         // Horizontal Line, below 
1796         //   (not if both this and next is category caption) 
1797         if ( p
->IsCategory() && 
1798              nextP 
&& nextP
->IsCategory() ) 
1799             dc
.SetPen(m_colCapBack
); 
1801         dc
.DrawLine( greyDepthX
, y2
-1, gridWidth
-xRelMod
, y2
-1 ); 
1804         // Need to override row colours? 
1808         if ( p 
!= selected 
) 
1810             // Disabled may get different colour. 
1811             if ( !p
->IsEnabled() ) 
1813                 renderFlags 
|= wxPGCellRenderer::Disabled 
| 
1814                                wxPGCellRenderer::DontUseCellFgCol
; 
1815                 rowFgCol 
= m_colDisPropFore
; 
1820             renderFlags 
|= wxPGCellRenderer::Selected
; 
1822             if ( !p
->IsCategory() ) 
1824                 renderFlags 
|= wxPGCellRenderer::DontUseCellFgCol 
| 
1825                                wxPGCellRenderer::DontUseCellBgCol
; 
1827 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
1828                 wasSelectedPainted 
= true; 
1831                 // Selected gets different colour. 
1832                 if ( reallyFocused 
) 
1834                     rowFgCol 
= m_colSelFore
; 
1835                     rowBgCol 
= m_colSelBack
; 
1837                 else if ( isEnabled 
) 
1839                     rowFgCol 
= m_colPropFore
; 
1840                     rowBgCol 
= m_colMargin
; 
1844                     rowFgCol 
= m_colDisPropFore
; 
1845                     rowBgCol 
= m_colSelBack
; 
1852         if ( rowBgCol
.IsOk() ) 
1853             rowBgBrush 
= wxBrush(rowBgCol
); 
1855         if ( HasInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
) ) 
1856             renderFlags 
= renderFlags 
& ~wxPGCellRenderer::DontUseCellColours
; 
1859         // Fill additional margin area with background colour of first cell 
1860         if ( greyDepthX 
< textMarginHere 
) 
1862             if ( !(renderFlags 
& wxPGCellRenderer::DontUseCellBgCol
) ) 
1864                 wxPGCell
& cell 
= p
->GetCell(0); 
1865                 rowBgCol 
= cell
.GetBgCol(); 
1866                 rowBgBrush 
= wxBrush(rowBgCol
); 
1868             dc
.SetBrush(rowBgBrush
); 
1869             dc
.SetPen(rowBgCol
); 
1870             dc
.DrawRectangle(greyDepthX
+1, y
, 
1871                              textMarginHere
-greyDepthX
, lh
-1); 
1874         bool fontChanged 
= false; 
1876         // Expander button rectangle 
1877         wxRect 
butRect( ((p
->m_depth 
- 1) * m_subgroup_extramargin
) - xRelMod
, 
1882         if ( p
->IsCategory() ) 
1884             // Captions have their cell areas merged as one 
1885             dc
.SetFont(m_captionFont
); 
1887             wxRect 
cellRect(greyDepthX
, y
, gridWidth 
- greyDepth 
+ 2, rowHeight
-1 ); 
1889             if ( renderFlags 
& wxPGCellRenderer::DontUseCellBgCol 
) 
1891                 dc
.SetBrush(rowBgBrush
); 
1892                 dc
.SetPen(rowBgCol
); 
1895             if ( renderFlags 
& wxPGCellRenderer::DontUseCellFgCol 
) 
1897                 dc
.SetTextForeground(rowFgCol
); 
1900             wxPGCellRenderer
* renderer 
= p
->GetCellRenderer(0); 
1901             renderer
->Render( dc
, cellRect
, this, p
, 0, -1, renderFlags 
); 
1904             if ( !HasFlag(wxPG_HIDE_MARGIN
) && p
->HasVisibleChildren() ) 
1905                 DrawExpanderButton( dc
, butRect
, p 
); 
1909             if ( p
->m_flags 
& wxPG_PROP_MODIFIED 
&& (windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
1911                 dc
.SetFont(m_captionFont
); 
1917             int nextCellWidth 
= state
->m_colWidths
[0] - 
1918                                 (greyDepthX 
- m_marginWidth
); 
1919             wxRect 
cellRect(greyDepthX
+1, y
, 0, rowHeight
-1); 
1920             int textXAdd 
= textMarginHere 
- greyDepthX
; 
1922             for ( ci
=0; ci
<state
->m_colWidths
.size(); ci
++ ) 
1924                 cellRect
.width 
= nextCellWidth 
- 1; 
1926                 bool ctrlCell 
= false; 
1927                 int cellRenderFlags 
= renderFlags
; 
1930                 if ( ci 
== 0 && !HasFlag(wxPG_HIDE_MARGIN
) && p
->HasVisibleChildren() ) 
1931                     DrawExpanderButton( dc
, butRect
, p 
); 
1934                 if ( p 
== selected 
&& m_wndEditor 
&& ci 
== 1 ) 
1936                     wxColour editorBgCol 
= GetEditorControl()->GetBackgroundColour(); 
1937                     dc
.SetBrush(editorBgCol
); 
1938                     dc
.SetPen(editorBgCol
); 
1939                     dc
.SetTextForeground(m_colPropFore
); 
1940                     dc
.DrawRectangle(cellRect
); 
1942                     if ( m_dragStatus 
== 0 && !(m_iFlags 
& wxPG_FL_CUR_USES_CUSTOM_IMAGE
) ) 
1947                     if ( renderFlags 
& wxPGCellRenderer::DontUseCellBgCol 
) 
1949                         dc
.SetBrush(rowBgBrush
); 
1950                         dc
.SetPen(rowBgCol
); 
1953                     if ( renderFlags 
& wxPGCellRenderer::DontUseCellFgCol 
) 
1955                         dc
.SetTextForeground(rowFgCol
); 
1959                 dc
.SetClippingRegion(cellRect
); 
1961                 cellRect
.x 
+= textXAdd
; 
1962                 cellRect
.width 
-= textXAdd
; 
1967                     wxPGCellRenderer
* renderer
; 
1968                     int cmnVal 
= p
->GetCommonValue(); 
1969                     if ( cmnVal 
== -1 || ci 
!= 1 ) 
1971                         renderer 
= p
->GetCellRenderer(ci
); 
1972                         renderer
->Render( dc
, cellRect
, this, p
, ci
, -1, 
1977                         renderer 
= GetCommonValue(cmnVal
)->GetRenderer(); 
1978                         renderer
->Render( dc
, cellRect
, this, p
, ci
, -1, 
1983                 cellX 
+= state
->m_colWidths
[ci
]; 
1984                 if ( ci 
< (state
->m_colWidths
.size()-1) ) 
1985                     nextCellWidth 
= state
->m_colWidths
[ci
+1]; 
1987                 dc
.DestroyClippingRegion(); // Is this really necessary? 
1993             dc
.SetFont(normalfont
); 
1998     // Refresh editor controls (seems not needed on msw) 
1999     // NOTE: This code is mandatory for GTK! 
2000 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2001     if ( wasSelectedPainted 
) 
2004             m_wndEditor
->Refresh(); 
2006             m_wndEditor2
->Refresh(); 
2013 // ----------------------------------------------------------------------- 
2015 wxRect 
wxPropertyGrid::GetPropertyRect( const wxPGProperty
* p1
, const wxPGProperty
* p2 
) const 
2019     if ( m_width 
< 10 || m_height 
< 10 || 
2020          !m_pState
->m_properties
->GetChildCount() || 
2022         return wxRect(0,0,0,0); 
2027     // Return rect which encloses the given property range 
2029     int visTop 
= p1
->GetY(); 
2032         visBottom 
= p2
->GetY() + m_lineHeight
; 
2034         visBottom 
= m_height 
+ visTop
; 
2036     // If seleced property is inside the range, we'll extend the range to include 
2038     wxPGProperty
* selected 
= m_selected
; 
2041         int selectedY 
= selected
->GetY(); 
2042         if ( selectedY 
>= visTop 
&& selectedY 
< visBottom 
) 
2044             wxWindow
* editor 
= GetEditorControl(); 
2047                 int visBottom2 
= selectedY 
+ editor
->GetSize().y
; 
2048                 if ( visBottom2 
> visBottom 
) 
2049                     visBottom 
= visBottom2
; 
2054     return wxRect(0,visTop
-vy
,m_pState
->m_width
,visBottom
-visTop
); 
2057 // ----------------------------------------------------------------------- 
2059 void wxPropertyGrid::DrawItems( const wxPGProperty
* p1
, const wxPGProperty
* p2 
) 
2064     if ( m_pState
->m_itemsAdded 
) 
2065         PrepareAfterItemsAdded(); 
2067     wxRect r 
= GetPropertyRect(p1
, p2
); 
2070         m_canvas
->RefreshRect(r
); 
2074 // ----------------------------------------------------------------------- 
2076 void wxPropertyGrid::RefreshProperty( wxPGProperty
* p 
) 
2078     if ( p 
== m_selected 
) 
2079         DoSelectProperty(p
, wxPG_SEL_FORCE
); 
2081     DrawItemAndChildren(p
); 
2084 // ----------------------------------------------------------------------- 
2086 void wxPropertyGrid::DrawItemAndValueRelated( wxPGProperty
* p 
) 
2091     // Draw item, children, and parent too, if it is not category 
2092     wxPGProperty
* parent 
= p
->GetParent(); 
2095             !parent
->IsCategory() && 
2096             parent
->GetParent() ) 
2099          parent 
= parent
->GetParent(); 
2102     DrawItemAndChildren(p
); 
2105 void wxPropertyGrid::DrawItemAndChildren( wxPGProperty
* p 
) 
2107     wxCHECK_RET( p
, wxT("invalid property id") ); 
2109     // Do not draw if in non-visible page 
2110     if ( p
->GetParentState() != m_pState 
) 
2113     // do not draw a single item if multiple pending 
2114     if ( m_pState
->m_itemsAdded 
|| m_frozen 
) 
2117     // Update child control. 
2118     if ( m_selected 
&& m_selected
->GetParent() == p 
) 
2121     const wxPGProperty
* lastDrawn 
= p
->GetLastVisibleSubItem(); 
2123     DrawItems(p
, lastDrawn
); 
2126 // ----------------------------------------------------------------------- 
2128 void wxPropertyGrid::Refresh( bool WXUNUSED(eraseBackground
), 
2129                               const wxRect 
*rect 
) 
2131     PrepareAfterItemsAdded(); 
2133     wxWindow::Refresh(false); 
2135         // TODO: Coordinate translation 
2136         m_canvas
->Refresh(false, rect
); 
2138 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2139     // I think this really helps only GTK+1.2 
2140     if ( m_wndEditor 
) m_wndEditor
->Refresh(); 
2141     if ( m_wndEditor2 
) m_wndEditor2
->Refresh(); 
2145 // ----------------------------------------------------------------------- 
2146 // wxPropertyGrid global operations 
2147 // ----------------------------------------------------------------------- 
2149 void wxPropertyGrid::Clear() 
2151     ClearSelection(false); 
2153     m_pState
->DoClear(); 
2159     RecalculateVirtualSize(); 
2161     // Need to clear some area at the end 
2163         RefreshRect(wxRect(0, 0, m_width
, m_height
)); 
2166 // ----------------------------------------------------------------------- 
2168 bool wxPropertyGrid::EnableCategories( bool enable 
) 
2170     ClearSelection(false); 
2175         // Enable categories 
2178         m_windowStyle 
&= ~(wxPG_HIDE_CATEGORIES
); 
2183         // Disable categories 
2185         m_windowStyle 
|= wxPG_HIDE_CATEGORIES
; 
2188     if ( !m_pState
->EnableCategories(enable
) ) 
2193         if ( m_windowStyle 
& wxPG_AUTO_SORT 
) 
2195             m_pState
->m_itemsAdded 
= 1; // force 
2196             PrepareAfterItemsAdded(); 
2200         m_pState
->m_itemsAdded 
= 1; 
2202     // No need for RecalculateVirtualSize() here - it is already called in 
2203     // wxPropertyGridPageState method above. 
2210 // ----------------------------------------------------------------------- 
2212 void wxPropertyGrid::SwitchState( wxPropertyGridPageState
* pNewState 
) 
2214     wxASSERT( pNewState 
); 
2215     wxASSERT( pNewState
->GetGrid() ); 
2217     if ( pNewState 
== m_pState 
) 
2220     wxPGProperty
* oldSelection 
= m_selected
; 
2222     ClearSelection(false); 
2224     m_pState
->m_selected 
= oldSelection
; 
2226     bool orig_mode 
= m_pState
->IsInNonCatMode(); 
2227     bool new_state_mode 
= pNewState
->IsInNonCatMode(); 
2229     m_pState 
= pNewState
; 
2232     int pgWidth 
= GetClientSize().x
; 
2233     if ( HasVirtualWidth() ) 
2235         int minWidth 
= pgWidth
; 
2236         if ( pNewState
->m_width 
< minWidth 
) 
2238             pNewState
->m_width 
= minWidth
; 
2239             pNewState
->CheckColumnWidths(); 
2245         // Just in case, fully re-center splitter 
2246         if ( HasFlag( wxPG_SPLITTER_AUTO_CENTER 
) ) 
2247             pNewState
->m_fSplitterX 
= -1.0; 
2249         pNewState
->OnClientWidthChange( pgWidth
, pgWidth 
- pNewState
->m_width 
); 
2254     // If necessary, convert state to correct mode. 
2255     if ( orig_mode 
!= new_state_mode 
) 
2257         // This should refresh as well. 
2258         EnableCategories( orig_mode
?false:true ); 
2260     else if ( !m_frozen 
) 
2262         // Refresh, if not frozen. 
2263         m_pState
->PrepareAfterItemsAdded(); 
2266         if ( m_pState
->m_selected 
) 
2267             DoSelectProperty( m_pState
->m_selected 
); 
2269         RecalculateVirtualSize(0); 
2273         m_pState
->m_itemsAdded 
= 1; 
2276 // ----------------------------------------------------------------------- 
2278 // Call to SetSplitterPosition will always disable splitter auto-centering 
2279 // if parent window is shown. 
2280 void wxPropertyGrid::DoSetSplitterPosition_( int newxpos
, bool refresh
, int splitterIndex
, bool allPages 
) 
2282     if ( ( newxpos 
< wxPG_DRAG_MARGIN 
) ) 
2285     wxPropertyGridPageState
* state 
= m_pState
; 
2287     state
->DoSetSplitterPosition( newxpos
, splitterIndex
, allPages 
); 
2292             CorrectEditorWidgetSizeX(); 
2298 // ----------------------------------------------------------------------- 
2300 void wxPropertyGrid::CenterSplitter( bool enableAutoCentering 
) 
2302     SetSplitterPosition( m_width
/2, true ); 
2303     if ( enableAutoCentering 
&& ( m_windowStyle 
& wxPG_SPLITTER_AUTO_CENTER 
) ) 
2304         m_iFlags 
&= ~(wxPG_FL_DONT_CENTER_SPLITTER
); 
2307 // ----------------------------------------------------------------------- 
2308 // wxPropertyGrid item iteration (GetNextProperty etc.) methods 
2309 // ----------------------------------------------------------------------- 
2311 // Returns nearest paint visible property (such that will be painted unless 
2312 // window is scrolled or resized). If given property is paint visible, then 
2313 // it itself will be returned 
2314 wxPGProperty
* wxPropertyGrid::GetNearestPaintVisible( wxPGProperty
* p 
) const 
2316     int vx
,vy1
;// Top left corner of client 
2317     GetViewStart(&vx
,&vy1
); 
2318     vy1 
*= wxPG_PIXELS_PER_UNIT
; 
2320     int vy2 
= vy1 
+ m_height
; 
2321     int propY 
= p
->GetY2(m_lineHeight
); 
2323     if ( (propY 
+ m_lineHeight
) < vy1 
) 
2326         return DoGetItemAtY( vy1 
); 
2328     else if ( propY 
> vy2 
) 
2331         return DoGetItemAtY( vy2 
); 
2334     // Itself paint visible 
2339 // ----------------------------------------------------------------------- 
2340 // Methods related to change in value, value modification and sending events 
2341 // ----------------------------------------------------------------------- 
2343 // commits any changes in editor of selected property 
2344 // return true if validation did not fail 
2345 // flags are same as with DoSelectProperty 
2346 bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags 
) 
2348     // Committing already? 
2349     if ( m_inCommitChangesFromEditor 
) 
2352     // Don't do this if already processing editor event. It might 
2353     // induce recursive dialogs and crap like that. 
2354     if ( m_iFlags 
& wxPG_FL_IN_HANDLECUSTOMEDITOREVENT 
) 
2356         if ( m_inDoPropertyChanged 
) 
2363          IsEditorsValueModified() && 
2364          (m_iFlags 
& wxPG_FL_INITIALIZED
) && 
2367         m_inCommitChangesFromEditor 
= 1; 
2369         wxVariant 
variant(m_selected
->GetValueRef()); 
2370         bool valueIsPending 
= false; 
2372         // JACS - necessary to avoid new focus being found spuriously within OnIdle 
2373         // due to another window getting focus 
2374         wxWindow
* oldFocus 
= m_curFocused
; 
2376         bool validationFailure 
= false; 
2377         bool forceSuccess 
= (flags 
& (wxPG_SEL_NOVALIDATE
|wxPG_SEL_FORCE
)) ? true : false; 
2379         m_chgInfo_changedProperty 
= NULL
; 
2381         // If truly modified, schedule value as pending. 
2382         if ( m_selected
->GetEditorClass()->GetValueFromControl( variant
, m_selected
, GetEditorControl() ) ) 
2384             if ( DoEditorValidate() && 
2385                  PerformValidation(m_selected
, variant
) ) 
2387                 valueIsPending 
= true; 
2391                 validationFailure 
= true; 
2396             EditorsValueWasNotModified(); 
2401         m_inCommitChangesFromEditor 
= 0; 
2403         if ( validationFailure 
&& !forceSuccess 
) 
2407                 oldFocus
->SetFocus(); 
2408                 m_curFocused 
= oldFocus
; 
2411             res 
= OnValidationFailure(m_selected
, variant
); 
2413             // Now prevent further validation failure messages 
2416                 EditorsValueWasNotModified(); 
2417                 OnValidationFailureReset(m_selected
); 
2420         else if ( valueIsPending 
) 
2422             DoPropertyChanged( m_selected
, flags 
); 
2423             EditorsValueWasNotModified(); 
2432 // ----------------------------------------------------------------------- 
2434 bool wxPropertyGrid::PerformValidation( wxPGProperty
* p
, wxVariant
& pendingValue
, 
2438     // Runs all validation functionality. 
2439     // Returns true if value passes all tests. 
2442     m_validationInfo
.m_failureBehavior 
= m_permanentValidationFailureBehavior
; 
2444     if ( pendingValue
.GetType() == wxPG_VARIANT_TYPE_LIST 
) 
2446         if ( !p
->ValidateValue(pendingValue
, m_validationInfo
) ) 
2451     // Adapt list to child values, if necessary 
2452     wxVariant listValue 
= pendingValue
; 
2453     wxVariant
* pPendingValue 
= &pendingValue
; 
2454     wxVariant
* pList 
= NULL
; 
2456     // If parent has wxPG_PROP_AGGREGATE flag, or uses composite 
2457     // string value, then we need treat as it was changed instead 
2458     // (or, in addition, as is the case with composite string parent). 
2459     // This includes creating list variant for child values. 
2461     wxPGProperty
* pwc 
= p
->GetParent(); 
2462     wxPGProperty
* changedProperty 
= p
; 
2463     wxPGProperty
* baseChangedProperty 
= changedProperty
; 
2464     wxVariant bcpPendingList
; 
2466     listValue 
= pendingValue
; 
2467     listValue
.SetName(p
->GetBaseName()); 
2470             (pwc
->HasFlag(wxPG_PROP_AGGREGATE
) || pwc
->HasFlag(wxPG_PROP_COMPOSED_VALUE
)) ) 
2472         wxVariantList tempList
; 
2473         wxVariant 
lv(tempList
, pwc
->GetBaseName()); 
2474         lv
.Append(listValue
); 
2476         pPendingValue 
= &listValue
; 
2478         if ( pwc
->HasFlag(wxPG_PROP_AGGREGATE
) ) 
2480             baseChangedProperty 
= pwc
; 
2481             bcpPendingList 
= lv
; 
2484         changedProperty 
= pwc
; 
2485         pwc 
= pwc
->GetParent(); 
2489     wxPGProperty
* evtChangingProperty 
= changedProperty
; 
2491     if ( pPendingValue
->GetType() != wxPG_VARIANT_TYPE_LIST 
) 
2493         value 
= *pPendingValue
; 
2497         // Convert list to child values 
2498         pList 
= pPendingValue
; 
2499         changedProperty
->AdaptListToValue( *pPendingValue
, &value 
); 
2502     wxVariant evtChangingValue 
= value
; 
2504     if ( flags 
& SendEvtChanging 
) 
2506         // FIXME: After proper ValueToString()s added, remove 
2507         // this. It is just a temporary fix, as evt_changing 
2508         // will simply not work for wxPG_PROP_COMPOSED_VALUE 
2509         // (unless it is selected, and textctrl editor is open). 
2510         if ( changedProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
2512             evtChangingProperty 
= baseChangedProperty
; 
2513             if ( evtChangingProperty 
!= p 
) 
2515                 evtChangingProperty
->AdaptListToValue( bcpPendingList
, &evtChangingValue 
); 
2519                 evtChangingValue 
= pendingValue
; 
2523         if ( evtChangingProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
2525             if ( changedProperty 
== m_selected 
) 
2527                 wxWindow
* editor 
= GetEditorControl(); 
2528                 wxASSERT( editor
->IsKindOf(CLASSINFO(wxTextCtrl
)) ); 
2529                 evtChangingValue 
= wxStaticCast(editor
, wxTextCtrl
)->GetValue(); 
2533                 wxLogDebug(wxT("WARNING: wxEVT_PG_CHANGING is about to happen with old value.")); 
2538     wxASSERT( m_chgInfo_changedProperty 
== NULL 
); 
2539     m_chgInfo_changedProperty 
= changedProperty
; 
2540     m_chgInfo_baseChangedProperty 
= baseChangedProperty
; 
2541     m_chgInfo_pendingValue 
= value
; 
2544         m_chgInfo_valueList 
= *pList
; 
2546         m_chgInfo_valueList
.MakeNull(); 
2548     // If changedProperty is not property which value was edited, 
2549     // then call wxPGProperty::ValidateValue() for that as well. 
2550     if ( p 
!= changedProperty 
&& value
.GetType() != wxPG_VARIANT_TYPE_LIST 
) 
2552         if ( !changedProperty
->ValidateValue(value
, m_validationInfo
) ) 
2556     if ( flags 
& SendEvtChanging 
) 
2558         // SendEvent returns true if event was vetoed 
2559         if ( SendEvent( wxEVT_PG_CHANGING
, evtChangingProperty
, &evtChangingValue
, 0 ) ) 
2563     if ( flags 
& IsStandaloneValidation 
) 
2565         // If called in 'generic' context, we need to reset 
2566         // m_chgInfo_changedProperty and write back translated value. 
2567         m_chgInfo_changedProperty 
= NULL
; 
2568         pendingValue 
= value
; 
2574 // ----------------------------------------------------------------------- 
2576 void wxPropertyGrid::DoShowPropertyError( wxPGProperty
* WXUNUSED(property
), const wxString
& msg 
) 
2578     if ( !msg
.length() ) 
2582     if ( !wxPGGlobalVars
->m_offline 
) 
2584         wxWindow
* topWnd 
= ::wxGetTopLevelParent(this); 
2587             wxFrame
* pFrame 
= wxDynamicCast(topWnd
, wxFrame
); 
2590                 wxStatusBar
* pStatusBar 
= pFrame
->GetStatusBar(); 
2593                     pStatusBar
->SetStatusText(msg
); 
2601     ::wxMessageBox(msg
, _T("Property Error")); 
2604 // ----------------------------------------------------------------------- 
2606 bool wxPropertyGrid::OnValidationFailure( wxPGProperty
* property
, 
2607                                           wxVariant
& invalidValue 
) 
2609     wxWindow
* editor 
= GetEditorControl(); 
2611     // First call property's handler 
2612     property
->OnValidationFailure(invalidValue
); 
2614     bool res 
= DoOnValidationFailure(property
, invalidValue
); 
2617     // For non-wxTextCtrl editors, we do need to revert the value 
2618     if ( !editor
->IsKindOf(CLASSINFO(wxTextCtrl
)) && 
2619          property 
== m_selected 
) 
2621         property
->GetEditorClass()->UpdateControl(property
, editor
); 
2624     property
->SetFlag(wxPG_PROP_INVALID_VALUE
); 
2629 bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty
* property
, wxVariant
& WXUNUSED(invalidValue
) ) 
2631     int vfb 
= m_validationInfo
.m_failureBehavior
; 
2633     if ( vfb 
& wxPG_VFB_BEEP 
) 
2636     if ( (vfb 
& wxPG_VFB_MARK_CELL
) && 
2637          !property
->HasFlag(wxPG_PROP_INVALID_VALUE
) ) 
2639         unsigned int colCount 
= m_pState
->GetColumnCount(); 
2641         // We need backup marked property's cells 
2642         m_propCellsBackup 
= property
->m_cells
; 
2644         wxColour vfbFg 
= *wxWHITE
; 
2645         wxColour vfbBg 
= *wxRED
; 
2647         property
->EnsureCells(colCount
); 
2649         for ( unsigned int i
=0; i
<colCount
; i
++ ) 
2651             wxPGCell
& cell 
= property
->m_cells
[i
]; 
2652             cell
.SetFgCol(vfbFg
); 
2653             cell
.SetBgCol(vfbBg
); 
2656         DrawItemAndChildren(property
); 
2658         if ( property 
== m_selected 
) 
2660             SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
); 
2662             wxWindow
* editor 
= GetEditorControl(); 
2665                 editor
->SetForegroundColour(vfbFg
); 
2666                 editor
->SetBackgroundColour(vfbBg
); 
2671     if ( vfb 
& wxPG_VFB_SHOW_MESSAGE 
) 
2673         wxString msg 
= m_validationInfo
.m_failureMessage
; 
2675         if ( !msg
.length() ) 
2676             msg 
= _T("You have entered invalid value. Press ESC to cancel editing."); 
2678         DoShowPropertyError(property
, msg
); 
2681     return (vfb 
& wxPG_VFB_STAY_IN_PROPERTY
) ? false : true; 
2684 // ----------------------------------------------------------------------- 
2686 void wxPropertyGrid::DoOnValidationFailureReset( wxPGProperty
* property 
) 
2688     int vfb 
= m_validationInfo
.m_failureBehavior
; 
2690     if ( vfb 
& wxPG_VFB_MARK_CELL 
) 
2693         property
->m_cells 
= m_propCellsBackup
; 
2695         ClearInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
); 
2697         if ( property 
== m_selected 
&& GetEditorControl() ) 
2699             // Calling this will recreate the control, thus resetting its colour 
2700             RefreshProperty(property
); 
2704             DrawItemAndChildren(property
); 
2709 // ----------------------------------------------------------------------- 
2711 // flags are same as with DoSelectProperty 
2712 bool wxPropertyGrid::DoPropertyChanged( wxPGProperty
* p
, unsigned int selFlags 
) 
2714     if ( m_inDoPropertyChanged 
) 
2717     wxWindow
* editor 
= GetEditorControl(); 
2719     m_pState
->m_anyModified 
= 1; 
2721     m_inDoPropertyChanged 
= 1; 
2723     // Maybe need to update control 
2724     wxASSERT( m_chgInfo_changedProperty 
!= NULL 
); 
2726     // These values were calculated in PerformValidation() 
2727     wxPGProperty
* changedProperty 
= m_chgInfo_changedProperty
; 
2728     wxVariant value 
= m_chgInfo_pendingValue
; 
2730     wxPGProperty
* topPaintedProperty 
= changedProperty
; 
2732     while ( !topPaintedProperty
->IsCategory() && 
2733             !topPaintedProperty
->IsRoot() ) 
2735         topPaintedProperty 
= topPaintedProperty
->GetParent(); 
2738     changedProperty
->SetValue(value
, &m_chgInfo_valueList
, wxPG_SETVAL_BY_USER
); 
2740     // Set as Modified (not if dragging just began) 
2741     if ( !(p
->m_flags 
& wxPG_PROP_MODIFIED
) ) 
2743         p
->m_flags 
|= wxPG_PROP_MODIFIED
; 
2744         if ( p 
== m_selected 
&& (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
2747                 SetCurControlBoldFont(); 
2753     // Propagate updates to parent(s) 
2755     wxPGProperty
* prevPwc 
= NULL
; 
2757     while ( prevPwc 
!= topPaintedProperty 
) 
2759         pwc
->m_flags 
|= wxPG_PROP_MODIFIED
; 
2761         if ( pwc 
== m_selected 
&& (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
2764                 SetCurControlBoldFont(); 
2768         pwc 
= pwc
->GetParent(); 
2771     // Draw the actual property 
2772     DrawItemAndChildren( topPaintedProperty 
); 
2775     // If value was set by wxPGProperty::OnEvent, then update the editor 
2777     if ( selFlags 
& wxPG_SEL_DIALOGVAL 
) 
2783 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2784         if ( m_wndEditor 
) m_wndEditor
->Refresh(); 
2785         if ( m_wndEditor2 
) m_wndEditor2
->Refresh(); 
2790     wxASSERT( !changedProperty
->GetParent()->HasFlag(wxPG_PROP_AGGREGATE
) ); 
2792     // If top parent has composite string value, then send to child parents, 
2793     // starting from baseChangedProperty. 
2794     if ( changedProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
2796         pwc 
= m_chgInfo_baseChangedProperty
; 
2798         while ( pwc 
!= changedProperty 
) 
2800             SendEvent( wxEVT_PG_CHANGED
, pwc
, NULL
, selFlags 
); 
2801             pwc 
= pwc
->GetParent(); 
2805     SendEvent( wxEVT_PG_CHANGED
, changedProperty
, NULL
, selFlags 
); 
2807     m_inDoPropertyChanged 
= 0; 
2812 // ----------------------------------------------------------------------- 
2814 bool wxPropertyGrid::ChangePropertyValue( wxPGPropArg id
, wxVariant newValue 
) 
2816     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) 
2818     m_chgInfo_changedProperty 
= NULL
; 
2820     if ( PerformValidation(p
, newValue
) ) 
2822         DoPropertyChanged(p
); 
2827         OnValidationFailure(p
, newValue
); 
2833 // ----------------------------------------------------------------------- 
2835 wxVariant 
wxPropertyGrid::GetUncommittedPropertyValue() 
2837     wxPGProperty
* prop 
= GetSelectedProperty(); 
2840         return wxNullVariant
; 
2842     wxTextCtrl
* tc 
= GetEditorTextCtrl(); 
2843     wxVariant value 
= prop
->GetValue(); 
2845     if ( !tc 
|| !IsEditorsValueModified() ) 
2848     if ( !prop
->StringToValue(value
, tc
->GetValue()) ) 
2851     if ( !PerformValidation(prop
, value
, IsStandaloneValidation
) ) 
2852         return prop
->GetValue(); 
2857 // ----------------------------------------------------------------------- 
2859 // Runs wxValidator for the selected property 
2860 bool wxPropertyGrid::DoEditorValidate() 
2865 // ----------------------------------------------------------------------- 
2867 void wxPropertyGrid::HandleCustomEditorEvent( wxEvent 
&event 
) 
2869     wxPGProperty
* selected 
= m_selected
; 
2871     // Somehow, event is handled after property has been deselected. 
2872     // Possibly, but very rare. 
2876     if ( m_iFlags 
& wxPG_FL_IN_HANDLECUSTOMEDITOREVENT 
) 
2879     wxVariant 
pendingValue(selected
->GetValueRef()); 
2880     wxWindow
* wnd 
= GetEditorControl(); 
2882     bool wasUnspecified 
= selected
->IsValueUnspecified(); 
2883     int usesAutoUnspecified 
= selected
->UsesAutoUnspecified(); 
2885     bool valueIsPending 
= false; 
2887     m_chgInfo_changedProperty 
= NULL
; 
2889     m_iFlags 
&= ~(wxPG_FL_VALIDATION_FAILED
|wxPG_FL_VALUE_CHANGE_IN_EVENT
); 
2892     // Filter out excess wxTextCtrl modified events 
2893     if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED 
&& 
2895          wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) ) 
2897         wxTextCtrl
* tc 
= (wxTextCtrl
*) wnd
; 
2899         wxString newTcValue 
= tc
->GetValue(); 
2900         if ( m_prevTcValue 
== newTcValue 
) 
2903         m_prevTcValue 
= newTcValue
; 
2906     SetInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT
); 
2908     bool validationFailure 
= false; 
2909     bool buttonWasHandled 
= false; 
2912     // Try common button handling 
2913     if ( m_wndEditor2 
&& event
.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED 
) 
2915         wxPGEditorDialogAdapter
* adapter 
= selected
->GetEditorDialog(); 
2919             buttonWasHandled 
= true; 
2920             // Store as res2, as previously (and still currently alternatively) 
2921             // dialogs can be shown by handling wxEVT_COMMAND_BUTTON_CLICKED 
2922             // in wxPGProperty::OnEvent(). 
2923             adapter
->ShowDialog( this, selected 
); 
2928     if ( !buttonWasHandled 
) 
2932             // First call editor class' event handler. 
2933             const wxPGEditor
* editor 
= selected
->GetEditorClass(); 
2935             if ( editor
->OnEvent( this, selected
, wnd
, event 
) ) 
2937                 // If changes, validate them 
2938                 if ( DoEditorValidate() ) 
2940                     if ( editor
->GetValueFromControl( pendingValue
, m_selected
, wnd 
) ) 
2941                         valueIsPending 
= true; 
2945                     validationFailure 
= true; 
2950         // Then the property's custom handler (must be always called, unless 
2951         // validation failed). 
2952         if ( !validationFailure 
) 
2953             buttonWasHandled 
= selected
->OnEvent( this, wnd
, event 
); 
2956     // SetValueInEvent(), as called in one of the functions referred above 
2957     // overrides editor's value. 
2958     if ( m_iFlags 
& wxPG_FL_VALUE_CHANGE_IN_EVENT 
) 
2960         valueIsPending 
= true; 
2961         pendingValue 
= m_changeInEventValue
; 
2962         selFlags 
|= wxPG_SEL_DIALOGVAL
; 
2965     if ( !validationFailure 
&& valueIsPending 
) 
2966         if ( !PerformValidation(m_selected
, pendingValue
) ) 
2967             validationFailure 
= true; 
2969     if ( validationFailure
) 
2971         OnValidationFailure(selected
, pendingValue
); 
2973     else if ( valueIsPending 
) 
2975         selFlags 
|= ( !wasUnspecified 
&& selected
->IsValueUnspecified() && usesAutoUnspecified 
) ? wxPG_SEL_SETUNSPEC 
: 0; 
2977         DoPropertyChanged(selected
, selFlags
); 
2978         EditorsValueWasNotModified(); 
2980         // Regardless of editor type, unfocus editor on 
2981         // text-editing related enter press. 
2982         if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER 
) 
2989         // No value after all 
2991         // Regardless of editor type, unfocus editor on 
2992         // text-editing related enter press. 
2993         if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER 
) 
2998         // Let unhandled button click events go to the parent 
2999         if ( !buttonWasHandled 
&& event
.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED 
) 
3001             wxCommandEvent 
evt(wxEVT_COMMAND_BUTTON_CLICKED
,GetId()); 
3002             GetEventHandler()->AddPendingEvent(evt
); 
3006     ClearInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT
); 
3009 // ----------------------------------------------------------------------- 
3010 // wxPropertyGrid editor control helper methods 
3011 // ----------------------------------------------------------------------- 
3013 wxRect 
wxPropertyGrid::GetEditorWidgetRect( wxPGProperty
* p
, int column 
) const 
3015     int itemy 
= p
->GetY2(m_lineHeight
); 
3017     int cust_img_space 
= 0; 
3018     int splitterX 
= m_pState
->DoGetSplitterPosition(column
-1); 
3019     int colEnd 
= splitterX 
+ m_pState
->m_colWidths
[column
]; 
3021     // TODO: If custom image detection changes from current, change this. 
3022     if ( m_iFlags 
& wxPG_FL_CUR_USES_CUSTOM_IMAGE 
/*p->m_flags & wxPG_PROP_CUSTOMIMAGE*/ ) 
3024         //m_iFlags |= wxPG_FL_CUR_USES_CUSTOM_IMAGE; 
3025         int imwid 
= p
->OnMeasureImage().x
; 
3026         if ( imwid 
< 1 ) imwid 
= wxPG_CUSTOM_IMAGE_WIDTH
; 
3027         cust_img_space 
= imwid 
+ wxCC_CUSTOM_IMAGE_MARGIN1 
+ wxCC_CUSTOM_IMAGE_MARGIN2
; 
3032         splitterX
+cust_img_space
+wxPG_XBEFOREWIDGET
+wxPG_CONTROL_MARGIN
+1, 
3034         colEnd
-splitterX
-wxPG_XBEFOREWIDGET
-wxPG_CONTROL_MARGIN
-cust_img_space
-1, 
3039 // ----------------------------------------------------------------------- 
3041 wxRect 
wxPropertyGrid::GetImageRect( wxPGProperty
* p
, int item 
) const 
3043     wxSize sz 
= GetImageSize(p
, item
); 
3044     return wxRect(wxPG_CONTROL_MARGIN 
+ wxCC_CUSTOM_IMAGE_MARGIN1
, 
3045                   wxPG_CUSTOM_IMAGE_SPACINGY
, 
3050 // return size of custom paint image 
3051 wxSize 
wxPropertyGrid::GetImageSize( wxPGProperty
* p
, int item 
) const 
3053     // If called with NULL property, then return default image 
3054     // size for properties that use image. 
3056         return wxSize(wxPG_CUSTOM_IMAGE_WIDTH
,wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
)); 
3058     wxSize cis 
= p
->OnMeasureImage(item
); 
3060     int choiceCount 
= p
->m_choices
.GetCount(); 
3061     int comVals 
= p
->GetDisplayedCommonValueCount(); 
3062     if ( item 
>= choiceCount 
&& comVals 
> 0 ) 
3064         unsigned int cvi 
= item
-choiceCount
; 
3065         cis 
= GetCommonValue(cvi
)->GetRenderer()->GetImageSize(NULL
, 1, cvi
); 
3067     else if ( item 
>= 0 && choiceCount 
== 0 ) 
3068         return wxSize(0, 0); 
3073             cis
.x 
= wxPG_CUSTOM_IMAGE_WIDTH
; 
3078             cis
.y 
= wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
); 
3085 // ----------------------------------------------------------------------- 
3087 // takes scrolling into account 
3088 void wxPropertyGrid::ImprovedClientToScreen( int* px
, int* py 
) 
3091     GetViewStart(&vx
,&vy
); 
3092     vy
*=wxPG_PIXELS_PER_UNIT
; 
3093     vx
*=wxPG_PIXELS_PER_UNIT
; 
3096     ClientToScreen( px
, py 
); 
3099 // ----------------------------------------------------------------------- 
3101 wxPropertyGridHitTestResult 
wxPropertyGrid::HitTest( const wxPoint
& pt 
) const 
3104     GetViewStart(&pt2
.x
,&pt2
.y
); 
3105     pt2
.x 
*= wxPG_PIXELS_PER_UNIT
; 
3106     pt2
.y 
*= wxPG_PIXELS_PER_UNIT
; 
3110     return m_pState
->HitTest(pt2
); 
3113 // ----------------------------------------------------------------------- 
3115 // custom set cursor 
3116 void wxPropertyGrid::CustomSetCursor( int type
, bool override 
) 
3118     if ( type 
== m_curcursor 
&& !override 
) return; 
3120     wxCursor
* cursor 
= &wxPG_DEFAULT_CURSOR
; 
3122     if ( type 
== wxCURSOR_SIZEWE 
) 
3123         cursor 
= m_cursorSizeWE
; 
3125     m_canvas
->SetCursor( *cursor 
); 
3130 // ----------------------------------------------------------------------- 
3131 // wxPropertyGrid property selection, editor creation 
3132 // ----------------------------------------------------------------------- 
3135 // This class forwards events from property editor controls to wxPropertyGrid. 
3136 class wxPropertyGridEditorEventForwarder 
: public wxEvtHandler
 
3139     wxPropertyGridEditorEventForwarder( wxPropertyGrid
* propGrid 
) 
3140         : wxEvtHandler(), m_propGrid(propGrid
) 
3144     virtual ~wxPropertyGridEditorEventForwarder() 
3149     bool ProcessEvent( wxEvent
& event 
) 
3154         m_propGrid
->HandleCustomEditorEvent(event
); 
3156         return wxEvtHandler::ProcessEvent(event
); 
3159     wxPropertyGrid
*         m_propGrid
; 
3162 // Setups event handling for child control 
3163 void wxPropertyGrid::SetupChildEventHandling( wxWindow
* argWnd 
) 
3165     wxWindowID id 
= argWnd
->GetId(); 
3167     if ( argWnd 
== m_wndEditor 
) 
3169         argWnd
->Connect(id
, wxEVT_MOTION
, 
3170             wxMouseEventHandler(wxPropertyGrid::OnMouseMoveChild
), 
3172         argWnd
->Connect(id
, wxEVT_LEFT_UP
, 
3173             wxMouseEventHandler(wxPropertyGrid::OnMouseUpChild
), 
3175         argWnd
->Connect(id
, wxEVT_LEFT_DOWN
, 
3176             wxMouseEventHandler(wxPropertyGrid::OnMouseClickChild
), 
3178         argWnd
->Connect(id
, wxEVT_RIGHT_UP
, 
3179             wxMouseEventHandler(wxPropertyGrid::OnMouseRightClickChild
), 
3181         argWnd
->Connect(id
, wxEVT_ENTER_WINDOW
, 
3182             wxMouseEventHandler(wxPropertyGrid::OnMouseEntry
), 
3184         argWnd
->Connect(id
, wxEVT_LEAVE_WINDOW
, 
3185             wxMouseEventHandler(wxPropertyGrid::OnMouseEntry
), 
3189     wxPropertyGridEditorEventForwarder
* forwarder
; 
3190     forwarder 
= new wxPropertyGridEditorEventForwarder(this); 
3191     argWnd
->PushEventHandler(forwarder
); 
3193     argWnd
->Connect(id
, wxEVT_KEY_DOWN
, 
3194         wxCharEventHandler(wxPropertyGrid::OnChildKeyDown
), 
3198 void wxPropertyGrid::FreeEditors() 
3201     // Return focus back to canvas from children (this is required at least for 
3202     // GTK+, which, unlike Windows, clears focus when control is destroyed 
3203     // instead of moving it to closest parent). 
3204     wxWindow
* focus 
= wxWindow::FindFocus(); 
3207         wxWindow
* parent 
= focus
->GetParent(); 
3210             if ( parent 
== m_canvas 
) 
3215             parent 
= parent
->GetParent(); 
3219     // Do not free editors immediately if processing events 
3222         m_wndEditor2
->PopEventHandler(true); 
3223         m_wndEditor2
->Hide(); 
3224         wxPendingDelete
.Append( m_wndEditor2 
); 
3225         m_wndEditor2 
= NULL
; 
3230         m_wndEditor
->PopEventHandler(true); 
3231         m_wndEditor
->Hide(); 
3232         wxPendingDelete
.Append( m_wndEditor 
); 
3237 // Call with NULL to de-select property 
3238 bool wxPropertyGrid::DoSelectProperty( wxPGProperty
* p
, unsigned int flags 
) 
3242         wxLogDebug(wxT("SelectProperty( %s (%s[%i]) )"),p->m_label.c_str(), 
3243             p->m_parent->m_label.c_str(),p->GetIndexInParent()); 
3245         wxLogDebug(wxT("SelectProperty( NULL, -1 )")); 
3248     if ( m_inDoSelectProperty 
) 
3251     m_inDoSelectProperty 
= 1; 
3253     wxPGProperty
* prev 
= m_selected
; 
3257         m_inDoSelectProperty 
= 0; 
3263         wxPrintf( "Selected %s\n", m_selected->GetClassInfo()->GetClassName() ); 
3265         wxPrintf( "None selected\n" ); 
3268         wxPrintf( "P =  %s\n", p->GetClassInfo()->GetClassName() ); 
3270         wxPrintf( "P = NULL\n" ); 
3273     // If we are frozen, then just set the values. 
3276         m_iFlags 
&= ~(wxPG_FL_ABNORMAL_EDITOR
); 
3277         m_editorFocused 
= 0; 
3280         m_pState
->m_selected 
= p
; 
3282         // If frozen, always free controls. But don't worry, as Thaw will 
3283         // recall SelectProperty to recreate them. 
3286         // Prevent any further selection measures in this call 
3292         if ( m_selected 
== p 
&& !(flags 
& wxPG_SEL_FORCE
) ) 
3294             // Only set focus if not deselecting 
3297                 if ( flags 
& wxPG_SEL_FOCUS 
) 
3301                         m_wndEditor
->SetFocus(); 
3302                         m_editorFocused 
= 1; 
3311             m_inDoSelectProperty 
= 0; 
3316         // First, deactivate previous 
3320             OnValidationFailureReset(m_selected
); 
3322             // Must double-check if this is an selected in case of forceswitch 
3325                 if ( !CommitChangesFromEditor(flags
) ) 
3327                     // Validation has failed, so we can't exit the previous editor 
3328                     //::wxMessageBox(_("Please correct the value or press ESC to cancel the edit."), 
3329                     //               _("Invalid Value"),wxOK|wxICON_ERROR); 
3330                     m_inDoSelectProperty 
= 0; 
3339             m_pState
->m_selected 
= NULL
; 
3341             // We need to always fully refresh the grid here 
3344             m_iFlags 
&= ~(wxPG_FL_ABNORMAL_EDITOR
); 
3345             EditorsValueWasNotModified(); 
3348         SetInternalFlag(wxPG_FL_IN_SELECT_PROPERTY
); 
3351         // Then, activate the one given. 
3354             int propY 
= p
->GetY2(m_lineHeight
); 
3356             int splitterX 
= GetSplitterPosition(); 
3357             m_editorFocused 
= 0; 
3359             m_pState
->m_selected 
= p
; 
3360             m_iFlags 
|= wxPG_FL_PRIMARY_FILLS_ENTIRE
; 
3362                 m_iFlags 
&= ~(wxPG_FL_VALIDATION_FAILED
); 
3364             wxASSERT( m_wndEditor 
== NULL 
); 
3367             // Only create editor for non-disabled non-caption 
3368             if ( !p
->IsCategory() && !(p
->m_flags 
& wxPG_PROP_DISABLED
) ) 
3370             // do this for non-caption items 
3374                 // Do we need to paint the custom image, if any? 
3375                 m_iFlags 
&= ~(wxPG_FL_CUR_USES_CUSTOM_IMAGE
); 
3376                 if ( (p
->m_flags 
& wxPG_PROP_CUSTOMIMAGE
) && 
3377                      !p
->GetEditorClass()->CanContainCustomImage() 
3379                     m_iFlags 
|= wxPG_FL_CUR_USES_CUSTOM_IMAGE
; 
3381                 wxRect grect 
= GetEditorWidgetRect(p
, m_selColumn
); 
3382                 wxPoint goodPos 
= grect
.GetPosition(); 
3383             #if wxPG_CREATE_CONTROLS_HIDDEN 
3384                 int coord_adjust 
= m_height 
- goodPos
.y
; 
3385                 goodPos
.y 
+= coord_adjust
; 
3388                 const wxPGEditor
* editor 
= p
->GetEditorClass(); 
3389                 wxCHECK_MSG(editor
, false, 
3390                     wxT("NULL editor class not allowed")); 
3392                 m_iFlags 
&= ~wxPG_FL_FIXED_WIDTH_EDITOR
; 
3394                 wxPGWindowList wndList 
= editor
->CreateControls(this, 
3399                 m_wndEditor 
= wndList
.m_primary
; 
3400                 m_wndEditor2 
= wndList
.m_secondary
; 
3401                 wxWindow
* primaryCtrl 
= GetEditorControl(); 
3404                 // Essentially, primaryCtrl == m_wndEditor 
3407                 // NOTE: It is allowed for m_wndEditor to be NULL - in this case 
3408                 //       value is drawn as normal, and m_wndEditor2 is assumed 
3409                 //       to be a right-aligned button that triggers a separate editorCtrl 
3414                     wxASSERT_MSG( m_wndEditor
->GetParent() == GetPanel(), 
3415                                   wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") ); 
3417                     // Set validator, if any 
3418                 #if wxUSE_VALIDATORS 
3419                     wxValidator
* validator 
= p
->GetValidator(); 
3421                         primaryCtrl
->SetValidator(*validator
); 
3424                     if ( m_wndEditor
->GetSize().y 
> (m_lineHeight
+6) ) 
3425                         m_iFlags 
|= wxPG_FL_ABNORMAL_EDITOR
; 
3427                     // If it has modified status, use bold font 
3428                     // (must be done before capturing m_ctrlXAdjust) 
3429                     if ( (p
->m_flags 
& wxPG_PROP_MODIFIED
) && (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
3430                         SetCurControlBoldFont(); 
3433                     // Fix TextCtrl indentation 
3434                 #if defined(__WXMSW__) && !defined(__WXWINCE__) 
3435                     wxTextCtrl
* tc 
= NULL
; 
3436                     if ( primaryCtrl
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) ) 
3437                         tc 
= ((wxOwnerDrawnComboBox
*)primaryCtrl
)->GetTextCtrl(); 
3439                         tc 
= wxDynamicCast(primaryCtrl
, wxTextCtrl
); 
3441                         ::SendMessage(GetHwndOf(tc
), EM_SETMARGINS
, EC_LEFTMARGIN 
| EC_RIGHTMARGIN
, MAKELONG(0, 0)); 
3444                     // Store x relative to splitter (we'll need it). 
3445                     m_ctrlXAdjust 
= m_wndEditor
->GetPosition().x 
- splitterX
; 
3447                     // Check if background clear is not necessary 
3448                     wxPoint pos 
= m_wndEditor
->GetPosition(); 
3449                     if ( pos
.x 
> (splitterX
+1) || pos
.y 
> propY 
) 
3451                         m_iFlags 
&= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE
); 
3454                     m_wndEditor
->SetSizeHints(3, 3); 
3456                 #if wxPG_CREATE_CONTROLS_HIDDEN 
3457                     m_wndEditor
->Show(false); 
3458                     m_wndEditor
->Freeze(); 
3460                     goodPos 
= m_wndEditor
->GetPosition(); 
3461                     goodPos
.y 
-= coord_adjust
; 
3462                     m_wndEditor
->Move( goodPos 
); 
3465                     SetupChildEventHandling(primaryCtrl
); 
3467                     // Focus and select all (wxTextCtrl, wxComboBox etc) 
3468                     if ( flags 
& wxPG_SEL_FOCUS 
) 
3470                         primaryCtrl
->SetFocus(); 
3472                         p
->GetEditorClass()->OnFocus(p
, primaryCtrl
); 
3478                     wxASSERT_MSG( m_wndEditor2
->GetParent() == GetPanel(), 
3479                                   wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") ); 
3481                     // Get proper id for wndSecondary 
3482                     m_wndSecId 
= m_wndEditor2
->GetId(); 
3483                     wxWindowList children 
= m_wndEditor2
->GetChildren(); 
3484                     wxWindowList::iterator node 
= children
.begin(); 
3485                     if ( node 
!= children
.end() ) 
3486                         m_wndSecId 
= ((wxWindow
*)*node
)->GetId(); 
3488                     m_wndEditor2
->SetSizeHints(3,3); 
3490                 #if wxPG_CREATE_CONTROLS_HIDDEN 
3491                     wxRect sec_rect 
= m_wndEditor2
->GetRect(); 
3492                     sec_rect
.y 
-= coord_adjust
; 
3494                     // Fine tuning required to fix "oversized" 
3495                     // button disappearance bug. 
3496                     if ( sec_rect
.y 
< 0 ) 
3498                         sec_rect
.height 
+= sec_rect
.y
; 
3501                     m_wndEditor2
->SetSize( sec_rect 
); 
3503                     m_wndEditor2
->Show(); 
3505                     SetupChildEventHandling(m_wndEditor2
); 
3507                     // If no primary editor, focus to button to allow 
3508                     // it to interprete ENTER etc. 
3509                     // NOTE: Due to problems focusing away from it, this 
3510                     //       has been disabled. 
3512                     if ( (flags & wxPG_SEL_FOCUS) && !m_wndEditor ) 
3513                         m_wndEditor2->SetFocus(); 
3517                 if ( flags 
& wxPG_SEL_FOCUS 
) 
3518                     m_editorFocused 
= 1; 
3523                 // Make sure focus is in grid canvas (important for wxGTK, at least) 
3527             EditorsValueWasNotModified(); 
3529             // If it's inside collapsed section, expand parent, scroll, etc. 
3530             // Also, if it was partially visible, scroll it into view. 
3531             if ( !(flags 
& wxPG_SEL_NONVISIBLE
) ) 
3536             #if wxPG_CREATE_CONTROLS_HIDDEN 
3537                 m_wndEditor
->Thaw(); 
3539                 m_wndEditor
->Show(true); 
3546             // Make sure focus is in grid canvas 
3550         ClearInternalFlag(wxPG_FL_IN_SELECT_PROPERTY
); 
3556     // Show help text in status bar. 
3557     //   (if found and grid not embedded in manager with help box and 
3558     //    style wxPG_EX_HELP_AS_TOOLTIPS is not used). 
3561     if ( !(GetExtraStyle() & wxPG_EX_HELP_AS_TOOLTIPS
) ) 
3563         wxStatusBar
* statusbar 
= NULL
; 
3564         if ( !(m_iFlags 
& wxPG_FL_NOSTATUSBARHELP
) ) 
3566             wxFrame
* frame 
= wxDynamicCast(::wxGetTopLevelParent(this),wxFrame
); 
3568                 statusbar 
= frame
->GetStatusBar(); 
3573             const wxString
* pHelpString 
= (const wxString
*) NULL
; 
3577                 pHelpString 
= &p
->GetHelpString(); 
3578                 if ( pHelpString
->length() ) 
3580                     // Set help box text. 
3581                     statusbar
->SetStatusText( *pHelpString 
); 
3582                     m_iFlags 
|= wxPG_FL_STRING_IN_STATUSBAR
; 
3586             if ( (!pHelpString 
|| !pHelpString
->length()) && 
3587                  (m_iFlags 
& wxPG_FL_STRING_IN_STATUSBAR
) ) 
3589                 // Clear help box - but only if it was written 
3590                 // by us at previous time. 
3591                 statusbar
->SetStatusText( m_emptyString 
); 
3592                 m_iFlags 
&= ~(wxPG_FL_STRING_IN_STATUSBAR
); 
3598     m_inDoSelectProperty 
= 0; 
3600     // call wx event handler (here so that it also occurs on deselection) 
3601     SendEvent( wxEVT_PG_SELECTED
, m_selected
, NULL
, flags 
); 
3606 // ----------------------------------------------------------------------- 
3608 bool wxPropertyGrid::UnfocusEditor() 
3610     if ( !m_selected 
|| !m_wndEditor 
|| m_frozen 
) 
3613     if ( !CommitChangesFromEditor(0) ) 
3617     DrawItem(m_selected
); 
3622 // ----------------------------------------------------------------------- 
3624 void wxPropertyGrid::RefreshEditor() 
3626     wxPGProperty
* p 
= m_selected
; 
3630     wxWindow
* wnd 
= GetEditorControl(); 
3634     // Set editor font boldness - must do this before 
3635     // calling UpdateControl(). 
3636     if ( HasFlag(wxPG_BOLD_MODIFIED
) ) 
3638         if ( p
->HasFlag(wxPG_PROP_MODIFIED
) ) 
3639             wnd
->SetFont(GetCaptionFont()); 
3641             wnd
->SetFont(GetFont()); 
3644     const wxPGEditor
* editorClass 
= p
->GetEditorClass(); 
3646     editorClass
->UpdateControl(p
, wnd
); 
3648     if ( p
->IsValueUnspecified() ) 
3649         editorClass 
->SetValueToUnspecified(p
, wnd
); 
3652 // ----------------------------------------------------------------------- 
3654 // This method is not inline because it called dozens of times 
3655 // (i.e. two-arg function calls create smaller code size). 
3656 bool wxPropertyGrid::DoClearSelection() 
3658     return DoSelectProperty(NULL
); 
3661 // ----------------------------------------------------------------------- 
3662 // wxPropertyGrid expand/collapse state 
3663 // ----------------------------------------------------------------------- 
3665 bool wxPropertyGrid::DoCollapse( wxPGProperty
* p
, bool sendEvents 
) 
3667     wxPGProperty
* pwc 
= wxStaticCast(p
, wxPGProperty
); 
3669     // If active editor was inside collapsed section, then disable it 
3670     if ( m_selected 
&& m_selected
->IsSomeParent(p
) ) 
3672         ClearSelection(false); 
3675     // Store dont-center-splitter flag 'cause we need to temporarily set it 
3676     wxUint32 old_flag 
= m_iFlags 
& wxPG_FL_DONT_CENTER_SPLITTER
; 
3677     m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
3679     bool res 
= m_pState
->DoCollapse(pwc
); 
3684             SendEvent( wxEVT_PG_ITEM_COLLAPSED
, p 
); 
3686         RecalculateVirtualSize(); 
3688         // Redraw etc. only if collapsed was visible. 
3689         if (pwc
->IsVisible() && 
3691             ( !pwc
->IsCategory() || !(m_windowStyle 
& wxPG_HIDE_CATEGORIES
) ) ) 
3693             // When item is collapsed so that scrollbar would move, 
3694             // graphics mess is about (unless we redraw everything). 
3699     // Clear dont-center-splitter flag if it wasn't set 
3700     m_iFlags 
= (m_iFlags 
& ~wxPG_FL_DONT_CENTER_SPLITTER
) | old_flag
; 
3705 // ----------------------------------------------------------------------- 
3707 bool wxPropertyGrid::DoExpand( wxPGProperty
* p
, bool sendEvents 
) 
3709     wxCHECK_MSG( p
, false, wxT("invalid property id") ); 
3711     wxPGProperty
* pwc 
= (wxPGProperty
*)p
; 
3713     // Store dont-center-splitter flag 'cause we need to temporarily set it 
3714     wxUint32 old_flag 
= m_iFlags 
& wxPG_FL_DONT_CENTER_SPLITTER
; 
3715     m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
3717     bool res 
= m_pState
->DoExpand(pwc
); 
3722             SendEvent( wxEVT_PG_ITEM_EXPANDED
, p 
); 
3724         RecalculateVirtualSize(); 
3726         // Redraw etc. only if expanded was visible. 
3727         if ( pwc
->IsVisible() && !m_frozen 
&& 
3728              ( !pwc
->IsCategory() || !(m_windowStyle 
& wxPG_HIDE_CATEGORIES
) ) 
3732         #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
3735             DrawItems(pwc
, NULL
); 
3740     // Clear dont-center-splitter flag if it wasn't set 
3741     m_iFlags 
= (m_iFlags 
& ~wxPG_FL_DONT_CENTER_SPLITTER
) | old_flag
; 
3746 // ----------------------------------------------------------------------- 
3748 bool wxPropertyGrid::DoHideProperty( wxPGProperty
* p
, bool hide
, int flags 
) 
3751         return m_pState
->DoHideProperty(p
, hide
, flags
); 
3754          ( m_selected 
== p 
|| m_selected
->IsSomeParent(p
) ) 
3757             ClearSelection(false); 
3760     m_pState
->DoHideProperty(p
, hide
, flags
); 
3762     RecalculateVirtualSize(); 
3769 // ----------------------------------------------------------------------- 
3770 // wxPropertyGrid size related methods 
3771 // ----------------------------------------------------------------------- 
3773 void wxPropertyGrid::RecalculateVirtualSize( int forceXPos 
) 
3775     if ( (m_iFlags 
& wxPG_FL_RECALCULATING_VIRTUAL_SIZE
) || m_frozen 
) 
3779     // If virtual height was changed, then recalculate editor control position(s) 
3780     if ( m_pState
->m_vhCalcPending 
) 
3781         CorrectEditorWidgetPosY(); 
3783     m_pState
->EnsureVirtualHeight(); 
3786     int by1 
= m_pState
->GetVirtualHeight(); 
3787     int by2 
= m_pState
->GetActualVirtualHeight(); 
3790         wxString s 
= wxString::Format(wxT("VirtualHeight=%i, ActualVirtualHeight=%i, should match!"), by1
, by2
); 
3791         wxFAIL_MSG(s
.c_str()); 
3796     m_iFlags 
|= wxPG_FL_RECALCULATING_VIRTUAL_SIZE
; 
3798     int x 
= m_pState
->m_width
; 
3799     int y 
= m_pState
->m_virtualHeight
; 
3802     GetClientSize(&width
,&height
); 
3804     // Now adjust virtual size. 
3805         SetVirtualSize(x
, y
); 
3811     // Adjust scrollbars 
3812     if ( HasVirtualWidth() ) 
3814         xAmount 
= x
/wxPG_PIXELS_PER_UNIT
; 
3815         xPos 
= GetScrollPos( wxHORIZONTAL 
); 
3818     if ( forceXPos 
!= -1 ) 
3821     else if ( xPos 
> (xAmount
-(width
/wxPG_PIXELS_PER_UNIT
)) ) 
3824     int yAmount 
= (y
+wxPG_PIXELS_PER_UNIT
+2)/wxPG_PIXELS_PER_UNIT
; 
3825     int yPos 
= GetScrollPos( wxVERTICAL 
); 
3827     SetScrollbars( wxPG_PIXELS_PER_UNIT
, wxPG_PIXELS_PER_UNIT
, 
3828                    xAmount
, yAmount
, xPos
, yPos
, true ); 
3830     // Must re-get size now 
3831     GetClientSize(&width
,&height
); 
3833     if ( !HasVirtualWidth() ) 
3835         m_pState
->SetVirtualWidth(width
); 
3842     m_canvas
->SetSize( x
, y 
); 
3844     m_pState
->CheckColumnWidths(); 
3847         CorrectEditorWidgetSizeX(); 
3849     m_iFlags 
&= ~wxPG_FL_RECALCULATING_VIRTUAL_SIZE
; 
3852 // ----------------------------------------------------------------------- 
3854 void wxPropertyGrid::OnResize( wxSizeEvent
& event 
) 
3856     if ( !(m_iFlags 
& wxPG_FL_INITIALIZED
) ) 
3860     GetClientSize(&width
,&height
); 
3865 #if wxPG_DOUBLE_BUFFER 
3866     if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING
) ) 
3868         int dblh 
= (m_lineHeight
*2); 
3869         if ( !m_doubleBuffer 
) 
3871             // Create double buffer bitmap to draw on, if none 
3872             int w 
= (width
>250)?width
:250; 
3873             int h 
= height 
+ dblh
; 
3875             m_doubleBuffer 
= new wxBitmap( w
, h 
); 
3879             int w 
= m_doubleBuffer
->GetWidth(); 
3880             int h 
= m_doubleBuffer
->GetHeight(); 
3882             // Double buffer must be large enough 
3883             if ( w 
< width 
|| h 
< (height
+dblh
) ) 
3885                 if ( w 
< width 
) w 
= width
; 
3886                 if ( h 
< (height
+dblh
) ) h 
= height 
+ dblh
; 
3887                 delete m_doubleBuffer
; 
3888                 m_doubleBuffer 
= new wxBitmap( w
, h 
); 
3895     m_pState
->OnClientWidthChange( width
, event
.GetSize().x 
- m_ncWidth
, true ); 
3896     m_ncWidth 
= event
.GetSize().x
; 
3900         if ( m_pState
->m_itemsAdded 
) 
3901             PrepareAfterItemsAdded(); 
3903             // Without this, virtual size (atleast under wxGTK) will be skewed 
3904             RecalculateVirtualSize(); 
3910 // ----------------------------------------------------------------------- 
3912 void wxPropertyGrid::SetVirtualWidth( int width 
) 
3916         // Disable virtual width 
3917         width 
= GetClientSize().x
; 
3918         ClearInternalFlag(wxPG_FL_HAS_VIRTUAL_WIDTH
); 
3922         // Enable virtual width 
3923         SetInternalFlag(wxPG_FL_HAS_VIRTUAL_WIDTH
); 
3925     m_pState
->SetVirtualWidth( width 
); 
3928 void wxPropertyGrid::SetFocusOnCanvas() 
3930     m_canvas
->SetFocusIgnoringChildren(); 
3931     m_editorFocused 
= 0; 
3934 // ----------------------------------------------------------------------- 
3935 // wxPropertyGrid mouse event handling 
3936 // ----------------------------------------------------------------------- 
3938 // selFlags uses same values DoSelectProperty's flags 
3939 // Returns true if event was vetoed. 
3940 bool wxPropertyGrid::SendEvent( int eventType
, wxPGProperty
* p
, wxVariant
* pValue
, unsigned int WXUNUSED(selFlags
) ) 
3942     // Send property grid event of specific type and with specific property 
3943     wxPropertyGridEvent 
evt( eventType
, m_eventObject
->GetId() ); 
3944     evt
.SetPropertyGrid(this); 
3945     evt
.SetEventObject(m_eventObject
); 
3949         evt
.SetCanVeto(true); 
3950         evt
.SetupValidationInfo(); 
3951         m_validationInfo
.m_pValue 
= pValue
; 
3953     wxEvtHandler
* evtHandler 
= m_eventObject
->GetEventHandler(); 
3955     evtHandler
->ProcessEvent(evt
); 
3957     return evt
.WasVetoed(); 
3960 // ----------------------------------------------------------------------- 
3962 // Return false if should be skipped 
3963 bool wxPropertyGrid::HandleMouseClick( int x
, unsigned int y
, wxMouseEvent 
&event 
) 
3967     // Need to set focus? 
3968     if ( !(m_iFlags 
& wxPG_FL_FOCUSED
) ) 
3973     wxPropertyGridPageState
* state 
= m_pState
; 
3975     int splitterHitOffset
; 
3976     int columnHit 
= state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
3978     wxPGProperty
* p 
= DoGetItemAtY(y
); 
3982         int depth 
= (int)p
->GetDepth() - 1; 
3984         int marginEnds 
= m_marginWidth 
+ ( depth 
* m_subgroup_extramargin 
); 
3986         if ( x 
>= marginEnds 
) 
3990             if ( p
->IsCategory() ) 
3992                 // This is category. 
3993                 wxPropertyCategory
* pwc 
= (wxPropertyCategory
*)p
; 
3995                 int textX 
= m_marginWidth 
+ ((unsigned int)((pwc
->m_depth
-1)*m_subgroup_extramargin
)); 
3997                 // Expand, collapse, activate etc. if click on text or left of splitter. 
4000                      ( x 
< (textX
+pwc
->GetTextExtent(this, m_captionFont
)+(wxPG_CAPRECTXMARGIN
*2)) || 
4005                     if ( !DoSelectProperty( p 
) ) 
4008                     // On double-click, expand/collapse. 
4009                     if ( event
.ButtonDClick() && !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
4011                         if ( pwc
->IsExpanded() ) DoCollapse( p
, true ); 
4012                         else DoExpand( p
, true ); 
4016             else if ( splitterHit 
== -1 ) 
4019                 unsigned int selFlag 
= 0; 
4020                 if ( columnHit 
== 1 ) 
4022                     m_iFlags 
|= wxPG_FL_ACTIVATION_BY_CLICK
; 
4023                     selFlag 
= wxPG_SEL_FOCUS
; 
4025                 if ( !DoSelectProperty( p
, selFlag 
) ) 
4028                 m_iFlags 
&= ~(wxPG_FL_ACTIVATION_BY_CLICK
); 
4030                 if ( p
->GetChildCount() && !p
->IsCategory() ) 
4031                     // On double-click, expand/collapse. 
4032                     if ( event
.ButtonDClick() && !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
4034                         wxPGProperty
* pwc 
= (wxPGProperty
*)p
; 
4035                         if ( pwc
->IsExpanded() ) DoCollapse( p
, true ); 
4036                         else DoExpand( p
, true ); 
4043             // click on splitter 
4044                 if ( !(m_windowStyle 
& wxPG_STATIC_SPLITTER
) ) 
4046                     if ( event
.GetEventType() == wxEVT_LEFT_DCLICK 
) 
4048                         // Double-clicking the splitter causes auto-centering 
4049                         CenterSplitter( true ); 
4051                     else if ( m_dragStatus 
== 0 ) 
4054                     // Begin draggin the splitter 
4058                             // Changes must be committed here or the 
4059                             // value won't be drawn correctly 
4060                             if ( !CommitChangesFromEditor() ) 
4063                             m_wndEditor
->Show ( false ); 
4066                         if ( !(m_iFlags 
& wxPG_FL_MOUSE_CAPTURED
) ) 
4068                             m_canvas
->CaptureMouse(); 
4069                             m_iFlags 
|= wxPG_FL_MOUSE_CAPTURED
; 
4073                         m_draggedSplitter 
= splitterHit
; 
4074                         m_dragOffset 
= splitterHitOffset
; 
4076                         wxClientDC 
dc(m_canvas
); 
4078                     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
4079                         // Fixes button disappearance bug 
4081                             m_wndEditor2
->Show ( false ); 
4084                         m_startingSplitterX 
= x 
- splitterHitOffset
; 
4092             if ( p
->GetChildCount() ) 
4094                 int nx 
= x 
+ m_marginWidth 
- marginEnds
; // Normalize x. 
4096                 if ( (nx 
>= m_gutterWidth 
&& nx 
< (m_gutterWidth
+m_iconWidth
)) ) 
4098                     int y2 
= y 
% m_lineHeight
; 
4099                     if ( (y2 
>= m_buttonSpacingY 
&& y2 
< (m_buttonSpacingY
+m_iconHeight
)) ) 
4101                         // On click on expander button, expand/collapse 
4102                         if ( ((wxPGProperty
*)p
)->IsExpanded() ) 
4103                             DoCollapse( p
, true ); 
4105                             DoExpand( p
, true ); 
4114 // ----------------------------------------------------------------------- 
4116 bool wxPropertyGrid::HandleMouseRightClick( int WXUNUSED(x
), unsigned int WXUNUSED(y
), 
4117                                             wxMouseEvent
& WXUNUSED(event
) ) 
4121         // Select property here as well 
4122         wxPGProperty
* p 
= m_propHover
; 
4123         if ( p 
!= m_selected 
) 
4124             DoSelectProperty( p 
); 
4126         // Send right click event. 
4127         SendEvent( wxEVT_PG_RIGHT_CLICK
, p 
); 
4134 // ----------------------------------------------------------------------- 
4136 bool wxPropertyGrid::HandleMouseDoubleClick( int WXUNUSED(x
), unsigned int WXUNUSED(y
), 
4137                                              wxMouseEvent
& WXUNUSED(event
) ) 
4141         // Select property here as well 
4142         wxPGProperty
* p 
= m_propHover
; 
4144         if ( p 
!= m_selected 
) 
4145             DoSelectProperty( p 
); 
4147         // Send double-click event. 
4148         SendEvent( wxEVT_PG_DOUBLE_CLICK
, m_propHover 
); 
4155 // ----------------------------------------------------------------------- 
4157 #if wxPG_SUPPORT_TOOLTIPS 
4159 void wxPropertyGrid::SetToolTip( const wxString
& tipString 
) 
4161     if ( tipString
.length() ) 
4163         m_canvas
->SetToolTip(tipString
); 
4167     #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4168         m_canvas
->SetToolTip( m_emptyString 
); 
4170         m_canvas
->SetToolTip( NULL 
); 
4175 #endif // #if wxPG_SUPPORT_TOOLTIPS 
4177 // ----------------------------------------------------------------------- 
4179 // Return false if should be skipped 
4180 bool wxPropertyGrid::HandleMouseMove( int x
, unsigned int y
, wxMouseEvent 
&event 
) 
4182     // Safety check (needed because mouse capturing may 
4183     // otherwise freeze the control) 
4184     if ( m_dragStatus 
> 0 && !event
.Dragging() ) 
4186         HandleMouseUp(x
,y
,event
); 
4189     wxPropertyGridPageState
* state 
= m_pState
; 
4191     int splitterHitOffset
; 
4192     int columnHit 
= state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
4193     int splitterX 
= x 
- splitterHitOffset
; 
4195     if ( m_dragStatus 
> 0 ) 
4197         if ( x 
> (m_marginWidth 
+ wxPG_DRAG_MARGIN
) && 
4198              x 
< (m_pState
->m_width 
- wxPG_DRAG_MARGIN
) ) 
4201             int newSplitterX 
= x 
- m_dragOffset
; 
4202             int splitterX 
= x 
- splitterHitOffset
; 
4204             // Splitter redraw required? 
4205             if ( newSplitterX 
!= splitterX 
) 
4208                 SetInternalFlag(wxPG_FL_DONT_CENTER_SPLITTER
); 
4209                 state
->DoSetSplitterPosition( newSplitterX
, m_draggedSplitter
, false ); 
4210                 state
->m_fSplitterX 
= (float) newSplitterX
; 
4213                     CorrectEditorWidgetSizeX(); 
4227         int ih 
= m_lineHeight
; 
4230     #if wxPG_SUPPORT_TOOLTIPS 
4231         wxPGProperty
* prevHover 
= m_propHover
; 
4232         unsigned char prevSide 
= m_mouseSide
; 
4234         int curPropHoverY 
= y 
- (y 
% ih
); 
4236         // On which item it hovers 
4239              ( sy 
< m_propHoverY 
|| sy 
>= (m_propHoverY
+ih
) ) 
4242             // Mouse moves on another property 
4244             m_propHover 
= DoGetItemAtY(y
); 
4245             m_propHoverY 
= curPropHoverY
; 
4248             SendEvent( wxEVT_PG_HIGHLIGHTED
, m_propHover 
); 
4251     #if wxPG_SUPPORT_TOOLTIPS 
4252         // Store which side we are on 
4254         if ( columnHit 
== 1 ) 
4256         else if ( columnHit 
== 0 ) 
4260         // If tooltips are enabled, show label or value as a tip 
4261         // in case it doesn't otherwise show in full length. 
4263         if ( m_windowStyle 
& wxPG_TOOLTIPS 
) 
4265             wxToolTip
* tooltip 
= m_canvas
->GetToolTip(); 
4267             if ( m_propHover 
!= prevHover 
|| prevSide 
!= m_mouseSide 
) 
4269                 if ( m_propHover 
&& !m_propHover
->IsCategory() ) 
4272                     if ( GetExtraStyle() & wxPG_EX_HELP_AS_TOOLTIPS 
) 
4274                         // Show help string as a tooltip 
4275                         wxString tipString 
= m_propHover
->GetHelpString(); 
4277                         SetToolTip(tipString
); 
4281                         // Show cropped value string as a tooltip 
4285                         if ( m_mouseSide 
== 1 ) 
4287                             tipString 
= m_propHover
->m_label
; 
4288                             space 
= splitterX
-m_marginWidth
-3; 
4290                         else if ( m_mouseSide 
== 2 ) 
4292                             tipString 
= m_propHover
->GetDisplayedString(); 
4294                             space 
= m_width 
- splitterX
; 
4295                             if ( m_propHover
->m_flags 
& wxPG_PROP_CUSTOMIMAGE 
) 
4296                                 space 
-= wxPG_CUSTOM_IMAGE_WIDTH 
+ wxCC_CUSTOM_IMAGE_MARGIN1 
+ wxCC_CUSTOM_IMAGE_MARGIN2
; 
4302                             GetTextExtent( tipString
, &tw
, &th
, 0, 0, &m_font 
); 
4305                                 SetToolTip( tipString 
); 
4312                             #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4313                                 m_canvas
->SetToolTip( m_emptyString 
); 
4315                                 m_canvas
->SetToolTip( NULL 
); 
4326                     #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4327                         m_canvas
->SetToolTip( m_emptyString 
); 
4329                         m_canvas
->SetToolTip( NULL 
); 
4337         if ( splitterHit 
== -1 || 
4339              HasFlag(wxPG_STATIC_SPLITTER
) ) 
4341             // hovering on something else 
4342             if ( m_curcursor 
!= wxCURSOR_ARROW 
) 
4343                 CustomSetCursor( wxCURSOR_ARROW 
); 
4347             // Do not allow splitter cursor on caption items. 
4348             // (also not if we were dragging and its started 
4349             // outside the splitter region) 
4351             if ( !m_propHover
->IsCategory() && 
4355                 // hovering on splitter 
4357                 // NB: Condition disabled since MouseLeave event (from the editor control) cannot be 
4358                 //     reliably detected. 
4359                 //if ( m_curcursor != wxCURSOR_SIZEWE ) 
4360                 CustomSetCursor( wxCURSOR_SIZEWE
, true ); 
4366                 // hovering on something else 
4367                 if ( m_curcursor 
!= wxCURSOR_ARROW 
) 
4368                     CustomSetCursor( wxCURSOR_ARROW 
); 
4375 // ----------------------------------------------------------------------- 
4377 // Also handles Leaving event 
4378 bool wxPropertyGrid::HandleMouseUp( int x
, unsigned int WXUNUSED(y
), 
4379                                     wxMouseEvent 
&WXUNUSED(event
) ) 
4381     wxPropertyGridPageState
* state 
= m_pState
; 
4385     int splitterHitOffset
; 
4386     state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
4388     // No event type check - basicly calling this method should 
4389     // just stop dragging. 
4390     // Left up after dragged? 
4391     if ( m_dragStatus 
>= 1 ) 
4394     // End Splitter Dragging 
4396         // DO NOT ENABLE FOLLOWING LINE! 
4397         // (it is only here as a reminder to not to do it) 
4400         // Disable splitter auto-centering 
4401         m_iFlags 
|= wxPG_FL_DONT_CENTER_SPLITTER
; 
4403         // This is necessary to return cursor 
4404         if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
4406             m_canvas
->ReleaseMouse(); 
4407             m_iFlags 
&= ~(wxPG_FL_MOUSE_CAPTURED
); 
4410         // Set back the default cursor, if necessary 
4411         if ( splitterHit 
== -1 || 
4414             CustomSetCursor( wxCURSOR_ARROW 
); 
4419         // Control background needs to be cleared 
4420         if ( !(m_iFlags 
& wxPG_FL_PRIMARY_FILLS_ENTIRE
) && m_selected 
) 
4421             DrawItem( m_selected 
); 
4425             m_wndEditor
->Show ( true ); 
4428     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
4429         // Fixes button disappearance bug 
4431             m_wndEditor2
->Show ( true ); 
4434         // This clears the focus. 
4435         m_editorFocused 
= 0; 
4441 // ----------------------------------------------------------------------- 
4443 bool wxPropertyGrid::OnMouseCommon( wxMouseEvent
& event
, int* px
, int* py 
) 
4445     int splitterX 
= GetSplitterPosition(); 
4448     //CalcUnscrolledPosition( event.m_x, event.m_y, &ux, &uy ); 
4452     wxWindow
* wnd 
= GetEditorControl(); 
4454     // Hide popup on clicks 
4455     if ( event
.GetEventType() != wxEVT_MOTION 
) 
4456         if ( wnd 
&& wnd
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) ) 
4458             ((wxOwnerDrawnComboBox
*)wnd
)->HidePopup(); 
4464     if ( wnd 
== NULL 
|| m_dragStatus 
|| 
4466            ux 
<= (splitterX 
+ wxPG_SPLITTERX_DETECTMARGIN2
) || 
4467            ux 
>= (r
.x
+r
.width
) || 
4469            event
.m_y 
>= (r
.y
+r
.height
) 
4479         if ( m_curcursor 
!= wxCURSOR_ARROW 
) CustomSetCursor ( wxCURSOR_ARROW 
); 
4484 // ----------------------------------------------------------------------- 
4486 void wxPropertyGrid::OnMouseClick( wxMouseEvent 
&event 
) 
4489     if ( OnMouseCommon( event
, &x
, &y 
) ) 
4491         HandleMouseClick(x
,y
,event
); 
4496 // ----------------------------------------------------------------------- 
4498 void wxPropertyGrid::OnMouseRightClick( wxMouseEvent 
&event 
) 
4501     CalcUnscrolledPosition( event
.m_x
, event
.m_y
, &x
, &y 
); 
4502     HandleMouseRightClick(x
,y
,event
); 
4506 // ----------------------------------------------------------------------- 
4508 void wxPropertyGrid::OnMouseDoubleClick( wxMouseEvent 
&event 
) 
4510     // Always run standard mouse-down handler as well 
4511     OnMouseClick(event
); 
4514     CalcUnscrolledPosition( event
.m_x
, event
.m_y
, &x
, &y 
); 
4515     HandleMouseDoubleClick(x
,y
,event
); 
4519 // ----------------------------------------------------------------------- 
4521 void wxPropertyGrid::OnMouseMove( wxMouseEvent 
&event 
) 
4524     if ( OnMouseCommon( event
, &x
, &y 
) ) 
4526         HandleMouseMove(x
,y
,event
); 
4531 // ----------------------------------------------------------------------- 
4533 void wxPropertyGrid::OnMouseMoveBottom( wxMouseEvent
& WXUNUSED(event
) ) 
4535     // Called when mouse moves in the empty space below the properties. 
4536     CustomSetCursor( wxCURSOR_ARROW 
); 
4539 // ----------------------------------------------------------------------- 
4541 void wxPropertyGrid::OnMouseUp( wxMouseEvent 
&event 
) 
4544     if ( OnMouseCommon( event
, &x
, &y 
) ) 
4546         HandleMouseUp(x
,y
,event
); 
4551 // ----------------------------------------------------------------------- 
4553 void wxPropertyGrid::OnMouseEntry( wxMouseEvent 
&event 
) 
4555     // This may get called from child control as well, so event's 
4556     // mouse position cannot be relied on. 
4558     if ( event
.Entering() ) 
4560         if ( !(m_iFlags 
& wxPG_FL_MOUSE_INSIDE
) ) 
4562             // TODO: Fix this (detect parent and only do 
4563             //   cursor trick if it is a manager). 
4564             wxASSERT( GetParent() ); 
4565             GetParent()->SetCursor(wxNullCursor
); 
4567             m_iFlags 
|= wxPG_FL_MOUSE_INSIDE
; 
4570             GetParent()->SetCursor(wxNullCursor
); 
4572     else if ( event
.Leaving() ) 
4574         // Without this, wxSpinCtrl editor will sometimes have wrong cursor 
4575         m_canvas
->SetCursor( wxNullCursor 
); 
4577         // Get real cursor position 
4578         wxPoint pt 
= ScreenToClient(::wxGetMousePosition()); 
4580         if ( ( pt
.x 
<= 0 || pt
.y 
<= 0 || pt
.x 
>= m_width 
|| pt
.y 
>= m_height 
) ) 
4583                 if ( (m_iFlags 
& wxPG_FL_MOUSE_INSIDE
) ) 
4585                     m_iFlags 
&= ~(wxPG_FL_MOUSE_INSIDE
); 
4589                     wxPropertyGrid::HandleMouseUp ( -1, 10000, event 
); 
4597 // ----------------------------------------------------------------------- 
4599 // Common code used by various OnMouseXXXChild methods. 
4600 bool wxPropertyGrid::OnMouseChildCommon( wxMouseEvent 
&event
, int* px
, int *py 
) 
4602     wxWindow
* topCtrlWnd 
= (wxWindow
*)event
.GetEventObject(); 
4603     wxASSERT( topCtrlWnd 
); 
4605     event
.GetPosition(&x
,&y
); 
4607     int splitterX 
= GetSplitterPosition(); 
4609     wxRect r 
= topCtrlWnd
->GetRect(); 
4610     if ( !m_dragStatus 
&& 
4611          x 
> (splitterX
-r
.x
+wxPG_SPLITTERX_DETECTMARGIN2
) && 
4612          y 
>= 0 && y 
< r
.height \
 
4615         if ( m_curcursor 
!= wxCURSOR_ARROW 
) CustomSetCursor ( wxCURSOR_ARROW 
); 
4620         CalcUnscrolledPosition( event
.m_x 
+ r
.x
, event
.m_y 
+ r
.y
, \
 
4627 void wxPropertyGrid::OnMouseClickChild( wxMouseEvent 
&event 
) 
4630     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
4632         bool res 
= HandleMouseClick(x
,y
,event
); 
4633         if ( !res 
) event
.Skip(); 
4637 void wxPropertyGrid::OnMouseRightClickChild( wxMouseEvent 
&event 
) 
4640     wxASSERT( m_wndEditor 
); 
4641     // These coords may not be exact (about +-2), 
4642     // but that should not matter (right click is about item, not position). 
4643     wxPoint pt 
= m_wndEditor
->GetPosition(); 
4644     CalcUnscrolledPosition( event
.m_x 
+ pt
.x
, event
.m_y 
+ pt
.y
, &x
, &y 
); 
4645     wxASSERT( m_selected 
); 
4646     m_propHover 
= m_selected
; 
4647     bool res 
= HandleMouseRightClick(x
,y
,event
); 
4648     if ( !res 
) event
.Skip(); 
4651 void wxPropertyGrid::OnMouseMoveChild( wxMouseEvent 
&event 
) 
4654     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
4656         bool res 
= HandleMouseMove(x
,y
,event
); 
4657         if ( !res 
) event
.Skip(); 
4661 void wxPropertyGrid::OnMouseUpChild( wxMouseEvent 
&event 
) 
4664     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
4666         bool res 
= HandleMouseUp(x
,y
,event
); 
4667         if ( !res 
) event
.Skip(); 
4671 // ----------------------------------------------------------------------- 
4672 // wxPropertyGrid keyboard event handling 
4673 // ----------------------------------------------------------------------- 
4675 int wxPropertyGrid::KeyEventToActions(wxKeyEvent 
&event
, int* pSecond
) const 
4677     // Translates wxKeyEvent to wxPG_ACTION_XXX 
4679     int keycode 
= event
.GetKeyCode(); 
4680     int modifiers 
= event
.GetModifiers(); 
4682     wxASSERT( !(modifiers
&~(0xFFFF)) ); 
4684     int hashMapKey 
= (keycode 
& 0xFFFF) | ((modifiers 
& 0xFFFF) << 16); 
4686     wxPGHashMapI2I::const_iterator it 
= m_actionTriggers
.find(hashMapKey
); 
4688     if ( it 
== m_actionTriggers
.end() ) 
4693         int second 
= (it
->second
>>16) & 0xFFFF; 
4697     return (it
->second 
& 0xFFFF); 
4700 void wxPropertyGrid::AddActionTrigger( int action
, int keycode
, int modifiers 
) 
4702     wxASSERT( !(modifiers
&~(0xFFFF)) ); 
4704     int hashMapKey 
= (keycode 
& 0xFFFF) | ((modifiers 
& 0xFFFF) << 16); 
4706     wxPGHashMapI2I::iterator it 
= m_actionTriggers
.find(hashMapKey
); 
4708     if ( it 
!= m_actionTriggers
.end() ) 
4710         // This key combination is already used 
4712         // Can add secondary? 
4713         wxASSERT_MSG( !(it
->second
&~(0xFFFF)), 
4714                       wxT("You can only add up to two separate actions per key combination.") ); 
4716         action 
= it
->second 
| (action
<<16); 
4719     m_actionTriggers
[hashMapKey
] = action
; 
4722 void wxPropertyGrid::ClearActionTriggers( int action 
) 
4724     wxPGHashMapI2I::iterator it
; 
4726     for ( it 
= m_actionTriggers
.begin(); it 
!= m_actionTriggers
.end(); ++it 
) 
4728         if ( it
->second 
== action 
) 
4730             m_actionTriggers
.erase(it
); 
4735 void wxPropertyGrid::HandleKeyEvent( wxKeyEvent 
&event
, bool fromChild 
) 
4738     // Handles key event when editor control is not focused. 
4741     wxCHECK2(!m_frozen
, return); 
4743     // Travelsal between items, collapsing/expanding, etc. 
4744     int keycode 
= event
.GetKeyCode(); 
4745     bool editorFocused 
= IsEditorFocused(); 
4747     if ( keycode 
== WXK_TAB 
) 
4749         wxWindow
* mainControl
; 
4751         if ( HasInternalFlag(wxPG_FL_IN_MANAGER
) ) 
4752             mainControl 
= GetParent(); 
4756         if ( !event
.ShiftDown() ) 
4758             if ( !editorFocused 
&& m_wndEditor 
) 
4760                 DoSelectProperty( m_selected
, wxPG_SEL_FOCUS 
); 
4764                 // Tab traversal workaround for platforms on which 
4765                 // wxWindow::Navigate() may navigate into first child 
4766                 // instead of next sibling. Does not work perfectly 
4767                 // in every scenario (for instance, when property grid 
4768                 // is either first or last control). 
4769             #if defined(__WXGTK__) 
4770                 wxWindow
* sibling 
= mainControl
->GetNextSibling(); 
4772                     sibling
->SetFocusFromKbd(); 
4774                 Navigate(wxNavigationKeyEvent::IsForward
); 
4780             if ( editorFocused 
) 
4786             #if defined(__WXGTK__) 
4787                 wxWindow
* sibling 
= mainControl
->GetPrevSibling(); 
4789                     sibling
->SetFocusFromKbd(); 
4791                 Navigate(wxNavigationKeyEvent::IsBackward
); 
4799     // Ignore Alt and Control when they are down alone 
4800     if ( keycode 
== WXK_ALT 
|| 
4801          keycode 
== WXK_CONTROL 
) 
4808     int action 
= KeyEventToActions(event
, &secondAction
); 
4810     if ( editorFocused 
&& action 
== wxPG_ACTION_CANCEL_EDIT 
) 
4813         // Esc cancels any changes 
4814         if ( IsEditorsValueModified() ) 
4816             EditorsValueWasNotModified(); 
4818             // Update the control as well 
4819             m_selected
->GetEditorClass()->SetControlStringValue( m_selected
, 
4821                                                                  m_selected
->GetDisplayedString() ); 
4824         OnValidationFailureReset(m_selected
); 
4830     // Except for TAB and ESC, handle child control events in child control 
4837     bool wasHandled 
= false; 
4842         if ( ButtonTriggerKeyTest(action
, event
) ) 
4845         wxPGProperty
* p 
= m_selected
; 
4847         // Travel and expand/collapse 
4850         if ( p
->GetChildCount() && 
4851              !(p
->m_flags 
& wxPG_PROP_DISABLED
) 
4854             if ( action 
== wxPG_ACTION_COLLAPSE_PROPERTY 
|| secondAction 
== wxPG_ACTION_COLLAPSE_PROPERTY 
) 
4856                 if ( (m_windowStyle 
& wxPG_HIDE_MARGIN
) || Collapse(p
) ) 
4859             else if ( action 
== wxPG_ACTION_EXPAND_PROPERTY 
|| secondAction 
== wxPG_ACTION_EXPAND_PROPERTY 
) 
4861                 if ( (m_windowStyle 
& wxPG_HIDE_MARGIN
) || Expand(p
) ) 
4868             if ( action 
== wxPG_ACTION_PREV_PROPERTY 
|| secondAction 
== wxPG_ACTION_PREV_PROPERTY 
) 
4872             else if ( action 
== wxPG_ACTION_NEXT_PROPERTY 
|| secondAction 
== wxPG_ACTION_NEXT_PROPERTY 
) 
4878         if ( selectDir 
>= -1 ) 
4880             p 
= wxPropertyGridIterator::OneStep( m_pState
, wxPG_ITERATE_VISIBLE
, p
, selectDir 
); 
4882                 DoSelectProperty(p
); 
4888         // If nothing was selected, select the first item now 
4889         // (or navigate out of tab). 
4890         if ( action 
!= wxPG_ACTION_CANCEL_EDIT 
&& secondAction 
!= wxPG_ACTION_CANCEL_EDIT 
) 
4892             wxPGProperty
* p 
= wxPropertyGridInterface::GetFirst(); 
4893             if ( p 
) DoSelectProperty(p
); 
4902 // ----------------------------------------------------------------------- 
4904 void wxPropertyGrid::OnKey( wxKeyEvent 
&event 
) 
4906     HandleKeyEvent(event
, false); 
4909 // ----------------------------------------------------------------------- 
4911 bool wxPropertyGrid::ButtonTriggerKeyTest( int action
, wxKeyEvent
& event 
) 
4916         action 
= KeyEventToActions(event
, &secondAction
); 
4919     // Does the keycode trigger button? 
4920     if ( action 
== wxPG_ACTION_PRESS_BUTTON 
&& 
4923         wxCommandEvent 
evt(wxEVT_COMMAND_BUTTON_CLICKED
, m_wndEditor2
->GetId()); 
4924         GetEventHandler()->AddPendingEvent(evt
); 
4931 // ----------------------------------------------------------------------- 
4933 void wxPropertyGrid::OnChildKeyDown( wxKeyEvent 
&event 
) 
4935     HandleKeyEvent(event
, true); 
4938 // ----------------------------------------------------------------------- 
4939 // wxPropertyGrid miscellaneous event handling 
4940 // ----------------------------------------------------------------------- 
4942 void wxPropertyGrid::OnIdle( wxIdleEvent
& WXUNUSED(event
) ) 
4945     // Check if the focus is in this control or one of its children 
4946     wxWindow
* newFocused 
= wxWindow::FindFocus(); 
4948     if ( newFocused 
!= m_curFocused 
) 
4949         HandleFocusChange( newFocused 
); 
4952 bool wxPropertyGrid::IsEditorFocused() const 
4954     wxWindow
* focus 
= wxWindow::FindFocus(); 
4956     if ( focus 
== m_wndEditor 
|| focus 
== m_wndEditor2 
|| 
4957          focus 
== GetEditorControl() ) 
4963 // Called by focus event handlers. newFocused is the window that becomes focused. 
4964 void wxPropertyGrid::HandleFocusChange( wxWindow
* newFocused 
) 
4966     unsigned int oldFlags 
= m_iFlags
; 
4968     m_iFlags 
&= ~(wxPG_FL_FOCUSED
); 
4970     wxWindow
* parent 
= newFocused
; 
4972     // This must be one of nextFocus' parents. 
4975         // Use m_eventObject, which is either wxPropertyGrid or 
4976         // wxPropertyGridManager, as appropriate. 
4977         if ( parent 
== m_eventObject 
) 
4979             m_iFlags 
|= wxPG_FL_FOCUSED
; 
4982         parent 
= parent
->GetParent(); 
4985     m_curFocused 
= newFocused
; 
4987     if ( (m_iFlags 
& wxPG_FL_FOCUSED
) != 
4988          (oldFlags 
& wxPG_FL_FOCUSED
) ) 
4990         if ( !(m_iFlags 
& wxPG_FL_FOCUSED
) ) 
4992             // Need to store changed value 
4993             CommitChangesFromEditor(); 
4999             // Preliminary code for tab-order respecting 
5000             // tab-traversal (but should be moved to 
5003             wxWindow* prevFocus = event.GetWindow(); 
5004             wxWindow* useThis = this; 
5005             if ( m_iFlags & wxPG_FL_IN_MANAGER ) 
5006                 useThis = GetParent(); 
5009                  prevFocus->GetParent() == useThis->GetParent() ) 
5011                 wxList& children = useThis->GetParent()->GetChildren(); 
5013                 wxNode* node = children.Find(prevFocus); 
5015                 if ( node->GetNext() && 
5016                      useThis == node->GetNext()->GetData() ) 
5017                     DoSelectProperty(GetFirst()); 
5018                 else if ( node->GetPrevious () && 
5019                           useThis == node->GetPrevious()->GetData() ) 
5020                     DoSelectProperty(GetLastProperty()); 
5027         if ( m_selected 
&& (m_iFlags 
& wxPG_FL_INITIALIZED
) ) 
5028             DrawItem( m_selected 
); 
5032 void wxPropertyGrid::OnFocusEvent( wxFocusEvent
& event 
) 
5034     if ( event
.GetEventType() == wxEVT_SET_FOCUS 
) 
5035         HandleFocusChange((wxWindow
*)event
.GetEventObject()); 
5036     // Line changed to "else" when applying wxPropertyGrid patch #1675902 
5037     //else if ( event.GetWindow() ) 
5039         HandleFocusChange(event
.GetWindow()); 
5044 // ----------------------------------------------------------------------- 
5046 void wxPropertyGrid::OnChildFocusEvent( wxChildFocusEvent
& event 
) 
5048     HandleFocusChange((wxWindow
*)event
.GetEventObject()); 
5051     // event.Skip() being commented out is aworkaround for bug reported 
5052     // in ticket #4840 (wxScrolledWindow problem with automatic scrolling). 
5056 // ----------------------------------------------------------------------- 
5058 void wxPropertyGrid::OnScrollEvent( wxScrollWinEvent 
&event 
) 
5060     m_iFlags 
|= wxPG_FL_SCROLLED
; 
5065 // ----------------------------------------------------------------------- 
5067 void wxPropertyGrid::OnCaptureChange( wxMouseCaptureChangedEvent
& WXUNUSED(event
) ) 
5069     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
5071         m_iFlags 
&= ~(wxPG_FL_MOUSE_CAPTURED
); 
5075 // ----------------------------------------------------------------------- 
5076 // Property editor related functions 
5077 // ----------------------------------------------------------------------- 
5079 // noDefCheck = true prevents infinite recursion. 
5080 wxPGEditor
* wxPropertyGrid::RegisterEditorClass( wxPGEditor
* editorClass
, 
5083     wxASSERT( editorClass 
); 
5085     if ( !noDefCheck 
&& wxPGGlobalVars
->m_mapEditorClasses
.empty() ) 
5086         RegisterDefaultEditors(); 
5088     wxString name 
= editorClass
->GetName(); 
5090     // Existing editor under this name? 
5091     wxPGHashMapS2P::iterator vt_it 
= wxPGGlobalVars
->m_mapEditorClasses
.find(name
); 
5093     if ( vt_it 
!= wxPGGlobalVars
->m_mapEditorClasses
.end() ) 
5095         // If this name was already used, try class name. 
5096         name 
= editorClass
->GetClassInfo()->GetClassName(); 
5097         vt_it 
= wxPGGlobalVars
->m_mapEditorClasses
.find(name
); 
5100     wxCHECK_MSG( vt_it 
== wxPGGlobalVars
->m_mapEditorClasses
.end(), 
5101                  (wxPGEditor
*) vt_it
->second
, 
5102                  "Editor with given name was already registered" ); 
5104     wxPGGlobalVars
->m_mapEditorClasses
[name
] = (void*)editorClass
; 
5109 // Use this in RegisterDefaultEditors. 
5110 #define wxPGRegisterDefaultEditorClass(EDITOR) \ 
5111     if ( wxPGEditor_##EDITOR == NULL ) \ 
5113         wxPGEditor_##EDITOR = wxPropertyGrid::RegisterEditorClass( \ 
5114             new wxPG##EDITOR##Editor, true ); \ 
5117 // Registers all default editor classes 
5118 void wxPropertyGrid::RegisterDefaultEditors() 
5120     wxPGRegisterDefaultEditorClass( TextCtrl 
); 
5121     wxPGRegisterDefaultEditorClass( Choice 
); 
5122     wxPGRegisterDefaultEditorClass( ComboBox 
); 
5123     wxPGRegisterDefaultEditorClass( TextCtrlAndButton 
); 
5124 #if wxPG_INCLUDE_CHECKBOX 
5125     wxPGRegisterDefaultEditorClass( CheckBox 
); 
5127     wxPGRegisterDefaultEditorClass( ChoiceAndButton 
); 
5129     // Register SpinCtrl etc. editors before use 
5130     RegisterAdditionalEditors(); 
5133 // ----------------------------------------------------------------------- 
5134 // wxPGStringTokenizer 
5135 //   Needed to handle C-style string lists (e.g. "str1" "str2") 
5136 // ----------------------------------------------------------------------- 
5138 wxPGStringTokenizer::wxPGStringTokenizer( const wxString
& str
, wxChar delimeter 
) 
5139     : m_str(&str
), m_curPos(str
.begin()), m_delimeter(delimeter
) 
5143 wxPGStringTokenizer::~wxPGStringTokenizer() 
5147 bool wxPGStringTokenizer::HasMoreTokens() 
5149     const wxString
& str 
= *m_str
; 
5151     wxString::const_iterator i 
= m_curPos
; 
5153     wxUniChar delim 
= m_delimeter
; 
5155     wxUniChar prev_a 
= wxT('\0'); 
5157     bool inToken 
= false; 
5159     while ( i 
!= str
.end() ) 
5168                 m_readyToken
.clear(); 
5173             if ( prev_a 
!= wxT('\\') ) 
5177                     if ( a 
!= wxT('\\') ) 
5197     m_curPos 
= str
.end(); 
5205 wxString 
wxPGStringTokenizer::GetNextToken() 
5207     return m_readyToken
; 
5210 // ----------------------------------------------------------------------- 
5212 // ----------------------------------------------------------------------- 
5214 wxPGChoiceEntry::wxPGChoiceEntry() 
5215     : wxPGCell(), m_value(wxPG_INVALID_VALUE
) 
5219 // ----------------------------------------------------------------------- 
5221 // ----------------------------------------------------------------------- 
5223 wxPGChoicesData::wxPGChoicesData() 
5228 wxPGChoicesData::~wxPGChoicesData() 
5233 void wxPGChoicesData::Clear() 
5238 void wxPGChoicesData::CopyDataFrom( wxPGChoicesData
* data 
) 
5240     wxASSERT( m_items
.size() == 0 ); 
5242     m_items 
= data
->m_items
; 
5245 wxPGChoiceEntry
& wxPGChoicesData::Insert( int index
, 
5246                                           const wxPGChoiceEntry
& item 
) 
5248     wxVector
<wxPGChoiceEntry
>::iterator it
; 
5252         index 
= (int) m_items
.size(); 
5256         it 
= m_items
.begin() + index
; 
5259     m_items
.insert(it
, item
); 
5261     wxPGChoiceEntry
& ownEntry 
= m_items
[index
]; 
5263     // Need to fix value? 
5264     if ( ownEntry
.GetValue() == wxPG_INVALID_VALUE 
) 
5265         ownEntry
.SetValue(index
); 
5270 // ----------------------------------------------------------------------- 
5272 // ----------------------------------------------------------------------- 
5274 wxPGChoiceEntry
& wxPGChoices::Add( const wxString
& label
, int value 
) 
5278     wxPGChoiceEntry 
entry(label
, value
); 
5279     return m_data
->Insert( -1, entry 
); 
5282 // ----------------------------------------------------------------------- 
5284 wxPGChoiceEntry
& wxPGChoices::Add( const wxString
& label
, const wxBitmap
& bitmap
, int value 
) 
5288     wxPGChoiceEntry 
entry(label
, value
); 
5289     entry
.SetBitmap(bitmap
); 
5290     return m_data
->Insert( -1, entry 
); 
5293 // ----------------------------------------------------------------------- 
5295 wxPGChoiceEntry
& wxPGChoices::Insert( const wxPGChoiceEntry
& entry
, int index 
) 
5298     return m_data
->Insert( index
, entry 
); 
5301 // ----------------------------------------------------------------------- 
5303 wxPGChoiceEntry
& wxPGChoices::Insert( const wxString
& label
, int index
, int value 
) 
5307     wxPGChoiceEntry 
entry(label
, value
); 
5308     return m_data
->Insert( index
, entry 
); 
5311 // ----------------------------------------------------------------------- 
5313 wxPGChoiceEntry
& wxPGChoices::AddAsSorted( const wxString
& label
, int value 
) 
5319     while ( index 
< GetCount() ) 
5321         int cmpRes 
= GetLabel(index
).Cmp(label
); 
5327     wxPGChoiceEntry 
entry(label
, value
); 
5328     return m_data
->Insert( index
, entry 
); 
5331 // ----------------------------------------------------------------------- 
5333 void wxPGChoices::Add( const wxChar
** labels
, const ValArrItem
* values 
) 
5337     unsigned int itemcount 
= 0; 
5338     const wxChar
** p 
= &labels
[0]; 
5339     while ( *p 
) { p
++; itemcount
++; } 
5342     for ( i 
= 0; i 
< itemcount
; i
++ ) 
5347         wxPGChoiceEntry 
entry(labels
[i
], value
); 
5348         m_data
->Insert( i
, entry 
); 
5352 // ----------------------------------------------------------------------- 
5354 void wxPGChoices::Add( const wxArrayString
& arr
, const wxArrayInt
& arrint 
) 
5359     unsigned int itemcount 
= arr
.size(); 
5361     for ( i 
= 0; i 
< itemcount
; i
++ ) 
5364         if ( &arrint 
&& arrint
.size() ) 
5366         wxPGChoiceEntry 
entry(arr
[i
], value
); 
5367         m_data
->Insert( i
, entry 
); 
5371 // ----------------------------------------------------------------------- 
5373 void wxPGChoices::RemoveAt(size_t nIndex
, size_t count
) 
5375     wxASSERT( m_data
->m_refCount 
!= 0xFFFFFFF ); 
5376     m_data
->m_items
.erase(m_data
->m_items
.begin()+nIndex
, 
5377                           m_data
->m_items
.begin()+nIndex
+count
); 
5380 // ----------------------------------------------------------------------- 
5382 int wxPGChoices::Index( const wxString
& str 
) const 
5387         for ( i
=0; i
< m_data
->GetCount(); i
++ ) 
5389             const wxPGChoiceEntry
& entry 
= m_data
->Item(i
); 
5390             if ( entry
.HasText() && entry
.GetText() == str 
) 
5397 // ----------------------------------------------------------------------- 
5399 int wxPGChoices::Index( int val 
) const 
5404         for ( i
=0; i
< m_data
->GetCount(); i
++ ) 
5406             const wxPGChoiceEntry
& entry 
= m_data
->Item(i
); 
5407             if ( entry
.GetValue() == val 
) 
5414 // ----------------------------------------------------------------------- 
5416 wxArrayString 
wxPGChoices::GetLabels() const 
5421     if ( this && IsOk() ) 
5422         for ( i
=0; i
<GetCount(); i
++ ) 
5423             arr
.push_back(GetLabel(i
)); 
5428 // ----------------------------------------------------------------------- 
5430 wxArrayInt 
wxPGChoices::GetValuesForStrings( const wxArrayString
& strings 
) const 
5437         for ( i
=0; i
< strings
.size(); i
++ ) 
5439             int index 
= Index(strings
[i
]); 
5441                 arr
.Add(GetValue(index
)); 
5443                 arr
.Add(wxPG_INVALID_VALUE
); 
5450 // ----------------------------------------------------------------------- 
5452 wxArrayInt 
wxPGChoices::GetIndicesForStrings( const wxArrayString
& strings
, 
5453                                               wxArrayString
* unmatched 
) const 
5460         for ( i
=0; i
< strings
.size(); i
++ ) 
5462             const wxString
& str 
= strings
[i
]; 
5463             int index 
= Index(str
); 
5466             else if ( unmatched 
) 
5467                 unmatched
->Add(str
); 
5474 // ----------------------------------------------------------------------- 
5476 void wxPGChoices::AssignData( wxPGChoicesData
* data 
) 
5480     if ( data 
!= wxPGChoicesEmptyData 
) 
5487 // ----------------------------------------------------------------------- 
5489 void wxPGChoices::Init() 
5491     m_data 
= wxPGChoicesEmptyData
; 
5494 // ----------------------------------------------------------------------- 
5496 void wxPGChoices::Free() 
5498     if ( m_data 
!= wxPGChoicesEmptyData 
) 
5501         m_data 
= wxPGChoicesEmptyData
; 
5505 // ----------------------------------------------------------------------- 
5506 // wxPropertyGridEvent 
5507 // ----------------------------------------------------------------------- 
5509 IMPLEMENT_DYNAMIC_CLASS(wxPropertyGridEvent
, wxCommandEvent
) 
5512 wxDEFINE_EVENT( wxEVT_PG_SELECTED
, wxPropertyGridEvent 
) 
5513 wxDEFINE_EVENT( wxEVT_PG_CHANGING
, wxPropertyGridEvent 
) 
5514 wxDEFINE_EVENT( wxEVT_PG_CHANGED
, wxPropertyGridEvent 
) 
5515 wxDEFINE_EVENT( wxEVT_PG_HIGHLIGHTED
, wxPropertyGridEvent 
) 
5516 wxDEFINE_EVENT( wxEVT_PG_RIGHT_CLICK
, wxPropertyGridEvent 
) 
5517 wxDEFINE_EVENT( wxEVT_PG_PAGE_CHANGED
, wxPropertyGridEvent 
) 
5518 wxDEFINE_EVENT( wxEVT_PG_ITEM_EXPANDED
, wxPropertyGridEvent 
) 
5519 wxDEFINE_EVENT( wxEVT_PG_ITEM_COLLAPSED
, wxPropertyGridEvent 
) 
5520 wxDEFINE_EVENT( wxEVT_PG_DOUBLE_CLICK
, wxPropertyGridEvent 
) 
5523 // ----------------------------------------------------------------------- 
5525 void wxPropertyGridEvent::Init() 
5527     m_validationInfo 
= NULL
; 
5529     m_wasVetoed 
= false; 
5532 // ----------------------------------------------------------------------- 
5534 wxPropertyGridEvent::wxPropertyGridEvent(wxEventType commandType
, int id
) 
5535     : wxCommandEvent(commandType
,id
) 
5541 // ----------------------------------------------------------------------- 
5543 wxPropertyGridEvent::wxPropertyGridEvent(const wxPropertyGridEvent
& event
) 
5544     : wxCommandEvent(event
) 
5546     m_eventType 
= event
.GetEventType(); 
5547     m_eventObject 
= event
.m_eventObject
; 
5549     m_property 
= event
.m_property
; 
5550     m_validationInfo 
= event
.m_validationInfo
; 
5551     m_canVeto 
= event
.m_canVeto
; 
5552     m_wasVetoed 
= event
.m_wasVetoed
; 
5555 // ----------------------------------------------------------------------- 
5557 wxPropertyGridEvent::~wxPropertyGridEvent() 
5561 // ----------------------------------------------------------------------- 
5563 wxEvent
* wxPropertyGridEvent::Clone() const 
5565     return new wxPropertyGridEvent( *this ); 
5568 // ----------------------------------------------------------------------- 
5569 // wxPropertyGridPopulator 
5570 // ----------------------------------------------------------------------- 
5572 wxPropertyGridPopulator::wxPropertyGridPopulator() 
5576     wxPGGlobalVars
->m_offline
++; 
5579 // ----------------------------------------------------------------------- 
5581 void wxPropertyGridPopulator::SetState( wxPropertyGridPageState
* state 
) 
5584     m_propHierarchy
.clear(); 
5587 // ----------------------------------------------------------------------- 
5589 void wxPropertyGridPopulator::SetGrid( wxPropertyGrid
* pg 
) 
5595 // ----------------------------------------------------------------------- 
5597 wxPropertyGridPopulator::~wxPropertyGridPopulator() 
5600     // Free unused sets of choices 
5601     wxPGHashMapS2P::iterator it
; 
5603     for( it 
= m_dictIdChoices
.begin(); it 
!= m_dictIdChoices
.end(); ++it 
) 
5605         wxPGChoicesData
* data 
= (wxPGChoicesData
*) it
->second
; 
5612         m_pg
->GetPanel()->Refresh(); 
5614     wxPGGlobalVars
->m_offline
--; 
5617 // ----------------------------------------------------------------------- 
5619 wxPGProperty
* wxPropertyGridPopulator::Add( const wxString
& propClass
, 
5620                                             const wxString
& propLabel
, 
5621                                             const wxString
& propName
, 
5622                                             const wxString
* propValue
, 
5623                                             wxPGChoices
* pChoices 
) 
5625     wxClassInfo
* classInfo 
= wxClassInfo::FindClass(propClass
); 
5626     wxPGProperty
* parent 
= GetCurParent(); 
5628     if ( parent
->HasFlag(wxPG_PROP_AGGREGATE
) ) 
5630         ProcessError(wxString::Format(wxT("new children cannot be added to '%s'"),parent
->GetName().c_str())); 
5634     if ( !classInfo 
|| !classInfo
->IsKindOf(CLASSINFO(wxPGProperty
)) ) 
5636         ProcessError(wxString::Format(wxT("'%s' is not valid property class"),propClass
.c_str())); 
5640     wxPGProperty
* property 
= (wxPGProperty
*) classInfo
->CreateObject(); 
5642     property
->SetLabel(propLabel
); 
5643     property
->DoSetName(propName
); 
5645     if ( pChoices 
&& pChoices
->IsOk() ) 
5646         property
->SetChoices(*pChoices
); 
5648     m_state
->DoInsert(parent
, -1, property
); 
5651         property
->SetValueFromString( *propValue
, wxPG_FULL_VALUE
| 
5652                                                   wxPG_PROGRAMMATIC_VALUE 
); 
5657 // ----------------------------------------------------------------------- 
5659 void wxPropertyGridPopulator::AddChildren( wxPGProperty
* property 
) 
5661     m_propHierarchy
.push_back(property
); 
5662     DoScanForChildren(); 
5663     m_propHierarchy
.pop_back(); 
5666 // ----------------------------------------------------------------------- 
5668 wxPGChoices 
wxPropertyGridPopulator::ParseChoices( const wxString
& choicesString
, 
5669                                                    const wxString
& idString 
) 
5671     wxPGChoices choices
; 
5674     if ( choicesString
[0] == wxT('@') ) 
5676         wxString ids 
= choicesString
.substr(1); 
5677         wxPGHashMapS2P::iterator it 
= m_dictIdChoices
.find(ids
); 
5678         if ( it 
== m_dictIdChoices
.end() ) 
5679             ProcessError(wxString::Format(wxT("No choices defined for id '%s'"),ids
.c_str())); 
5681             choices
.AssignData((wxPGChoicesData
*)it
->second
); 
5686         if ( idString
.length() ) 
5688             wxPGHashMapS2P::iterator it 
= m_dictIdChoices
.find(idString
); 
5689             if ( it 
!= m_dictIdChoices
.end() ) 
5691                 choices
.AssignData((wxPGChoicesData
*)it
->second
); 
5698             // Parse choices string 
5699             wxString::const_iterator it 
= choicesString
.begin(); 
5703             bool labelValid 
= false; 
5705             for ( ; it 
!= choicesString
.end(); ++it 
) 
5711                     if ( c 
== wxT('"') ) 
5716                             if ( !value
.ToLong(&l
, 0) ) l 
= wxPG_INVALID_VALUE
; 
5717                             choices
.Add(label
, l
); 
5720                         //wxLogDebug(wxT("%s, %s"),label.c_str(),value.c_str()); 
5725                     else if ( c 
== wxT('=') ) 
5732                     else if ( state 
== 2 && (wxIsalnum(c
) || c 
== wxT('x')) ) 
5739                     if ( c 
== wxT('"') ) 
5752                 if ( !value
.ToLong(&l
, 0) ) l 
= wxPG_INVALID_VALUE
; 
5753                 choices
.Add(label
, l
); 
5756             if ( !choices
.IsOk() ) 
5758                 choices
.EnsureData(); 
5762             if ( idString
.length() ) 
5763                 m_dictIdChoices
[idString
] = choices
.GetData(); 
5770 // ----------------------------------------------------------------------- 
5772 bool wxPropertyGridPopulator::ToLongPCT( const wxString
& s
, long* pval
, long max 
) 
5774     if ( s
.Last() == wxT('%') ) 
5776         wxString s2 
= s
.substr(0,s
.length()-1); 
5778         if ( s2
.ToLong(&val
, 10) ) 
5780             *pval 
= (val
*max
)/100; 
5786     return s
.ToLong(pval
, 10); 
5789 // ----------------------------------------------------------------------- 
5791 bool wxPropertyGridPopulator::AddAttribute( const wxString
& name
, 
5792                                             const wxString
& type
, 
5793                                             const wxString
& value 
) 
5795     int l 
= m_propHierarchy
.size(); 
5799     wxPGProperty
* p 
= m_propHierarchy
[l
-1]; 
5800     wxString valuel 
= value
.Lower(); 
5803     if ( type
.length() == 0 ) 
5808         if ( valuel 
== wxT("true") || valuel 
== wxT("yes") || valuel 
== wxT("1") ) 
5810         else if ( valuel 
== wxT("false") || valuel 
== wxT("no") || valuel 
== wxT("0") ) 
5812         else if ( value
.ToLong(&v
, 0) ) 
5819         if ( type 
== wxT("string") ) 
5823         else if ( type 
== wxT("int") ) 
5826             value
.ToLong(&v
, 0); 
5829         else if ( type 
== wxT("bool") ) 
5831             if ( valuel 
== wxT("true") || valuel 
== wxT("yes") || valuel 
== wxT("1") ) 
5838             ProcessError(wxString::Format(wxT("Invalid attribute type '%s'"),type
.c_str())); 
5843     p
->SetAttribute( name
, variant 
); 
5848 // ----------------------------------------------------------------------- 
5850 void wxPropertyGridPopulator::ProcessError( const wxString
& msg 
) 
5852     wxLogError(_("Error in resource: %s"),msg
.c_str()); 
5855 // ----------------------------------------------------------------------- 
5857 #endif  // wxUSE_PROPGRID