#include "wx/timer.h"
#include "wx/dcbuffer.h"
-#include "wx/clipbrd.h"
-#include "wx/dataobj.h"
#ifdef __WXMSW__
#include "wx/msw/private.h"
IMPLEMENT_DYNAMIC_CLASS(wxPGGlobalVarsClassManager, wxModule)
+// 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()
+{
+ wxModule* module = new wxPGGlobalVarsClassManager;
+ module->Init();
+ wxModule::RegisterModule(module);
+}
+
wxPGGlobalVarsClass* wxPGGlobalVars = NULL;
wxVariant v;
- // Prepare some shared variants
+ // Prepare some shared variants
m_vEmptyString = wxString();
m_vZero = (long) 0;
m_vMinusOne = (long) -1;
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
}
{
}
-// -----------------------------------------------------------------------
-// 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
// -----------------------------------------------------------------------
m_propHover = NULL;
m_eventObject = this;
m_curFocused = NULL;
- m_tlwHandler = NULL;
m_sortFunction = NULL;
m_inDoPropertyChanged = 0;
m_inCommitChangesFromEditor = 0;
#endif
#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
#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;
CalculateFontAndBitmapStuff( wxPG_DEFAULT_VSPACING );
// 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();
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_cursorSizeWE;
#ifndef wxPG_ICON_WIDTH
- delete m_expandbmp;
- delete m_collbmp;
+ delete m_expandbmp;
+ delete m_collbmp;
#endif
// Delete common value records
// 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() && !DoClearSelection() )
+ {
+ 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;
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;
bool wxPropertyGrid::SetFont( const wxFont& font )
{
// Must disable active editor.
- ClearSelection(false);
+ DoClearSelection();
bool res = wxScrolledWindow::SetFont( font );
- if ( res )
+ if ( res && GetParent()) // may not have been Create()ed yet
{
CalculateFontAndBitmapStuff( m_vspacing );
Refresh();
bool wxPropertyGrid::EnableCategories( bool enable )
{
- ClearSelection(false);
+ DoClearSelection();
if ( enable )
{
wxPGProperty* oldSelection = m_selected;
- ClearSelection(false);
+ DoClearSelection();
m_pState->m_selected = oldSelection;
}
#endif
- ::wxMessageBox(msg, _T("Property Error"));
+ ::wxMessageBox(msg, wxT("Property Error"));
}
// -----------------------------------------------------------------------
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);
}
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;
if ( !buttonWasHandled )
{
- if ( wnd )
+ if ( wnd || m_wndEditor2 )
{
// First call editor class' event handler.
const wxPGEditor* editor = selected->GetEditorClass();
- if ( editor->OnEvent( this, selected, wnd, event ) )
+ if ( editor->OnEvent( this, selected, editorWnd, event ) )
{
// If changes, validate them
if ( DoEditorValidate() )
{
- if ( editor->GetValueFromControl( pendingValue, m_selected, wnd ) )
+ if ( editor->GetValueFromControl( pendingValue,
+ m_selected,
+ wnd ) )
valueIsPending = true;
}
else
// 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
{
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
);
}
{
/*
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 )
m_inDoSelectProperty = 0;
// call wx event handler (here so that it also occurs on deselection)
- SendEvent( wxEVT_PG_SELECTED, m_selected, NULL, flags );
+ if ( !(flags & wxPG_SEL_DONT_SEND_EVENT) )
+ SendEvent( wxEVT_PG_SELECTED, m_selected, NULL, flags );
return true;
}
// -----------------------------------------------------------------------
-// This method is not inline because it called dozens of times
-// (i.e. two-arg function calls create smaller code size).
+bool wxPropertyGrid::SelectProperty( wxPGPropArg id, bool focus )
+{
+ wxPG_PROP_ARG_CALL_PROLOG_RETVAL(false)
+
+ int flags = wxPG_SEL_DONT_SEND_EVENT;
+ if ( focus )
+ flags |= wxPG_SEL_FOCUS;
+
+ return DoSelectProperty(p, flags);
+}
+
+// -----------------------------------------------------------------------
+
bool wxPropertyGrid::DoClearSelection()
{
- return DoSelectProperty(NULL);
+ // Unlike ClearSelection(), here we send the wxEVT_PG_SELECTED event.
+ return DoSelectProperty(NULL, 0);
}
// -----------------------------------------------------------------------
// If active editor was inside collapsed section, then disable it
if ( m_selected && m_selected->IsSomeParent(p) )
{
- ClearSelection(false);
+ DoClearSelection();
}
// Store dont-center-splitter flag 'cause we need to temporarily set it
( m_selected == p || m_selected->IsSomeParent(p) )
)
{
- ClearSelection(false);
+ DoClearSelection();
}
m_pState->DoHideProperty(p, hide, flags);
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);
- wxFAIL_MSG(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;
GetClientSize(&width,&height);
// Now adjust virtual size.
- SetVirtualSize(x, y);
+ SetVirtualSize(x, y);
int xAmount = 0;
int xPos = 0;
if ( space )
{
int tw, th;
- GetTextExtent( tipString, &tw, &th, 0, 0 );
+ GetTextExtent( tipString, &tw, &th, 0, 0 );
if ( tw > space )
{
SetToolTip( tipString );
// 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 ( 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
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();
}
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
// noDefCheck = true prevents infinite recursion.
-wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* editorClass,
- bool noDefCheck )
+wxPGEditor* wxPropertyGrid::DoRegisterEditorClass( wxPGEditor* editorClass,
+ const wxString& editorName,
+ bool noDefCheck )
{
wxASSERT( editorClass );
if ( !noDefCheck && wxPGGlobalVars->m_mapEditorClasses.empty() )
RegisterDefaultEditors();
- wxString name = editorClass->GetName();
+ wxString name = editorName;
+ if ( name.length() == 0 )
+ name = editorClass->GetName();
// Existing editor under this name?
wxPGHashMapS2P::iterator vt_it = wxPGGlobalVars->m_mapEditorClasses.find(name);
wxPGChoicesData::wxPGChoicesData()
{
- m_refCount = 1;
}
wxPGChoicesData::~wxPGChoicesData()