#include "wx/timer.h"
#include "wx/dcbuffer.h"
-#ifdef __WXMSW__
- #include "wx/msw/private.h"
-#endif
-
// 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).
const wxString& name )
{
- if ( !(style&wxBORDER_MASK) )
- style |= wxSIMPLE_BORDER;
+ if (!(style&wxBORDER_MASK))
+ {
+ style |= wxBORDER_THEME;
+ }
style |= wxVSCROLL;
m_iFlags = 0;
m_pState = NULL;
m_wndEditor = m_wndEditor2 = NULL;
- m_selColumn = -1;
+ m_selColumn = 1;
+ m_colHover = 1;
m_propHover = NULL;
+ m_labelEditor = NULL;
+ m_labelEditorProperty = NULL;
m_eventObject = this;
m_curFocused = NULL;
+ m_processedEvent = NULL;
m_sortFunction = NULL;
m_inDoPropertyChanged = 0;
m_inCommitChangesFromEditor = 0;
m_tlp = NULL;
m_tlpClosed = NULL;
m_tlpClosedTime = 0;
- OnTLPChanging(::wxGetTopLevelParent(this));
// set virtual size to this window size
wxSize wndsize = GetSize();
m_timeCreated = ::wxGetLocalTimeMillis();
m_canvas = new wxPGCanvas();
- m_canvas->Create(this, 1, wxPoint(0, 0), GetClientSize(),
+ m_canvas->Create(this, wxID_ANY, wxPoint(0, 0), GetClientSize(),
wxWANTS_CHARS | wxCLIP_CHILDREN);
m_canvas->SetBackgroundStyle( wxBG_STYLE_CUSTOM );
{
size_t i;
+ if ( m_processedEvent )
+ {
+ // All right... we are being deleted while wxPropertyGrid event
+ // is being sent. Make sure that event propagates as little
+ // as possible (although usually this is not enough to prevent
+ // a crash).
+ m_processedEvent->Skip(false);
+ m_processedEvent->StopPropagation();
+
+ // Let's use wxMessageBox to make the message appear more
+ // reliably (and *before* the crash can happend).
+ ::wxMessageBox("wxPropertyGrid was being destroyed in an event "
+ "generated by it. This usually leads to a crash "
+ "so it is recommended to destroy the control "
+ "at idle time instead.");
+ }
+
DoSelectProperty(NULL, wxPG_SEL_NOVALIDATE|wxPG_SEL_DONT_SEND_EVENT);
// This should do prevent things from going too badly wrong
m_canvas->ReleaseMouse();
// Call with NULL to disconnect event handling
- OnTLPChanging(NULL);
+ if ( GetExtraStyle() & wxPG_EX_ENABLE_TLP_TRACKING )
+ {
+ OnTLPChanging(NULL);
- 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).)") );
+ wxASSERT_MSG( !IsEditorsValueModified(),
+ wxS("Most recent change in property editor was ")
+ wxS("lost!!! (if you don't want this to happen, ")
+ wxS("close your frames and dialogs using ")
+ wxS("Close(false).)") );
+ }
#if wxPG_DOUBLE_BUFFER
if ( m_doubleBuffer )
// Delete common value records
for ( i=0; i<m_commonValues.size(); i++ )
{
- delete GetCommonValue(i);
+ // Use temporary variable to work around possible strange VC6 (asserts because m_size is zero)
+ wxPGCommonValue* value = m_commonValues[i];
+ delete value;
}
}
if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
{
- SendEvent( wxEVT_PG_SELECTED, prop, NULL, selFlags );
+ SendEvent( wxEVT_PG_SELECTED, prop, NULL );
}
- // For some reason, if we use RefreshProperty(prop) here,
- // we may go into infinite drawing loop.
- Refresh();
+ DrawItem(prop);
}
return true;
else
{
m_pState->DoRemoveFromSelection(prop);
- RefreshProperty(prop);
+ DrawItem(prop);
res = true;
}
// -----------------------------------------------------------------------
+bool wxPropertyGrid::DoSelectAndEdit( wxPGProperty* prop,
+ unsigned int colIndex,
+ unsigned int selFlags )
+{
+ //
+ // NB: Enable following if label editor background colour is
+ // ever changed to any other than m_colSelBack.
+ //
+ // We use this workaround to prevent visible flicker when editing
+ // a cell. Atleast on wxMSW, there is a difficult to find
+ // (and perhaps prevent) redraw somewhere between making property
+ // selected and enabling label editing.
+ //
+ //wxColour prevColSelBack = m_colSelBack;
+ //m_colSelBack = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
+
+ bool res;
+
+ if ( colIndex == 1 )
+ {
+ res = DoSelectProperty(prop, selFlags);
+ }
+ else
+ {
+ // send event
+ DoClearSelection(false, wxPG_SEL_NO_REFRESH);
+
+ if ( m_pState->m_editableColumns.Index(colIndex) == wxNOT_FOUND )
+ {
+ res = DoAddToSelection(prop, selFlags);
+ }
+ else
+ {
+ res = DoAddToSelection(prop, selFlags|wxPG_SEL_NO_REFRESH);
+
+ DoBeginLabelEdit(colIndex, selFlags);
+ }
+ }
+
+ //m_colSelBack = prevColSelBack;
+ return res;
+}
+
+// -----------------------------------------------------------------------
+
bool wxPropertyGrid::AddToSelectionFromInputEvent( wxPGProperty* prop,
+ unsigned int colIndex,
wxMouseEvent* mouseEvent,
int selFlags )
{
// disturbing the selection.
if ( GetSelectedProperties().size() <= 1 ||
!alreadySelected )
- return DoSelectProperty(prop, selFlags);
+ return DoSelectAndEdit(prop, colIndex, selFlags);
return true;
}
else
}
else
{
- res = DoSelectProperty(prop, selFlags);
+ res = DoSelectAndEdit(prop, colIndex, selFlags);
}
return res;
// -----------------------------------------------------------------------
+void wxPropertyGrid::MakeColumnEditable( unsigned int column,
+ bool editable )
+{
+ wxASSERT( column != 1 );
+
+ wxArrayInt& cols = m_pState->m_editableColumns;
+
+ if ( editable )
+ {
+ cols.push_back(column);
+ }
+ else
+ {
+ for ( int i = cols.size() - 1; i > 0; i-- )
+ {
+ if ( cols[i] == (int)column )
+ cols.erase( cols.begin() + i );
+ }
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoBeginLabelEdit( unsigned int colIndex,
+ int selFlags )
+{
+ wxPGProperty* selected = GetSelection();
+ wxCHECK_RET(selected, wxT("No property selected"));
+ wxCHECK_RET(colIndex != 1, wxT("Do not use this for column 1"));
+
+ if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
+ {
+ if ( SendEvent( wxEVT_PG_LABEL_EDIT_BEGIN,
+ selected, NULL, 0,
+ colIndex ) )
+ return;
+ }
+
+ wxString text;
+ const wxPGCell* cell = NULL;
+ if ( selected->HasCell(colIndex) )
+ {
+ cell = &selected->GetCell(colIndex);
+ if ( !cell->HasText() && colIndex == 0 )
+ text = selected->GetLabel();
+ }
+
+ if ( !cell )
+ {
+ if ( colIndex == 0 )
+ text = selected->GetLabel();
+ else
+ cell = &selected->GetOrCreateCell(colIndex);
+ }
+
+ if ( cell && cell->HasText() )
+ text = cell->GetText();
+
+ DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE); // send event
+
+ m_selColumn = colIndex;
+
+ wxRect r = GetEditorWidgetRect(selected, m_selColumn);
+
+ wxWindow* tc = GenerateEditorTextCtrl(r.GetPosition(),
+ r.GetSize(),
+ text,
+ NULL,
+ wxTE_PROCESS_ENTER,
+ 0,
+ colIndex);
+
+ wxWindowID id = tc->GetId();
+ tc->Connect(id, wxEVT_COMMAND_TEXT_ENTER,
+ wxCommandEventHandler(wxPropertyGrid::OnLabelEditorEnterPress),
+ NULL, this);
+ tc->Connect(id, wxEVT_KEY_DOWN,
+ wxKeyEventHandler(wxPropertyGrid::OnLabelEditorKeyPress),
+ NULL, this);
+
+ tc->SetFocus();
+
+ m_labelEditor = wxStaticCast(tc, wxTextCtrl);
+ m_labelEditorProperty = selected;
+}
+
+// -----------------------------------------------------------------------
+
+void
+wxPropertyGrid::OnLabelEditorEnterPress( wxCommandEvent& WXUNUSED(event) )
+{
+ DoEndLabelEdit(true);
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::OnLabelEditorKeyPress( wxKeyEvent& event )
+{
+ int keycode = event.GetKeyCode();
+
+ if ( keycode == WXK_ESCAPE )
+ {
+ DoEndLabelEdit(false);
+ }
+ else
+ {
+ event.Skip();
+ }
+}
+
+// -----------------------------------------------------------------------
+
+void wxPropertyGrid::DoEndLabelEdit( bool commit, int selFlags )
+{
+ if ( !m_labelEditor )
+ return;
+
+ wxPGProperty* prop = m_labelEditorProperty;
+ wxASSERT(prop);
+
+ if ( commit )
+ {
+ if ( !(selFlags & wxPG_SEL_DONT_SEND_EVENT) )
+ {
+ // wxPG_SEL_NOVALIDATE is passed correctly in selFlags
+ if ( SendEvent( wxEVT_PG_LABEL_EDIT_ENDING,
+ prop, NULL, selFlags,
+ m_selColumn ) )
+ return;
+ }
+
+ wxString text = m_labelEditor->GetValue();
+ wxPGCell* cell = NULL;
+ if ( prop->HasCell(m_selColumn) )
+ {
+ cell = &prop->GetCell(m_selColumn);
+ }
+ else
+ {
+ if ( m_selColumn == 0 )
+ prop->SetLabel(text);
+ else
+ cell = &prop->GetOrCreateCell(m_selColumn);
+ }
+
+ if ( cell )
+ cell->SetText(text);
+ }
+
+ m_selColumn = 1;
+
+ DestroyEditorWnd(m_labelEditor);
+ m_labelEditor = NULL;
+ m_labelEditorProperty = NULL;
+
+ DrawItem(prop);
+}
+
+// -----------------------------------------------------------------------
+
void wxPropertyGrid::SetExtraStyle( long exStyle )
{
+ if ( exStyle & wxPG_EX_ENABLE_TLP_TRACKING )
+ OnTLPChanging(::wxGetTopLevelParent(this));
+ else
+ OnTLPChanging(NULL);
+
if ( exStyle & wxPG_EX_NATIVE_DOUBLE_BUFFERING )
{
#if defined(__WXMSW__)
10
);
- const wxSize sz = wxSize(60, lineHeight*numLines + 40);
+ wxClientDC dc(const_cast<wxPropertyGrid *>(this));
+ int width = m_marginWidth;
+ for ( unsigned int i = 0; i < m_pState->m_colWidths.size(); i++ )
+ {
+ width += m_pState->GetColumnFitWidth(dc, m_pState->DoGetRoot(), i, true);
+ }
+
+ const wxSize sz = wxSize(width, lineHeight*numLines + 40);
+
CacheBestSize(sz);
return sz;
}
void wxPropertyGrid::OnTLPChanging( wxWindow* newTLP )
{
+ if ( newTLP == m_tlp )
+ return;
+
wxLongLong currentTime = ::wxGetLocalTimeMillis();
//
DoClearSelection();
bool res = wxScrolledWindow::SetFont( font );
- if ( res && GetParent()) // may not have been Create()ed yet
+ if ( res && GetParent()) // may not have been Create()ed yet if SetFont called from SetWindowVariant
{
CalculateFontAndBitmapStuff( m_vspacing );
Refresh();
int y2 = y + lh;
+#ifdef __WXMSW__
// Margin Edge
- dc.DrawLine( greyDepthX, y, greyDepthX, y2 );
+ // Modified by JACS to not draw a margin if wxPG_HIDE_MARGIN is specified, since it
+ // looks better, at least under Windows when we have a themed border (the themed-window-specific
+ // whitespace between the real border and the propgrid margin exacerbates the double-border look).
+
+ // Is this or its parent themed?
+ bool suppressMarginEdge = (GetWindowStyle() & wxPG_HIDE_MARGIN) &&
+ (((GetWindowStyle() & wxBORDER_MASK) == wxBORDER_THEME) ||
+ (((GetWindowStyle() & wxBORDER_MASK) == wxBORDER_NONE) && ((GetParent()->GetWindowStyle() & wxBORDER_MASK) == wxBORDER_THEME)));
+#else
+ bool suppressMarginEdge = false;
+#endif
+ if (!suppressMarginEdge)
+ dc.DrawLine( greyDepthX, y, greyDepthX, y2 );
+ else
+ {
+ // Blank out the margin edge
+ dc.SetPen(wxPen(GetBackgroundColour()));
+ dc.DrawLine( greyDepthX, y, greyDepthX, y2 );
+ dc.SetPen( linepen );
+ }
// Splitters
unsigned int si;
{
cellRect.width = nextCellWidth - 1;
- bool ctrlCell = false;
+ wxWindow* cellEditor = NULL;
int cellRenderFlags = renderFlags;
- // Tree Item Button
+ // Tree Item Button (must be drawn before clipping is set up)
if ( ci == 0 && !HasFlag(wxPG_HIDE_MARGIN) && p->HasVisibleChildren() )
DrawExpanderButton( dc, butRect, p );
// Background
- if ( isSelected && ci == 1 )
+ if ( isSelected && (ci == 1 || ci == m_selColumn) )
{
- if ( p == firstSelected && m_wndEditor )
+ if ( p == firstSelected )
+ {
+ if ( ci == 1 && m_wndEditor )
+ cellEditor = m_wndEditor;
+ else if ( ci == m_selColumn && m_labelEditor )
+ cellEditor = m_labelEditor;
+ }
+
+ if ( cellEditor )
{
wxColour editorBgCol =
- GetEditorControl()->GetBackgroundColour();
+ cellEditor->GetBackgroundColour();
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;
+ if ( m_dragStatus != 0 ||
+ (m_iFlags & wxPG_FL_CUR_USES_CUSTOM_IMAGE) )
+ cellEditor = NULL;
}
else
{
cellRect.width -= textXAdd;
// Foreground
- if ( !ctrlCell )
+ if ( !cellEditor )
{
wxPGCellRenderer* renderer;
int cmnVal = p->GetCommonValue();
if ( flags & SendEvtChanging )
{
// SendEvent returns true if event was vetoed
- if ( SendEvent( wxEVT_PG_CHANGING, evtChangingProperty, &evtChangingValue, 0 ) )
+ if ( SendEvent( wxEVT_PG_CHANGING, evtChangingProperty,
+ &evtChangingValue ) )
return false;
}
while ( pwc != changedProperty )
{
- SendEvent( wxEVT_PG_CHANGED, pwc, NULL, selFlags );
+ SendEvent( wxEVT_PG_CHANGED, pwc, NULL );
pwc = pwc->GetParent();
}
}
- SendEvent( wxEVT_PG_CHANGED, changedProperty, NULL, selFlags );
+ SendEvent( wxEVT_PG_CHANGED, changedProperty, NULL );
m_inDoPropertyChanged = 0;
NULL, this);
}
+void wxPropertyGrid::DestroyEditorWnd( wxWindow* wnd )
+{
+ if ( !wnd )
+ return;
+
+ wnd->Hide();
+
+ // Do not free editors immediately (for sake of processing events)
+ wxPendingDelete.Append(wnd);
+}
+
void wxPropertyGrid::FreeEditors()
{
//
wxEvtHandler* handler = m_wndEditor2->PopEventHandler(false);
m_wndEditor2->Hide();
wxPendingDelete.Append( handler );
- wxPendingDelete.Append( m_wndEditor2 );
+ DestroyEditorWnd(m_wndEditor2);
m_wndEditor2 = NULL;
}
wxEvtHandler* handler = m_wndEditor->PopEventHandler(false);
m_wndEditor->Hide();
wxPendingDelete.Append( handler );
- wxPendingDelete.Append( m_wndEditor );
+ DestroyEditorWnd(m_wndEditor);
m_wndEditor = NULL;
}
}
if ( prevFirstSel && prevFirstSel->HasFlag(wxPG_PROP_BEING_DELETED) )
prevFirstSel = NULL;
+ // Always send event, as this is indirect call
+ DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE);
+
/*
if ( prevFirstSel )
wxPrintf( "Selected %s\n", prevFirstSel->GetClassInfo()->GetClassName() );
{
m_iFlags &= ~(wxPG_FL_ABNORMAL_EDITOR);
m_editorFocused = 0;
- m_selColumn = 1;
m_pState->DoSetSelection(p);
// If frozen, always free controls. But don't worry, as Thaw will
}
FreeEditors();
- m_selColumn = -1;
-
- // We need to always fully refresh the grid here
- Refresh(false);
m_iFlags &= ~(wxPG_FL_ABNORMAL_EDITOR);
EditorsValueWasNotModified();
m_pState->DoSetSelection(p);
+ // Redraw unselected
+ for ( unsigned int i=0; i<prevSelection.size(); i++ )
+ {
+ DrawItem(prevSelection[i]);
+ }
+
//
// Then, activate the one given.
if ( p )
wxRect grect = GetEditorWidgetRect(p, m_selColumn);
wxPoint goodPos = grect.GetPosition();
- #if wxPG_CREATE_CONTROLS_HIDDEN
- int coord_adjust = m_height - goodPos.y;
- goodPos.y += coord_adjust;
- #endif
const wxPGEditor* editor = p->GetEditorClass();
wxCHECK_MSG(editor, false,
if ( (p->m_flags & wxPG_PROP_MODIFIED) && (m_windowStyle & wxPG_BOLD_MODIFIED) )
SetCurControlBoldFont();
- //
- // Fix TextCtrl indentation
- #if defined(__WXMSW__) && !defined(__WXWINCE__)
- wxTextCtrl* tc = NULL;
- if ( primaryCtrl->IsKindOf(CLASSINFO(wxOwnerDrawnComboBox)) )
- tc = ((wxOwnerDrawnComboBox*)primaryCtrl)->GetTextCtrl();
- else
- tc = wxDynamicCast(primaryCtrl, wxTextCtrl);
- if ( tc )
- ::SendMessage(GetHwndOf(tc), EM_SETMARGINS, EC_LEFTMARGIN | EC_RIGHTMARGIN, MAKELONG(0, 0));
- #endif
-
// Store x relative to splitter (we'll need it).
m_ctrlXAdjust = m_wndEditor->GetPosition().x - splitterX;
m_wndEditor->SetSizeHints(3, 3);
- #if wxPG_CREATE_CONTROLS_HIDDEN
- m_wndEditor->Show(false);
- m_wndEditor->Freeze();
-
- goodPos = m_wndEditor->GetPosition();
- goodPos.y -= coord_adjust;
- m_wndEditor->Move( goodPos );
- #endif
-
SetupChildEventHandling(primaryCtrl);
// Focus and select all (wxTextCtrl, wxComboBox etc)
m_wndEditor2->SetSizeHints(3,3);
- #if wxPG_CREATE_CONTROLS_HIDDEN
- wxRect sec_rect = m_wndEditor2->GetRect();
- sec_rect.y -= coord_adjust;
-
- // Fine tuning required to fix "oversized"
- // button disappearance bug.
- if ( sec_rect.y < 0 )
- {
- sec_rect.height += sec_rect.y;
- sec_rect.y = 0;
- }
- m_wndEditor2->SetSize( sec_rect );
- #endif
m_wndEditor2->Show();
SetupChildEventHandling(m_wndEditor2);
if ( m_wndEditor )
{
- #if wxPG_CREATE_CONTROLS_HIDDEN
- m_wndEditor->Thaw();
- #endif
m_wndEditor->Show(true);
}
- DrawItems(p, p);
+ if ( !(flags & wxPG_SEL_NO_REFRESH) )
+ DrawItem(p);
}
else
{
// call wx event handler (here so that it also occurs on deselection)
if ( !(flags & wxPG_SEL_DONT_SEND_EVENT) )
- SendEvent( wxEVT_PG_SELECTED, p, NULL, flags );
+ SendEvent( wxEVT_PG_SELECTED, p, NULL );
return true;
}
void wxPropertyGrid::RefreshEditor()
{
wxPGProperty* p = GetSelection();
- if ( !p )
+ if ( !p )
return;
wxWindow* wnd = GetEditorControl();
m_width = width;
m_height = height;
- m_canvas->SetSize( x, y );
+ // Explicitly pass the position - works around a bug in wxWidgets when the property grid
+ // has a native XP border and a contained window creeps up-and-left when size is set without
+ // the position.
+ m_canvas->SetSize( 0, 0, x, y );
m_pState->CheckColumnWidths();
// selFlags uses same values DoSelectProperty's flags
// Returns true if event was vetoed.
-bool wxPropertyGrid::SendEvent( int eventType, wxPGProperty* p, wxVariant* pValue, unsigned int WXUNUSED(selFlags) )
+bool wxPropertyGrid::SendEvent( int eventType, wxPGProperty* p,
+ wxVariant* pValue,
+ unsigned int selFlags,
+ unsigned int column )
{
// Send property grid event of specific type and with specific property
wxPropertyGridEvent evt( eventType, m_eventObject->GetId() );
evt.SetPropertyGrid(this);
evt.SetEventObject(m_eventObject);
evt.SetProperty(p);
+ evt.SetColumn(column);
if ( pValue )
{
evt.SetCanVeto(true);
evt.SetupValidationInfo();
m_validationInfo.m_pValue = pValue;
}
+ else if ( !(selFlags & wxPG_SEL_NOVALIDATE) )
+ {
+ evt.SetCanVeto(true);
+ }
+
+ m_processedEvent = &evt;
+
wxEvtHandler* evtHandler = m_eventObject->GetEventHandler();
+ m_processedEvent = NULL;
+
evtHandler->ProcessEvent(evt);
return evt.WasVetoed();
)
)
{
- if ( !AddToSelectionFromInputEvent( p, &event ) )
+ if ( !AddToSelectionFromInputEvent( p,
+ columnHit,
+ &event ) )
return res;
// On double-click, expand/collapse.
m_iFlags |= wxPG_FL_ACTIVATION_BY_CLICK;
selFlag = wxPG_SEL_FOCUS;
}
- if ( !AddToSelectionFromInputEvent( p, &event, selFlag ) )
+ if ( !AddToSelectionFromInputEvent( p,
+ columnHit,
+ &event,
+ selFlag ) )
return res;
m_iFlags &= ~(wxPG_FL_ACTIVATION_BY_CLICK);
}
else if ( m_dragStatus == 0 )
{
- //
- // Begin draggin the splitter
- //
+ //
+ // Begin draggin the splitter
+ //
+
+ // send event
+ DoEndLabelEdit(true, wxPG_SEL_NOVALIDATE);
+
if ( m_wndEditor )
{
// Changes must be committed here or the
{
// Select property here as well
wxPGProperty* p = m_propHover;
- AddToSelectionFromInputEvent(p, &event);
+ AddToSelectionFromInputEvent(p, m_colHover, &event);
// Send right click event.
SendEvent( wxEVT_PG_RIGHT_CLICK, p );
// Select property here as well
wxPGProperty* p = m_propHover;
- AddToSelectionFromInputEvent(p, &event);
+ AddToSelectionFromInputEvent(p, m_colHover, &event);
// Send double-click event.
SendEvent( wxEVT_PG_DOUBLE_CLICK, m_propHover );
int columnHit = state->HitTestH( x, &splitterHit, &splitterHitOffset );
int splitterX = x - splitterHitOffset;
+ m_colHover = columnHit;
+
if ( m_dragStatus > 0 )
{
if ( x > (m_marginWidth + wxPG_DRAG_MARGIN) &&
//
// Multi select by dragging
//
- if ( GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION &&
+ if ( (GetExtraStyle() & wxPG_EX_MULTIPLE_SELECTION) &&
event.LeftIsDown() &&
m_propHover &&
GetSelection() &&
+ columnHit != 1 &&
!state->DoIsPropertySelected(m_propHover) )
{
- DoAddToSelection(m_propHover);
+ // Additional requirement is that the hovered property
+ // is adjacent to edges of selection.
+ const wxArrayPGProperty& selection = GetSelectedProperties();
+
+ // Since categories cannot be selected along with 'other'
+ // properties, exclude them from iterator flags.
+ int iterFlags = wxPG_ITERATE_VISIBLE & (~wxPG_PROP_CATEGORY);
+
+ for ( int i=(selection.size()-1); i>=0; i-- )
+ {
+ // TODO: This could be optimized by keeping track of
+ // which properties are at the edges of selection.
+ wxPGProperty* selProp = selection[i];
+ if ( state->ArePropertiesAdjacent(m_propHover, selProp,
+ iterFlags) )
+ {
+ DoAddToSelection(m_propHover);
+ break;
+ }
+ }
}
}
return true;
void wxPropertyGrid::ClearActionTriggers( int action )
{
wxPGHashMapI2I::iterator it;
+ bool didSomething;
- for ( it = m_actionTriggers.begin(); it != m_actionTriggers.end(); ++it )
+ do
{
- if ( it->second == action )
+ didSomething = false;
+
+ for ( it = m_actionTriggers.begin();
+ it != m_actionTriggers.end();
+ it++ )
{
- m_actionTriggers.erase(it);
+ if ( it->second == action )
+ {
+ m_actionTriggers.erase(it);
+ didSomething = true;
+ break;
+ }
}
}
+ while ( didSomething );
}
void wxPropertyGrid::HandleKeyEvent( wxKeyEvent &event, bool fromChild )
//
// Check if top-level parent has changed
- wxWindow* tlp = ::wxGetTopLevelParent(this);
- if ( tlp != m_tlp )
+ if ( GetExtraStyle() & wxPG_EX_ENABLE_TLP_TRACKING )
{
- OnTLPChanging(tlp);
+ wxWindow* tlp = ::wxGetTopLevelParent(this);
+ if ( tlp != m_tlp )
+ OnTLPChanging(tlp);
}
}
wxDEFINE_EVENT( wxEVT_PG_ITEM_EXPANDED, wxPropertyGridEvent );
wxDEFINE_EVENT( wxEVT_PG_ITEM_COLLAPSED, wxPropertyGridEvent );
wxDEFINE_EVENT( wxEVT_PG_DOUBLE_CLICK, wxPropertyGridEvent );
-
+wxDEFINE_EVENT( wxEVT_PG_LABEL_EDIT_BEGIN, wxPropertyGridEvent );
+wxDEFINE_EVENT( wxEVT_PG_LABEL_EDIT_ENDING, wxPropertyGridEvent );
// -----------------------------------------------------------------------
void wxPropertyGridEvent::Init()
{
m_validationInfo = NULL;
+ m_column = 1;
m_canVeto = false;
m_wasVetoed = false;
}