X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/f9189014b7162155ab7d4b329c0e5c99bbd9acf3..4cd4a9ff70cdfdfc054747d7dae6101da3f94c03:/src/propgrid/propgrid.cpp?ds=sidebyside diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index f412d75de9..62459e6476 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -4,7 +4,7 @@ // Author: Jaakko Salli // Modified by: // Created: 2004-09-25 -// RCS-ID: $Id: +// RCS-ID: $Id$ // Copyright: (c) Jaakko Salli // Licence: wxWindows license ///////////////////////////////////////////////////////////////////////////// @@ -16,6 +16,8 @@ #pragma hdrstop #endif +#if wxUSE_PROPGRID + #ifndef WX_PRECOMP #include "wx/defs.h" #include "wx/object.h" @@ -38,7 +40,6 @@ #include "wx/stattext.h" #include "wx/scrolwin.h" #include "wx/dirdlg.h" - #include "wx/layout.h" #include "wx/sizer.h" #include "wx/textdlg.h" #include "wx/filedlg.h" @@ -51,26 +52,22 @@ // This define is necessary to prevent macro clearing #define __wxPG_SOURCE_FILE__ -#include -#include +#include "wx/propgrid/propgrid.h" +#include "wx/propgrid/editors.h" #if wxPG_USE_RENDERER_NATIVE - #include + #include "wx/renderer.h" #endif -#include +#include "wx/odcombo.h" #include "wx/timer.h" #include "wx/dcbuffer.h" -#include -#include #ifdef __WXMSW__ - #include + #include "wx/msw/private.h" #endif -#include - // Two pics for the expand / collapse buttons. // Files are not supplied with this project (since it is // recommended to use either custom or native rendering). @@ -93,16 +90,16 @@ //#define wxPG_TEXT_INDENT 4 // For the wxComboControl -#define wxPG_ALLOW_CLIPPING 1 // If 1, GetUpdateRegion() in OnPaint event handler is not ignored +//#define wxPG_ALLOW_CLIPPING 1 // If 1, GetUpdateRegion() in OnPaint event handler is not ignored #define wxPG_GUTTER_DIV 3 // gutter is max(iconwidth/gutter_div,gutter_min) #define wxPG_GUTTER_MIN 3 // gutter before and after image of [+] or [-] #define wxPG_YSPACING_MIN 1 #define wxPG_DEFAULT_VSPACING 2 // This matches .NET propertygrid's value, // but causes normal combobox to spill out under MSW -#define wxPG_OPTIMAL_WIDTH 200 // Arbitrary +//#define wxPG_OPTIMAL_WIDTH 200 // Arbitrary -#define wxPG_MIN_SCROLLBAR_WIDTH 10 // Smallest scrollbar width on any platform +//#define wxPG_MIN_SCROLLBAR_WIDTH 10 // Smallest scrollbar width on any platform // Must be larger than largest control border // width * 2. @@ -112,7 +109,7 @@ //#define wxPG_NAT_CHOICE_BORDER_ANY 0 -#define wxPG_HIDER_BUTTON_HEIGHT 25 +//#define wxPG_HIDER_BUTTON_HEIGHT 25 #define wxPG_PIXELS_PER_UNIT m_lineHeight @@ -120,7 +117,7 @@ #define m_iconHeight m_iconWidth #endif -#define wxPG_TOOLTIP_DELAY 1000 +//#define wxPG_TOOLTIP_DELAY 1000 // ----------------------------------------------------------------------- @@ -135,22 +132,13 @@ void wxPropertyGrid::AutoGetTranslation ( bool ) { } // ----------------------------------------------------------------------- -const wxChar *wxPropertyGridNameStr = wxT("wxPropertyGrid"); +const char wxPropertyGridNameStr[] = "wxPropertyGrid"; // ----------------------------------------------------------------------- // Statics in one class for easy destruction. -// NB: We prefer to use wxModule, as it offers more consistent behavior -// across platforms. However, for those rare problem situations, we -// also need to offer option to use simpler approach. // ----------------------------------------------------------------------- -#ifndef wxPG_USE_WXMODULE - #define wxPG_USE_WXMODULE 1 -#endif - -#if wxPG_USE_WXMODULE - -#include +#include "wx/module.h" class wxPGGlobalVarsClassManager : public wxModule { @@ -163,21 +151,17 @@ public: IMPLEMENT_DYNAMIC_CLASS(wxPGGlobalVarsClassManager, wxModule) -#else // !wxPG_USE_WXMODULE -class wxPGGlobalVarsClassManager +// When wxPG is loaded dynamically after the application is already running +// then the built-in module system won't pick this one up. Add it manually. +void wxPGInitResourceModule() { -public: - wxPGGlobalVarsClassManager() {} - ~wxPGGlobalVarsClassManager() { delete wxPGGlobalVars; } -}; - -static wxPGGlobalVarsClassManager gs_pgGlobalVarsClassManager; - -#endif - + wxModule* module = new wxPGGlobalVarsClassManager; + module->Init(); + wxModule::RegisterModule(module); +} -wxPGGlobalVarsClass* wxPGGlobalVars = (wxPGGlobalVarsClass*) NULL; +wxPGGlobalVarsClass* wxPGGlobalVars = NULL; wxPGGlobalVarsClass::wxPGGlobalVarsClass() @@ -187,7 +171,7 @@ wxPGGlobalVarsClass::wxPGGlobalVarsClass() m_boolChoices.Add(_("False")); m_boolChoices.Add(_("True")); - m_fontFamilyChoices = (wxPGChoices*) NULL; + m_fontFamilyChoices = NULL; m_defaultRenderer = new wxPGDefaultRenderer(); @@ -199,38 +183,7 @@ wxPGGlobalVarsClass::wxPGGlobalVarsClass() wxVariant v; - v = (long)0; - wxVariantClassInfo_long = wxPGVariantDataGetClassInfo(v.GetData()); - - v = wxString(); - wxVariantClassInfo_string = wxPGVariantDataGetClassInfo(v.GetData()); - - v = (double)0.0; - wxVariantClassInfo_double = wxPGVariantDataGetClassInfo(v.GetData()); - - v = (bool)false; - wxVariantClassInfo_bool = wxPGVariantDataGetClassInfo(v.GetData()); - - v = wxArrayString(); - wxVariantClassInfo_arrstring = wxPGVariantDataGetClassInfo(v.GetData()); - - wxColour col; - wxVariant v2((wxObject*)&col); - wxVariantClassInfo_wxobject = wxPGVariantDataGetClassInfo(v2.GetData()); - - wxVariantList list; - v = wxVariant(list); - wxVariantClassInfo_list = wxPGVariantDataGetClassInfo(v.GetData()); - - v << *wxRED; - wxVariantClassInfo_wxColour = wxPGVariantDataGetClassInfo(v.GetData()); - -#if wxUSE_DATETIME - v = wxVariant(wxDateTime::Now()); - wxVariantClassInfo_datetime = wxPGVariantDataGetClassInfo(v.GetData()); -#endif - - // Prepare some shared variants + // Prepare some shared variants m_vEmptyString = wxString(); m_vZero = (long) 0; m_vMinusOne = (long) -1; @@ -238,14 +191,17 @@ wxPGGlobalVarsClass::wxPGGlobalVarsClass() m_vFalse = false; // Prepare cached string constants + m_strstring = wxS("string"); + m_strlong = wxS("long"); + m_strbool = wxS("bool"); + m_strlist = wxS("list"); + m_strDefaultValue = wxS("DefaultValue"); m_strMin = wxS("Min"); m_strMax = wxS("Max"); m_strUnits = wxS("Units"); m_strInlineHelp = wxS("InlineHelp"); -#ifdef __WXDEBUG__ m_warnings = 0; -#endif } @@ -277,130 +233,10 @@ wxPGGlobalVarsClass::~wxPGGlobalVarsClass() delete wxPGProperty::sm_wxPG_LABEL; } -// ----------------------------------------------------------------------- -// wxPGBrush -// ----------------------------------------------------------------------- - -// -// This class is a wxBrush derivative used in the background colour -// brush cache. It adds wxPG-type colour-in-long to the class. -// JMS: Yes I know wxBrush doesn't actually hold the value (refcounted -// object does), but this is simpler implementation and equally -// effective. -// - -class wxPGBrush : public wxBrush -{ -public: - wxPGBrush( const wxColour& colour ); - wxPGBrush(); - virtual ~wxPGBrush() { } - void SetColour2( const wxColour& colour ); - inline long GetColourAsLong() const { return m_colAsLong; } -private: - long m_colAsLong; -}; - - -void wxPGBrush::SetColour2( const wxColour& colour ) -{ - wxBrush::SetColour(colour); - m_colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue()); -} - - -wxPGBrush::wxPGBrush() : wxBrush() -{ - m_colAsLong = 0; -} - - -wxPGBrush::wxPGBrush( const wxColour& colour ) : wxBrush(colour) -{ - m_colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue()); -} - - -// ----------------------------------------------------------------------- -// wxPGColour -// ----------------------------------------------------------------------- - -// -// Same as wxPGBrush, but for wxColour instead. -// - -class wxPGColour : public wxColour -{ -public: - wxPGColour( const wxColour& colour ); - wxPGColour(); - virtual ~wxPGColour() { } - void SetColour2( const wxColour& colour ); - inline long GetColourAsLong() const { return m_colAsLong; } -private: - long m_colAsLong; -}; - - -void wxPGColour::SetColour2( const wxColour& colour ) -{ - *this = colour; - m_colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue()); -} - - -wxPGColour::wxPGColour() : wxColour() -{ - m_colAsLong = 0; -} - - -wxPGColour::wxPGColour( const wxColour& colour ) : wxColour(colour) +void wxPropertyGridInitGlobalsIfNeeded() { - m_colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue()); } - -// ----------------------------------------------------------------------- -// wxPGTLWHandler -// Intercepts Close-events sent to wxPropertyGrid's top-level parent, -// and tries to commit property value. -// ----------------------------------------------------------------------- - -class wxPGTLWHandler : public wxEvtHandler -{ -public: - - wxPGTLWHandler( wxPropertyGrid* pg ) - : wxEvtHandler() - { - m_pg = pg; - } - -protected: - - void OnClose( wxCloseEvent& event ) - { - // ClearSelection forces value validation/commit. - if ( event.CanVeto() && !m_pg->ClearSelection() ) - { - event.Veto(); - return; - } - - event.Skip(); - } - -private: - wxPropertyGrid* m_pg; - - DECLARE_EVENT_TABLE() -}; - -BEGIN_EVENT_TABLE(wxPGTLWHandler, wxEvtHandler) - EVT_CLOSE(wxPGTLWHandler::OnClose) -END_EVENT_TABLE() - // ----------------------------------------------------------------------- // wxPGCanvas // ----------------------------------------------------------------------- @@ -454,25 +290,21 @@ protected: pg->OnKey( event ); } - void OnKeyUp( wxKeyEvent& event ) - { - wxPropertyGrid* pg = wxStaticCast(GetParent(), wxPropertyGrid); - pg->OnKeyUp( event ); - } + void OnPaint( wxPaintEvent& event ); - void OnNavigationKey( wxNavigationKeyEvent& event ) - { - wxPropertyGrid* pg = wxStaticCast(GetParent(), wxPropertyGrid); - pg->OnNavigationKey( event ); - } + // Always be focussable, even with child windows + virtual void SetCanFocus(bool WXUNUSED(canFocus)) + { wxPanel::SetCanFocus(true); } - void OnPaint( wxPaintEvent& event ); private: DECLARE_EVENT_TABLE() + DECLARE_ABSTRACT_CLASS(wxPGCanvas) }; +IMPLEMENT_ABSTRACT_CLASS(wxPGCanvas,wxPanel) + BEGIN_EVENT_TABLE(wxPGCanvas, wxPanel) EVT_MOTION(wxPGCanvas::OnMouseMove) EVT_PAINT(wxPGCanvas::OnPaint) @@ -481,9 +313,6 @@ BEGIN_EVENT_TABLE(wxPGCanvas, wxPanel) EVT_RIGHT_UP(wxPGCanvas::OnMouseRightClick) EVT_LEFT_DCLICK(wxPGCanvas::OnMouseDoubleClick) EVT_KEY_DOWN(wxPGCanvas::OnKey) - EVT_KEY_UP(wxPGCanvas::OnKeyUp) - EVT_CHAR(wxPGCanvas::OnKey) - EVT_NAVIGATION_KEY(wxPGCanvas::OnNavigationKey) END_EVENT_TABLE() @@ -501,6 +330,12 @@ void wxPGCanvas::OnPaint( wxPaintEvent& WXUNUSED(event) ) // Update everything inside the box wxRect r = GetUpdateRegion().GetBox(); + // FIXME: This is just a workaround for a bug that causes splitters not + // to paint when other windows are being dragged over the grid. + wxRect fullRect = GetRect(); + r.x = fullRect.x; + r.width = fullRect.width; + // Repaint this rectangle pg->DrawItems( dc, r.y, r.y + r.height, &r ); @@ -527,7 +362,6 @@ BEGIN_EVENT_TABLE(wxPropertyGrid, wxScrolledWindow) EVT_CHILD_FOCUS(wxPropertyGrid::OnChildFocusEvent) EVT_SET_FOCUS(wxPropertyGrid::OnFocusEvent) EVT_KILL_FOCUS(wxPropertyGrid::OnFocusEvent) - EVT_TEXT_ENTER(wxPG_SUBID1,wxPropertyGrid::OnCustomEditorEvent) EVT_SYS_COLOUR_CHANGED(wxPropertyGrid::OnSysColourChanged) END_EVENT_TABLE() @@ -547,7 +381,7 @@ wxPropertyGrid::wxPropertyGrid( wxWindow *parent, const wxPoint& pos, const wxSize& size, long style, - const wxChar* name ) + const wxString& name ) : wxScrolledWindow() { Init1(); @@ -561,7 +395,7 @@ bool wxPropertyGrid::Create( wxWindow *parent, const wxPoint& pos, const wxSize& size, long style, - const wxChar* name ) + const wxString& name ) { if ( !(style&wxBORDER_MASK) ) @@ -569,18 +403,9 @@ bool wxPropertyGrid::Create( wxWindow *parent, style |= wxVSCROLL; -#ifdef __WXMSW__ - // This prevents crash under Win2K, but still - // enables keyboard navigation - if ( style & wxTAB_TRAVERSAL ) - { - style &= ~(wxTAB_TRAVERSAL); - style |= wxWANTS_CHARS; - } -#else - if ( style & wxTAB_TRAVERSAL ) - style |= wxWANTS_CHARS; -#endif + // Filter out wxTAB_TRAVERSAL - we will handle TABs manually + style &= ~(wxTAB_TRAVERSAL); + style |= wxWANTS_CHARS; wxScrolledWindow::Create(parent,id,pos,size,style,name); @@ -596,24 +421,19 @@ bool wxPropertyGrid::Create( wxWindow *parent, // void wxPropertyGrid::Init1() { -#if !wxPG_USE_WXMODULE - if ( !wxPGGlobalVars ) - wxPGGlobalVars = new wxPGGlobalVarsClass(); -#endif - // Register editor classes, if necessary. if ( wxPGGlobalVars->m_mapEditorClasses.empty() ) - RegisterDefaultEditors(); + wxPropertyGrid::RegisterDefaultEditors(); m_iFlags = 0; - m_pState = (wxPropertyGridPageState*) NULL; - m_wndEditor = m_wndEditor2 = (wxWindow*) NULL; - m_selected = (wxPGProperty*) NULL; + m_pState = NULL; + m_wndEditor = m_wndEditor2 = NULL; + m_selected = NULL; m_selColumn = -1; - m_propHover = (wxPGProperty*) NULL; + m_propHover = NULL; m_eventObject = this; - m_curFocused = (wxWindow*) NULL; - m_tlwHandler = NULL; + m_curFocused = NULL; + m_sortFunction = NULL; m_inDoPropertyChanged = 0; m_inCommitChangesFromEditor = 0; m_inDoSelectProperty = 0; @@ -630,12 +450,8 @@ void wxPropertyGrid::Init1() AddActionTrigger( wxPG_ACTION_EXPAND_PROPERTY, WXK_RIGHT); AddActionTrigger( wxPG_ACTION_COLLAPSE_PROPERTY, WXK_LEFT); AddActionTrigger( wxPG_ACTION_CANCEL_EDIT, WXK_ESCAPE ); - AddActionTrigger( wxPG_ACTION_CUT, 'X', wxMOD_CONTROL ); - AddActionTrigger( wxPG_ACTION_CUT, WXK_DELETE, wxMOD_SHIFT ); - AddActionTrigger( wxPG_ACTION_COPY, 'C', wxMOD_CONTROL); - AddActionTrigger( wxPG_ACTION_COPY, WXK_INSERT, wxMOD_CONTROL ); - AddActionTrigger( wxPG_ACTION_PASTE, 'V', wxMOD_CONTROL ); - AddActionTrigger( wxPG_ACTION_PASTE, WXK_INSERT, wxMOD_SHIFT ); + AddActionTrigger( wxPG_ACTION_PRESS_BUTTON, WXK_DOWN, wxMOD_ALT ); + AddActionTrigger( wxPG_ACTION_PRESS_BUTTON, WXK_F4 ); m_coloursCustomized = 0; m_frozen = 0; @@ -643,16 +459,14 @@ void wxPropertyGrid::Init1() m_canvas = NULL; #if wxPG_DOUBLE_BUFFER - m_doubleBuffer = (wxBitmap*) NULL; + m_doubleBuffer = NULL; #endif - m_windowsToDelete = NULL; - #ifndef wxPG_ICON_WIDTH - m_expandbmp = NULL; - m_collbmp = NULL; - m_iconWidth = 11; - m_iconHeight = 11; + m_expandbmp = NULL; + m_collbmp = NULL; + m_iconWidth = 11; + m_iconHeight = 11; #else m_iconWidth = wxPG_ICON_WIDTH; #endif @@ -666,10 +480,6 @@ void wxPropertyGrid::Init1() m_width = m_height = 0; - SetButtonShortcut(0); - - m_keyComboConsumed = 0; - m_commonValues.push_back(new wxPGCommonValue(_("Unspecified"), wxPGGlobalVars->m_defaultRenderer) ); m_cvUnspecified = 0; @@ -688,7 +498,7 @@ void wxPropertyGrid::Init2() #ifdef __WXMAC__ // Smaller controls on Mac SetWindowVariant(wxWINDOW_VARIANT_SMALL); -#endif +#endif // Now create state, if one didn't exist already // (wxPropertyGridManager might have created it for us). @@ -713,57 +523,47 @@ void wxPropertyGrid::Init2() #ifndef wxPG_ICON_WIDTH // create two bitmap nodes for drawing - m_expandbmp = new wxBitmap(expand_xpm); - m_collbmp = new wxBitmap(collapse_xpm); + m_expandbmp = new wxBitmap(expand_xpm); + m_collbmp = new wxBitmap(collapse_xpm); - // calculate average font height for bitmap centering + // calculate average font height for bitmap centering - m_iconWidth = m_expandbmp->GetWidth(); - m_iconHeight = m_expandbmp->GetHeight(); + m_iconWidth = m_expandbmp->GetWidth(); + m_iconHeight = m_expandbmp->GetHeight(); #endif m_curcursor = wxCURSOR_ARROW; m_cursorSizeWE = new wxCursor( wxCURSOR_SIZEWE ); - // adjust bitmap icon y position so they are centered + // adjust bitmap icon y position so they are centered m_vspacing = wxPG_DEFAULT_VSPACING; - if ( !m_font.Ok() ) - { - wxFont useFont = wxScrolledWindow::GetFont(); - wxScrolledWindow::SetOwnFont( useFont ); - } - else - // This should be otherwise called by SetOwnFont - CalculateFontAndBitmapStuff( wxPG_DEFAULT_VSPACING ); - - // Add base brush item - m_arrBgBrushes.Add((void*)new wxPGBrush()); + CalculateFontAndBitmapStuff( wxPG_DEFAULT_VSPACING ); - // Add base colour items - m_arrFgCols.Add((void*)new wxPGColour()); - m_arrFgCols.Add((void*)new wxPGColour()); + // Allocate cell datas indirectly by calling setter + m_propertyDefaultCell.SetBgCol(*wxBLACK); + m_categoryDefaultCell.SetBgCol(*wxBLACK); RegainColours(); // This helps with flicker SetBackgroundStyle( wxBG_STYLE_CUSTOM ); - // Hook the TLW - wxPGTLWHandler* handler = new wxPGTLWHandler(this); - m_tlp = ::wxGetTopLevelParent(this); - m_tlwHandler = handler; - m_tlp->PushEventHandler(handler); + // Hook the top-level parent + m_tlp = NULL; + m_tlpClosed = NULL; + m_tlpClosedTime = 0; + OnTLPChanging(::wxGetTopLevelParent(this)); - // set virtual size to this window size + // set virtual size to this window size wxSize wndsize = GetSize(); - SetVirtualSize(wndsize.GetWidth(), wndsize.GetWidth()); + SetVirtualSize(wndsize.GetWidth(), wndsize.GetWidth()); m_timeCreated = ::wxGetLocalTimeMillis(); m_canvas = new wxPGCanvas(); m_canvas->Create(this, 1, wxPoint(0, 0), GetClientSize(), - (GetWindowStyle() & wxTAB_TRAVERSAL) | wxWANTS_CHARS | wxCLIP_CHILDREN); + wxWANTS_CHARS | wxCLIP_CHILDREN); m_canvas->SetBackgroundStyle( wxBG_STYLE_CUSTOM ); m_iFlags |= wxPG_FL_INITIALIZED; @@ -790,24 +590,20 @@ wxPropertyGrid::~wxPropertyGrid() if ( m_iFlags & wxPG_FL_MOUSE_CAPTURED ) m_canvas->ReleaseMouse(); - wxPGTLWHandler* handler = (wxPGTLWHandler*) m_tlwHandler; - m_tlp->RemoveEventHandler(handler); - delete handler; + // Call with NULL to disconnect event handling + OnTLPChanging(NULL); -#ifdef __WXDEBUG__ - if ( IsEditorsValueModified() ) - ::wxMessageBox(wxS("Most recent change in property editor was lost!!!\n\n(if you don't want this to happen, close your frames and dialogs using Close(false).)"), - wxS("wxPropertyGrid Debug Warning") ); -#endif + wxASSERT_MSG( !IsEditorsValueModified(), + wxS("Most recent change in property editor was lost!!! ") + wxS("(if you don't want this to happen, close your frames ") + wxS("and dialogs using Close(false).)") ); #if wxPG_DOUBLE_BUFFER if ( m_doubleBuffer ) delete m_doubleBuffer; #endif - delete m_windowsToDelete; - - //m_selected = (wxPGProperty*) NULL; + //m_selected = NULL; if ( m_iFlags & wxPG_FL_CREATEDSTATE ) delete m_pState; @@ -815,22 +611,10 @@ wxPropertyGrid::~wxPropertyGrid() delete m_cursorSizeWE; #ifndef wxPG_ICON_WIDTH - delete m_expandbmp; - delete m_collbmp; + delete m_expandbmp; + delete m_collbmp; #endif - // Delete cached text colours. - for ( i=0; iSetToolTip( (wxToolTip*) NULL ); + m_canvas->SetToolTip( NULL ); } #endif } @@ -1007,28 +791,102 @@ void wxPropertyGrid::SetExtraStyle( long exStyle ) // returns the best acceptable minimal size wxSize wxPropertyGrid::DoGetBestSize() const { - int hei = 15; - if ( m_lineHeight > hei ) - hei = m_lineHeight; - wxSize sz = wxSize( 60, hei+40 ); + int lineHeight = wxMax(15, m_lineHeight); + // don't make the grid too tall (limit height to 10 items) but don't + // make it too small neither + int numLines = wxMin + ( + wxMax(m_pState->m_properties->GetChildCount(), 3), + 10 + ); + + const wxSize sz = wxSize(60, lineHeight*numLines + 40); CacheBestSize(sz); return sz; } +// ----------------------------------------------------------------------- + +void wxPropertyGrid::OnTLPChanging( wxWindow* newTLP ) +{ + wxLongLong currentTime = ::wxGetLocalTimeMillis(); + + // + // Parent changed so let's redetermine and re-hook the + // correct top-level window. + if ( m_tlp ) + { + m_tlp->Disconnect( wxEVT_CLOSE_WINDOW, + wxCloseEventHandler(wxPropertyGrid::OnTLPClose), + NULL, this ); + m_tlpClosed = m_tlp; + m_tlpClosedTime = currentTime; + } + + if ( newTLP ) + { + // Only accept new tlp if same one was not just dismissed. + if ( newTLP != m_tlpClosed || + m_tlpClosedTime+250 < currentTime ) + { + newTLP->Connect( wxEVT_CLOSE_WINDOW, + wxCloseEventHandler(wxPropertyGrid::OnTLPClose), + NULL, this ); + m_tlpClosed = NULL; + } + else + { + newTLP = NULL; + } + } + + m_tlp = newTLP; +} + +// ----------------------------------------------------------------------- + +void wxPropertyGrid::OnTLPClose( wxCloseEvent& event ) +{ + // ClearSelection forces value validation/commit. + if ( event.CanVeto() && !ClearSelection() ) + { + event.Veto(); + return; + } + + // Ok, it can close, set tlp pointer to NULL. Some other event + // handler can of course veto the close, but our OnIdle() should + // then be able to regain the tlp pointer. + OnTLPChanging(NULL); + + event.Skip(); +} + +// ----------------------------------------------------------------------- + +bool wxPropertyGrid::Reparent( wxWindowBase *newParent ) +{ + OnTLPChanging((wxWindow*)newParent); + + bool res = wxScrolledWindow::Reparent(newParent); + + return res; +} + // ----------------------------------------------------------------------- // wxPropertyGrid Font and Colour Methods // ----------------------------------------------------------------------- void wxPropertyGrid::CalculateFontAndBitmapStuff( int vspacing ) { - int x = 0, y = 0; + int x = 0, y = 0; m_captionFont = wxScrolledWindow::GetFont(); - GetTextExtent(wxS("jG"), &x, &y, 0, 0, &m_captionFont); + GetTextExtent(wxS("jG"), &x, &y, 0, 0, &m_captionFont); m_subgroup_extramargin = x + (x/2); - m_fontHeight = y; + m_fontHeight = y; #if wxPG_USE_RENDERER_NATIVE m_iconWidth = wxPG_ICON_WIDTH; @@ -1057,7 +915,7 @@ void wxPropertyGrid::CalculateFontAndBitmapStuff( int vspacing ) m_marginWidth = m_gutterWidth*2 + m_iconWidth; m_captionFont.SetWeight(wxBOLD); - GetTextExtent(wxS("jG"), &x, &y, 0, 0, &m_captionFont); + GetTextExtent(wxS("jG"), &x, &y, 0, 0, &m_captionFont); m_lineHeight = m_fontHeight+(2*m_spacingy)+1; @@ -1136,8 +994,6 @@ static int wxPGGetColAvg( const wxColour& col ) void wxPropertyGrid::RegainColours() { - wxColour def_bgcol = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ); - if ( !(m_coloursCustomized & 0x0002) ) { wxColour col = wxSystemSettings::GetColour( wxSYS_COLOUR_BTNFACE ); @@ -1152,6 +1008,7 @@ void wxPropertyGrid::RegainColours() m_colCapBack = wxPGAdjustColour(col,-colDec); else m_colCapBack = col; + m_categoryDefaultCell.GetData()->SetBgCol(m_colCapBack); } if ( !(m_coloursCustomized & 0x0001) ) @@ -1166,27 +1023,21 @@ void wxPropertyGrid::RegainColours() #endif wxColour capForeCol = wxPGAdjustColour(m_colCapBack,colDec,5000,5000,true); m_colCapFore = capForeCol; - - // Set the cached colour as well. - ((wxPGColour*)m_arrFgCols.Item(1))->SetColour2(capForeCol); + m_categoryDefaultCell.GetData()->SetFgCol(capForeCol); } if ( !(m_coloursCustomized & 0x0008) ) { wxColour bgCol = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW ); m_colPropBack = bgCol; - - // Set the cached brush as well. - ((wxPGBrush*)m_arrBgBrushes.Item(0))->SetColour2(bgCol); + m_propertyDefaultCell.GetData()->SetBgCol(bgCol); } if ( !(m_coloursCustomized & 0x0010) ) { wxColour fgCol = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ); m_colPropFore = fgCol; - - // Set the cached colour as well. - ((wxPGColour*)m_arrFgCols.Item(0))->SetColour2(fgCol); + m_propertyDefaultCell.GetData()->SetFgCol(fgCol); } if ( !(m_coloursCustomized & 0x0020) ) @@ -1220,39 +1071,16 @@ void wxPropertyGrid::ResetColours() bool wxPropertyGrid::SetFont( const wxFont& font ) { // Must disable active editor. - if ( m_selected ) - { - bool selRes = ClearSelection(); - wxPG_CHECK_MSG_DBG( selRes, - false, - wxT("failed to deselect a property (editor probably had invalid value)") ); - } + ClearSelection(false); - // TODO: Following code is disabled with wxMac because - // it is reported to fail. I (JMS) cannot debug it - // personally right now. -#if !defined(__WXMAC__) bool res = wxScrolledWindow::SetFont( font ); - if ( res ) + if ( res && GetParent()) // may not have been Create()ed yet { CalculateFontAndBitmapStuff( m_vspacing ); - - if ( m_pState ) - m_pState->CalculateFontAndBitmapStuff(m_vspacing); - Refresh(); } return res; -#else - // ** wxMAC Only ** - // TODO: Remove after SetFont crash fixed. - if ( m_iFlags & wxPG_FL_INITIALIZED ) - { - wxLogDebug(wxT("WARNING: propGrid.cpp: wxPropertyGrid::SetFont has been disabled on wxMac since there has been crash reported in it. If you are willing to debug the cause, replace line '#if !defined(__WXMAC__)' with line '#if 1' in wxPropertyGrid::SetFont.")); - } - return false; -#endif } // ----------------------------------------------------------------------- @@ -1280,8 +1108,7 @@ void wxPropertyGrid::SetCellBackgroundColour( const wxColour& col ) m_colPropBack = col; m_coloursCustomized |= 0x08; - // Set the cached brush as well. - ((wxPGBrush*)m_arrBgBrushes.Item(0))->SetColour2(col); + m_propertyDefaultCell.GetData()->SetBgCol(col); Refresh(); } @@ -1293,8 +1120,7 @@ void wxPropertyGrid::SetCellTextColour( const wxColour& col ) m_colPropFore = col; m_coloursCustomized |= 0x10; - // Set the cached colour as well. - ((wxPGColour*)m_arrFgCols.Item(0))->SetColour2(col); + m_propertyDefaultCell.GetData()->SetFgCol(col); Refresh(); } @@ -1341,6 +1167,9 @@ void wxPropertyGrid::SetCaptionBackgroundColour( const wxColour& col ) { m_colCapBack = col; m_coloursCustomized |= 0x02; + + m_categoryDefaultCell.GetData()->SetBgCol(col); + Refresh(); } @@ -1351,283 +1180,104 @@ void wxPropertyGrid::SetCaptionTextColour( const wxColour& col ) m_colCapFore = col; m_coloursCustomized |= 0x04; - // Set the cached colour as well. - ((wxPGColour*)m_arrFgCols.Item(1))->SetColour2(col); + m_categoryDefaultCell.GetData()->SetFgCol(col); Refresh(); } +// ----------------------------------------------------------------------- +// wxPropertyGrid property adding and removal // ----------------------------------------------------------------------- -void wxPropertyGrid::SetBackgroundColourIndex( wxPGProperty* p, int index ) +void wxPropertyGrid::PrepareAfterItemsAdded() { - unsigned char ind = index; + if ( !m_pState || !m_pState->m_itemsAdded ) return; + + m_pState->m_itemsAdded = 0; - p->m_bgColIndex = ind; + if ( m_windowStyle & wxPG_AUTO_SORT ) + Sort(wxPG_SORT_TOP_LEVEL_ONLY); - unsigned int i; - for ( i=0; iGetChildCount(); i++ ) - SetBackgroundColourIndex(p->Item(i),index); + RecalculateVirtualSize(); } +// ----------------------------------------------------------------------- +// wxPropertyGrid property operations // ----------------------------------------------------------------------- -void wxPropertyGrid::SetPropertyBackgroundColour( wxPGPropArg id, const wxColour& colour ) +bool wxPropertyGrid::EnsureVisible( wxPGPropArg id ) { - wxPG_PROP_ARG_CALL_PROLOG() + wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) - size_t i; - int colInd = -1; + Update(); - long colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue()); + bool changed = false; - // As it is most likely that the previous colour is used, start comparison - // from the end. - for ( i=(m_arrBgBrushes.size()-1); i>0; i-- ) + // Is it inside collapsed section? + if ( !p->IsVisible() ) { - if ( ((wxPGBrush*)m_arrBgBrushes.Item(i))->GetColourAsLong() == colAsLong ) - { - colInd = i; - break; - } + // expand parents + wxPGProperty* parent = p->GetParent(); + wxPGProperty* grandparent = parent->GetParent(); + + if ( grandparent && grandparent != m_pState->m_properties ) + Expand( grandparent ); + + Expand( parent ); + changed = true; } - if ( colInd < 0 ) + // Need to scroll? + int vx, vy; + GetViewStart(&vx,&vy); + vy*=wxPG_PIXELS_PER_UNIT; + + int y = p->GetY(); + + if ( y < vy ) + { + Scroll(vx, y/wxPG_PIXELS_PER_UNIT ); + m_iFlags |= wxPG_FL_SCROLLED; + changed = true; + } + else if ( (y+m_lineHeight) > (vy+m_height) ) { - colInd = m_arrBgBrushes.size(); - wxCHECK_RET( colInd < 256, wxT("wxPropertyGrid: Warning - Only 255 different property background colours allowed.") ); - m_arrBgBrushes.Add( (void*)new wxPGBrush(colour) ); + Scroll(vx, (y-m_height+(m_lineHeight*2))/wxPG_PIXELS_PER_UNIT ); + m_iFlags |= wxPG_FL_SCROLLED; + changed = true; } - // Set indexes - SetBackgroundColourIndex(p,colInd); + if ( changed ) + DrawItems( p, p ); - // If this was on a visible grid, then draw it. - DrawItemAndChildren(p); + return changed; } +// ----------------------------------------------------------------------- +// wxPropertyGrid helper methods called by properties // ----------------------------------------------------------------------- -wxColour wxPropertyGrid::GetPropertyBackgroundColour( wxPGPropArg id ) const +// Control font changer helper. +void wxPropertyGrid::SetCurControlBoldFont() { - wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxColour()) - - return ((wxPGBrush*)m_arrBgBrushes.Item(p->m_bgColIndex))->GetColour(); + wxASSERT( m_wndEditor ); + m_wndEditor->SetFont( m_captionFont ); } // ----------------------------------------------------------------------- -void wxPropertyGrid::SetTextColourIndex( wxPGProperty* p, int index, int flags ) +wxPoint wxPropertyGrid::GetGoodEditorDialogPosition( wxPGProperty* p, + const wxSize& sz ) { - unsigned char ind = index; +#if wxPG_SMALL_SCREEN + // On small-screen devices, always show dialogs with default position and size. + return wxDefaultPosition; +#else + int splitterX = GetSplitterPosition(); + int x = splitterX; + int y = p->GetY(); - p->m_fgColIndex = ind; - - if ( p->GetChildCount() && (flags & wxPG_RECURSE) ) - { - unsigned int i; - for ( i=0; iGetChildCount(); i++ ) - SetTextColourIndex( p->Item(i), index, flags ); - } -} - -// ----------------------------------------------------------------------- - -int wxPropertyGrid::CacheColour( const wxColour& colour ) -{ - unsigned int i; - int colInd = -1; - - long colAsLong = wxPG_COLOUR(colour.Red(),colour.Green(),colour.Blue()); - - // As it is most likely that the previous colour is used, start comparison - // from the end. - for ( i=(m_arrFgCols.size()-1); i>0; i-- ) - { - if ( ((wxPGColour*)m_arrFgCols.Item(i))->GetColourAsLong() == colAsLong ) - { - colInd = i; - break; - } - } - - if ( colInd < 0 ) - { - colInd = m_arrFgCols.size(); - wxCHECK_MSG( colInd < 256, 0, wxT("wxPropertyGrid: Warning - Only 255 different property foreground colours allowed.") ); - m_arrFgCols.Add( (void*)new wxPGColour(colour) ); - } - - return colInd; -} - -// ----------------------------------------------------------------------- - -void wxPropertyGrid::SetPropertyTextColour( wxPGPropArg id, const wxColour& colour, - bool recursively ) -{ - wxPG_PROP_ARG_CALL_PROLOG() - - if ( p->IsCategory() ) - { - wxPropertyCategory* cat = (wxPropertyCategory*) p; - cat->SetTextColIndex(CacheColour(colour)); - } - - // Set indexes - int flags = 0; - if ( recursively ) - flags |= wxPG_RECURSE; - SetTextColourIndex(p, CacheColour(colour), flags); - - DrawItemAndChildren(p); -} - -// ----------------------------------------------------------------------- - -wxColour wxPropertyGrid::GetPropertyTextColour( wxPGPropArg id ) const -{ - wxPG_PROP_ARG_CALL_PROLOG_RETVAL(wxColour()) - - return wxColour(*((wxPGColour*)m_arrFgCols.Item(p->m_fgColIndex))); -} - -void wxPropertyGrid::SetPropertyColoursToDefault( wxPGPropArg id ) -{ - wxPG_PROP_ARG_CALL_PROLOG() - - SetBackgroundColourIndex( p, 0 ); - SetTextColourIndex( p, 0, wxPG_RECURSE ); - - if ( p->IsCategory() ) - { - wxPropertyCategory* cat = (wxPropertyCategory*) p; - cat->SetTextColIndex(1); - } -} - -// ----------------------------------------------------------------------- -// wxPropertyGrid property adding and removal -// ----------------------------------------------------------------------- - -void wxPropertyGrid::PrepareAfterItemsAdded() -{ - if ( !m_pState || !m_pState->m_itemsAdded ) return; - - m_pState->m_itemsAdded = 0; - - if ( m_windowStyle & wxPG_AUTO_SORT ) - Sort(); - - RecalculateVirtualSize(); -} - -// ----------------------------------------------------------------------- -// wxPropertyGrid property value setting and getting -// ----------------------------------------------------------------------- - -void wxPropertyGrid::DoSetPropertyValueUnspecified( wxPGProperty* p ) -{ - m_pState->DoSetPropertyValueUnspecified(p); - DrawItemAndChildren(p); - - wxPGProperty* parent = p->GetParent(); - while ( (parent->GetFlags() & wxPG_PROP_PARENTAL_FLAGS) == wxPG_PROP_MISC_PARENT ) - { - DrawItem(parent); - parent = parent->GetParent(); - } -} - -// ----------------------------------------------------------------------- -// wxPropertyGrid property operations -// ----------------------------------------------------------------------- - -void wxPropertyGrid::DoSetPropertyName( wxPGProperty* p, const wxString& newname ) -{ - wxCHECK_RET( p, wxT("invalid property id") ); - - if ( p->GetBaseName().Len() ) m_pState->m_dictName.erase( p->GetBaseName() ); - if ( newname.Len() ) m_pState->m_dictName[newname] = (void*) p; - - p->DoSetName(newname); -} - -// ----------------------------------------------------------------------- - -bool wxPropertyGrid::EnsureVisible( wxPGPropArg id ) -{ - wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false) - - Update(); - - bool changed = false; - - // Is it inside collapsed section? - if ( !p->IsVisible() ) - { - // expand parents - wxPGProperty* parent = p->GetParent(); - wxPGProperty* grandparent = parent->GetParent(); - - if ( grandparent && grandparent != m_pState->m_properties ) - Expand( grandparent ); - - Expand( parent ); - changed = true; - } - - // Need to scroll? - int vx, vy; - GetViewStart(&vx,&vy); - vy*=wxPG_PIXELS_PER_UNIT; - - int y = p->GetY(); - - if ( y < vy ) - { - Scroll(vx, y/wxPG_PIXELS_PER_UNIT ); - m_iFlags |= wxPG_FL_SCROLLED; - changed = true; - } - else if ( (y+m_lineHeight) > (vy+m_height) ) - { - Scroll(vx, (y-m_height+(m_lineHeight*2))/wxPG_PIXELS_PER_UNIT ); - m_iFlags |= wxPG_FL_SCROLLED; - changed = true; - } - - if ( changed ) - DrawItems( p, p ); - - return changed; -} - -// ----------------------------------------------------------------------- -// wxPropertyGrid helper methods called by properties -// ----------------------------------------------------------------------- - -// Control font changer helper. -void wxPropertyGrid::SetCurControlBoldFont() -{ - wxASSERT( m_wndEditor ); - m_wndEditor->SetFont( m_captionFont ); -} - -// ----------------------------------------------------------------------- - -wxPoint wxPropertyGrid::GetGoodEditorDialogPosition( wxPGProperty* p, - const wxSize& sz ) -{ -#if wxPG_SMALL_SCREEN - // On small-screen devices, always show dialogs with default position and size. - return wxDefaultPosition; -#else - int splitterX = GetSplitterPosition(); - int x = splitterX; - int y = p->GetY(); - - wxCHECK_MSG( y >= 0, wxPoint(-1,-1), wxT("invalid y?") ); + wxCHECK_MSG( y >= 0, wxPoint(-1,-1), wxT("invalid y?") ); ImprovedClientToScreen( &x, &y ); @@ -1671,7 +1321,7 @@ wxString& wxPropertyGrid::ExpandEscapeSequences( wxString& dst_str, wxString& sr dst_str.clear(); - for ( ; i != src_str.end(); i++ ) + for ( ; i != src_str.end(); ++i ) { wxUniChar a = *i; @@ -1729,7 +1379,7 @@ wxString& wxPropertyGrid::CreateEscapeSequences( wxString& dst_str, wxString& sr dst_str.clear(); - for ( ; i != src_str.end(); i++ ) + for ( ; i != src_str.end(); ++i ) { wxChar a = *i; @@ -1770,7 +1420,7 @@ wxPGProperty* wxPropertyGrid::DoGetItemAtY( int y ) const { // Outside? if ( y < 0 ) - return (wxPGProperty*) NULL; + return NULL; unsigned int a = 0; return m_pState->m_properties->GetItemAtY(y, m_lineHeight, &a); @@ -1922,7 +1572,7 @@ void wxPropertyGrid::DrawItems( wxDC& dc, if ( dcPtr ) { dc.SetClippingRegion( *clipRect ); - paintFinishY = DoDrawItems( *dcPtr, NULL, NULL, clipRect, isBuffered ); + paintFinishY = DoDrawItems( *dcPtr, clipRect, isBuffered ); } #if wxPG_DOUBLE_BUFFER @@ -1948,30 +1598,17 @@ void wxPropertyGrid::DrawItems( wxDC& dc, // ----------------------------------------------------------------------- int wxPropertyGrid::DoDrawItems( wxDC& dc, - const wxPGProperty* firstItem, - const wxPGProperty* lastItem, const wxRect* clipRect, bool isBuffered ) const { - // TODO: This should somehow be eliminated. - wxRect tempClipRect; - if ( !clipRect ) - { - wxASSERT(firstItem); - wxASSERT(lastItem); - tempClipRect = GetPropertyRect(firstItem, lastItem); - clipRect = &tempClipRect; - } + const wxPGProperty* firstItem; + const wxPGProperty* lastItem; - if ( !firstItem ) - firstItem = DoGetItemAtY(clipRect->y); + firstItem = DoGetItemAtY(clipRect->y); + lastItem = DoGetItemAtY(clipRect->y+clipRect->height-1); if ( !lastItem ) - { - lastItem = DoGetItemAtY(clipRect->y+clipRect->height-1); - if ( !lastItem ) - lastItem = GetLastItem( wxPG_ITERATE_VISIBLE ); - } + lastItem = GetLastItem( wxPG_ITERATE_VISIBLE ); if ( m_frozen || m_height < 1 || firstItem == NULL ) return clipRect->y; @@ -2030,13 +1667,10 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, // // clipRect conversion - if ( clipRect ) - { - cr2 = *clipRect; - cr2.x -= xRelMod; - cr2.y -= yRelMod; - clipRect = &cr2; - } + cr2 = *clipRect; + cr2.x -= xRelMod; + cr2.y -= yRelMod; + clipRect = &cr2; firstItemTopY -= yRelMod; lastItemBottomY -= yRelMod; } @@ -2046,9 +1680,9 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, int x = m_marginWidth - xRelMod; - const wxFont& normalfont = m_font; + wxFont normalFont = GetFont(); - bool reallyFocused = (m_iFlags & wxPG_FL_FOCUSED) ? true : false; + bool reallyFocused = (m_iFlags & wxPG_FL_FOCUSED) != 0; bool isEnabled = IsEnabled(); @@ -2083,7 +1717,7 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, // TODO: Only render columns that are within clipping region. - dc.SetFont(normalfont); + dc.SetFont(normalFont); wxPropertyGridConstIterator it( state, wxPG_ITERATE_VISIBLE, firstItem ); int endScanBottomY = lastItemBottomY + lh; @@ -2125,7 +1759,7 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, int rowHeight = m_fontHeight+(m_spacingy*2)+1; int textMarginHere = x; - int renderFlags = wxPGCellRenderer::Control; + int renderFlags = 0; int greyDepth = m_marginWidth; if ( !(windowStyle & wxPG_HIDE_CATEGORIES) ) @@ -2169,58 +1803,80 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, dc.DrawLine( greyDepthX, y2-1, gridWidth-xRelMod, y2-1 ); - if ( p == selected ) - { - renderFlags |= wxPGCellRenderer::Selected; -#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT - wasSelectedPainted = true; -#endif - } - - wxColour rowBgCol; + // + // Need to override row colours? wxColour rowFgCol; - wxBrush rowBgBrush; + wxColour rowBgCol; - if ( p->IsCategory() ) - { - if ( p->m_fgColIndex == 0 ) - rowFgCol = m_colCapFore; - else - rowFgCol = *(wxPGColour*)m_arrFgCols[p->m_fgColIndex]; - rowBgBrush = wxBrush(m_colCapBack); - } - else if ( p != selected ) + if ( p != selected ) { // Disabled may get different colour. if ( !p->IsEnabled() ) + { + renderFlags |= wxPGCellRenderer::Disabled | + wxPGCellRenderer::DontUseCellFgCol; rowFgCol = m_colDisPropFore; - else - rowFgCol = *(wxPGColour*)m_arrFgCols[p->m_fgColIndex]; - - rowBgBrush = *(wxPGBrush*)m_arrBgBrushes[p->m_bgColIndex]; + } } else { - // Selected gets different colour. - if ( reallyFocused ) - { - rowFgCol = m_colSelFore; - rowBgBrush = wxBrush(m_colSelBack); - } - else if ( isEnabled ) + renderFlags |= wxPGCellRenderer::Selected; + + if ( !p->IsCategory() ) { - rowFgCol = *(wxPGColour*)m_arrFgCols[p->m_fgColIndex]; - rowBgBrush = marginBrush; + renderFlags |= wxPGCellRenderer::DontUseCellFgCol | + wxPGCellRenderer::DontUseCellBgCol; + +#if wxPG_REFRESH_CONTROLS_AFTER_REPAINT + wasSelectedPainted = true; +#endif + + // Selected gets different colour. + if ( reallyFocused ) + { + rowFgCol = m_colSelFore; + rowBgCol = m_colSelBack; + } + else if ( isEnabled ) + { + rowFgCol = m_colPropFore; + rowBgCol = m_colMargin; + } + else + { + rowFgCol = m_colDisPropFore; + rowBgCol = m_colSelBack; + } } - else + } + + wxBrush rowBgBrush; + + if ( rowBgCol.IsOk() ) + rowBgBrush = wxBrush(rowBgCol); + + if ( HasInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL) ) + renderFlags = renderFlags & ~wxPGCellRenderer::DontUseCellColours; + + // + // Fill additional margin area with background colour of first cell + if ( greyDepthX < textMarginHere ) + { + if ( !(renderFlags & wxPGCellRenderer::DontUseCellBgCol) ) { - rowFgCol = m_colDisPropFore; - rowBgBrush = wxBrush(m_colSelBack); + wxPGCell& cell = p->GetCell(0); + rowBgCol = cell.GetBgCol(); + rowBgBrush = wxBrush(rowBgCol); } + dc.SetBrush(rowBgBrush); + dc.SetPen(rowBgCol); + dc.DrawRectangle(greyDepthX+1, y, + textMarginHere-greyDepthX, lh-1); } bool fontChanged = false; + // Expander button rectangle wxRect butRect( ((p->m_depth - 1) * m_subgroup_extramargin) - xRelMod, y, m_marginWidth, @@ -2228,18 +1884,22 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, if ( p->IsCategory() ) { - // Captions are all cells merged as one + // Captions have their cell areas merged as one dc.SetFont(m_captionFont); fontChanged = true; wxRect cellRect(greyDepthX, y, gridWidth - greyDepth + 2, rowHeight-1 ); - dc.SetBrush(rowBgBrush); - dc.SetPen(rowBgBrush.GetColour()); - dc.SetTextForeground(rowFgCol); + if ( renderFlags & wxPGCellRenderer::DontUseCellBgCol ) + { + dc.SetBrush(rowBgBrush); + dc.SetPen(rowBgCol); + } - dc.DrawRectangle(cellRect); + if ( renderFlags & wxPGCellRenderer::DontUseCellFgCol ) + { + dc.SetTextForeground(rowFgCol); + } - // Foreground wxPGCellRenderer* renderer = p->GetCellRenderer(0); renderer->Render( dc, cellRect, this, p, 0, -1, renderFlags ); @@ -2257,7 +1917,8 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, unsigned int ci; int cellX = x + 1; - int nextCellWidth = state->m_colWidths[0]; + int nextCellWidth = state->m_colWidths[0] - + (greyDepthX - m_marginWidth); wxRect cellRect(greyDepthX+1, y, 0, rowHeight-1); int textXAdd = textMarginHere - greyDepthX; @@ -2266,6 +1927,11 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, cellRect.width = nextCellWidth - 1; bool ctrlCell = false; + int cellRenderFlags = renderFlags; + + // Tree Item Button + if ( ci == 0 && !HasFlag(wxPG_HIDE_MARGIN) && p->HasVisibleChildren() ) + DrawExpanderButton( dc, butRect, p ); // Background if ( p == selected && m_wndEditor && ci == 1 ) @@ -2274,22 +1940,24 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, dc.SetBrush(editorBgCol); dc.SetPen(editorBgCol); dc.SetTextForeground(m_colPropFore); + dc.DrawRectangle(cellRect); if ( m_dragStatus == 0 && !(m_iFlags & wxPG_FL_CUR_USES_CUSTOM_IMAGE) ) ctrlCell = true; } else { - dc.SetBrush(rowBgBrush); - dc.SetPen(rowBgBrush.GetColour()); - dc.SetTextForeground(rowFgCol); - } - - dc.DrawRectangle(cellRect); + if ( renderFlags & wxPGCellRenderer::DontUseCellBgCol ) + { + dc.SetBrush(rowBgBrush); + dc.SetPen(rowBgCol); + } - // Tree Item Button - if ( ci == 0 && !HasFlag(wxPG_HIDE_MARGIN) && p->HasVisibleChildren() ) - DrawExpanderButton( dc, butRect, p ); + if ( renderFlags & wxPGCellRenderer::DontUseCellFgCol ) + { + dc.SetTextForeground(rowFgCol); + } + } dc.SetClippingRegion(cellRect); @@ -2304,26 +1972,28 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, if ( cmnVal == -1 || ci != 1 ) { renderer = p->GetCellRenderer(ci); - renderer->Render( dc, cellRect, this, p, ci, -1, renderFlags ); + renderer->Render( dc, cellRect, this, p, ci, -1, + cellRenderFlags ); } else { renderer = GetCommonValue(cmnVal)->GetRenderer(); - renderer->Render( dc, cellRect, this, p, ci, -1, renderFlags ); + renderer->Render( dc, cellRect, this, p, ci, -1, + cellRenderFlags ); } } cellX += state->m_colWidths[ci]; if ( ci < (state->m_colWidths.size()-1) ) nextCellWidth = state->m_colWidths[ci+1]; - cellRect.x = cellX; + cellRect.x = cellX; dc.DestroyClippingRegion(); // Is this really necessary? textXAdd = 0; } } if ( fontChanged ) - dc.SetFont(normalfont); + dc.SetFont(normalFont); y += rowHeight; } @@ -2351,7 +2021,7 @@ wxRect wxPropertyGrid::GetPropertyRect( const wxPGProperty* p1, const wxPGProper if ( m_width < 10 || m_height < 10 || !m_pState->m_properties->GetChildCount() || - p1 == (wxPGProperty*) NULL ) + p1 == NULL ) return wxRect(0,0,0,0); int vy = 0; @@ -2447,11 +2117,9 @@ void wxPropertyGrid::DrawItemAndChildren( wxPGProperty* p ) if ( m_pState->m_itemsAdded || m_frozen ) return; - wxWindow* wndPrimary = GetEditorControl(); - // Update child control. if ( m_selected && m_selected->GetParent() == p ) - m_selected->UpdateControl(wndPrimary); + RefreshEditor(); const wxPGProperty* lastDrawn = p->GetLastVisibleSubItem(); @@ -2483,13 +2151,6 @@ void wxPropertyGrid::Refresh( bool WXUNUSED(eraseBackground), void wxPropertyGrid::Clear() { - if ( m_selected ) - { - bool selRes = DoSelectProperty(NULL, wxPG_SEL_DELETING); // This must be before state clear - wxPG_CHECK_RET_DBG( selRes, - wxT("failed to deselect a property (editor probably had invalid value)") ); - } - m_pState->DoClear(); m_propHover = NULL; @@ -2507,8 +2168,7 @@ void wxPropertyGrid::Clear() bool wxPropertyGrid::EnableCategories( bool enable ) { - if ( !ClearSelection() ) - return false; + ClearSelection(false); if ( enable ) { @@ -2560,13 +2220,7 @@ void wxPropertyGrid::SwitchState( wxPropertyGridPageState* pNewState ) wxPGProperty* oldSelection = m_selected; - // Deselect - if ( m_selected ) - { - bool selRes = ClearSelection(); - wxPG_CHECK_RET_DBG( selRes, - wxT("failed to deselect a property (editor probably had invalid value)") ); - } + ClearSelection(false); m_pState->m_selected = oldSelection; @@ -2596,7 +2250,7 @@ void wxPropertyGrid::SwitchState( wxPropertyGridPageState* pNewState ) pNewState->OnClientWidthChange( pgWidth, pgWidth - pNewState->m_width ); } - m_propHover = (wxPGProperty*) NULL; + m_propHover = NULL; // If necessary, convert state to correct mode. if ( orig_mode != new_state_mode ) @@ -2607,8 +2261,7 @@ void wxPropertyGrid::SwitchState( wxPropertyGridPageState* pNewState ) else if ( !m_frozen ) { // Refresh, if not frozen. - if ( m_pState->m_itemsAdded ) - PrepareAfterItemsAdded(); + m_pState->PrepareAfterItemsAdded(); // Reselect if ( m_pState->m_selected ) @@ -2623,26 +2276,6 @@ void wxPropertyGrid::SwitchState( wxPropertyGridPageState* pNewState ) // ----------------------------------------------------------------------- -void wxPropertyGrid::SortChildren( wxPGPropArg id ) -{ - wxPG_PROP_ARG_CALL_PROLOG() - - m_pState->SortChildren( p ); -} - -// ----------------------------------------------------------------------- - -void wxPropertyGrid::Sort() -{ - bool selRes = ClearSelection(); // This must be before state clear - wxPG_CHECK_RET_DBG( selRes, - wxT("failed to deselect a property (editor probably had invalid value)") ); - - m_pState->Sort(); -} - -// ----------------------------------------------------------------------- - // Call to SetSplitterPosition will always disable splitter auto-centering // if parent window is shown. void wxPropertyGrid::DoSetSplitterPosition_( int newxpos, bool refresh, int splitterIndex, bool allPages ) @@ -2704,26 +2337,8 @@ wxPGProperty* wxPropertyGrid::GetNearestPaintVisible( wxPGProperty* p ) const } -// ----------------------------------------------------------------------- - -void wxPropertyGrid::SetButtonShortcut( int keycode, bool ctrlDown, bool altDown ) -{ - if ( keycode ) - { - m_pushButKeyCode = keycode; - m_pushButKeyCodeNeedsCtrl = ctrlDown ? 1 : 0; - m_pushButKeyCodeNeedsAlt = altDown ? 1 : 0; - } - else - { - m_pushButKeyCode = WXK_DOWN; - m_pushButKeyCodeNeedsCtrl = 0; - m_pushButKeyCodeNeedsAlt = 1; - } -} - -// ----------------------------------------------------------------------- -// Methods related to change in value, value modification and sending events +// ----------------------------------------------------------------------- +// Methods related to change in value, value modification and sending events // ----------------------------------------------------------------------- // commits any changes in editor of selected property @@ -2737,7 +2352,7 @@ bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags ) // Don't do this if already processing editor event. It might // induce recursive dialogs and crap like that. - if ( m_iFlags & wxPG_FL_IN_ONCUSTOMEDITOREVENT ) + if ( m_iFlags & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT ) { if ( m_inDoPropertyChanged ) return true; @@ -2817,7 +2432,8 @@ bool wxPropertyGrid::CommitChangesFromEditor( wxUint32 flags ) // ----------------------------------------------------------------------- -bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue ) +bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue, + int flags ) { // // Runs all validation functionality. @@ -2826,7 +2442,7 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue m_validationInfo.m_failureBehavior = m_permanentValidationFailureBehavior; - if ( !wxPGIsVariantType(pendingValue, list) ) + if ( pendingValue.GetType() == wxPG_VARIANT_TYPE_LIST ) { if ( !p->ValidateValue(pendingValue, m_validationInfo) ) return false; @@ -2849,13 +2465,13 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue wxVariant bcpPendingList; listValue = pendingValue; - listValue.SetName(p->GetLabel()); + listValue.SetName(p->GetBaseName()); while ( pwc && (pwc->HasFlag(wxPG_PROP_AGGREGATE) || pwc->HasFlag(wxPG_PROP_COMPOSED_VALUE)) ) { wxVariantList tempList; - wxVariant lv(tempList, pwc->GetLabel()); + wxVariant lv(tempList, pwc->GetBaseName()); lv.Append(listValue); listValue = lv; pPendingValue = &listValue; @@ -2873,7 +2489,7 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue wxVariant value; wxPGProperty* evtChangingProperty = changedProperty; - if ( !wxPGIsVariantType(*pPendingValue, list) ) + if ( pPendingValue->GetType() != wxPG_VARIANT_TYPE_LIST ) { value = *pPendingValue; } @@ -2886,33 +2502,37 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue wxVariant evtChangingValue = value; - // FIXME: After proper ValueToString()s added, remove - // this. It is just a temporary fix, as evt_changing - // will simply not work for wxPG_PROP_COMPOSED_VALUE - // (unless it is selected, and textctrl editor is open). - if ( changedProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) ) + if ( flags & SendEvtChanging ) { - evtChangingProperty = baseChangedProperty; - if ( evtChangingProperty != p ) - { - evtChangingProperty->AdaptListToValue( bcpPendingList, &evtChangingValue ); - } - else + // FIXME: After proper ValueToString()s added, remove + // this. It is just a temporary fix, as evt_changing + // will simply not work for wxPG_PROP_COMPOSED_VALUE + // (unless it is selected, and textctrl editor is open). + if ( changedProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) ) { - evtChangingValue = pendingValue; + evtChangingProperty = baseChangedProperty; + if ( evtChangingProperty != p ) + { + evtChangingProperty->AdaptListToValue( bcpPendingList, &evtChangingValue ); + } + else + { + evtChangingValue = pendingValue; + } } - } - if ( evtChangingProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) ) - { - if ( changedProperty == m_selected ) + if ( evtChangingProperty->HasFlag(wxPG_PROP_COMPOSED_VALUE) ) { - wxASSERT( m_wndEditor->IsKindOf(CLASSINFO(wxTextCtrl)) ); - evtChangingValue = ((wxTextCtrl*)m_wndEditor)->GetValue(); - } - else - { - wxLogDebug(wxT("WARNING: wxEVT_PG_CHANGING is about to happen with old value.")); + if ( changedProperty == m_selected ) + { + wxWindow* editor = GetEditorControl(); + wxASSERT( editor->IsKindOf(CLASSINFO(wxTextCtrl)) ); + evtChangingValue = wxStaticCast(editor, wxTextCtrl)->GetValue(); + } + else + { + wxLogDebug(wxT("WARNING: wxEVT_PG_CHANGING is about to happen with old value.")); + } } } @@ -2928,15 +2548,26 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue // If changedProperty is not property which value was edited, // then call wxPGProperty::ValidateValue() for that as well. - if ( p != changedProperty && !wxPGIsVariantType(value, list) ) + if ( p != changedProperty && value.GetType() != wxPG_VARIANT_TYPE_LIST ) { if ( !changedProperty->ValidateValue(value, m_validationInfo) ) return false; } - // SendEvent returns true if event was vetoed - if ( SendEvent( wxEVT_PG_CHANGING, evtChangingProperty, &evtChangingValue, 0 ) ) - return false; + if ( flags & SendEvtChanging ) + { + // SendEvent returns true if event was vetoed + if ( SendEvent( wxEVT_PG_CHANGING, evtChangingProperty, &evtChangingValue, 0 ) ) + return false; + } + + if ( flags & IsStandaloneValidation ) + { + // If called in 'generic' context, we need to reset + // m_chgInfo_changedProperty and write back translated value. + m_chgInfo_changedProperty = NULL; + pendingValue = value; + } return true; } @@ -2968,11 +2599,34 @@ void wxPropertyGrid::DoShowPropertyError( wxPGProperty* WXUNUSED(property), cons } #endif - ::wxMessageBox(msg, _T("Property Error")); + ::wxMessageBox(msg, wxT("Property Error")); } // ----------------------------------------------------------------------- +bool wxPropertyGrid::OnValidationFailure( wxPGProperty* property, + wxVariant& invalidValue ) +{ + wxWindow* editor = GetEditorControl(); + + // First call property's handler + property->OnValidationFailure(invalidValue); + + bool res = DoOnValidationFailure(property, invalidValue); + + // + // For non-wxTextCtrl editors, we do need to revert the value + if ( !editor->IsKindOf(CLASSINFO(wxTextCtrl)) && + property == m_selected ) + { + property->GetEditorClass()->UpdateControl(property, editor); + } + + property->SetFlag(wxPG_PROP_INVALID_VALUE); + + return res; +} + bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty* property, wxVariant& WXUNUSED(invalidValue) ) { int vfb = m_validationInfo.m_failureBehavior; @@ -2983,28 +2637,34 @@ bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty* property, wxVariant& W if ( (vfb & wxPG_VFB_MARK_CELL) && !property->HasFlag(wxPG_PROP_INVALID_VALUE) ) { - wxASSERT_MSG( !property->GetCell(0) && !property->GetCell(1), - wxT("Currently wxPG_VFB_MARK_CELL only works with properties with standard first two cells") ); + unsigned int colCount = m_pState->GetColumnCount(); + + // We need backup marked property's cells + m_propCellsBackup = property->m_cells; + + wxColour vfbFg = *wxWHITE; + wxColour vfbBg = *wxRED; - if ( !property->GetCell(0) && !property->GetCell(1) ) + property->EnsureCells(colCount); + + for ( unsigned int i=0; iSetCell(0, new wxPGCell(property->GetLabel(), wxNullBitmap, vfbFg, vfbBg)); - property->SetCell(1, new wxPGCell(property->GetDisplayedString(), wxNullBitmap, vfbFg, vfbBg)); + wxPGCell& cell = property->m_cells[i]; + cell.SetFgCol(vfbFg); + cell.SetBgCol(vfbBg); + } - DrawItemAndChildren(property); + DrawItemAndChildren(property); - if ( property == m_selected ) - { - SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL); + if ( property == m_selected ) + { + SetInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL); - wxWindow* editor = GetEditorControl(); - if ( editor ) - { - editor->SetForegroundColour(vfbFg); - editor->SetBackgroundColour(vfbBg); - } + wxWindow* editor = GetEditorControl(); + if ( editor ) + { + editor->SetForegroundColour(vfbFg); + editor->SetBackgroundColour(vfbBg); } } } @@ -3014,7 +2674,7 @@ bool wxPropertyGrid::DoOnValidationFailure( wxPGProperty* property, wxVariant& W wxString msg = m_validationInfo.m_failureMessage; if ( !msg.length() ) - msg = _T("You have entered invalid value. Press ESC to cancel editing."); + msg = wxT("You have entered invalid value. Press ESC to cancel editing."); DoShowPropertyError(property, msg); } @@ -3030,8 +2690,8 @@ void wxPropertyGrid::DoOnValidationFailureReset( wxPGProperty* property ) if ( vfb & wxPG_VFB_MARK_CELL ) { - property->SetCell(0, NULL); - property->SetCell(1, NULL); + // Revert cells + property->m_cells = m_propCellsBackup; ClearInternalFlag(wxPG_FL_CELL_OVERRIDES_SEL); @@ -3076,7 +2736,7 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags ) topPaintedProperty = topPaintedProperty->GetParent(); } - changedProperty->SetValue(value, &m_chgInfo_valueList); + changedProperty->SetValue(value, &m_chgInfo_valueList, wxPG_SETVAL_BY_USER); // Set as Modified (not if dragging just began) if ( !(p->m_flags & wxPG_PROP_MODIFIED) ) @@ -3117,8 +2777,7 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags ) // control. if ( selFlags & wxPG_SEL_DIALOGVAL ) { - if ( editor ) - p->GetEditorClass()->UpdateControl(p, editor); + RefreshEditor(); } else { @@ -3174,96 +2833,56 @@ bool wxPropertyGrid::ChangePropertyValue( wxPGPropArg id, wxVariant newValue ) // ----------------------------------------------------------------------- -// Runs wxValidator for the selected property -bool wxPropertyGrid::DoEditorValidate() +wxVariant wxPropertyGrid::GetUncommittedPropertyValue() { -#if wxUSE_VALIDATORS - // With traditional validator style, we dont need to more - if ( !(GetExtraStyle() & wxPG_EX_LEGACY_VALIDATORS) ) - return true; + wxPGProperty* prop = GetSelectedProperty(); - if ( m_iFlags & wxPG_FL_VALIDATION_FAILED ) - { - return false; - } + if ( !prop ) + return wxNullVariant; - wxWindow* wnd = GetEditorControl(); + wxTextCtrl* tc = GetEditorTextCtrl(); + wxVariant value = prop->GetValue(); - wxValidator* validator = m_selected->GetValidator(); - if ( validator && wnd ) - { - // Use TextCtrl of ODComboBox instead - if ( wnd->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) ) - { - wnd = ((wxOwnerDrawnComboBox*)wnd)->GetTextCtrl(); + if ( !tc || !IsEditorsValueModified() ) + return value; - if ( !wnd ) - return true; - } + if ( !prop->StringToValue(value, tc->GetValue()) ) + return value; - validator->SetWindow(wnd); + if ( !PerformValidation(prop, value, IsStandaloneValidation) ) + return prop->GetValue(); - // Instead setting the flag after the failure, we set - // it before checking and then clear afterwards if things - // went fine. This trick is necessary since focus events - // may be triggered while in Validate. - m_iFlags |= wxPG_FL_VALIDATION_FAILED; - if ( !validator->Validate(this) ) - { - // If you dpm't want to display message multiple times per change, - // comment the following line. - m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED); - return false; - } - m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED); - } -#endif - return true; + return value; } // ----------------------------------------------------------------------- -bool wxPropertyGrid::ProcessEvent(wxEvent& event) +// Runs wxValidator for the selected property +bool wxPropertyGrid::DoEditorValidate() { - wxWindow* wnd = (wxWindow*) event.GetEventObject(); - if ( wnd && wnd->IsKindOf(CLASSINFO(wxWindow)) ) - { - wxWindow* parent = wnd->GetParent(); - - if ( parent && - (parent == m_canvas || - parent->GetParent() == m_canvas) ) - { - OnCustomEditorEvent((wxCommandEvent&)event); - return true; - } - } - return wxPanel::ProcessEvent(event); + return true; } // ----------------------------------------------------------------------- -// NB: It may really not be wxCommandEvent - must check if necessary -// (usually not). -void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) +void wxPropertyGrid::HandleCustomEditorEvent( wxEvent &event ) { wxPGProperty* selected = m_selected; - // // Somehow, event is handled after property has been deselected. // Possibly, but very rare. if ( !selected ) return; - if ( m_iFlags & wxPG_FL_IN_ONCUSTOMEDITOREVENT ) + if ( m_iFlags & wxPG_FL_IN_HANDLECUSTOMEDITOREVENT ) return; wxVariant pendingValue(selected->GetValueRef()); wxWindow* wnd = GetEditorControl(); + wxWindow* editorWnd = wxDynamicCast(event.GetEventObject(), wxWindow); int selFlags = 0; bool wasUnspecified = selected->IsValueUnspecified(); int usesAutoUnspecified = selected->UsesAutoUnspecified(); - bool valueIsPending = false; m_chgInfo_changedProperty = NULL; @@ -3285,7 +2904,7 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) m_prevTcValue = newTcValue; } - SetInternalFlag(wxPG_FL_IN_ONCUSTOMEDITOREVENT); + SetInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT); bool validationFailure = false; bool buttonWasHandled = false; @@ -3309,27 +2928,32 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) if ( !buttonWasHandled ) { - // First call editor class' event handler. - const wxPGEditor* editor = selected->GetEditorClass(); - - if ( editor->OnEvent( this, selected, wnd, event ) ) + if ( wnd || m_wndEditor2 ) { - // If changes, validate them - if ( DoEditorValidate() ) - { - if ( editor->GetValueFromControl( pendingValue, m_selected, wnd ) ) - valueIsPending = true; - } - else + // First call editor class' event handler. + const wxPGEditor* editor = selected->GetEditorClass(); + + if ( editor->OnEvent( this, selected, editorWnd, event ) ) { - validationFailure = true; + // If changes, validate them + if ( DoEditorValidate() ) + { + if ( editor->GetValueFromControl( pendingValue, + m_selected, + wnd ) ) + valueIsPending = true; + } + else + { + validationFailure = true; + } } } // Then the property's custom handler (must be always called, unless // validation failed). if ( !validationFailure ) - buttonWasHandled = selected->OnEvent( this, wnd, event ); + buttonWasHandled = selected->OnEvent( this, editorWnd, event ); } // SetValueInEvent(), as called in one of the functions referred above @@ -3345,7 +2969,7 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) if ( !PerformValidation(m_selected, pendingValue) ) validationFailure = true; - if ( validationFailure ) + if ( validationFailure) { OnValidationFailure(selected, pendingValue); } @@ -3355,11 +2979,25 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) DoPropertyChanged(selected, selFlags); EditorsValueWasNotModified(); + + // Regardless of editor type, unfocus editor on + // text-editing related enter press. + if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER ) + { + SetFocusOnCanvas(); + } } else { // No value after all + // Regardless of editor type, unfocus editor on + // text-editing related enter press. + if ( event.GetEventType() == wxEVT_COMMAND_TEXT_ENTER ) + { + SetFocusOnCanvas(); + } + // Let unhandled button click events go to the parent if ( !buttonWasHandled && event.GetEventType() == wxEVT_COMMAND_BUTTON_CLICKED ) { @@ -3368,7 +3006,7 @@ void wxPropertyGrid::OnCustomEditorEvent( wxCommandEvent &event ) } } - ClearInternalFlag(wxPG_FL_IN_ONCUSTOMEDITOREVENT); + ClearInternalFlag(wxPG_FL_IN_HANDLECUSTOMEDITOREVENT); } // ----------------------------------------------------------------------- @@ -3379,24 +3017,25 @@ wxRect wxPropertyGrid::GetEditorWidgetRect( wxPGProperty* p, int column ) const { int itemy = p->GetY2(m_lineHeight); int vy = 0; - int cust_img_space = 0; int splitterX = m_pState->DoGetSplitterPosition(column-1); int colEnd = splitterX + m_pState->m_colWidths[column]; + int imageOffset = 0; // TODO: If custom image detection changes from current, change this. - if ( m_iFlags & wxPG_FL_CUR_USES_CUSTOM_IMAGE /*p->m_flags & wxPG_PROP_CUSTOMIMAGE*/ ) + if ( m_iFlags & wxPG_FL_CUR_USES_CUSTOM_IMAGE ) { //m_iFlags |= wxPG_FL_CUR_USES_CUSTOM_IMAGE; - int imwid = p->OnMeasureImage().x; - if ( imwid < 1 ) imwid = wxPG_CUSTOM_IMAGE_WIDTH; - cust_img_space = imwid + wxCC_CUSTOM_IMAGE_MARGIN1 + wxCC_CUSTOM_IMAGE_MARGIN2; + int iw = p->OnMeasureImage().x; + if ( iw < 1 ) + iw = wxPG_CUSTOM_IMAGE_WIDTH; + imageOffset = p->GetImageOffset(iw); } return wxRect ( - splitterX+cust_img_space+wxPG_XBEFOREWIDGET+wxPG_CONTROL_MARGIN+1, + splitterX+imageOffset+wxPG_XBEFOREWIDGET+wxPG_CONTROL_MARGIN+1, itemy-vy, - colEnd-splitterX-wxPG_XBEFOREWIDGET-wxPG_CONTROL_MARGIN-cust_img_space-1, + colEnd-splitterX-wxPG_XBEFOREWIDGET-wxPG_CONTROL_MARGIN-imageOffset-1, m_lineHeight-1 ); } @@ -3422,7 +3061,7 @@ wxSize wxPropertyGrid::GetImageSize( wxPGProperty* p, int item ) const wxSize cis = p->OnMeasureImage(item); - int choiceCount = p->GetChoiceCount(); + int choiceCount = p->m_choices.GetCount(); int comVals = p->GetDisplayedCommonValueCount(); if ( item >= choiceCount && comVals > 0 ) { @@ -3493,56 +3132,111 @@ void wxPropertyGrid::CustomSetCursor( int type, bool override ) } // ----------------------------------------------------------------------- -// wxPropertyGrid property selection +// wxPropertyGrid property selection, editor creation // ----------------------------------------------------------------------- -#define CONNECT_CHILD(EVT,FUNCTYPE,FUNC) \ - wnd->Connect(id, EVT, \ - (wxObjectEventFunction) (wxEventFunction) \ - FUNCTYPE (&wxPropertyGrid::FUNC), \ - NULL, this ); - -// Setups event handling for child control -void wxPropertyGrid::SetupEventHandling( wxWindow* argWnd, int id ) +// +// This class forwards events from property editor controls to wxPropertyGrid. +class wxPropertyGridEditorEventForwarder : public wxEvtHandler { - wxWindow* wnd = argWnd; +public: + wxPropertyGridEditorEventForwarder( wxPropertyGrid* propGrid ) + : wxEvtHandler(), m_propGrid(propGrid) + { + } - if ( argWnd == m_wndEditor ) + virtual ~wxPropertyGridEditorEventForwarder() { - CONNECT_CHILD(wxEVT_MOTION,(wxMouseEventFunction),OnMouseMoveChild) - CONNECT_CHILD(wxEVT_LEFT_UP,(wxMouseEventFunction),OnMouseUpChild) - CONNECT_CHILD(wxEVT_LEFT_DOWN,(wxMouseEventFunction),OnMouseClickChild) - CONNECT_CHILD(wxEVT_RIGHT_UP,(wxMouseEventFunction),OnMouseRightClickChild) - CONNECT_CHILD(wxEVT_ENTER_WINDOW,(wxMouseEventFunction),OnMouseEntry) - CONNECT_CHILD(wxEVT_LEAVE_WINDOW,(wxMouseEventFunction),OnMouseEntry) } - else + +private: + bool ProcessEvent( wxEvent& event ) { - CONNECT_CHILD(wxEVT_NAVIGATION_KEY,(wxNavigationKeyEventFunction),OnNavigationKey) + // Always skip + event.Skip(); + + m_propGrid->HandleCustomEditorEvent(event); + + return wxEvtHandler::ProcessEvent(event); } - CONNECT_CHILD(wxEVT_KEY_DOWN,(wxCharEventFunction),OnChildKeyDown) - CONNECT_CHILD(wxEVT_KEY_UP,(wxCharEventFunction),OnChildKeyUp) - CONNECT_CHILD(wxEVT_KILL_FOCUS,(wxFocusEventFunction),OnFocusEvent) + + wxPropertyGrid* m_propGrid; +}; + +// Setups event handling for child control +void wxPropertyGrid::SetupChildEventHandling( wxWindow* argWnd ) +{ + wxWindowID id = argWnd->GetId(); + + if ( argWnd == m_wndEditor ) + { + argWnd->Connect(id, wxEVT_MOTION, + wxMouseEventHandler(wxPropertyGrid::OnMouseMoveChild), + NULL, this); + argWnd->Connect(id, wxEVT_LEFT_UP, + wxMouseEventHandler(wxPropertyGrid::OnMouseUpChild), + NULL, this); + argWnd->Connect(id, wxEVT_LEFT_DOWN, + wxMouseEventHandler(wxPropertyGrid::OnMouseClickChild), + NULL, this); + argWnd->Connect(id, wxEVT_RIGHT_UP, + wxMouseEventHandler(wxPropertyGrid::OnMouseRightClickChild), + NULL, this); + argWnd->Connect(id, wxEVT_ENTER_WINDOW, + wxMouseEventHandler(wxPropertyGrid::OnMouseEntry), + NULL, this); + argWnd->Connect(id, wxEVT_LEAVE_WINDOW, + wxMouseEventHandler(wxPropertyGrid::OnMouseEntry), + NULL, this); + } + + wxPropertyGridEditorEventForwarder* forwarder; + forwarder = new wxPropertyGridEditorEventForwarder(this); + argWnd->PushEventHandler(forwarder); + + argWnd->Connect(id, wxEVT_KEY_DOWN, + wxCharEventHandler(wxPropertyGrid::OnChildKeyDown), + NULL, this); } void wxPropertyGrid::FreeEditors() { - // Do not free editors immediately if processing events - if ( !m_windowsToDelete ) - m_windowsToDelete = new wxArrayPtrVoid; + // + // Return focus back to canvas from children (this is required at least for + // GTK+, which, unlike Windows, clears focus when control is destroyed + // instead of moving it to closest parent). + wxWindow* focus = wxWindow::FindFocus(); + if ( focus ) + { + wxWindow* parent = focus->GetParent(); + while ( parent ) + { + if ( parent == m_canvas ) + { + SetFocusOnCanvas(); + break; + } + parent = parent->GetParent(); + } + } + // Do not free editors immediately if processing events if ( m_wndEditor2 ) { - m_windowsToDelete->push_back(m_wndEditor2); + wxEvtHandler* handler = m_wndEditor2->PopEventHandler(false); m_wndEditor2->Hide(); - m_wndEditor2 = (wxWindow*) NULL; + wxPendingDelete.Append( handler ); + wxPendingDelete.Append( m_wndEditor2 ); + m_wndEditor2 = NULL; } if ( m_wndEditor ) { - m_windowsToDelete->push_back(m_wndEditor); + wxEvtHandler* handler = m_wndEditor->PopEventHandler(false); m_wndEditor->Hide(); - m_wndEditor = (wxWindow*) NULL; + wxPendingDelete.Append( handler ); + wxPendingDelete.Append( m_wndEditor ); + m_wndEditor = NULL; } } @@ -3551,10 +3245,14 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) { /* if (p) + { wxLogDebug(wxT("SelectProperty( %s (%s[%i]) )"),p->m_label.c_str(), p->m_parent->m_label.c_str(),p->GetIndexInParent()); + } else + { wxLogDebug(wxT("SelectProperty( NULL, -1 )")); + } */ if ( m_inDoSelectProperty ) @@ -3564,25 +3262,24 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) wxPGProperty* prev = m_selected; - // - // Delete windows pending for deletion - if ( m_windowsToDelete && !m_inDoPropertyChanged && m_windowsToDelete->size() ) - { - unsigned int i; - - for ( i=0; isize(); i++ ) - delete ((wxWindow*)((*m_windowsToDelete)[i])); - - m_windowsToDelete->clear(); - } - if ( !m_pState ) { m_inDoSelectProperty = 0; return false; } - // +/* + if (m_selected) + wxPrintf( "Selected %s\n", m_selected->GetClassInfo()->GetClassName() ); + else + wxPrintf( "None selected\n" ); + + if (p) + wxPrintf( "P = %s\n", p->GetClassInfo()->GetClassName() ); + else + wxPrintf( "P = NULL\n" ); +*/ + // If we are frozen, then just set the values. if ( m_frozen ) { @@ -3597,7 +3294,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) FreeEditors(); // Prevent any further selection measures in this call - p = (wxPGProperty*) NULL; + p = NULL; } else { @@ -3617,8 +3314,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) } else { - wxScrolledWindow::SetFocus(); - m_editorFocused = 0; + SetFocusOnCanvas(); } } @@ -3649,8 +3345,8 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) FreeEditors(); m_selColumn = -1; - m_selected = (wxPGProperty*) NULL; - m_pState->m_selected = (wxPGProperty*) NULL; + m_selected = NULL; + m_pState->m_selected = NULL; // We need to always fully refresh the grid here Refresh(false); @@ -3675,10 +3371,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) if ( p != prev ) m_iFlags &= ~(wxPG_FL_VALIDATION_FAILED); - wxASSERT( m_wndEditor == (wxWindow*) NULL ); - - // Do we need OnMeasureCalls? - wxSize imsz = p->OnMeasureImage(); + wxASSERT( m_wndEditor == NULL ); // // Only create editor for non-disabled non-caption @@ -3715,25 +3408,27 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) m_wndEditor = wndList.m_primary; m_wndEditor2 = wndList.m_secondary; + wxWindow* primaryCtrl = GetEditorControl(); + + // + // Essentially, primaryCtrl == m_wndEditor + // // NOTE: It is allowed for m_wndEditor to be NULL - in this case // value is drawn as normal, and m_wndEditor2 is assumed - // to be a right-aligned button that triggers a separate editor + // to be a right-aligned button that triggers a separate editorCtrl // window. if ( m_wndEditor ) { - wxASSERT_MSG( m_wndEditor->GetParent() == m_canvas, + wxASSERT_MSG( m_wndEditor->GetParent() == GetPanel(), wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") ); // Set validator, if any #if wxUSE_VALIDATORS - if ( !(GetExtraStyle() & wxPG_EX_LEGACY_VALIDATORS) ) - { - wxValidator* validator = p->GetValidator(); - if ( validator ) - m_wndEditor->SetValidator(*validator); - } + wxValidator* validator = p->GetValidator(); + if ( validator ) + primaryCtrl->SetValidator(*validator); #endif if ( m_wndEditor->GetSize().y > (m_lineHeight+6) ) @@ -3748,10 +3443,10 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) // Fix TextCtrl indentation #if defined(__WXMSW__) && !defined(__WXWINCE__) wxTextCtrl* tc = NULL; - if ( m_wndEditor->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) ) - tc = ((wxOwnerDrawnComboBox*)m_wndEditor)->GetTextCtrl(); + if ( primaryCtrl->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) ) + tc = ((wxOwnerDrawnComboBox*)primaryCtrl)->GetTextCtrl(); else - tc = wxDynamicCast(m_wndEditor, wxTextCtrl); + tc = wxDynamicCast(primaryCtrl, wxTextCtrl); if ( tc ) ::SendMessage(GetHwndOf(tc), EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0)); #endif @@ -3777,8 +3472,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) m_wndEditor->Move( goodPos ); #endif - wxWindow* primaryCtrl = GetEditorControl(); - SetupEventHandling(primaryCtrl, wxPG_SUBID1); + SetupChildEventHandling(primaryCtrl); // Focus and select all (wxTextCtrl, wxComboBox etc) if ( flags & wxPG_SEL_FOCUS ) @@ -3791,7 +3485,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) if ( m_wndEditor2 ) { - wxASSERT_MSG( m_wndEditor2->GetParent() == m_canvas, + wxASSERT_MSG( m_wndEditor2->GetParent() == GetPanel(), wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") ); // Get proper id for wndSecondary @@ -3818,7 +3512,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) #endif m_wndEditor2->Show(); - SetupEventHandling(m_wndEditor2,wxPG_SUBID2); + SetupChildEventHandling(m_wndEditor2); // If no primary editor, focus to button to allow // it to interprete ENTER etc. @@ -3836,8 +3530,8 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) } else { - // wxGTK atleast seems to need this (wxMSW not) - SetFocus(); + // Make sure focus is in grid canvas (important for wxGTK, at least) + SetFocusOnCanvas(); } EditorsValueWasNotModified(); @@ -3857,6 +3551,11 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) DrawItems(p, p); } + else + { + // Make sure focus is in grid canvas + SetFocusOnCanvas(); + } ClearInternalFlag(wxPG_FL_IN_SELECT_PROPERTY); } @@ -3871,7 +3570,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) if ( !(GetExtraStyle() & wxPG_EX_HELP_AS_TOOLTIPS) ) { - wxStatusBar* statusbar = (wxStatusBar*) NULL; + wxStatusBar* statusbar = NULL; if ( !(m_iFlags & wxPG_FL_NOSTATUSBARHELP) ) { wxFrame* frame = wxDynamicCast(::wxGetTopLevelParent(this),wxFrame); @@ -3924,7 +3623,7 @@ bool wxPropertyGrid::UnfocusEditor() if ( !CommitChangesFromEditor(0) ) return false; - m_canvas->SetFocusIgnoringChildren(); + SetFocusOnCanvas(); DrawItem(m_selected); return true; @@ -3932,11 +3631,41 @@ bool wxPropertyGrid::UnfocusEditor() // ----------------------------------------------------------------------- +void wxPropertyGrid::RefreshEditor() +{ + wxPGProperty* p = m_selected; + if ( !p ) + return; + + wxWindow* wnd = GetEditorControl(); + if ( !wnd ) + return; + + // Set editor font boldness - must do this before + // calling UpdateControl(). + if ( HasFlag(wxPG_BOLD_MODIFIED) ) + { + if ( p->HasFlag(wxPG_PROP_MODIFIED) ) + wnd->SetFont(GetCaptionFont()); + else + wnd->SetFont(GetFont()); + } + + const wxPGEditor* editorClass = p->GetEditorClass(); + + editorClass->UpdateControl(p, wnd); + + if ( p->IsValueUnspecified() ) + editorClass ->SetValueToUnspecified(p, wnd); +} + +// ----------------------------------------------------------------------- + // This method is not inline because it called dozens of times // (i.e. two-arg function calls create smaller code size). bool wxPropertyGrid::DoClearSelection() { - return DoSelectProperty((wxPGProperty*)NULL); + return DoSelectProperty(NULL); } // ----------------------------------------------------------------------- @@ -3948,10 +3677,9 @@ bool wxPropertyGrid::DoCollapse( wxPGProperty* p, bool sendEvents ) wxPGProperty* pwc = wxStaticCast(p, wxPGProperty); // If active editor was inside collapsed section, then disable it - if ( m_selected && m_selected->IsSomeParent (p) ) + if ( m_selected && m_selected->IsSomeParent(p) ) { - if ( !ClearSelection() ) - return false; + ClearSelection(false); } // Store dont-center-splitter flag 'cause we need to temporarily set it @@ -3979,7 +3707,7 @@ bool wxPropertyGrid::DoCollapse( wxPGProperty* p, bool sendEvents ) } // Clear dont-center-splitter flag if it wasn't set - m_iFlags = m_iFlags & ~(wxPG_FL_DONT_CENTER_SPLITTER) | old_flag; + m_iFlags = (m_iFlags & ~wxPG_FL_DONT_CENTER_SPLITTER) | old_flag; return res; } @@ -4020,7 +3748,7 @@ bool wxPropertyGrid::DoExpand( wxPGProperty* p, bool sendEvents ) } // Clear dont-center-splitter flag if it wasn't set - m_iFlags = m_iFlags & ~(wxPG_FL_DONT_CENTER_SPLITTER) | old_flag; + m_iFlags = (m_iFlags & ~wxPG_FL_DONT_CENTER_SPLITTER) | old_flag; return res; } @@ -4036,8 +3764,7 @@ bool wxPropertyGrid::DoHideProperty( wxPGProperty* p, bool hide, int flags ) ( m_selected == p || m_selected->IsSomeParent(p) ) ) { - if ( !ClearSelection() ) - return false; + ClearSelection(false); } m_pState->DoHideProperty(p, hide, flags); @@ -4065,17 +3792,10 @@ void wxPropertyGrid::RecalculateVirtualSize( int forceXPos ) m_pState->EnsureVirtualHeight(); -#ifdef __WXDEBUG__ - int by1 = m_pState->GetVirtualHeight(); - int by2 = m_pState->GetActualVirtualHeight(); - if ( by1 != by2 ) - { - wxString s = wxString::Format(wxT("VirtualHeight=%i, ActualVirtualHeight=%i, should match!"), by1, by2); - wxASSERT_MSG( false, - s.c_str() ); - wxLogDebug(s); - } -#endif + wxASSERT_LEVEL_2_MSG( + m_pState->GetVirtualHeight() == m_pState->GetActualVirtualHeight(), + "VirtualHeight and ActualVirtualHeight should match" + ); m_iFlags |= wxPG_FL_RECALCULATING_VIRTUAL_SIZE; @@ -4086,7 +3806,7 @@ void wxPropertyGrid::RecalculateVirtualSize( int forceXPos ) GetClientSize(&width,&height); // Now adjust virtual size. - SetVirtualSize(x, y); + SetVirtualSize(x, y); int xAmount = 0; int xPos = 0; @@ -4105,7 +3825,7 @@ void wxPropertyGrid::RecalculateVirtualSize( int forceXPos ) else if ( xPos > (xAmount-(width/wxPG_PIXELS_PER_UNIT)) ) xPos = 0; - int yAmount = (y+wxPG_PIXELS_PER_UNIT+2)/wxPG_PIXELS_PER_UNIT; + int yAmount = y / wxPG_PIXELS_PER_UNIT; int yPos = GetScrollPos( wxVERTICAL ); SetScrollbars( wxPG_PIXELS_PER_UNIT, wxPG_PIXELS_PER_UNIT, @@ -4209,6 +3929,12 @@ void wxPropertyGrid::SetVirtualWidth( int width ) m_pState->SetVirtualWidth( width ); } +void wxPropertyGrid::SetFocusOnCanvas() +{ + m_canvas->SetFocusIgnoringChildren(); + m_editorFocused = 0; +} + // ----------------------------------------------------------------------- // wxPropertyGrid mouse event handling // ----------------------------------------------------------------------- @@ -4245,7 +3971,7 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even // Need to set focus? if ( !(m_iFlags & wxPG_FL_FOCUSED) ) { - m_canvas->SetFocus(); + SetFocusOnCanvas(); } wxPropertyGridPageState* state = m_pState; @@ -4512,9 +4238,9 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxMouseEvent &event int curPropHoverY = y - (y % ih); // On which item it hovers - if ( ( !m_propHover ) + if ( !m_propHover || - ( m_propHover && ( sy < m_propHoverY || sy >= (m_propHoverY+ih) ) ) + ( sy < m_propHoverY || sy >= (m_propHoverY+ih) ) ) { // Mouse moves on another property @@ -4577,7 +4303,7 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxMouseEvent &event if ( space ) { int tw, th; - GetTextExtent( tipString, &tw, &th, 0, 0, &m_font ); + GetTextExtent( tipString, &tw, &th, 0, 0 ); if ( tw > space ) { SetToolTip( tipString ); @@ -4626,8 +4352,7 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxMouseEvent &event // (also not if we were dragging and its started // outside the splitter region) - if ( m_propHover && - !m_propHover->IsCategory() && + if ( !m_propHover->IsCategory() && !event.Dragging() ) { @@ -4728,19 +4453,19 @@ bool wxPropertyGrid::OnMouseCommon( wxMouseEvent& event, int* px, int* py ) int ux = event.m_x; int uy = event.m_y; - wxWindow* wnd = m_wndEditor; + wxWindow* wnd = GetEditorControl(); // Hide popup on clicks if ( event.GetEventType() != wxEVT_MOTION ) if ( wnd && wnd->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) ) { - ((wxOwnerDrawnComboBox*)m_wndEditor)->HidePopup(); + ((wxOwnerDrawnComboBox*)wnd)->HidePopup(); } wxRect r; if ( wnd ) r = wnd->GetRect(); - if ( wnd == (wxWindow*) NULL || m_dragStatus || + if ( wnd == NULL || m_dragStatus || ( ux <= (splitterX + wxPG_SPLITTERX_DETECTMARGIN2) || ux >= (r.x+r.width) || @@ -4883,8 +4608,6 @@ bool wxPropertyGrid::OnMouseChildCommon( wxMouseEvent &event, int* px, int *py ) int x, y; event.GetPosition(&x,&y); - AdjustPosForClipperWindow( topCtrlWnd, &x, &y ); - int splitterX = GetSplitterPosition(); wxRect r = topCtrlWnd->GetRect(); @@ -4953,17 +4676,6 @@ void wxPropertyGrid::OnMouseUpChild( wxMouseEvent &event ) // wxPropertyGrid keyboard event handling // ----------------------------------------------------------------------- -void wxPropertyGrid::SendNavigationKeyEvent( int dir ) -{ - wxNavigationKeyEvent evt; - evt.SetFlags(wxNavigationKeyEvent::FromTab| - (dir?wxNavigationKeyEvent::IsForward: - wxNavigationKeyEvent::IsBackward)); - evt.SetEventObject(this); - m_canvas->GetEventHandler()->AddPendingEvent(evt); -} - - int wxPropertyGrid::KeyEventToActions(wxKeyEvent &event, int* pSecond) const { // Translates wxKeyEvent to wxPG_ACTION_XXX @@ -5015,7 +4727,7 @@ void wxPropertyGrid::ClearActionTriggers( int action ) { wxPGHashMapI2I::iterator it; - for ( it = m_actionTriggers.begin(); it != m_actionTriggers.end(); it++ ) + for ( it = m_actionTriggers.begin(); it != m_actionTriggers.end(); ++it ) { if ( it->second == action ) { @@ -5024,33 +4736,67 @@ void wxPropertyGrid::ClearActionTriggers( int action ) } } -static void CopyTextToClipboard( const wxString& text ) -{ - if ( wxTheClipboard->Open() ) - { - // This data objects are held by the clipboard, - // so do not delete them in the app. - wxTheClipboard->SetData( new wxTextDataObject(text) ); - wxTheClipboard->Close(); - } -} - -void wxPropertyGrid::HandleKeyEvent(wxKeyEvent &event) +void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild ) { // // Handles key event when editor control is not focused. // - wxASSERT( !m_frozen ); - if ( m_frozen ) - return; + wxCHECK2(!m_frozen, return); // Travelsal between items, collapsing/expanding, etc. int keycode = event.GetKeyCode(); + bool editorFocused = IsEditorFocused(); if ( keycode == WXK_TAB ) { - SendNavigationKeyEvent( event.ShiftDown()?0:1 ); + wxWindow* mainControl; + + if ( HasInternalFlag(wxPG_FL_IN_MANAGER) ) + mainControl = GetParent(); + else + mainControl = this; + + if ( !event.ShiftDown() ) + { + if ( !editorFocused && m_wndEditor ) + { + DoSelectProperty( m_selected, wxPG_SEL_FOCUS ); + } + else + { + // Tab traversal workaround for platforms on which + // wxWindow::Navigate() may navigate into first child + // instead of next sibling. Does not work perfectly + // in every scenario (for instance, when property grid + // is either first or last control). + #if defined(__WXGTK__) + wxWindow* sibling = mainControl->GetNextSibling(); + if ( sibling ) + sibling->SetFocusFromKbd(); + #else + Navigate(wxNavigationKeyEvent::IsForward); + #endif + } + } + else + { + if ( editorFocused ) + { + UnfocusEditor(); + } + else + { + #if defined(__WXGTK__) + wxWindow* sibling = mainControl->GetPrevSibling(); + if ( sibling ) + sibling->SetFocusFromKbd(); + #else + Navigate(wxNavigationKeyEvent::IsBackward); + #endif + } + } + return; } @@ -5065,64 +4811,84 @@ void wxPropertyGrid::HandleKeyEvent(wxKeyEvent &event) int secondAction; int action = KeyEventToActions(event, &secondAction); - if ( m_selected ) + if ( editorFocused && action == wxPG_ACTION_CANCEL_EDIT ) + { + // + // Esc cancels any changes + if ( IsEditorsValueModified() ) + { + EditorsValueWasNotModified(); + + // Update the control as well + m_selected->GetEditorClass()->SetControlStringValue( m_selected, + GetEditorControl(), + m_selected->GetDisplayedString() ); + } + + OnValidationFailureReset(m_selected); + + UnfocusEditor(); + return; + } + + // Except for TAB and ESC, handle child control events in child control + if ( fromChild ) { + // Only propagate event if it had modifiers + if ( !event.HasModifiers() ) + { + event.StopPropagation(); + } + event.Skip(); + return; + } + bool wasHandled = false; + + if ( m_selected ) + { // Show dialog? - if ( ButtonTriggerKeyTest(event) ) + if ( ButtonTriggerKeyTest(action, event) ) return; wxPGProperty* p = m_selected; - if ( action == wxPG_ACTION_COPY ) - { - CopyTextToClipboard(p->GetDisplayedString()); - } - else - { - // Travel and expand/collapse - int selectDir = -2; + // Travel and expand/collapse + int selectDir = -2; - if ( p->GetChildCount() && - !(p->m_flags & wxPG_PROP_DISABLED) - ) + if ( p->GetChildCount() ) + { + if ( action == wxPG_ACTION_COLLAPSE_PROPERTY || secondAction == wxPG_ACTION_COLLAPSE_PROPERTY ) { - if ( action == wxPG_ACTION_COLLAPSE_PROPERTY || secondAction == wxPG_ACTION_COLLAPSE_PROPERTY ) - { - if ( (m_windowStyle & wxPG_HIDE_MARGIN) || Collapse(p) ) - keycode = 0; - } - else if ( action == wxPG_ACTION_EXPAND_PROPERTY || secondAction == wxPG_ACTION_EXPAND_PROPERTY ) - { - if ( (m_windowStyle & wxPG_HIDE_MARGIN) || Expand(p) ) - keycode = 0; - } + if ( (m_windowStyle & wxPG_HIDE_MARGIN) || Collapse(p) ) + wasHandled = true; } - - if ( keycode ) + else if ( action == wxPG_ACTION_EXPAND_PROPERTY || secondAction == wxPG_ACTION_EXPAND_PROPERTY ) { - if ( action == wxPG_ACTION_PREV_PROPERTY || secondAction == wxPG_ACTION_PREV_PROPERTY ) - { - selectDir = -1; - } - else if ( action == wxPG_ACTION_NEXT_PROPERTY || secondAction == wxPG_ACTION_NEXT_PROPERTY ) - { - selectDir = 1; - } - else - { - event.Skip(); - } - + if ( (m_windowStyle & wxPG_HIDE_MARGIN) || Expand(p) ) + wasHandled = true; } + } - if ( selectDir >= -1 ) + if ( !wasHandled ) + { + if ( action == wxPG_ACTION_PREV_PROPERTY || secondAction == wxPG_ACTION_PREV_PROPERTY ) + { + selectDir = -1; + } + else if ( action == wxPG_ACTION_NEXT_PROPERTY || secondAction == wxPG_ACTION_NEXT_PROPERTY ) { - p = wxPropertyGridIterator::OneStep( m_pState, wxPG_ITERATE_VISIBLE, p, selectDir ); - if ( p ) - DoSelectProperty(p); + selectDir = 1; } } + + if ( selectDir >= -1 ) + { + p = wxPropertyGridIterator::OneStep( m_pState, wxPG_ITERATE_VISIBLE, p, selectDir ); + if ( p ) + DoSelectProperty(p); + wasHandled = true; + } } else { @@ -5132,242 +4898,49 @@ void wxPropertyGrid::HandleKeyEvent(wxKeyEvent &event) { wxPGProperty* p = wxPropertyGridInterface::GetFirst(); if ( p ) DoSelectProperty(p); + wasHandled = true; } } -} - -// ----------------------------------------------------------------------- - -// Potentially handles a keyboard event for editor controls. -// Returns false if event should *not* be skipped (on true it can -// be optionally skipped). -// Basicly, false means that SelectProperty was called (or was about -// to be called, if canDestroy was false). -bool wxPropertyGrid::HandleChildKey( wxKeyEvent& event ) -{ - bool res = true; - - if ( !m_selected || !m_wndEditor ) - { - return true; - } - int action = KeyEventToAction(event); - - // Unfocus? - if ( action == wxPG_ACTION_CANCEL_EDIT ) - { - // - // Esc cancels any changes - if ( IsEditorsValueModified() ) - { - EditorsValueWasNotModified(); - - // Update the control as well - m_selected->GetEditorClass()->SetControlStringValue( m_selected, - m_wndEditor, - m_selected->GetDisplayedString() ); - } - - OnValidationFailureReset(m_selected); - - res = false; - - UnfocusEditor(); - } - else if ( action == wxPG_ACTION_COPY ) - { - // NB: There is some problem with getting native cut-copy-paste keys to go through - // for embedded editor wxTextCtrl. This is why we emulate. - // - wxTextCtrl* tc = GetEditorTextCtrl(); - if ( tc ) - { - wxString sel = tc->GetStringSelection(); - if ( sel.length() ) - CopyTextToClipboard(sel); - } - else - { - CopyTextToClipboard(m_selected->GetDisplayedString()); - } - } - else if ( action == wxPG_ACTION_CUT ) - { - wxTextCtrl* tc = GetEditorTextCtrl(); - if ( tc ) - { - long from, to; - tc->GetSelection(&from, &to); - if ( from < to ) - { - CopyTextToClipboard(tc->GetStringSelection()); - tc->Remove(from, to); - } - } - } - else if ( action == wxPG_ACTION_PASTE ) - { - wxTextCtrl* tc = GetEditorTextCtrl(); - if ( tc ) - { - if (wxTheClipboard->Open()) - { - if (wxTheClipboard->IsSupported( wxDF_TEXT )) - { - wxTextDataObject data; - wxTheClipboard->GetData( data ); - long from, to; - tc->GetSelection(&from, &to); - if ( from < to ) - { - tc->Remove(from, to); - tc->WriteText(data.GetText()); - } - else - { - tc->WriteText(data.GetText()); - } - } - wxTheClipboard->Close(); - } - } - } - - return res; + if ( !wasHandled ) + event.Skip(); } // ----------------------------------------------------------------------- void wxPropertyGrid::OnKey( wxKeyEvent &event ) { - - // - // Events to editor controls should get relayed here. - // - wxWindow* focused = wxWindow::FindFocus(); - - wxWindow* primaryCtrl = GetEditorControl(); - - if ( primaryCtrl && - (focused==primaryCtrl - || m_editorFocused) ) + // If there was editor open and focused, then this event should not + // really be processed here. + if ( IsEditorFocused() ) { - // Child key must be processed here, since it can - // destroy the control which is referred by its own - // event handling. - HandleChildKey( event ); + // However, if event had modifiers, it is probably still best + // to skip it. + if ( event.HasModifiers() ) + event.Skip(); + else + event.StopPropagation(); + return; } - else - HandleKeyEvent( event ); -} - -// ----------------------------------------------------------------------- - -void wxPropertyGrid::OnKeyUp(wxKeyEvent &event) -{ - m_keyComboConsumed = 0; - event.Skip(); + HandleKeyEvent(event, false); } // ----------------------------------------------------------------------- -void wxPropertyGrid::OnNavigationKey( wxNavigationKeyEvent& event ) +bool wxPropertyGrid::ButtonTriggerKeyTest( int action, wxKeyEvent& event ) { - // Ignore events that occur very close to focus set - if ( m_iFlags & wxPG_FL_IGNORE_NEXT_NAVKEY ) - { - m_iFlags &= ~(wxPG_FL_IGNORE_NEXT_NAVKEY); - event.Skip(); - return; - } - - wxPGProperty* next = (wxPGProperty*) NULL; - - int dir = event.GetDirection()?1:-1; - - if ( m_selected ) + if ( action == -1 ) { - if ( dir == 1 && (m_wndEditor || m_wndEditor2) ) - { - wxWindow* focused = wxWindow::FindFocus(); - - wxWindow* wndToCheck = GetEditorControl(); - - // ODComboBox focus goes to its text ctrl, so we need to use it instead - if ( wndToCheck && wndToCheck->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) ) - { - wxTextCtrl* comboTextCtrl = ((wxOwnerDrawnComboBox*)wndToCheck)->GetTextCtrl(); - if ( comboTextCtrl ) - wndToCheck = comboTextCtrl; - } - - /* - // Because of problems navigating from wxButton, do not go to it. - if ( !wndToCheck ) - { - // No primary, use secondary - wndToCheck = m_wndEditor2; - } - // If it has editor button, focus to it after the primary editor. - // NB: Doesn't work since wxButton on wxMSW doesn't seem to propagate - // key events (yes, I'm using wxWANTS_CHARS with it, and yes I - // have somewhat debugged in window.cpp itself). - else if ( focused == wndToCheck && - m_wndEditor2 && - !(GetExtraStyle() & wxPG_EX_NO_TAB_TO_BUTTON) ) - { - wndToCheck = m_wndEditor2; - wxLogDebug(wxT("Exp1")); - } - */ - - if ( focused != wndToCheck && - wndToCheck ) - { - wndToCheck->SetFocus(); - - // Select all text in wxTextCtrl etc. - if ( m_wndEditor && wndToCheck == m_wndEditor ) - m_selected->GetEditorClass()->OnFocus(m_selected,wndToCheck); - - m_editorFocused = 1; - next = m_selected; - } - } - - if ( !next ) - { - next = wxPropertyGridIterator::OneStep(m_pState, wxPG_ITERATE_VISIBLE, m_selected, dir); - - if ( next ) - { - // This allows preventing NavigateOut to occur - DoSelectProperty( next, wxPG_SEL_FOCUS ); - } - } + int secondAction; + action = KeyEventToActions(event, &secondAction); } - if ( !next ) - event.Skip(); -} - -// ----------------------------------------------------------------------- - -bool wxPropertyGrid::ButtonTriggerKeyTest( wxKeyEvent &event ) -{ - int keycode = event.GetKeyCode(); - // Does the keycode trigger button? - if ( keycode == m_pushButKeyCode && - m_wndEditor2 && - (!m_pushButKeyCodeNeedsAlt || event.AltDown()) && - (!m_pushButKeyCodeNeedsCtrl || event.ControlDown()) ) + if ( action == wxPG_ACTION_PRESS_BUTTON && + m_wndEditor2 ) { - m_keyComboConsumed = 1; - - wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED,m_wndEditor2->GetId()); + wxCommandEvent evt(wxEVT_COMMAND_BUTTON_CLICKED, m_wndEditor2->GetId()); GetEventHandler()->AddPendingEvent(evt); return true; } @@ -5379,32 +4952,7 @@ bool wxPropertyGrid::ButtonTriggerKeyTest( wxKeyEvent &event ) void wxPropertyGrid::OnChildKeyDown( wxKeyEvent &event ) { - int keycode = event.GetKeyCode(); - - // Ignore Alt and Control when they are down alone - if ( keycode == WXK_ALT || - keycode == WXK_CONTROL ) - { - event.Skip(); - return; - } - - if ( ButtonTriggerKeyTest(event) ) - return; - - if ( HandleChildKey(event) == true ) - event.Skip(); - - GetEventHandler()->AddPendingEvent(event); -} - -void wxPropertyGrid::OnChildKeyUp( wxKeyEvent &event ) -{ - m_keyComboConsumed = 0; - - GetEventHandler()->AddPendingEvent(event); - - event.Skip(); + HandleKeyEvent(event, true); } // ----------------------------------------------------------------------- @@ -5419,6 +4967,25 @@ void wxPropertyGrid::OnIdle( wxIdleEvent& WXUNUSED(event) ) if ( newFocused != m_curFocused ) HandleFocusChange( newFocused ); + + // + // Check if top-level parent has changed + wxWindow* tlp = ::wxGetTopLevelParent(this); + if ( tlp != m_tlp ) + { + OnTLPChanging(tlp); + } +} + +bool wxPropertyGrid::IsEditorFocused() const +{ + wxWindow* focus = wxWindow::FindFocus(); + + if ( focus == m_wndEditor || focus == m_wndEditor2 || + focus == GetEditorControl() ) + return true; + + return false; } // Called by focus event handlers. newFocused is the window that becomes focused. @@ -5448,13 +5015,8 @@ void wxPropertyGrid::HandleFocusChange( wxWindow* newFocused ) if ( (m_iFlags & wxPG_FL_FOCUSED) != (oldFlags & wxPG_FL_FOCUSED) ) { - // On each focus kill, mark the next nav key event - // to be ignored (can't do on set focus since the - // event would occur before it). if ( !(m_iFlags & wxPG_FL_FOCUSED) ) { - m_iFlags |= wxPG_FL_IGNORE_NEXT_NAVKEY; - // Need to store changed value CommitChangesFromEditor(); } @@ -5487,8 +5049,6 @@ void wxPropertyGrid::HandleFocusChange( wxWindow* newFocused ) } */ - - m_iFlags &= ~(wxPG_FL_IGNORE_NEXT_NAVKEY); } // Redraw selected @@ -5514,11 +5074,7 @@ void wxPropertyGrid::OnFocusEvent( wxFocusEvent& event ) void wxPropertyGrid::OnChildFocusEvent( wxChildFocusEvent& event ) { HandleFocusChange((wxWindow*)event.GetEventObject()); - - // - // event.Skip() being commented out is aworkaround for bug reported - // in ticket #4840 (wxScrolledWindow problem with automatic scrolling). - //event.Skip(); + event.Skip(); } // ----------------------------------------------------------------------- @@ -5545,20 +5101,46 @@ void wxPropertyGrid::OnCaptureChange( wxMouseCaptureChangedEvent& WXUNUSED(event // ----------------------------------------------------------------------- // noDefCheck = true prevents infinite recursion. -wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* editorclass, - const wxString& name, - bool noDefCheck ) +wxPGEditor* wxPropertyGrid::DoRegisterEditorClass( wxPGEditor* editorClass, + const wxString& editorName, + bool noDefCheck ) { - wxASSERT( editorclass ); + wxASSERT( editorClass ); if ( !noDefCheck && wxPGGlobalVars->m_mapEditorClasses.empty() ) RegisterDefaultEditors(); - wxPGGlobalVars->m_mapEditorClasses[name] = (void*)editorclass; + wxString name = editorName; + if ( name.length() == 0 ) + name = editorClass->GetName(); + + // Existing editor under this name? + wxPGHashMapS2P::iterator vt_it = wxPGGlobalVars->m_mapEditorClasses.find(name); + + if ( vt_it != wxPGGlobalVars->m_mapEditorClasses.end() ) + { + // If this name was already used, try class name. + name = editorClass->GetClassInfo()->GetClassName(); + vt_it = wxPGGlobalVars->m_mapEditorClasses.find(name); + } - return editorclass; + wxCHECK_MSG( vt_it == wxPGGlobalVars->m_mapEditorClasses.end(), + (wxPGEditor*) vt_it->second, + "Editor with given name was already registered" ); + + wxPGGlobalVars->m_mapEditorClasses[name] = (void*)editorClass; + + return editorClass; } +// Use this in RegisterDefaultEditors. +#define wxPGRegisterDefaultEditorClass(EDITOR) \ + if ( wxPGEditor_##EDITOR == NULL ) \ + { \ + wxPGEditor_##EDITOR = wxPropertyGrid::RegisterEditorClass( \ + new wxPG##EDITOR##Editor, true ); \ + } + // Registers all default editor classes void wxPropertyGrid::RegisterDefaultEditors() { @@ -5624,7 +5206,7 @@ bool wxPGStringTokenizer::HasMoreTokens() } else { - i++; + ++i; m_curPos = i; return true; } @@ -5636,7 +5218,7 @@ bool wxPGStringTokenizer::HasMoreTokens() prev_a = wxT('\0'); } } - i++; + ++i; } m_curPos = str.end(); @@ -5661,19 +5243,12 @@ wxPGChoiceEntry::wxPGChoiceEntry() { } -wxPGChoiceEntry::wxPGChoiceEntry( const wxPGChoiceEntry& entry ) - : wxPGCell( entry.GetText(), entry.GetBitmap(), - entry.GetFgCol(), entry.GetBgCol() ), m_value(entry.GetValue()) -{ -} - // ----------------------------------------------------------------------- // wxPGChoicesData // ----------------------------------------------------------------------- wxPGChoicesData::wxPGChoicesData() { - m_refCount = 1; } wxPGChoicesData::~wxPGChoicesData() @@ -5683,293 +5258,39 @@ wxPGChoicesData::~wxPGChoicesData() void wxPGChoicesData::Clear() { - unsigned int i; - - for ( i=0; iGetCount(); i++ ) - m_items.push_back( new wxPGChoiceEntry(*data->Item(i)) ); -} - -// ----------------------------------------------------------------------- -// wxPGChoices -// ----------------------------------------------------------------------- - -wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, int value ) -{ - EnsureData(); - - wxPGChoiceEntry* p = new wxPGChoiceEntry(label, value); - m_data->Insert( -1, p ); - return *p; -} - -// ----------------------------------------------------------------------- - -wxPGChoiceEntry& wxPGChoices::Add( const wxString& label, const wxBitmap& bitmap, int value ) -{ - EnsureData(); - - wxPGChoiceEntry* p = new wxPGChoiceEntry(label, value); - p->SetBitmap(bitmap); - m_data->Insert( -1, p ); - return *p; + m_items = data->m_items; } -// ----------------------------------------------------------------------- - -wxPGChoiceEntry& wxPGChoices::Insert( const wxPGChoiceEntry& entry, int index ) +wxPGChoiceEntry& wxPGChoicesData::Insert( int index, + const wxPGChoiceEntry& item ) { - EnsureData(); - - wxPGChoiceEntry* p = new wxPGChoiceEntry(entry); - m_data->Insert(index, p); - return *p; -} - -// ----------------------------------------------------------------------- - -wxPGChoiceEntry& wxPGChoices::Insert( const wxString& label, int index, int value ) -{ - EnsureData(); - - wxPGChoiceEntry* p = new wxPGChoiceEntry(label, value); - m_data->Insert( index, p ); - return *p; -} - -// ----------------------------------------------------------------------- - -wxPGChoiceEntry& wxPGChoices::AddAsSorted( const wxString& label, int value ) -{ - EnsureData(); - - size_t index = 0; - - while ( index < GetCount() ) - { - int cmpRes = GetLabel(index).Cmp(label); - if ( cmpRes > 0 ) - break; - index++; - } - - wxPGChoiceEntry* p = new wxPGChoiceEntry(label, value); - m_data->Insert( index, p ); - return *p; -} - -// ----------------------------------------------------------------------- - -void wxPGChoices::Add( const wxChar** labels, const ValArrItem* values ) -{ - EnsureData(); - - unsigned int itemcount = 0; - const wxChar** p = &labels[0]; - while ( *p ) { p++; itemcount++; } - - unsigned int i; - for ( i = 0; i < itemcount; i++ ) - { - int value = wxPG_INVALID_VALUE; - if ( values ) - value = values[i]; - m_data->Insert( -1, new wxPGChoiceEntry(labels[i], value) ); - } -} - -// ----------------------------------------------------------------------- - -void wxPGChoices::Add( const wxArrayString& arr, const ValArrItem* values ) -{ - EnsureData(); - - unsigned int i; - unsigned int itemcount = arr.size(); - - for ( i = 0; i < itemcount; i++ ) + wxVector::iterator it; + if ( index == -1 ) { - int value = wxPG_INVALID_VALUE; - if ( values ) - value = values[i]; - m_data->Insert( -1, new wxPGChoiceEntry(arr[i], value) ); + it = m_items.end(); + index = (int) m_items.size(); } -} - -// ----------------------------------------------------------------------- - -void wxPGChoices::Add( const wxArrayString& arr, const wxArrayInt& arrint ) -{ - EnsureData(); - - unsigned int i; - unsigned int itemcount = arr.size(); - - for ( i = 0; i < itemcount; i++ ) - { - int value = wxPG_INVALID_VALUE; - if ( &arrint && arrint.size() ) - value = arrint[i]; - m_data->Insert( -1, new wxPGChoiceEntry(arr[i], value) ); - } -} - -// ----------------------------------------------------------------------- - -void wxPGChoices::RemoveAt(size_t nIndex, size_t count) -{ - wxASSERT( m_data->m_refCount != 0xFFFFFFF ); - unsigned int i; - for ( i=nIndex; i<(nIndex+count); i++) - delete m_data->Item(i); - m_data->m_items.RemoveAt(nIndex, count); -} - -// ----------------------------------------------------------------------- - -int wxPGChoices::Index( const wxString& str ) const -{ - if ( IsOk() ) - { - unsigned int i; - for ( i=0; i< m_data->GetCount(); i++ ) - { - if ( m_data->Item(i)->GetText() == str ) - return i; - } - } - return -1; -} - -// ----------------------------------------------------------------------- - -int wxPGChoices::Index( int val ) const -{ - if ( IsOk() ) - { - unsigned int i; - for ( i=0; i< m_data->GetCount(); i++ ) - { - if ( m_data->Item(i)->GetValue() == val ) - return i; - } - } - return -1; -} - -// ----------------------------------------------------------------------- - -wxArrayString wxPGChoices::GetLabels() const -{ - wxArrayString arr; - unsigned int i; - - if ( this && IsOk() ) - for ( i=0; i= 0 ) - arr.Add(GetValue(index)); - else - arr.Add(wxPG_INVALID_VALUE); - } - } - - return arr; -} - -// ----------------------------------------------------------------------- - -wxArrayInt wxPGChoices::GetIndicesForStrings( const wxArrayString& strings, - wxArrayString* unmatched ) const -{ - wxArrayInt arr; - - if ( IsOk() ) - { - unsigned int i; - for ( i=0; i< strings.size(); i++ ) - { - const wxString& str = strings[i]; - int index = Index(str); - if ( index >= 0 ) - arr.Add(index); - else if ( unmatched ) - unmatched->Add(str); - } - } - - return arr; -} - -// ----------------------------------------------------------------------- - -void wxPGChoices::AssignData( wxPGChoicesData* data ) -{ - Free(); - - if ( data != wxPGChoicesEmptyData ) + else { - m_data = data; - data->m_refCount++; + it = m_items.begin() + index; } -} -// ----------------------------------------------------------------------- + m_items.insert(it, item); -void wxPGChoices::Init() -{ - m_data = wxPGChoicesEmptyData; -} + wxPGChoiceEntry& ownEntry = m_items[index]; -// ----------------------------------------------------------------------- + // Need to fix value? + if ( ownEntry.GetValue() == wxPG_INVALID_VALUE ) + ownEntry.SetValue(index); -void wxPGChoices::Free() -{ - if ( m_data != wxPGChoicesEmptyData ) - { - m_data->DecRef(); - m_data = wxPGChoicesEmptyData; - } + return ownEntry; } // ----------------------------------------------------------------------- @@ -5979,15 +5300,15 @@ void wxPGChoices::Free() IMPLEMENT_DYNAMIC_CLASS(wxPropertyGridEvent, wxCommandEvent) -DEFINE_EVENT_TYPE( wxEVT_PG_SELECTED ) -DEFINE_EVENT_TYPE( wxEVT_PG_CHANGING ) -DEFINE_EVENT_TYPE( wxEVT_PG_CHANGED ) -DEFINE_EVENT_TYPE( wxEVT_PG_HIGHLIGHTED ) -DEFINE_EVENT_TYPE( wxEVT_PG_RIGHT_CLICK ) -DEFINE_EVENT_TYPE( wxEVT_PG_PAGE_CHANGED ) -DEFINE_EVENT_TYPE( wxEVT_PG_ITEM_EXPANDED ) -DEFINE_EVENT_TYPE( wxEVT_PG_ITEM_COLLAPSED ) -DEFINE_EVENT_TYPE( wxEVT_PG_DOUBLE_CLICK ) +wxDEFINE_EVENT( wxEVT_PG_SELECTED, wxPropertyGridEvent ); +wxDEFINE_EVENT( wxEVT_PG_CHANGING, wxPropertyGridEvent ); +wxDEFINE_EVENT( wxEVT_PG_CHANGED, wxPropertyGridEvent ); +wxDEFINE_EVENT( wxEVT_PG_HIGHLIGHTED, wxPropertyGridEvent ); +wxDEFINE_EVENT( wxEVT_PG_RIGHT_CLICK, wxPropertyGridEvent ); +wxDEFINE_EVENT( wxEVT_PG_PAGE_CHANGED, wxPropertyGridEvent ); +wxDEFINE_EVENT( wxEVT_PG_ITEM_EXPANDED, wxPropertyGridEvent ); +wxDEFINE_EVENT( wxEVT_PG_ITEM_COLLAPSED, wxPropertyGridEvent ); +wxDEFINE_EVENT( wxEVT_PG_DOUBLE_CLICK, wxPropertyGridEvent ); // ----------------------------------------------------------------------- @@ -6035,11 +5356,6 @@ wxEvent* wxPropertyGridEvent::Clone() const return new wxPropertyGridEvent( *this ); } -void wxPropertyGrid::SetPropertyAttributeAll( const wxString& attrName, wxVariant value ) -{ - DoSetPropertyAttribute(GetRoot(), attrName, value, wxPG_RECURSE); -} - // ----------------------------------------------------------------------- // wxPropertyGridPopulator // ----------------------------------------------------------------------- @@ -6123,7 +5439,8 @@ wxPGProperty* wxPropertyGridPopulator::Add( const wxString& propClass, m_state->DoInsert(parent, -1, property); if ( propValue ) - property->SetValueFromString( *propValue, wxPG_FULL_VALUE ); + property->SetValueFromString( *propValue, wxPG_FULL_VALUE| + wxPG_PROGRAMMATIC_VALUE ); return property; } @@ -6176,7 +5493,7 @@ wxPGChoices wxPropertyGridPopulator::ParseChoices( const wxString& choicesString int state = 0; bool labelValid = false; - for ( ; it != choicesString.end(); it++ ) + for ( ; it != choicesString.end(); ++it ) { wxChar c = *it; @@ -6327,3 +5644,5 @@ void wxPropertyGridPopulator::ProcessError( const wxString& msg ) } // ----------------------------------------------------------------------- + +#endif // wxUSE_PROPGRID