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" 
  67 // Two pics for the expand / collapse buttons. 
  68 // Files are not supplied with this project (since it is 
  69 // recommended to use either custom or native rendering). 
  70 // If you want them, get wxTreeMultiCtrl by Jorgen Bodde, 
  71 // and copy xpm files from archive to wxPropertyGrid src directory 
  72 // (and also comment/undef wxPG_ICON_WIDTH in propGrid.h 
  73 // and set wxPG_USE_RENDERER_NATIVE to 0). 
  74 #ifndef wxPG_ICON_WIDTH 
  75   #if defined(__WXMAC__) 
  76     #include "mac_collapse.xpm" 
  77     #include "mac_expand.xpm" 
  78   #elif defined(__WXGTK__) 
  79     #include "linux_collapse.xpm" 
  80     #include "linux_expand.xpm" 
  82     #include "default_collapse.xpm" 
  83     #include "default_expand.xpm" 
  88 //#define wxPG_TEXT_INDENT                4 // For the wxComboControl 
  89 //#define wxPG_ALLOW_CLIPPING             1 // If 1, GetUpdateRegion() in OnPaint event handler is not ignored 
  90 #define wxPG_GUTTER_DIV                 3 // gutter is max(iconwidth/gutter_div,gutter_min) 
  91 #define wxPG_GUTTER_MIN                 3 // gutter before and after image of [+] or [-] 
  92 #define wxPG_YSPACING_MIN               1 
  93 #define wxPG_DEFAULT_VSPACING           2 // This matches .NET propertygrid's value, 
  94                                           // but causes normal combobox to spill out under MSW 
  96 //#define wxPG_OPTIMAL_WIDTH              200 // Arbitrary 
  98 //#define wxPG_MIN_SCROLLBAR_WIDTH        10 // Smallest scrollbar width on any platform 
  99                                            // Must be larger than largest control border 
 103 #define wxPG_DEFAULT_CURSOR             wxNullCursor 
 106 //#define wxPG_NAT_CHOICE_BORDER_ANY   0 
 108 //#define wxPG_HIDER_BUTTON_HEIGHT        25 
 110 #define wxPG_PIXELS_PER_UNIT            m_lineHeight 
 112 #ifdef wxPG_ICON_WIDTH 
 113   #define m_iconHeight m_iconWidth 
 116 //#define wxPG_TOOLTIP_DELAY              1000 
 118 // This is the number of pixels the expander button inside 
 119 // property cells (i.e. not in the grey margin area are 
 121 #define IN_CELL_EXPANDER_BUTTON_X_ADJUST    2 
 123 // ----------------------------------------------------------------------- 
 126 void wxPropertyGrid::AutoGetTranslation ( bool enable 
) 
 128     wxPGGlobalVars
->m_autoGetTranslation 
= enable
; 
 131 void wxPropertyGrid::AutoGetTranslation ( bool ) { } 
 134 // ----------------------------------------------------------------------- 
 136 const char wxPropertyGridNameStr
[] = "wxPropertyGrid"; 
 138 // ----------------------------------------------------------------------- 
 139 // Statics in one class for easy destruction. 
 140 // ----------------------------------------------------------------------- 
 142 #include "wx/module.h" 
 144 class wxPGGlobalVarsClassManager 
: public wxModule
 
 146     DECLARE_DYNAMIC_CLASS(wxPGGlobalVarsClassManager
) 
 148     wxPGGlobalVarsClassManager() {} 
 149     virtual bool OnInit() { wxPGGlobalVars 
= new wxPGGlobalVarsClass(); return true; } 
 150     virtual void OnExit() { delete wxPGGlobalVars
; wxPGGlobalVars 
= NULL
; } 
 153 IMPLEMENT_DYNAMIC_CLASS(wxPGGlobalVarsClassManager
, wxModule
) 
 156 // When wxPG is loaded dynamically after the application is already running 
 157 // then the built-in module system won't pick this one up.  Add it manually. 
 158 void wxPGInitResourceModule() 
 160     wxModule
* module = new wxPGGlobalVarsClassManager
; 
 162     wxModule::RegisterModule(module); 
 165 wxPGGlobalVarsClass
* wxPGGlobalVars 
= NULL
; 
 168 wxPGGlobalVarsClass::wxPGGlobalVarsClass() 
 170     wxPGProperty::sm_wxPG_LABEL 
= new wxString(wxPG_LABEL_STRING
); 
 172     m_boolChoices
.Add(_("False")); 
 173     m_boolChoices
.Add(_("True")); 
 175     m_fontFamilyChoices 
= NULL
; 
 177     m_defaultRenderer 
= new wxPGDefaultRenderer(); 
 179     m_autoGetTranslation 
= false; 
 187     // Prepare some shared variants 
 188     m_vEmptyString 
= wxString(); 
 190     m_vMinusOne 
= (long) -1; 
 194     // Prepare cached string constants 
 195     m_strstring 
= wxS("string"); 
 196     m_strlong 
= wxS("long"); 
 197     m_strbool 
= wxS("bool"); 
 198     m_strlist 
= wxS("list"); 
 199     m_strDefaultValue 
= wxS("DefaultValue"); 
 200     m_strMin 
= wxS("Min"); 
 201     m_strMax 
= wxS("Max"); 
 202     m_strUnits 
= wxS("Units"); 
 203     m_strHint 
= wxS("Hint"); 
 204 #if wxPG_COMPATIBILITY_1_4 
 205     m_strInlineHelp 
= wxS("InlineHelp"); 
 212 wxPGGlobalVarsClass::~wxPGGlobalVarsClass() 
 216     delete m_defaultRenderer
; 
 218     // This will always have one ref 
 219     delete m_fontFamilyChoices
; 
 222     for ( i
=0; i
<m_arrValidators
.size(); i
++ ) 
 223         delete ((wxValidator
*)m_arrValidators
[i
]); 
 227     // Destroy value type class instances. 
 228     wxPGHashMapS2P::iterator vt_it
; 
 230     // Destroy editor class instances. 
 231     // iterate over all the elements in the class 
 232     for( vt_it 
= m_mapEditorClasses
.begin(); vt_it 
!= m_mapEditorClasses
.end(); ++vt_it 
) 
 234         delete ((wxPGEditor
*)vt_it
->second
); 
 237     delete wxPGProperty::sm_wxPG_LABEL
; 
 240 void wxPropertyGridInitGlobalsIfNeeded() 
 244 // ----------------------------------------------------------------------- 
 246 // ----------------------------------------------------------------------- 
 248 IMPLEMENT_DYNAMIC_CLASS(wxPropertyGrid
, wxScrolledWindow
) 
 250 BEGIN_EVENT_TABLE(wxPropertyGrid
, wxScrolledWindow
) 
 251   EVT_IDLE(wxPropertyGrid::OnIdle
) 
 252   EVT_PAINT(wxPropertyGrid::OnPaint
) 
 253   EVT_SIZE(wxPropertyGrid::OnResize
) 
 254   EVT_ENTER_WINDOW(wxPropertyGrid::OnMouseEntry
) 
 255   EVT_LEAVE_WINDOW(wxPropertyGrid::OnMouseEntry
) 
 256   EVT_MOUSE_CAPTURE_CHANGED(wxPropertyGrid::OnCaptureChange
) 
 257   EVT_SCROLLWIN(wxPropertyGrid::OnScrollEvent
) 
 258   EVT_CHILD_FOCUS(wxPropertyGrid::OnChildFocusEvent
) 
 259   EVT_SET_FOCUS(wxPropertyGrid::OnFocusEvent
) 
 260   EVT_KILL_FOCUS(wxPropertyGrid::OnFocusEvent
) 
 261   EVT_SYS_COLOUR_CHANGED(wxPropertyGrid::OnSysColourChanged
) 
 262   EVT_MOTION(wxPropertyGrid::OnMouseMove
) 
 263   EVT_LEFT_DOWN(wxPropertyGrid::OnMouseClick
) 
 264   EVT_LEFT_UP(wxPropertyGrid::OnMouseUp
) 
 265   EVT_RIGHT_UP(wxPropertyGrid::OnMouseRightClick
) 
 266   EVT_LEFT_DCLICK(wxPropertyGrid::OnMouseDoubleClick
) 
 267   EVT_KEY_DOWN(wxPropertyGrid::OnKey
) 
 270 // ----------------------------------------------------------------------- 
 272 wxPropertyGrid::wxPropertyGrid() 
 278 // ----------------------------------------------------------------------- 
 280 wxPropertyGrid::wxPropertyGrid( wxWindow 
*parent
, 
 285                                 const wxString
& name 
) 
 289     Create(parent
,id
,pos
,size
,style
,name
); 
 292 // ----------------------------------------------------------------------- 
 294 bool wxPropertyGrid::Create( wxWindow 
*parent
, 
 299                              const wxString
& name 
) 
 302     if (!(style
&wxBORDER_MASK
)) 
 304         style 
|= wxBORDER_THEME
; 
 309     // Filter out wxTAB_TRAVERSAL - we will handle TABs manually 
 310     style 
&= ~(wxTAB_TRAVERSAL
); 
 311     style 
|= wxWANTS_CHARS
; 
 313     wxScrolledWindow::Create(parent
,id
,pos
,size
,style
,name
); 
 320 // ----------------------------------------------------------------------- 
 323 // Initialize values to defaults 
 325 void wxPropertyGrid::Init1() 
 327     // Register editor classes, if necessary. 
 328     if ( wxPGGlobalVars
->m_mapEditorClasses
.empty() ) 
 329         wxPropertyGrid::RegisterDefaultEditors(); 
 333     m_wndEditor 
= m_wndEditor2 
= NULL
; 
 337     m_labelEditor 
= NULL
; 
 338     m_labelEditorProperty 
= NULL
; 
 339     m_eventObject 
= this; 
 341     m_processedEvent 
= NULL
; 
 342     m_sortFunction 
= NULL
; 
 343     m_inDoPropertyChanged 
= 0; 
 344     m_inCommitChangesFromEditor 
= 0; 
 345     m_inDoSelectProperty 
= 0; 
 346     m_permanentValidationFailureBehavior 
= wxPG_VFB_DEFAULT
; 
 351     // Must set empty but valid data 
 352     m_unspecifiedAppearance
.SetEmptyData(); 
 355     AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY
, WXK_RIGHT 
); 
 356     AddActionTrigger( wxPG_ACTION_NEXT_PROPERTY
, WXK_DOWN 
); 
 357     AddActionTrigger( wxPG_ACTION_PREV_PROPERTY
, WXK_LEFT 
); 
 358     AddActionTrigger( wxPG_ACTION_PREV_PROPERTY
, WXK_UP 
); 
 359     AddActionTrigger( wxPG_ACTION_EXPAND_PROPERTY
, WXK_RIGHT
); 
 360     AddActionTrigger( wxPG_ACTION_COLLAPSE_PROPERTY
, WXK_LEFT
); 
 361     AddActionTrigger( wxPG_ACTION_CANCEL_EDIT
, WXK_ESCAPE 
); 
 362     AddActionTrigger( wxPG_ACTION_PRESS_BUTTON
, WXK_DOWN
, wxMOD_ALT 
); 
 363     AddActionTrigger( wxPG_ACTION_PRESS_BUTTON
, WXK_F4 
); 
 365     m_coloursCustomized 
= 0; 
 368 #if wxPG_DOUBLE_BUFFER 
 369     m_doubleBuffer 
= NULL
; 
 372 #ifndef wxPG_ICON_WIDTH 
 378     m_iconWidth 
= wxPG_ICON_WIDTH
; 
 383     m_gutterWidth 
= wxPG_GUTTER_MIN
; 
 384     m_subgroup_extramargin 
= 10; 
 388     m_width 
= m_height 
= 0; 
 390     m_commonValues
.push_back(new wxPGCommonValue(_("Unspecified"), wxPGGlobalVars
->m_defaultRenderer
) ); 
 393     m_chgInfo_changedProperty 
= NULL
; 
 396 // ----------------------------------------------------------------------- 
 399 // Initialize after parent etc. set 
 401 void wxPropertyGrid::Init2() 
 403     wxASSERT( !(m_iFlags 
& wxPG_FL_INITIALIZED 
) ); 
 406    // Smaller controls on Mac 
 407    SetWindowVariant(wxWINDOW_VARIANT_SMALL
); 
 410     // Now create state, if one didn't exist already 
 411     // (wxPropertyGridManager might have created it for us). 
 414         m_pState 
= CreateState(); 
 415         m_pState
->m_pPropGrid 
= this; 
 416         m_iFlags 
|= wxPG_FL_CREATEDSTATE
; 
 419     if ( !(m_windowStyle 
& wxPG_SPLITTER_AUTO_CENTER
) ) 
 420         m_pState
->m_dontCenterSplitter 
= true; 
 422     if ( m_windowStyle 
& wxPG_HIDE_CATEGORIES 
) 
 424         m_pState
->InitNonCatMode(); 
 426         m_pState
->m_properties 
= m_pState
->m_abcArray
; 
 429     GetClientSize(&m_width
,&m_height
); 
 431 #ifndef wxPG_ICON_WIDTH 
 432     // create two bitmap nodes for drawing 
 433     m_expandbmp 
= new wxBitmap(expand_xpm
); 
 434     m_collbmp 
= new wxBitmap(collapse_xpm
); 
 436     // calculate average font height for bitmap centering 
 438     m_iconWidth 
= m_expandbmp
->GetWidth(); 
 439     m_iconHeight 
= m_expandbmp
->GetHeight(); 
 442     m_curcursor 
= wxCURSOR_ARROW
; 
 443     m_cursorSizeWE 
= new wxCursor( wxCURSOR_SIZEWE 
); 
 445     // adjust bitmap icon y position so they are centered 
 446     m_vspacing 
= wxPG_DEFAULT_VSPACING
; 
 448     CalculateFontAndBitmapStuff( wxPG_DEFAULT_VSPACING 
); 
 450     // Allocate cell datas 
 451     m_propertyDefaultCell
.SetEmptyData(); 
 452     m_categoryDefaultCell
.SetEmptyData(); 
 456     // This helps with flicker 
 457     SetBackgroundStyle( wxBG_STYLE_CUSTOM 
); 
 459     // Hook the top-level parent 
 464     // set virtual size to this window size 
 465     wxSize wndsize 
= GetSize(); 
 466     SetVirtualSize(wndsize
.GetWidth(), wndsize
.GetWidth()); 
 468     m_timeCreated 
= ::wxGetLocalTimeMillis(); 
 470     //m_canvas->Create(this, wxID_ANY, wxPoint(0, 0), GetClientSize(), 
 471     //                 wxWANTS_CHARS | wxCLIP_CHILDREN); 
 472     SetBackgroundStyle( wxBG_STYLE_CUSTOM 
); 
 474     m_iFlags 
|= wxPG_FL_INITIALIZED
; 
 476     m_ncWidth 
= wndsize
.GetWidth(); 
 478     // Need to call OnResize handler or size given in constructor/Create 
 480     wxSizeEvent 
sizeEvent(wndsize
,0); 
 484 // ----------------------------------------------------------------------- 
 486 wxPropertyGrid::~wxPropertyGrid() 
 491     wxCriticalSectionLocker(wxPGGlobalVars
->m_critSect
); 
 495     // Remove grid and property pointers from live wxPropertyGridEvents. 
 496     for ( i
=0; i
<m_liveEvents
.size(); i
++ ) 
 498         wxPropertyGridEvent
* evt 
= m_liveEvents
[i
]; 
 499         evt
->SetPropertyGrid(NULL
); 
 500         evt
->SetProperty(NULL
); 
 502     m_liveEvents
.clear(); 
 504     if ( m_processedEvent 
) 
 506         // All right... we are being deleted while wxPropertyGrid event 
 507         // is being sent. Make sure that event propagates as little 
 508         // as possible (although usually this is not enough to prevent 
 510         m_processedEvent
->Skip(false); 
 511         m_processedEvent
->StopPropagation(); 
 513         // Let's use wxMessageBox to make the message appear more 
 514         // reliably (and *before* the crash can happen). 
 515         ::wxMessageBox("wxPropertyGrid was being destroyed in an event " 
 516                        "generated by it. This usually leads to a crash " 
 517                        "so it is recommended to destroy the control " 
 518                        "at idle time instead."); 
 521     DoSelectProperty(NULL
, wxPG_SEL_NOVALIDATE
|wxPG_SEL_DONT_SEND_EVENT
); 
 523     // This should do prevent things from going too badly wrong 
 524     m_iFlags 
&= ~(wxPG_FL_INITIALIZED
); 
 526     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
 529     // Call with NULL to disconnect event handling 
 530     if ( GetExtraStyle() & wxPG_EX_ENABLE_TLP_TRACKING 
) 
 534         wxASSERT_MSG( !IsEditorsValueModified(), 
 535                       wxS("Most recent change in property editor was ") 
 536                       wxS("lost!!! (if you don't want this to happen, ") 
 537                       wxS("close your frames and dialogs using ") 
 538                       wxS("Close(false).)") ); 
 541 #if wxPG_DOUBLE_BUFFER 
 542     if ( m_doubleBuffer 
) 
 543         delete m_doubleBuffer
; 
 546     if ( m_iFlags 
& wxPG_FL_CREATEDSTATE 
) 
 549     delete m_cursorSizeWE
; 
 551 #ifndef wxPG_ICON_WIDTH 
 556     // Delete common value records 
 557     for ( i
=0; i
<m_commonValues
.size(); i
++ ) 
 559         // Use temporary variable to work around possible strange VC6 (asserts because m_size is zero) 
 560         wxPGCommonValue
* value 
= m_commonValues
[i
]; 
 565 // ----------------------------------------------------------------------- 
 567 bool wxPropertyGrid::Destroy() 
 569     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
 572     return wxScrolledWindow::Destroy(); 
 575 // ----------------------------------------------------------------------- 
 577 wxPropertyGridPageState
* wxPropertyGrid::CreateState() const 
 579     return new wxPropertyGridPageState(); 
 582 // ----------------------------------------------------------------------- 
 583 // wxPropertyGrid overridden wxWindow methods 
 584 // ----------------------------------------------------------------------- 
 586 void wxPropertyGrid::SetWindowStyleFlag( long style 
) 
 588     long old_style 
= m_windowStyle
; 
 590     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
 592         wxASSERT( m_pState 
); 
 594         if ( !(style 
& wxPG_HIDE_CATEGORIES
) && (old_style 
& wxPG_HIDE_CATEGORIES
) ) 
 597             EnableCategories( true ); 
 599         else if ( (style 
& wxPG_HIDE_CATEGORIES
) && !(old_style 
& wxPG_HIDE_CATEGORIES
) ) 
 601         // Disable categories 
 602             EnableCategories( false ); 
 604         if ( !(old_style 
& wxPG_AUTO_SORT
) && (style 
& wxPG_AUTO_SORT
) ) 
 610                 PrepareAfterItemsAdded(); 
 612                 m_pState
->m_itemsAdded 
= 1; 
 614     #if wxPG_SUPPORT_TOOLTIPS 
 615         if ( !(old_style 
& wxPG_TOOLTIPS
) && (style 
& wxPG_TOOLTIPS
) ) 
 621             wxToolTip* tooltip = new wxToolTip ( wxEmptyString ); 
 622             SetToolTip ( tooltip ); 
 623             tooltip->SetDelay ( wxPG_TOOLTIP_DELAY ); 
 626         else if ( (old_style 
& wxPG_TOOLTIPS
) && !(style 
& wxPG_TOOLTIPS
) ) 
 631             wxScrolledWindow::SetToolTip( NULL 
); 
 636     wxScrolledWindow::SetWindowStyleFlag ( style 
); 
 638     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
 640         if ( (old_style 
& wxPG_HIDE_MARGIN
) != (style 
& wxPG_HIDE_MARGIN
) ) 
 642             CalculateFontAndBitmapStuff( m_vspacing 
); 
 648 // ----------------------------------------------------------------------- 
 650 void wxPropertyGrid::Freeze() 
 654         wxScrolledWindow::Freeze(); 
 659 // ----------------------------------------------------------------------- 
 661 void wxPropertyGrid::Thaw() 
 667         wxScrolledWindow::Thaw(); 
 668         RecalculateVirtualSize(); 
 669     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
 673         // Force property re-selection 
 674         // NB: We must copy the selection. 
 675         wxArrayPGProperty selection 
= m_pState
->m_selection
; 
 676         DoSetSelection(selection
, wxPG_SEL_FORCE 
| wxPG_SEL_NONVISIBLE
); 
 680 // ----------------------------------------------------------------------- 
 682 bool wxPropertyGrid::DoAddToSelection( wxPGProperty
* prop
, int selFlags 
) 
 684     wxCHECK( prop
, false ); 
 686     if ( !(GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION
) ) 
 687         return DoSelectProperty(prop
, selFlags
); 
 689     wxArrayPGProperty
& selection 
= m_pState
->m_selection
; 
 691     if ( !selection
.size() ) 
 693         return DoSelectProperty(prop
, selFlags
); 
 697         // For categories, only one can be selected at a time 
 698         if ( prop
->IsCategory() || selection
[0]->IsCategory() ) 
 701         selection
.push_back(prop
); 
 703         if ( !(selFlags 
& wxPG_SEL_DONT_SEND_EVENT
) ) 
 705             SendEvent( wxEVT_PG_SELECTED
, prop
, NULL 
); 
 714 // ----------------------------------------------------------------------- 
 716 bool wxPropertyGrid::DoRemoveFromSelection( wxPGProperty
* prop
, int selFlags 
) 
 718     wxCHECK( prop
, false ); 
 721     wxArrayPGProperty
& selection 
= m_pState
->m_selection
; 
 722     if ( selection
.size() <= 1 ) 
 724         res 
= DoSelectProperty(NULL
, selFlags
); 
 728         m_pState
->DoRemoveFromSelection(prop
); 
 736 // ----------------------------------------------------------------------- 
 738 bool wxPropertyGrid::DoSelectAndEdit( wxPGProperty
* prop
, 
 739                                       unsigned int colIndex
, 
 740                                       unsigned int selFlags 
) 
 743     // NB: Enable following if label editor background colour is 
 744     //     ever changed to any other than m_colSelBack. 
 746     // We use this workaround to prevent visible flicker when editing 
 747     // a cell. Atleast on wxMSW, there is a difficult to find 
 748     // (and perhaps prevent) redraw somewhere between making property 
 749     // selected and enabling label editing. 
 751     //wxColour prevColSelBack = m_colSelBack; 
 752     //m_colSelBack = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ); 
 758         res 
= DoSelectProperty(prop
, selFlags
); 
 763         DoClearSelection(false, wxPG_SEL_NO_REFRESH
); 
 765         if ( m_pState
->m_editableColumns
.Index(colIndex
) == wxNOT_FOUND 
) 
 767             res 
= DoAddToSelection(prop
, selFlags
); 
 771             res 
