// Author: Jaakko Salli
// Modified by:
// Created: 2004-09-25
-// RCS-ID: $Id:
+// RCS-ID: $Id$
// Copyright: (c) Jaakko Salli
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
#pragma hdrstop
#endif
+#if wxUSE_PROPGRID
+
#ifndef WX_PRECOMP
#include "wx/defs.h"
#include "wx/object.h"
#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"
// This define is necessary to prevent macro clearing
#define __wxPG_SOURCE_FILE__
-#include <wx/propgrid/propgrid.h>
-#include <wx/propgrid/editors.h>
+#include "wx/propgrid/propgrid.h"
+#include "wx/propgrid/editors.h"
#if wxPG_USE_RENDERER_NATIVE
- #include <wx/renderer.h>
+ #include "wx/renderer.h"
#endif
-#include <wx/odcombo.h>
+#include "wx/odcombo.h"
#include "wx/timer.h"
#include "wx/dcbuffer.h"
-#include <wx/clipbrd.h>
-#include <wx/dataobj.h>
+#include "wx/clipbrd.h"
+#include "wx/dataobj.h"
#ifdef __WXMSW__
- #include <wx/msw/private.h>
+ #include "wx/msw/private.h"
#endif
-#include <typeinfo>
-
// 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).
// -----------------------------------------------------------------------
// 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 <wx/module.h>
+#include "wx/module.h"
class wxPGGlobalVarsClassManager : public wxModule
{
IMPLEMENT_DYNAMIC_CLASS(wxPGGlobalVarsClassManager, wxModule)
-#else // !wxPG_USE_WXMODULE
-
-class wxPGGlobalVarsClassManager
-{
-public:
- wxPGGlobalVarsClassManager() {}
- ~wxPGGlobalVarsClassManager() { delete wxPGGlobalVars; }
-};
-
-static wxPGGlobalVarsClassManager gs_pgGlobalVarsClassManager;
-
-#endif
-
wxPGGlobalVarsClass* wxPGGlobalVars = (wxPGGlobalVarsClass*) NULL;
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
m_vEmptyString = wxString();
m_vZero = (long) 0;
m_vFalse = false;
// Prepare cached string constants
+ m_strstring = wxS("string");
+ m_strlong = wxS("long");
+ m_strbool = wxS("bool");
+ m_strlist = wxS("list");
m_strMin = wxS("Min");
m_strMax = wxS("Max");
m_strUnits = wxS("Units");
delete wxPGProperty::sm_wxPG_LABEL;
}
+void wxPropertyGridInitGlobalsIfNeeded()
+{
+}
+
// -----------------------------------------------------------------------
// wxPGBrush
// -----------------------------------------------------------------------
pg->OnKeyUp( event );
}
- void OnNavigationKey( wxNavigationKeyEvent& event )
- {
- wxPropertyGrid* pg = wxStaticCast(GetParent(), wxPropertyGrid);
- pg->OnNavigationKey( event );
- }
-
void OnPaint( wxPaintEvent& event );
+
+ // Always be focussable, even with child windows
+ virtual void SetCanFocus(bool WXUNUSED(canFocus))
+ { wxPanel::SetCanFocus(true); }
+
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)
EVT_KEY_DOWN(wxPGCanvas::OnKey)
EVT_KEY_UP(wxPGCanvas::OnKeyUp)
EVT_CHAR(wxPGCanvas::OnKey)
- EVT_NAVIGATION_KEY(wxPGCanvas::OnNavigationKey)
END_EVENT_TABLE()
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()
//
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;
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;
m_doubleBuffer = (wxBitmap*) NULL;
#endif
- m_windowsToDelete = NULL;
-
#ifndef wxPG_ICON_WIDTH
m_expandbmp = NULL;
m_collbmp = NULL;
m_width = m_height = 0;
- SetButtonShortcut(0);
-
- m_keyComboConsumed = 0;
-
m_commonValues.push_back(new wxPGCommonValue(_("Unspecified"), wxPGGlobalVars->m_defaultRenderer) );
m_cvUnspecified = 0;
delete m_doubleBuffer;
#endif
- delete m_windowsToDelete;
-
//m_selected = (wxPGProperty*) NULL;
if ( m_iFlags & wxPG_FL_CREATEDSTATE )
GetTextExtent(wxS("jG"), &x, &y, 0, 0, &m_captionFont);
m_lineHeight = m_fontHeight+(2*m_spacingy)+1;
- m_visPropArray.SetCount((m_height/m_lineHeight)+10);
// button spacing
m_buttonSpacingY = (m_lineHeight - m_iconHeight) / 2;
// TODO: Following code is disabled with wxMac because
// it is reported to fail. I (JMS) cannot debug it
// personally right now.
-#if !defined(__WXMAC__)
+ // CS: should be fixed now, leaving old code in just in case, TODO: REMOVE
+#if 1 // !defined(__WXMAC__)
bool res = wxScrolledWindow::SetFont( font );
if ( res )
{
DrawItemAndChildren(p);
wxPGProperty* parent = p->GetParent();
- while ( (parent->GetFlags() & wxPG_PROP_PARENTAL_FLAGS) == wxPG_PROP_MISC_PARENT )
+ while ( parent &&
+ (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)
wxPropertyGridConstIterator it( state, wxPG_ITERATE_VISIBLE, firstItem );
int endScanBottomY = lastItemBottomY + lh;
int y = firstItemTopY;
- unsigned int arrInd = 0;
+
+ //
+ // Pregenerate list of visible properties.
+ wxArrayPGProperty visPropArray;
+ visPropArray.reserve((m_height/m_lineHeight)+6);
for ( ; !it.AtEnd(); it.Next() )
{
if ( !p->HasFlag(wxPG_PROP_HIDDEN) )
{
- m_visPropArray[arrInd] = (wxPGProperty*)p;
- arrInd++;
+ visPropArray.push_back((wxPGProperty*)p);
if ( y > endScanBottomY )
break;
}
}
- m_visPropArray[arrInd] = NULL;
+ visPropArray.push_back(NULL);
+
+ wxPGProperty* nextP = visPropArray[0];
int gridWidth = state->m_width;
y = firstItemTopY;
- for ( arrInd=0;
- m_visPropArray[arrInd] != NULL && y <= lastItemBottomY;
+ for ( unsigned int arrInd=1;
+ nextP && y <= lastItemBottomY;
arrInd++ )
{
- wxPGProperty* p =(wxPGProperty*) m_visPropArray[arrInd];
- wxPGProperty* nextP = (wxPGProperty*) m_visPropArray[arrInd+1];
+ wxPGProperty* p = nextP;
+ nextP = visPropArray[arrInd];
int rowHeight = m_fontHeight+(m_spacingy*2)+1;
int textMarginHere = x;
}
-// -----------------------------------------------------------------------
-
-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
// -----------------------------------------------------------------------
// -----------------------------------------------------------------------
-bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue )
+bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue,
+ int flags )
{
//
// Runs all validation functionality.
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;
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;
wxVariant value;
wxPGProperty* evtChangingProperty = changedProperty;
- if ( !wxPGIsVariantType(*pPendingValue, list) )
+ if ( pPendingValue->GetType() != wxPG_VARIANT_TYPE_LIST )
{
value = *pPendingValue;
}
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."));
+ }
}
}
// 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;
}
if ( m_inDoPropertyChanged )
return true;
+ wxWindow* editor = GetEditorControl();
+
m_pState->m_anyModified = 1;
m_inDoPropertyChanged = 1;
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) )
p->m_flags |= wxPG_PROP_MODIFIED;
if ( p == m_selected && (m_windowStyle & wxPG_BOLD_MODIFIED) )
{
- if ( m_wndEditor )
+ if ( editor )
SetCurControlBoldFont();
}
}
if ( pwc == m_selected && (m_windowStyle & wxPG_BOLD_MODIFIED) )
{
- if ( m_wndEditor )
+ if ( editor )
SetCurControlBoldFont();
}
// control.
if ( selFlags & wxPG_SEL_DIALOGVAL )
{
- if ( m_wndEditor )
- p->GetEditorClass()->UpdateControl(p, m_wndEditor);
+ if ( editor )
+ p->GetEditorClass()->UpdateControl(p, editor);
}
else
{
// -----------------------------------------------------------------------
-// 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 value;
+}
+
+// -----------------------------------------------------------------------
+
+// Runs wxValidator for the selected property
+bool wxPropertyGrid::DoEditorValidate()
+{
return true;
}
{
wxPGProperty* selected = m_selected;
- //
// Somehow, event is handled after property has been deselected.
// Possibly, but very rare.
if ( !selected )
if ( !buttonWasHandled )
{
- // First call editor class' event handler.
- const wxPGEditor* editor = selected->GetEditorClass();
-
- if ( editor->OnEvent( this, selected, wnd, event ) )
+ if ( wnd )
{
- // 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, wnd, event ) )
{
- validationFailure = true;
+ // If changes, validate them
+ if ( DoEditorValidate() )
+ {
+ if ( editor->GetValueFromControl( pendingValue, m_selected, wnd ) )
+ valueIsPending = true;
+ }
+ else
+ {
+ validationFailure = true;
+ }
}
}
if ( !PerformValidation(m_selected, pendingValue) )
validationFailure = true;
- if ( validationFailure )
+ if ( validationFailure)
{
OnValidationFailure(selected, pendingValue);
}
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 )
wxSize cis = p->OnMeasureImage(item);
- int choiceCount = p->GetChoiceCount();
+ int choiceCount = p->m_choices.GetCount();
int comVals = p->GetDisplayedCommonValueCount();
if ( item >= choiceCount && comVals > 0 )
{
// wxPropertyGrid property selection
// -----------------------------------------------------------------------
-#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 )
+void wxPropertyGrid::SetupChildEventHandling( wxWindow* argWnd )
{
- wxWindow* wnd = argWnd;
+ wxWindowID id = argWnd->GetId();
if ( argWnd == m_wndEditor )
{
- 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)
+ 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);
+ argWnd->Connect(id, wxEVT_KEY_DOWN,
+ wxCharEventHandler(wxPropertyGrid::OnChildKeyDown),
+ NULL, this);
}
- else
- {
- CONNECT_CHILD(wxEVT_NAVIGATION_KEY,(wxNavigationKeyEventFunction),OnNavigationKey)
- }
- CONNECT_CHILD(wxEVT_KEY_DOWN,(wxCharEventFunction),OnChildKeyDown)
- CONNECT_CHILD(wxEVT_KEY_UP,(wxCharEventFunction),OnChildKeyUp)
- CONNECT_CHILD(wxEVT_KILL_FOCUS,(wxFocusEventFunction),OnFocusEvent)
}
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);
m_wndEditor2->Hide();
+ wxPendingDelete.Append( m_wndEditor2 );
m_wndEditor2 = (wxWindow*) NULL;
}
if ( m_wndEditor )
{
- m_windowsToDelete->push_back(m_wndEditor);
m_wndEditor->Hide();
+ wxPendingDelete.Append( m_wndEditor );
m_wndEditor = (wxWindow*) NULL;
}
}
// Call with NULL to de-select property
bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags )
{
+ wxPanel* canvas = GetPanel();
+
/*
if (p)
wxLogDebug(wxT("SelectProperty( %s (%s[%i]) )"),p->m_label.c_str(),
wxPGProperty* prev = m_selected;
- //
- // Delete windows pending for deletion
- if ( m_windowsToDelete && !m_inDoPropertyChanged && m_windowsToDelete->size() )
- {
- unsigned int i;
-
- for ( i=0; i<m_windowsToDelete->size(); 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 )
{
}
else
{
- wxScrolledWindow::SetFocus();
- m_editorFocused = 0;
+ SetFocusOnCanvas();
}
}
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() == canvas,
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) )
// 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
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 )
if ( m_wndEditor2 )
{
- wxASSERT_MSG( m_wndEditor2->GetParent() == m_canvas,
+ wxASSERT_MSG( m_wndEditor2->GetParent() == canvas,
wxT("CreateControls must use result of wxPropertyGrid::GetPanel() as parent of controls.") );
// Get proper id for wndSecondary
#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.
}
else
{
- // wxGTK atleast seems to need this (wxMSW not)
- SetFocus();
+ // Make sure focus is in grid canvas (important for wxGTK, at least)
+ SetFocusOnCanvas();
}
EditorsValueWasNotModified();
DrawItems(p, p);
}
+ else
+ {
+ // Make sure focus is in grid canvas
+ SetFocusOnCanvas();
+ }
ClearInternalFlag(wxPG_FL_IN_SELECT_PROPERTY);
}
if ( !CommitChangesFromEditor(0) )
return false;
- m_canvas->SetFocusIgnoringChildren();
+ SetFocusOnCanvas();
DrawItem(m_selected);
return true;
}
// 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;
}
m_width = width;
m_height = height;
- m_visPropArray.SetCount((height/m_lineHeight)+10);
-
#if wxPG_DOUBLE_BUFFER
if ( !(GetExtraStyle() & wxPG_EX_NATIVE_DOUBLE_BUFFERING) )
{
m_pState->SetVirtualWidth( width );
}
+void wxPropertyGrid::SetFocusOnCanvas()
+{
+ m_canvas->SetFocusIgnoringChildren();
+ m_editorFocused = 0;
+}
+
// -----------------------------------------------------------------------
// wxPropertyGrid mouse event handling
// -----------------------------------------------------------------------
// Need to set focus?
if ( !(m_iFlags & wxPG_FL_FOCUSED) )
{
- m_canvas->SetFocus();
+ SetFocusOnCanvas();
}
wxPropertyGridPageState* state = m_pState;
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;
int x, y;
event.GetPosition(&x,&y);
- AdjustPosForClipperWindow( topCtrlWnd, &x, &y );
-
int splitterX = GetSplitterPosition();
wxRect r = topCtrlWnd->GetRect();
// 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
}
}
-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)
{
//
if ( keycode == WXK_TAB )
{
- SendNavigationKeyEvent( event.ShiftDown()?0:1 );
+ if (m_selected)
+ DoSelectProperty( m_selected, wxPG_SEL_FOCUS );
return;
}
{
// Show dialog?
- if ( ButtonTriggerKeyTest(event) )
+ if ( ButtonTriggerKeyTest(action, event) )
return;
wxPGProperty* p = m_selected;
- if ( action == wxPG_ACTION_COPY )
+ // Travel and expand/collapse
+ int selectDir = -2;
+
+ if ( p->GetChildCount() &&
+ !(p->m_flags & wxPG_PROP_DISABLED)
+ )
{
- CopyTextToClipboard(p->GetDisplayedString());
+ 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;
+ }
}
- else
- {
- // Travel and expand/collapse
- int selectDir = -2;
- if ( p->GetChildCount() &&
- !(p->m_flags & wxPG_PROP_DISABLED)
- )
+ if ( keycode )
+ {
+ if ( action == wxPG_ACTION_PREV_PROPERTY || secondAction == wxPG_ACTION_PREV_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;
- }
+ selectDir = -1;
}
-
- if ( keycode )
+ else if ( action == wxPG_ACTION_NEXT_PROPERTY || secondAction == wxPG_ACTION_NEXT_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();
- }
-
+ selectDir = 1;
}
-
- if ( selectDir >= -1 )
+ else
{
- p = wxPropertyGridIterator::OneStep( m_pState, wxPG_ITERATE_VISIBLE, p, selectDir );
- if ( p )
- DoSelectProperty(p);
+ event.Skip();
}
+
+ }
+
+ if ( selectDir >= -1 )
+ {
+ p = wxPropertyGridIterator::OneStep( m_pState, wxPG_ITERATE_VISIBLE, p, selectDir );
+ if ( p )
+ DoSelectProperty(p);
}
}
else
// Update the control as well
m_selected->GetEditorClass()->SetControlStringValue( m_selected,
- m_wndEditor,
+ GetEditorControl(),
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;
}
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) )
- {
- // Child key must be processed here, since it can
- // destroy the control which is referred by its own
- // event handling.
- HandleChildKey( event );
- }
- else
- HandleKeyEvent( event );
+ HandleKeyEvent( event );
}
// -----------------------------------------------------------------------
void wxPropertyGrid::OnKeyUp(wxKeyEvent &event)
{
- m_keyComboConsumed = 0;
-
event.Skip();
}
// -----------------------------------------------------------------------
-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 )
+ if ( action == -1 )
{
- m_iFlags &= ~(wxPG_FL_IGNORE_NEXT_NAVKEY);
- event.Skip();
- return;
+ int secondAction;
+ action = KeyEventToActions(event, &secondAction);
}
- wxPGProperty* next = (wxPGProperty*) NULL;
-
- int dir = event.GetDirection()?1:-1;
-
- if ( m_selected )
- {
- 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 );
- }
- }
- }
-
- 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;
}
return;
}
- if ( ButtonTriggerKeyTest(event) )
+ if ( ButtonTriggerKeyTest(-1, event) )
return;
if ( HandleChildKey(event) == true )
void wxPropertyGrid::OnChildKeyUp( wxKeyEvent &event )
{
- m_keyComboConsumed = 0;
-
GetEventHandler()->AddPendingEvent(event);
event.Skip();
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();
}
}
*/
-
- m_iFlags &= ~(wxPG_FL_IGNORE_NEXT_NAVKEY);
}
// Redraw selected
// -----------------------------------------------------------------------
// noDefCheck = true prevents infinite recursion.
-wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* editorclass,
- const wxString& name,
+wxPGEditor* wxPropertyGrid::RegisterEditorClass( wxPGEditor* editorClass,
bool noDefCheck )
{
- wxASSERT( editorclass );
+ wxASSERT( editorClass );
if ( !noDefCheck && wxPGGlobalVars->m_mapEditorClasses.empty() )
RegisterDefaultEditors();
- wxPGGlobalVars->m_mapEditorClasses[name] = (void*)editorclass;
+ wxString 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);
+ }
+
+ wxCHECK_MSG( vt_it == wxPGGlobalVars->m_mapEditorClasses.end(),
+ (wxPGEditor*) vt_it->second,
+ "Editor with given name was already registered" );
- return editorclass;
+ wxPGGlobalVars->m_mapEditorClasses[name] = (void*)editorClass;
+
+ return editorClass;
}
+// Use this in RegisterDefaultEditors.
+#define wxPGRegisterDefaultEditorClass(EDITOR) \
+ if ( wxPGEditor_##EDITOR == (wxPGEditor*) NULL ) \
+ { \
+ wxPGEditor_##EDITOR = wxPropertyGrid::RegisterEditorClass( \
+ new wxPG##EDITOR##Editor, true ); \
+ }
+
// Registers all default editor classes
void wxPropertyGrid::RegisterDefaultEditors()
{
delete Item(i);
}
-#if wxUSE_STL
- m_items.resize(0);
-#else
- m_items.Empty();
-#endif
+ m_items.clear();
}
void wxPGChoicesData::CopyDataFrom( wxPGChoicesData* data )
unsigned int i;
for ( i=nIndex; i<(nIndex+count); i++)
delete m_data->Item(i);
- m_data->m_items.RemoveAt(nIndex, count);
+ m_data->m_items.erase(m_data->m_items.begin()+nIndex,
+ m_data->m_items.begin()+nIndex+count);
}
// -----------------------------------------------------------------------
return new wxPropertyGridEvent( *this );
}
-void wxPropertyGrid::SetPropertyAttributeAll( const wxString& attrName, wxVariant value )
-{
- DoSetPropertyAttribute(GetRoot(), attrName, value, wxPG_RECURSE);
-}
-
// -----------------------------------------------------------------------
// wxPropertyGridPopulator
// -----------------------------------------------------------------------
}
// -----------------------------------------------------------------------
+
+#endif // wxUSE_PROPGRID