X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/7f3f8f1e85e34898a30a8463ca73c86d6550548d..b80fdc029995a0c2ce04910e26d652292c64d7bc:/src/propgrid/propgrid.cpp diff --git a/src/propgrid/propgrid.cpp b/src/propgrid/propgrid.cpp index bedca1688b..4eb8520799 100644 --- a/src/propgrid/propgrid.cpp +++ b/src/propgrid/propgrid.cpp @@ -64,10 +64,6 @@ #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). @@ -398,8 +394,10 @@ bool wxPropertyGrid::Create( wxWindow *parent, const wxString& name ) { - if ( !(style&wxBORDER_MASK) ) - style |= wxSIMPLE_BORDER; + if (!(style&wxBORDER_MASK)) + { + style |= wxBORDER_THEME; + } style |= wxVSCROLL; @@ -428,10 +426,14 @@ void wxPropertyGrid::Init1() 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; @@ -552,7 +554,6 @@ void wxPropertyGrid::Init2() m_tlp = NULL; m_tlpClosed = NULL; m_tlpClosedTime = 0; - OnTLPChanging(::wxGetTopLevelParent(this)); // set virtual size to this window size wxSize wndsize = GetSize(); @@ -561,7 +562,7 @@ void wxPropertyGrid::Init2() 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 ); @@ -581,6 +582,23 @@ wxPropertyGrid::~wxPropertyGrid() { 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 @@ -590,12 +608,16 @@ wxPropertyGrid::~wxPropertyGrid() 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 ) @@ -615,7 +637,9 @@ wxPropertyGrid::~wxPropertyGrid() // Delete common value records for ( i=0; iDoRemoveFromSelection(prop); - RefreshProperty(prop); + DrawItem(prop); res = true; } @@ -794,7 +816,53 @@ bool wxPropertyGrid::DoRemoveFromSelection( wxPGProperty* prop, int selFlags ) // ----------------------------------------------------------------------- +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 ) { @@ -813,7 +881,7 @@ bool wxPropertyGrid::AddToSelectionFromInputEvent( wxPGProperty* prop, // disturbing the selection. if ( GetSelectedProperties().size() <= 1 || !alreadySelected ) - return DoSelectProperty(prop, selFlags); + return DoSelectAndEdit(prop, colIndex, selFlags); return true; } else @@ -844,7 +912,7 @@ bool wxPropertyGrid::AddToSelectionFromInputEvent( wxPGProperty* prop, } else { - res = DoSelectProperty(prop, selFlags); + res = DoSelectAndEdit(prop, colIndex, selFlags); } return res; @@ -875,8 +943,173 @@ void wxPropertyGrid::DoSetSelection( const wxArrayPGProperty& newSelection, // ----------------------------------------------------------------------- +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__) @@ -938,7 +1171,15 @@ wxSize wxPropertyGrid::DoGetBestSize() const 10 ); - const wxSize sz = wxSize(60, lineHeight*numLines + 40); + wxClientDC dc(const_cast(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; } @@ -947,6 +1188,9 @@ wxSize wxPropertyGrid::DoGetBestSize() const void wxPropertyGrid::OnTLPChanging( wxWindow* newTLP ) { + if ( newTLP == m_tlp ) + return; + wxLongLong currentTime = ::wxGetLocalTimeMillis(); // @@ -1211,7 +1455,7 @@ bool wxPropertyGrid::SetFont( const wxFont& font ) 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(); @@ -1925,8 +2169,28 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, 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; @@ -2074,28 +2338,36 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, { 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 { @@ -2128,7 +2400,7 @@ int wxPropertyGrid::DoDrawItems( wxDC& dc, cellRect.width -= textXAdd; // Foreground - if ( !ctrlCell ) + if ( !cellEditor ) { wxPGCellRenderer* renderer; int cmnVal = p->GetCommonValue(); @@ -2732,7 +3004,8 @@ bool wxPropertyGrid::PerformValidation( wxPGProperty* p, wxVariant& pendingValue 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; } @@ -2974,12 +3247,12 @@ bool wxPropertyGrid::DoPropertyChanged( wxPGProperty* p, unsigned int selFlags ) 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; @@ -3375,6 +3648,17 @@ void wxPropertyGrid::SetupChildEventHandling( wxWindow* argWnd ) 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() { // @@ -3402,7 +3686,7 @@ 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; } @@ -3411,7 +3695,7 @@ void wxPropertyGrid::FreeEditors() wxEvtHandler* handler = m_wndEditor->PopEventHandler(false); m_wndEditor->Hide(); wxPendingDelete.Append( handler ); - wxPendingDelete.Append( m_wndEditor ); + DestroyEditorWnd(m_wndEditor); m_wndEditor = NULL; } } @@ -3453,6 +3737,9 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) 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() ); @@ -3470,7 +3757,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) { 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 @@ -3528,10 +3814,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) } FreeEditors(); - m_selColumn = -1; - - // We need to always fully refresh the grid here - Refresh(false); m_iFlags &= ~(wxPG_FL_ABNORMAL_EDITOR); EditorsValueWasNotModified(); @@ -3541,6 +3823,12 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) m_pState->DoSetSelection(p); + // Redraw unselected + for ( unsigned int i=0; iGetEditorClass(); wxCHECK_MSG(editor, false, @@ -3621,18 +3905,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) 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; @@ -3645,15 +3917,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) 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) @@ -3679,19 +3942,6 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) 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); @@ -3725,13 +3975,11 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) 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 { @@ -3791,7 +4039,7 @@ bool wxPropertyGrid::DoSelectProperty( wxPGProperty* p, unsigned int flags ) // 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; } @@ -3819,7 +4067,7 @@ bool wxPropertyGrid::UnfocusEditor() void wxPropertyGrid::RefreshEditor() { wxPGProperty* p = GetSelection(); - if ( !p ) + if ( !p ) return; wxWindow* wnd = GetEditorControl(); @@ -4039,7 +4287,10 @@ void wxPropertyGrid::RecalculateVirtualSize( int forceXPos ) 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(); @@ -4137,21 +4388,34 @@ void wxPropertyGrid::SetFocusOnCanvas() // 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(); @@ -4202,7 +4466,9 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even ) ) { - if ( !AddToSelectionFromInputEvent( p, &event ) ) + if ( !AddToSelectionFromInputEvent( p, + columnHit, + &event ) ) return res; // On double-click, expand/collapse. @@ -4222,7 +4488,10 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even 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); @@ -4250,9 +4519,13 @@ bool wxPropertyGrid::HandleMouseClick( int x, unsigned int y, wxMouseEvent &even } 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 @@ -4321,7 +4594,7 @@ bool wxPropertyGrid::HandleMouseRightClick( int WXUNUSED(x), { // 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 ); @@ -4342,7 +4615,7 @@ bool wxPropertyGrid::HandleMouseDoubleClick( int WXUNUSED(x), // 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 ); @@ -4392,6 +4665,8 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxMouseEvent &event 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) && @@ -4572,13 +4847,33 @@ bool wxPropertyGrid::HandleMouseMove( int x, unsigned int y, wxMouseEvent &event // // 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; @@ -4937,14 +5232,25 @@ void wxPropertyGrid::AddActionTrigger( int action, int keycode, int modifiers ) 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 ) @@ -5183,10 +5489,11 @@ void wxPropertyGrid::OnIdle( wxIdleEvent& WXUNUSED(event) ) // // 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); } } @@ -5523,13 +5830,15 @@ 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 ); - +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; }