= DoAddToSelection(prop
, selFlags
|wxPG_SEL_NO_REFRESH
); 
 773             DoBeginLabelEdit(colIndex
, selFlags
); 
 777     //m_colSelBack = prevColSelBack; 
 781 // ----------------------------------------------------------------------- 
 783 bool wxPropertyGrid::AddToSelectionFromInputEvent( wxPGProperty
* prop
, 
 784                                                    unsigned int colIndex
, 
 785                                                    wxMouseEvent
* mouseEvent
, 
 788     const wxArrayPGProperty
& selection 
= GetSelectedProperties(); 
 789     bool alreadySelected 
= m_pState
->DoIsPropertySelected(prop
); 
 792     // Set to 2 if also add all items in between 
 793     int addToExistingSelection 
= 0; 
 795     if ( GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION 
) 
 799             if ( mouseEvent
->GetEventType() == wxEVT_RIGHT_DOWN 
|| 
 800                  mouseEvent
->GetEventType() == wxEVT_RIGHT_UP 
) 
 802                 // Allow right-click for context menu without 
 803                 // disturbing the selection. 
 804                 if ( GetSelectedProperties().size() <= 1 || 
 806                     return DoSelectAndEdit(prop
, colIndex
, selFlags
); 
 811                 if ( mouseEvent
->ControlDown() ) 
 813                     addToExistingSelection 
= 1; 
 815                 else if ( mouseEvent
->ShiftDown() ) 
 817                     if ( selection
.size() > 0 && !prop
->IsCategory() ) 
 818                         addToExistingSelection 
= 2; 
 820                         addToExistingSelection 
= 1; 
 826     if ( addToExistingSelection 
== 1 ) 
 829         if ( !alreadySelected 
) 
 831             res 
= DoAddToSelection(prop
, selFlags
); 
 833         else if ( GetSelectedProperties().size() > 1 ) 
 835             res 
= DoRemoveFromSelection(prop
, selFlags
); 
 838     else if ( addToExistingSelection 
== 2 ) 
 840         // Add this, and all in between 
 842         // Find top selected property 
 843         wxPGProperty
* topSelProp 
= selection
[0]; 
 844         int topSelPropY 
= topSelProp
->GetY(); 
 845         for ( unsigned int i
=1; i
<selection
.size(); i
++ ) 
 847             wxPGProperty
* p 
= selection
[i
]; 
 849             if ( y 
< topSelPropY 
) 
 856         wxPGProperty
* startFrom
; 
 857         wxPGProperty
* stopAt
; 
 859         if ( prop
->GetY() <= topSelPropY 
) 
 861             // Property is above selection (or same) 
 867             // Property is below selection 
 868             startFrom 
= topSelProp
; 
 872         // Iterate through properties in-between, and select them 
 873         wxPropertyGridIterator it
; 
 875         for ( it 
= GetIterator(wxPG_ITERATE_VISIBLE
, startFrom
); 
 879             wxPGProperty
* p 
= *it
; 
 881             if ( !p
->IsCategory() && 
 882                  !m_pState
->DoIsPropertySelected(p
) ) 
 884                 DoAddToSelection(p
, selFlags
); 
 893         res 
= DoSelectAndEdit(prop
, colIndex
, selFlags
); 
 899 // ----------------------------------------------------------------------- 
 901 void wxPropertyGrid::DoSetSelection( const wxArrayPGProperty
& newSelection
, 
 904     if ( newSelection
.size() > 0 ) 
 906         if ( !DoSelectProperty(newSelection
[0], selFlags
) ) 
 911         DoClearSelection(false, selFlags
); 
 914     for ( unsigned int i 
= 1; i 
< newSelection
.size(); i
++ ) 
 916         DoAddToSelection(newSelection
[i
], selFlags
); 
 922 // ----------------------------------------------------------------------- 
 924 void wxPropertyGrid::MakeColumnEditable( unsigned int column
, 
 927     wxASSERT( column 
!= 1 ); 
 929     wxArrayInt
& cols 
= m_pState
->m_editableColumns
; 
 933         cols
.push_back(column
); 
 937         for ( int i 
= cols
.size() - 1; i 
> 0; i
-- ) 
 939             if ( cols
[i
] == (int)column 
) 
 940                 cols
.erase( cols
.begin() + i 
); 
 945 // ----------------------------------------------------------------------- 
 947 void wxPropertyGrid::DoBeginLabelEdit( unsigned int colIndex
, 
 950     wxPGProperty
* selected 
= GetSelection(); 
 951     wxCHECK_RET(selected
, wxT("No property selected")); 
 952     wxCHECK_RET(colIndex 
!= 1, wxT("Do not use this for column 1")); 
 954     if ( !(selFlags 
& wxPG_SEL_DONT_SEND_EVENT
) ) 
 956         if ( SendEvent( wxEVT_PG_LABEL_EDIT_BEGIN
, 
 963     const wxPGCell
* cell 
= NULL
; 
 964     if ( selected
->HasCell(colIndex
) ) 
 966         cell 
= &selected
->GetCell(colIndex
); 
 967         if ( !cell
->HasText() && colIndex 
== 0 ) 
 968             text 
= selected
->GetLabel(); 
 974             text 
= selected
->GetLabel(); 
 976             cell 
= &selected
->GetOrCreateCell(colIndex
); 
 979     if ( cell 
&& cell
->HasText() ) 
 980         text 
= cell
->GetText(); 
 982     DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE
);  // send event 
 984     m_selColumn 
= colIndex
; 
 986     wxRect r 
= GetEditorWidgetRect(selected
, m_selColumn
); 
 988     wxWindow
* tc 
= GenerateEditorTextCtrl(r
.GetPosition(), 
 996     wxWindowID id 
= tc
->GetId(); 
 997     tc
->Connect(id
, wxEVT_COMMAND_TEXT_ENTER
, 
 998         wxCommandEventHandler(wxPropertyGrid::OnLabelEditorEnterPress
), 
1000     tc
->Connect(id
, wxEVT_KEY_DOWN
, 
1001         wxKeyEventHandler(wxPropertyGrid::OnLabelEditorKeyPress
), 
1006     m_labelEditor 
= wxStaticCast(tc
, wxTextCtrl
); 
1007     m_labelEditorProperty 
= selected
; 
1010 // ----------------------------------------------------------------------- 
1013 wxPropertyGrid::OnLabelEditorEnterPress( wxCommandEvent
& WXUNUSED(event
) ) 
1015     DoEndLabelEdit(true); 
1018 // ----------------------------------------------------------------------- 
1020 void wxPropertyGrid::OnLabelEditorKeyPress( wxKeyEvent
& event 
) 
1022     int keycode 
= event
.GetKeyCode(); 
1024     if ( keycode 
== WXK_ESCAPE 
) 
1026         DoEndLabelEdit(false); 
1034 // ----------------------------------------------------------------------- 
1036 void wxPropertyGrid::DoEndLabelEdit( bool commit
, int selFlags 
) 
1038     if ( !m_labelEditor 
) 
1041     wxPGProperty
* prop 
= m_labelEditorProperty
; 
1046         if ( !(selFlags 
& wxPG_SEL_DONT_SEND_EVENT
) ) 
1048             // wxPG_SEL_NOVALIDATE is passed correctly in selFlags 
1049             if ( SendEvent( wxEVT_PG_LABEL_EDIT_ENDING
, 
1050                             prop
, NULL
, selFlags
, 
1055         wxString text 
= m_labelEditor
->GetValue(); 
1056         wxPGCell
* cell 
= NULL
; 
1057         if ( prop
->HasCell(m_selColumn
) ) 
1059             cell 
= &prop
->GetCell(m_selColumn
); 
1063             if ( m_selColumn 
== 0 ) 
1064                 prop
->SetLabel(text
); 
1066                 cell 
= &prop
->GetOrCreateCell(m_selColumn
); 
1070             cell
->SetText(text
); 
1075     DestroyEditorWnd(m_labelEditor
); 
1076     m_labelEditor 
= NULL
; 
1077     m_labelEditorProperty 
= NULL
; 
1082 // ----------------------------------------------------------------------- 
1084 void wxPropertyGrid::SetExtraStyle( long exStyle 
) 
1086     if ( exStyle 
& wxPG_EX_ENABLE_TLP_TRACKING 
) 
1087         OnTLPChanging(::wxGetTopLevelParent(this)); 
1089         OnTLPChanging(NULL
); 
1091     if ( exStyle 
& wxPG_EX_NATIVE_DOUBLE_BUFFERING 
) 
1093 #if defined(__WXMSW__) 
1096         // Don't use WS_EX_COMPOSITED just now. 
1099         if ( m_iFlags & wxPG_FL_IN_MANAGER ) 
1100             hWnd = (HWND)GetParent()->GetHWND(); 
1102             hWnd = (HWND)GetHWND(); 
1104         ::SetWindowLong( hWnd, GWL_EXSTYLE, 
1105                          ::GetWindowLong(hWnd, GWL_EXSTYLE) | WS_EX_COMPOSITED ); 
1108 //#elif defined(__WXGTK20__) 
1110         // Only apply wxPG_EX_NATIVE_DOUBLE_BUFFERING if the window 
1111         // truly was double-buffered. 
1112         if ( !this->IsDoubleBuffered() ) 
1114             exStyle 
&= ~(wxPG_EX_NATIVE_DOUBLE_BUFFERING
); 
1118         #if wxPG_DOUBLE_BUFFER 
1119             delete m_doubleBuffer
; 
1120             m_doubleBuffer 
= NULL
; 
1125     wxScrolledWindow::SetExtraStyle( exStyle 
); 
1127     if ( exStyle 
& wxPG_EX_INIT_NOCAT 
) 
1128         m_pState
->InitNonCatMode(); 
1130     if ( exStyle 
& wxPG_EX_HELP_AS_TOOLTIPS 
) 
1131         m_windowStyle 
|= wxPG_TOOLTIPS
; 
1134     wxPGGlobalVars
->m_extraStyle 
= exStyle
; 
1137 // ----------------------------------------------------------------------- 
1139 // returns the best acceptable minimal size 
1140 wxSize 
wxPropertyGrid::DoGetBestSize() const 
1142     int lineHeight 
= wxMax(15, m_lineHeight
); 
1144     // don't make the grid too tall (limit height to 10 items) but don't 
1145     // make it too small neither 
1146     int numLines 
= wxMin
 
1148                     wxMax(m_pState
->m_properties
->GetChildCount(), 3), 
1152     wxClientDC 
dc(const_cast<wxPropertyGrid 
*>(this)); 
1153     int width 
= m_marginWidth
; 
1154     for ( unsigned int i 
= 0; i 
< m_pState
->m_colWidths
.size(); i
++ ) 
1156         width 
+= m_pState
->GetColumnFitWidth(dc
, m_pState
->DoGetRoot(), i
, true); 
1159     const wxSize sz 
= wxSize(width
, lineHeight
*numLines 
+ 40); 
1165 // ----------------------------------------------------------------------- 
1167 void wxPropertyGrid::OnTLPChanging( wxWindow
* newTLP 
) 
1169     if ( newTLP 
== m_tlp 
) 
1172     wxLongLong currentTime 
= ::wxGetLocalTimeMillis(); 
1175     // Parent changed so let's redetermine and re-hook the 
1176     // correct top-level window. 
1179         m_tlp
->Disconnect( wxEVT_CLOSE_WINDOW
, 
1180                            wxCloseEventHandler(wxPropertyGrid::OnTLPClose
), 
1182         m_tlpClosed 
= m_tlp
; 
1183         m_tlpClosedTime 
= currentTime
; 
1188         // Only accept new tlp if same one was not just dismissed. 
1189         if ( newTLP 
!= m_tlpClosed 
|| 
1190              m_tlpClosedTime
+250 < currentTime 
) 
1192             newTLP
->Connect( wxEVT_CLOSE_WINDOW
, 
1193                              wxCloseEventHandler(wxPropertyGrid::OnTLPClose
), 
1206 // ----------------------------------------------------------------------- 
1208 void wxPropertyGrid::OnTLPClose( wxCloseEvent
& event 
) 
1210     // ClearSelection forces value validation/commit. 
1211     if ( event
.CanVeto() && !DoClearSelection() ) 
1217     // Ok, it can close, set tlp pointer to NULL. Some other event 
1218     // handler can of course veto the close, but our OnIdle() should 
1219     // then be able to regain the tlp pointer. 
1220     OnTLPChanging(NULL
); 
1225 // ----------------------------------------------------------------------- 
1227 bool wxPropertyGrid::Reparent( wxWindowBase 
*newParent 
) 
1229     OnTLPChanging((wxWindow
*)newParent
); 
1231     bool res 
= wxScrolledWindow::Reparent(newParent
); 
1236 // ----------------------------------------------------------------------- 
1237 // wxPropertyGrid Font and Colour Methods 
1238 // ----------------------------------------------------------------------- 
1240 void wxPropertyGrid::CalculateFontAndBitmapStuff( int vspacing 
) 
1244     m_captionFont 
= wxScrolledWindow::GetFont(); 
1246     GetTextExtent(wxS("jG"), &x
, &y
, 0, 0, &m_captionFont
); 
1247     m_subgroup_extramargin 
= x 
+ (x
/2); 
1250 #if wxPG_USE_RENDERER_NATIVE 
1251     m_iconWidth 
= wxPG_ICON_WIDTH
; 
1252 #elif wxPG_ICON_WIDTH 
1254     m_iconWidth 
= (m_fontHeight 
* wxPG_ICON_WIDTH
) / 13; 
1255     if ( m_iconWidth 
< 5 ) m_iconWidth 
= 5; 
1256     else if ( !(m_iconWidth 
& 0x01) ) m_iconWidth
++; // must be odd 
1260     m_gutterWidth 
= m_iconWidth 
/ wxPG_GUTTER_DIV
; 
1261     if ( m_gutterWidth 
< wxPG_GUTTER_MIN 
) 
1262         m_gutterWidth 
= wxPG_GUTTER_MIN
; 
1265     if ( vspacing 
<= 1 ) vdiv 
= 12; 
1266     else if ( vspacing 
>= 3 ) vdiv 
= 3; 
1268     m_spacingy 
= m_fontHeight 
/ vdiv
; 
1269     if ( m_spacingy 
< wxPG_YSPACING_MIN 
) 
1270         m_spacingy 
= wxPG_YSPACING_MIN
; 
1273     if ( !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
1274         m_marginWidth 
= m_gutterWidth
*2 + m_iconWidth
; 
1276     m_captionFont
.SetWeight(wxBOLD
); 
1277     GetTextExtent(wxS("jG"), &x
, &y
, 0, 0, &m_captionFont
); 
1279     m_lineHeight 
= m_fontHeight
+(2*m_spacingy
)+1; 
1282     m_buttonSpacingY 
= (m_lineHeight 
- m_iconHeight
) / 2; 
1283     if ( m_buttonSpacingY 
< 0 ) m_buttonSpacingY 
= 0; 
1286         m_pState
->CalculateFontAndBitmapStuff(vspacing
); 
1288     if ( m_iFlags 
& wxPG_FL_INITIALIZED 
) 
1289         RecalculateVirtualSize(); 
1291     InvalidateBestSize(); 
1294 // ----------------------------------------------------------------------- 
1296 void wxPropertyGrid::OnSysColourChanged( wxSysColourChangedEvent 
&WXUNUSED(event
) ) 
1302 // ----------------------------------------------------------------------- 
1304 static wxColour 
wxPGAdjustColour(const wxColour
& src
, int ra
, 
1305                                  int ga 
= 1000, int ba 
= 1000, 
1306                                  bool forceDifferent 
= false) 
1313     // Recursion guard (allow 2 max) 
1314     static int isinside 
= 0; 
1316     wxCHECK_MSG( isinside 
< 3, 
1318                  wxT("wxPGAdjustColour should not be recursively called more than once") ); 
1323     int g 
= src
.Green(); 
1326     if ( r2
>255 ) r2 
= 255; 
1327     else if ( r2
<0) r2 
= 0; 
1329     if ( g2
>255 ) g2 
= 255; 
1330     else if ( g2
<0) g2 
= 0; 
1332     if ( b2
>255 ) b2 
= 255; 
1333     else if ( b2
<0) b2 
= 0; 
1335     // Make sure they are somewhat different 
1336     if ( forceDifferent 
&& (abs((r
+g
+b
)-(r2
+g2
+b2
)) < abs(ra
/2)) ) 
1337         dst 
= wxPGAdjustColour(src
,-(ra
*2)); 
1339         dst 
= wxColour(r2
,g2
,b2
); 
1341     // Recursion guard (allow 2 max) 
1348 static int wxPGGetColAvg( const wxColour
& col 
) 
1350     return (col
.Red() + col
.Green() + col
.Blue()) / 3; 
1354 void wxPropertyGrid::RegainColours() 
1356     if ( !(m_coloursCustomized 
& 0x0002) ) 
1358         wxColour col 
= wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE 
); 
1360         // Make sure colour is dark enough 
1362         int colDec 
= wxPGGetColAvg(col
) - 230; 
1364         int colDec 
= wxPGGetColAvg(col
) - 200; 
1367             m_colCapBack 
= wxPGAdjustColour(col
,-colDec
); 
1370         m_categoryDefaultCell
.GetData()->SetBgCol(m_colCapBack
); 
1373     if ( !(m_coloursCustomized 
& 0x0001) ) 
1374         m_colMargin 
= m_colCapBack
; 
1376     if ( !(m_coloursCustomized 
& 0x0004) ) 
1383         wxColour capForeCol 
= wxPGAdjustColour(m_colCapBack
,colDec
,5000,5000,true); 
1384         m_colCapFore 
= capForeCol
; 
1385         m_categoryDefaultCell
.GetData()->SetFgCol(capForeCol
); 
1388     if ( !(m_coloursCustomized 
& 0x0008) ) 
1390         wxColour bgCol 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
1391         m_colPropBack 
= bgCol
; 
1392         m_propertyDefaultCell
.GetData()->SetBgCol(bgCol
); 
1393         if ( !m_unspecifiedAppearance
.GetBgCol().IsOk() ) 
1394             m_unspecifiedAppearance
.SetBgCol(bgCol
); 
1397     if ( !(m_coloursCustomized 
& 0x0010) ) 
1399         wxColour fgCol 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT 
); 
1400         m_colPropFore 
= fgCol
; 
1401         m_propertyDefaultCell
.GetData()->SetFgCol(fgCol
); 
1402         if ( !m_unspecifiedAppearance
.GetFgCol().IsOk() ) 
1403             m_unspecifiedAppearance
.SetFgCol(fgCol
); 
1406     if ( !(m_coloursCustomized 
& 0x0020) ) 
1407         m_colSelBack 
= wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT 
); 
1409     if ( !(m_coloursCustomized 
& 0x0040) ) 
1410         m_colSelFore 
= wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHTTEXT 
); 
1412     if ( !(m_coloursCustomized 
& 0x0080) ) 
1413         m_colLine 
= m_colCapBack
; 
1415     if ( !(m_coloursCustomized 
& 0x0100) ) 
1416         m_colDisPropFore 
= m_colCapFore
; 
1418     m_colEmptySpace 
= wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW 
); 
1421 // ----------------------------------------------------------------------- 
1423 void wxPropertyGrid::ResetColours() 
1425     m_coloursCustomized 
= 0; 
1432 // ----------------------------------------------------------------------- 
1434 bool wxPropertyGrid::SetFont( const wxFont
& font 
) 
1436     // Must disable active editor. 
1439     bool res 
= wxScrolledWindow::SetFont( font 
); 
1440     if ( res 
&& GetParent()) // may not have been Create()ed yet if SetFont called from SetWindowVariant 
1442         CalculateFontAndBitmapStuff( m_vspacing 
); 
1449 // ----------------------------------------------------------------------- 
1451 void wxPropertyGrid::SetLineColour( const wxColour
& col 
) 
1454     m_coloursCustomized 
|= 0x80; 
1458 // ----------------------------------------------------------------------- 
1460 void wxPropertyGrid::SetMarginColour( const wxColour
& col 
) 
1463     m_coloursCustomized 
|= 0x01; 
1467 // ----------------------------------------------------------------------- 
1469 void wxPropertyGrid::SetCellBackgroundColour( const wxColour
& col 
) 
1471     m_colPropBack 
= col
; 
1472     m_coloursCustomized 
|= 0x08; 
1474     m_propertyDefaultCell
.GetData()->SetBgCol(col
); 
1475     m_unspecifiedAppearance
.SetBgCol(col
); 
1480 // ----------------------------------------------------------------------- 
1482 void wxPropertyGrid::SetCellTextColour( const wxColour
& col 
) 
1484     m_colPropFore 
= col
; 
1485     m_coloursCustomized 
|= 0x10; 
1487     m_propertyDefaultCell
.GetData()->SetFgCol(col
); 
1488     m_unspecifiedAppearance
.SetFgCol(col
); 
1493 // ----------------------------------------------------------------------- 
1495 void wxPropertyGrid::SetEmptySpaceColour( const wxColour
& col 
) 
1497     m_colEmptySpace 
= col
; 
1502 // ----------------------------------------------------------------------- 
1504 void wxPropertyGrid::SetCellDisabledTextColour( const wxColour
& col 
) 
1506     m_colDisPropFore 
= col
; 
1507     m_coloursCustomized 
|= 0x100; 
1511 // ----------------------------------------------------------------------- 
1513 void wxPropertyGrid::SetSelectionBackgroundColour( const wxColour
& col 
) 
1516     m_coloursCustomized 
|= 0x20; 
1520 // ----------------------------------------------------------------------- 
1522 void wxPropertyGrid::SetSelectionTextColour( const wxColour
& col 
) 
1525     m_coloursCustomized 
|= 0x40; 
1529 // ----------------------------------------------------------------------- 
1531 void wxPropertyGrid::SetCaptionBackgroundColour( const wxColour
& col 
) 
1534     m_coloursCustomized 
|= 0x02; 
1536     m_categoryDefaultCell
.GetData()->SetBgCol(col
); 
1541 // ----------------------------------------------------------------------- 
1543 void wxPropertyGrid::SetCaptionTextColour( const wxColour
& col 
) 
1546     m_coloursCustomized 
|= 0x04; 
1548     m_categoryDefaultCell
.GetData()->SetFgCol(col
); 
1553 // ----------------------------------------------------------------------- 
1554 // wxPropertyGrid property adding and removal 
1555 // ----------------------------------------------------------------------- 
1557 void wxPropertyGrid::PrepareAfterItemsAdded() 
1559     if ( !m_pState 
|| !m_pState
->m_itemsAdded 
) return; 
1561     m_pState
->m_itemsAdded 
= 0; 
1563     if ( m_windowStyle 
& wxPG_AUTO_SORT 
) 
1564         Sort(wxPG_SORT_TOP_LEVEL_ONLY
); 
1566     RecalculateVirtualSize(); 
1569 // ----------------------------------------------------------------------- 
1570 // wxPropertyGrid property operations 
1571 // ----------------------------------------------------------------------- 
1573 bool wxPropertyGrid::EnsureVisible( wxPGPropArg id 
) 
1575     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) 
1579     bool changed 
= false; 
1581     // Is it inside collapsed section? 
1582     if ( !p
->IsVisible() ) 
1585         wxPGProperty
* parent 
= p
->GetParent(); 
1586         wxPGProperty
* grandparent 
= parent
->GetParent(); 
1588         if ( grandparent 
&& grandparent 
!= m_pState
->m_properties 
) 
1589             Expand( grandparent 
); 
1597     GetViewStart(&vx
,&vy
); 
1598     vy
*=wxPG_PIXELS_PER_UNIT
; 
1604         Scroll(vx
, y
/wxPG_PIXELS_PER_UNIT 
); 
1605         m_iFlags 
|= wxPG_FL_SCROLLED
; 
1608     else if ( (y
+m_lineHeight
) > (vy
+m_height
) ) 
1610         Scroll(vx
, (y
-m_height
+(m_lineHeight
*2))/wxPG_PIXELS_PER_UNIT 
); 
1611         m_iFlags 
|= wxPG_FL_SCROLLED
; 
1621 // ----------------------------------------------------------------------- 
1622 // wxPropertyGrid helper methods called by properties 
1623 // ----------------------------------------------------------------------- 
1625 // Control font changer helper. 
1626 void wxPropertyGrid::SetCurControlBoldFont() 
1628     wxASSERT( m_wndEditor 
); 
1629     m_wndEditor
->SetFont( m_captionFont 
); 
1632 // ----------------------------------------------------------------------- 
1634 wxPoint 
wxPropertyGrid::GetGoodEditorDialogPosition( wxPGProperty
* p
, 
1637 #if wxPG_SMALL_SCREEN 
1638     // On small-screen devices, always show dialogs with default position and size. 
1639     return wxDefaultPosition
; 
1641     int splitterX 
= GetSplitterPosition(); 
1645     wxCHECK_MSG( y 
>= 0, wxPoint(-1,-1), wxT("invalid y?") ); 
1647     ImprovedClientToScreen( &x
, &y 
); 
1649     int sw 
= wxSystemSettings::GetMetric( ::wxSYS_SCREEN_X 
); 
1650     int sh 
= wxSystemSettings::GetMetric( ::wxSYS_SCREEN_Y 
); 
1657         new_x 
= x 
+ (m_width
-splitterX
) - sz
.x
; 
1667         new_y 
= y 
+ m_lineHeight
; 
1669     return wxPoint(new_x
,new_y
); 
1673 // ----------------------------------------------------------------------- 
1675 wxString
& wxPropertyGrid::ExpandEscapeSequences( wxString
& dst_str
, wxString
& src_str 
) 
1677     if ( src_str
.length() == 0 ) 
1683     bool prev_is_slash 
= false; 
1685     wxString::const_iterator i 
= src_str
.begin(); 
1689     for ( ; i 
!= src_str
.end(); ++i 
) 
1693         if ( a 
!= wxS('\\') ) 
1695             if ( !prev_is_slash 
) 
1701                 if ( a 
== wxS('n') ) 
1704                     dst_str 
<< wxS('\n'); 
1706                     dst_str 
<< wxS('\n'); 
1709                 else if ( a 
== wxS('t') ) 
1710                     dst_str 
<< wxS('\t'); 
1714             prev_is_slash 
= false; 
1718             if ( prev_is_slash 
) 
1720                 dst_str 
<< wxS('\\'); 
1721                 prev_is_slash 
= false; 
1725                 prev_is_slash 
= true; 
1732 // ----------------------------------------------------------------------- 
1734 wxString
& wxPropertyGrid::CreateEscapeSequences( wxString
& dst_str
, wxString
& src_str 
) 
1736     if ( src_str
.length() == 0 ) 
1742     wxString::const_iterator i 
= src_str
.begin(); 
1743     wxUniChar prev_a 
= wxS('\0'); 
1747     for ( ; i 
!= src_str
.end(); ++i 
) 
1751         if ( a 
>= wxS(' ') ) 
1753             // This surely is not something that requires an escape sequence. 
1758             // This might need... 
1759             if ( a 
== wxS('\r')  ) 
1761                 // DOS style line end. 
1762                 // Already taken care below 
1764             else if ( a 
== wxS('\n') ) 
1765                 // UNIX style line end. 
1766                 dst_str 
<< wxS("\\n"); 
1767             else if ( a 
== wxS('\t') ) 
1769                 dst_str 
<< wxS('\t'); 
1772                 //wxLogDebug(wxT("WARNING: Could not create escape sequence for character #%i"),(int)a); 
1782 // ----------------------------------------------------------------------- 
1784 wxPGProperty
* wxPropertyGrid::DoGetItemAtY( int y 
) const 
1791     return m_pState
->m_properties
->GetItemAtY(y
, m_lineHeight
, &a
); 
1794 // ----------------------------------------------------------------------- 
1795 // wxPropertyGrid graphics related methods 
1796 // ----------------------------------------------------------------------- 
1798 void wxPropertyGrid::OnPaint( wxPaintEvent
& WXUNUSED(event
) ) 
1803     // Don't paint after destruction has begun 
1804     if ( !HasInternalFlag(wxPG_FL_INITIALIZED
) ) 
1807     // Find out where the window is scrolled to 
1808     int vx
,vy
;                     // Top left corner of client 
1809     GetViewStart(&vx
,&vy
); 
1810     vy 
*= wxPG_PIXELS_PER_UNIT
; 
1812     // Update everything inside the box 
1813     wxRect r 
= GetUpdateRegion().GetBox(); 
1817     // FIXME: This is just a workaround for a bug that causes splitters not 
1818     //        to paint when other windows are being dragged over the grid. 
1820     r
.width 
= GetClientSize().x
; 
1822     // Repaint this rectangle 
1823     DrawItems( dc
, r
.y
, r
.y 
+ r
.height
, &r 
); 
1825     // We assume that the size set when grid is shown 
1826     // is what is desired. 
1827     SetInternalFlag(wxPG_FL_GOOD_SIZE_SET
); 
1830 // ----------------------------------------------------------------------- 
1832 void wxPropertyGrid::DrawExpanderButton( wxDC
& dc
, const wxRect
& rect
, 
1833                                          wxPGProperty
* property 
) const 
1835     // Prepare rectangle to be used 
1837     r
.x 
+= m_gutterWidth
; r
.y 
+= m_buttonSpacingY
; 
1838     r
.width 
= m_iconWidth
; r
.height 
= m_iconHeight
; 
1840 #if (wxPG_USE_RENDERER_NATIVE) 
1842 #elif wxPG_ICON_WIDTH 
1843     // Drawing expand/collapse button manually 
1844     dc
.SetPen(m_colPropFore
); 
1845     if ( property
->IsCategory() ) 
1846         dc
.SetBrush(*wxTRANSPARENT_BRUSH
); 
1848         dc
.SetBrush(m_colPropBack
); 
1850     dc
.DrawRectangle( r 
); 
1851     int _y 
= r
.y
+(m_iconWidth
/2); 
1852     dc
.DrawLine(r
.x
+2,_y
,r
.x
+m_iconWidth
-2,_y
); 
1857     if ( property
->IsExpanded() ) 
1859     // wxRenderer functions are non-mutating in nature, so it 
1860     // should be safe to cast "const wxPropertyGrid*" to "wxWindow*". 
1861     // Hopefully this does not cause problems. 
1862     #if (wxPG_USE_RENDERER_NATIVE) 
1863         wxRendererNative::Get().DrawTreeItemButton( 
1869     #elif wxPG_ICON_WIDTH 
1878     #if (wxPG_USE_RENDERER_NATIVE) 
1879         wxRendererNative::Get().DrawTreeItemButton( 
1885     #elif wxPG_ICON_WIDTH 
1886         int _x 
= r
.x
+(m_iconWidth
/2); 
1887         dc
.DrawLine(_x
,r
.y
+2,_x
,r
.y
+m_iconWidth
-2); 
1893 #if (wxPG_USE_RENDERER_NATIVE) 
1895 #elif wxPG_ICON_WIDTH 
1898     dc
.DrawBitmap( *bmp
, r
.x
, r
.y
, true ); 
1902 // ----------------------------------------------------------------------- 
1905 // This is the one called by OnPaint event handler and others. 
1906 // topy and bottomy are already unscrolled (ie. physical) 
1908 void wxPropertyGrid::DrawItems( wxDC
& dc
, 
1909                                 unsigned int topItemY
, 
1910                                 unsigned int bottomItemY
, 
1911                                 const wxRect
* drawRect 
) 
1915          bottomItemY 
< topItemY 
|| 
1919     m_pState
->EnsureVirtualHeight(); 
1921     wxRect tempDrawRect
; 
1924         tempDrawRect 
= wxRect(0, topItemY
, 
1927         drawRect 
= &tempDrawRect
; 
1930     // items added check 
1931     if ( m_pState
->m_itemsAdded 
) PrepareAfterItemsAdded(); 
1933     int paintFinishY 
= 0; 
1935     if ( m_pState
->m_properties
->GetChildCount() > 0 ) 
1938         bool isBuffered 
= false; 
1940     #if wxPG_DOUBLE_BUFFER 
1941         wxMemoryDC
* bufferDC 
= NULL
; 
1943         if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING
) ) 
1945             if ( !m_doubleBuffer 
) 
1947                 paintFinishY 
= drawRect
->y
; 
1952                 bufferDC 
= new wxMemoryDC(); 
1954                 // If nothing was changed, then just copy from double-buffer 
1955                 bufferDC
->SelectObject( *m_doubleBuffer 
); 
1965             dc
.SetClippingRegion( *drawRect 
); 
1966             paintFinishY 
= DoDrawItems( *dcPtr
, drawRect
, isBuffered 
); 
1967             int drawBottomY 
= drawRect
->y 
+ drawRect
->height
; 
1969             // Clear area beyond last painted property 
1970             if ( paintFinishY 
< drawBottomY 
) 
1972                 dcPtr
->SetPen(m_colEmptySpace
); 
1973                 dcPtr
->SetBrush(m_colEmptySpace
); 
1974                 dcPtr
->DrawRectangle(0, paintFinishY
, 
1979             dc
.DestroyClippingRegion(); 
1982     #if wxPG_DOUBLE_BUFFER 
1985             dc
.Blit( drawRect
->x
, drawRect
->y
, drawRect
->width
, 
1987                      bufferDC
, 0, 0, wxCOPY 
); 
1994         // Just clear the area 
1995         dc
.SetPen(m_colEmptySpace
); 
1996         dc
.SetBrush(m_colEmptySpace
); 
1997         dc
.DrawRectangle(*drawRect
); 
2001 // ----------------------------------------------------------------------- 
2003 int wxPropertyGrid::DoDrawItems( wxDC
& dc
, 
2004                                  const wxRect
* drawRect
, 
2005                                  bool isBuffered 
) const 
2007     const wxPGProperty
* firstItem
; 
2008     const wxPGProperty
* lastItem
; 
2010     firstItem 
= DoGetItemAtY(drawRect
->y
); 
2011     lastItem 
= DoGetItemAtY(drawRect
->y
+drawRect
->height
-1); 
2014         lastItem 
= GetLastItem( wxPG_ITERATE_VISIBLE 
); 
2016     if ( m_frozen 
|| m_height 
< 1 || firstItem 
== NULL 
) 
2019     wxCHECK_MSG( !m_pState
->m_itemsAdded
, drawRect
->y
, 
2021     wxASSERT( m_pState
->m_properties
->GetChildCount() ); 
2023     int lh 
= m_lineHeight
; 
2026     int lastItemBottomY
; 
2028     firstItemTopY 
= drawRect
->y
; 
2029     lastItemBottomY 
= drawRect
->y 
+ drawRect
->height
; 
2031     // Align y coordinates to item boundaries 
2032     firstItemTopY 
-= firstItemTopY 
% lh
; 
2033     lastItemBottomY 
+= lh 
- (lastItemBottomY 
% lh
); 
2034     lastItemBottomY 
-= 1; 
2036     // Entire range outside scrolled, visible area? 
2037     if ( firstItemTopY 
>= (int)m_pState
->GetVirtualHeight() || 
2038          lastItemBottomY 
<= 0 ) 
2041     wxCHECK_MSG( firstItemTopY 
< lastItemBottomY
, 
2043                  "invalid y values" ); 
2046     wxLogDebug("  -> DoDrawItems ( \"%s\" -> \"%s\" 
2047                "height=%i (ch=%i), drawRect = 0x%lX )", 
2048         firstItem->GetLabel().c_str(), 
2049         lastItem->GetLabel().c_str(), 
2050         (int)(lastItemBottomY - firstItemTopY), 
2052         (unsigned long)drawRect ); 
2057     long windowStyle 
= m_windowStyle
; 
2062     // With wxPG_DOUBLE_BUFFER, do double buffering 
2063     // - buffer's y = 0, so align drawRect and coordinates to that 
2065 #if wxPG_DOUBLE_BUFFER 
2072         xRelMod 
= drawRect
->x
; 
2073         yRelMod 
= drawRect
->y
; 
2076         // drawRect conversion 
2081         firstItemTopY 
-= yRelMod
; 
2082         lastItemBottomY 
-= yRelMod
; 
2085     wxUnusedVar(isBuffered
); 
2088     int x 
= m_marginWidth 
- xRelMod
; 
2090     wxFont normalFont 
= GetFont(); 
2092     bool reallyFocused 
= (m_iFlags 
& wxPG_FL_FOCUSED
) != 0; 
2094     bool isPgEnabled 
= IsEnabled(); 
2097     // Prepare some pens and brushes that are often changed to. 
2100     wxBrush 
marginBrush(m_colMargin
); 
2101     wxPen 
marginPen(m_colMargin
); 
2102     wxBrush 
capbgbrush(m_colCapBack
,wxSOLID
); 
2103     wxPen 
linepen(m_colLine
,1,wxSOLID
); 
2105     wxColour selBackCol
; 
2107         selBackCol 
= m_colSelBack
; 
2109         selBackCol 
= m_colMargin
; 
2111     // pen that has same colour as text 
2112     wxPen 
outlinepen(m_colPropFore
,1,wxSOLID
); 
2115     // Clear margin with background colour 
2117     dc
.SetBrush( marginBrush 
); 
2118     if ( !(windowStyle 
& wxPG_HIDE_MARGIN
) ) 
2120         dc
.SetPen( *wxTRANSPARENT_PEN 
); 
2121         dc
.DrawRectangle(-1-xRelMod
,firstItemTopY
-1,x
+2,lastItemBottomY
-firstItemTopY
+2); 
2124     const wxPGProperty
* firstSelected 
= GetSelection(); 
2125     const wxPropertyGridPageState
* state 
= m_pState
; 
2126     const wxArrayInt
& colWidths 
= state
->m_colWidths
; 
2128 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2129     bool wasSelectedPainted 
= false; 
2132     // TODO: Only render columns that are within clipping region. 
2134     dc
.SetFont(normalFont
); 
2136     wxPropertyGridConstIterator 
it( state
, wxPG_ITERATE_VISIBLE
, firstItem 
); 
2137     int endScanBottomY 
= lastItemBottomY 
+ lh
; 
2138     int y 
= firstItemTopY
; 
2141     // Pregenerate list of visible properties. 
2142     wxArrayPGProperty visPropArray
; 
2143     visPropArray
.reserve((m_height
/m_lineHeight
)+6); 
2145     for ( ; !it
.AtEnd(); it
.Next() ) 
2147         const wxPGProperty
* p 
= *it
; 
2149         if ( !p
->HasFlag(wxPG_PROP_HIDDEN
) ) 
2151             visPropArray
.push_back((wxPGProperty
*)p
); 
2153             if ( y 
> endScanBottomY 
) 
2160     visPropArray
.push_back(NULL
); 
2162     wxPGProperty
* nextP 
= visPropArray
[0]; 
2164     int gridWidth 
= state
->m_width
; 
2167     for ( unsigned int arrInd
=1; 
2168           nextP 
&& y 
<= lastItemBottomY
; 
2171         wxPGProperty
* p 
= nextP
; 
2172         nextP 
= visPropArray
[arrInd
]; 
2174         int rowHeight 
= m_fontHeight
+(m_spacingy
*2)+1; 
2175         int textMarginHere 
= x
; 
2176         int renderFlags 
= 0; 
2178         int greyDepth 
= m_marginWidth
; 
2179         if ( !(windowStyle 
& wxPG_HIDE_CATEGORIES
) ) 
2180             greyDepth 
= (((int)p
->m_depthBgCol
)-1) * m_subgroup_extramargin 
+ m_marginWidth
; 
2182         int greyDepthX 
= greyDepth 
- xRelMod
; 
2184         // Use basic depth if in non-categoric mode and parent is base array. 
2185         if ( !(windowStyle 
& wxPG_HIDE_CATEGORIES
) || p
->GetParent() != m_pState
->m_properties 
) 
2187             textMarginHere 
+= ((unsigned int)((p
->m_depth
-1)*m_subgroup_extramargin
)); 
2190         // Paint margin area 
2191         dc
.SetBrush(marginBrush
); 
2192         dc
.SetPen(marginPen
); 
2193         dc
.DrawRectangle( -xRelMod
, y
, greyDepth
, lh 
); 
2195         dc
.SetPen( linepen 
); 
2201         // Modified by JACS to not draw a margin if wxPG_HIDE_MARGIN is specified, since it 
2202         // looks better, at least under Windows when we have a themed border (the themed-window-specific 
2203         // whitespace between the real border and the propgrid margin exacerbates the double-border look). 
2205         // Is this or its parent themed? 
2206         bool suppressMarginEdge 
= (GetWindowStyle() & wxPG_HIDE_MARGIN
) && 
2207             (((GetWindowStyle() & wxBORDER_MASK
) == wxBORDER_THEME
) || 
2208             (((GetWindowStyle() & wxBORDER_MASK
) == wxBORDER_NONE
) && ((GetParent()->GetWindowStyle() & wxBORDER_MASK
) == wxBORDER_THEME
))); 
2210         bool suppressMarginEdge 
= false; 
2212         if (!suppressMarginEdge
) 
2213             dc
.DrawLine( greyDepthX
, y
, greyDepthX
, y2 
); 
2216             // Blank out the margin edge 
2217             dc
.SetPen(wxPen(GetBackgroundColour())); 
2218             dc
.DrawLine( greyDepthX
, y
, greyDepthX
, y2 
); 
2219             dc
.SetPen( linepen 
); 
2226         for ( si
=0; si
<colWidths
.size(); si
++ ) 
2228             sx 
+= colWidths
[si
]; 
2229             dc
.DrawLine( sx
, y
, sx
, y2 
); 
2232         // Horizontal Line, below 
2233         //   (not if both this and next is category caption) 
2234         if ( p
->IsCategory() && 
2235              nextP 
&& nextP
->IsCategory() ) 
2236             dc
.SetPen(m_colCapBack
); 
2238         dc
.DrawLine( greyDepthX
, y2
-1, gridWidth
-xRelMod
, y2
-1 ); 
2241         // Need to override row colours? 
2245         bool isSelected 
= state
->DoIsPropertySelected(p
); 
2249             // Disabled may get different colour. 
2250             if ( !p
->IsEnabled() ) 
2252                 renderFlags 
|= wxPGCellRenderer::Disabled 
| 
2253                                wxPGCellRenderer::DontUseCellFgCol
; 
2254                 rowFgCol 
= m_colDisPropFore
; 
2259 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2260             if ( p 
== firstSelected 
) 
2261                 wasSelectedPainted 
= true; 
2264             renderFlags 
|= wxPGCellRenderer::Selected
; 
2266             if ( !p
->IsCategory() ) 
2268                 renderFlags 
|= wxPGCellRenderer::DontUseCellFgCol 
| 
2269                                wxPGCellRenderer::DontUseCellBgCol
; 
2271                 if ( reallyFocused 
&& p 
== firstSelected 
) 
2273                     rowFgCol 
= m_colSelFore
; 
2274                     rowBgCol 
= selBackCol
; 
2276                 else if ( isPgEnabled 
) 
2278                     rowFgCol 
= m_colPropFore
; 
2279                     if ( p 
== firstSelected 
) 
2280                         rowBgCol 
= m_colMargin
; 
2282                         rowBgCol 
= selBackCol
; 
2286                     rowFgCol 
= m_colDisPropFore
; 
2287                     rowBgCol 
= selBackCol
; 
2294         if ( rowBgCol
.IsOk() ) 
2295             rowBgBrush 
= wxBrush(rowBgCol
); 
2297         if ( HasInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
) ) 
2298             renderFlags 
= renderFlags 
& ~wxPGCellRenderer::DontUseCellColours
; 
2301         // Fill additional margin area with background colour of first cell 
2302         if ( greyDepthX 
< textMarginHere 
) 
2304             if ( !(renderFlags 
& wxPGCellRenderer::DontUseCellBgCol
) ) 
2306                 wxPGCell
& cell 
= p
->GetCell(0); 
2307                 rowBgCol 
= cell
.GetBgCol(); 
2308                 rowBgBrush 
= wxBrush(rowBgCol
); 
2310             dc
.SetBrush(rowBgBrush
); 
2311             dc
.SetPen(rowBgCol
); 
2312             dc
.DrawRectangle(greyDepthX
+1, y
, 
2313                              textMarginHere
-greyDepthX
, lh
-1); 
2316         bool fontChanged 
= false; 
2318         // Expander button rectangle 
2319         wxRect 
butRect( ((p
->m_depth 
- 1) * m_subgroup_extramargin
) - xRelMod
, 
2324         // Default cell rect fill the entire row 
2325         wxRect 
cellRect(greyDepthX
, y
, 
2326                         gridWidth 
- greyDepth 
+ 2, rowHeight
-1 ); 
2328         bool isCategory 
= p
->IsCategory(); 
2332             dc
.SetFont(m_captionFont
); 
2335             if ( renderFlags 
& wxPGCellRenderer::DontUseCellBgCol 
) 
2337                 dc
.SetBrush(rowBgBrush
); 
2338                 dc
.SetPen(rowBgCol
); 
2341             if ( renderFlags 
& wxPGCellRenderer::DontUseCellFgCol 
) 
2343                 dc
.SetTextForeground(rowFgCol
); 
2348             // Fine tune button rectangle to actually fit the cell 
2349             if ( butRect
.x 
> 0 ) 
2350                 butRect
.x 
+= IN_CELL_EXPANDER_BUTTON_X_ADJUST
; 
2352             if ( p
->m_flags 
& wxPG_PROP_MODIFIED 
&& 
2353                  (windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
2355                 dc
.SetFont(m_captionFont
); 
2359             // Magic fine-tuning for non-category rows 
2363         int firstCellWidth 
= colWidths
[0] - (greyDepthX 
- m_marginWidth
); 
2364         int firstCellX 
= cellRect
.x
; 
2366         // Calculate cellRect.x for the last cell 
2367         unsigned int ci 
= 0; 
2369         for ( ci
=0; ci
<colWidths
.size(); ci
++ ) 
2370             cellX 
+= colWidths
[ci
]; 
2373         // Draw cells from back to front so that we can easily tell if the 
2374         // cell on the right was empty from text 
2375         bool prevFilled 
= true; 
2376         ci 
= colWidths
.size(); 
2385                 textXAdd 
= textMarginHere 
- greyDepthX
; 
2386                 cellRect
.width 
= firstCellWidth
; 
2387                 cellRect
.x 
= firstCellX
; 
2391                 int colWidth 
= colWidths
[ci
]; 
2392                 cellRect
.width 
= colWidth
; 
2393                 cellRect
.x 
-= colWidth
; 
2396             // Merge with column to the right? 
2397             if ( !prevFilled 
&& isCategory 
) 
2399                 cellRect
.width 
+= colWidths
[ci
+1]; 
2403                 cellRect
.width 
-= 1; 
2405             wxWindow
* cellEditor 
= NULL
; 
2406             int cellRenderFlags 
= renderFlags
; 
2408             // Tree Item Button (must be drawn before clipping is set up) 
2409             if ( ci 
== 0 && !HasFlag(wxPG_HIDE_MARGIN
) && p
->HasVisibleChildren() ) 
2410                 DrawExpanderButton( dc
, butRect
, p 
); 
2413             if ( isSelected 
&& (ci 
== 1 || ci 
== m_selColumn
) ) 
2415                 if ( p 
== firstSelected 
) 
2417                     if ( ci 
== 1 && m_wndEditor 
) 
2418                         cellEditor 
= m_wndEditor
; 
2419                     else if ( ci 
== m_selColumn 
&& m_labelEditor 
) 
2420                         cellEditor 
= m_labelEditor
; 
2425                     wxColour editorBgCol 
= 
2426                         cellEditor
->GetBackgroundColour(); 
2427                     dc
.SetBrush(editorBgCol
); 
2428                     dc
.SetPen(editorBgCol
); 
2429                     dc
.SetTextForeground(m_colPropFore
); 
2430                     dc
.DrawRectangle(cellRect
); 
2432                     if ( m_dragStatus 
!= 0 || 
2433                          (m_iFlags 
& wxPG_FL_CUR_USES_CUSTOM_IMAGE
) ) 
2438                     dc
.SetBrush(m_colPropBack
); 
2439                     dc
.SetPen(m_colPropBack
); 
2440                     dc
.SetTextForeground(m_colDisPropFore
); 
2441                     if ( p
->IsEnabled() ) 
2442                         dc
.SetTextForeground(rowFgCol
); 
2444                         dc
.SetTextForeground(m_colDisPropFore
); 
2449                 if ( renderFlags 
& wxPGCellRenderer::DontUseCellBgCol 
) 
2451                     dc
.SetBrush(rowBgBrush
); 
2452                     dc
.SetPen(rowBgCol
); 
2455                 if ( renderFlags 
& wxPGCellRenderer::DontUseCellFgCol 
) 
2457                     dc
.SetTextForeground(rowFgCol
); 
2461             dc
.SetClippingRegion(cellRect
); 
2463             cellRect
.x 
+= textXAdd
; 
2464             cellRect
.width 
-= textXAdd
; 
2469                 wxPGCellRenderer
* renderer
; 
2470                 int cmnVal 
= p
->GetCommonValue(); 
2471                 if ( cmnVal 
== -1 || ci 
!= 1 ) 
2473                     renderer 
= p
->GetCellRenderer(ci
); 
2474                     prevFilled 
= renderer
->Render(dc
, cellRect
, this, 
2480                     renderer 
= GetCommonValue(cmnVal
)->GetRenderer(); 
2481                     prevFilled 
= renderer
->Render(dc
, cellRect
, this, 
2491             dc
.DestroyClippingRegion(); // Is this really necessary? 
2496             dc
.SetFont(normalFont
); 
2501     // Refresh editor controls (seems not needed on msw) 
2502     // NOTE: This code is mandatory for GTK! 
2503 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2504     if ( wasSelectedPainted 
) 
2507             m_wndEditor
->Refresh(); 
2509             m_wndEditor2
->Refresh(); 
2516 // ----------------------------------------------------------------------- 
2518 wxRect 
wxPropertyGrid::GetPropertyRect( const wxPGProperty
* p1
, const wxPGProperty
* p2 
) const 
2522     if ( m_width 
< 10 || m_height 
< 10 || 
2523          !m_pState
->m_properties
->GetChildCount() || 
2525         return wxRect(0,0,0,0); 
2530     // Return rect which encloses the given property range 
2532     int visTop 
= p1
->GetY(); 
2535         visBottom 
= p2
->GetY() + m_lineHeight
; 
2537         visBottom 
= m_height 
+ visTop
; 
2539     // If seleced property is inside the range, we'll extend the range to include 
2541     wxPGProperty
* selected 
= GetSelection(); 
2544         int selectedY 
= selected
->GetY(); 
2545         if ( selectedY 
>= visTop 
&& selectedY 
< visBottom 
) 
2547             wxWindow
* editor 
= GetEditorControl(); 
2550                 int visBottom2 
= selectedY 
+ editor
->GetSize().y
; 
2551                 if ( visBottom2 
> visBottom 
) 
2552                     visBottom 
= visBottom2
; 
2557     return wxRect(0,visTop
-vy
,m_pState
->m_width
,visBottom
-visTop
); 
2560 // ----------------------------------------------------------------------- 
2562 void wxPropertyGrid::DrawItems( const wxPGProperty
* p1
, const wxPGProperty
* p2 
) 
2567     if ( m_pState
->m_itemsAdded 
) 
2568         PrepareAfterItemsAdded(); 
2570     wxRect r 
= GetPropertyRect(p1
, p2
); 
2577 // ----------------------------------------------------------------------- 
2579 void wxPropertyGrid::RefreshProperty( wxPGProperty
* p 
) 
2581     if ( m_pState
->DoIsPropertySelected(p
) ) 
2583         // NB: We must copy the selection. 
2584         wxArrayPGProperty selection 
= m_pState
->m_selection
; 
2585         DoSetSelection(selection
, wxPG_SEL_FORCE
); 
2588     DrawItemAndChildren(p
); 
2591 // ----------------------------------------------------------------------- 
2593 void wxPropertyGrid::DrawItemAndValueRelated( wxPGProperty
* p 
) 
2598     // Draw item, children, and parent too, if it is not category 
2599     wxPGProperty
* parent 
= p
->GetParent(); 
2602             !parent
->IsCategory() && 
2603             parent
->GetParent() ) 
2606          parent 
= parent
->GetParent(); 
2609     DrawItemAndChildren(p
); 
2612 void wxPropertyGrid::DrawItemAndChildren( wxPGProperty
* p 
) 
2614     wxCHECK_RET( p
, wxT("invalid property id") ); 
2616     // Do not draw if in non-visible page 
2617     if ( p
->GetParentState() != m_pState 
) 
2620     // do not draw a single item if multiple pending 
2621     if ( m_pState
->m_itemsAdded 
|| m_frozen 
) 
2624     // Update child control. 
2625     wxPGProperty
* selected 
= GetSelection(); 
2626     if ( selected 
&& selected
->GetParent() == p 
) 
2629     const wxPGProperty
* lastDrawn 
= p
->GetLastVisibleSubItem(); 
2631     DrawItems(p
, lastDrawn
); 
2634 // ----------------------------------------------------------------------- 
2636 void wxPropertyGrid::Refresh( bool WXUNUSED(eraseBackground
), 
2637                               const wxRect 
*rect 
) 
2639     PrepareAfterItemsAdded(); 
2641     wxWindow::Refresh(false, rect
); 
2643 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
2644     // I think this really helps only GTK+1.2 
2645     if ( m_wndEditor 
) m_wndEditor
->Refresh(); 
2646     if ( m_wndEditor2 
) m_wndEditor2
->Refresh(); 
2650 // ----------------------------------------------------------------------- 
2651 // wxPropertyGrid global operations 
2652 // ----------------------------------------------------------------------- 
2654 void wxPropertyGrid::Clear() 
2656     m_pState
->DoClear(); 
2662     RecalculateVirtualSize(); 
2664     // Need to clear some area at the end 
2666         RefreshRect(wxRect(0, 0, m_width
, m_height
)); 
2669 // ----------------------------------------------------------------------- 
2671 bool wxPropertyGrid::EnableCategories( bool enable 
) 
2678         // Enable categories 
2681         m_windowStyle 
&= ~(wxPG_HIDE_CATEGORIES
); 
2686         // Disable categories 
2688         m_windowStyle 
|= wxPG_HIDE_CATEGORIES
; 
2691     if ( !m_pState
->EnableCategories(enable
) ) 
2696         if ( m_windowStyle 
& wxPG_AUTO_SORT 
) 
2698             m_pState
->m_itemsAdded 
= 1; // force 
2699             PrepareAfterItemsAdded(); 
2703         m_pState
->m_itemsAdded 
= 1; 
2705     // No need for RecalculateVirtualSize() here - it is already called in 
2706     // wxPropertyGridPageState method above. 
2713 // ----------------------------------------------------------------------- 
2715 void wxPropertyGrid::SwitchState( wxPropertyGridPageState
* pNewState 
) 
2717     wxASSERT( pNewState 
); 
2718     wxASSERT( pNewState
->GetGrid() ); 
2720     if ( pNewState 
== m_pState 
) 
2723     wxArrayPGProperty oldSelection 
= m_pState
->m_selection
; 
2725     // Call ClearSelection() instead of DoClearSelection() 
2726     // so that selection clear events are not sent. 
2729     m_pState
->m_selection 
= oldSelection
; 
2731     bool orig_mode 
= m_pState
->IsInNonCatMode(); 
2732     bool new_state_mode 
= pNewState
->IsInNonCatMode(); 
2734     m_pState 
= pNewState
; 
2737     int pgWidth 
= GetClientSize().x
; 
2738     if ( HasVirtualWidth() ) 
2740         int minWidth 
= pgWidth
; 
2741         if ( pNewState
->m_width 
< minWidth 
) 
2743             pNewState
->m_width 
= minWidth
; 
2744             pNewState
->CheckColumnWidths(); 
2750         // Just in case, fully re-center splitter 
2751         //if ( HasFlag( wxPG_SPLITTER_AUTO_CENTER ) ) 
2752         //    pNewState->m_fSplitterX = -1.0; 
2754         pNewState
->OnClientWidthChange(pgWidth
, 
2755                                        pgWidth 
- pNewState
->m_width
); 
2760     // If necessary, convert state to correct mode. 
2761     if ( orig_mode 
!= new_state_mode 
) 
2763         // This should refresh as well. 
2764         EnableCategories( orig_mode
?false:true ); 
2766     else if ( !m_frozen 
) 
2768         // Refresh, if not frozen. 
2769         m_pState
->PrepareAfterItemsAdded(); 
2771         // Reselect (Use SetSelection() instead of Do-variant so that 
2772         // events won't be sent). 
2773         SetSelection(m_pState
->m_selection
); 
2775         RecalculateVirtualSize(0); 
2779         m_pState
->m_itemsAdded 
= 1; 
2782 // ----------------------------------------------------------------------- 
2784 // Call to SetSplitterPosition will always disable splitter auto-centering 
2785 // if parent window is shown. 
2786 void wxPropertyGrid::DoSetSplitterPosition( int newxpos
, 
2790     if ( ( newxpos 
< wxPG_DRAG_MARGIN 
) ) 
2793     wxPropertyGridPageState
* state 
= m_pState
; 
2795     if ( flags 
& wxPG_SPLITTER_FROM_EVENT 
) 
2796         state
->m_dontCenterSplitter 
= true; 
2798     state
->DoSetSplitterPosition(newxpos
, splitterIndex
, flags
); 
2800     if ( flags 
& wxPG_SPLITTER_REFRESH 
) 
2802         if ( GetSelection() ) 
2803             CorrectEditorWidgetSizeX(); 
2811 // ----------------------------------------------------------------------- 
2813 void wxPropertyGrid::CenterSplitter( bool enableAutoCentering 
) 
2815     SetSplitterPosition( m_width
/2 ); 
2816     if ( enableAutoCentering 
&& HasFlag(wxPG_SPLITTER_AUTO_CENTER
) ) 
2817         m_pState
->m_dontCenterSplitter 
= false; 
2820 // ----------------------------------------------------------------------- 
2821 // wxPropertyGrid item iteration (GetNextProperty etc.) methods 
2822 // ----------------------------------------------------------------------- 
2824 // Returns nearest paint visible property (such that will be painted unless 
2825 // window is scrolled or resized). If given property is paint visible, then 
2826 // it itself will be returned 
2827 wxPGProperty
* wxPropertyGrid::GetNearestPaintVisible( wxPGProperty
* p 
) const 
2829     int vx
,vy1
;// Top left corner of client 
2830     GetViewStart(&vx
,&vy1
); 
2831     vy1 
*= wxPG_PIXELS_PER_UNIT
; 
2833     int vy2 
= vy1 
+ m_height
; 
2834     int propY 
= p
->GetY2(m_lineHeight
); 
2836     if ( (propY 
+ m_lineHeight
) < vy1 
) 
2839         return DoGetItemAtY( vy1 
); 
2841     else if ( propY 
> vy2 
) 
2844         return DoGetItemAtY( vy2 
); 
2847     // Itself paint visible 
2852 // ----------------------------------------------------------------------- 
2853 // Methods related to change in value, value modification and sending events 
2854 // ----------------------------------------------------------------------- 
2856 // commits any changes in editor of selected property 
2857 // return true if validation did not fail 
2858 // flags are same as with DoSelectProperty 
2859 bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags 
) 
2861     // Committing already? 
2862     if ( m_inCommitChangesFromEditor 
) 
2865     // Don't do this if already processing editor event. It might 
2866     // induce recursive dialogs and crap like that. 
2867     if ( m_iFlags 
& wxPG_FL_IN_HANDLECUSTOMEDITOREVENT 
) 
2869         if ( m_inDoPropertyChanged 
) 
2875     wxPGProperty
* selected 
= GetSelection(); 
2878          IsEditorsValueModified() && 
2879          (m_iFlags 
& wxPG_FL_INITIALIZED
) && 
2882         m_inCommitChangesFromEditor 
= 1; 
2884         wxVariant 
variant(selected
->GetValueRef()); 
2885         bool valueIsPending 
= false; 
2887         // JACS - necessary to avoid new focus being found spuriously within OnIdle 
2888         // due to another window getting focus 
2889         wxWindow
* oldFocus 
= m_curFocused
; 
2891         bool validationFailure 
= false; 
2892         bool forceSuccess 
= (flags 
& (wxPG_SEL_NOVALIDATE
|wxPG_SEL_FORCE
)) ? true : false; 
2894         m_chgInfo_changedProperty 
= NULL
; 
2896         // If truly modified, schedule value as pending. 
2897         if ( selected
->GetEditorClass()-> 
2898                 GetValueFromControl( variant
, 
2900                                      GetEditorControl() ) ) 
2902             if ( DoEditorValidate() && 
2903                  PerformValidation(selected
, variant
) ) 
2905                 valueIsPending 
= true; 
2909                 validationFailure 
= true; 
2914             EditorsValueWasNotModified(); 
2919         m_inCommitChangesFromEditor 
= 0; 
2921         if ( validationFailure 
&& !forceSuccess 
) 
2925                 oldFocus
->SetFocus(); 
2926                 m_curFocused 
= oldFocus
; 
2929             res 
= OnValidationFailure(selected
, variant
); 
2931             // Now prevent further validation failure messages 
2934                 EditorsValueWasNotModified(); 
2935                 OnValidationFailureReset(selected
); 
2938         else if ( valueIsPending 
) 
2940             DoPropertyChanged( selected
, flags 
); 
2941             EditorsValueWasNotModified(); 
2950 // ----------------------------------------------------------------------- 
2952 bool wxPropertyGrid::PerformValidation( wxPGProperty
* p
, wxVariant
& pendingValue
, 
2956     // Runs all validation functionality. 
2957     // Returns true if value passes all tests. 
2960     m_validationInfo
.m_failureBehavior 
= m_permanentValidationFailureBehavior
; 
2963     // Variant list a special value that cannot be validated 
2965     if ( pendingValue
.GetType() != wxPG_VARIANT_TYPE_LIST 
) 
2967         if ( !p
->ValidateValue(pendingValue
, m_validationInfo
) ) 
2972     // Adapt list to child values, if necessary 
2973     wxVariant listValue 
= pendingValue
; 
2974     wxVariant
* pPendingValue 
= &pendingValue
; 
2975     wxVariant
* pList 
= NULL
; 
2977     // If parent has wxPG_PROP_AGGREGATE flag, or uses composite 
2978     // string value, then we need treat as it was changed instead 
2979     // (or, in addition, as is the case with composite string parent). 
2980     // This includes creating list variant for child values. 
2982     wxPGProperty
* pwc 
= p
->GetParent(); 
2983     wxPGProperty
* changedProperty 
= p
; 
2984     wxPGProperty
* baseChangedProperty 
= changedProperty
; 
2985     wxVariant bcpPendingList
; 
2987     listValue 
= pendingValue
; 
2988     listValue
.SetName(p
->GetBaseName()); 
2991             (pwc
->HasFlag(wxPG_PROP_AGGREGATE
) || pwc
->HasFlag(wxPG_PROP_COMPOSED_VALUE
)) ) 
2993         wxVariantList tempList
; 
2994         wxVariant 
lv(tempList
, pwc
->GetBaseName()); 
2995         lv
.Append(listValue
); 
2997         pPendingValue 
= &listValue
; 
2999         if ( pwc
->HasFlag(wxPG_PROP_AGGREGATE
) ) 
3001             baseChangedProperty 
= pwc
; 
3002             bcpPendingList 
= lv
; 
3005         changedProperty 
= pwc
; 
3006         pwc 
= pwc
->GetParent(); 
3010     wxPGProperty
* evtChangingProperty 
= changedProperty
; 
3012     if ( pPendingValue
->GetType() != wxPG_VARIANT_TYPE_LIST 
) 
3014         value 
= *pPendingValue
; 
3018         // Convert list to child values 
3019         pList 
= pPendingValue
; 
3020         changedProperty
->AdaptListToValue( *pPendingValue
, &value 
); 
3023     wxVariant evtChangingValue 
= value
; 
3025     if ( flags 
& SendEvtChanging 
) 
3027         // FIXME: After proper ValueToString()s added, remove 
3028         // this. It is just a temporary fix, as evt_changing 
3029         // will simply not work for wxPG_PROP_COMPOSED_VALUE 
3030         // (unless it is selected, and textctrl editor is open). 
3031         if ( changedProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
3033             evtChangingProperty 
= baseChangedProperty
; 
3034             if ( evtChangingProperty 
!= p 
) 
3036                 evtChangingProperty
->AdaptListToValue( bcpPendingList
, &evtChangingValue 
); 
3040                 evtChangingValue 
= pendingValue
; 
3044         if ( evtChangingProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
3046             if ( changedProperty 
== GetSelection() ) 
3048                 wxWindow
* editor 
= GetEditorControl(); 
3049                 wxASSERT( editor
->IsKindOf(CLASSINFO(wxTextCtrl
)) ); 
3050                 evtChangingValue 
= wxStaticCast(editor
, wxTextCtrl
)->GetValue(); 
3054                 wxLogDebug(wxT("WARNING: wxEVT_PG_CHANGING is about to happen with old value.")); 
3059     wxASSERT( m_chgInfo_changedProperty 
== NULL 
); 
3060     m_chgInfo_changedProperty 
= changedProperty
; 
3061     m_chgInfo_baseChangedProperty 
= baseChangedProperty
; 
3062     m_chgInfo_pendingValue 
= value
; 
3065         m_chgInfo_valueList 
= *pList
; 
3067         m_chgInfo_valueList
.MakeNull(); 
3069     // If changedProperty is not property which value was edited, 
3070     // then call wxPGProperty::ValidateValue() for that as well. 
3071     if ( p 
!= changedProperty 
&& value
.GetType() != wxPG_VARIANT_TYPE_LIST 
) 
3073         if ( !changedProperty
->ValidateValue(value
, m_validationInfo
) ) 
3077     if ( flags 
& SendEvtChanging 
) 
3079         // SendEvent returns true if event was vetoed 
3080         if ( SendEvent( wxEVT_PG_CHANGING
, evtChangingProperty
, 
3081                         &evtChangingValue 
) ) 
3085     if ( flags 
& IsStandaloneValidation 
) 
3087         // If called in 'generic' context, we need to reset 
3088         // m_chgInfo_changedProperty and write back translated value. 
3089         m_chgInfo_changedProperty 
= NULL
; 
3090         pendingValue 
= value
; 
3096 // ----------------------------------------------------------------------- 
3098 void wxPropertyGrid::DoShowPropertyError( wxPGProperty
* WXUNUSED(property
), const wxString
& msg 
) 
3100     if ( !msg
.length() ) 
3104     if ( !wxPGGlobalVars
->m_offline 
) 
3106         wxWindow
* topWnd 
= ::wxGetTopLevelParent(this); 
3109             wxFrame
* pFrame 
= wxDynamicCast(topWnd
, wxFrame
); 
3112                 wxStatusBar
* pStatusBar 
= pFrame
->GetStatusBar(); 
3115                     pStatusBar
->SetStatusText(msg
); 
3123     ::wxMessageBox(msg
, wxT("Property Error")); 
3126 // ----------------------------------------------------------------------- 
3128 bool wxPropertyGrid::OnValidationFailure( wxPGProperty
* property
, 
3129                                           wxVariant
& invalidValue 
) 
3131     wxWindow
* editor 
= GetEditorControl(); 
3133     // First call property's handler 
3134     property
->OnValidationFailure(invalidValue
); 
3136     bool res 
= DoOnValidationFailure(property
, invalidValue
); 
3139     // For non-wxTextCtrl editors, we do need to revert the value 
3140     if ( !editor
->IsKindOf(CLASSINFO(wxTextCtrl
)) && 
3141          property 
== GetSelection() ) 
3143         property
->GetEditorClass()->UpdateControl(property
, editor
); 
3146     property
->SetFlag(wxPG_PROP_INVALID_VALUE
); 
3151 bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty
* property
, wxVariant
& WXUNUSED(invalidValue
) ) 
3153     int vfb 
= m_validationInfo
.m_failureBehavior
; 
3155     if ( vfb 
& wxPG_VFB_BEEP 
) 
3158     if ( (vfb 
& wxPG_VFB_MARK_CELL
) && 
3159          !property
->HasFlag(wxPG_PROP_INVALID_VALUE
) ) 
3161         unsigned int colCount 
= m_pState
->GetColumnCount(); 
3163         // We need backup marked property's cells 
3164         m_propCellsBackup 
= property
->m_cells
; 
3166         wxColour vfbFg 
= *wxWHITE
; 
3167         wxColour vfbBg 
= *wxRED
; 
3169         property
->EnsureCells(colCount
); 
3171         for ( unsigned int i
=0; i
<colCount
; i
++ ) 
3173             wxPGCell
& cell 
= property
->m_cells
[i
]; 
3174             cell
.SetFgCol(vfbFg
); 
3175             cell
.SetBgCol(vfbBg
); 
3178         DrawItemAndChildren(property
); 
3180         if ( property 
== GetSelection() ) 
3182             SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
); 
3184             wxWindow
* editor 
= GetEditorControl(); 
3187                 editor
->SetForegroundColour(vfbFg
); 
3188                 editor
->SetBackgroundColour(vfbBg
); 
3193     if ( vfb 
& wxPG_VFB_SHOW_MESSAGE 
) 
3195         wxString msg 
= m_validationInfo
.m_failureMessage
; 
3197         if ( !msg
.length() ) 
3198             msg 
= wxT("You have entered invalid value. Press ESC to cancel editing."); 
3200         DoShowPropertyError(property
, msg
); 
3203     return (vfb 
& wxPG_VFB_STAY_IN_PROPERTY
) ? false : true; 
3206 // ----------------------------------------------------------------------- 
3208 void wxPropertyGrid::DoOnValidationFailureReset( wxPGProperty
* property 
) 
3210     int vfb 
= m_validationInfo
.m_failureBehavior
; 
3212     if ( vfb 
& wxPG_VFB_MARK_CELL 
) 
3215         property
->m_cells 
= m_propCellsBackup
; 
3217         ClearInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL
); 
3219         if ( property 
== GetSelection() && GetEditorControl() ) 
3221             // Calling this will recreate the control, thus resetting its colour 
3222             RefreshProperty(property
); 
3226             DrawItemAndChildren(property
); 
3231 // ----------------------------------------------------------------------- 
3233 // flags are same as with DoSelectProperty 
3234 bool wxPropertyGrid::DoPropertyChanged( wxPGProperty
* p
, unsigned int selFlags 
) 
3236     if ( m_inDoPropertyChanged 
) 
3239     wxWindow
* editor 
= GetEditorControl(); 
3240     wxPGProperty
* selected 
= GetSelection(); 
3242     m_pState
->m_anyModified 
= 1; 
3244     m_inDoPropertyChanged 
= 1; 
3246     // Maybe need to update control 
3247     wxASSERT( m_chgInfo_changedProperty 
!= NULL 
); 
3249     // These values were calculated in PerformValidation() 
3250     wxPGProperty
* changedProperty 
= m_chgInfo_changedProperty
; 
3251     wxVariant value 
= m_chgInfo_pendingValue
; 
3253     wxPGProperty
* topPaintedProperty 
= changedProperty
; 
3255     while ( !topPaintedProperty
->IsCategory() && 
3256             !topPaintedProperty
->IsRoot() ) 
3258         topPaintedProperty 
= topPaintedProperty
->GetParent(); 
3261     changedProperty
->SetValue(value
, &m_chgInfo_valueList
, wxPG_SETVAL_BY_USER
); 
3263     // Set as Modified (not if dragging just began) 
3264     if ( !(p
->m_flags 
& wxPG_PROP_MODIFIED
) ) 
3266         p
->m_flags 
|= wxPG_PROP_MODIFIED
; 
3267         if ( p 
== selected 
&& (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
3270                 SetCurControlBoldFont(); 
3276     // Propagate updates to parent(s) 
3278     wxPGProperty
* prevPwc 
= NULL
; 
3280     while ( prevPwc 
!= topPaintedProperty 
) 
3282         pwc
->m_flags 
|= wxPG_PROP_MODIFIED
; 
3284         if ( pwc 
== selected 
&& (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
3287                 SetCurControlBoldFont(); 
3291         pwc 
= pwc
->GetParent(); 
3294     // Draw the actual property 
3295     DrawItemAndChildren( topPaintedProperty 
); 
3298     // If value was set by wxPGProperty::OnEvent, then update the editor 
3300     if ( selFlags 
& wxPG_SEL_DIALOGVAL 
) 
3306 #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
3307         if ( m_wndEditor 
) m_wndEditor
->Refresh(); 
3308         if ( m_wndEditor2 
) m_wndEditor2
->Refresh(); 
3313     wxASSERT( !changedProperty
->GetParent()->HasFlag(wxPG_PROP_AGGREGATE
) ); 
3315     // If top parent has composite string value, then send to child parents, 
3316     // starting from baseChangedProperty. 
3317     if ( changedProperty
->HasFlag(wxPG_PROP_COMPOSED_VALUE
) ) 
3319         pwc 
= m_chgInfo_baseChangedProperty
; 
3321         while ( pwc 
!= changedProperty 
) 
3323             SendEvent( wxEVT_PG_CHANGED
, pwc
, NULL 
); 
3324             pwc 
= pwc
->GetParent(); 
3328     SendEvent( wxEVT_PG_CHANGED
, changedProperty
, NULL 
); 
3330     m_inDoPropertyChanged 
= 0; 
3335 // ----------------------------------------------------------------------- 
3337 bool wxPropertyGrid::ChangePropertyValue( wxPGPropArg id
, wxVariant newValue 
) 
3339     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) 
3341     m_chgInfo_changedProperty 
= NULL
; 
3343     if ( PerformValidation(p
, newValue
) ) 
3345         DoPropertyChanged(p
); 
3350         OnValidationFailure(p
, newValue
); 
3356 // ----------------------------------------------------------------------- 
3358 wxVariant 
wxPropertyGrid::GetUncommittedPropertyValue() 
3360     wxPGProperty
* prop 
= GetSelectedProperty(); 
3363         return wxNullVariant
; 
3365     wxTextCtrl
* tc 
= GetEditorTextCtrl(); 
3366     wxVariant value 
= prop
->GetValue(); 
3368     if ( !tc 
|| !IsEditorsValueModified() ) 
3371     if ( !prop
->StringToValue(value
, tc
->GetValue()) ) 
3374     if ( !PerformValidation(prop
, value
, IsStandaloneValidation
) ) 
3375         return prop
->GetValue(); 
3380 // ----------------------------------------------------------------------- 
3382 // Runs wxValidator for the selected property 
3383 bool wxPropertyGrid::DoEditorValidate() 
3388 // ----------------------------------------------------------------------- 
3390 void wxPropertyGrid::HandleCustomEditorEvent( wxEvent 
&event 
) 
3392     // It is possible that this handler receives event even before 
3393     // the control has been properly initialized. Let's skip the 
3394     // event handling in that case. 
3398     wxPGProperty
* selected 
= GetSelection(); 
3400     // Somehow, event is handled after property has been deselected. 
3401     // Possibly, but very rare. 
3403           selected
->HasFlag(wxPG_PROP_BEING_DELETED
) || 
3404           // Also don't handle editor event if wxEVT_PG_CHANGED or 
3405           // similar is currently doing something (showing a 
3406           // message box, for instance). 
3410     if ( m_iFlags 
& wxPG_FL_IN_HANDLECUSTOMEDITOREVENT 
) 
3413     wxVariant 
pendingValue(selected
->GetValueRef()); 
3414     wxWindow
* wnd 
= GetEditorControl(); 
3415     wxWindow
* editorWnd 
= wxDynamicCast(event
.GetEventObject(), wxWindow
); 
3417     bool wasUnspecified 
= selected
->IsValueUnspecified(); 
3418     int usesAutoUnspecified 
= selected
->UsesAutoUnspecified(); 
3419     bool valueIsPending 
= false; 
3421     m_chgInfo_changedProperty 
= NULL
; 
3423     m_iFlags 
&= ~(wxPG_FL_VALIDATION_FAILED
|wxPG_FL_VALUE_CHANGE_IN_EVENT
); 
3426     // Filter out excess wxTextCtrl modified events 
3427     if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_UPDATED 
&& wnd 
) 
3429         if ( wnd
->IsKindOf(CLASSINFO(wxTextCtrl
)) ) 
3431             wxTextCtrl
* tc 
= (wxTextCtrl
*) wnd
; 
3433             wxString newTcValue 
= tc
->GetValue(); 
3434             if ( m_prevTcValue 
== newTcValue 
) 
3436             m_prevTcValue 
= newTcValue
; 
3438         else if ( wnd
->IsKindOf(CLASSINFO(wxComboCtrl
)) ) 
3440             wxComboCtrl
* cc 
= (wxComboCtrl
*) wnd
; 
3442             wxString newTcValue 
= cc
->GetTextCtrl()->GetValue(); 
3443             if ( m_prevTcValue 
== newTcValue 
) 
3445             m_prevTcValue 
= newTcValue
; 
3449     SetInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT
); 
3451     bool validationFailure 
= false; 
3452     bool buttonWasHandled 
= false; 
3455     // Try common button handling 
3456     if ( m_wndEditor2 
&& event
.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED 
) 
3458         wxPGEditorDialogAdapter
* adapter 
= selected
->GetEditorDialog(); 
3462             buttonWasHandled 
= true; 
3463             // Store as res2, as previously (and still currently alternatively) 
3464             // dialogs can be shown by handling wxEVT_COMMAND_BUTTON_CLICKED 
3465             // in wxPGProperty::OnEvent(). 
3466             adapter
->ShowDialog( this, selected 
); 
3471     if ( !buttonWasHandled 
) 
3473         if ( wnd 
|| m_wndEditor2 
) 
3475             // First call editor class' event handler. 
3476             const wxPGEditor
* editor 
= selected
->GetEditorClass(); 
3478             if ( editor
->OnEvent( this, selected
, editorWnd
, event 
) ) 
3480                 // If changes, validate them 
3481                 if ( DoEditorValidate() ) 
3483                     if ( editor
->GetValueFromControl( pendingValue
, 
3486                         valueIsPending 
= true; 
3490                     validationFailure 
= true; 
3495         // Then the property's custom handler (must be always called, unless 
3496         // validation failed). 
3497         if ( !validationFailure 
) 
3498             buttonWasHandled 
= selected
->OnEvent( this, editorWnd
, event 
); 
3501     // SetValueInEvent(), as called in one of the functions referred above 
3502     // overrides editor's value. 
3503     if ( m_iFlags 
& wxPG_FL_VALUE_CHANGE_IN_EVENT 
) 
3505         valueIsPending 
= true; 
3506         pendingValue 
= m_changeInEventValue
; 
3507         selFlags 
|= wxPG_SEL_DIALOGVAL
; 
3510     if ( !validationFailure 
&& valueIsPending 
) 
3511         if ( !PerformValidation(selected
, pendingValue
) ) 
3512             validationFailure 
= true; 
3514     if ( validationFailure
) 
3516         OnValidationFailure(selected
, pendingValue
); 
3518     else if ( valueIsPending 
) 
3520         selFlags 
|= ( !wasUnspecified 
&& selected
->IsValueUnspecified() && usesAutoUnspecified 
) ? wxPG_SEL_SETUNSPEC 
: 0; 
3522         DoPropertyChanged(selected
, selFlags
); 
3523         EditorsValueWasNotModified(); 
3525         // Regardless of editor type, unfocus editor on 
3526         // text-editing related enter press. 
3527         if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER 
) 
3534         // No value after all 
3536         // Regardless of editor type, unfocus editor on 
3537         // text-editing related enter press. 
3538         if ( event
.GetEventType() == wxEVT_COMMAND_TEXT_ENTER 
) 
3543         // Let unhandled button click events go to the parent 
3544         if ( !buttonWasHandled 
&& event
.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED 
) 
3546             wxCommandEvent 
evt(wxEVT_COMMAND_BUTTON_CLICKED
,GetId()); 
3547             GetEventHandler()->AddPendingEvent(evt
); 
3551     ClearInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT
); 
3554 // ----------------------------------------------------------------------- 
3555 // wxPropertyGrid editor control helper methods 
3556 // ----------------------------------------------------------------------- 
3558 wxRect 
wxPropertyGrid::GetEditorWidgetRect( wxPGProperty
* p
, int column 
) const 
3560     int itemy 
= p
->GetY2(m_lineHeight
); 
3561     int splitterX 
= m_pState
->DoGetSplitterPosition(column
-1); 
3562     int colEnd 
= splitterX 
+ m_pState
->m_colWidths
[column
]; 
3563     int imageOffset 
= 0; 
3565     int vx
, vy
;  // Top left corner of client 
3566     GetViewStart(&vx
, &vy
); 
3567     vy 
*= wxPG_PIXELS_PER_UNIT
; 
3569     // TODO: If custom image detection changes from current, change this. 
3570     if ( m_iFlags 
& wxPG_FL_CUR_USES_CUSTOM_IMAGE 
) 
3572         //m_iFlags |= wxPG_FL_CUR_USES_CUSTOM_IMAGE; 
3573         int iw 
= p
->OnMeasureImage().x
; 
3575             iw 
= wxPG_CUSTOM_IMAGE_WIDTH
; 
3576         imageOffset 
= p
->GetImageOffset(iw
); 
3581         splitterX
+imageOffset
+wxPG_XBEFOREWIDGET
+wxPG_CONTROL_MARGIN
+1, 
3583         colEnd
-splitterX
-wxPG_XBEFOREWIDGET
-wxPG_CONTROL_MARGIN
-imageOffset
-1, 
3588 // ----------------------------------------------------------------------- 
3590 wxRect 
wxPropertyGrid::GetImageRect( wxPGProperty
* p
, int item 
) const 
3592     wxSize sz 
= GetImageSize(p
, item
); 
3593     return wxRect(wxPG_CONTROL_MARGIN 
+ wxCC_CUSTOM_IMAGE_MARGIN1
, 
3594                   wxPG_CUSTOM_IMAGE_SPACINGY
, 
3599 // return size of custom paint image 
3600 wxSize 
wxPropertyGrid::GetImageSize( wxPGProperty
* p
, int item 
) const 
3602     // If called with NULL property, then return default image 
3603     // size for properties that use image. 
3605         return wxSize(wxPG_CUSTOM_IMAGE_WIDTH
,wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
)); 
3607     wxSize cis 
= p
->OnMeasureImage(item
); 
3609     int choiceCount 
= p
->m_choices
.GetCount(); 
3610     int comVals 
= p
->GetDisplayedCommonValueCount(); 
3611     if ( item 
>= choiceCount 
&& comVals 
> 0 ) 
3613         unsigned int cvi 
= item
-choiceCount
; 
3614         cis 
= GetCommonValue(cvi
)->GetRenderer()->GetImageSize(NULL
, 1, cvi
); 
3616     else if ( item 
>= 0 && choiceCount 
== 0 ) 
3617         return wxSize(0, 0); 
3622             cis
.x 
= wxPG_CUSTOM_IMAGE_WIDTH
; 
3627             cis
.y 
= wxPG_STD_CUST_IMAGE_HEIGHT(m_lineHeight
); 
3634 // ----------------------------------------------------------------------- 
3636 // takes scrolling into account 
3637 void wxPropertyGrid::ImprovedClientToScreen( int* px
, int* py 
) 
3640     GetViewStart(&vx
,&vy
); 
3641     vy
*=wxPG_PIXELS_PER_UNIT
; 
3642     vx
*=wxPG_PIXELS_PER_UNIT
; 
3645     ClientToScreen( px
, py 
); 
3648 // ----------------------------------------------------------------------- 
3650 wxPropertyGridHitTestResult 
wxPropertyGrid::HitTest( const wxPoint
& pt 
) const 
3653     GetViewStart(&pt2
.x
,&pt2
.y
); 
3654     pt2
.x 
*= wxPG_PIXELS_PER_UNIT
; 
3655     pt2
.y 
*= wxPG_PIXELS_PER_UNIT
; 
3659     return m_pState
->HitTest(pt2
); 
3662 // ----------------------------------------------------------------------- 
3664 // custom set cursor 
3665 void wxPropertyGrid::CustomSetCursor( int type
, bool override 
) 
3667     if ( type 
== m_curcursor 
&& !override 
) return; 
3669     wxCursor
* cursor 
= &wxPG_DEFAULT_CURSOR
; 
3671     if ( type 
== wxCURSOR_SIZEWE 
) 
3672         cursor 
= m_cursorSizeWE
; 
3674     SetCursor( *cursor 
); 
3679 // ----------------------------------------------------------------------- 
3682 wxPropertyGrid::GetUnspecifiedValueText( int argFlags 
) const 
3684     const wxPGCell
& ua 
= GetUnspecifiedValueAppearance(); 
3686     if ( ua
.HasText() && 
3687          !(argFlags 
& wxPG_FULL_VALUE
) && 
3688          !(argFlags 
& wxPG_EDITABLE_VALUE
) ) 
3689         return ua
.GetText(); 
3691     return wxEmptyString
; 
3694 // ----------------------------------------------------------------------- 
3695 // wxPropertyGrid property selection, editor creation 
3696 // ----------------------------------------------------------------------- 
3699 // This class forwards events from property editor controls to wxPropertyGrid. 
3700 class wxPropertyGridEditorEventForwarder 
: public wxEvtHandler
 
3703     wxPropertyGridEditorEventForwarder( wxPropertyGrid
* propGrid 
) 
3704         : wxEvtHandler(), m_propGrid(propGrid
) 
3708     virtual ~wxPropertyGridEditorEventForwarder() 
3713     bool ProcessEvent( wxEvent
& event 
) 
3718         m_propGrid
->HandleCustomEditorEvent(event
); 
3720         return wxEvtHandler::ProcessEvent(event
); 
3723     wxPropertyGrid
*         m_propGrid
; 
3726 // Setups event handling for child control 
3727 void wxPropertyGrid::SetupChildEventHandling( wxWindow
* argWnd 
) 
3729     wxWindowID id 
= argWnd
->GetId(); 
3731     if ( argWnd 
== m_wndEditor 
) 
3733         argWnd
->Connect(id
, wxEVT_MOTION
, 
3734             wxMouseEventHandler(wxPropertyGrid::OnMouseMoveChild
), 
3736         argWnd
->Connect(id
, wxEVT_LEFT_UP
, 
3737             wxMouseEventHandler(wxPropertyGrid::OnMouseUpChild
), 
3739         argWnd
->Connect(id
, wxEVT_LEFT_DOWN
, 
3740             wxMouseEventHandler(wxPropertyGrid::OnMouseClickChild
), 
3742         argWnd
->Connect(id
, wxEVT_RIGHT_UP
, 
3743             wxMouseEventHandler(wxPropertyGrid::OnMouseRightClickChild
), 
3745         argWnd
->Connect(id
, wxEVT_ENTER_WINDOW
, 
3746             wxMouseEventHandler(wxPropertyGrid::OnMouseEntry
), 
3748         argWnd
->Connect(id
, wxEVT_LEAVE_WINDOW
, 
3749             wxMouseEventHandler(wxPropertyGrid::OnMouseEntry
), 
3753     wxPropertyGridEditorEventForwarder
* forwarder
; 
3754     forwarder 
= new wxPropertyGridEditorEventForwarder(this); 
3755     argWnd
->PushEventHandler(forwarder
); 
3757     argWnd
->Connect(id
, wxEVT_KEY_DOWN
, 
3758         wxCharEventHandler(wxPropertyGrid::OnChildKeyDown
), 
3762 void wxPropertyGrid::DestroyEditorWnd( wxWindow
* wnd 
) 
3769     // Do not free editors immediately (for sake of processing events) 
3770     wxPendingDelete
.Append(wnd
); 
3773 void wxPropertyGrid::FreeEditors() 
3776     // Return focus back to canvas from children (this is required at least for 
3777     // GTK+, which, unlike Windows, clears focus when control is destroyed 
3778     // instead of moving it to closest parent). 
3779     wxWindow
* focus 
= wxWindow::FindFocus(); 
3782         wxWindow
* parent 
= focus
->GetParent(); 
3785             if ( parent 
== this ) 
3790             parent 
= parent
->GetParent(); 
3794     // Do not free editors immediately if processing events 
3797         wxEvtHandler
* handler 
= m_wndEditor2
->PopEventHandler(false); 
3798         m_wndEditor2
->Hide(); 
3799         wxPendingDelete
.Append( handler 
); 
3800         DestroyEditorWnd(m_wndEditor2
); 
3801         m_wndEditor2 
= NULL
; 
3806         wxEvtHandler
* handler 
= m_wndEditor
->PopEventHandler(false); 
3807         m_wndEditor
->Hide(); 
3808         wxPendingDelete
.Append( handler 
); 
3809         DestroyEditorWnd(m_wndEditor
); 
3814 // Call with NULL to de-select property 
3815 bool wxPropertyGrid::DoSelectProperty( wxPGProperty
* p
, unsigned int flags 
) 
3820         wxLogDebug(wxT("SelectProperty( %s (%s[%i]) )"),p->m_label.c_str(), 
3821             p->m_parent->m_label.c_str(),p->GetIndexInParent()); 
3825         wxLogDebug(wxT("SelectProperty( NULL, -1 )")); 
3829     if ( m_inDoSelectProperty 
) 
3832     m_inDoSelectProperty 
= 1; 
3836         m_inDoSelectProperty 
= 0; 
3840     wxArrayPGProperty prevSelection 
= m_pState
->m_selection
; 
3841     wxPGProperty
* prevFirstSel
; 
3843     if ( prevSelection
.size() > 0 ) 
3844         prevFirstSel 
= prevSelection
[0]; 
3846         prevFirstSel 
= NULL
; 
3848     if ( prevFirstSel 
&& prevFirstSel
->HasFlag(wxPG_PROP_BEING_DELETED
) ) 
3849         prevFirstSel 
= NULL
; 
3851     // Always send event, as this is indirect call 
3852     DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE
); 
3856         wxPrintf( "Selected %s\n", prevFirstSel->GetClassInfo()->GetClassName() ); 
3858         wxPrintf( "None selected\n" ); 
3861         wxPrintf( "P =  %s\n", p->GetClassInfo()->GetClassName() ); 
3863         wxPrintf( "P = NULL\n" ); 
3866     // If we are frozen, then just set the values. 
3869         m_iFlags 
&= ~(wxPG_FL_ABNORMAL_EDITOR
); 
3870         m_editorFocused 
= 0; 
3871         m_pState
->DoSetSelection(p
); 
3873         // If frozen, always free controls. But don't worry, as Thaw will 
3874         // recall SelectProperty to recreate them. 
3877         // Prevent any further selection measures in this call 
3883         if ( prevFirstSel 
== p 
&& 
3884              prevSelection
.size() <= 1 && 
3885              !(flags 
& wxPG_SEL_FORCE
) ) 
3887             // Only set focus if not deselecting 
3890                 if ( flags 
& wxPG_SEL_FOCUS 
) 
3894                         m_wndEditor
->SetFocus(); 
3895                         m_editorFocused 
= 1; 
3904             m_inDoSelectProperty 
= 0; 
3909         // First, deactivate previous 
3912             OnValidationFailureReset(prevFirstSel
); 
3914             // Must double-check if this is an selected in case of forceswitch 
3915             if ( p 
!= prevFirstSel 
) 
3917                 if ( !CommitChangesFromEditor(flags
) ) 
3919                     // Validation has failed, so we can't exit the previous editor 
3920                     //::wxMessageBox(_("Please correct the value or press ESC to cancel the edit."), 
3921                     //               _("Invalid Value"),wxOK|wxICON_ERROR); 
3922                     m_inDoSelectProperty 
= 0; 
3929             m_iFlags 
&= ~(wxPG_FL_ABNORMAL_EDITOR
); 
3930             EditorsValueWasNotModified(); 
3933         SetInternalFlag(wxPG_FL_IN_SELECT_PROPERTY
); 
3935         m_pState
->DoSetSelection(p
); 
3937         // Redraw unselected 
3938         for ( unsigned int i
=0; i
<prevSelection
.size(); i
++ ) 
3940             DrawItem(prevSelection
[i
]); 
3944         // Then, activate the one given. 
3947             int propY 
= p
->GetY2(m_lineHeight
); 
3949             int splitterX 
= GetSplitterPosition(); 
3950             m_editorFocused 
= 0; 
3951             m_iFlags 
|= wxPG_FL_PRIMARY_FILLS_ENTIRE
; 
3952             if ( p 
!= prevFirstSel 
) 
3953                 m_iFlags 
&= ~(wxPG_FL_VALIDATION_FAILED
); 
3955             wxASSERT( m_wndEditor 
== NULL 
); 
3958             // Only create editor for non-disabled non-caption 
3959             if ( !p
->IsCategory() && !(p
->m_flags 
& wxPG_PROP_DISABLED
) ) 
3961             // do this for non-caption items 
3965                 // Do we need to paint the custom image, if any? 
3966                 m_iFlags 
&= ~(wxPG_FL_CUR_USES_CUSTOM_IMAGE
); 
3967                 if ( (p
->m_flags 
& wxPG_PROP_CUSTOMIMAGE
) && 
3968                      !p
->GetEditorClass()->CanContainCustomImage() 
3970                     m_iFlags 
|= wxPG_FL_CUR_USES_CUSTOM_IMAGE
; 
3972                 wxRect grect 
= GetEditorWidgetRect(p
, m_selColumn
); 
3973                 wxPoint goodPos 
= grect
.GetPosition(); 
3975                 // Editor appearance can now be considered clear 
3976                 m_editorAppearance
.SetEmptyData(); 
3978                 const wxPGEditor
* editor 
= p
->GetEditorClass(); 
3979                 wxCHECK_MSG(editor
, false, 
3980                     wxT("NULL editor class not allowed")); 
3982                 m_iFlags 
&= ~wxPG_FL_FIXED_WIDTH_EDITOR
; 
3984                 wxPGWindowList wndList 
= 
3985                     editor
->CreateControls(this, 
3990                 m_wndEditor 
= wndList
.m_primary
; 
3991                 m_wndEditor2 
= wndList
.m_secondary
; 
3992                 wxWindow
* primaryCtrl 
= GetEditorControl(); 
3995                 // Essentially, primaryCtrl == m_wndEditor 
3998                 // NOTE: It is allowed for m_wndEditor to be NULL - in this 
3999                 //       case value is drawn as normal, and m_wndEditor2 is 
4000                 //       assumed to be a right-aligned button that triggers 
4001                 //       a separate editorCtrl window. 
4005                     wxASSERT_MSG( m_wndEditor
->GetParent() == GetPanel(), 
4006                                   "CreateControls must use result of " 
4007                                   "wxPropertyGrid::GetPanel() as parent " 
4010                     // Set validator, if any 
4011                 #if wxUSE_VALIDATORS 
4012                     wxValidator
* validator 
= p
->GetValidator(); 
4014                         primaryCtrl
->SetValidator(*validator
); 
4017                     if ( m_wndEditor
->GetSize().y 
> (m_lineHeight
+6) ) 
4018                         m_iFlags 
|= wxPG_FL_ABNORMAL_EDITOR
; 
4020                     // If it has modified status, use bold font 
4021                     // (must be done before capturing m_ctrlXAdjust) 
4022                     if ( (p
->m_flags 
& wxPG_PROP_MODIFIED
) && 
4023                          (m_windowStyle 
& wxPG_BOLD_MODIFIED
) ) 
4024                         SetCurControlBoldFont(); 
4026                     // Store x relative to splitter (we'll need it). 
4027                     m_ctrlXAdjust 
= m_wndEditor
->GetPosition().x 
- splitterX
; 
4029                     // Check if background clear is not necessary 
4030                     wxPoint pos 
= m_wndEditor
->GetPosition(); 
4031                     if ( pos
.x 
> (splitterX
+1) || pos
.y 
> propY 
) 
4033                         m_iFlags 
&= ~(wxPG_FL_PRIMARY_FILLS_ENTIRE
); 
4036                     m_wndEditor
->SetSizeHints(3, 3); 
4038                     SetupChildEventHandling(primaryCtrl
); 
4040                     // Focus and select all (wxTextCtrl, wxComboBox etc) 
4041                     if ( flags 
& wxPG_SEL_FOCUS 
) 
4043                         primaryCtrl
->SetFocus(); 
4045                         p
->GetEditorClass()->OnFocus(p
, primaryCtrl
); 
4049                         if ( p
->IsValueUnspecified() ) 
4050                             SetEditorAppearance(m_unspecifiedAppearance
, 
4057                     wxASSERT_MSG( m_wndEditor2
->GetParent() == GetPanel(), 
4058                                   "CreateControls must use result of " 
4059                                   "wxPropertyGrid::GetPanel() as parent " 
4062                     // Get proper id for wndSecondary 
4063                     m_wndSecId 
= m_wndEditor2
->GetId(); 
4064                     wxWindowList children 
= m_wndEditor2
->GetChildren(); 
4065                     wxWindowList::iterator node 
= children
.begin(); 
4066                     if ( node 
!= children
.end() ) 
4067                         m_wndSecId 
= ((wxWindow
*)*node
)->GetId(); 
4069                     m_wndEditor2
->SetSizeHints(3,3); 
4071                     m_wndEditor2
->Show(); 
4073                     SetupChildEventHandling(m_wndEditor2
); 
4075                     // If no primary editor, focus to button to allow 
4076                     // it to interprete ENTER etc. 
4077                     // NOTE: Due to problems focusing away from it, this 
4078                     //       has been disabled. 
4080                     if ( (flags & wxPG_SEL_FOCUS) && !m_wndEditor ) 
4081                         m_wndEditor2->SetFocus(); 
4085                 if ( flags 
& wxPG_SEL_FOCUS 
) 
4086                     m_editorFocused 
= 1; 
4091                 // Make sure focus is in grid canvas (important for wxGTK, 
4096             EditorsValueWasNotModified(); 
4098             // If it's inside collapsed section, expand parent, scroll, etc. 
4099             // Also, if it was partially visible, scroll it into view. 
4100             if ( !(flags 
& wxPG_SEL_NONVISIBLE
) ) 
4105                 m_wndEditor
->Show(true); 
4108             if ( !(flags 
& wxPG_SEL_NO_REFRESH
) ) 
4113             // Make sure focus is in grid canvas 
4117         ClearInternalFlag(wxPG_FL_IN_SELECT_PROPERTY
); 
4123     // Show help text in status bar. 
4124     //   (if found and grid not embedded in manager with help box and 
4125     //    style wxPG_EX_HELP_AS_TOOLTIPS is not used). 
4128     if ( !(GetExtraStyle() & wxPG_EX_HELP_AS_TOOLTIPS
) ) 
4130         wxStatusBar
* statusbar 
= NULL
; 
4131         if ( !(m_iFlags 
& wxPG_FL_NOSTATUSBARHELP
) ) 
4133             wxFrame
* frame 
= wxDynamicCast(::wxGetTopLevelParent(this),wxFrame
); 
4135                 statusbar 
= frame
->GetStatusBar(); 
4140             const wxString
* pHelpString 
= (const wxString
*) NULL
; 
4144                 pHelpString 
= &p
->GetHelpString(); 
4145                 if ( pHelpString
->length() ) 
4147                     // Set help box text. 
4148                     statusbar
->SetStatusText( *pHelpString 
); 
4149                     m_iFlags 
|= wxPG_FL_STRING_IN_STATUSBAR
; 
4153             if ( (!pHelpString 
|| !pHelpString
->length()) && 
4154                  (m_iFlags 
& wxPG_FL_STRING_IN_STATUSBAR
) ) 
4156                 // Clear help box - but only if it was written 
4157                 // by us at previous time. 
4158                 statusbar
->SetStatusText( m_emptyString 
); 
4159                 m_iFlags 
&= ~(wxPG_FL_STRING_IN_STATUSBAR
); 
4165     m_inDoSelectProperty 
= 0; 
4167     // call wx event handler (here so that it also occurs on deselection) 
4168     if ( !(flags 
& wxPG_SEL_DONT_SEND_EVENT
) ) 
4169         SendEvent( wxEVT_PG_SELECTED
, p
, NULL 
); 
4174 // ----------------------------------------------------------------------- 
4176 bool wxPropertyGrid::UnfocusEditor() 
4178     wxPGProperty
* selected 
= GetSelection(); 
4180     if ( !selected 
|| !m_wndEditor 
|| m_frozen 
) 
4183     if ( !CommitChangesFromEditor(0) ) 
4192 // ----------------------------------------------------------------------- 
4194 void wxPropertyGrid::RefreshEditor() 
4196     wxPGProperty
* p 
= GetSelection(); 
4200     wxWindow
* wnd 
= GetEditorControl(); 
4204     // Set editor font boldness - must do this before 
4205     // calling UpdateControl(). 
4206     if ( HasFlag(wxPG_BOLD_MODIFIED
) ) 
4208         if ( p
->HasFlag(wxPG_PROP_MODIFIED
) ) 
4209             wnd
->SetFont(GetCaptionFont()); 
4211             wnd
->SetFont(GetFont()); 
4214     const wxPGEditor
* editorClass 
= p
->GetEditorClass(); 
4216     editorClass
->UpdateControl(p
, wnd
); 
4218     if ( p
->IsValueUnspecified() ) 
4219         SetEditorAppearance(m_unspecifiedAppearance
, true); 
4222 // ----------------------------------------------------------------------- 
4224 bool wxPropertyGrid::SelectProperty( wxPGPropArg id
, bool focus 
) 
4226     wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) 
4228     int flags 
= wxPG_SEL_DONT_SEND_EVENT
; 
4230         flags 
|= wxPG_SEL_FOCUS
; 
4232     return DoSelectProperty(p
, flags
); 
4235 // ----------------------------------------------------------------------- 
4236 // wxPropertyGrid expand/collapse state 
4237 // ----------------------------------------------------------------------- 
4239 bool wxPropertyGrid::DoCollapse( wxPGProperty
* p
, bool sendEvents 
) 
4241     wxPGProperty
* pwc 
= wxStaticCast(p
, wxPGProperty
); 
4242     wxPGProperty
* selected 
= GetSelection(); 
4244     // If active editor was inside collapsed section, then disable it 
4245     if ( selected 
&& selected
->IsSomeParent(p
) ) 
4250     // Store dont-center-splitter flag 'cause we need to temporarily set it 
4251     bool prevDontCenterSplitter 
= m_pState
->m_dontCenterSplitter
; 
4252     m_pState
->m_dontCenterSplitter 
= true; 
4254     bool res 
= m_pState
->DoCollapse(pwc
); 
4259             SendEvent( wxEVT_PG_ITEM_COLLAPSED
, p 
); 
4261         RecalculateVirtualSize(); 
4265     m_pState
->m_dontCenterSplitter 
= prevDontCenterSplitter
; 
4270 // ----------------------------------------------------------------------- 
4272 bool wxPropertyGrid::DoExpand( wxPGProperty
* p
, bool sendEvents 
) 
4274     wxCHECK_MSG( p
, false, wxT("invalid property id") ); 
4276     wxPGProperty
* pwc 
= (wxPGProperty
*)p
; 
4278     // Store dont-center-splitter flag 'cause we need to temporarily set it 
4279     bool prevDontCenterSplitter 
= m_pState
->m_dontCenterSplitter
; 
4280     m_pState
->m_dontCenterSplitter 
= true; 
4282     bool res 
= m_pState
->DoExpand(pwc
); 
4287             SendEvent( wxEVT_PG_ITEM_EXPANDED
, p 
); 
4289         RecalculateVirtualSize(); 
4293     m_pState
->m_dontCenterSplitter 
= prevDontCenterSplitter
; 
4298 // ----------------------------------------------------------------------- 
4300 bool wxPropertyGrid::DoHideProperty( wxPGProperty
* p
, bool hide
, int flags 
) 
4303         return m_pState
->DoHideProperty(p
, hide
, flags
); 
4305     wxArrayPGProperty selection 
= m_pState
->m_selection
;  // Must use a copy 
4306     int selRemoveCount 
= 0; 
4307     for ( unsigned int i
=0; i
<selection
.size(); i
++ ) 
4309         wxPGProperty
* selected 
= selection
[i
]; 
4310         if ( selected 
== p 
|| selected
->IsSomeParent(p
) ) 
4312             if ( !DoRemoveFromSelection(p
, flags
) ) 
4314             selRemoveCount 
+= 1; 
4318     m_pState
->DoHideProperty(p
, hide
, flags
); 
4320     RecalculateVirtualSize(); 
4327 // ----------------------------------------------------------------------- 
4328 // wxPropertyGrid size related methods 
4329 // ----------------------------------------------------------------------- 
4331 void wxPropertyGrid::RecalculateVirtualSize( int forceXPos 
) 
4333     // Don't check for !HasInternalFlag(wxPG_FL_INITIALIZED) here. Otherwise 
4334     // virtual size calculation may go wrong. 
4335     if ( HasInternalFlag(wxPG_FL_RECALCULATING_VIRTUAL_SIZE
) || 
4341     // If virtual height was changed, then recalculate editor control position(s) 
4342     if ( m_pState
->m_vhCalcPending 
) 
4343         CorrectEditorWidgetPosY(); 
4345     m_pState
->EnsureVirtualHeight(); 
4347     wxASSERT_LEVEL_2_MSG( 
4348         m_pState
->GetVirtualHeight() == m_pState
->GetActualVirtualHeight(), 
4349         "VirtualHeight and ActualVirtualHeight should match" 
4352     m_iFlags 
|= wxPG_FL_RECALCULATING_VIRTUAL_SIZE
; 
4354     int x 
= m_pState
->m_width
; 
4355     int y 
= m_pState
->m_virtualHeight
; 
4358     GetClientSize(&width
,&height
); 
4360     // Now adjust virtual size. 
4361     SetVirtualSize(x
, y
); 
4367     // Adjust scrollbars 
4368     if ( HasVirtualWidth() ) 
4370         xAmount 
= x
/wxPG_PIXELS_PER_UNIT
; 
4371         xPos 
= GetScrollPos( wxHORIZONTAL 
); 
4374     if ( forceXPos 
!= -1 ) 
4377     else if ( xPos 
> (xAmount
-(width
/wxPG_PIXELS_PER_UNIT
)) ) 
4380     int yAmount 
= y 
/ wxPG_PIXELS_PER_UNIT
; 
4381     int yPos 
= GetScrollPos( wxVERTICAL 
); 
4383     SetScrollbars( wxPG_PIXELS_PER_UNIT
, wxPG_PIXELS_PER_UNIT
, 
4384                    xAmount
, yAmount
, xPos
, yPos
, true ); 
4386     // Must re-get size now 
4387     GetClientSize(&width
,&height
); 
4389     if ( !HasVirtualWidth() ) 
4391         m_pState
->SetVirtualWidth(width
); 
4398     m_pState
->CheckColumnWidths(); 
4400     if ( GetSelection() ) 
4401         CorrectEditorWidgetSizeX(); 
4403     m_iFlags 
&= ~wxPG_FL_RECALCULATING_VIRTUAL_SIZE
; 
4406 // ----------------------------------------------------------------------- 
4408 void wxPropertyGrid::OnResize( wxSizeEvent
& event 
) 
4410     if ( !(m_iFlags 
& wxPG_FL_INITIALIZED
) ) 
4414     GetClientSize(&width
, &height
); 
4419 #if wxPG_DOUBLE_BUFFER 
4420     if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING
) ) 
4422         int dblh 
= (m_lineHeight
*2); 
4423         if ( !m_doubleBuffer 
) 
4425             // Create double buffer bitmap to draw on, if none 
4426             int w 
= (width
>250)?width
:250; 
4427             int h 
= height 
+ dblh
; 
4429             m_doubleBuffer 
= new wxBitmap( w
, h 
); 
4433             int w 
= m_doubleBuffer
->GetWidth(); 
4434             int h 
= m_doubleBuffer
->GetHeight(); 
4436             // Double buffer must be large enough 
4437             if ( w 
< width 
|| h 
< (height
+dblh
) ) 
4439                 if ( w 
< width 
) w 
= width
; 
4440                 if ( h 
< (height
+dblh
) ) h 
= height 
+ dblh
; 
4441                 delete m_doubleBuffer
; 
4442                 m_doubleBuffer 
= new wxBitmap( w
, h 
); 
4449     m_pState
->OnClientWidthChange( width
, event
.GetSize().x 
- m_ncWidth
, true ); 
4450     m_ncWidth 
= event
.GetSize().x
; 
4454         if ( m_pState
->m_itemsAdded 
) 
4455             PrepareAfterItemsAdded(); 
4457             // Without this, virtual size (atleast under wxGTK) will be skewed 
4458             RecalculateVirtualSize(); 
4464 // ----------------------------------------------------------------------- 
4466 void wxPropertyGrid::SetVirtualWidth( int width 
) 
4470         // Disable virtual width 
4471         width 
= GetClientSize().x
; 
4472         ClearInternalFlag(wxPG_FL_HAS_VIRTUAL_WIDTH
); 
4476         // Enable virtual width 
4477         SetInternalFlag(wxPG_FL_HAS_VIRTUAL_WIDTH
); 
4479     m_pState
->SetVirtualWidth( width 
); 
4482 void wxPropertyGrid::SetFocusOnCanvas() 
4484     SetFocusIgnoringChildren(); 
4485     m_editorFocused 
= 0; 
4488 // ----------------------------------------------------------------------- 
4489 // wxPropertyGrid mouse event handling 
4490 // ----------------------------------------------------------------------- 
4492 // selFlags uses same values DoSelectProperty's flags 
4493 // Returns true if event was vetoed. 
4494 bool wxPropertyGrid::SendEvent( int eventType
, wxPGProperty
* p
, 
4496                                 unsigned int selFlags
, 
4497                                 unsigned int column 
) 
4499     // selFlags should have wxPG_SEL_NOVALIDATE if event is not 
4502     // Send property grid event of specific type and with specific property 
4503     wxPropertyGridEvent 
evt( eventType
, m_eventObject
->GetId() ); 
4504     evt
.SetPropertyGrid(this); 
4505     evt
.SetEventObject(m_eventObject
); 
4507     evt
.SetColumn(column
); 
4508     if ( eventType 
== wxEVT_PG_CHANGING 
) 
4511         evt
.SetCanVeto(true); 
4512         m_validationInfo
.m_pValue 
= pValue
; 
4513         evt
.SetupValidationInfo(); 
4518             evt
.SetPropertyValue(p
->GetValue()); 
4520         if ( !(selFlags 
& wxPG_SEL_NOVALIDATE
) ) 
4521             evt
.SetCanVeto(true); 
4524     m_processedEvent 
= &evt
; 
4525     m_eventObject
->HandleWindowEvent(evt
); 
4526     m_processedEvent 
= NULL
; 
4528     return evt
.WasVetoed(); 
4531 // ----------------------------------------------------------------------- 
4533 // Return false if should be skipped 
4534 bool wxPropertyGrid::HandleMouseClick( int x
, unsigned int y
, wxMouseEvent 
&event 
) 
4538     // Need to set focus? 
4539     if ( !(m_iFlags 
& wxPG_FL_FOCUSED
) ) 
4544     wxPropertyGridPageState
* state 
= m_pState
; 
4546     int splitterHitOffset
; 
4547     int columnHit 
= state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
4549     wxPGProperty
* p 
= DoGetItemAtY(y
); 
4553         int depth 
= (int)p
->GetDepth() - 1; 
4555         int marginEnds 
= m_marginWidth 
+ ( depth 
* m_subgroup_extramargin 
); 
4557         if ( x 
>= marginEnds 
) 
4561             if ( p
->IsCategory() ) 
4563                 // This is category. 
4564                 wxPropertyCategory
* pwc 
= (wxPropertyCategory
*)p
; 
4566                 int textX 
= m_marginWidth 
+ ((unsigned int)((pwc
->m_depth
-1)*m_subgroup_extramargin
)); 
4568                 // Expand, collapse, activate etc. if click on text or left of splitter. 
4571                      ( x 
< (textX
+pwc
->GetTextExtent(this, m_captionFont
)+(wxPG_CAPRECTXMARGIN
*2)) || 
4576                     if ( !AddToSelectionFromInputEvent( p
, 
4581                     // On double-click, expand/collapse. 
4582                     if ( event
.ButtonDClick() && !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
4584                         if ( pwc
->IsExpanded() ) DoCollapse( p
, true ); 
4585                         else DoExpand( p
, true ); 
4589             else if ( splitterHit 
== -1 ) 
4592                 unsigned int selFlag 
= 0; 
4593                 if ( columnHit 
== 1 ) 
4595                     m_iFlags 
|= wxPG_FL_ACTIVATION_BY_CLICK
; 
4596                     selFlag 
= wxPG_SEL_FOCUS
; 
4598                 if ( !AddToSelectionFromInputEvent( p
, 
4604                 m_iFlags 
&= ~(wxPG_FL_ACTIVATION_BY_CLICK
); 
4606                 if ( p
->GetChildCount() && !p
->IsCategory() ) 
4607                     // On double-click, expand/collapse. 
4608                     if ( event
.ButtonDClick() && !(m_windowStyle 
& wxPG_HIDE_MARGIN
) ) 
4610                         wxPGProperty
* pwc 
= (wxPGProperty
*)p
; 
4611                         if ( pwc
->IsExpanded() ) DoCollapse( p
, true ); 
4612                         else DoExpand( p
, true ); 
4619             // click on splitter 
4620                 if ( !(m_windowStyle 
& wxPG_STATIC_SPLITTER
) ) 
4622                     if ( event
.GetEventType() == wxEVT_LEFT_DCLICK 
) 
4624                         // Double-clicking the splitter causes auto-centering 
4625                         if ( m_pState
->GetColumnCount() <= 2 ) 
4627                             CenterSplitter( true ); 
4629                             SendEvent(wxEVT_PG_COL_DRAGGING
, 
4632                                       wxPG_SEL_NOVALIDATE
, 
4633                                       (unsigned int)m_draggedSplitter
); 
4636                     else if ( m_dragStatus 
== 0 ) 
4639                         // Begin draggin the splitter 
4643                         DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE
); 
4645                         // Allow application to veto dragging 
4646                         if ( !SendEvent(wxEVT_PG_COL_BEGIN_DRAG
, 
4648                                         (unsigned int)splitterHit
) ) 
4652                                 // Changes must be committed here or the 
4653                                 // value won't be drawn correctly 
4654                                 if ( !CommitChangesFromEditor() ) 
4657                                 m_wndEditor
->Show ( false ); 
4660                             if ( !(m_iFlags 
& wxPG_FL_MOUSE_CAPTURED
) ) 
4663                                 m_iFlags 
|= wxPG_FL_MOUSE_CAPTURED
; 
4667                             m_draggedSplitter 
= splitterHit
; 
4668                             m_dragOffset 
= splitterHitOffset
; 
4670                         #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
4671                             // Fixes button disappearance bug 
4673                                 m_wndEditor2
->Show ( false ); 
4676                             m_startingSplitterX 
= x 
- splitterHitOffset
; 
4685             if ( p
->GetChildCount() ) 
4687                 int nx 
= x 
+ m_marginWidth 
- marginEnds
; // Normalize x. 
4689                 // Fine tune cell button x 
4690                 if ( !p
->IsCategory() ) 
4691                     nx 
-= IN_CELL_EXPANDER_BUTTON_X_ADJUST
; 
4693                 if ( (nx 
>= m_gutterWidth 
&& nx 
< (m_gutterWidth
+m_iconWidth
)) ) 
4695                     int y2 
= y 
% m_lineHeight
; 
4696                     if ( (y2 
>= m_buttonSpacingY 
&& y2 
< (m_buttonSpacingY
+m_iconHeight
)) ) 
4698                         // On click on expander button, expand/collapse 
4699                         if ( ((wxPGProperty
*)p
)->IsExpanded() ) 
4700                             DoCollapse( p
, true ); 
4702                             DoExpand( p
, true ); 
4711 // ----------------------------------------------------------------------- 
4713 bool wxPropertyGrid::HandleMouseRightClick( int WXUNUSED(x
), 
4714                                             unsigned int WXUNUSED(y
), 
4715                                             wxMouseEvent
& event 
) 
4719         // Select property here as well 
4720         wxPGProperty
* p 
= m_propHover
; 
4721         AddToSelectionFromInputEvent(p
, m_colHover
, &event
); 
4723         // Send right click event. 
4724         SendEvent( wxEVT_PG_RIGHT_CLICK
, p 
); 
4731 // ----------------------------------------------------------------------- 
4733 bool wxPropertyGrid::HandleMouseDoubleClick( int WXUNUSED(x
), 
4734                                              unsigned int WXUNUSED(y
), 
4735                                              wxMouseEvent
& event 
) 
4739         // Select property here as well 
4740         wxPGProperty
* p 
= m_propHover
; 
4742         AddToSelectionFromInputEvent(p
, m_colHover
, &event
); 
4744         // Send double-click event. 
4745         SendEvent( wxEVT_PG_DOUBLE_CLICK
, m_propHover 
); 
4752 // ----------------------------------------------------------------------- 
4754 #if wxPG_SUPPORT_TOOLTIPS 
4756 void wxPropertyGrid::SetToolTip( const wxString
& tipString 
) 
4758     if ( tipString
.length() ) 
4760         wxScrolledWindow::SetToolTip(tipString
); 
4764     #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4765         wxScrolledWindow::SetToolTip( m_emptyString 
); 
4767         wxScrolledWindow::SetToolTip( NULL 
); 
4772 #endif // #if wxPG_SUPPORT_TOOLTIPS 
4774 // ----------------------------------------------------------------------- 
4776 // Return false if should be skipped 
4777 bool wxPropertyGrid::HandleMouseMove( int x
, unsigned int y
, 
4778                                       wxMouseEvent 
&event 
) 
4780     // Safety check (needed because mouse capturing may 
4781     // otherwise freeze the control) 
4782     if ( m_dragStatus 
> 0 && !event
.Dragging() ) 
4784         HandleMouseUp(x
, y
, event
); 
4787     wxPropertyGridPageState
* state 
= m_pState
; 
4789     int splitterHitOffset
; 
4790     int columnHit 
= state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
4791     int splitterX 
= x 
- splitterHitOffset
; 
4793     m_colHover 
= columnHit
; 
4795     if ( m_dragStatus 
> 0 ) 
4797         if ( x 
> (m_marginWidth 
+ wxPG_DRAG_MARGIN
) && 
4798              x 
< (m_pState
->m_width 
- wxPG_DRAG_MARGIN
) ) 
4801             int newSplitterX 
= x 
- m_dragOffset
; 
4802             int splitterX 
= x 
- splitterHitOffset
; 
4804             // Splitter redraw required? 
4805             if ( newSplitterX 
!= splitterX 
) 
4808                 DoSetSplitterPosition(newSplitterX
, 
4810                                       wxPG_SPLITTER_REFRESH 
| 
4811                                       wxPG_SPLITTER_FROM_EVENT
); 
4813                 SendEvent(wxEVT_PG_COL_DRAGGING
, 
4816                           wxPG_SEL_NOVALIDATE
, 
4817                           (unsigned int)m_draggedSplitter
); 
4828         int ih 
= m_lineHeight
; 
4831     #if wxPG_SUPPORT_TOOLTIPS 
4832         wxPGProperty
* prevHover 
= m_propHover
; 
4833         unsigned char prevSide 
= m_mouseSide
; 
4835         int curPropHoverY 
= y 
- (y 
% ih
); 
4837         // On which item it hovers 
4840              ( sy 
< m_propHoverY 
|| sy 
>= (m_propHoverY
+ih
) ) 
4843             // Mouse moves on another property 
4845             m_propHover 
= DoGetItemAtY(y
); 
4846             m_propHoverY 
= curPropHoverY
; 
4849             SendEvent( wxEVT_PG_HIGHLIGHTED
, m_propHover 
); 
4852     #if wxPG_SUPPORT_TOOLTIPS 
4853         // Store which side we are on 
4855         if ( columnHit 
== 1 ) 
4857         else if ( columnHit 
== 0 ) 
4861         // If tooltips are enabled, show label or value as a tip 
4862         // in case it doesn't otherwise show in full length. 
4864         if ( m_windowStyle 
& wxPG_TOOLTIPS 
) 
4866             wxToolTip
* tooltip 
= GetToolTip(); 
4868             if ( m_propHover 
!= prevHover 
|| prevSide 
!= m_mouseSide 
) 
4870                 if ( m_propHover 
&& !m_propHover
->IsCategory() ) 
4873                     if ( GetExtraStyle() & wxPG_EX_HELP_AS_TOOLTIPS 
) 
4875                         // Show help string as a tooltip 
4876                         wxString tipString 
= m_propHover
->GetHelpString(); 
4878                         SetToolTip(tipString
); 
4882                         // Show cropped value string as a tooltip 
4886                         if ( m_mouseSide 
== 1 ) 
4888                             tipString 
= m_propHover
->m_label
; 
4889                             space 
= splitterX
-m_marginWidth
-3; 
4891                         else if ( m_mouseSide 
== 2 ) 
4893                             tipString 
= m_propHover
->GetDisplayedString(); 
4895                             space 
= m_width 
- splitterX
; 
4896                             if ( m_propHover
->m_flags 
& wxPG_PROP_CUSTOMIMAGE 
) 
4897                                 space 
-= wxPG_CUSTOM_IMAGE_WIDTH 
+ 
4898                                          wxCC_CUSTOM_IMAGE_MARGIN1 
+ 
4899                                          wxCC_CUSTOM_IMAGE_MARGIN2
; 
4905                             GetTextExtent( tipString
, &tw
, &th
, 0, 0 ); 
4908                                 SetToolTip( tipString 
); 
4915                             #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4916                                 SetToolTip( m_emptyString 
); 
4918                                 wxScrolledWindow::SetToolTip( NULL 
); 
4929                     #if wxPG_ALLOW_EMPTY_TOOLTIPS 
4930                         SetToolTip( m_emptyString 
); 
4932                         wxScrolledWindow::SetToolTip( NULL 
); 
4940         if ( splitterHit 
== -1 || 
4942              HasFlag(wxPG_STATIC_SPLITTER
) ) 
4944             // hovering on something else 
4945             if ( m_curcursor 
!= wxCURSOR_ARROW 
) 
4946                 CustomSetCursor( wxCURSOR_ARROW 
); 
4950             // Do not allow splitter cursor on caption items. 
4951             // (also not if we were dragging and its started 
4952             // outside the splitter region) 
4954             if ( !m_propHover
->IsCategory() && 
4958                 // hovering on splitter 
4960                 // NB: Condition disabled since MouseLeave event (from the 
4961                 //     editor control) cannot be reliably detected. 
4962                 //if ( m_curcursor != wxCURSOR_SIZEWE ) 
4963                 CustomSetCursor( wxCURSOR_SIZEWE
, true ); 
4969                 // hovering on something else 
4970                 if ( m_curcursor 
!= wxCURSOR_ARROW 
) 
4971                     CustomSetCursor( wxCURSOR_ARROW 
); 
4976         // Multi select by dragging 
4978         if ( (GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION
) && 
4979              event
.LeftIsDown() && 
4983              !state
->DoIsPropertySelected(m_propHover
) ) 
4985             // Additional requirement is that the hovered property 
4986             // is adjacent to edges of selection. 
4987             const wxArrayPGProperty
& selection 
= GetSelectedProperties(); 
4989             // Since categories cannot be selected along with 'other' 
4990             // properties, exclude them from iterator flags. 
4991             int iterFlags 
= wxPG_ITERATE_VISIBLE 
& (~wxPG_PROP_CATEGORY
); 
4993             for ( int i
=(selection
.size()-1); i
>=0; i
-- ) 
4995                 // TODO: This could be optimized by keeping track of 
4996                 //       which properties are at the edges of selection. 
4997                 wxPGProperty
* selProp 
= selection
[i
]; 
4998                 if ( state
->ArePropertiesAdjacent(m_propHover
, selProp
, 
5001                     DoAddToSelection(m_propHover
); 
5010 // ----------------------------------------------------------------------- 
5012 // Also handles Leaving event 
5013 bool wxPropertyGrid::HandleMouseUp( int x
, unsigned int WXUNUSED(y
), 
5014                                     wxMouseEvent 
&WXUNUSED(event
) ) 
5016     wxPropertyGridPageState
* state 
= m_pState
; 
5020     int splitterHitOffset
; 
5021     state
->HitTestH( x
, &splitterHit
, &splitterHitOffset 
); 
5023     // No event type check - basicly calling this method should 
5024     // just stop dragging. 
5025     // Left up after dragged? 
5026     if ( m_dragStatus 
>= 1 ) 
5029     // End Splitter Dragging 
5031         // DO NOT ENABLE FOLLOWING LINE! 
5032         // (it is only here as a reminder to not to do it) 
5035         SendEvent(wxEVT_PG_COL_END_DRAG
, 
5038                   wxPG_SEL_NOVALIDATE
, 
5039                   (unsigned int)m_draggedSplitter
); 
5041         // Disable splitter auto-centering 
5042         state
->m_dontCenterSplitter 
= true; 
5044         // This is necessary to return cursor 
5045         if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
5048             m_iFlags 
&= ~(wxPG_FL_MOUSE_CAPTURED
); 
5051         // Set back the default cursor, if necessary 
5052         if ( splitterHit 
== -1 || 
5055             CustomSetCursor( wxCURSOR_ARROW 
); 
5060         // Control background needs to be cleared 
5061         wxPGProperty
* selected 
= GetSelection(); 
5062         if ( !(m_iFlags 
& wxPG_FL_PRIMARY_FILLS_ENTIRE
) && selected 
) 
5063             DrawItem( selected 
); 
5067             m_wndEditor
->Show ( true ); 
5070     #if wxPG_REFRESH_CONTROLS_AFTER_REPAINT 
5071         // Fixes button disappearance bug 
5073             m_wndEditor2
->Show ( true ); 
5076         // This clears the focus. 
5077         m_editorFocused 
= 0; 
5083 // ----------------------------------------------------------------------- 
5085 bool wxPropertyGrid::OnMouseCommon( wxMouseEvent
& event
, int* px
, int* py 
) 
5087     int splitterX 
= GetSplitterPosition(); 
5090     CalcUnscrolledPosition( event
.m_x
, event
.m_y
, &ux
, &uy 
); 
5092     wxWindow
* wnd 
= GetEditorControl(); 
5094     // Hide popup on clicks 
5095     if ( event
.GetEventType() != wxEVT_MOTION 
) 
5096         if ( wnd 
&& wnd
->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox
)) ) 
5098             ((wxOwnerDrawnComboBox
*)wnd
)->HidePopup(); 
5104     if ( wnd 
== NULL 
|| m_dragStatus 
|| 
5106            ux 
<= (splitterX 
+ wxPG_SPLITTERX_DETECTMARGIN2
) || 
5107            ux 
>= (r
.x
+r
.width
) || 
5109            event
.m_y 
>= (r
.y
+r
.height
) 
5119         if ( m_curcursor 
!= wxCURSOR_ARROW 
) CustomSetCursor ( wxCURSOR_ARROW 
); 
5124 // ----------------------------------------------------------------------- 
5126 void wxPropertyGrid::OnMouseClick( wxMouseEvent 
&event 
) 
5129     if ( OnMouseCommon( event
, &x
, &y 
) ) 
5131         HandleMouseClick(x
,y
,event
); 
5136 // ----------------------------------------------------------------------- 
5138 void wxPropertyGrid::OnMouseRightClick( wxMouseEvent 
&event 
) 
5141     CalcUnscrolledPosition( event
.m_x
, event
.m_y
, &x
, &y 
); 
5142     HandleMouseRightClick(x
,y
,event
); 
5146 // ----------------------------------------------------------------------- 
5148 void wxPropertyGrid::OnMouseDoubleClick( wxMouseEvent 
&event 
) 
5150     // Always run standard mouse-down handler as well 
5151     OnMouseClick(event
); 
5154     CalcUnscrolledPosition( event
.m_x
, event
.m_y
, &x
, &y 
); 
5155     HandleMouseDoubleClick(x
,y
,event
); 
5159 // ----------------------------------------------------------------------- 
5161 void wxPropertyGrid::OnMouseMove( wxMouseEvent 
&event 
) 
5164     if ( OnMouseCommon( event
, &x
, &y 
) ) 
5166         HandleMouseMove(x
,y
,event
); 
5171 // ----------------------------------------------------------------------- 
5173 void wxPropertyGrid::OnMouseUp( wxMouseEvent 
&event 
) 
5176     if ( OnMouseCommon( event
, &x
, &y 
) ) 
5178         HandleMouseUp(x
,y
,event
); 
5183 // ----------------------------------------------------------------------- 
5185 void wxPropertyGrid::OnMouseEntry( wxMouseEvent 
&event 
) 
5187     // This may get called from child control as well, so event's 
5188     // mouse position cannot be relied on. 
5190     if ( event
.Entering() ) 
5192         if ( !(m_iFlags 
& wxPG_FL_MOUSE_INSIDE
) ) 
5194             // TODO: Fix this (detect parent and only do 
5195             //   cursor trick if it is a manager). 
5196             wxASSERT( GetParent() ); 
5197             GetParent()->SetCursor(wxNullCursor
); 
5199             m_iFlags 
|= wxPG_FL_MOUSE_INSIDE
; 
5202             GetParent()->SetCursor(wxNullCursor
); 
5204     else if ( event
.Leaving() ) 
5206         // Without this, wxSpinCtrl editor will sometimes have wrong cursor 
5207         SetCursor( wxNullCursor 
); 
5209         // Get real cursor position 
5210         wxPoint pt 
= ScreenToClient(::wxGetMousePosition()); 
5212         if ( ( pt
.x 
<= 0 || pt
.y 
<= 0 || pt
.x 
>= m_width 
|| pt
.y 
>= m_height 
) ) 
5215                 if ( (m_iFlags 
& wxPG_FL_MOUSE_INSIDE
) ) 
5217                     m_iFlags 
&= ~(wxPG_FL_MOUSE_INSIDE
); 
5221                     wxPropertyGrid::HandleMouseUp ( -1, 10000, event 
); 
5229 // ----------------------------------------------------------------------- 
5231 // Common code used by various OnMouseXXXChild methods. 
5232 bool wxPropertyGrid::OnMouseChildCommon( wxMouseEvent 
&event
, int* px
, int *py 
) 
5234     wxWindow
* topCtrlWnd 
= (wxWindow
*)event
.GetEventObject(); 
5235     wxASSERT( topCtrlWnd 
); 
5237     event
.GetPosition(&x
,&y
); 
5239     int splitterX 
= GetSplitterPosition(); 
5241     wxRect r 
= topCtrlWnd
->GetRect(); 
5242     if ( !m_dragStatus 
&& 
5243          x 
> (splitterX
-r
.x
+wxPG_SPLITTERX_DETECTMARGIN2
) && 
5244          y 
>= 0 && y 
< r
.height \
 
5247         if ( m_curcursor 
!= wxCURSOR_ARROW 
) CustomSetCursor ( wxCURSOR_ARROW 
); 
5252         CalcUnscrolledPosition( event
.m_x 
+ r
.x
, event
.m_y 
+ r
.y
, \
 
5259 void wxPropertyGrid::OnMouseClickChild( wxMouseEvent 
&event 
) 
5262     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
5264         bool res 
= HandleMouseClick(x
,y
,event
); 
5265         if ( !res 
) event
.Skip(); 
5269 void wxPropertyGrid::OnMouseRightClickChild( wxMouseEvent 
&event 
) 
5272     wxASSERT( m_wndEditor 
); 
5273     // These coords may not be exact (about +-2), 
5274     // but that should not matter (right click is about item, not position). 
5275     wxPoint pt 
= m_wndEditor
->GetPosition(); 
5276     CalcUnscrolledPosition( event
.m_x 
+ pt
.x
, event
.m_y 
+ pt
.y
, &x
, &y 
); 
5278     // FIXME: Used to set m_propHover to selection here. Was it really 
5281     bool res 
= HandleMouseRightClick(x
,y
,event
); 
5282     if ( !res 
) event
.Skip(); 
5285 void wxPropertyGrid::OnMouseMoveChild( wxMouseEvent 
&event 
) 
5288     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
5290         bool res 
= HandleMouseMove(x
,y
,event
); 
5291         if ( !res 
) event
.Skip(); 
5295 void wxPropertyGrid::OnMouseUpChild( wxMouseEvent 
&event 
) 
5298     if ( OnMouseChildCommon(event
,&x
,&y
) ) 
5300         bool res 
= HandleMouseUp(x
,y
,event
); 
5301         if ( !res 
) event
.Skip(); 
5305 // ----------------------------------------------------------------------- 
5306 // wxPropertyGrid keyboard event handling 
5307 // ----------------------------------------------------------------------- 
5309 int wxPropertyGrid::KeyEventToActions(wxKeyEvent 
&event
, int* pSecond
) const 
5311     // Translates wxKeyEvent to wxPG_ACTION_XXX 
5313     int keycode 
= event
.GetKeyCode(); 
5314     int modifiers 
= event
.GetModifiers(); 
5316     wxASSERT( !(modifiers
&~(0xFFFF)) ); 
5318     int hashMapKey 
= (keycode 
& 0xFFFF) | ((modifiers 
& 0xFFFF) << 16); 
5320     wxPGHashMapI2I::const_iterator it 
= m_actionTriggers
.find(hashMapKey
); 
5322     if ( it 
== m_actionTriggers
.end() ) 
5327         int second 
= (it
->second
>>16) & 0xFFFF; 
5331     return (it
->second 
& 0xFFFF); 
5334 void wxPropertyGrid::AddActionTrigger( int action
, int keycode
, int modifiers 
) 
5336     wxASSERT( !(modifiers
&~(0xFFFF)) ); 
5338     int hashMapKey 
= (keycode 
& 0xFFFF) | ((modifiers 
& 0xFFFF) << 16); 
5340     wxPGHashMapI2I::iterator it 
= m_actionTriggers
.find(hashMapKey
); 
5342     if ( it 
!= m_actionTriggers
.end() ) 
5344         // This key combination is already used 
5346         // Can add secondary? 
5347         wxASSERT_MSG( !(it
->second
&~(0xFFFF)), 
5348                       wxT("You can only add up to two separate actions per key combination.") ); 
5350         action 
= it
->second 
| (action
<<16); 
5353     m_actionTriggers
[hashMapKey
] = action
; 
5356 void wxPropertyGrid::ClearActionTriggers( int action 
) 
5358     wxPGHashMapI2I::iterator it
; 
5363         didSomething 
= false; 
5365         for ( it 
= m_actionTriggers
.begin(); 
5366               it 
!= m_actionTriggers
.end(); 
5369             if ( it
->second 
== action 
) 
5371                 m_actionTriggers
.erase(it
); 
5372                 didSomething 
= true; 
5377     while ( didSomething 
); 
5380 void wxPropertyGrid::HandleKeyEvent( wxKeyEvent 
&event
, bool fromChild 
) 
5383     // Handles key event when editor control is not focused. 
5386     wxCHECK2(!m_frozen
, return); 
5388     // Travelsal between items, collapsing/expanding, etc. 
5389     wxPGProperty
* selected 
= GetSelection(); 
5390     int keycode 
= event
.GetKeyCode(); 
5391     bool editorFocused 
= IsEditorFocused(); 
5393     if ( keycode 
== WXK_TAB 
) 
5395         wxWindow
* mainControl
; 
5397         if ( HasInternalFlag(wxPG_FL_IN_MANAGER
) ) 
5398             mainControl 
= GetParent(); 
5402         if ( !event
.ShiftDown() ) 
5404             if ( !editorFocused 
&& m_wndEditor 
) 
5406                 DoSelectProperty( selected
, wxPG_SEL_FOCUS 
); 
5410                 // Tab traversal workaround for platforms on which 
5411                 // wxWindow::Navigate() may navigate into first child 
5412                 // instead of next sibling. Does not work perfectly 
5413                 // in every scenario (for instance, when property grid 
5414                 // is either first or last control). 
5415             #if defined(__WXGTK__) 
5416                 wxWindow
* sibling 
= mainControl
->GetNextSibling(); 
5418                     sibling
->SetFocusFromKbd(); 
5420                 Navigate(wxNavigationKeyEvent::IsForward
); 
5426             if ( editorFocused 
) 
5432             #if defined(__WXGTK__) 
5433                 wxWindow
* sibling 
= mainControl
->GetPrevSibling(); 
5435                     sibling
->SetFocusFromKbd(); 
5437                 Navigate(wxNavigationKeyEvent::IsBackward
); 
5445     // Ignore Alt and Control when they are down alone 
5446     if ( keycode 
== WXK_ALT 
|| 
5447          keycode 
== WXK_CONTROL 
) 
5454     int action 
= KeyEventToActions(event
, &secondAction
); 
5456     if ( editorFocused 
&& action 
== wxPG_ACTION_CANCEL_EDIT 
) 
5459         // Esc cancels any changes 
5460         if ( IsEditorsValueModified() ) 
5462             EditorsValueWasNotModified(); 
5464             // Update the control as well 
5465             selected
->GetEditorClass()-> 
5466                 SetControlStringValue( selected
, 
5468                                        selected
->GetDisplayedString() ); 
5471         OnValidationFailureReset(selected
); 
5477     // Except for TAB and ESC, handle child control events in child control 
5480         // Only propagate event if it had modifiers 
5481         if ( !event
.HasModifiers() ) 
5483             event
.StopPropagation(); 
5489     bool wasHandled 
= false; 
5494         if ( ButtonTriggerKeyTest(action
, event
) ) 
5497         wxPGProperty
* p 
= selected
; 
5499         // Travel and expand/collapse 
5502         if ( p
->GetChildCount() ) 
5504             if ( action 
== wxPG_ACTION_COLLAPSE_PROPERTY 
|| secondAction 
== wxPG_ACTION_COLLAPSE_PROPERTY 
) 
5506                 if ( (m_windowStyle 
& wxPG_HIDE_MARGIN
) || Collapse(p
) ) 
5509             else if ( action 
== wxPG_ACTION_EXPAND_PROPERTY 
|| secondAction 
== wxPG_ACTION_EXPAND_PROPERTY 
) 
5511                 if ( (m_windowStyle 
& wxPG_HIDE_MARGIN
) || Expand(p
) ) 
5518             if ( action 
== wxPG_ACTION_PREV_PROPERTY 
|| secondAction 
== wxPG_ACTION_PREV_PROPERTY 
) 
5522             else if ( action 
== wxPG_ACTION_NEXT_PROPERTY 
|| secondAction 
== wxPG_ACTION_NEXT_PROPERTY 
) 
5528         if ( selectDir 
>= -1 ) 
5530             p 
= wxPropertyGridIterator::OneStep( m_pState
, wxPG_ITERATE_VISIBLE
, p
, selectDir 
); 
5532                 DoSelectProperty(p
); 
5538         // If nothing was selected, select the first item now 
5539         // (or navigate out of tab). 
5540         if ( action 
!= wxPG_ACTION_CANCEL_EDIT 
&& secondAction 
!= wxPG_ACTION_CANCEL_EDIT 
) 
5542             wxPGProperty
* p 
= wxPropertyGridInterface::GetFirst(); 
5543             if ( p 
) DoSelectProperty(p
); 
5552 // ----------------------------------------------------------------------- 
5554 void wxPropertyGrid::OnKey( wxKeyEvent 
&event 
) 
5556     // If there was editor open and focused, then this event should not 
5557     // really be processed here. 
5558     if ( IsEditorFocused() ) 
5560         // However, if event had modifiers, it is probably still best 
5562         if ( event
.HasModifiers() ) 
5565             event
.StopPropagation(); 
5569     HandleKeyEvent(event
, false); 
5572 // ----------------------------------------------------------------------- 
5574 bool wxPropertyGrid::ButtonTriggerKeyTest( int action
, wxKeyEvent
& event 
) 
5579         action 
= KeyEventToActions(event
, &secondAction
); 
5582     // Does the keycode trigger button? 
5583     if ( action 
== wxPG_ACTION_PRESS_BUTTON 
&& 
5586         wxCommandEvent 
evt(wxEVT_COMMAND_BUTTON_CLICKED
, m_wndEditor2
->GetId()); 
5587         GetEventHandler()->AddPendingEvent(evt
); 
5594 // ----------------------------------------------------------------------- 
5596 void wxPropertyGrid::OnChildKeyDown( wxKeyEvent 
&event 
) 
5598     HandleKeyEvent(event
, true); 
5601 // ----------------------------------------------------------------------- 
5602 // wxPropertyGrid miscellaneous event handling 
5603 // ----------------------------------------------------------------------- 
5605 void wxPropertyGrid::OnIdle( wxIdleEvent
& WXUNUSED(event
) ) 
5608     // Check if the focus is in this control or one of its children 
5609     wxWindow
* newFocused 
= wxWindow::FindFocus(); 
5611     if ( newFocused 
!= m_curFocused 
) 
5612         HandleFocusChange( newFocused 
); 
5615     // Check if top-level parent has changed 
5616     if ( GetExtraStyle() & wxPG_EX_ENABLE_TLP_TRACKING 
) 
5618         wxWindow
* tlp 
= ::wxGetTopLevelParent(this); 
5624 bool wxPropertyGrid::IsEditorFocused() const 
5626     wxWindow
* focus 
= wxWindow::FindFocus(); 
5628     if ( focus 
== m_wndEditor 
|| focus 
== m_wndEditor2 
|| 
5629          focus 
== GetEditorControl() ) 
5635 // Called by focus event handlers. newFocused is the window that becomes focused. 
5636 void wxPropertyGrid::HandleFocusChange( wxWindow
* newFocused 
) 
5638     unsigned int oldFlags 
= m_iFlags
; 
5639     bool wasEditorFocused 
= false; 
5640     wxWindow
* wndEditor 
= m_wndEditor
; 
5642     m_iFlags 
&= ~(wxPG_FL_FOCUSED
); 
5644     wxWindow
* parent 
= newFocused
; 
5646     // This must be one of nextFocus' parents. 
5649         if ( parent 
== wndEditor 
) 
5651             wasEditorFocused 
= true; 
5653         // Use m_eventObject, which is either wxPropertyGrid or 
5654         // wxPropertyGridManager, as appropriate. 
5655         else if ( parent 
== m_eventObject 
) 
5657             m_iFlags 
|= wxPG_FL_FOCUSED
; 
5660         parent 
= parent
->GetParent(); 
5663     // Notify editor control when it receives a focus 
5664     if ( wasEditorFocused 
&& m_curFocused 
!= newFocused 
) 
5666         wxPGProperty
* p 
= GetSelection(); 
5669             const wxPGEditor
* editor 
= p
->GetEditorClass(); 
5670             editor
->OnFocus(p
, GetEditorControl()); 
5674     m_curFocused 
= newFocused
; 
5676     if ( (m_iFlags 
& wxPG_FL_FOCUSED
) != 
5677          (oldFlags 
& wxPG_FL_FOCUSED
) ) 
5679         if ( !(m_iFlags 
& wxPG_FL_FOCUSED
) ) 
5681             // Need to store changed value 
5682             CommitChangesFromEditor(); 
5688             // Preliminary code for tab-order respecting 
5689             // tab-traversal (but should be moved to 
5692             wxWindow* prevFocus = event.GetWindow(); 
5693             wxWindow* useThis = this; 
5694             if ( m_iFlags & wxPG_FL_IN_MANAGER ) 
5695                 useThis = GetParent(); 
5698                  prevFocus->GetParent() == useThis->GetParent() ) 
5700                 wxList& children = useThis->GetParent()->GetChildren(); 
5702                 wxNode* node = children.Find(prevFocus); 
5704                 if ( node->GetNext() && 
5705                      useThis == node->GetNext()->GetData() ) 
5706                     DoSelectProperty(GetFirst()); 
5707                 else if ( node->GetPrevious () && 
5708                           useThis == node->GetPrevious()->GetData() ) 
5709                     DoSelectProperty(GetLastProperty()); 
5716         wxPGProperty
* selected 
= GetSelection(); 
5717         if ( selected 
&& (m_iFlags 
& wxPG_FL_INITIALIZED
) ) 
5718             DrawItem( selected 
); 
5722 void wxPropertyGrid::OnFocusEvent( wxFocusEvent
& event 
) 
5724     if ( event
.GetEventType() == wxEVT_SET_FOCUS 
) 
5725         HandleFocusChange((wxWindow
*)event
.GetEventObject()); 
5726     // Line changed to "else" when applying wxPropertyGrid patch #1675902 
5727     //else if ( event.GetWindow() ) 
5729         HandleFocusChange(event
.GetWindow()); 
5734 // ----------------------------------------------------------------------- 
5736 void wxPropertyGrid::OnChildFocusEvent( wxChildFocusEvent
& event 
) 
5738     HandleFocusChange((wxWindow
*)event
.GetEventObject()); 
5742 // ----------------------------------------------------------------------- 
5744 void wxPropertyGrid::OnScrollEvent( wxScrollWinEvent 
&event 
) 
5746     m_iFlags 
|= wxPG_FL_SCROLLED
; 
5751 // ----------------------------------------------------------------------- 
5753 void wxPropertyGrid::OnCaptureChange( wxMouseCaptureChangedEvent
& WXUNUSED(event
) ) 
5755     if ( m_iFlags 
& wxPG_FL_MOUSE_CAPTURED 
) 
5757         m_iFlags 
&= ~(wxPG_FL_MOUSE_CAPTURED
); 
5761 // ----------------------------------------------------------------------- 
5762 // Property editor related functions 
5763 // ----------------------------------------------------------------------- 
5765 // noDefCheck = true prevents infinite recursion. 
5766 wxPGEditor
* wxPropertyGrid::DoRegisterEditorClass( wxPGEditor
* editorClass
, 
5767                                                    const wxString
& editorName
, 
5770     wxASSERT( editorClass 
); 
5772     if ( !noDefCheck 
&& wxPGGlobalVars
->m_mapEditorClasses
.empty() ) 
5773         RegisterDefaultEditors(); 
5775     wxString name 
= editorName
; 
5776     if ( name
.length() == 0 ) 
5777         name 
= editorClass
->GetName(); 
5779     // Existing editor under this name? 
5780     wxPGHashMapS2P::iterator vt_it 
= wxPGGlobalVars
->m_mapEditorClasses
.find(name
); 
5782     if ( vt_it 
!= wxPGGlobalVars
->m_mapEditorClasses
.end() ) 
5784         // If this name was already used, try class name. 
5785         name 
= editorClass
->GetClassInfo()->GetClassName(); 
5786         vt_it 
= wxPGGlobalVars
->m_mapEditorClasses
.find(name
); 
5789     wxCHECK_MSG( vt_it 
== wxPGGlobalVars
->m_mapEditorClasses
.end(), 
5790                  (wxPGEditor
*) vt_it
->second
, 
5791                  "Editor with given name was already registered" ); 
5793     wxPGGlobalVars
->m_mapEditorClasses
[name
] = (void*)editorClass
; 
5798 // Use this in RegisterDefaultEditors. 
5799 #define wxPGRegisterDefaultEditorClass(EDITOR) \ 
5800     if ( wxPGEditor_##EDITOR == NULL ) \ 
5802         wxPGEditor_##EDITOR = wxPropertyGrid::RegisterEditorClass( \ 
5803             new wxPG##EDITOR##Editor, true ); \ 
5806 // Registers all default editor classes 
5807 void wxPropertyGrid::RegisterDefaultEditors() 
5809     wxPGRegisterDefaultEditorClass( TextCtrl 
); 
5810     wxPGRegisterDefaultEditorClass( Choice 
); 
5811     wxPGRegisterDefaultEditorClass( ComboBox 
); 
5812     wxPGRegisterDefaultEditorClass( TextCtrlAndButton 
); 
5813 #if wxPG_INCLUDE_CHECKBOX 
5814     wxPGRegisterDefaultEditorClass( CheckBox 
); 
5816     wxPGRegisterDefaultEditorClass( ChoiceAndButton 
); 
5818     // Register SpinCtrl etc. editors before use 
5819     RegisterAdditionalEditors(); 
5822 // ----------------------------------------------------------------------- 
5823 // wxPGStringTokenizer 
5824 //   Needed to handle C-style string lists (e.g. "str1" "str2") 
5825 // ----------------------------------------------------------------------- 
5827 wxPGStringTokenizer::wxPGStringTokenizer( const wxString
& str
, wxChar delimeter 
) 
5828     : m_str(&str
), m_curPos(str
.begin()), m_delimeter(delimeter
) 
5832 wxPGStringTokenizer::~wxPGStringTokenizer() 
5836 bool wxPGStringTokenizer::HasMoreTokens() 
5838     const wxString
& str 
= *m_str
; 
5840     wxString::const_iterator i 
= m_curPos
; 
5842     wxUniChar delim 
= m_delimeter
; 
5844     wxUniChar prev_a 
= wxT('\0'); 
5846     bool inToken 
= false; 
5848     while ( i 
!= str
.end() ) 
5857                 m_readyToken
.clear(); 
5862             if ( prev_a 
!= wxT('\\') ) 
5866                     if ( a 
!= wxT('\\') ) 
5886     m_curPos 
= str
.end(); 
5894 wxString 
wxPGStringTokenizer::GetNextToken() 
5896     return m_readyToken
; 
5899 // ----------------------------------------------------------------------- 
5901 // ----------------------------------------------------------------------- 
5903 wxPGChoiceEntry::wxPGChoiceEntry() 
5904     : wxPGCell(), m_value(wxPG_INVALID_VALUE
) 
5908 // ----------------------------------------------------------------------- 
5910 // ----------------------------------------------------------------------- 
5912 wxPGChoicesData::wxPGChoicesData() 
5916 wxPGChoicesData::~wxPGChoicesData() 
5921 void wxPGChoicesData::Clear() 
5926 void wxPGChoicesData::CopyDataFrom( wxPGChoicesData
* data 
) 
5928     wxASSERT( m_items
.size() == 0 ); 
5930     m_items 
= data
->m_items
; 
5933 wxPGChoiceEntry
& wxPGChoicesData::Insert( int index
, 
5934                                           const wxPGChoiceEntry
& item 
) 
5936     wxVector
<wxPGChoiceEntry
>::iterator it
; 
5940         index 
= (int) m_items
.size(); 
5944         it 
= m_items
.begin() + index
; 
5947     m_items
.insert(it
, item
); 
5949     wxPGChoiceEntry
& ownEntry 
= m_items
[index
]; 
5951     // Need to fix value? 
5952     if ( ownEntry
.GetValue() == wxPG_INVALID_VALUE 
) 
5953         ownEntry
.SetValue(index
); 
5958 // ----------------------------------------------------------------------- 
5959 // wxPropertyGridEvent 
5960 // ----------------------------------------------------------------------- 
5962 IMPLEMENT_DYNAMIC_CLASS(wxPropertyGridEvent
, wxCommandEvent
) 
5965 wxDEFINE_EVENT( wxEVT_PG_SELECTED
, wxPropertyGridEvent 
); 
5966 wxDEFINE_EVENT( wxEVT_PG_CHANGING
, wxPropertyGridEvent 
); 
5967 wxDEFINE_EVENT( wxEVT_PG_CHANGED
, wxPropertyGridEvent 
); 
5968 wxDEFINE_EVENT( wxEVT_PG_HIGHLIGHTED
, wxPropertyGridEvent 
); 
5969 wxDEFINE_EVENT( wxEVT_PG_RIGHT_CLICK
, wxPropertyGridEvent 
); 
5970 wxDEFINE_EVENT( wxEVT_PG_PAGE_CHANGED
, wxPropertyGridEvent 
); 
5971 wxDEFINE_EVENT( wxEVT_PG_ITEM_EXPANDED
, wxPropertyGridEvent 
); 
5972 wxDEFINE_EVENT( wxEVT_PG_ITEM_COLLAPSED
, wxPropertyGridEvent 
); 
5973 wxDEFINE_EVENT( wxEVT_PG_DOUBLE_CLICK
, wxPropertyGridEvent 
); 
5974 wxDEFINE_EVENT( wxEVT_PG_LABEL_EDIT_BEGIN
, wxPropertyGridEvent 
); 
5975 wxDEFINE_EVENT( wxEVT_PG_LABEL_EDIT_ENDING
, wxPropertyGridEvent 
); 
5976 wxDEFINE_EVENT( wxEVT_PG_COL_BEGIN_DRAG
, wxPropertyGridEvent 
); 
5977 wxDEFINE_EVENT( wxEVT_PG_COL_DRAGGING
, wxPropertyGridEvent 
); 
5978 wxDEFINE_EVENT( wxEVT_PG_COL_END_DRAG
, wxPropertyGridEvent 
); 
5980 // ----------------------------------------------------------------------- 
5982 void wxPropertyGridEvent::Init() 
5984     m_validationInfo 
= NULL
; 
5987     m_wasVetoed 
= false; 
5990 // ----------------------------------------------------------------------- 
5992 wxPropertyGridEvent::wxPropertyGridEvent(wxEventType commandType
, int id
) 
5993     : wxCommandEvent(commandType
,id
) 
5999 // ----------------------------------------------------------------------- 
6001 wxPropertyGridEvent::wxPropertyGridEvent(const wxPropertyGridEvent
& event
) 
6002     : wxCommandEvent(event
) 
6004     m_eventType 
= event
.GetEventType(); 
6005     m_eventObject 
= event
.m_eventObject
; 
6007     OnPropertyGridSet(); 
6008     m_property 
= event
.m_property
; 
6009     m_validationInfo 
= event
.m_validationInfo
; 
6010     m_canVeto 
= event
.m_canVeto
; 
6011     m_wasVetoed 
= event
.m_wasVetoed
; 
6014 // ----------------------------------------------------------------------- 
6016 void wxPropertyGridEvent::OnPropertyGridSet() 
6022     wxCriticalSectionLocker(wxPGGlobalVars
->m_critSect
); 
6024     m_pg
->m_liveEvents
.push_back(this); 
6027 // ----------------------------------------------------------------------- 
6029 wxPropertyGridEvent::~wxPropertyGridEvent() 
6034         wxCriticalSectionLocker(wxPGGlobalVars
->m_critSect
); 
6037         // Use iterate from the back since it is more likely that the event 
6038         // being desroyed is at the end of the array. 
6039         wxVector
<wxPropertyGridEvent
*>& liveEvents 
= m_pg
->m_liveEvents
; 
6041         for ( int i 
= liveEvents
.size()-1; i 
>= 0; i
-- ) 
6043             if ( liveEvents
[i
] == this ) 
6045                 liveEvents
.erase(liveEvents
.begin() + i
); 
6052 // ----------------------------------------------------------------------- 
6054 wxEvent
* wxPropertyGridEvent::Clone() const 
6056     return new wxPropertyGridEvent( *this ); 
6059 // ----------------------------------------------------------------------- 
6060 // wxPropertyGridPopulator 
6061 // ----------------------------------------------------------------------- 
6063 wxPropertyGridPopulator::wxPropertyGridPopulator() 
6067     wxPGGlobalVars
->m_offline
++; 
6070 // ----------------------------------------------------------------------- 
6072 void wxPropertyGridPopulator::SetState( wxPropertyGridPageState
* state 
) 
6075     m_propHierarchy
.clear(); 
6078 // ----------------------------------------------------------------------- 
6080 void wxPropertyGridPopulator::SetGrid( wxPropertyGrid
* pg 
) 
6086 // ----------------------------------------------------------------------- 
6088 wxPropertyGridPopulator::~wxPropertyGridPopulator() 
6091     // Free unused sets of choices 
6092     wxPGHashMapS2P::iterator it
; 
6094     for( it 
= m_dictIdChoices
.begin(); it 
!= m_dictIdChoices
.end(); ++it 
) 
6096         wxPGChoicesData
* data 
= (wxPGChoicesData
*) it
->second
; 
6103         m_pg
->GetPanel()->Refresh(); 
6105     wxPGGlobalVars
->m_offline
--; 
6108 // ----------------------------------------------------------------------- 
6110 wxPGProperty
* wxPropertyGridPopulator::Add( const wxString
& propClass
, 
6111                                             const wxString
& propLabel
, 
6112                                             const wxString
& propName
, 
6113                                             const wxString
* propValue
, 
6114                                             wxPGChoices
* pChoices 
) 
6116     wxClassInfo
* classInfo 
= wxClassInfo::FindClass(propClass
); 
6117     wxPGProperty
* parent 
= GetCurParent(); 
6119     if ( parent
->HasFlag(wxPG_PROP_AGGREGATE
) ) 
6121         ProcessError(wxString::Format(wxT("new children cannot be added to '%s'"),parent
->GetName().c_str())); 
6125     if ( !classInfo 
|| !classInfo
->IsKindOf(CLASSINFO(wxPGProperty
)) ) 
6127         ProcessError(wxString::Format(wxT("'%s' is not valid property class"),propClass
.c_str())); 
6131     wxPGProperty
* property 
= (wxPGProperty
*) classInfo
->CreateObject(); 
6133     property
->SetLabel(propLabel
); 
6134     property
->DoSetName(propName
); 
6136     if ( pChoices 
&& pChoices
->IsOk() ) 
6137         property
->SetChoices(*pChoices
); 
6139     m_state
->DoInsert(parent
, -1, property
); 
6142         property
->SetValueFromString( *propValue
, wxPG_FULL_VALUE
| 
6143                                                   wxPG_PROGRAMMATIC_VALUE 
); 
6148 // ----------------------------------------------------------------------- 
6150 void wxPropertyGridPopulator::AddChildren( wxPGProperty
* property 
) 
6152     m_propHierarchy
.push_back(property
); 
6153     DoScanForChildren(); 
6154     m_propHierarchy
.pop_back(); 
6157 // ----------------------------------------------------------------------- 
6159 wxPGChoices 
wxPropertyGridPopulator::ParseChoices( const wxString
& choicesString
, 
6160                                                    const wxString
& idString 
) 
6162     wxPGChoices choices
; 
6165     if ( choicesString
[0] == wxT('@') ) 
6167         wxString ids 
= choicesString
.substr(1); 
6168         wxPGHashMapS2P::iterator it 
= m_dictIdChoices
.find(ids
); 
6169         if ( it 
== m_dictIdChoices
.end() ) 
6170             ProcessError(wxString::Format(wxT("No choices defined for id '%s'"),ids
.c_str())); 
6172             choices
.AssignData((wxPGChoicesData
*)it
->second
); 
6177         if ( idString
.length() ) 
6179             wxPGHashMapS2P::iterator it 
= m_dictIdChoices
.find(idString
); 
6180             if ( it 
!= m_dictIdChoices
.end() ) 
6182                 choices
.AssignData((wxPGChoicesData
*)it
->second
); 
6189             // Parse choices string 
6190             wxString::const_iterator it 
= choicesString
.begin(); 
6194             bool labelValid 
= false; 
6196             for ( ; it 
!= choicesString
.end(); ++it 
) 
6202                     if ( c 
== wxT('"') ) 
6207                             if ( !value
.ToLong(&l
, 0) ) l 
= wxPG_INVALID_VALUE
; 
6208                             choices
.Add(label
, l
); 
6211                         //wxLogDebug(wxT("%s, %s"),label.c_str(),value.c_str()); 
6216                     else if ( c 
== wxT('=') ) 
6223                     else if ( state 
== 2 && (wxIsalnum(c
) || c 
== wxT('x')) ) 
6230                     if ( c 
== wxT('"') ) 
6243                 if ( !value
.ToLong(&l
, 0) ) l 
= wxPG_INVALID_VALUE
; 
6244                 choices
.Add(label
, l
); 
6247             if ( !choices
.IsOk() ) 
6249                 choices
.EnsureData(); 
6253             if ( idString
.length() ) 
6254                 m_dictIdChoices
[idString
] = choices
.GetData(); 
6261 // ----------------------------------------------------------------------- 
6263 bool wxPropertyGridPopulator::ToLongPCT( const wxString
& s
, long* pval
, long max 
) 
6265     if ( s
.Last() == wxT('%') ) 
6267         wxString s2 
= s
.substr(0,s
.length()-1); 
6269         if ( s2
.ToLong(&val
, 10) ) 
6271             *pval 
= (val
*max
)/100; 
6277     return s
.ToLong(pval
, 10); 
6280 // ----------------------------------------------------------------------- 
6282 bool wxPropertyGridPopulator::AddAttribute( const wxString
& name
, 
6283                                             const wxString
& type
, 
6284                                             const wxString
& value 
) 
6286     int l 
= m_propHierarchy
.size(); 
6290     wxPGProperty
* p 
= m_propHierarchy
[l
-1]; 
6291     wxString valuel 
= value
.Lower(); 
6294     if ( type
.length() == 0 ) 
6299         if ( valuel 
== wxT("true") || valuel 
== wxT("yes") || valuel 
== wxT("1") ) 
6301         else if ( valuel 
== wxT("false") || valuel 
== wxT("no") || valuel 
== wxT("0") ) 
6303         else if ( value
.ToLong(&v
, 0) ) 
6310         if ( type 
== wxT("string") ) 
6314         else if ( type 
== wxT("int") ) 
6317             value
.ToLong(&v
, 0); 
6320         else if ( type 
== wxT("bool") ) 
6322             if ( valuel 
== wxT("true") || valuel 
== wxT("yes") || valuel 
== wxT("1") ) 
6329             ProcessError(wxString::Format(wxT("Invalid attribute type '%s'"),type
.c_str())); 
6334     p
->SetAttribute( name
, variant 
); 
6339 // ----------------------------------------------------------------------- 
6341 void wxPropertyGridPopulator::ProcessError( const wxString
& msg 
) 
6343     wxLogError(_("Error in resource: %s"),msg
.c_str()); 
6346 // ----------------------------------------------------------------------- 
6348 #endif  // wxUSE_PROPGRID